3 * This is the file cluster.c for the Moira Client, which allows users
4 * to quickly and easily maintain most parts of the Moira database.
8 * By: Chris D. Peterson
10 * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
11 * For copying and distribution information, please see the file
15 /* BTW: for anyone who cares MCD is short for Machine, Cluster, Data. */
17 #include <mit-copyright.h>
19 #include <moira_site.h>
26 #include <sys/types.h>
29 #include <sys/utsname.h>
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
43 void PrintAliases(char **info);
44 static void PrintMachine(char **info);
45 struct mqelem *GetMCInfo(int type, char *name1, char *name2);
46 struct mqelem *GetMachineByOwner(char *type, char *name);
47 char **AskMCDInfo(char **info, int type, Bool name);
48 int CheckAndRemoveFromCluster(char *name, Bool ask_user);
49 int CheckAndRemoveCnames(char *name, Bool ask_user);
50 int CheckAndRemoveMachines(char *name, Bool ask_first);
59 #define M_DEFAULT_TYPE DEFAULT_NONE
61 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
62 #define C_DEFAULT_LOCATION DEFAULT_NONE
64 #define CD_DEFAULT_LABEL DEFAULT_NONE
65 #define CD_DEFAULT_DATA DEFAULT_NONE
67 #define S_DEFAULT_LOW "18.0.0.20"
68 #define S_DEFAULT_HIGH "18.0.2.249"
70 static char *states[] = {
77 static char *MacState(int state)
79 static char buf[BUFSIZ];
81 if (state < 0 || state > 3)
83 sprintf(buf, "Unknown (%d)", state);
91 /* -------------------- Set Defaults -------------------- */
93 /* Function Name: SetMachineDefaults
94 * Description: sets machine defaults.
95 * Arguments: info - an array to put the defaults into.
96 * name - Canonacalized name of the machine.
97 * Returns: info - the array.
100 static char **SetMachineDefaults(char **info, char *name)
102 info[M_NAME] = strdup(name);
103 info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
104 info[M_MODEL] = strdup(M_DEFAULT_TYPE);
105 info[M_OS] = strdup(M_DEFAULT_TYPE);
106 info[M_LOC] = strdup(M_DEFAULT_TYPE);
107 info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
108 info[M_BILL_CONTACT] = strdup(M_DEFAULT_TYPE);
109 info[M_USE] = strdup("0");
110 info[M_STAT] = strdup("1");
111 info[M_SUBNET] = strdup("NONE");
112 info[M_ADDR] = strdup("unique");
113 info[M_OWNER_TYPE] = strdup("NONE");
114 info[M_OWNER_NAME] = strdup("NONE");
115 info[M_ACOMMENT] = strdup("");
116 info[M_OCOMMENT] = strdup("");
117 info[16] = info[17] = NULL;
121 /* Function Name: SetClusterDefaults
122 * Description: sets Cluster defaults.
123 * Arguments: info - an array to put the defaults into.
124 * name - name of the Cluster.
125 * Returns: info - the array.
128 static char **SetClusterDefaults(char **info, char *name)
130 info[C_NAME] = strdup(name);
131 info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
132 info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
133 info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
137 /* Function Name: SetSubnetDefaults
138 * Description: sets Subnet defaults.
139 * Arguments: info - an array to put the defaults into.
140 * name - name of the Subnet.
141 * Returns: info - the array.
144 static char **SetSubnetDefaults(char **info, char *name)
148 info[C_NAME] = strdup(name);
149 info[SN_DESC] = strdup("");
150 sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
151 info[SN_ADDRESS] = strdup(buf);
152 sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
153 info[SN_MASK] = strdup(buf);
154 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
155 info[SN_LOW] = strdup(buf);
156 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
157 info[SN_HIGH] = strdup(buf);
158 info[SN_PREFIX] = strdup("");
159 info[SN_ACE_TYPE] = strdup("LIST");
160 info[SN_ACE_NAME] = strdup("network");
161 info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
165 /* -------------------- General Functions -------------------- */
167 static char aliasbuf[256];
169 void PrintAliases(char **info)
171 if (strlen(aliasbuf) == 0)
172 sprintf(aliasbuf, "Aliases: %s", info[0]);
175 strcat(aliasbuf, ", ");
176 strcat(aliasbuf, info[0]);
181 /* Function Name: PrintMachInfo
182 * Description: This function Prints out the Machine info in
184 * Arguments: info - array of information about a machine.
185 * Returns: The name of the Machine
188 static char *PrintMachInfo(char **info)
190 char buf[BUFSIZ], tbuf[256];
192 struct mqelem *elem = NULL;
196 sprintf(buf, "Machine: %s", info[M_NAME]);
199 args[1] = info[M_NAME];
200 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
202 if (stat != MR_NO_MATCH)
203 com_err(program_name, stat, " looking up aliases");
208 Loop(QueueTop(elem), (void (*)(char **)) PrintAliases);
210 Put_message(aliasbuf);
212 sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
213 strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
214 sprintf(buf, "Address: %-16s Network: %-16s",
215 info[M_ADDR], info[M_SUBNET]);
217 sprintf(buf, "Owner: %-16s Use data: %s", tbuf, info[M_INUSE]);
219 sprintf(buf, "Status: %-16s Changed: %s",
220 MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
224 sprintf(buf, "Vendor: %-16s Location: %s", info[M_VENDOR],
227 sprintf(buf, "Model: %-16s Contact: %s", info[M_MODEL],
230 sprintf(buf, "OS: %-16s Billing Contact: %s", info[M_OS],
231 info[M_BILL_CONTACT]);
234 sprintf(buf, "Opt: %s", info[M_USE]);
237 sprintf(buf, "Adm cmt: %s", info[M_ACOMMENT]);
239 sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]);
242 sprintf(buf, "Created by %s on %s", info[M_CREATOR], info[M_CREATED]);
244 sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
249 /* Function Name: PrintMachine
250 * Description: Prints the name of a machine record
251 * Arguments: info - array of information about the machine.
255 static void PrintMachine(char **info)
259 sprintf(buf, "Machine: %s", info[M_NAME]);
263 /* Function Name: PrintCname
264 * Description: Prints the Data on a host alias
265 * Arguments: info a pointer to the data array.
266 * Returns: The name of the alias.
269 static char *PrintCname(char **info)
273 sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
278 /* Function Name: PrintClusterInfo
279 * Description: This function Prints out the cluster info
280 * in a coherent form.
281 * Arguments: info - array of information about a cluster.
282 * Returns: The name of the cluster.
285 static char *PrintClusterInfo(char **info)
290 sprintf(buf, "Cluster: %s", info[C_NAME]);
292 sprintf(buf, "Description: %s", info[C_DESCRIPT]);
294 sprintf(buf, "Location: %s", info[C_LOCATION]);
296 sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
301 /* Function Name: PrintClusterData
302 * Description: Prints the Data on a cluster
303 * Arguments: info a pointer to the data array.
304 * Returns: The name of the cluster.
307 static char *PrintClusterData(char **info)
312 sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
313 info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
315 return info[CD_NAME];
318 /* Function Name: PrintMCMap
319 * Description: Prints the data about a machine to cluster mapping.
320 * Arguments: info a pointer to the data array.
324 static char *PrintMCMap(char **info)
327 sprintf(buf, "Cluster: %-30s Machine: %-20s",
328 info[MAP_CLUSTER], info[MAP_MACHINE]);
330 return ""; /* Used by QueryLoop(). */
333 /* Function Name: PrintSubnetInfo
334 * Description: This function Prints out the subnet info
335 * in a coherent form.
336 * Arguments: info - array of information about a subnet.
337 * Returns: The name of the subnet.
340 static char *PrintSubnetInfo(char **info)
343 struct in_addr addr, mask, low, high;
346 sprintf(buf, " Network: %s", info[SN_NAME]);
348 sprintf(buf, " Description: %s", info[SN_DESC]);
350 addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
351 mask.s_addr = htonl(atoi(info[SN_MASK]));
352 low.s_addr = htonl(atoi(info[SN_LOW]));
353 high.s_addr = htonl(atoi(info[SN_HIGH]));
354 /* screwy sequence is here because inet_ntoa returns a pointer to
355 a static buf. If it were all one sprintf, the last value would
357 sprintf(buf, " Address: %s Mask: ", inet_ntoa(addr));
358 strcat(buf, inet_ntoa(mask));
359 strcat(buf, "\n High: ");
360 strcat(buf, inet_ntoa(high));
361 strcat(buf, " Low: ");
362 strcat(buf, inet_ntoa(low));
364 sprintf(buf, "Hostname prefix: %s", info[SN_PREFIX]);
366 sprintf(buf, " Owner: %s %s\n", info[SN_ACE_TYPE],
367 strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
369 sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
371 return info[SN_NAME];
374 /* Function Name: GetMCInfo.
375 * Description: This function stores info about a machine.
376 * type - type of data we are trying to retrieve.
377 * name1 - the name of argv[0] for the call.
378 * name2 - the name of argv[1] for the call.
379 * Returns: the top element of a queue containing the data or NULL.
382 struct mqelem *GetMCInfo(int type, char *name1, char *name2)
385 struct mqelem *elem = NULL;
392 args[1] = args[2] = args[3] = "*";
393 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
395 if (stat == MR_NO_MATCH)
398 sprintf(buf, "Machine '%s' is not in the database.", name1);
402 com_err(program_name, stat, " in get_machine.");
409 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
411 com_err(program_name, stat, " in get_hostalias.");
416 if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
418 if (stat == MR_NO_MATCH)
421 sprintf(buf, "Network '%s' is not in the database.", name1);
425 com_err(program_name, stat, " in get_subnet.");
430 if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
432 com_err(program_name, stat, " in get_cluster.");
437 args[MAP_MACHINE] = name1;
438 args[MAP_CLUSTER] = name2;
439 if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
442 com_err(program_name, stat, " in get_machine_to_cluster_map.");
447 args[CD_NAME] = name1;
448 args[CD_LABEL] = name2;
449 if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
451 com_err(program_name, stat, " in get_cluster_data.");
455 return QueueTop(elem);
458 /* Function Name: AskMCDInfo.
459 * Description: This function askes the user for information about a
460 * machine and saves it into a structure.
461 * Arguments: info - a pointer the information to ask about
462 * type - type of information - MACHINE
465 * name - T/F : change the name of this type.
469 char **AskMCDInfo(char **info, int type, Bool name)
471 char temp_buf[BUFSIZ], *newname, *oldnewname;
476 sprintf(temp_buf, "\nSetting the information for the Machine %s...",
480 sprintf(temp_buf, "Setting the information for the Network %s...",
484 sprintf(temp_buf, "Setting the information for the Cluster %s...",
488 sprintf(temp_buf, "Setting the Data for the Cluster %s...",
492 Put_message(temp_buf);
499 newname = strdup(info[M_NAME]);
500 if (GetValueFromUser("The new name for this machine? ", &newname) ==
503 oldnewname = strdup(newname);
504 newname = canonicalize_hostname(newname);
505 if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
507 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
508 oldnewname, newname);
509 Put_message(temp_buf);
514 newname = strdup(info[SN_NAME]);
515 if (GetValueFromUser("The new name for this network? ", &newname) ==
520 newname = strdup(info[C_NAME]);
521 if (GetValueFromUser("The new name for this cluster? ", &newname) ==
526 Put_message("Unknown type in AskMCDInfo, programmer botch");
534 if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
536 if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
538 if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
541 if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
543 if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
546 if (GetValueFromUser("Machine's billing contact",
547 &info[M_BILL_CONTACT]) == SUB_ERROR)
552 if (GetValueFromUser("Machine's status (? for help)",
553 &info[M_STAT]) == SUB_ERROR)
555 if (isdigit(info[M_STAT][0]))
557 Put_message("Valid status numbers:");
558 for (i = 0; i < 4; i++)
559 Put_message(states[i]);
562 /* there appears to be some argument mismatch between the client
563 * and the server.. so here is this argument shuffler.
564 * I have since modified this to always shuffle the arguments..
565 * not just do so when performing a modify all fields request.
566 * The SetMachinedefaults() has been changed to reflect this.
567 * pray for us and may we attain enlightenment through structures.
572 /* info did not come from SetMachineDefaults(), which does not
573 * initialize entry 8 (M_STAT_CHNG), therefore we can
576 /* This is an update of an existing machine and the structure
577 * was filled in thru a query to the db which does fill in this
583 info[9] = info[M_SUBNET];
584 info[10] = info[M_ADDR];
585 info[11] = info[M_OWNER_TYPE];
586 info[12] = info[M_OWNER_NAME];
587 info[13] = info[M_ACOMMENT];
588 info[14] = info[M_OCOMMENT];
592 if (GetValueFromUser("Machine's network (or 'none')", &info[9])
596 if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
597 &info[10]) == SUB_ERROR)
599 if (GetTypeFromUser("Machine's owner type", "ace_type", &info[11]) ==
602 if (strcmp(info[11], "NONE") &&
603 GetValueFromUser("Owner's Name", &info[12]) == SUB_ERROR)
605 if (!strcmp(info[11], "KERBEROS"))
609 mrcl_validate_kerberos_member(info[12], &canon);
610 if (mrcl_get_message())
611 Put_message(mrcl_get_message());
615 if (GetValueFromUser("Administrative comment", &info[13]) == SUB_ERROR)
617 if (GetValueFromUser("Operational comment", &info[14]) == SUB_ERROR)
620 FreeAndClear(&info[16], TRUE);
621 FreeAndClear(&info[17], TRUE);
624 if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
626 if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
628 if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
630 if (atoi(info[SN_LOW]) == (int)ntohl(inet_addr(S_DEFAULT_LOW)))
633 unsigned long mask, addr;
635 addr = atoi(info[SN_ADDRESS]);
636 mask = atoi(info[SN_MASK]);
637 low.s_addr = atoi(info[SN_LOW]);
638 low.s_addr = (low.s_addr & ~mask) | (addr & mask);
640 sprintf(temp_buf, "%ld", low.s_addr);
641 info[SN_LOW] = strdup(temp_buf);
643 if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
646 if (atoi(info[SN_HIGH]) == (int)ntohl(inet_addr(S_DEFAULT_HIGH)))
649 unsigned long mask, addr;
651 addr = atoi(info[SN_ADDRESS]);
652 mask = atoi(info[SN_MASK]);
653 high.s_addr = atoi(info[SN_HIGH]);
654 high.s_addr = (high.s_addr & ~mask) | (addr & mask);
656 sprintf(temp_buf, "%ld", high.s_addr);
657 info[SN_HIGH] = strdup(temp_buf);
659 if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
662 if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
664 if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
667 if (strcmp(info[SN_ACE_TYPE], "NONE") &&
668 GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
670 if (!strcmp(info[SN_ACE_TYPE], "KERBEROS"))
674 mrcl_validate_kerberos_member(info[SN_ACE_NAME], &canon);
675 if (mrcl_get_message())
676 Put_message(mrcl_get_message());
677 free(info[SN_ACE_NAME]);
678 info[SN_ACE_NAME] = canon;
680 FreeAndClear(&info[SN_MODTIME], TRUE);
681 FreeAndClear(&info[SN_MODBY], TRUE);
682 FreeAndClear(&info[SN_MODWITH], TRUE);
685 if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
688 if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
691 FreeAndClear(&info[C_MODTIME], TRUE);
692 FreeAndClear(&info[C_MODBY], TRUE);
693 FreeAndClear(&info[C_MODWITH], TRUE);
696 if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
699 if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
705 * Slide the newname into the #2 slot, this screws up all future references
709 SlipInNewName(info, newname);
714 /* ----------- Machine Menu ----------- */
716 /* Function Name: ShowMachineInfo
717 * Description: This function shows the information about a machine.
718 * Arguments: argc, argv - the name of the machine in argv[1].
719 * Returns: DM_NORMAL.
722 int ShowMachineInfo(int argc, char **argv)
727 tmpname = canonicalize_hostname(strdup(argv[1]));
728 top = GetMCInfo(MACHINE, tmpname, NULL);
729 Loop(top, ((void (*)(char **)) PrintMachInfo));
734 /* Function Name: ShowMachineQuery
735 * Description: This function shows the information about a machine.
736 * or group of machines, which may be selected through a
737 * number of criteria.
738 * Arguments: argc, argv - the name of the machine in argv[1],
739 * the address of the machine in argv[2],
740 * the location of the machine in argv[3],
741 * and the contact name in argv[4].
742 * any of these may be wildcards.
743 * Returns: DM_NORMAL.
746 int ShowMachineQuery(int argc, char **argv)
749 struct mqelem *top, *elem = NULL;
752 if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
753 !strcmp(argv[3], "") && !strcmp(argv[4], ""))
755 Put_message("You must specify at least one parameter of the query.");
760 args[0] = canonicalize_hostname(strdup(argv[1]));
776 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
778 if (stat == MR_NO_MATCH)
779 Put_message("No machine(s) found matching query in the database.");
781 com_err(program_name, stat, " in get_machine.");
784 top = QueueTop(elem);
785 Loop(top, ((void (*)(char **)) PrintMachInfo));
790 /* Function Name: AddMachine
791 * Description: This function adds a new machine to the database.
792 * Arguments: argc, argv - the name of the network in argv[1].
793 * Returns: DM_NORMAL.
796 int AddMachine(int argc, char **argv)
798 char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
800 struct mqelem *elem = NULL;
803 if (!ValidName(argv[1])) /* Checks for wildcards. */
807 * get the network record
810 if (strcasecmp(argv[1], "none") &&
811 (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
813 if (stat == MR_NO_MATCH)
816 sprintf(buf, "Network '%s' is not in the database.", argv[1]);
819 com_err(program_name, stat, " in get_subnet.");
824 * Check to see if this machine already exists.
827 name = strdup(""); /* want to put prefix here */
828 if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
831 name = canonicalize_hostname(strdup(name));
834 xargs[1] = xargs[2] = xargs[3] = "*";
835 if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
837 sprintf(buf, "The machine '%s' already exists.", name);
842 else if (stat != MR_NO_MATCH)
844 com_err(program_name, stat,
845 " while checking machine '%s' in AddMachine.", name);
849 rinfo = SetMachineDefaults(info, name);
850 rinfo[M_SUBNET] = strdup(argv[1]);
851 if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
853 Put_message("Aborted.");
858 * Actually create the new Machine.
861 if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
862 com_err(program_name, stat, " in AddMachine.");
869 /* Function Name: RealUpdateMachine
870 * Description: Performs the actual update of the machine data.
871 * Arguments: info - the information on the machine to update.
872 * junk - an UNUSED Boolean.
876 static void RealUpdateMachine(char **info, Bool junk)
879 char **args = AskMCDInfo(info, MACHINE, TRUE);
882 Put_message("Aborted.");
885 if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
886 com_err(program_name, stat, " in UpdateMachine.");
888 Put_message("Machine successfully updated.");
891 /* Function Name: UpdateMachine
892 * Description: This function adds a new machine to the database.
893 * Arguments: argc, argv - the name of the machine in argv[1].
894 * Returns: DM_NORMAL.
897 int UpdateMachine(int argc, char **argv)
902 tmpname = canonicalize_hostname(strdup(argv[1]));
903 top = GetMCInfo(MACHINE, tmpname, NULL);
904 QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
911 /* Function Name: CheckAndRemoveFromCluster
912 * Description: This func tests to see if a machine is in a cluster.
913 * and if so then removes it
914 * Arguments: name - name of the machine (already Canonicalized).
915 * ask_user- query the user before removing if from clusters?
916 * Returns: MR_ERROR if machine left in a cluster, or mr_error.
919 int CheckAndRemoveFromCluster(char *name, Bool ask_user)
923 char *args[10], temp_buf[BUFSIZ], *ptr;
924 struct mqelem *top, *elem = NULL;
926 ret_value = SUB_NORMAL; /* initialize ret_value. */
929 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
930 if (stat && stat != MR_NO_MATCH)
932 com_err(program_name, stat, " in get_machine_to_cluster_map.");
935 if (stat == MR_SUCCESS)
937 elem = top = QueueTop(elem);
940 sprintf(temp_buf, "%s is assigned to the following clusters.", name);
941 Put_message(temp_buf);
942 Loop(top, (void (*)(char **)) PrintMCMap);
943 ptr = "Remove this machine from ** ALL ** these clusters?";
944 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
948 Put_message("Aborting...");
960 char **info = elem->q_data;
961 if ((stat = do_mr_query("delete_machine_from_cluster",
962 2, info, NULL, NULL)))
964 ret_value = SUB_ERROR;
965 com_err(program_name, stat,
966 " in delete_machine_from_cluster.");
968 "Machine %s ** NOT ** removed from cluster %s.",
969 info[MAP_MACHINE], info[MAP_CLUSTER]);
970 Put_message(temp_buf);
979 /* Function Name: CheckAndRemoveCnames
980 * Description: This func tests to see if a machine has cnames,
981 * and if so then removes them.
982 * Arguments: name - name of the machine (already Canonicalized).
983 * ask_user- query the user before removing cnames?
984 * Returns: MR_ERROR if machine left with a cname, or mr_error.
987 int CheckAndRemoveCnames(char *name, Bool ask_user)
991 char *args[10], temp_buf[BUFSIZ], *ptr;
992 struct mqelem *top, *elem = NULL;
994 ret_value = SUB_NORMAL;
997 stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem);
998 if (stat && stat != MR_NO_MATCH)
1000 com_err(program_name, stat, " in get_hostalias.");
1003 if (stat == MR_SUCCESS)
1005 elem = top = QueueTop(elem);
1008 sprintf(temp_buf, "%s has the following cnames.", name);
1009 Put_message(temp_buf);
1010 Loop(top, (void (*)(char **)) PrintCname);
1011 ptr = "Remove ** ALL ** these cnames?";
1012 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1016 Put_message("Aborting...");
1028 char **info = elem->q_data;
1029 if ((stat = do_mr_query("delete_hostalias", 2, info,
1032 ret_value = SUB_ERROR;
1033 com_err(program_name, stat, " in delete_hostalias.");
1035 "Cname %s ** NOT ** removed from host %s.",
1037 Put_message(temp_buf);
1039 elem = elem->q_forw;
1046 /* Function Name: RealDeleteMachine
1047 * Description: Actually Deletes the Machine.
1048 * Arguments: info - nescessary information stored as an array of char *'s
1049 * one_machine - a boolean, true if there is only one item in
1054 static void RealDeleteMachine(char **info, Bool one_machine)
1057 char temp_buf[BUFSIZ];
1059 sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
1061 if (!one_machine || Confirm(temp_buf))
1063 if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
1065 if (CheckAndRemoveCnames(info[M_NAME], TRUE) != SUB_ERROR)
1067 if ((stat = do_mr_query("delete_host", 1,
1068 &info[M_NAME], NULL, NULL)))
1070 com_err(program_name, stat, " in DeleteMachine.");
1071 sprintf(temp_buf, "%s ** NOT ** deleted.",
1073 Put_message(temp_buf);
1077 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
1078 Put_message(temp_buf);
1085 /* Function Name: DeleteMachine
1086 * Description: This function removes a machine from the data base.
1087 * Arguments: argc, argv - the machines name int argv[1].
1088 * Returns: DM_NORMAL.
1091 /* Perhaps we should remove the cluster if it has no machine now. */
1093 int DeleteMachine(int argc, char **argv)
1098 tmpname = canonicalize_hostname(strdup(argv[1]));
1099 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
1100 QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
1107 /* Function Name: ShowCname
1108 * Description: This function shows machine aliases
1109 * Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1110 * Returns: DM_NORMAL.
1113 int ShowCname(int argc, char **argv)
1116 char *tmpalias, *tmpname;
1118 tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
1119 tmpname = canonicalize_hostname(strdup(argv[2]));
1120 top = GetMCInfo(CNAME, tmpalias, tmpname);
1121 Put_message(""); /* blank line on screen */
1122 Loop(top, ((void (*)(char **)) PrintCname));
1128 int AddCname(int argc, char **argv)
1133 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1134 args[1] = canonicalize_hostname(strdup(argv[2]));
1135 stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
1141 Put_message("That alias name is already in use.");
1144 Put_message("Permission denied. "
1145 "(Regular users can only add two aliases to a host.");
1148 com_err(program_name, stat, " in add_hostalias");
1154 int DeleteCname(int argc, char **argv)
1159 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1160 args[1] = canonicalize_hostname(strdup(argv[2]));
1161 stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
1163 com_err(program_name, stat, " in delete_hostalias");
1168 /* Function Name: AddMachineToCluster
1169 * Description: This function adds a machine to a cluster
1170 * Arguments: argc, argv - The machine name is argv[1].
1171 * The cluster name in argv[2].
1172 * Returns: DM_NORMAL.
1175 int AddMachineToCluster(int argc, char **argv)
1178 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1179 Bool add_it, one_machine, one_cluster;
1180 struct mqelem *melem, *mtop, *celem, *ctop;
1182 machine = canonicalize_hostname(strdup(argv[1]));
1183 if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
1185 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1187 Put_message(temp_buf);
1191 celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
1192 melem = mtop = GetMCInfo(MACHINE, machine, NULL);
1195 one_machine = (QueueCount(mtop) == 1);
1196 one_cluster = (QueueCount(ctop) == 1);
1198 /* No good way to use QueryLoop() here, sigh */
1202 char **minfo = melem->q_data;
1205 char **cinfo = celem->q_data;
1206 if (one_machine && one_cluster)
1210 sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
1211 minfo[M_NAME], cinfo[C_NAME]);
1212 switch (YesNoQuitQuestion(temp_buf, FALSE))
1221 Put_message("Aborting...");
1229 args[0] = minfo[M_NAME];
1230 args[1] = cinfo[C_NAME];
1231 stat = do_mr_query("add_machine_to_cluster", 2, args,
1238 sprintf(temp_buf, "%s is already in cluster %s",
1239 minfo[M_NAME], cinfo[C_NAME]);
1240 Put_message(temp_buf);
1243 com_err(program_name, stat, " in AddMachineToCluster.");
1247 celem = celem->q_forw;
1249 celem = ctop; /* reset cluster element. */
1250 melem = melem->q_forw;
1257 /* Function Name: RealRemoveMachineFromCluster
1258 * Description: This function actually removes the machine from its
1260 * Arguments: info - all information nescessary to perform the removal.
1261 * one_map - True if there is only one case, and we should
1266 static void RealRemoveMachineFromCluster(char **info, Bool one_map)
1268 char temp_buf[BUFSIZ];
1271 sprintf(temp_buf, "Remove %s from the cluster %s",
1272 info[MAP_MACHINE], info[MAP_CLUSTER]);
1273 if (!one_map || Confirm(temp_buf))
1275 if ((stat = do_mr_query("delete_machine_from_cluster", 2,
1277 com_err(program_name, stat, " in delete_machine_from_cluster");
1280 sprintf(temp_buf, "%s has been removed from the cluster %s.",
1281 info[MAP_MACHINE], info[MAP_CLUSTER]);
1282 Put_message(temp_buf);
1286 Put_message("Machine not removed.");
1289 /* Function Name: RemoveMachineFromCluster
1290 * Description: Removes this machine form a specific cluster.
1291 * Arguments: argc, argv - Name of machine in argv[1].
1292 * Name of cluster in argv[2].
1296 int RemoveMachineFromCluster(int argc, char **argv)
1298 struct mqelem *elem = NULL;
1299 char buf[BUFSIZ], * args[10];
1302 args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
1303 if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
1305 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1306 argv[1], args[MAP_MACHINE]);
1309 args[MAP_CLUSTER] = argv[2];
1310 args[MAP_END] = NULL;
1312 stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1314 if (stat == MR_NO_MATCH)
1316 sprintf(buf, "The machine %s is not is the cluster %s.",
1317 args[MAP_MACHINE], args[MAP_CLUSTER]);
1319 free(args[MAP_MACHINE]);
1322 if (stat != MR_SUCCESS)
1323 com_err(program_name, stat, " in delete_machine_from_cluster");
1325 elem = QueueTop(elem);
1326 QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1327 "Remove this machine from this cluster");
1330 free(args[MAP_MACHINE]);
1334 /* ---------- Subnet Menu -------- */
1336 /* Function Name: ShowSubnetInfo
1337 * Description: Gets information about a subnet given its name.
1338 * Arguments: argc, argc - the name of the subnet in in argv[1].
1339 * Returns: DM_NORMAL.
1342 int ShowSubnetInfo(int argc, char **argv)
1346 top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1347 Loop(top, (void (*)(char **)) PrintSubnetInfo);
1352 /* Function Name: AddSubnet
1353 * Description: Creates a new subnet.
1354 * Arguments: argc, argv - the name of the new subnet is argv[1].
1355 * Returns: DM_NORMAL.
1358 int AddSubnet(int argc, char **argv)
1360 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1364 * Check to see if this subnet already exists.
1366 if (!ValidName(name))
1369 if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
1371 Put_message("This subnet already exists.");
1374 else if (stat != MR_NO_MATCH)
1376 com_err(program_name, stat, " in AddSubnet.");
1379 if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
1381 Put_message("Aborted.");
1387 * Actually create the new Subnet.
1389 if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
1390 com_err(program_name, stat, " in AddSubnet.");
1396 /* Function Name: RealUpdateSubnet
1397 * Description: This function actually performs the subnet update.
1398 * Arguments: info - all information nesc. for updating the subnet.
1399 * junk - an UNUSED boolean.
1403 static void RealUpdateSubnet(char **info, Bool junk)
1406 char **args = AskMCDInfo(info, SUBNET, TRUE);
1409 Put_message("Aborted.");
1412 if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
1413 com_err(program_name, stat, " in UpdateSubnet.");
1415 Put_message("Subnet successfully updated.");
1418 /* Function Name: UpdateSubnet
1419 * Description: This Function Updates a subnet
1420 * Arguments: name of the subnet in argv[1].
1421 * Returns: DM_NORMAL.
1424 int UpdateSubnet(int argc, char **argv)
1427 top = GetMCInfo(SUBNET, argv[1], NULL);
1428 QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1434 /* Function Name: RealDeleteSubnet
1435 * Description: Actually performs the subnet deletion.
1436 * Arguments: info - all information about this subnet.
1437 * one_subnet - If true then there was only one subnet in
1438 * the queue, and we should confirm.
1442 static void RealDeleteSubnet(char **info, Bool one_subnet)
1445 char temp_buf[BUFSIZ];
1448 "Are you sure the you want to delete the subnet %s (y/n) ?",
1450 if (!one_subnet || Confirm(temp_buf))
1452 if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
1454 com_err(program_name, stat, " in delete_subnet.");
1455 sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
1456 Put_message(temp_buf);
1460 sprintf(temp_buf, "subnet %s successfully deleted.",
1462 Put_message(temp_buf);
1467 /* Function Name: DeleteSubnet
1468 * Description: This function removes a subnet from the database.
1469 * Arguments: argc, argv - the name of the subnet is stored in argv[1].
1470 * Returns: DM_NORMAL.
1473 int DeleteSubnet(int argc, char **argv)
1477 top = GetMCInfo(SUBNET, argv[1], NULL);
1478 QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1484 /* ---------- Cluster Menu -------- */
1486 /* Function Name: ShowClusterInfo
1487 * Description: Gets information about a cluser given its name.
1488 * Arguments: argc, argc - the name of the cluster in in argv[1].
1489 * Returns: DM_NORMAL.
1492 int ShowClusterInfo(int argc, char **argv)
1496 top = GetMCInfo(CLUSTER, argv[1], NULL);
1497 Loop(top, (void (*)(char **)) PrintClusterInfo);
1502 /* Function Name: AddCluster
1503 * Description: Creates a new cluster.
1504 * Arguments: argc, argv - the name of the new cluster is argv[1].
1505 * Returns: DM_NORMAL.
1508 int AddCluster(int argc, char **argv)
1510 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1514 * Check to see if this cluster already exists.
1516 if (!ValidName(name))
1519 if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
1521 Put_message("This cluster already exists.");
1524 else if (stat != MR_NO_MATCH)
1526 com_err(program_name, stat, " in AddCluster.");
1529 if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
1531 Put_message("Aborted.");
1537 * Actually create the new Cluster.
1539 if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
1540 com_err(program_name, stat, " in AddCluster.");
1546 /* Function Name: RealUpdateCluster
1547 * Description: This function actually performs the cluster update.
1548 * Arguments: info - all information nesc. for updating the cluster.
1549 * junk - an UNUSED boolean.
1553 static void RealUpdateCluster(char **info, Bool junk)
1556 char **args = AskMCDInfo(info, CLUSTER, TRUE);
1560 Put_message("Aborted.");
1563 if ((stat = do_mr_query("update_cluster", CountArgs(args),
1565 com_err(program_name, stat, " in UpdateCluster.");
1567 Put_message("Cluster successfully updated.");
1570 /* Function Name: UpdateCluster
1571 * Description: This Function Updates a cluster
1572 * Arguments: name of the cluster in argv[1].
1573 * Returns: DM_NORMAL.
1576 int UpdateCluster(int argc, char **argv)
1579 top = GetMCInfo(CLUSTER, argv[1], NULL);
1580 QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1586 /* Function Name: CheckAndRemoveMachine
1587 * Description: This function checks and removes all machines from a
1589 * Arguments: name - name of the cluster.
1590 * ask_first - if TRUE, then we will query the user, before
1592 * Returns: SUB_ERROR if all machines not removed.
1595 int CheckAndRemoveMachines(char *name, Bool ask_first)
1597 int stat, ret_value;
1599 char *args[10], temp_buf[BUFSIZ], *ptr;
1600 struct mqelem *top, *elem = NULL;
1602 ret_value = SUB_NORMAL;
1603 args[MAP_MACHINE] = "*";
1604 args[MAP_CLUSTER] = name;
1605 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1606 if (stat && stat != MR_NO_MATCH)
1608 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1611 if (stat == MR_SUCCESS)
1613 elem = top = QueueTop(elem);
1616 sprintf(temp_buf, "The cluster %s has the following machines in it:",
1618 Put_message(temp_buf);
1621 char **info = elem->q_data;
1622 Print(1, &info[MAP_MACHINE], (char *) NULL);
1623 elem = elem->q_forw;
1625 ptr = "Remove ** ALL ** these machines from this cluster?";
1627 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1631 Put_message("Aborting...");
1644 char **info = elem->q_data;
1645 if ((stat = do_mr_query("delete_machine_from_cluster",
1646 2, info, NULL, NULL)))
1648 ret_value = SUB_ERROR;
1649 com_err(program_name, stat,
1650 " in delete_machine_from_cluster.");
1652 "Machine %s ** NOT ** removed from cluster %s.",
1653 info[MAP_MACHINE], info[MAP_CLUSTER]);
1654 Put_message(temp_buf);
1656 elem = elem->q_forw;
1663 /* Function Name: RealDeleteCluster
1664 * Description: Actually performs the cluster deletion.
1665 * Arguments: info - all information about this cluster.
1666 * one_cluster - If true then there was only one cluster in
1667 * the queue, and we should confirm.
1671 static void RealDeleteCluster(char **info, Bool one_cluster)
1674 char temp_buf[BUFSIZ];
1677 "Are you sure the you want to delete the cluster %s (y/n) ?",
1679 if (!one_cluster || Confirm(temp_buf))
1681 if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
1683 if ((stat = do_mr_query("delete_cluster", 1,
1684 &info[C_NAME], NULL, NULL)))
1686 com_err(program_name, stat, " in delete_cluster.");
1687 sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
1688 Put_message(temp_buf);
1692 sprintf(temp_buf, "cluster %s successfully deleted.",
1694 Put_message(temp_buf);
1700 /* Function Name: DeleteCluster
1701 * Description: This function removes a cluster from the database.
1702 * Arguments: argc, argv - the name of the cluster is stored in argv[1].
1703 * Returns: DM_NORMAL.
1706 int DeleteCluster(int argc, char **argv)
1710 top = GetMCInfo(CLUSTER, argv[1], NULL);
1711 QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1717 /* ----------- Cluster Data Menu -------------- */
1719 /* Function Name: ShowClusterData
1720 * Description: This function shows the services for one cluster.
1721 * Arguments: argc, argv - The name of the cluster is argv[1].
1722 * The label of the data in argv[2].
1723 * Returns: DM_NORMAL.
1726 int ShowClusterData(int argc, char **argv)
1728 struct mqelem *elem, *top;
1731 top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1734 info = elem->q_data;
1735 PrintClusterData(info);
1736 elem = elem->q_forw;
1742 /* Function Name: AddClusterData
1743 * Description: This function adds some data to the cluster.
1744 * Arguments: argv, argc: argv[1] - the name of the cluster.
1745 * argv[2] - the label of the data.
1746 * argv[3] - the data.
1747 * Returns: DM_NORMAL.
1750 int AddClusterData(int argc, char **argv)
1754 if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
1755 com_err(program_name, stat, " in AddClusterData.");
1759 /* Function Name: RealRemoveClusterData
1760 * Description: actually removes the cluster data.
1761 * Arguments: info - all info necessary to remove the cluster, in an array
1763 * one_item - if true then the queue has only one elem and we
1768 static void RealRemoveClusterData(char **info, Bool one_item)
1774 temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1775 PrintClusterData(info);
1776 if (!one_item || Confirm(temp_ptr))
1778 if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
1780 com_err(program_name, stat, " in DeleteClusterData.");
1781 Put_message("Data not removed.");
1784 Put_message("Removal successful.");
1788 /* Function Name: RemoveClusterData
1789 * Description: This function removes data on a given cluster.
1790 * Arguments: argv, argc: argv[1] - the name of the cluster.
1791 * argv[2] - the label of the data.
1792 * argv[3] - the data.
1793 * Returns: DM_NORMAL.
1796 int RemoveClusterData(int argc, char **argv)
1800 top = GetMCInfo(DATA, argv[1], argv[2]);
1801 QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1802 "Remove data from cluster");
1808 /* Function Name: MachineToClusterMap
1809 * Description: This Retrieves the mapping between machine and cluster
1810 * Arguments: argc, argv - argv[1] -> machine name or wildcard.
1811 * argv[2] -> cluster name or wildcard.
1815 int MachineToClusterMap(int argc, char **argv)
1817 struct mqelem *elem, *top;
1818 char *tmpname, temp_buf[256];
1820 tmpname = canonicalize_hostname(strdup(argv[1]));
1821 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
1823 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1825 Put_message(temp_buf);
1827 top = elem = GetMCInfo(MAP, tmpname, argv[2]);
1829 Put_message(""); /* blank line on screen */
1832 char **info = elem->q_data;
1834 elem = elem->q_forw;
1842 /* Function Name: MachineByOwner
1843 * Description: This function prints all machines which are owned by
1844 * a given user or group.
1846 * Returns: DM_NORMAL.
1849 int MachineByOwner(int argc, char **argv)
1851 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
1854 type = strdup("USER");
1855 if (GetTypeFromUser("Type of owner", "ace_type", &type) == SUB_ERROR)
1858 sprintf(buf, "Name of %s", type);
1859 name = strdup(user);
1860 if (GetValueFromUser(buf, &name) == SUB_ERROR)
1863 switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE))
1866 sprintf(temp_buf, "R%s", type); /* "USER to "RUSER", etc. */
1868 type = strdup(temp_buf);
1876 top = GetMachineByOwner(type, name);
1877 Loop(top, PrintMachine);
1883 /* Function Name: GetMachineByOwner
1884 * Description: This function stores information retrieved by
1885 * the get_host_by_owner query
1886 * Arguments: type - an ace_type, argv[0] for the query
1887 * name - name of machine, argv[1] for the query
1888 * Returns: the top element of a queue returning the data, or NULL.
1891 struct mqelem *GetMachineByOwner(char *type, char *name)
1894 struct mqelem *elem = NULL;
1899 if ((status = do_mr_query("get_host_by_owner", 2, args, StoreInfo, &elem)))
1901 com_err(program_name, status, " in get_host_by_owner");
1904 return QueueTop(elem);