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/utsname.h>
27 #include <netinet/in.h>
28 #include <arpa/inet.h>
36 void PrintAliases(char **info);
37 struct qelem *GetMCInfo(int type, char *name1, char *name2);
38 char **AskMCDInfo(char **info, int type, Bool name);
39 int CheckAndRemoveFromCluster(char *name, Bool ask_user);
40 int CheckAndRemoveMachines(char *name, Bool ask_first);
41 char *partial_canonicalize_hostname(char *s);
50 #define M_DEFAULT_TYPE DEFAULT_NONE
52 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
53 #define C_DEFAULT_LOCATION DEFAULT_NONE
55 #define CD_DEFAULT_LABEL DEFAULT_NONE
56 #define CD_DEFAULT_DATA DEFAULT_NONE
58 #define S_DEFAULT_LOW "18.0.0.20"
59 #define S_DEFAULT_HIGH "18.0.2.249"
61 static char *states[] = {
68 static char *MacState(int state)
70 static char buf[BUFSIZ];
72 if (state < 0 || state > 3)
74 sprintf(buf, "Unknown (%d)", state);
82 /* -------------------- Set Defaults -------------------- */
84 /* Function Name: SetMachineDefaults
85 * Description: sets machine defaults.
86 * Arguments: info - an array to put the defaults into.
87 * name - Canonacalized name of the machine.
88 * Returns: info - the array.
91 static char **SetMachineDefaults(char **info, char *name)
93 info[M_NAME] = strdup(name);
94 info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
95 info[M_MODEL] = strdup(M_DEFAULT_TYPE);
96 info[M_OS] = strdup(M_DEFAULT_TYPE);
97 info[M_LOC] = strdup(M_DEFAULT_TYPE);
98 info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
99 info[M_USE] = strdup("0");
100 info[M_STAT] = strdup("1");
101 info[M_SUBNET] = strdup("NONE");
102 info[M_ADDR] = strdup("unique");
103 info[M_OWNER_TYPE] = strdup("NONE");
104 info[M_OWNER_NAME] = strdup("NONE");
105 info[M_ACOMMENT] = strdup("");
106 info[M_OCOMMENT] = strdup("");
107 info[15] = info[16] = NULL;
111 /* Function Name: SetClusterDefaults
112 * Description: sets Cluster defaults.
113 * Arguments: info - an array to put the defaults into.
114 * name - name of the Cluster.
115 * Returns: info - the array.
118 static char **SetClusterDefaults(char **info, char *name)
120 info[C_NAME] = strdup(name);
121 info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
122 info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
123 info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
127 /* Function Name: SetSubnetDefaults
128 * Description: sets Subnet defaults.
129 * Arguments: info - an array to put the defaults into.
130 * name - name of the Subnet.
131 * Returns: info - the array.
134 static char **SetSubnetDefaults(char **info, char *name)
138 info[C_NAME] = strdup(name);
139 info[SN_DESC] = strdup("");
140 sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
141 info[SN_ADDRESS] = strdup(buf);
142 sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
143 info[SN_MASK] = strdup(buf);
144 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
145 info[SN_LOW] = strdup(buf);
146 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
147 info[SN_HIGH] = strdup(buf);
148 info[SN_PREFIX] = strdup("");
149 info[SN_ACE_TYPE] = strdup("LIST");
150 info[SN_ACE_NAME] = strdup("network");
151 info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
155 /* -------------------- General Functions -------------------- */
157 static char aliasbuf[256];
159 void PrintAliases(char **info)
161 if (strlen(aliasbuf) == 0)
162 sprintf(aliasbuf, "Aliases: %s", info[0]);
165 strcat(aliasbuf, ", ");
166 strcat(aliasbuf, info[0]);
171 /* Function Name: PrintMachInfo
172 * Description: This function Prints out the Machine info in
174 * Arguments: info - array of information about a machine.
175 * Returns: The name of the Machine
178 static char *PrintMachInfo(char **info)
180 char buf[BUFSIZ], tbuf[256];
182 struct qelem *elem = NULL;
186 sprintf(buf, "Machine: %s", info[M_NAME]);
189 args[1] = info[M_NAME];
190 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
192 if (stat != MR_NO_MATCH)
193 com_err(program_name, stat, " looking up aliases");
198 Loop(QueueTop(elem), (void *) PrintAliases);
200 Put_message(aliasbuf);
202 sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
203 strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
204 sprintf(buf, "Address: %-16s Network: %-16s",
205 info[M_ADDR], info[M_SUBNET]);
207 sprintf(buf, "Owner: %-16s Use data: %s", tbuf, info[M_INUSE]);
209 sprintf(buf, "Status: %-16s Changed: %s",
210 MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
214 sprintf(buf, "Vendor: %-16s Model: %-20s OS: %s",
215 info[M_VENDOR], info[M_MODEL], info[M_OS]);
217 sprintf(buf, "Location: %-16s Contact: %-20s Opt: %s",
218 info[M_LOC], info[M_CONTACT], info[M_USE]);
220 sprintf(buf, "\nAdm cmt: %s", info[M_ACOMMENT]);
222 sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]);
225 sprintf(buf, "Created by %s on %s", info[M_CREATOR], info[M_CREATED]);
227 sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
232 /* Function Name: PrintCname
233 * Description: Prints the Data on a host alias
234 * Arguments: info a pointer to the data array.
235 * Returns: The name of the alias.
238 static char *PrintCname(char **info)
242 sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
247 /* Function Name: PrintClusterInfo
248 * Description: This function Prints out the cluster info
249 * in a coherent form.
250 * Arguments: info - array of information about a cluster.
251 * Returns: The name of the cluster.
254 static char *PrintClusterInfo(char **info)
259 sprintf(buf, "Cluster: %s", info[C_NAME]);
261 sprintf(buf, "Description: %s", info[C_DESCRIPT]);
263 sprintf(buf, "Location: %s", info[C_LOCATION]);
265 sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
270 /* Function Name: PrintClusterData
271 * Description: Prints the Data on a cluster
272 * Arguments: info a pointer to the data array.
273 * Returns: The name of the cluster.
276 static char *PrintClusterData(char **info)
281 sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
282 info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
284 return info[CD_NAME];
287 /* Function Name: PrintMCMap
288 * Description: Prints the data about a machine to cluster mapping.
289 * Arguments: info a pointer to the data array.
293 static char *PrintMCMap(char **info)
296 sprintf(buf, "Cluster: %-30s Machine: %-20s",
297 info[MAP_CLUSTER], info[MAP_MACHINE]);
299 return ""; /* Used by QueryLoop(). */
302 /* Function Name: PrintSubnetInfo
303 * Description: This function Prints out the subnet info
304 * in a coherent form.
305 * Arguments: info - array of information about a subnet.
306 * Returns: The name of the subnet.
309 static char *PrintSubnetInfo(char **info)
312 struct in_addr addr, mask, low, high;
315 sprintf(buf, " Network: %s", info[SN_NAME]);
317 sprintf(buf, " Description: %s", info[SN_DESC]);
319 addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
320 mask.s_addr = htonl(atoi(info[SN_MASK]));
321 low.s_addr = htonl(atoi(info[SN_LOW]));
322 high.s_addr = htonl(atoi(info[SN_HIGH]));
323 /* screwy sequence is here because inet_ntoa returns a pointer to
324 a static buf. If it were all one sprintf, the last value would
326 sprintf(buf, " Address: %s Mask: ", inet_ntoa(addr));
327 strcat(buf, inet_ntoa(mask));
328 strcat(buf, "\n High: ");
329 strcat(buf, inet_ntoa(high));
330 strcat(buf, " Low: ");
331 strcat(buf, inet_ntoa(low));
333 sprintf(buf, "Hostname prefix: %s", info[SN_PREFIX]);
335 sprintf(buf, " Owner: %s %s\n", info[SN_ACE_TYPE],
336 strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
338 sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
340 return info[SN_NAME];
343 /* Function Name: GetMCInfo.
344 * Description: This function stores info about a machine.
345 * type - type of data we are trying to retrieve.
346 * name1 - the name of argv[0] for the call.
347 * name2 - the name of argv[1] for the call.
348 * Returns: the top element of a queue containing the data or NULL.
351 struct qelem *GetMCInfo(int type, char *name1, char *name2)
354 struct qelem *elem = NULL;
361 args[1] = args[2] = args[3] = "*";
362 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
364 if (stat == MR_NO_MATCH)
367 sprintf(buf, "Machine '%s' is not in the database.", name1);
371 com_err(program_name, stat, " in get_machine.");
378 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
380 com_err(program_name, stat, " in get_hostalias.");
385 if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
387 if (stat == MR_NO_MATCH)
390 sprintf(buf, "Network '%s' is not in the database.", name1);
394 com_err(program_name, stat, " in get_subnet.");
399 if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
401 com_err(program_name, stat, " in get_cluster.");
406 args[MAP_MACHINE] = name1;
407 args[MAP_CLUSTER] = name2;
408 if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
411 com_err(program_name, stat, " in get_machine_to_cluster_map.");
416 args[CD_NAME] = name1;
417 args[CD_LABEL] = name2;
418 if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
420 com_err(program_name, stat, " in get_cluster_data.");
424 return QueueTop(elem);
427 /* Function Name: AskMCDInfo.
428 * Description: This function askes the user for information about a
429 * machine and saves it into a structure.
430 * Arguments: info - a pointer the information to ask about
431 * type - type of information - MACHINE
434 * name - T/F : change the name of this type.
438 char **AskMCDInfo(char **info, int type, Bool name)
440 char temp_buf[BUFSIZ], *newname, *oldnewname;
445 sprintf(temp_buf, "\nSetting the information for the Machine %s...",
449 sprintf(temp_buf, "Setting the information for the Network %s...",
453 sprintf(temp_buf, "Setting the information for the Cluster %s...",
457 sprintf(temp_buf, "Setting the Data for the Cluster %s...",
461 Put_message(temp_buf);
468 newname = strdup(info[M_NAME]);
469 if (GetValueFromUser("The new name for this machine? ", &newname) ==
472 oldnewname = strdup(newname);
473 newname = canonicalize_hostname(newname);
474 if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
476 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
477 oldnewname, newname);
478 Put_message(temp_buf);
483 newname = strdup(info[SN_NAME]);
484 if (GetValueFromUser("The new name for this network? ", &newname) ==
489 newname = strdup(info[C_NAME]);
490 if (GetValueFromUser("The new name for this cluster? ", &newname) ==
495 Put_message("Unknown type in AskMCDInfo, programmer botch");
503 if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
505 if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
507 if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
510 if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
512 if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
518 if (GetValueFromUser("Machine's status (? for help)",
519 &info[M_STAT]) == SUB_ERROR)
521 if (isdigit(info[M_STAT][0]))
523 Put_message("Valid status numbers:");
524 for (i = 0; i < 4; i++)
525 Put_message(states[i]);
528 /* there appears to be some argument mismatch between the client
529 * and the server.. so here is this argument shuffler.
530 * I have since modified this to always shuffle the arguments..
531 * not just do so when performing a modify all fields request.
532 * The SetMachinedefaults() has been changed to reflect this.
533 * pray for us and may we attain enlightenment through structures.
538 /* info did not come from SetMachineDefaults(), which does not
539 * initialize entry 8 (M_STAT_CHNG), therefore we can
542 /* This is an update of an existing machine and the structure
543 * was filled in thru a query to the db which does fill in this
549 info[8] = info[M_SUBNET];
550 info[9] = info[M_ADDR];
551 info[10] = info[M_OWNER_TYPE];
552 info[11] = info[M_OWNER_NAME];
553 info[12] = info[M_ACOMMENT];
554 info[13] = info[M_OCOMMENT];
558 if (GetValueFromUser("Machine's network (or 'none')", &info[8])
562 if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
563 &info[9]) == SUB_ERROR)
565 if (GetTypeFromUser("Machine's owner type", "ace_type", &info[10]) ==
568 if (strcmp(info[10], "NONE") &&
569 GetValueFromUser("Owner's Name", &info[11]) == SUB_ERROR)
571 if (GetValueFromUser("Administrative comment", &info[12]) == SUB_ERROR)
573 if (GetValueFromUser("Operational comment", &info[13]) == SUB_ERROR)
576 FreeAndClear(&info[15], TRUE);
577 FreeAndClear(&info[16], TRUE);
580 if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
582 if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
584 if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
586 if (atoi(info[SN_LOW]) == ntohl(inet_addr(S_DEFAULT_LOW)))
589 unsigned long mask, addr;
591 addr = atoi(info[SN_ADDRESS]);
592 mask = atoi(info[SN_MASK]);
593 low.s_addr = atoi(info[SN_LOW]);
594 low.s_addr = (low.s_addr & ~mask) | (addr & mask);
596 sprintf(temp_buf, "%ld", low.s_addr);
597 info[SN_LOW] = strdup(temp_buf);
599 if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
602 if (atoi(info[SN_HIGH]) == ntohl(inet_addr(S_DEFAULT_HIGH)))
605 unsigned long mask, addr;
607 addr = atoi(info[SN_ADDRESS]);
608 mask = atoi(info[SN_MASK]);
609 high.s_addr = atoi(info[SN_HIGH]);
610 high.s_addr = (high.s_addr & ~mask) | (addr & mask);
612 sprintf(temp_buf, "%ld", high.s_addr);
613 info[SN_HIGH] = strdup(temp_buf);
615 if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
618 if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
620 if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
623 if (strcmp(info[SN_ACE_TYPE], "NONE") &&
624 GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
626 FreeAndClear(&info[SN_MODTIME], TRUE);
627 FreeAndClear(&info[SN_MODBY], TRUE);
628 FreeAndClear(&info[SN_MODWITH], TRUE);
631 if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
634 if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
637 FreeAndClear(&info[C_MODTIME], TRUE);
638 FreeAndClear(&info[C_MODBY], TRUE);
639 FreeAndClear(&info[C_MODWITH], TRUE);
642 if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
645 if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
651 * Slide the newname into the #2 slot, this screws up all future references
655 SlipInNewName(info, newname);
660 /* ----------- Machine Menu ----------- */
662 /* Function Name: ShowMachineInfo
663 * Description: This function shows the information about a machine.
664 * Arguments: argc, argv - the name of the machine in argv[1].
665 * Returns: DM_NORMAL.
668 int ShowMachineInfo(int argc, char **argv)
673 tmpname = canonicalize_hostname(strdup(argv[1]));
674 top = GetMCInfo(MACHINE, tmpname, NULL);
675 Loop(top, ((void *) PrintMachInfo));
680 /* Function Name: ShowMachineQuery
681 * Description: This function shows the information about a machine.
682 * or group of machines, which may be selected through a
683 * number of criteria.
684 * Arguments: argc, argv - the name of the machine in argv[1],
685 * the address of the machine in argv[2],
686 * the location of the machine in argv[3],
687 * and the contact name in argv[4].
688 * any of these may be wildcards.
689 * Returns: DM_NORMAL.
692 int ShowMachineQuery(int argc, char **argv)
695 struct qelem *top, *elem = NULL;
698 if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
699 !strcmp(argv[3], "") && !strcmp(argv[4], ""))
701 Put_message("You must specify at least one parameter of the query.");
706 args[0] = canonicalize_hostname(strdup(argv[1]));
722 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
724 if (stat == MR_NO_MATCH)
725 Put_message("No machine(s) found matching query in the database.");
727 com_err(program_name, stat, " in get_machine.");
730 top = QueueTop(elem);
731 Loop(top, ((void *) PrintMachInfo));
736 /* Function Name: AddMachine
737 * Description: This function adds a new machine to the database.
738 * Arguments: argc, argv - the name of the network in argv[1].
739 * Returns: DM_NORMAL.
742 int AddMachine(int argc, char **argv)
744 char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
746 struct qelem *elem = NULL;
749 if (!ValidName(argv[1])) /* Checks for wildcards. */
753 * get the network record
756 if (strcasecmp(argv[1], "none") &&
757 (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
759 if (stat == MR_NO_MATCH)
762 sprintf(buf, "Network '%s' is not in the database.", argv[1]);
765 com_err(program_name, stat, " in get_subnet.");
770 * Check to see if this machine already exists.
773 name = strdup(""); /* want to put prefix here */
774 if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
777 name = canonicalize_hostname(strdup(name));
780 xargs[1] = xargs[2] = xargs[3] = "*";
781 if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
783 sprintf(buf, "The machine '%s' already exists.", name);
788 else if (stat != MR_NO_MATCH)
790 com_err(program_name, stat,
791 " while checking machine '%s' in AddMachine.", name);
795 rinfo = SetMachineDefaults(info, name);
796 rinfo[M_SUBNET] = strdup(argv[1]);
797 if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
799 Put_message("Aborted.");
804 * Actually create the new Machine.
807 if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
808 com_err(program_name, stat, " in AddMachine.");
815 /* Function Name: RealUpdateMachine
816 * Description: Performs the actual update of the machine data.
817 * Arguments: info - the information on the machine to update.
818 * junk - an UNUSED Boolean.
822 static void RealUpdateMachine(char **info, Bool junk)
825 char **args = AskMCDInfo(info, MACHINE, TRUE);
828 Put_message("Aborted.");
831 if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
832 com_err(program_name, stat, " in UpdateMachine.");
834 Put_message("Machine successfully updated.");
837 /* Function Name: UpdateMachine
838 * Description: This function adds a new machine to the database.
839 * Arguments: argc, argv - the name of the machine in argv[1].
840 * Returns: DM_NORMAL.
843 int UpdateMachine(int argc, char **argv)
848 tmpname = canonicalize_hostname(strdup(argv[1]));
849 top = GetMCInfo(MACHINE, tmpname, NULL);
850 QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
857 /* Function Name: CheckAndRemoveFromCluster
858 * Description: This func tests to see if a machine is in a cluster.
859 * and if so then removes it
860 * Arguments: name - name of the machine (already Canonocalized).
861 * ask_user- query the user before removing if from clusters?
862 * Returns: MR_ERROR if machine left in a cluster, or mr_error.
865 int CheckAndRemoveFromCluster(char *name, Bool ask_user)
869 char *args[10], temp_buf[BUFSIZ], *ptr;
870 struct qelem *top, *elem = NULL;
872 ret_value = SUB_NORMAL; /* initialize ret_value. */
875 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
876 if (stat && stat != MR_NO_MATCH)
878 com_err(program_name, stat, " in get_machine_to_cluster_map.");
881 if (stat == MR_SUCCESS)
883 elem = top = QueueTop(elem);
886 sprintf(temp_buf, "%s is assigned to the following clusters.", name);
887 Put_message(temp_buf);
888 Loop(top, (void *) PrintMCMap);
889 ptr = "Remove this machine from ** ALL ** these clusters?";
890 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
894 Put_message("Aborting...");
906 char **info = elem->q_data;
907 if ((stat = do_mr_query("delete_machine_from_cluster",
908 2, info, NULL, NULL)))
910 ret_value = SUB_ERROR;
911 com_err(program_name, stat,
912 " in delete_machine_from_cluster.");
914 "Machine %s ** NOT ** removed from cluster %s.",
915 info[MAP_MACHINE], info[MAP_CLUSTER]);
916 Put_message(temp_buf);
925 /* Function Name: RealDeleteMachine
926 * Description: Actually Deletes the Machine.
927 * Arguments: info - nescessary information stored as an array of char *'s
928 * one_machine - a boolean, true if there is only one item in
933 static void RealDeleteMachine(char **info, Bool one_machine)
936 char temp_buf[BUFSIZ];
938 sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
940 if (!one_machine || Confirm(temp_buf))
942 if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
944 if ((stat = do_mr_query("delete_host", 1,
945 &info[M_NAME], NULL, NULL)))
947 com_err(program_name, stat, " in DeleteMachine.");
948 sprintf(temp_buf, "%s ** NOT ** deleted.",
950 Put_message(temp_buf);
954 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
955 Put_message(temp_buf);
961 /* Function Name: DeleteMachine
962 * Description: This function removes a machine from the data base.
963 * Arguments: argc, argv - the machines name int argv[1].
964 * Returns: DM_NORMAL.
967 /* Perhaps we should remove the cluster if it has no machine now. */
969 int DeleteMachine(int argc, char **argv)
974 tmpname = canonicalize_hostname(strdup(argv[1]));
975 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
976 QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
983 char *partial_canonicalize_hostname(char *s)
986 static char *def_domain = NULL;
993 hp = gethostbyname(name.nodename);
994 cp = strchr(hp->h_name, '.');
996 def_domain = strdup(++cp);
1001 if (strchr(s, '.') || strchr(s, '*'))
1003 sprintf(buf, "%s.%s", s, def_domain);
1009 /* Function Name: ShowCname
1010 * Description: This function shows machine aliases
1011 * Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1012 * Returns: DM_NORMAL.
1015 int ShowCname(int argc, char **argv)
1018 char *tmpalias, *tmpname;
1020 tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
1021 tmpname = canonicalize_hostname(strdup(argv[2]));
1022 top = GetMCInfo(CNAME, tmpalias, tmpname);
1023 Put_message(""); /* blank line on screen */
1024 Loop(top, ((void *) PrintCname));
1030 int AddCname(int argc, char **argv)
1035 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1036 args[1] = canonicalize_hostname(strdup(argv[2]));
1037 stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
1043 Put_message("That alias name is already in use.");
1046 Put_message("Permission denied. "
1047 "(Regular users can only add two aliases to a host.");
1050 com_err(program_name, stat, " in add_hostalias");
1056 int DeleteCname(int argc, char **argv)
1061 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1062 args[1] = canonicalize_hostname(strdup(argv[2]));
1063 stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
1065 com_err(program_name, stat, " in delete_hostalias");
1070 /* Function Name: AddMachineToCluster
1071 * Description: This function adds a machine to a cluster
1072 * Arguments: argc, argv - The machine name is argv[1].
1073 * The cluster name in argv[2].
1074 * Returns: DM_NORMAL.
1077 int AddMachineToCluster(int argc, char **argv)
1080 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1081 Bool add_it, one_machine, one_cluster;
1082 struct qelem *melem, *mtop, *celem, *ctop;
1084 machine = canonicalize_hostname(strdup(argv[1]));
1085 if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
1087 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1089 Put_message(temp_buf);
1093 celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
1094 melem = mtop = GetMCInfo(MACHINE, machine, NULL);
1097 one_machine = (QueueCount(mtop) == 1);
1098 one_cluster = (QueueCount(ctop) == 1);
1100 /* No good way to use QueryLoop() here, sigh */
1104 char **minfo = melem->q_data;
1107 char **cinfo = celem->q_data;
1108 if (one_machine && one_cluster)
1112 sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
1113 minfo[M_NAME], cinfo[C_NAME]);
1114 switch (YesNoQuitQuestion(temp_buf, FALSE))
1123 Put_message("Aborting...");
1131 args[0] = minfo[M_NAME];
1132 args[1] = cinfo[C_NAME];
1133 stat = do_mr_query("add_machine_to_cluster", 2, args,
1140 sprintf(temp_buf, "%s is already in cluster %s",
1141 minfo[M_NAME], cinfo[C_NAME]);
1142 Put_message(temp_buf);
1145 com_err(program_name, stat, " in AddMachineToCluster.");
1149 celem = celem->q_forw;
1151 celem = ctop; /* reset cluster element. */
1152 melem = melem->q_forw;
1159 /* Function Name: RealRemoveMachineFromCluster
1160 * Description: This function actually removes the machine from its
1162 * Arguments: info - all information nescessary to perform the removal.
1163 * one_map - True if there is only one case, and we should
1168 static void RealRemoveMachineFromCluster(char **info, Bool one_map)
1170 char temp_buf[BUFSIZ];
1173 sprintf(temp_buf, "Remove %s from the cluster %s",
1174 info[MAP_MACHINE], info[MAP_CLUSTER]);
1175 if (!one_map || Confirm(temp_buf))
1177 if ((stat = do_mr_query("delete_machine_from_cluster", 2,
1179 com_err(program_name, stat, " in delete_machine_from_cluster");
1182 sprintf(temp_buf, "%s has been removed from the cluster %s.",
1183 info[MAP_MACHINE], info[MAP_CLUSTER]);
1184 Put_message(temp_buf);
1188 Put_message("Machine not removed.");
1191 /* Function Name: RemoveMachineFromCluster
1192 * Description: Removes this machine form a specific cluster.
1193 * Arguments: argc, argv - Name of machine in argv[1].
1194 * Name of cluster in argv[2].
1198 int RemoveMachineFromCluster(int argc, char **argv)
1200 struct qelem *elem = NULL;
1201 char buf[BUFSIZ], * args[10];
1204 args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
1205 if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
1207 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1208 argv[1], args[MAP_MACHINE]);
1211 args[MAP_CLUSTER] = argv[2];
1212 args[MAP_END] = NULL;
1214 stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1216 if (stat == MR_NO_MATCH)
1218 sprintf(buf, "The machine %s is not is the cluster %s.",
1219 args[MAP_MACHINE], args[MAP_CLUSTER]);
1221 free(args[MAP_MACHINE]);
1224 if (stat != MR_SUCCESS)
1225 com_err(program_name, stat, " in delete_machine_from_cluster");
1227 elem = QueueTop(elem);
1228 QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1229 "Remove this machine from this cluster");
1232 free(args[MAP_MACHINE]);
1236 /* ---------- Subnet Menu -------- */
1238 /* Function Name: ShowSubnetInfo
1239 * Description: Gets information about a subnet given its name.
1240 * Arguments: argc, argc - the name of the subnet in in argv[1].
1241 * Returns: DM_NORMAL.
1244 int ShowSubnetInfo(int argc, char **argv)
1248 top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1249 Loop(top, (void *) PrintSubnetInfo);
1254 /* Function Name: AddSubnet
1255 * Description: Creates a new subnet.
1256 * Arguments: argc, argv - the name of the new subnet is argv[1].
1257 * Returns: DM_NORMAL.
1260 int AddSubnet(int argc, char **argv)
1262 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1266 * Check to see if this subnet already exists.
1268 if (!ValidName(name))
1271 if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
1273 Put_message("This subnet already exists.");
1276 else if (stat != MR_NO_MATCH)
1278 com_err(program_name, stat, " in AddSubnet.");
1281 if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
1283 Put_message("Aborted.");
1289 * Actually create the new Subnet.
1291 if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
1292 com_err(program_name, stat, " in AddSubnet.");
1298 /* Function Name: RealUpdateSubnet
1299 * Description: This function actually performs the subnet update.
1300 * Arguments: info - all information nesc. for updating the subnet.
1301 * junk - an UNUSED boolean.
1305 static void RealUpdateSubnet(char **info, Bool junk)
1308 char **args = AskMCDInfo(info, SUBNET, TRUE);
1311 Put_message("Aborted.");
1314 if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
1315 com_err(program_name, stat, " in UpdateSubnet.");
1317 Put_message("Subnet successfully updated.");
1320 /* Function Name: UpdateSubnet
1321 * Description: This Function Updates a subnet
1322 * Arguments: name of the subnet in argv[1].
1323 * Returns: DM_NORMAL.
1326 int UpdateSubnet(int argc, char **argv)
1329 top = GetMCInfo(SUBNET, argv[1], NULL);
1330 QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1336 /* Function Name: RealDeleteSubnet
1337 * Description: Actually performs the subnet deletion.
1338 * Arguments: info - all information about this subnet.
1339 * one_subnet - If true then there was only one subnet in
1340 * the queue, and we should confirm.
1344 static void RealDeleteSubnet(char **info, Bool one_subnet)
1347 char temp_buf[BUFSIZ];
1350 "Are you sure the you want to delete the subnet %s (y/n) ?",
1352 if (!one_subnet || Confirm(temp_buf))
1354 if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
1356 com_err(program_name, stat, " in delete_subnet.");
1357 sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
1358 Put_message(temp_buf);
1362 sprintf(temp_buf, "subnet %s successfully deleted.",
1364 Put_message(temp_buf);
1369 /* Function Name: DeleteSubnet
1370 * Description: This function removes a subnet from the database.
1371 * Arguments: argc, argv - the name of the subnet is stored in argv[1].
1372 * Returns: DM_NORMAL.
1375 int DeleteSubnet(int argc, char **argv)
1379 top = GetMCInfo(SUBNET, argv[1], NULL);
1380 QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1386 /* ---------- Cluster Menu -------- */
1388 /* Function Name: ShowClusterInfo
1389 * Description: Gets information about a cluser given its name.
1390 * Arguments: argc, argc - the name of the cluster in in argv[1].
1391 * Returns: DM_NORMAL.
1394 int ShowClusterInfo(int argc, char **argv)
1398 top = GetMCInfo(CLUSTER, argv[1], NULL);
1399 Loop(top, (void *) PrintClusterInfo);
1404 /* Function Name: AddCluster
1405 * Description: Creates a new cluster.
1406 * Arguments: argc, argv - the name of the new cluster is argv[1].
1407 * Returns: DM_NORMAL.
1410 int AddCluster(int argc, char **argv)
1412 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1416 * Check to see if this cluster already exists.
1418 if (!ValidName(name))
1421 if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
1423 Put_message("This cluster already exists.");
1426 else if (stat != MR_NO_MATCH)
1428 com_err(program_name, stat, " in AddCluster.");
1431 if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
1433 Put_message("Aborted.");
1439 * Actually create the new Cluster.
1441 if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
1442 com_err(program_name, stat, " in AddCluster.");
1448 /* Function Name: RealUpdateCluster
1449 * Description: This function actually performs the cluster update.
1450 * Arguments: info - all information nesc. for updating the cluster.
1451 * junk - an UNUSED boolean.
1455 static void RealUpdateCluster(char **info, Bool junk)
1458 char **args = AskMCDInfo(info, CLUSTER, TRUE);
1462 Put_message("Aborted.");
1465 if ((stat = do_mr_query("update_cluster", CountArgs(args),
1467 com_err(program_name, stat, " in UpdateCluster.");
1469 Put_message("Cluster successfully updated.");
1472 /* Function Name: UpdateCluster
1473 * Description: This Function Updates a cluster
1474 * Arguments: name of the cluster in argv[1].
1475 * Returns: DM_NORMAL.
1478 int UpdateCluster(int argc, char **argv)
1481 top = GetMCInfo(CLUSTER, argv[1], NULL);
1482 QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1488 /* Function Name: CheckAndRemoveMachine
1489 * Description: This function checks and removes all machines from a
1491 * Arguments: name - name of the cluster.
1492 * ask_first - if TRUE, then we will query the user, before
1494 * Returns: SUB_ERROR if all machines not removed.
1497 int CheckAndRemoveMachines(char *name, Bool ask_first)
1499 int stat, ret_value;
1501 char *args[10], temp_buf[BUFSIZ], *ptr;
1502 struct qelem *top, *elem = NULL;
1504 ret_value = SUB_NORMAL;
1505 args[MAP_MACHINE] = "*";
1506 args[MAP_CLUSTER] = name;
1507 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1508 if (stat && stat != MR_NO_MATCH)
1510 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1513 if (stat == MR_SUCCESS)
1515 elem = top = QueueTop(elem);
1518 sprintf(temp_buf, "The cluster %s has the following machines in it:",
1520 Put_message(temp_buf);
1523 char **info = elem->q_data;
1524 Print(1, &info[MAP_MACHINE], (char *) NULL);
1525 elem = elem->q_forw;
1527 ptr = "Remove ** ALL ** these machines from this cluster?";
1529 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1533 Put_message("Aborting...");
1546 char **info = elem->q_data;
1547 if ((stat = do_mr_query("delete_machine_from_cluster",
1548 2, info, NULL, NULL)))
1550 ret_value = SUB_ERROR;
1551 com_err(program_name, stat,
1552 " in delete_machine_from_cluster.");
1554 "Machine %s ** NOT ** removed from cluster %s.",
1555 info[MAP_MACHINE], info[MAP_CLUSTER]);
1556 Put_message(temp_buf);
1558 elem = elem->q_forw;
1565 /* Function Name: RealDeleteCluster
1566 * Description: Actually performs the cluster deletion.
1567 * Arguments: info - all information about this cluster.
1568 * one_cluster - If true then there was only one cluster in
1569 * the queue, and we should confirm.
1573 static void RealDeleteCluster(char **info, Bool one_cluster)
1576 char temp_buf[BUFSIZ];
1579 "Are you sure the you want to delete the cluster %s (y/n) ?",
1581 if (!one_cluster || Confirm(temp_buf))
1583 if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
1585 if ((stat = do_mr_query("delete_cluster", 1,
1586 &info[C_NAME], NULL, NULL)))
1588 com_err(program_name, stat, " in delete_cluster.");
1589 sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
1590 Put_message(temp_buf);
1594 sprintf(temp_buf, "cluster %s successfully deleted.",
1596 Put_message(temp_buf);
1602 /* Function Name: DeleteCluster
1603 * Description: This function removes a cluster from the database.
1604 * Arguments: argc, argv - the name of the cluster is stored in argv[1].
1605 * Returns: DM_NORMAL.
1608 int DeleteCluster(int argc, char **argv)
1612 top = GetMCInfo(CLUSTER, argv[1], NULL);
1613 QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1619 /* ----------- Cluster Data Menu -------------- */
1621 /* Function Name: ShowClusterData
1622 * Description: This function shows the services for one cluster.
1623 * Arguments: argc, argv - The name of the cluster is argv[1].
1624 * The label of the data in argv[2].
1625 * Returns: DM_NORMAL.
1628 int ShowClusterData(int argc, char **argv)
1630 struct qelem *elem, *top;
1633 top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1636 info = elem->q_data;
1637 PrintClusterData(info);
1638 elem = elem->q_forw;
1644 /* Function Name: AddClusterData
1645 * Description: This function adds some data to the cluster.
1646 * Arguments: argv, argc: argv[1] - the name of the cluster.
1647 * argv[2] - the label of the data.
1648 * argv[3] - the data.
1649 * Returns: DM_NORMAL.
1652 int AddClusterData(int argc, char **argv)
1656 if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
1657 com_err(program_name, stat, " in AddClusterData.");
1661 /* Function Name: RealRemoveClusterData
1662 * Description: actually removes the cluster data.
1663 * Arguments: info - all info necessary to remove the cluster, in an array
1665 * one_item - if true then the queue has only one elem and we
1670 static void RealRemoveClusterData(char **info, Bool one_item)
1676 temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1677 PrintClusterData(info);
1678 if (!one_item || Confirm(temp_ptr))
1680 if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
1682 com_err(program_name, stat, " in DeleteClusterData.");
1683 Put_message("Data not removed.");
1686 Put_message("Removal successful.");
1690 /* Function Name: RemoveClusterData
1691 * Description: This function removes data on a given cluster.
1692 * Arguments: argv, argc: argv[1] - the name of the cluster.
1693 * argv[2] - the label of the data.
1694 * argv[3] - the data.
1695 * Returns: DM_NORMAL.
1698 int RemoveClusterData(int argc, char **argv)
1702 top = GetMCInfo(DATA, argv[1], argv[2]);
1703 QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1704 "Remove data from cluster");
1710 /* Function Name: MachineToClusterMap
1711 * Description: This Retrieves the mapping between machine and cluster
1712 * Arguments: argc, argv - argv[1] -> machine name or wildcard.
1713 * argv[2] -> cluster name or wildcard.
1717 int MachineToClusterMap(int argc, char **argv)
1719 struct qelem *elem, *top;
1720 char *tmpname, temp_buf[256];
1722 tmpname = canonicalize_hostname(strdup(argv[1]));
1723 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
1725 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1727 Put_message(temp_buf);
1729 top = elem = GetMCInfo(MAP, tmpname, argv[2]);
1731 Put_message(""); /* blank line on screen */
1734 char **info = elem->q_data;
1736 elem = elem->q_forw;