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>
25 #include <sys/types.h>
26 #include <sys/utsname.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
37 void PrintAliases(char **info);
38 struct mqelem *GetMCInfo(int type, char *name1, char *name2);
39 char **AskMCDInfo(char **info, int type, Bool name);
40 int CheckAndRemoveFromCluster(char *name, Bool ask_user);
41 int CheckAndRemoveMachines(char *name, Bool ask_first);
42 char *partial_canonicalize_hostname(char *s);
51 #define M_DEFAULT_TYPE DEFAULT_NONE
53 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
54 #define C_DEFAULT_LOCATION DEFAULT_NONE
56 #define CD_DEFAULT_LABEL DEFAULT_NONE
57 #define CD_DEFAULT_DATA DEFAULT_NONE
59 #define S_DEFAULT_LOW "18.0.0.20"
60 #define S_DEFAULT_HIGH "18.0.2.249"
62 static char *states[] = {
69 static char *MacState(int state)
71 static char buf[BUFSIZ];
73 if (state < 0 || state > 3)
75 sprintf(buf, "Unknown (%d)", state);
83 /* -------------------- Set Defaults -------------------- */
85 /* Function Name: SetMachineDefaults
86 * Description: sets machine defaults.
87 * Arguments: info - an array to put the defaults into.
88 * name - Canonacalized name of the machine.
89 * Returns: info - the array.
92 static char **SetMachineDefaults(char **info, char *name)
94 info[M_NAME] = strdup(name);
95 info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
96 info[M_MODEL] = strdup(M_DEFAULT_TYPE);
97 info[M_OS] = strdup(M_DEFAULT_TYPE);
98 info[M_LOC] = strdup(M_DEFAULT_TYPE);
99 info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
100 info[M_USE] = strdup("0");
101 info[M_STAT] = strdup("1");
102 info[M_SUBNET] = strdup("NONE");
103 info[M_ADDR] = strdup("unique");
104 info[M_OWNER_TYPE] = strdup("NONE");
105 info[M_OWNER_NAME] = strdup("NONE");
106 info[M_ACOMMENT] = strdup("");
107 info[M_OCOMMENT] = strdup("");
108 info[15] = info[16] = NULL;
112 /* Function Name: SetClusterDefaults
113 * Description: sets Cluster defaults.
114 * Arguments: info - an array to put the defaults into.
115 * name - name of the Cluster.
116 * Returns: info - the array.
119 static char **SetClusterDefaults(char **info, char *name)
121 info[C_NAME] = strdup(name);
122 info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
123 info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
124 info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
128 /* Function Name: SetSubnetDefaults
129 * Description: sets Subnet defaults.
130 * Arguments: info - an array to put the defaults into.
131 * name - name of the Subnet.
132 * Returns: info - the array.
135 static char **SetSubnetDefaults(char **info, char *name)
139 info[C_NAME] = strdup(name);
140 info[SN_DESC] = strdup("");
141 sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
142 info[SN_ADDRESS] = strdup(buf);
143 sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
144 info[SN_MASK] = strdup(buf);
145 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
146 info[SN_LOW] = strdup(buf);
147 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
148 info[SN_HIGH] = strdup(buf);
149 info[SN_PREFIX] = strdup("");
150 info[SN_ACE_TYPE] = strdup("LIST");
151 info[SN_ACE_NAME] = strdup("network");
152 info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
156 /* -------------------- General Functions -------------------- */
158 static char aliasbuf[256];
160 void PrintAliases(char **info)
162 if (strlen(aliasbuf) == 0)
163 sprintf(aliasbuf, "Aliases: %s", info[0]);
166 strcat(aliasbuf, ", ");
167 strcat(aliasbuf, info[0]);
172 /* Function Name: PrintMachInfo
173 * Description: This function Prints out the Machine info in
175 * Arguments: info - array of information about a machine.
176 * Returns: The name of the Machine
179 static char *PrintMachInfo(char **info)
181 char buf[BUFSIZ], tbuf[256];
183 struct mqelem *elem = NULL;
187 sprintf(buf, "Machine: %s", info[M_NAME]);
190 args[1] = info[M_NAME];
191 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
193 if (stat != MR_NO_MATCH)
194 com_err(program_name, stat, " looking up aliases");
199 Loop(QueueTop(elem), (void *) PrintAliases);
201 Put_message(aliasbuf);
203 sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
204 strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
205 sprintf(buf, "Address: %-16s Network: %-16s",
206 info[M_ADDR], info[M_SUBNET]);
208 sprintf(buf, "Owner: %-16s Use data: %s", tbuf, info[M_INUSE]);
210 sprintf(buf, "Status: %-16s Changed: %s",
211 MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
215 sprintf(buf, "Vendor: %-16s Model: %-20s OS: %s",
216 info[M_VENDOR], info[M_MODEL], info[M_OS]);
218 sprintf(buf, "Location: %-16s Contact: %-20s Opt: %s",
219 info[M_LOC], info[M_CONTACT], info[M_USE]);
221 sprintf(buf, "\nAdm cmt: %s", info[M_ACOMMENT]);
223 sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]);
226 sprintf(buf, "Created by %s on %s", info[M_CREATOR], info[M_CREATED]);
228 sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
233 /* Function Name: PrintCname
234 * Description: Prints the Data on a host alias
235 * Arguments: info a pointer to the data array.
236 * Returns: The name of the alias.
239 static char *PrintCname(char **info)
243 sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
248 /* Function Name: PrintClusterInfo
249 * Description: This function Prints out the cluster info
250 * in a coherent form.
251 * Arguments: info - array of information about a cluster.
252 * Returns: The name of the cluster.
255 static char *PrintClusterInfo(char **info)
260 sprintf(buf, "Cluster: %s", info[C_NAME]);
262 sprintf(buf, "Description: %s", info[C_DESCRIPT]);
264 sprintf(buf, "Location: %s", info[C_LOCATION]);
266 sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
271 /* Function Name: PrintClusterData
272 * Description: Prints the Data on a cluster
273 * Arguments: info a pointer to the data array.
274 * Returns: The name of the cluster.
277 static char *PrintClusterData(char **info)
282 sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
283 info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
285 return info[CD_NAME];
288 /* Function Name: PrintMCMap
289 * Description: Prints the data about a machine to cluster mapping.
290 * Arguments: info a pointer to the data array.
294 static char *PrintMCMap(char **info)
297 sprintf(buf, "Cluster: %-30s Machine: %-20s",
298 info[MAP_CLUSTER], info[MAP_MACHINE]);
300 return ""; /* Used by QueryLoop(). */
303 /* Function Name: PrintSubnetInfo
304 * Description: This function Prints out the subnet info
305 * in a coherent form.
306 * Arguments: info - array of information about a subnet.
307 * Returns: The name of the subnet.
310 static char *PrintSubnetInfo(char **info)
313 struct in_addr addr, mask, low, high;
316 sprintf(buf, " Network: %s", info[SN_NAME]);
318 sprintf(buf, " Description: %s", info[SN_DESC]);
320 addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
321 mask.s_addr = htonl(atoi(info[SN_MASK]));
322 low.s_addr = htonl(atoi(info[SN_LOW]));
323 high.s_addr = htonl(atoi(info[SN_HIGH]));
324 /* screwy sequence is here because inet_ntoa returns a pointer to
325 a static buf. If it were all one sprintf, the last value would
327 sprintf(buf, " Address: %s Mask: ", inet_ntoa(addr));
328 strcat(buf, inet_ntoa(mask));
329 strcat(buf, "\n High: ");
330 strcat(buf, inet_ntoa(high));
331 strcat(buf, " Low: ");
332 strcat(buf, inet_ntoa(low));
334 sprintf(buf, "Hostname prefix: %s", info[SN_PREFIX]);
336 sprintf(buf, " Owner: %s %s\n", info[SN_ACE_TYPE],
337 strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
339 sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
341 return info[SN_NAME];
344 /* Function Name: GetMCInfo.
345 * Description: This function stores info about a machine.
346 * type - type of data we are trying to retrieve.
347 * name1 - the name of argv[0] for the call.
348 * name2 - the name of argv[1] for the call.
349 * Returns: the top element of a queue containing the data or NULL.
352 struct mqelem *GetMCInfo(int type, char *name1, char *name2)
355 struct mqelem *elem = NULL;
362 args[1] = args[2] = args[3] = "*";
363 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
365 if (stat == MR_NO_MATCH)
368 sprintf(buf, "Machine '%s' is not in the database.", name1);
372 com_err(program_name, stat, " in get_machine.");
379 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
381 com_err(program_name, stat, " in get_hostalias.");
386 if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
388 if (stat == MR_NO_MATCH)
391 sprintf(buf, "Network '%s' is not in the database.", name1);
395 com_err(program_name, stat, " in get_subnet.");
400 if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
402 com_err(program_name, stat, " in get_cluster.");
407 args[MAP_MACHINE] = name1;
408 args[MAP_CLUSTER] = name2;
409 if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
412 com_err(program_name, stat, " in get_machine_to_cluster_map.");
417 args[CD_NAME] = name1;
418 args[CD_LABEL] = name2;
419 if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
421 com_err(program_name, stat, " in get_cluster_data.");
425 return QueueTop(elem);
428 /* Function Name: AskMCDInfo.
429 * Description: This function askes the user for information about a
430 * machine and saves it into a structure.
431 * Arguments: info - a pointer the information to ask about
432 * type - type of information - MACHINE
435 * name - T/F : change the name of this type.
439 char **AskMCDInfo(char **info, int type, Bool name)
441 char temp_buf[BUFSIZ], *newname, *oldnewname;
446 sprintf(temp_buf, "\nSetting the information for the Machine %s...",
450 sprintf(temp_buf, "Setting the information for the Network %s...",
454 sprintf(temp_buf, "Setting the information for the Cluster %s...",
458 sprintf(temp_buf, "Setting the Data for the Cluster %s...",
462 Put_message(temp_buf);
469 newname = strdup(info[M_NAME]);
470 if (GetValueFromUser("The new name for this machine? ", &newname) ==
473 oldnewname = strdup(newname);
474 newname = canonicalize_hostname(newname);
475 if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
477 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
478 oldnewname, newname);
479 Put_message(temp_buf);
484 newname = strdup(info[SN_NAME]);
485 if (GetValueFromUser("The new name for this network? ", &newname) ==
490 newname = strdup(info[C_NAME]);
491 if (GetValueFromUser("The new name for this cluster? ", &newname) ==
496 Put_message("Unknown type in AskMCDInfo, programmer botch");
504 if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
506 if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
508 if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
511 if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
513 if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
519 if (GetValueFromUser("Machine's status (? for help)",
520 &info[M_STAT]) == SUB_ERROR)
522 if (isdigit(info[M_STAT][0]))
524 Put_message("Valid status numbers:");
525 for (i = 0; i < 4; i++)
526 Put_message(states[i]);
529 /* there appears to be some argument mismatch between the client
530 * and the server.. so here is this argument shuffler.
531 * I have since modified this to always shuffle the arguments..
532 * not just do so when performing a modify all fields request.
533 * The SetMachinedefaults() has been changed to reflect this.
534 * pray for us and may we attain enlightenment through structures.
539 /* info did not come from SetMachineDefaults(), which does not
540 * initialize entry 8 (M_STAT_CHNG), therefore we can
543 /* This is an update of an existing machine and the structure
544 * was filled in thru a query to the db which does fill in this
550 info[8] = info[M_SUBNET];
551 info[9] = info[M_ADDR];
552 info[10] = info[M_OWNER_TYPE];
553 info[11] = info[M_OWNER_NAME];
554 info[12] = info[M_ACOMMENT];
555 info[13] = info[M_OCOMMENT];
559 if (GetValueFromUser("Machine's network (or 'none')", &info[8])
563 if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
564 &info[9]) == SUB_ERROR)
566 if (GetTypeFromUser("Machine's owner type", "ace_type", &info[10]) ==
569 if (strcmp(info[10], "NONE") &&
570 GetValueFromUser("Owner's Name", &info[11]) == SUB_ERROR)
572 if (GetValueFromUser("Administrative comment", &info[12]) == SUB_ERROR)
574 if (GetValueFromUser("Operational comment", &info[13]) == SUB_ERROR)
577 FreeAndClear(&info[15], TRUE);
578 FreeAndClear(&info[16], TRUE);
581 if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
583 if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
585 if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
587 if (atoi(info[SN_LOW]) == ntohl(inet_addr(S_DEFAULT_LOW)))
590 unsigned long mask, addr;
592 addr = atoi(info[SN_ADDRESS]);
593 mask = atoi(info[SN_MASK]);
594 low.s_addr = atoi(info[SN_LOW]);
595 low.s_addr = (low.s_addr & ~mask) | (addr & mask);
597 sprintf(temp_buf, "%ld", low.s_addr);
598 info[SN_LOW] = strdup(temp_buf);
600 if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
603 if (atoi(info[SN_HIGH]) == ntohl(inet_addr(S_DEFAULT_HIGH)))
606 unsigned long mask, addr;
608 addr = atoi(info[SN_ADDRESS]);
609 mask = atoi(info[SN_MASK]);
610 high.s_addr = atoi(info[SN_HIGH]);
611 high.s_addr = (high.s_addr & ~mask) | (addr & mask);
613 sprintf(temp_buf, "%ld", high.s_addr);
614 info[SN_HIGH] = strdup(temp_buf);
616 if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
619 if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
621 if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
624 if (strcmp(info[SN_ACE_TYPE], "NONE") &&
625 GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
627 FreeAndClear(&info[SN_MODTIME], TRUE);
628 FreeAndClear(&info[SN_MODBY], TRUE);
629 FreeAndClear(&info[SN_MODWITH], TRUE);
632 if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
635 if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
638 FreeAndClear(&info[C_MODTIME], TRUE);
639 FreeAndClear(&info[C_MODBY], TRUE);
640 FreeAndClear(&info[C_MODWITH], TRUE);
643 if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
646 if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
652 * Slide the newname into the #2 slot, this screws up all future references
656 SlipInNewName(info, newname);
661 /* ----------- Machine Menu ----------- */
663 /* Function Name: ShowMachineInfo
664 * Description: This function shows the information about a machine.
665 * Arguments: argc, argv - the name of the machine in argv[1].
666 * Returns: DM_NORMAL.
669 int ShowMachineInfo(int argc, char **argv)
674 tmpname = canonicalize_hostname(strdup(argv[1]));
675 top = GetMCInfo(MACHINE, tmpname, NULL);
676 Loop(top, ((void *) PrintMachInfo));
681 /* Function Name: ShowMachineQuery
682 * Description: This function shows the information about a machine.
683 * or group of machines, which may be selected through a
684 * number of criteria.
685 * Arguments: argc, argv - the name of the machine in argv[1],
686 * the address of the machine in argv[2],
687 * the location of the machine in argv[3],
688 * and the contact name in argv[4].
689 * any of these may be wildcards.
690 * Returns: DM_NORMAL.
693 int ShowMachineQuery(int argc, char **argv)
696 struct mqelem *top, *elem = NULL;
699 if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
700 !strcmp(argv[3], "") && !strcmp(argv[4], ""))
702 Put_message("You must specify at least one parameter of the query.");
707 args[0] = canonicalize_hostname(strdup(argv[1]));
723 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
725 if (stat == MR_NO_MATCH)
726 Put_message("No machine(s) found matching query in the database.");
728 com_err(program_name, stat, " in get_machine.");
731 top = QueueTop(elem);
732 Loop(top, ((void *) PrintMachInfo));
737 /* Function Name: AddMachine
738 * Description: This function adds a new machine to the database.
739 * Arguments: argc, argv - the name of the network in argv[1].
740 * Returns: DM_NORMAL.
743 int AddMachine(int argc, char **argv)
745 char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
747 struct mqelem *elem = NULL;
750 if (!ValidName(argv[1])) /* Checks for wildcards. */
754 * get the network record
757 if (strcasecmp(argv[1], "none") &&
758 (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
760 if (stat == MR_NO_MATCH)
763 sprintf(buf, "Network '%s' is not in the database.", argv[1]);
766 com_err(program_name, stat, " in get_subnet.");
771 * Check to see if this machine already exists.
774 name = strdup(""); /* want to put prefix here */
775 if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
778 name = canonicalize_hostname(strdup(name));
781 xargs[1] = xargs[2] = xargs[3] = "*";
782 if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
784 sprintf(buf, "The machine '%s' already exists.", name);
789 else if (stat != MR_NO_MATCH)
791 com_err(program_name, stat,
792 " while checking machine '%s' in AddMachine.", name);
796 rinfo = SetMachineDefaults(info, name);
797 rinfo[M_SUBNET] = strdup(argv[1]);
798 if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
800 Put_message("Aborted.");
805 * Actually create the new Machine.
808 if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
809 com_err(program_name, stat, " in AddMachine.");
816 /* Function Name: RealUpdateMachine
817 * Description: Performs the actual update of the machine data.
818 * Arguments: info - the information on the machine to update.
819 * junk - an UNUSED Boolean.
823 static void RealUpdateMachine(char **info, Bool junk)
826 char **args = AskMCDInfo(info, MACHINE, TRUE);
829 Put_message("Aborted.");
832 if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
833 com_err(program_name, stat, " in UpdateMachine.");
835 Put_message("Machine successfully updated.");
838 /* Function Name: UpdateMachine
839 * Description: This function adds a new machine to the database.
840 * Arguments: argc, argv - the name of the machine in argv[1].
841 * Returns: DM_NORMAL.
844 int UpdateMachine(int argc, char **argv)
849 tmpname = canonicalize_hostname(strdup(argv[1]));
850 top = GetMCInfo(MACHINE, tmpname, NULL);
851 QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
858 /* Function Name: CheckAndRemoveFromCluster
859 * Description: This func tests to see if a machine is in a cluster.
860 * and if so then removes it
861 * Arguments: name - name of the machine (already Canonocalized).
862 * ask_user- query the user before removing if from clusters?
863 * Returns: MR_ERROR if machine left in a cluster, or mr_error.
866 int CheckAndRemoveFromCluster(char *name, Bool ask_user)
870 char *args[10], temp_buf[BUFSIZ], *ptr;
871 struct mqelem *top, *elem = NULL;
873 ret_value = SUB_NORMAL; /* initialize ret_value. */
876 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
877 if (stat && stat != MR_NO_MATCH)
879 com_err(program_name, stat, " in get_machine_to_cluster_map.");
882 if (stat == MR_SUCCESS)
884 elem = top = QueueTop(elem);
887 sprintf(temp_buf, "%s is assigned to the following clusters.", name);
888 Put_message(temp_buf);
889 Loop(top, (void *) PrintMCMap);
890 ptr = "Remove this machine from ** ALL ** these clusters?";
891 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
895 Put_message("Aborting...");
907 char **info = elem->q_data;
908 if ((stat = do_mr_query("delete_machine_from_cluster",
909 2, info, NULL, NULL)))
911 ret_value = SUB_ERROR;
912 com_err(program_name, stat,
913 " in delete_machine_from_cluster.");
915 "Machine %s ** NOT ** removed from cluster %s.",
916 info[MAP_MACHINE], info[MAP_CLUSTER]);
917 Put_message(temp_buf);
926 /* Function Name: RealDeleteMachine
927 * Description: Actually Deletes the Machine.
928 * Arguments: info - nescessary information stored as an array of char *'s
929 * one_machine - a boolean, true if there is only one item in
934 static void RealDeleteMachine(char **info, Bool one_machine)
937 char temp_buf[BUFSIZ];
939 sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
941 if (!one_machine || Confirm(temp_buf))
943 if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
945 if ((stat = do_mr_query("delete_host", 1,
946 &info[M_NAME], NULL, NULL)))
948 com_err(program_name, stat, " in DeleteMachine.");
949 sprintf(temp_buf, "%s ** NOT ** deleted.",
951 Put_message(temp_buf);
955 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
956 Put_message(temp_buf);
962 /* Function Name: DeleteMachine
963 * Description: This function removes a machine from the data base.
964 * Arguments: argc, argv - the machines name int argv[1].
965 * Returns: DM_NORMAL.
968 /* Perhaps we should remove the cluster if it has no machine now. */
970 int DeleteMachine(int argc, char **argv)
975 tmpname = canonicalize_hostname(strdup(argv[1]));
976 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
977 QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
984 char *partial_canonicalize_hostname(char *s)
987 static char *def_domain = NULL;
994 hp = gethostbyname(name.nodename);
995 cp = strchr(hp->h_name, '.');
997 def_domain = strdup(++cp);
1002 if (strchr(s, '.') || strchr(s, '*'))
1004 sprintf(buf, "%s.%s", s, def_domain);
1010 /* Function Name: ShowCname
1011 * Description: This function shows machine aliases
1012 * Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1013 * Returns: DM_NORMAL.
1016 int ShowCname(int argc, char **argv)
1019 char *tmpalias, *tmpname;
1021 tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
1022 tmpname = canonicalize_hostname(strdup(argv[2]));
1023 top = GetMCInfo(CNAME, tmpalias, tmpname);
1024 Put_message(""); /* blank line on screen */
1025 Loop(top, ((void *) PrintCname));
1031 int AddCname(int argc, char **argv)
1036 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1037 args[1] = canonicalize_hostname(strdup(argv[2]));
1038 stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
1044 Put_message("That alias name is already in use.");
1047 Put_message("Permission denied. "
1048 "(Regular users can only add two aliases to a host.");
1051 com_err(program_name, stat, " in add_hostalias");
1057 int DeleteCname(int argc, char **argv)
1062 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1063 args[1] = canonicalize_hostname(strdup(argv[2]));
1064 stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
1066 com_err(program_name, stat, " in delete_hostalias");
1071 /* Function Name: AddMachineToCluster
1072 * Description: This function adds a machine to a cluster
1073 * Arguments: argc, argv - The machine name is argv[1].
1074 * The cluster name in argv[2].
1075 * Returns: DM_NORMAL.
1078 int AddMachineToCluster(int argc, char **argv)
1081 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1082 Bool add_it, one_machine, one_cluster;
1083 struct mqelem *melem, *mtop, *celem, *ctop;
1085 machine = canonicalize_hostname(strdup(argv[1]));
1086 if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
1088 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1090 Put_message(temp_buf);
1094 celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
1095 melem = mtop = GetMCInfo(MACHINE, machine, NULL);
1098 one_machine = (QueueCount(mtop) == 1);
1099 one_cluster = (QueueCount(ctop) == 1);
1101 /* No good way to use QueryLoop() here, sigh */
1105 char **minfo = melem->q_data;
1108 char **cinfo = celem->q_data;
1109 if (one_machine && one_cluster)
1113 sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
1114 minfo[M_NAME], cinfo[C_NAME]);
1115 switch (YesNoQuitQuestion(temp_buf, FALSE))
1124 Put_message("Aborting...");
1132 args[0] = minfo[M_NAME];
1133 args[1] = cinfo[C_NAME];
1134 stat = do_mr_query("add_machine_to_cluster", 2, args,
1141 sprintf(temp_buf, "%s is already in cluster %s",
1142 minfo[M_NAME], cinfo[C_NAME]);
1143 Put_message(temp_buf);
1146 com_err(program_name, stat, " in AddMachineToCluster.");
1150 celem = celem->q_forw;
1152 celem = ctop; /* reset cluster element. */
1153 melem = melem->q_forw;
1160 /* Function Name: RealRemoveMachineFromCluster
1161 * Description: This function actually removes the machine from its
1163 * Arguments: info - all information nescessary to perform the removal.
1164 * one_map - True if there is only one case, and we should
1169 static void RealRemoveMachineFromCluster(char **info, Bool one_map)
1171 char temp_buf[BUFSIZ];
1174 sprintf(temp_buf, "Remove %s from the cluster %s",
1175 info[MAP_MACHINE], info[MAP_CLUSTER]);
1176 if (!one_map || Confirm(temp_buf))
1178 if ((stat = do_mr_query("delete_machine_from_cluster", 2,
1180 com_err(program_name, stat, " in delete_machine_from_cluster");
1183 sprintf(temp_buf, "%s has been removed from the cluster %s.",
1184 info[MAP_MACHINE], info[MAP_CLUSTER]);
1185 Put_message(temp_buf);
1189 Put_message("Machine not removed.");
1192 /* Function Name: RemoveMachineFromCluster
1193 * Description: Removes this machine form a specific cluster.
1194 * Arguments: argc, argv - Name of machine in argv[1].
1195 * Name of cluster in argv[2].
1199 int RemoveMachineFromCluster(int argc, char **argv)
1201 struct mqelem *elem = NULL;
1202 char buf[BUFSIZ], * args[10];
1205 args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
1206 if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
1208 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1209 argv[1], args[MAP_MACHINE]);
1212 args[MAP_CLUSTER] = argv[2];
1213 args[MAP_END] = NULL;
1215 stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1217 if (stat == MR_NO_MATCH)
1219 sprintf(buf, "The machine %s is not is the cluster %s.",
1220 args[MAP_MACHINE], args[MAP_CLUSTER]);
1222 free(args[MAP_MACHINE]);
1225 if (stat != MR_SUCCESS)
1226 com_err(program_name, stat, " in delete_machine_from_cluster");
1228 elem = QueueTop(elem);
1229 QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1230 "Remove this machine from this cluster");
1233 free(args[MAP_MACHINE]);
1237 /* ---------- Subnet Menu -------- */
1239 /* Function Name: ShowSubnetInfo
1240 * Description: Gets information about a subnet given its name.
1241 * Arguments: argc, argc - the name of the subnet in in argv[1].
1242 * Returns: DM_NORMAL.
1245 int ShowSubnetInfo(int argc, char **argv)
1249 top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1250 Loop(top, (void *) PrintSubnetInfo);
1255 /* Function Name: AddSubnet
1256 * Description: Creates a new subnet.
1257 * Arguments: argc, argv - the name of the new subnet is argv[1].
1258 * Returns: DM_NORMAL.
1261 int AddSubnet(int argc, char **argv)
1263 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1267 * Check to see if this subnet already exists.
1269 if (!ValidName(name))
1272 if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
1274 Put_message("This subnet already exists.");
1277 else if (stat != MR_NO_MATCH)
1279 com_err(program_name, stat, " in AddSubnet.");
1282 if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
1284 Put_message("Aborted.");
1290 * Actually create the new Subnet.
1292 if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
1293 com_err(program_name, stat, " in AddSubnet.");
1299 /* Function Name: RealUpdateSubnet
1300 * Description: This function actually performs the subnet update.
1301 * Arguments: info - all information nesc. for updating the subnet.
1302 * junk - an UNUSED boolean.
1306 static void RealUpdateSubnet(char **info, Bool junk)
1309 char **args = AskMCDInfo(info, SUBNET, TRUE);
1312 Put_message("Aborted.");
1315 if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
1316 com_err(program_name, stat, " in UpdateSubnet.");
1318 Put_message("Subnet successfully updated.");
1321 /* Function Name: UpdateSubnet
1322 * Description: This Function Updates a subnet
1323 * Arguments: name of the subnet in argv[1].
1324 * Returns: DM_NORMAL.
1327 int UpdateSubnet(int argc, char **argv)
1330 top = GetMCInfo(SUBNET, argv[1], NULL);
1331 QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1337 /* Function Name: RealDeleteSubnet
1338 * Description: Actually performs the subnet deletion.
1339 * Arguments: info - all information about this subnet.
1340 * one_subnet - If true then there was only one subnet in
1341 * the queue, and we should confirm.
1345 static void RealDeleteSubnet(char **info, Bool one_subnet)
1348 char temp_buf[BUFSIZ];
1351 "Are you sure the you want to delete the subnet %s (y/n) ?",
1353 if (!one_subnet || Confirm(temp_buf))
1355 if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
1357 com_err(program_name, stat, " in delete_subnet.");
1358 sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
1359 Put_message(temp_buf);
1363 sprintf(temp_buf, "subnet %s successfully deleted.",
1365 Put_message(temp_buf);
1370 /* Function Name: DeleteSubnet
1371 * Description: This function removes a subnet from the database.
1372 * Arguments: argc, argv - the name of the subnet is stored in argv[1].
1373 * Returns: DM_NORMAL.
1376 int DeleteSubnet(int argc, char **argv)
1380 top = GetMCInfo(SUBNET, argv[1], NULL);
1381 QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1387 /* ---------- Cluster Menu -------- */
1389 /* Function Name: ShowClusterInfo
1390 * Description: Gets information about a cluser given its name.
1391 * Arguments: argc, argc - the name of the cluster in in argv[1].
1392 * Returns: DM_NORMAL.
1395 int ShowClusterInfo(int argc, char **argv)
1399 top = GetMCInfo(CLUSTER, argv[1], NULL);
1400 Loop(top, (void *) PrintClusterInfo);
1405 /* Function Name: AddCluster
1406 * Description: Creates a new cluster.
1407 * Arguments: argc, argv - the name of the new cluster is argv[1].
1408 * Returns: DM_NORMAL.
1411 int AddCluster(int argc, char **argv)
1413 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1417 * Check to see if this cluster already exists.
1419 if (!ValidName(name))
1422 if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
1424 Put_message("This cluster already exists.");
1427 else if (stat != MR_NO_MATCH)
1429 com_err(program_name, stat, " in AddCluster.");
1432 if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
1434 Put_message("Aborted.");
1440 * Actually create the new Cluster.
1442 if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
1443 com_err(program_name, stat, " in AddCluster.");
1449 /* Function Name: RealUpdateCluster
1450 * Description: This function actually performs the cluster update.
1451 * Arguments: info - all information nesc. for updating the cluster.
1452 * junk - an UNUSED boolean.
1456 static void RealUpdateCluster(char **info, Bool junk)
1459 char **args = AskMCDInfo(info, CLUSTER, TRUE);
1463 Put_message("Aborted.");
1466 if ((stat = do_mr_query("update_cluster", CountArgs(args),
1468 com_err(program_name, stat, " in UpdateCluster.");
1470 Put_message("Cluster successfully updated.");
1473 /* Function Name: UpdateCluster
1474 * Description: This Function Updates a cluster
1475 * Arguments: name of the cluster in argv[1].
1476 * Returns: DM_NORMAL.
1479 int UpdateCluster(int argc, char **argv)
1482 top = GetMCInfo(CLUSTER, argv[1], NULL);
1483 QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1489 /* Function Name: CheckAndRemoveMachine
1490 * Description: This function checks and removes all machines from a
1492 * Arguments: name - name of the cluster.
1493 * ask_first - if TRUE, then we will query the user, before
1495 * Returns: SUB_ERROR if all machines not removed.
1498 int CheckAndRemoveMachines(char *name, Bool ask_first)
1500 int stat, ret_value;
1502 char *args[10], temp_buf[BUFSIZ], *ptr;
1503 struct mqelem *top, *elem = NULL;
1505 ret_value = SUB_NORMAL;
1506 args[MAP_MACHINE] = "*";
1507 args[MAP_CLUSTER] = name;
1508 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1509 if (stat && stat != MR_NO_MATCH)
1511 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1514 if (stat == MR_SUCCESS)
1516 elem = top = QueueTop(elem);
1519 sprintf(temp_buf, "The cluster %s has the following machines in it:",
1521 Put_message(temp_buf);
1524 char **info = elem->q_data;
1525 Print(1, &info[MAP_MACHINE], (char *) NULL);
1526 elem = elem->q_forw;
1528 ptr = "Remove ** ALL ** these machines from this cluster?";
1530 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1534 Put_message("Aborting...");
1547 char **info = elem->q_data;
1548 if ((stat = do_mr_query("delete_machine_from_cluster",
1549 2, info, NULL, NULL)))
1551 ret_value = SUB_ERROR;
1552 com_err(program_name, stat,
1553 " in delete_machine_from_cluster.");
1555 "Machine %s ** NOT ** removed from cluster %s.",
1556 info[MAP_MACHINE], info[MAP_CLUSTER]);
1557 Put_message(temp_buf);
1559 elem = elem->q_forw;
1566 /* Function Name: RealDeleteCluster
1567 * Description: Actually performs the cluster deletion.
1568 * Arguments: info - all information about this cluster.
1569 * one_cluster - If true then there was only one cluster in
1570 * the queue, and we should confirm.
1574 static void RealDeleteCluster(char **info, Bool one_cluster)
1577 char temp_buf[BUFSIZ];
1580 "Are you sure the you want to delete the cluster %s (y/n) ?",
1582 if (!one_cluster || Confirm(temp_buf))
1584 if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
1586 if ((stat = do_mr_query("delete_cluster", 1,
1587 &info[C_NAME], NULL, NULL)))
1589 com_err(program_name, stat, " in delete_cluster.");
1590 sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
1591 Put_message(temp_buf);
1595 sprintf(temp_buf, "cluster %s successfully deleted.",
1597 Put_message(temp_buf);
1603 /* Function Name: DeleteCluster
1604 * Description: This function removes a cluster from the database.
1605 * Arguments: argc, argv - the name of the cluster is stored in argv[1].
1606 * Returns: DM_NORMAL.
1609 int DeleteCluster(int argc, char **argv)
1613 top = GetMCInfo(CLUSTER, argv[1], NULL);
1614 QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1620 /* ----------- Cluster Data Menu -------------- */
1622 /* Function Name: ShowClusterData
1623 * Description: This function shows the services for one cluster.
1624 * Arguments: argc, argv - The name of the cluster is argv[1].
1625 * The label of the data in argv[2].
1626 * Returns: DM_NORMAL.
1629 int ShowClusterData(int argc, char **argv)
1631 struct mqelem *elem, *top;
1634 top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1637 info = elem->q_data;
1638 PrintClusterData(info);
1639 elem = elem->q_forw;
1645 /* Function Name: AddClusterData
1646 * Description: This function adds some data to the cluster.
1647 * Arguments: argv, argc: argv[1] - the name of the cluster.
1648 * argv[2] - the label of the data.
1649 * argv[3] - the data.
1650 * Returns: DM_NORMAL.
1653 int AddClusterData(int argc, char **argv)
1657 if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
1658 com_err(program_name, stat, " in AddClusterData.");
1662 /* Function Name: RealRemoveClusterData
1663 * Description: actually removes the cluster data.
1664 * Arguments: info - all info necessary to remove the cluster, in an array
1666 * one_item - if true then the queue has only one elem and we
1671 static void RealRemoveClusterData(char **info, Bool one_item)
1677 temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1678 PrintClusterData(info);
1679 if (!one_item || Confirm(temp_ptr))
1681 if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
1683 com_err(program_name, stat, " in DeleteClusterData.");
1684 Put_message("Data not removed.");
1687 Put_message("Removal successful.");
1691 /* Function Name: RemoveClusterData
1692 * Description: This function removes data on a given cluster.
1693 * Arguments: argv, argc: argv[1] - the name of the cluster.
1694 * argv[2] - the label of the data.
1695 * argv[3] - the data.
1696 * Returns: DM_NORMAL.
1699 int RemoveClusterData(int argc, char **argv)
1703 top = GetMCInfo(DATA, argv[1], argv[2]);
1704 QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1705 "Remove data from cluster");
1711 /* Function Name: MachineToClusterMap
1712 * Description: This Retrieves the mapping between machine and cluster
1713 * Arguments: argc, argv - argv[1] -> machine name or wildcard.
1714 * argv[2] -> cluster name or wildcard.
1718 int MachineToClusterMap(int argc, char **argv)
1720 struct mqelem *elem, *top;
1721 char *tmpname, temp_buf[256];
1723 tmpname = canonicalize_hostname(strdup(argv[1]));
1724 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
1726 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1728 Put_message(temp_buf);
1730 top = elem = GetMCInfo(MAP, tmpname, argv[2]);
1732 Put_message(""); /* blank line on screen */
1735 char **info = elem->q_data;
1737 elem = elem->q_forw;