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);
52 static char *PrintContainerInfo(char **info);
53 static void RealUpdateContainer(char **info, Bool junk);
54 static void RealDeleteContainer(char **info, Bool one_container);
55 static void RealRemoveMachineFromContainer(char **info, Bool one_contmap);
66 #define M_DEFAULT_TYPE DEFAULT_NONE
68 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
69 #define C_DEFAULT_LOCATION DEFAULT_NONE
71 #define CON_DEFAULT_TYPE DEFAULT_NONE
73 #define CD_DEFAULT_LABEL DEFAULT_NONE
74 #define CD_DEFAULT_DATA DEFAULT_NONE
76 #define S_DEFAULT_LOW "18.0.0.20"
77 #define S_DEFAULT_HIGH "18.0.2.249"
79 static char *states[] = {
86 static char *subnet_states[] = {
89 "Private, 10 Mbps (2)",
90 "Private, 100 Mbps (3)",
96 static char *MacState(int state)
98 static char buf[BUFSIZ];
100 if (state < 0 || state > 3)
102 sprintf(buf, "Unknown (%d)", state);
105 return states[state];
108 static char *SubnetState(int state)
110 static char buf[BUFSIZ];
112 if (state < 0 || state > 6)
114 sprintf(buf, "Unknown (%d)", state);
117 return subnet_states[state];
120 /* -------------------- Set Defaults -------------------- */
122 /* Function Name: SetMachineDefaults
123 * Description: sets machine defaults.
124 * Arguments: info - an array to put the defaults into.
125 * name - Canonacalized name of the machine.
126 * Returns: info - the array.
129 static char **SetMachineDefaults(char **info, char *name)
131 info[M_NAME] = strdup(name);
132 info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
133 info[M_MODEL] = strdup(M_DEFAULT_TYPE);
134 info[M_OS] = strdup(M_DEFAULT_TYPE);
135 info[M_LOC] = strdup(M_DEFAULT_TYPE);
136 info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
137 info[M_BILL_CONTACT] = strdup(M_DEFAULT_TYPE);
138 info[M_ACCT_NUMBER] = strdup("");
139 info[M_USE] = strdup("0");
140 info[M_STAT] = strdup("1");
141 info[M_SUBNET] = strdup("NONE");
142 info[M_ADDR] = strdup("unique");
143 info[M_OWNER_TYPE] = strdup("NONE");
144 info[M_OWNER_NAME] = strdup("NONE");
145 info[M_ACOMMENT] = strdup("");
146 info[M_OCOMMENT] = strdup("");
147 info[17] = info[18] = NULL;
151 /* Function Name: SetClusterDefaults
152 * Description: sets Cluster defaults.
153 * Arguments: info - an array to put the defaults into.
154 * name - name of the Cluster.
155 * Returns: info - the array.
158 static char **SetClusterDefaults(char **info, char *name)
160 info[C_NAME] = strdup(name);
161 info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
162 info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
163 info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
167 static char **SetContainerDefaults(char **info, char *name)
169 info[CON_NAME] = strdup(name);
170 info[CON_DESCRIPT] = strdup(CON_DEFAULT_TYPE);
171 info[CON_LOCATION] = strdup(CON_DEFAULT_TYPE);
172 info[CON_CONTACT] = strdup(CON_DEFAULT_TYPE);
173 info[CON_OWNER_TYPE] = strdup("NONE");
174 info[CON_OWNER_NAME] = strdup("NONE");
175 info[CON_MEMACE_TYPE] = strdup("NONE");
176 info[CON_MEMACE_NAME] = strdup("NONE");
177 info[CON_MODBY] = info[CON_MODTIME] = info[CON_MODWITH] = NULL;
178 info[CON_END] = NULL;
182 /* Function Name: SetSubnetDefaults
183 * Description: sets Subnet defaults.
184 * Arguments: info - an array to put the defaults into.
185 * name - name of the Subnet.
186 * Returns: info - the array.
189 static char **SetSubnetDefaults(char **info, char *name)
193 info[SN_NAME] = strdup(name);
194 info[SN_DESC] = strdup("");
195 info[SN_STATUS] = strdup("1");
196 info[SN_CONTACT] = strdup(DEFAULT_NONE);
197 info[SN_ACCT_NUMBER] = strdup("");
198 sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
199 info[SN_ADDRESS] = strdup(buf);
200 sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
201 info[SN_MASK] = strdup(buf);
202 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
203 info[SN_LOW] = strdup(buf);
204 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
205 info[SN_HIGH] = strdup(buf);
206 info[SN_PREFIX] = strdup("");
207 info[SN_ACE_TYPE] = strdup("LIST");
208 info[SN_ACE_NAME] = strdup("network");
209 info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
213 /* -------------------- General Functions -------------------- */
215 static char aliasbuf[256];
217 void PrintAliases(char **info)
219 if (strlen(aliasbuf) == 0)
220 sprintf(aliasbuf, "Aliases: %s", info[0]);
223 strcat(aliasbuf, ", ");
224 strcat(aliasbuf, info[0]);
229 /* Function Name: PrintMachInfo
230 * Description: This function Prints out the Machine info in
232 * Arguments: info - array of information about a machine.
233 * Returns: The name of the Machine
236 static char *PrintMachInfo(char **info)
238 char buf[BUFSIZ], tbuf[256];
240 struct mqelem *elem = NULL, *elem2 = NULL;
244 sprintf(buf, "Machine: %s", info[M_NAME]);
247 args[1] = info[M_NAME];
248 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
250 if (stat != MR_NO_MATCH)
251 com_err(program_name, stat, " looking up aliases");
256 Loop(QueueTop(elem), (void (*)(char **)) PrintAliases);
258 Put_message(aliasbuf);
260 sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
261 strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
262 sprintf(buf, "Address: %-16s Network: %-16s",
263 info[M_ADDR], info[M_SUBNET]);
265 sprintf(buf, "Owner: %-16s Use data: %s", tbuf, info[M_INUSE]);
267 sprintf(buf, "Status: %-16s Changed: %s",
268 MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
271 sprintf(buf, "Vendor: %-16s Location: %s", info[M_VENDOR],
274 sprintf(buf, "Model: %-16s Contact: %s", info[M_MODEL],
277 sprintf(buf, "OS: %-16s Billing Contact: %s", info[M_OS],
278 info[M_BILL_CONTACT]);
280 sprintf(buf, "Opt: %-16s Account Number: %s", info[M_USE],
281 info[M_ACCT_NUMBER]);
284 sprintf(buf, "Adm cmt: %s", info[M_ACOMMENT]);
286 sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]);
289 sprintf(buf, "Created by %s on %s", info[M_CREATOR], info[M_CREATED]);
291 sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
293 /* Do a get_subnet for the machine's subnet. We need to know if it's
296 args[0] = info[M_SUBNET];
297 stat = do_mr_query("get_subnet", 1, args, StoreInfo, &elem2);
299 com_err(program_name, stat, " looking up subnet info");
300 else if (atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_10MBPS ||
301 atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_100MBPS)
304 sprintf(buf, "Warning: This host is on a private subnet.");
306 sprintf(buf, "Billing information shown is superceded by billing information for the subnet.");
314 /* Function Name: PrintMachine
315 * Description: Prints the name of a machine record
316 * Arguments: info - array of information about the machine.
320 static void PrintMachine(char **info)
324 sprintf(buf, "Machine: %s", info[M_NAME]);
328 /* Function Name: PrintCname
329 * Description: Prints the Data on a host alias
330 * Arguments: info a pointer to the data array.
331 * Returns: The name of the alias.
334 static char *PrintCname(char **info)
338 sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
343 /* Function Name: PrintClusterInfo
344 * Description: This function Prints out the cluster info
345 * in a coherent form.
346 * Arguments: info - array of information about a cluster.
347 * Returns: The name of the cluster.
350 static char *PrintClusterInfo(char **info)
355 sprintf(buf, "Cluster: %s", info[C_NAME]);
357 sprintf(buf, "Description: %s", info[C_DESCRIPT]);
359 sprintf(buf, "Location: %s", info[C_LOCATION]);
361 sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
366 /* Function Name: PrintClusterData
367 * Description: Prints the Data on a cluster
368 * Arguments: info a pointer to the data array.
369 * Returns: The name of the cluster.
372 static char *PrintClusterData(char **info)
377 sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
378 info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
380 return info[CD_NAME];
383 /* Function Name: PrintMCMap
384 * Description: Prints the data about a machine to cluster mapping.
385 * Arguments: info a pointer to the data array.
389 static char *PrintMCMap(char **info)
392 sprintf(buf, "Cluster: %-30s Machine: %-20s",
393 info[MAP_CLUSTER], info[MAP_MACHINE]);
395 return ""; /* Used by QueryLoop(). */
398 /* Function Name: PrintSubnetInfo
399 * Description: This function Prints out the subnet info
400 * in a coherent form.
401 * Arguments: info - array of information about a subnet.
402 * Returns: The name of the subnet.
405 static char *PrintSubnetInfo(char **info)
408 struct in_addr addr, mask, low, high;
411 sprintf(buf, " Network: %s", info[SN_NAME]);
413 sprintf(buf, " Description: %s", info[SN_DESC]);
415 sprintf(buf, " Status: %s", SubnetState(atoi(info[SN_STATUS])));
417 sprintf(buf, " Contact: %s", info[SN_CONTACT]);
419 sprintf(buf, " Account Number: %s", info[SN_ACCT_NUMBER]);
421 addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
422 mask.s_addr = htonl(atoi(info[SN_MASK]));
423 low.s_addr = htonl(atoi(info[SN_LOW]));
424 high.s_addr = htonl(atoi(info[SN_HIGH]));
425 /* screwy sequence is here because inet_ntoa returns a pointer to
426 a static buf. If it were all one sprintf, the last value would
428 sprintf(buf, " Address: %s Mask: ", inet_ntoa(addr));
429 strcat(buf, inet_ntoa(mask));
430 strcat(buf, "\n High: ");
431 strcat(buf, inet_ntoa(high));
432 strcat(buf, " Low: ");
433 strcat(buf, inet_ntoa(low));
435 sprintf(buf, "Hostname prefix: %s", info[SN_PREFIX]);
437 sprintf(buf, " Owner: %s %s\n", info[SN_ACE_TYPE],
438 strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
440 sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
442 return info[SN_NAME];
445 /* Function Name: GetMCInfo.
446 * Description: This function stores info about a machine.
447 * type - type of data we are trying to retrieve.
448 * name1 - the name of argv[0] for the call.
449 * name2 - the name of argv[1] for the call.
450 * Returns: the top element of a queue containing the data or NULL.
453 struct mqelem *GetMCInfo(int type, char *name1, char *name2)
456 struct mqelem *elem = NULL;
463 args[1] = args[2] = args[3] = "*";
464 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
466 if (stat == MR_NO_MATCH)
469 sprintf(buf, "Machine '%s' is not in the database.", name1);
473 com_err(program_name, stat, " in get_machine.");
480 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
482 com_err(program_name, stat, " in get_hostalias.");
487 if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
489 if (stat == MR_NO_MATCH)
492 sprintf(buf, "Network '%s' is not in the database.", name1);
496 com_err(program_name, stat, " in get_subnet.");
501 if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
503 com_err(program_name, stat, " in get_cluster.");
508 args[MAP_MACHINE] = name1;
509 args[MAP_CLUSTER] = name2;
510 if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
513 com_err(program_name, stat, " in get_machine_to_cluster_map.");
518 args[CD_NAME] = name1;
519 args[CD_LABEL] = name2;
520 if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
522 com_err(program_name, stat, " in get_cluster_data.");
527 args[CON_NAME] = name1;
528 if ((stat = do_mr_query("get_container", 1, &name1, StoreInfo, &elem)))
530 com_err(program_name, stat, " in get_container.");
536 if ((stat = do_mr_query("get_machine_to_container_map", 1, &name1,
539 com_err(program_name, stat, " in get_machine_to_container_map.");
543 return QueueTop(elem);
546 /* Function Name: AskMCDInfo.
547 * Description: This function askes the user for information about a
548 * machine and saves it into a structure.
549 * Arguments: info - a pointer the information to ask about
550 * type - type of information - MACHINE
554 * name - T/F : change the name of this type.
558 char **AskMCDInfo(char **info, int type, Bool name)
560 char temp_buf[BUFSIZ], *newname, *oldnewname;
565 sprintf(temp_buf, "\nSetting the information for the Machine %s...",
569 sprintf(temp_buf, "Setting the information for the Network %s...",
573 sprintf(temp_buf, "Setting the information for the Cluster %s...",
577 sprintf(temp_buf, "Setting the Data for the Cluster %s...",
581 sprintf(temp_buf, "Setting the Data for the Container %s...",
585 Put_message(temp_buf);
592 newname = strdup(info[M_NAME]);
593 if (GetValueFromUser("The new name for this machine? ", &newname) ==
596 oldnewname = strdup(newname);
597 newname = canonicalize_hostname(newname);
598 if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
600 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
601 oldnewname, newname);
602 Put_message(temp_buf);
607 newname = strdup(info[SN_NAME]);
608 if (GetValueFromUser("The new name for this network? ", &newname) ==
613 newname = strdup(info[C_NAME]);
614 if (GetValueFromUser("The new name for this cluster? ", &newname) ==
619 newname = strdup(info[CON_NAME]);
620 if (GetValueFromUser("The new name for this container? ", &newname)
625 Put_message("Unknown type in AskMCDInfo, programmer botch");
633 if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
635 if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
637 if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
640 if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
642 if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
645 if (GetValueFromUser("Machine's billing contact",
646 &info[M_BILL_CONTACT]) == SUB_ERROR)
648 if (GetValueFromUser("Machine's billing account number",
649 &info[M_ACCT_NUMBER]) == SUB_ERROR)
654 if (GetValueFromUser("Machine's status (? for help)",
655 &info[M_STAT]) == SUB_ERROR)
657 if (isdigit(info[M_STAT][0]))
659 Put_message("Valid status numbers:");
660 for (i = 0; i < 4; i++)
661 Put_message(states[i]);
664 /* there appears to be some argument mismatch between the client
665 * and the server.. so here is this argument shuffler.
666 * I have since modified this to always shuffle the arguments..
667 * not just do so when performing a modify all fields request.
668 * The SetMachinedefaults() has been changed to reflect this.
669 * pray for us and may we attain enlightenment through structures.
674 /* info did not come from SetMachineDefaults(), which does not
675 * initialize entry 10 (M_STAT_CHNG), therefore we can
678 /* This is an update of an existing machine and the structure
679 * was filled in thru a query to the db which does fill in this
685 info[10] = info[M_SUBNET];
686 info[11] = info[M_ADDR];
687 info[12] = info[M_OWNER_TYPE];
688 info[13] = info[M_OWNER_NAME];
689 info[14] = info[M_ACOMMENT];
690 info[15] = info[M_OCOMMENT];
694 if (GetValueFromUser("Machine's network (or 'none')", &info[10])
698 if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
699 &info[11]) == SUB_ERROR)
701 if (GetTypeFromUser("Machine's owner type", "ace_type", &info[12]) ==
704 if (strcmp(info[12], "NONE") &&
705 GetValueFromUser("Owner's Name", &info[13]) == SUB_ERROR)
707 if (!strcmp(info[12], "KERBEROS"))
711 mrcl_validate_kerberos_member(info[13], &canon);
712 if (mrcl_get_message())
713 Put_message(mrcl_get_message());
717 if (GetValueFromUser("Administrative comment", &info[14]) == SUB_ERROR)
719 if (GetValueFromUser("Operational comment", &info[15]) == SUB_ERROR)
722 FreeAndClear(&info[17], TRUE);
723 FreeAndClear(&info[18], TRUE);
726 if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
731 if (GetValueFromUser("Network's status (? for help)",
732 &info[SN_STATUS]) == SUB_ERROR)
734 if (isdigit(info[SN_STATUS][0]))
736 Put_message("Valid status numbers:");
737 for (i = 0; i < 7; i++)
738 Put_message(subnet_states[i]);
740 if (GetValueFromUser("Network's contact", &info[SN_CONTACT]) == SUB_ERROR)
742 if (GetValueFromUser("Network's billing account number",
743 &info[SN_ACCT_NUMBER]) == SUB_ERROR)
745 if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
747 if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
749 if (atoi(info[SN_LOW]) == (int)ntohl(inet_addr(S_DEFAULT_LOW)))
752 unsigned long mask, addr;
754 addr = atoi(info[SN_ADDRESS]);
755 mask = atoi(info[SN_MASK]);
756 low.s_addr = atoi(info[SN_LOW]);
757 low.s_addr = (low.s_addr & ~mask) | (addr & mask);
759 sprintf(temp_buf, "%ld", low.s_addr);
760 info[SN_LOW] = strdup(temp_buf);
762 if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
765 if (atoi(info[SN_HIGH]) == (int)ntohl(inet_addr(S_DEFAULT_HIGH)))
768 unsigned long mask, addr;
770 addr = atoi(info[SN_ADDRESS]);
771 mask = atoi(info[SN_MASK]);
772 high.s_addr = atoi(info[SN_HIGH]);
773 high.s_addr = (high.s_addr & ~mask) | (addr & mask);
775 sprintf(temp_buf, "%ld", high.s_addr);
776 info[SN_HIGH] = strdup(temp_buf);
778 if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
781 if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
783 if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
786 if (strcmp(info[SN_ACE_TYPE], "NONE") &&
787 GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
789 if (!strcmp(info[SN_ACE_TYPE], "KERBEROS"))
793 mrcl_validate_kerberos_member(info[SN_ACE_NAME], &canon);
794 if (mrcl_get_message())
795 Put_message(mrcl_get_message());
796 free(info[SN_ACE_NAME]);
797 info[SN_ACE_NAME] = canon;
799 FreeAndClear(&info[SN_MODTIME], TRUE);
800 FreeAndClear(&info[SN_MODBY], TRUE);
801 FreeAndClear(&info[SN_MODWITH], TRUE);
804 if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
807 if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
810 FreeAndClear(&info[C_MODTIME], TRUE);
811 FreeAndClear(&info[C_MODBY], TRUE);
812 FreeAndClear(&info[C_MODWITH], TRUE);
815 if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
818 if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
822 if (GetValueFromUser("Container's Description:", &info[CON_DESCRIPT]) ==
825 if (GetValueFromUser("Container's Location:", &info[CON_LOCATION]) ==
828 if (GetValueFromUser("Container's Contact:", &info[CON_CONTACT]) ==
831 if (GetTypeFromUser("Container's owner type", "ace_type",
832 &info[CON_OWNER_TYPE]) == SUB_ERROR)
834 if (strcmp(info[CON_OWNER_TYPE], "NONE") &&
835 GetValueFromUser("Owner's Name", &info[CON_OWNER_NAME]) == SUB_ERROR)
837 if (!strcmp(info[CON_OWNER_TYPE], "KERBEROS"))
841 mrcl_validate_kerberos_member(info[CON_OWNER_NAME], &canon);
842 if (mrcl_get_message())
843 Put_message(mrcl_get_message());
844 free(info[CON_OWNER_NAME]);
845 info[CON_OWNER_NAME] = canon;
847 if (GetTypeFromUser("Container's Membership ACL", "ace_type",
848 &info[CON_MEMACE_TYPE]) == SUB_ERROR)
850 if (strcmp(info[CON_MEMACE_TYPE], "NONE") &&
851 GetValueFromUser("Membership ACL", &info[CON_MEMACE_NAME])
854 if (!strcmp(info[CON_MEMACE_TYPE], "KERBEROS"))
858 mrcl_validate_kerberos_member(info[CON_MEMACE_NAME], &canon);
859 if (mrcl_get_message())
860 Put_message(mrcl_get_message());
861 free(info[CON_MEMACE_NAME]);
862 info[CON_MEMACE_NAME] = canon;
864 FreeAndClear(&info[CON_MODTIME], TRUE);
865 FreeAndClear(&info[CON_MODBY], TRUE);
866 FreeAndClear(&info[CON_MODWITH], TRUE);
871 * Slide the newname into the #2 slot, this screws up all future references
875 SlipInNewName(info, newname);
880 /* ----------- Machine Menu ----------- */
882 /* Function Name: ShowMachineInfo
883 * Description: This function shows the information about a machine.
884 * Arguments: argc, argv - the name of the machine in argv[1].
885 * Returns: DM_NORMAL.
888 int ShowMachineInfo(int argc, char **argv)
893 tmpname = canonicalize_hostname(strdup(argv[1]));
894 top = GetMCInfo(MACHINE, tmpname, NULL);
895 Loop(top, ((void (*)(char **)) PrintMachInfo));
900 /* Function Name: ShowMachineQuery
901 * Description: This function shows the information about a machine.
902 * or group of machines, which may be selected through a
903 * number of criteria.
904 * Arguments: argc, argv - the name of the machine in argv[1],
905 * the address of the machine in argv[2],
906 * the location of the machine in argv[3],
907 * and the contact name in argv[4].
908 * any of these may be wildcards.
909 * Returns: DM_NORMAL.
912 int ShowMachineQuery(int argc, char **argv)
915 struct mqelem *top, *elem = NULL;
918 if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
919 !strcmp(argv[3], "") && !strcmp(argv[4], ""))
921 Put_message("You must specify at least one parameter of the query.");
926 args[0] = canonicalize_hostname(strdup(argv[1]));
942 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
944 if (stat == MR_NO_MATCH)
945 Put_message("No machine(s) found matching query in the database.");
947 com_err(program_name, stat, " in get_machine.");
950 top = QueueTop(elem);
951 Loop(top, ((void (*)(char **)) PrintMachInfo));
956 /* Function Name: AddMachine
957 * Description: This function adds a new machine to the database.
958 * Arguments: argc, argv - the name of the network in argv[1].
959 * Returns: DM_NORMAL.
962 int AddMachine(int argc, char **argv)
964 char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
966 struct mqelem *elem = NULL;
969 if (!ValidName(argv[1])) /* Checks for wildcards. */
973 * get the network record
976 if (strcasecmp(argv[1], "none") &&
977 (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
979 if (stat == MR_NO_MATCH)
982 sprintf(buf, "Network '%s' is not in the database.", argv[1]);
985 com_err(program_name, stat, " in get_subnet.");
990 * Check to see if this machine already exists.
993 name = strdup(""); /* want to put prefix here */
994 if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
997 name = canonicalize_hostname(strdup(name));
1000 xargs[1] = xargs[2] = xargs[3] = "*";
1001 if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
1003 sprintf(buf, "The machine '%s' already exists.", name);
1008 else if (stat != MR_NO_MATCH)
1010 com_err(program_name, stat,
1011 " while checking machine '%s' in AddMachine.", name);
1015 rinfo = SetMachineDefaults(info, name);
1016 rinfo[M_SUBNET] = strdup(argv[1]);
1017 if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
1019 Put_message("Aborted.");
1024 * Actually create the new Machine.
1027 if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
1028 com_err(program_name, stat, " in AddMachine.");
1035 /* Function Name: RealUpdateMachine
1036 * Description: Performs the actual update of the machine data.
1037 * Arguments: info - the information on the machine to update.
1038 * junk - an UNUSED Boolean.
1042 static void RealUpdateMachine(char **info, Bool junk)
1045 char **args = AskMCDInfo(info, MACHINE, TRUE);
1048 Put_message("Aborted.");
1051 if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
1052 com_err(program_name, stat, " in UpdateMachine.");
1054 Put_message("Machine successfully updated.");
1057 /* Function Name: UpdateMachine
1058 * Description: This function adds a new machine to the database.
1059 * Arguments: argc, argv - the name of the machine in argv[1].
1060 * Returns: DM_NORMAL.
1063 int UpdateMachine(int argc, char **argv)
1068 tmpname = canonicalize_hostname(strdup(argv[1]));
1069 top = GetMCInfo(MACHINE, tmpname, NULL);
1070 QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
1077 /* Function Name: CheckAndRemoveFromCluster
1078 * Description: This func tests to see if a machine is in a cluster.
1079 * and if so then removes it
1080 * Arguments: name - name of the machine (already Canonicalized).
1081 * ask_user- query the user before removing if from clusters?
1082 * Returns: MR_ERROR if machine left in a cluster, or mr_error.
1085 int CheckAndRemoveFromCluster(char *name, Bool ask_user)
1087 int stat, ret_value;
1089 char *args[10], temp_buf[BUFSIZ], *ptr;
1090 struct mqelem *top, *elem = NULL;
1092 ret_value = SUB_NORMAL; /* initialize ret_value. */
1095 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1096 if (stat && stat != MR_NO_MATCH)
1098 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1101 if (stat == MR_SUCCESS)
1103 elem = top = QueueTop(elem);
1106 sprintf(temp_buf, "%s is assigned to the following clusters.", name);
1107 Put_message(temp_buf);
1108 Loop(top, (void (*)(char **)) PrintMCMap);
1109 ptr = "Remove this machine from ** ALL ** these clusters?";
1110 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1114 Put_message("Aborting...");
1126 char **info = elem->q_data;
1127 if ((stat = do_mr_query("delete_machine_from_cluster",
1128 2, info, NULL, NULL)))
1130 ret_value = SUB_ERROR;
1131 com_err(program_name, stat,
1132 " in delete_machine_from_cluster.");
1134 "Machine %s ** NOT ** removed from cluster %s.",
1135 info[MAP_MACHINE], info[MAP_CLUSTER]);
1136 Put_message(temp_buf);
1138 elem = elem->q_forw;
1145 /* Function Name: CheckAndRemoveCnames
1146 * Description: This func tests to see if a machine has cnames,
1147 * and if so then removes them.
1148 * Arguments: name - name of the machine (already Canonicalized).
1149 * ask_user- query the user before removing cnames?
1150 * Returns: MR_ERROR if machine left with a cname, or mr_error.
1153 int CheckAndRemoveCnames(char *name, Bool ask_user)
1155 int stat, ret_value;
1157 char *args[10], temp_buf[BUFSIZ], *ptr;
1158 struct mqelem *top, *elem = NULL;
1160 ret_value = SUB_NORMAL;
1163 stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem);
1164 if (stat && stat != MR_NO_MATCH)
1166 com_err(program_name, stat, " in get_hostalias.");
1169 if (stat == MR_SUCCESS)
1171 elem = top = QueueTop(elem);
1174 sprintf(temp_buf, "%s has the following cnames.", name);
1175 Put_message(temp_buf);
1176 Loop(top, (void (*)(char **)) PrintCname);
1177 ptr = "Remove ** ALL ** these cnames?";
1178 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1182 Put_message("Aborting...");
1194 char **info = elem->q_data;
1195 if ((stat = do_mr_query("delete_hostalias", 2, info,
1198 ret_value = SUB_ERROR;
1199 com_err(program_name, stat, " in delete_hostalias.");
1201 "Cname %s ** NOT ** removed from host %s.",
1203 Put_message(temp_buf);
1205 elem = elem->q_forw;
1212 /* Function Name: RealDeleteMachine
1213 * Description: Actually Deletes the Machine.
1214 * Arguments: info - nescessary information stored as an array of char *'s
1215 * one_machine - a boolean, true if there is only one item in
1220 static void RealDeleteMachine(char **info, Bool one_machine)
1223 char temp_buf[BUFSIZ];
1225 sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
1227 if (!one_machine || Confirm(temp_buf))
1229 if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
1231 if (CheckAndRemoveCnames(info[M_NAME], TRUE) != SUB_ERROR)
1233 if ((stat = do_mr_query("delete_host", 1,
1234 &info[M_NAME], NULL, NULL)))
1236 com_err(program_name, stat, " in DeleteMachine.");
1237 sprintf(temp_buf, "%s ** NOT ** deleted.",
1239 Put_message(temp_buf);
1243 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
1244 Put_message(temp_buf);
1251 /* Function Name: DeleteMachine
1252 * Description: This function removes a machine from the data base.
1253 * Arguments: argc, argv - the machines name int argv[1].
1254 * Returns: DM_NORMAL.
1257 /* Perhaps we should remove the cluster if it has no machine now. */
1259 int DeleteMachine(int argc, char **argv)
1264 tmpname = canonicalize_hostname(strdup(argv[1]));
1265 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
1266 QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
1273 /* Function Name: ShowCname
1274 * Description: This function shows machine aliases
1275 * Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1276 * Returns: DM_NORMAL.
1279 int ShowCname(int argc, char **argv)
1282 char *tmpalias, *tmpname;
1284 tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
1285 tmpname = canonicalize_hostname(strdup(argv[2]));
1286 top = GetMCInfo(CNAME, tmpalias, tmpname);
1287 Put_message(""); /* blank line on screen */
1288 Loop(top, ((void (*)(char **)) PrintCname));
1294 int AddCname(int argc, char **argv)
1299 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1300 args[1] = canonicalize_hostname(strdup(argv[2]));
1301 stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
1307 Put_message("That alias name is already in use.");
1310 Put_message("Permission denied. "
1311 "(Regular users can only add two aliases to a host.");
1314 com_err(program_name, stat, " in add_hostalias");
1320 int DeleteCname(int argc, char **argv)
1325 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1326 args[1] = canonicalize_hostname(strdup(argv[2]));
1327 stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
1329 com_err(program_name, stat, " in delete_hostalias");
1334 /* Function Name: AddMachineToCluster
1335 * Description: This function adds a machine to a cluster
1336 * Arguments: argc, argv - The machine name is argv[1].
1337 * The cluster name in argv[2].
1338 * Returns: DM_NORMAL.
1341 int AddMachineToCluster(int argc, char **argv)
1344 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1345 Bool add_it, one_machine, one_cluster;
1346 struct mqelem *melem, *mtop, *celem, *ctop;
1348 machine = canonicalize_hostname(strdup(argv[1]));
1349 if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
1351 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1353 Put_message(temp_buf);
1357 celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
1358 melem = mtop = GetMCInfo(MACHINE, machine, NULL);
1361 one_machine = (QueueCount(mtop) == 1);
1362 one_cluster = (QueueCount(ctop) == 1);
1364 /* No good way to use QueryLoop() here, sigh */
1368 char **minfo = melem->q_data;
1371 char **cinfo = celem->q_data;
1372 if (one_machine && one_cluster)
1376 sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
1377 minfo[M_NAME], cinfo[C_NAME]);
1378 switch (YesNoQuitQuestion(temp_buf, FALSE))
1387 Put_message("Aborting...");
1395 args[0] = minfo[M_NAME];
1396 args[1] = cinfo[C_NAME];
1397 stat = do_mr_query("add_machine_to_cluster", 2, args,
1404 sprintf(temp_buf, "%s is already in cluster %s",
1405 minfo[M_NAME], cinfo[C_NAME]);
1406 Put_message(temp_buf);
1409 com_err(program_name, stat, " in AddMachineToCluster.");
1413 celem = celem->q_forw;
1415 celem = ctop; /* reset cluster element. */
1416 melem = melem->q_forw;
1423 /* Function Name: RealRemoveMachineFromCluster
1424 * Description: This function actually removes the machine from its
1426 * Arguments: info - all information nescessary to perform the removal.
1427 * one_map - True if there is only one case, and we should
1432 static void RealRemoveMachineFromCluster(char **info, Bool one_map)
1434 char temp_buf[BUFSIZ];
1437 sprintf(temp_buf, "Remove %s from the cluster %s",
1438 info[MAP_MACHINE], info[MAP_CLUSTER]);
1439 if (!one_map || Confirm(temp_buf))
1441 if ((stat = do_mr_query("delete_machine_from_cluster", 2,
1443 com_err(program_name, stat, " in delete_machine_from_cluster");
1446 sprintf(temp_buf, "%s has been removed from the cluster %s.",
1447 info[MAP_MACHINE], info[MAP_CLUSTER]);
1448 Put_message(temp_buf);
1452 Put_message("Machine not removed.");
1455 /* Function Name: RemoveMachineFromCluster
1456 * Description: Removes this machine form a specific cluster.
1457 * Arguments: argc, argv - Name of machine in argv[1].
1458 * Name of cluster in argv[2].
1462 int RemoveMachineFromCluster(int argc, char **argv)
1464 struct mqelem *elem = NULL;
1465 char buf[BUFSIZ], *args[10];
1468 args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
1469 if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
1471 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1472 argv[1], args[MAP_MACHINE]);
1475 args[MAP_CLUSTER] = argv[2];
1476 args[MAP_END] = NULL;
1478 stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1480 if (stat == MR_NO_MATCH)
1482 sprintf(buf, "The machine %s is not in the cluster %s.",
1483 args[MAP_MACHINE], args[MAP_CLUSTER]);
1485 free(args[MAP_MACHINE]);
1488 if (stat != MR_SUCCESS)
1489 com_err(program_name, stat, " in delete_machine_from_cluster");
1491 elem = QueueTop(elem);
1492 QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1493 "Remove this machine from this cluster");
1496 free(args[MAP_MACHINE]);
1500 /* ---------- Subnet Menu -------- */
1502 /* Function Name: ShowSubnetInfo
1503 * Description: Gets information about a subnet given its name.
1504 * Arguments: argc, argc - the name of the subnet in in argv[1].
1505 * Returns: DM_NORMAL.
1508 int ShowSubnetInfo(int argc, char **argv)
1512 top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1513 Loop(top, (void (*)(char **)) PrintSubnetInfo);
1518 /* Function Name: AddSubnet
1519 * Description: Creates a new subnet.
1520 * Arguments: argc, argv - the name of the new subnet is argv[1].
1521 * Returns: DM_NORMAL.
1524 int AddSubnet(int argc, char **argv)
1526 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1530 * Check to see if this subnet already exists.
1532 if (!ValidName(name))
1535 if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
1537 Put_message("This subnet already exists.");
1540 else if (stat != MR_NO_MATCH)
1542 com_err(program_name, stat, " in AddSubnet.");
1545 if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
1547 Put_message("Aborted.");
1553 * Actually create the new Subnet.
1555 if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
1556 com_err(program_name, stat, " in AddSubnet.");
1562 /* Function Name: RealUpdateSubnet
1563 * Description: This function actually performs the subnet update.
1564 * Arguments: info - all information nesc. for updating the subnet.
1565 * junk - an UNUSED boolean.
1569 static void RealUpdateSubnet(char **info, Bool junk)
1572 char **args = AskMCDInfo(info, SUBNET, TRUE);
1575 Put_message("Aborted.");
1578 if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
1579 com_err(program_name, stat, " in UpdateSubnet.");
1581 Put_message("Subnet successfully updated.");
1584 /* Function Name: UpdateSubnet
1585 * Description: This Function Updates a subnet
1586 * Arguments: name of the subnet in argv[1].
1587 * Returns: DM_NORMAL.
1590 int UpdateSubnet(int argc, char **argv)
1593 top = GetMCInfo(SUBNET, argv[1], NULL);
1594 QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1600 /* Function Name: RealDeleteSubnet
1601 * Description: Actually performs the subnet deletion.
1602 * Arguments: info - all information about this subnet.
1603 * one_subnet - If true then there was only one subnet in
1604 * the queue, and we should confirm.
1608 static void RealDeleteSubnet(char **info, Bool one_subnet)
1611 char temp_buf[BUFSIZ];
1614 "Are you sure the you want to delete the subnet %s (y/n) ?",
1616 if (!one_subnet || Confirm(temp_buf))
1618 if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
1620 com_err(program_name, stat, " in delete_subnet.");
1621 sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
1622 Put_message(temp_buf);
1626 sprintf(temp_buf, "subnet %s successfully deleted.",
1628 Put_message(temp_buf);
1633 /* Function Name: DeleteSubnet
1634 * Description: This function removes a subnet from the database.
1635 * Arguments: argc, argv - the name of the subnet is stored in argv[1].
1636 * Returns: DM_NORMAL.
1639 int DeleteSubnet(int argc, char **argv)
1643 top = GetMCInfo(SUBNET, argv[1], NULL);
1644 QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1650 /* ---------- Cluster Menu -------- */
1652 /* Function Name: ShowClusterInfo
1653 * Description: Gets information about a cluser given its name.
1654 * Arguments: argc, argc - the name of the cluster in in argv[1].
1655 * Returns: DM_NORMAL.
1658 int ShowClusterInfo(int argc, char **argv)
1662 top = GetMCInfo(CLUSTER, argv[1], NULL);
1663 Loop(top, (void (*)(char **)) PrintClusterInfo);
1668 /* Function Name: AddCluster
1669 * Description: Creates a new cluster.
1670 * Arguments: argc, argv - the name of the new cluster is argv[1].
1671 * Returns: DM_NORMAL.
1674 int AddCluster(int argc, char **argv)
1676 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1680 * Check to see if this cluster already exists.
1682 if (!ValidName(name))
1685 if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
1687 Put_message("This cluster already exists.");
1690 else if (stat != MR_NO_MATCH)
1692 com_err(program_name, stat, " in AddCluster.");
1695 if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
1697 Put_message("Aborted.");
1703 * Actually create the new Cluster.
1705 if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
1706 com_err(program_name, stat, " in AddCluster.");
1712 /* Function Name: RealUpdateCluster
1713 * Description: This function actually performs the cluster update.
1714 * Arguments: info - all information nesc. for updating the cluster.
1715 * junk - an UNUSED boolean.
1719 static void RealUpdateCluster(char **info, Bool junk)
1722 char **args = AskMCDInfo(info, CLUSTER, TRUE);
1726 Put_message("Aborted.");
1729 if ((stat = do_mr_query("update_cluster", CountArgs(args),
1731 com_err(program_name, stat, " in UpdateCluster.");
1733 Put_message("Cluster successfully updated.");
1736 /* Function Name: UpdateCluster
1737 * Description: This Function Updates a cluster
1738 * Arguments: name of the cluster in argv[1].
1739 * Returns: DM_NORMAL.
1742 int UpdateCluster(int argc, char **argv)
1745 top = GetMCInfo(CLUSTER, argv[1], NULL);
1746 QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1752 /* Function Name: CheckAndRemoveMachine
1753 * Description: This function checks and removes all machines from a
1755 * Arguments: name - name of the cluster.
1756 * ask_first - if TRUE, then we will query the user, before
1758 * Returns: SUB_ERROR if all machines not removed.
1761 int CheckAndRemoveMachines(char *name, Bool ask_first)
1763 int stat, ret_value;
1765 char *args[10], temp_buf[BUFSIZ], *ptr;
1766 struct mqelem *top, *elem = NULL;
1768 ret_value = SUB_NORMAL;
1769 args[MAP_MACHINE] = "*";
1770 args[MAP_CLUSTER] = name;
1771 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1772 if (stat && stat != MR_NO_MATCH)
1774 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1777 if (stat == MR_SUCCESS)
1779 elem = top = QueueTop(elem);
1782 sprintf(temp_buf, "The cluster %s has the following machines in it:",
1784 Put_message(temp_buf);
1787 char **info = elem->q_data;
1788 Print(1, &info[MAP_MACHINE], (char *) NULL);
1789 elem = elem->q_forw;
1791 ptr = "Remove ** ALL ** these machines from this cluster?";
1793 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1797 Put_message("Aborting...");
1810 char **info = elem->q_data;
1811 if ((stat = do_mr_query("delete_machine_from_cluster",
1812 2, info, NULL, NULL)))
1814 ret_value = SUB_ERROR;
1815 com_err(program_name, stat,
1816 " in delete_machine_from_cluster.");
1818 "Machine %s ** NOT ** removed from cluster %s.",
1819 info[MAP_MACHINE], info[MAP_CLUSTER]);
1820 Put_message(temp_buf);
1822 elem = elem->q_forw;
1829 /* Function Name: RealDeleteCluster
1830 * Description: Actually performs the cluster deletion.
1831 * Arguments: info - all information about this cluster.
1832 * one_cluster - If true then there was only one cluster in
1833 * the queue, and we should confirm.
1837 static void RealDeleteCluster(char **info, Bool one_cluster)
1840 char temp_buf[BUFSIZ];
1843 "Are you sure the you want to delete the cluster %s (y/n) ?",
1845 if (!one_cluster || Confirm(temp_buf))
1847 if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
1849 if ((stat = do_mr_query("delete_cluster", 1,
1850 &info[C_NAME], NULL, NULL)))
1852 com_err(program_name, stat, " in delete_cluster.");
1853 sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
1854 Put_message(temp_buf);
1858 sprintf(temp_buf, "cluster %s successfully deleted.",
1860 Put_message(temp_buf);
1866 /* Function Name: DeleteCluster
1867 * Description: This function removes a cluster from the database.
1868 * Arguments: argc, argv - the name of the cluster is stored in argv[1].
1869 * Returns: DM_NORMAL.
1872 int DeleteCluster(int argc, char **argv)
1876 top = GetMCInfo(CLUSTER, argv[1], NULL);
1877 QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1883 /* ----------- Cluster Data Menu -------------- */
1885 /* Function Name: ShowClusterData
1886 * Description: This function shows the services for one cluster.
1887 * Arguments: argc, argv - The name of the cluster is argv[1].
1888 * The label of the data in argv[2].
1889 * Returns: DM_NORMAL.
1892 int ShowClusterData(int argc, char **argv)
1894 struct mqelem *elem, *top;
1897 top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1900 info = elem->q_data;
1901 PrintClusterData(info);
1902 elem = elem->q_forw;
1908 /* Function Name: AddClusterData
1909 * Description: This function adds some data to the cluster.
1910 * Arguments: argv, argc: argv[1] - the name of the cluster.
1911 * argv[2] - the label of the data.
1912 * argv[3] - the data.
1913 * Returns: DM_NORMAL.
1916 int AddClusterData(int argc, char **argv)
1920 for (i = 1; i < 4; i++)
1922 if (IS_EMPTY(argv[i]))
1924 Put_message("Cluster data cannot be an empty string.");
1928 if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
1929 com_err(program_name, stat, " in AddClusterData.");
1933 /* Function Name: RealRemoveClusterData
1934 * Description: actually removes the cluster data.
1935 * Arguments: info - all info necessary to remove the cluster, in an array
1937 * one_item - if true then the queue has only one elem and we
1942 static void RealRemoveClusterData(char **info, Bool one_item)
1948 temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1949 PrintClusterData(info);
1950 if (!one_item || Confirm(temp_ptr))
1952 if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
1954 com_err(program_name, stat, " in DeleteClusterData.");
1955 Put_message("Data not removed.");
1958 Put_message("Removal successful.");
1962 /* Function Name: RemoveClusterData
1963 * Description: This function removes data on a given cluster.
1964 * Arguments: argv, argc: argv[1] - the name of the cluster.
1965 * argv[2] - the label of the data.
1966 * argv[3] - the data.
1967 * Returns: DM_NORMAL.
1970 int RemoveClusterData(int argc, char **argv)
1974 top = GetMCInfo(DATA, argv[1], argv[2]);
1975 QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1976 "Remove data from cluster");
1982 /* Function Name: MachineToClusterMap
1983 * Description: This Retrieves the mapping between machine and cluster
1984 * Arguments: argc, argv - argv[1] -> machine name or wildcard.
1985 * argv[2] -> cluster name or wildcard.
1989 int MachineToClusterMap(int argc, char **argv)
1991 struct mqelem *elem, *top;
1992 char *tmpname, temp_buf[256];
1994 tmpname = canonicalize_hostname(strdup(argv[1]));
1995 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
1997 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1999 Put_message(temp_buf);
2001 top = elem = GetMCInfo(MAP, tmpname, argv[2]);
2003 Put_message(""); /* blank line on screen */
2006 char **info = elem->q_data;
2008 elem = elem->q_forw;
2016 /* Function Name: MachineByOwner
2017 * Description: This function prints all machines which are owned by
2018 * a given user or group.
2020 * Returns: DM_NORMAL.
2023 int MachineByOwner(int argc, char **argv)
2025 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
2028 type = strdup("USER");
2029 if (GetTypeFromUser("Type of owner", "ace_type", &type) == SUB_ERROR)
2032 sprintf(buf, "Name of %s", type);
2033 name = strdup(user);
2034 if (GetValueFromUser(buf, &name) == SUB_ERROR)
2037 switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE))
2040 sprintf(temp_buf, "R%s", type); /* "USER to "RUSER", etc. */
2042 type = strdup(temp_buf);
2050 top = GetMachineByOwner(type, name);
2051 Loop(top, PrintMachine);
2057 /* Function Name: GetMachineByOwner
2058 * Description: This function stores information retrieved by
2059 * the get_host_by_owner query
2060 * Arguments: type - an ace_type, argv[0] for the query
2061 * name - name of machine, argv[1] for the query
2062 * Returns: the top element of a queue returning the data, or NULL.
2065 struct mqelem *GetMachineByOwner(char *type, char *name)
2068 struct mqelem *elem = NULL;
2073 if ((status = do_mr_query("get_host_by_owner", 2, args, StoreInfo, &elem)))
2075 com_err(program_name, status, " in get_host_by_owner");
2078 return QueueTop(elem);
2081 int MachineByAcctNumber(int argc, char **argv)
2083 char *args[1], *account_number;
2085 struct mqelem *elem = NULL;
2087 account_number = strdup("");
2088 if (GetValueFromUser("Account Number", &account_number) == SUB_ERROR)
2091 args[0] = account_number;
2092 if (status = do_mr_query("get_host_by_account_number", 1, args, StoreInfo,
2095 com_err(program_name, status, " in get_host_by_account_number");
2098 Loop(QueueTop(elem), (void (*)(char **)) PrintMachInfo);
2104 int ShowContainerInfo(int argc, char **argv)
2108 top = GetMCInfo(CONTAINER, argv[1], NULL);
2109 Loop(top, (void (*)(char **)) PrintContainerInfo);
2114 static char *PrintContainerInfo(char **info)
2116 char buf[BUFSIZ], tbuf[256];
2119 sprintf(buf, "Container: %-16s", info[CON_NAME]);
2121 sprintf(buf, "Description: %-16s", info[CON_DESCRIPT]);
2123 sprintf(buf, "Location: %-16s Contact: %s", info[CON_LOCATION],
2126 sprintf(tbuf, "%s %s", info[CON_OWNER_TYPE],
2127 strcmp(info[CON_OWNER_TYPE], "NONE") ? info[CON_OWNER_NAME] : "");
2128 sprintf(buf, "Owner: %-16s", tbuf);
2130 sprintf(tbuf, "%s %s", info[CON_MEMACE_TYPE],
2131 strcmp(info[CON_MEMACE_TYPE], "NONE") ? info[CON_MEMACE_NAME] : "");
2132 sprintf(buf, "Membership ACL: %-16s", tbuf);
2135 sprintf(buf, MOD_FORMAT, info[CON_MODBY], info[CON_MODTIME],
2138 return info[CON_NAME];
2141 static char *PrintContainer(char **info)
2145 sprintf(buf, "Container: %s", info[CON_NAME]);
2150 static char *PrintMContMap(char **info)
2153 sprintf(buf, "Container: %-30s Machine: %-20s",
2159 int AddContainer(int argc, char **argv)
2161 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
2164 /* Can't use ValidName() because spaces are allowed in container names */
2167 Put_message("Please use a non-empty name.");
2171 if (strchr(name, '*') || strchr(name, '?'))
2173 Put_message("Wildcards not accepted here.");
2177 /* Check if this cluster already exists. */
2178 if ((stat = do_mr_query("get_container", 1, &name, NULL, NULL))
2181 Put_message("This container already exists.");
2184 else if (stat != MR_NO_MATCH)
2186 com_err(program_name, stat, " in AddContainer.");
2189 if (!(args = AskMCDInfo(SetContainerDefaults(info, name), CONTAINER, FALSE)))
2191 Put_message("Aborted.");
2196 /* Create the new container. */
2197 if ((stat = do_mr_query("add_container", CountArgs(args), args, NULL, NULL)))
2198 com_err(program_name, stat, " in AddContainer.");
2204 int UpdateContainer(int argc, char **argv)
2207 top = GetMCInfo(CONTAINER, argv[1], NULL);
2208 QueryLoop(top, NullPrint, RealUpdateContainer, "Update the container");
2214 static void RealUpdateContainer(char **info, Bool junk)
2217 char **args = AskMCDInfo(info, CONTAINER, TRUE);
2221 Put_message("Aborted.");
2224 if ((stat = do_mr_query("update_container", CountArgs(args), args,
2226 com_err(program_name, stat, " in UpdateContainer.");
2228 Put_message("Container successfully updated.");
2231 int DeleteContainer(int argc, char **argv)
2235 top = GetMCInfo(CONTAINER, argv[1], NULL);
2236 QueryLoop(top, PrintClusterInfo, RealDeleteContainer,
2237 "Delete the container");
2243 static void RealDeleteContainer(char **info, Bool one_container)
2246 char temp_buf[BUFSIZ];
2249 "Are you sure you want to delete the container %s (y/n) ?",
2251 if (!one_container || Confirm(temp_buf))
2253 if (CheckAndRemoveMachinesFromContainer(info[CON_NAME], TRUE)
2256 if ((stat = do_mr_query("delete_container", 1, &info[CON_NAME],
2259 com_err(program_name, stat, " in delete_container.");
2260 sprintf(temp_buf, "Container %s ** NOT ** deleted.",
2262 Put_message(temp_buf);
2266 sprintf(temp_buf, "Container %s successfully deleted.",
2268 Put_message(temp_buf);
2274 int CheckAndRemoveMachinesFromContainer(char *name, Bool ask_first)
2276 int stat, ret_value;
2278 char *args[10], temp_buf[BUFSIZ], *ptr;
2279 struct mqelem *top, *elem = NULL;
2281 ret_value = SUB_NORMAL;
2284 stat = do_mr_query("get_machines_of_container", 2, args, StoreInfo,
2286 if (stat && stat != MR_NO_MATCH)
2288 com_err(program_name, stat, " in get_machines_of_container");
2291 if (stat == MR_SUCCESS)
2293 elem = top = QueueTop(elem);
2297 "The container %s has the following machines in it:", name);
2298 Put_message(temp_buf);
2301 char **info = elem->q_data;
2302 Print(1, &info[0], (char *) NULL);
2303 elem = elem->q_forw;
2305 ptr = "Remove ** ALL ** these machines from this container?";
2307 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
2311 Put_message("Aborting...");
2324 char **info = elem->q_data;
2325 if ((stat = do_mr_query("delete_machine_from_container",
2326 2, info, NULL, NULL)))
2328 ret_value = SUB_ERROR;
2329 com_err(program_name, stat,
2330 " in delete_machine_from_container.");
2332 "Machine %s ** NOT ** removed from container %s.",
2334 Put_message(temp_buf);
2336 elem = elem->q_forw;
2343 int GetSubContainers(int argc, char **argv)
2346 struct mqelem *elem = NULL, *top = NULL;
2351 if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
2356 if (stat = do_mr_query("get_subcontainers_of_container", 2, args,
2358 com_err(program_name, stat, " in get_subcontainers_of_container");
2360 top = QueueTop(elem);
2361 Loop(top, ((void (*)(char **)) PrintContainer));
2366 int MachineToContainerMap(int argc, char **argv)
2368 struct mqelem *elem, *top;
2369 char *tmpname, temp_buf[256];
2371 tmpname = canonicalize_hostname(strdup(argv[1]));
2372 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
2374 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2376 Put_message(temp_buf);
2378 top = elem = GetMCInfo(CONTMAP, tmpname, NULL);
2383 char **info = elem->q_data;
2384 PrintMContMap(info);
2385 elem = elem->q_forw;
2393 int AddMachineToContainer(int argc, char **argv)
2396 char *machine, *container, temp_buf[BUFSIZ], *args[10];
2397 Bool add_it, one_machine, one_container;
2398 struct mqelem *melem, *mtop, *celem, *ctop;
2400 machine = canonicalize_hostname(strdup(argv[1]));
2401 if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
2403 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2405 Put_message(temp_buf);
2407 container = argv[2];
2409 celem = ctop = GetMCInfo(CONTAINER, container, NULL);
2410 melem = mtop = GetMCInfo(MACHINE, machine, NULL);
2413 one_machine = (QueueCount(mtop) == 1);
2414 one_container = (QueueCount(ctop) == 1);
2418 char **minfo = melem->q_data;
2421 char **cinfo = celem->q_data;
2422 if (one_machine && one_container)
2426 sprintf(temp_buf, "Add machine %s to container %s (y/n/q) ?",
2427 minfo[M_NAME], cinfo[CON_NAME]);
2428 switch (YesNoQuestion(temp_buf, FALSE))
2437 Put_message("Aborting...");
2445 args[0] = minfo[M_NAME];
2446 args[1] = cinfo[CON_NAME];
2447 stat = do_mr_query("add_machine_to_container", 2, args, NULL,
2454 sprintf(temp_buf, "%s is already in container %s",
2455 minfo[M_NAME], cinfo[CON_NAME]);
2456 Put_message(temp_buf);
2459 com_err(program_name, stat, " in AddMachineToContainer.");
2463 celem = celem->q_forw;
2466 melem = melem->q_forw;
2473 int RemoveMachineFromContainer(int argc, char **argv)
2475 struct mqelem *elem = NULL;
2476 char buf[BUFSIZ], *args[10];
2479 args[0] = canonicalize_hostname(strdup(argv[1]));
2480 if (strcasecmp(args[0], argv[1]) && *argv[1] != '"')
2482 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
2489 stat = do_mr_query("get_machine_to_container_map", 1, args, StoreInfo,
2491 if (stat == MR_NO_MATCH)
2493 sprintf(buf, "The machine %s is not in the container %s.",
2499 if (stat != MR_SUCCESS)
2500 com_err(program_name, stat, " in deleter_machine_from_container");
2502 elem = QueueTop(elem);
2503 QueryLoop(elem, PrintMContMap, RealRemoveMachineFromContainer,
2504 "Remove this machine from this container");
2511 static void RealRemoveMachineFromContainer(char **info, Bool one_contmap)
2513 char temp_buf[BUFSIZ];
2516 sprintf(temp_buf, "Remove %s from the container %s",
2518 if (!one_contmap || Confirm(temp_buf))
2520 if ((stat = do_mr_query("delete_machine_from_container", 2,
2522 com_err(program_name, stat, " in delete_machine_from_container");
2525 sprintf(temp_buf, "%s has been removed from the container %s.",
2527 Put_message(temp_buf);
2531 Put_message("Machine not removed.");
2534 int GetMachinesOfContainer(int argc, char **argv)
2537 struct mqelem *elem = NULL, *top = NULL;
2542 if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
2547 if (stat = do_mr_query("get_machines_of_container", 2, args,
2549 com_err(program_name, stat, " in get_machines_of_container");
2551 top = QueueTop(elem);
2552 Loop(top, ((void (*)(char **)) PrintMContMap));
2557 int GetTopLevelCont(int argc, char **argv)
2560 struct mqelem *elem = NULL;
2561 if (status = do_mr_query("get_toplevel_containers", 0, NULL, StoreInfo,
2564 com_err(program_name, status, " in get_toplevel_containers");
2567 Loop(QueueTop(elem), (void(*)(char **)) PrintContainer);