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)",
94 "Private, 1000 Mbps (7)",
98 static char *MacState(int state)
100 static char buf[BUFSIZ];
102 if (state < 0 || state > 3)
104 sprintf(buf, "Unknown (%d)", state);
107 return states[state];
110 static char *SubnetState(int state)
112 static char buf[BUFSIZ];
114 if (state < 0 || state > 8)
116 sprintf(buf, "Unknown (%d)", state);
119 return subnet_states[state];
122 /* -------------------- Set Defaults -------------------- */
124 /* Function Name: SetMachineDefaults
125 * Description: sets machine defaults.
126 * Arguments: info - an array to put the defaults into.
127 * name - Canonacalized name of the machine.
128 * Returns: info - the array.
131 static char **SetMachineDefaults(char **info, char *name)
133 info[M_NAME] = strdup(name);
134 info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
135 info[M_MODEL] = strdup(M_DEFAULT_TYPE);
136 info[M_OS] = strdup(M_DEFAULT_TYPE);
137 info[M_LOC] = strdup(M_DEFAULT_TYPE);
138 info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
139 info[M_BILL_CONTACT] = strdup(M_DEFAULT_TYPE);
140 info[M_ACCT_NUMBER] = strdup("");
141 info[M_USE] = strdup("0");
142 info[M_STAT] = strdup("1");
143 info[M_SUBNET] = strdup("NONE");
144 info[M_ADDR] = strdup("unique");
145 info[M_OWNER_TYPE] = strdup("NONE");
146 info[M_OWNER_NAME] = strdup("NONE");
147 info[M_ACOMMENT] = strdup("");
148 info[M_OCOMMENT] = strdup("");
149 info[17] = info[18] = NULL;
153 /* Function Name: SetClusterDefaults
154 * Description: sets Cluster defaults.
155 * Arguments: info - an array to put the defaults into.
156 * name - name of the Cluster.
157 * Returns: info - the array.
160 static char **SetClusterDefaults(char **info, char *name)
162 info[C_NAME] = strdup(name);
163 info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
164 info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
165 info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
169 static char **SetContainerDefaults(char **info, char *name)
171 info[CON_NAME] = strdup(name);
172 info[CON_DESCRIPT] = strdup(CON_DEFAULT_TYPE);
173 info[CON_LOCATION] = strdup(CON_DEFAULT_TYPE);
174 info[CON_CONTACT] = strdup(CON_DEFAULT_TYPE);
175 info[CON_OWNER_TYPE] = strdup("NONE");
176 info[CON_OWNER_NAME] = strdup("NONE");
177 info[CON_MEMACE_TYPE] = strdup("NONE");
178 info[CON_MEMACE_NAME] = strdup("NONE");
179 info[CON_MODBY] = info[CON_MODTIME] = info[CON_MODWITH] = NULL;
180 info[CON_END] = NULL;
184 /* Function Name: SetSubnetDefaults
185 * Description: sets Subnet defaults.
186 * Arguments: info - an array to put the defaults into.
187 * name - name of the Subnet.
188 * Returns: info - the array.
191 static char **SetSubnetDefaults(char **info, char *name)
195 info[SN_NAME] = strdup(name);
196 info[SN_DESC] = strdup("");
197 info[SN_STATUS] = strdup("1");
198 info[SN_CONTACT] = strdup(DEFAULT_NONE);
199 info[SN_ACCT_NUMBER] = strdup("");
200 sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
201 info[SN_ADDRESS] = strdup(buf);
202 sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
203 info[SN_MASK] = strdup(buf);
204 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
205 info[SN_LOW] = strdup(buf);
206 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
207 info[SN_HIGH] = strdup(buf);
208 info[SN_PREFIX] = strdup("");
209 info[SN_ACE_TYPE] = strdup("LIST");
210 info[SN_ACE_NAME] = strdup("network");
211 info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
215 /* -------------------- General Functions -------------------- */
217 static char aliasbuf[256];
219 void PrintAliases(char **info)
221 if (strlen(aliasbuf) == 0)
222 sprintf(aliasbuf, "Aliases: %s", info[0]);
225 strcat(aliasbuf, ", ");
226 strcat(aliasbuf, info[0]);
231 /* Function Name: PrintMachInfo
232 * Description: This function Prints out the Machine info in
234 * Arguments: info - array of information about a machine.
235 * Returns: The name of the Machine
238 static char *PrintMachInfo(char **info)
240 char buf[BUFSIZ], tbuf[256];
242 struct mqelem *elem = NULL, *elem2 = NULL;
246 sprintf(buf, "Machine: %s", info[M_NAME]);
249 args[1] = info[M_NAME];
250 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
252 if (stat != MR_NO_MATCH)
253 com_err(program_name, stat, " looking up aliases");
258 Loop(QueueTop(elem), (void (*)(char **)) PrintAliases);
260 Put_message(aliasbuf);
262 sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
263 strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
264 sprintf(buf, "Address: %-16s Network: %-16s",
265 info[M_ADDR], info[M_SUBNET]);
267 sprintf(buf, "Owner: %-16s Use data: %s", tbuf, info[M_INUSE]);
269 sprintf(buf, "Status: %-16s Changed: %s",
270 MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
273 sprintf(buf, "Vendor: %-16s Location: %s", info[M_VENDOR],
276 sprintf(buf, "Model: %-16s Contact: %s", info[M_MODEL],
279 sprintf(buf, "OS: %-16s Billing Contact: %s", info[M_OS],
280 info[M_BILL_CONTACT]);
282 sprintf(buf, "Opt: %-16s Account Number: %s", info[M_USE],
283 info[M_ACCT_NUMBER]);
286 sprintf(buf, "Adm cmt: %s", info[M_ACOMMENT]);
288 sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]);
291 sprintf(buf, "Created by %s on %s", info[M_CREATOR], info[M_CREATED]);
293 sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
295 /* Do a get_subnet for the machine's subnet. We need to know if it's
298 args[0] = info[M_SUBNET];
299 stat = do_mr_query("get_subnet", 1, args, StoreInfo, &elem2);
301 com_err(program_name, stat, " looking up subnet info");
302 else if (atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_10MBPS ||
303 atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_100MBPS ||
304 atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_1000MBPS)
307 sprintf(buf, "Warning: This host is on a private subnet.");
309 sprintf(buf, "Billing information shown is superseded by billing information for the subnet.");
317 /* Function Name: PrintMachine
318 * Description: Prints the name of a machine record
319 * Arguments: info - array of information about the machine.
323 static void PrintMachine(char **info)
327 sprintf(buf, "Machine: %s", info[M_NAME]);
331 /* Function Name: PrintCname
332 * Description: Prints the Data on a host alias
333 * Arguments: info a pointer to the data array.
334 * Returns: The name of the alias.
337 static char *PrintCname(char **info)
341 sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
346 /* Function Name: PrintClusterInfo
347 * Description: This function Prints out the cluster info
348 * in a coherent form.
349 * Arguments: info - array of information about a cluster.
350 * Returns: The name of the cluster.
353 static char *PrintClusterInfo(char **info)
358 sprintf(buf, "Cluster: %s", info[C_NAME]);
360 sprintf(buf, "Description: %s", info[C_DESCRIPT]);
362 sprintf(buf, "Location: %s", info[C_LOCATION]);
364 sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
369 /* Function Name: PrintClusterData
370 * Description: Prints the Data on a cluster
371 * Arguments: info a pointer to the data array.
372 * Returns: The name of the cluster.
375 static char *PrintClusterData(char **info)
380 sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
381 info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
383 return info[CD_NAME];
386 /* Function Name: PrintMCMap
387 * Description: Prints the data about a machine to cluster mapping.
388 * Arguments: info a pointer to the data array.
392 static char *PrintMCMap(char **info)
395 sprintf(buf, "Cluster: %-30s Machine: %-20s",
396 info[MAP_CLUSTER], info[MAP_MACHINE]);
398 return ""; /* Used by QueryLoop(). */
401 /* Function Name: PrintSubnetInfo
402 * Description: This function Prints out the subnet info
403 * in a coherent form.
404 * Arguments: info - array of information about a subnet.
405 * Returns: The name of the subnet.
408 static char *PrintSubnetInfo(char **info)
411 struct in_addr addr, mask, low, high;
414 sprintf(buf, " Network: %s", info[SN_NAME]);
416 sprintf(buf, " Description: %s", info[SN_DESC]);
418 sprintf(buf, " Status: %s", SubnetState(atoi(info[SN_STATUS])));
420 sprintf(buf, " Contact: %s", info[SN_CONTACT]);
422 sprintf(buf, " Account Number: %s", info[SN_ACCT_NUMBER]);
424 addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
425 mask.s_addr = htonl(atoi(info[SN_MASK]));
426 low.s_addr = htonl(atoi(info[SN_LOW]));
427 high.s_addr = htonl(atoi(info[SN_HIGH]));
428 /* screwy sequence is here because inet_ntoa returns a pointer to
429 a static buf. If it were all one sprintf, the last value would
431 sprintf(buf, " Address: %s Mask: ", inet_ntoa(addr));
432 strcat(buf, inet_ntoa(mask));
433 strcat(buf, "\n High: ");
434 strcat(buf, inet_ntoa(high));
435 strcat(buf, " Low: ");
436 strcat(buf, inet_ntoa(low));
438 sprintf(buf, "Hostname prefix: %s", info[SN_PREFIX]);
440 sprintf(buf, " Owner: %s %s\n", info[SN_ACE_TYPE],
441 strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
443 sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
445 return info[SN_NAME];
448 /* Function Name: GetMCInfo.
449 * Description: This function stores info about a machine.
450 * type - type of data we are trying to retrieve.
451 * name1 - the name of argv[0] for the call.
452 * name2 - the name of argv[1] for the call.
453 * Returns: the top element of a queue containing the data or NULL.
456 struct mqelem *GetMCInfo(int type, char *name1, char *name2)
459 struct mqelem *elem = NULL;
466 args[1] = args[2] = args[3] = "*";
467 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
469 if (stat == MR_NO_MATCH)
472 sprintf(buf, "Machine '%s' is not in the database.", name1);
476 com_err(program_name, stat, " in get_machine.");
483 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
485 com_err(program_name, stat, " in get_hostalias.");
490 if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
492 if (stat == MR_NO_MATCH)
495 sprintf(buf, "Network '%s' is not in the database.", name1);
499 com_err(program_name, stat, " in get_subnet.");
504 if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
506 com_err(program_name, stat, " in get_cluster.");
511 args[MAP_MACHINE] = name1;
512 args[MAP_CLUSTER] = name2;
513 if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
516 com_err(program_name, stat, " in get_machine_to_cluster_map.");
521 args[CD_NAME] = name1;
522 args[CD_LABEL] = name2;
523 if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
525 com_err(program_name, stat, " in get_cluster_data.");
530 args[CON_NAME] = name1;
531 if ((stat = do_mr_query("get_container", 1, &name1, StoreInfo, &elem)))
533 com_err(program_name, stat, " in get_container.");
539 if ((stat = do_mr_query("get_machine_to_container_map", 1, &name1,
542 com_err(program_name, stat, " in get_machine_to_container_map.");
546 return QueueTop(elem);
549 /* Function Name: AskMCDInfo.
550 * Description: This function askes the user for information about a
551 * machine and saves it into a structure.
552 * Arguments: info - a pointer the information to ask about
553 * type - type of information - MACHINE
557 * name - T/F : change the name of this type.
561 char **AskMCDInfo(char **info, int type, Bool name)
563 char temp_buf[BUFSIZ], *newname, *oldnewname;
568 sprintf(temp_buf, "\nSetting the information for the Machine %s...",
572 sprintf(temp_buf, "Setting the information for the Network %s...",
576 sprintf(temp_buf, "Setting the information for the Cluster %s...",
580 sprintf(temp_buf, "Setting the Data for the Cluster %s...",
584 sprintf(temp_buf, "Setting the Data for the Container %s...",
588 Put_message(temp_buf);
595 newname = strdup(info[M_NAME]);
596 if (GetValueFromUser("The new name for this machine? ", &newname) ==
599 oldnewname = strdup(newname);
600 newname = canonicalize_hostname(newname);
601 if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
603 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
604 oldnewname, newname);
605 Put_message(temp_buf);
610 newname = strdup(info[SN_NAME]);
611 if (GetValueFromUser("The new name for this network? ", &newname) ==
616 newname = strdup(info[C_NAME]);
617 if (GetValueFromUser("The new name for this cluster? ", &newname) ==
622 newname = strdup(info[CON_NAME]);
623 if (GetValueFromUser("The new name for this container? ", &newname)
628 Put_message("Unknown type in AskMCDInfo, programmer botch");
636 if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
638 if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
640 if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
643 if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
645 if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
648 if (GetValueFromUser("Machine's billing contact",
649 &info[M_BILL_CONTACT]) == SUB_ERROR)
651 if (GetValueFromUser("Machine's billing account number",
652 &info[M_ACCT_NUMBER]) == SUB_ERROR)
657 if (GetValueFromUser("Machine's status (? for help)",
658 &info[M_STAT]) == SUB_ERROR)
660 if (isdigit(info[M_STAT][0]))
662 Put_message("Valid status numbers:");
663 for (i = 0; i < 4; i++)
664 Put_message(states[i]);
667 /* there appears to be some argument mismatch between the client
668 * and the server.. so here is this argument shuffler.
669 * I have since modified this to always shuffle the arguments..
670 * not just do so when performing a modify all fields request.
671 * The SetMachinedefaults() has been changed to reflect this.
672 * pray for us and may we attain enlightenment through structures.
677 /* info did not come from SetMachineDefaults(), which does not
678 * initialize entry 10 (M_STAT_CHNG), therefore we can
681 /* This is an update of an existing machine and the structure
682 * was filled in thru a query to the db which does fill in this
688 info[10] = info[M_SUBNET];
689 info[11] = info[M_ADDR];
690 info[12] = info[M_OWNER_TYPE];
691 info[13] = info[M_OWNER_NAME];
692 info[14] = info[M_ACOMMENT];
693 info[15] = info[M_OCOMMENT];
697 if (GetValueFromUser("Machine's network (or 'none')", &info[10])
701 if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
702 &info[11]) == SUB_ERROR)
704 if (GetTypeFromUser("Machine's owner type", "ace_type", &info[12]) ==
707 if (strcmp(info[12], "NONE") &&
708 GetValueFromUser("Owner's Name", &info[13]) == SUB_ERROR)
710 if (!strcmp(info[12], "KERBEROS"))
714 mrcl_validate_kerberos_member(info[13], &canon);
715 if (mrcl_get_message())
716 Put_message(mrcl_get_message());
720 if (GetValueFromUser("Administrative comment", &info[14]) == SUB_ERROR)
722 if (GetValueFromUser("Operational comment", &info[15]) == SUB_ERROR)
725 FreeAndClear(&info[17], TRUE);
726 FreeAndClear(&info[18], TRUE);
729 if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
734 if (GetValueFromUser("Network's status (? for help)",
735 &info[SN_STATUS]) == SUB_ERROR)
737 if (isdigit(info[SN_STATUS][0]))
739 Put_message("Valid status numbers:");
740 for (i = 0; i < 8; i++)
741 Put_message(subnet_states[i]);
743 if (GetValueFromUser("Network's contact", &info[SN_CONTACT]) == SUB_ERROR)
745 if (GetValueFromUser("Network's billing account number",
746 &info[SN_ACCT_NUMBER]) == SUB_ERROR)
748 if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
750 if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
752 if (atoi(info[SN_LOW]) == (int)ntohl(inet_addr(S_DEFAULT_LOW)))
755 unsigned long mask, addr;
757 addr = atoi(info[SN_ADDRESS]);
758 mask = atoi(info[SN_MASK]);
759 low.s_addr = atoi(info[SN_LOW]);
760 low.s_addr = (low.s_addr & ~mask) | (addr & mask);
762 sprintf(temp_buf, "%ld", low.s_addr);
763 info[SN_LOW] = strdup(temp_buf);
765 if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
768 if (atoi(info[SN_HIGH]) == (int)ntohl(inet_addr(S_DEFAULT_HIGH)))
771 unsigned long mask, addr;
773 addr = atoi(info[SN_ADDRESS]);
774 mask = atoi(info[SN_MASK]);
775 high.s_addr = atoi(info[SN_HIGH]);
776 high.s_addr = (high.s_addr & ~mask) | (addr & mask);
778 sprintf(temp_buf, "%ld", high.s_addr);
779 info[SN_HIGH] = strdup(temp_buf);
781 if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
784 if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
786 if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
789 if (strcmp(info[SN_ACE_TYPE], "NONE") &&
790 GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
792 if (!strcmp(info[SN_ACE_TYPE], "KERBEROS"))
796 mrcl_validate_kerberos_member(info[SN_ACE_NAME], &canon);
797 if (mrcl_get_message())
798 Put_message(mrcl_get_message());
799 free(info[SN_ACE_NAME]);
800 info[SN_ACE_NAME] = canon;
802 FreeAndClear(&info[SN_MODTIME], TRUE);
803 FreeAndClear(&info[SN_MODBY], TRUE);
804 FreeAndClear(&info[SN_MODWITH], TRUE);
807 if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
810 if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
813 FreeAndClear(&info[C_MODTIME], TRUE);
814 FreeAndClear(&info[C_MODBY], TRUE);
815 FreeAndClear(&info[C_MODWITH], TRUE);
818 if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
821 if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
825 if (GetValueFromUser("Container's Description:", &info[CON_DESCRIPT]) ==
828 if (GetValueFromUser("Container's Location:", &info[CON_LOCATION]) ==
831 if (GetValueFromUser("Container's Contact:", &info[CON_CONTACT]) ==
834 if (GetTypeFromUser("Container's owner type", "ace_type",
835 &info[CON_OWNER_TYPE]) == SUB_ERROR)
837 if (strcmp(info[CON_OWNER_TYPE], "NONE") &&
838 GetValueFromUser("Owner's Name", &info[CON_OWNER_NAME]) == SUB_ERROR)
840 if (!strcmp(info[CON_OWNER_TYPE], "KERBEROS"))
844 mrcl_validate_kerberos_member(info[CON_OWNER_NAME], &canon);
845 if (mrcl_get_message())
846 Put_message(mrcl_get_message());
847 free(info[CON_OWNER_NAME]);
848 info[CON_OWNER_NAME] = canon;
850 if (GetTypeFromUser("Container's Membership ACL", "ace_type",
851 &info[CON_MEMACE_TYPE]) == SUB_ERROR)
853 if (strcmp(info[CON_MEMACE_TYPE], "NONE") &&
854 GetValueFromUser("Membership ACL", &info[CON_MEMACE_NAME])
857 if (!strcmp(info[CON_MEMACE_TYPE], "KERBEROS"))
861 mrcl_validate_kerberos_member(info[CON_MEMACE_NAME], &canon);
862 if (mrcl_get_message())
863 Put_message(mrcl_get_message());
864 free(info[CON_MEMACE_NAME]);
865 info[CON_MEMACE_NAME] = canon;
867 FreeAndClear(&info[CON_MODTIME], TRUE);
868 FreeAndClear(&info[CON_MODBY], TRUE);
869 FreeAndClear(&info[CON_MODWITH], TRUE);
874 * Slide the newname into the #2 slot, this screws up all future references
878 SlipInNewName(info, newname);
883 /* ----------- Machine Menu ----------- */
885 /* Function Name: ShowMachineInfo
886 * Description: This function shows the information about a machine.
887 * Arguments: argc, argv - the name of the machine in argv[1].
888 * Returns: DM_NORMAL.
891 int ShowMachineInfo(int argc, char **argv)
896 tmpname = canonicalize_hostname(strdup(argv[1]));
897 top = GetMCInfo(MACHINE, tmpname, NULL);
898 Loop(top, ((void (*)(char **)) PrintMachInfo));
903 /* Function Name: ShowMachineQuery
904 * Description: This function shows the information about a machine.
905 * or group of machines, which may be selected through a
906 * number of criteria.
907 * Arguments: argc, argv - the name of the machine in argv[1],
908 * the address of the machine in argv[2],
909 * the location of the machine in argv[3],
910 * and the contact name in argv[4].
911 * any of these may be wildcards.
912 * Returns: DM_NORMAL.
915 int ShowMachineQuery(int argc, char **argv)
918 struct mqelem *top, *elem = NULL;
921 if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
922 !strcmp(argv[3], "") && !strcmp(argv[4], ""))
924 Put_message("You must specify at least one parameter of the query.");
929 args[0] = canonicalize_hostname(strdup(argv[1]));
945 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
947 if (stat == MR_NO_MATCH)
948 Put_message("No machine(s) found matching query in the database.");
950 com_err(program_name, stat, " in get_machine.");
953 top = QueueTop(elem);
954 Loop(top, ((void (*)(char **)) PrintMachInfo));
959 /* Function Name: AddMachine
960 * Description: This function adds a new machine to the database.
961 * Arguments: argc, argv - the name of the network in argv[1].
962 * Returns: DM_NORMAL.
965 int AddMachine(int argc, char **argv)
967 char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
969 struct mqelem *elem = NULL;
972 if (!ValidName(argv[1])) /* Checks for wildcards. */
976 * get the network record
979 if (strcasecmp(argv[1], "none") &&
980 (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
982 if (stat == MR_NO_MATCH)
985 sprintf(buf, "Network '%s' is not in the database.", argv[1]);
988 com_err(program_name, stat, " in get_subnet.");
993 * Check to see if this machine already exists.
996 name = strdup(""); /* want to put prefix here */
997 if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
1000 name = canonicalize_hostname(strdup(name));
1003 xargs[1] = xargs[2] = xargs[3] = "*";
1004 if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
1006 sprintf(buf, "The machine '%s' already exists.", name);
1011 else if (stat != MR_NO_MATCH)
1013 com_err(program_name, stat,
1014 " while checking machine '%s' in AddMachine.", name);
1018 rinfo = SetMachineDefaults(info, name);
1019 rinfo[M_SUBNET] = strdup(argv[1]);
1020 if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
1022 Put_message("Aborted.");
1027 * Actually create the new Machine.
1030 if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
1031 com_err(program_name, stat, " in AddMachine.");
1038 /* Function Name: RealUpdateMachine
1039 * Description: Performs the actual update of the machine data.
1040 * Arguments: info - the information on the machine to update.
1041 * junk - an UNUSED Boolean.
1045 static void RealUpdateMachine(char **info, Bool junk)
1048 char **args = AskMCDInfo(info, MACHINE, TRUE);
1051 Put_message("Aborted.");
1054 if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
1055 com_err(program_name, stat, " in UpdateMachine.");
1057 Put_message("Machine successfully updated.");
1060 /* Function Name: UpdateMachine
1061 * Description: This function adds a new machine to the database.
1062 * Arguments: argc, argv - the name of the machine in argv[1].
1063 * Returns: DM_NORMAL.
1066 int UpdateMachine(int argc, char **argv)
1071 tmpname = canonicalize_hostname(strdup(argv[1]));
1072 top = GetMCInfo(MACHINE, tmpname, NULL);
1073 QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
1080 /* Function Name: CheckAndRemoveFromCluster
1081 * Description: This func tests to see if a machine is in a cluster.
1082 * and if so then removes it
1083 * Arguments: name - name of the machine (already Canonicalized).
1084 * ask_user- query the user before removing if from clusters?
1085 * Returns: MR_ERROR if machine left in a cluster, or mr_error.
1088 int CheckAndRemoveFromCluster(char *name, Bool ask_user)
1090 int stat, ret_value;
1092 char *args[10], temp_buf[BUFSIZ], *ptr;
1093 struct mqelem *top, *elem = NULL;
1095 ret_value = SUB_NORMAL; /* initialize ret_value. */
1098 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1099 if (stat && stat != MR_NO_MATCH)
1101 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1104 if (stat == MR_SUCCESS)
1106 elem = top = QueueTop(elem);
1109 sprintf(temp_buf, "%s is assigned to the following clusters.", name);
1110 Put_message(temp_buf);
1111 Loop(top, (void (*)(char **)) PrintMCMap);
1112 ptr = "Remove this machine from ** ALL ** these clusters?";
1113 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1117 Put_message("Aborting...");
1129 char **info = elem->q_data;
1130 if ((stat = do_mr_query("delete_machine_from_cluster",
1131 2, info, NULL, NULL)))
1133 ret_value = SUB_ERROR;
1134 com_err(program_name, stat,
1135 " in delete_machine_from_cluster.");
1137 "Machine %s ** NOT ** removed from cluster %s.",
1138 info[MAP_MACHINE], info[MAP_CLUSTER]);
1139 Put_message(temp_buf);
1141 elem = elem->q_forw;
1148 /* Function Name: CheckAndRemoveCnames
1149 * Description: This func tests to see if a machine has cnames,
1150 * and if so then removes them.
1151 * Arguments: name - name of the machine (already Canonicalized).
1152 * ask_user- query the user before removing cnames?
1153 * Returns: MR_ERROR if machine left with a cname, or mr_error.
1156 int CheckAndRemoveCnames(char *name, Bool ask_user)
1158 int stat, ret_value;
1160 char *args[10], temp_buf[BUFSIZ], *ptr;
1161 struct mqelem *top, *elem = NULL;
1163 ret_value = SUB_NORMAL;
1166 stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem);
1167 if (stat && stat != MR_NO_MATCH)
1169 com_err(program_name, stat, " in get_hostalias.");
1172 if (stat == MR_SUCCESS)
1174 elem = top = QueueTop(elem);
1177 sprintf(temp_buf, "%s has the following cnames.", name);
1178 Put_message(temp_buf);
1179 Loop(top, (void (*)(char **)) PrintCname);
1180 ptr = "Remove ** ALL ** these cnames?";
1181 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1185 Put_message("Aborting...");
1197 char **info = elem->q_data;
1198 if ((stat = do_mr_query("delete_hostalias", 2, info,
1201 ret_value = SUB_ERROR;
1202 com_err(program_name, stat, " in delete_hostalias.");
1204 "Cname %s ** NOT ** removed from host %s.",
1206 Put_message(temp_buf);
1208 elem = elem->q_forw;
1215 /* Function Name: RealDeleteMachine
1216 * Description: Actually Deletes the Machine.
1217 * Arguments: info - nescessary information stored as an array of char *'s
1218 * one_machine - a boolean, true if there is only one item in
1223 static void RealDeleteMachine(char **info, Bool one_machine)
1226 char temp_buf[BUFSIZ];
1228 sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
1230 if (!one_machine || Confirm(temp_buf))
1232 if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
1234 if (CheckAndRemoveCnames(info[M_NAME], TRUE) != SUB_ERROR)
1236 if ((stat = do_mr_query("delete_host", 1,
1237 &info[M_NAME], NULL, NULL)))
1239 com_err(program_name, stat, " in DeleteMachine.");
1240 sprintf(temp_buf, "%s ** NOT ** deleted.",
1242 Put_message(temp_buf);
1246 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
1247 Put_message(temp_buf);
1254 /* Function Name: DeleteMachine
1255 * Description: This function removes a machine from the data base.
1256 * Arguments: argc, argv - the machines name int argv[1].
1257 * Returns: DM_NORMAL.
1260 /* Perhaps we should remove the cluster if it has no machine now. */
1262 int DeleteMachine(int argc, char **argv)
1267 tmpname = canonicalize_hostname(strdup(argv[1]));
1268 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
1269 QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
1276 /* Function Name: ShowCname
1277 * Description: This function shows machine aliases
1278 * Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1279 * Returns: DM_NORMAL.
1282 int ShowCname(int argc, char **argv)
1285 char *tmpalias, *tmpname;
1287 tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
1288 tmpname = canonicalize_hostname(strdup(argv[2]));
1289 top = GetMCInfo(CNAME, tmpalias, tmpname);
1290 Put_message(""); /* blank line on screen */
1291 Loop(top, ((void (*)(char **)) PrintCname));
1297 int AddCname(int argc, char **argv)
1302 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1303 args[1] = canonicalize_hostname(strdup(argv[2]));
1304 stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
1310 Put_message("That alias name is already in use.");
1313 Put_message("Permission denied. "
1314 "(Regular users can only add two aliases to a host.");
1317 com_err(program_name, stat, " in add_hostalias");
1323 int DeleteCname(int argc, char **argv)
1328 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1329 args[1] = canonicalize_hostname(strdup(argv[2]));
1330 stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
1332 com_err(program_name, stat, " in delete_hostalias");
1337 /* Function Name: AddMachineToCluster
1338 * Description: This function adds a machine to a cluster
1339 * Arguments: argc, argv - The machine name is argv[1].
1340 * The cluster name in argv[2].
1341 * Returns: DM_NORMAL.
1344 int AddMachineToCluster(int argc, char **argv)
1347 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1348 Bool add_it, one_machine, one_cluster;
1349 struct mqelem *melem, *mtop, *celem, *ctop;
1351 machine = canonicalize_hostname(strdup(argv[1]));
1352 if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
1354 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1356 Put_message(temp_buf);
1360 celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
1361 melem = mtop = GetMCInfo(MACHINE, machine, NULL);
1364 one_machine = (QueueCount(mtop) == 1);
1365 one_cluster = (QueueCount(ctop) == 1);
1367 /* No good way to use QueryLoop() here, sigh */
1371 char **minfo = melem->q_data;
1374 char **cinfo = celem->q_data;
1375 if (one_machine && one_cluster)
1379 sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
1380 minfo[M_NAME], cinfo[C_NAME]);
1381 switch (YesNoQuitQuestion(temp_buf, FALSE))
1390 Put_message("Aborting...");
1398 args[0] = minfo[M_NAME];
1399 args[1] = cinfo[C_NAME];
1400 stat = do_mr_query("add_machine_to_cluster", 2, args,
1407 sprintf(temp_buf, "%s is already in cluster %s",
1408 minfo[M_NAME], cinfo[C_NAME]);
1409 Put_message(temp_buf);
1412 com_err(program_name, stat, " in AddMachineToCluster.");
1416 celem = celem->q_forw;
1418 celem = ctop; /* reset cluster element. */
1419 melem = melem->q_forw;
1426 /* Function Name: RealRemoveMachineFromCluster
1427 * Description: This function actually removes the machine from its
1429 * Arguments: info - all information nescessary to perform the removal.
1430 * one_map - True if there is only one case, and we should
1435 static void RealRemoveMachineFromCluster(char **info, Bool one_map)
1437 char temp_buf[BUFSIZ];
1440 sprintf(temp_buf, "Remove %s from the cluster %s",
1441 info[MAP_MACHINE], info[MAP_CLUSTER]);
1442 if (!one_map || Confirm(temp_buf))
1444 if ((stat = do_mr_query("delete_machine_from_cluster", 2,
1446 com_err(program_name, stat, " in delete_machine_from_cluster");
1449 sprintf(temp_buf, "%s has been removed from the cluster %s.",
1450 info[MAP_MACHINE], info[MAP_CLUSTER]);
1451 Put_message(temp_buf);
1455 Put_message("Machine not removed.");
1458 /* Function Name: RemoveMachineFromCluster
1459 * Description: Removes this machine form a specific cluster.
1460 * Arguments: argc, argv - Name of machine in argv[1].
1461 * Name of cluster in argv[2].
1465 int RemoveMachineFromCluster(int argc, char **argv)
1467 struct mqelem *elem = NULL;
1468 char buf[BUFSIZ], *args[10];
1471 args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
1472 if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
1474 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1475 argv[1], args[MAP_MACHINE]);
1478 args[MAP_CLUSTER] = argv[2];
1479 args[MAP_END] = NULL;
1481 stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1483 if (stat == MR_NO_MATCH)
1485 sprintf(buf, "The machine %s is not in the cluster %s.",
1486 args[MAP_MACHINE], args[MAP_CLUSTER]);
1488 free(args[MAP_MACHINE]);
1491 if (stat != MR_SUCCESS)
1492 com_err(program_name, stat, " in delete_machine_from_cluster");
1494 elem = QueueTop(elem);
1495 QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1496 "Remove this machine from this cluster");
1499 free(args[MAP_MACHINE]);
1503 /* ---------- Subnet Menu -------- */
1505 /* Function Name: ShowSubnetInfo
1506 * Description: Gets information about a subnet given its name.
1507 * Arguments: argc, argc - the name of the subnet in in argv[1].
1508 * Returns: DM_NORMAL.
1511 int ShowSubnetInfo(int argc, char **argv)
1515 top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1516 Loop(top, (void (*)(char **)) PrintSubnetInfo);
1521 /* Function Name: AddSubnet
1522 * Description: Creates a new subnet.
1523 * Arguments: argc, argv - the name of the new subnet is argv[1].
1524 * Returns: DM_NORMAL.
1527 int AddSubnet(int argc, char **argv)
1529 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1533 * Check to see if this subnet already exists.
1535 if (!ValidName(name))
1538 if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
1540 Put_message("This subnet already exists.");
1543 else if (stat != MR_NO_MATCH)
1545 com_err(program_name, stat, " in AddSubnet.");
1548 if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
1550 Put_message("Aborted.");
1556 * Actually create the new Subnet.
1558 if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
1559 com_err(program_name, stat, " in AddSubnet.");
1565 /* Function Name: RealUpdateSubnet
1566 * Description: This function actually performs the subnet update.
1567 * Arguments: info - all information nesc. for updating the subnet.
1568 * junk - an UNUSED boolean.
1572 static void RealUpdateSubnet(char **info, Bool junk)
1575 char **args = AskMCDInfo(info, SUBNET, TRUE);
1578 Put_message("Aborted.");
1581 if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
1582 com_err(program_name, stat, " in UpdateSubnet.");
1584 Put_message("Subnet successfully updated.");
1587 /* Function Name: UpdateSubnet
1588 * Description: This Function Updates a subnet
1589 * Arguments: name of the subnet in argv[1].
1590 * Returns: DM_NORMAL.
1593 int UpdateSubnet(int argc, char **argv)
1596 top = GetMCInfo(SUBNET, argv[1], NULL);
1597 QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1603 /* Function Name: RealDeleteSubnet
1604 * Description: Actually performs the subnet deletion.
1605 * Arguments: info - all information about this subnet.
1606 * one_subnet - If true then there was only one subnet in
1607 * the queue, and we should confirm.
1611 static void RealDeleteSubnet(char **info, Bool one_subnet)
1614 char temp_buf[BUFSIZ];
1617 "Are you sure the you want to delete the subnet %s (y/n) ?",
1619 if (!one_subnet || Confirm(temp_buf))
1621 if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
1623 com_err(program_name, stat, " in delete_subnet.");
1624 sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
1625 Put_message(temp_buf);
1629 sprintf(temp_buf, "subnet %s successfully deleted.",
1631 Put_message(temp_buf);
1636 /* Function Name: DeleteSubnet
1637 * Description: This function removes a subnet from the database.
1638 * Arguments: argc, argv - the name of the subnet is stored in argv[1].
1639 * Returns: DM_NORMAL.
1642 int DeleteSubnet(int argc, char **argv)
1646 top = GetMCInfo(SUBNET, argv[1], NULL);
1647 QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1653 /* ---------- Cluster Menu -------- */
1655 /* Function Name: ShowClusterInfo
1656 * Description: Gets information about a cluser given its name.
1657 * Arguments: argc, argc - the name of the cluster in in argv[1].
1658 * Returns: DM_NORMAL.
1661 int ShowClusterInfo(int argc, char **argv)
1665 top = GetMCInfo(CLUSTER, argv[1], NULL);
1666 Loop(top, (void (*)(char **)) PrintClusterInfo);
1671 /* Function Name: AddCluster
1672 * Description: Creates a new cluster.
1673 * Arguments: argc, argv - the name of the new cluster is argv[1].
1674 * Returns: DM_NORMAL.
1677 int AddCluster(int argc, char **argv)
1679 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1683 * Check to see if this cluster already exists.
1685 if (!ValidName(name))
1688 if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
1690 Put_message("This cluster already exists.");
1693 else if (stat != MR_NO_MATCH)
1695 com_err(program_name, stat, " in AddCluster.");
1698 if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
1700 Put_message("Aborted.");
1706 * Actually create the new Cluster.
1708 if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
1709 com_err(program_name, stat, " in AddCluster.");
1715 /* Function Name: RealUpdateCluster
1716 * Description: This function actually performs the cluster update.
1717 * Arguments: info - all information nesc. for updating the cluster.
1718 * junk - an UNUSED boolean.
1722 static void RealUpdateCluster(char **info, Bool junk)
1725 char **args = AskMCDInfo(info, CLUSTER, TRUE);
1729 Put_message("Aborted.");
1732 if ((stat = do_mr_query("update_cluster", CountArgs(args),
1734 com_err(program_name, stat, " in UpdateCluster.");
1736 Put_message("Cluster successfully updated.");
1739 /* Function Name: UpdateCluster
1740 * Description: This Function Updates a cluster
1741 * Arguments: name of the cluster in argv[1].
1742 * Returns: DM_NORMAL.
1745 int UpdateCluster(int argc, char **argv)
1748 top = GetMCInfo(CLUSTER, argv[1], NULL);
1749 QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1755 /* Function Name: CheckAndRemoveMachine
1756 * Description: This function checks and removes all machines from a
1758 * Arguments: name - name of the cluster.
1759 * ask_first - if TRUE, then we will query the user, before
1761 * Returns: SUB_ERROR if all machines not removed.
1764 int CheckAndRemoveMachines(char *name, Bool ask_first)
1766 int stat, ret_value;
1768 char *args[10], temp_buf[BUFSIZ], *ptr;
1769 struct mqelem *top, *elem = NULL;
1771 ret_value = SUB_NORMAL;
1772 args[MAP_MACHINE] = "*";
1773 args[MAP_CLUSTER] = name;
1774 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1775 if (stat && stat != MR_NO_MATCH)
1777 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1780 if (stat == MR_SUCCESS)
1782 elem = top = QueueTop(elem);
1785 sprintf(temp_buf, "The cluster %s has the following machines in it:",
1787 Put_message(temp_buf);
1790 char **info = elem->q_data;
1791 Print(1, &info[MAP_MACHINE], (char *) NULL);
1792 elem = elem->q_forw;
1794 ptr = "Remove ** ALL ** these machines from this cluster?";
1796 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1800 Put_message("Aborting...");
1813 char **info = elem->q_data;
1814 if ((stat = do_mr_query("delete_machine_from_cluster",
1815 2, info, NULL, NULL)))
1817 ret_value = SUB_ERROR;
1818 com_err(program_name, stat,
1819 " in delete_machine_from_cluster.");
1821 "Machine %s ** NOT ** removed from cluster %s.",
1822 info[MAP_MACHINE], info[MAP_CLUSTER]);
1823 Put_message(temp_buf);
1825 elem = elem->q_forw;
1832 /* Function Name: RealDeleteCluster
1833 * Description: Actually performs the cluster deletion.
1834 * Arguments: info - all information about this cluster.
1835 * one_cluster - If true then there was only one cluster in
1836 * the queue, and we should confirm.
1840 static void RealDeleteCluster(char **info, Bool one_cluster)
1843 char temp_buf[BUFSIZ];
1846 "Are you sure the you want to delete the cluster %s (y/n) ?",
1848 if (!one_cluster || Confirm(temp_buf))
1850 if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
1852 if ((stat = do_mr_query("delete_cluster", 1,
1853 &info[C_NAME], NULL, NULL)))
1855 com_err(program_name, stat, " in delete_cluster.");
1856 sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
1857 Put_message(temp_buf);
1861 sprintf(temp_buf, "cluster %s successfully deleted.",
1863 Put_message(temp_buf);
1869 /* Function Name: DeleteCluster
1870 * Description: This function removes a cluster from the database.
1871 * Arguments: argc, argv - the name of the cluster is stored in argv[1].
1872 * Returns: DM_NORMAL.
1875 int DeleteCluster(int argc, char **argv)
1879 top = GetMCInfo(CLUSTER, argv[1], NULL);
1880 QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1886 /* ----------- Cluster Data Menu -------------- */
1888 /* Function Name: ShowClusterData
1889 * Description: This function shows the services for one cluster.
1890 * Arguments: argc, argv - The name of the cluster is argv[1].
1891 * The label of the data in argv[2].
1892 * Returns: DM_NORMAL.
1895 int ShowClusterData(int argc, char **argv)
1897 struct mqelem *elem, *top;
1900 top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1903 info = elem->q_data;
1904 PrintClusterData(info);
1905 elem = elem->q_forw;
1911 /* Function Name: AddClusterData
1912 * Description: This function adds some data to the cluster.
1913 * Arguments: argv, argc: argv[1] - the name of the cluster.
1914 * argv[2] - the label of the data.
1915 * argv[3] - the data.
1916 * Returns: DM_NORMAL.
1919 int AddClusterData(int argc, char **argv)
1923 for (i = 1; i < 4; i++)
1925 if (IS_EMPTY(argv[i]))
1927 Put_message("Cluster data cannot be an empty string.");
1931 if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
1932 com_err(program_name, stat, " in AddClusterData.");
1936 /* Function Name: RealRemoveClusterData
1937 * Description: actually removes the cluster data.
1938 * Arguments: info - all info necessary to remove the cluster, in an array
1940 * one_item - if true then the queue has only one elem and we
1945 static void RealRemoveClusterData(char **info, Bool one_item)
1951 temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1952 PrintClusterData(info);
1953 if (!one_item || Confirm(temp_ptr))
1955 if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
1957 com_err(program_name, stat, " in DeleteClusterData.");
1958 Put_message("Data not removed.");
1961 Put_message("Removal successful.");
1965 /* Function Name: RemoveClusterData
1966 * Description: This function removes data on a given cluster.
1967 * Arguments: argv, argc: argv[1] - the name of the cluster.
1968 * argv[2] - the label of the data.
1969 * argv[3] - the data.
1970 * Returns: DM_NORMAL.
1973 int RemoveClusterData(int argc, char **argv)
1977 top = GetMCInfo(DATA, argv[1], argv[2]);
1978 QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1979 "Remove data from cluster");
1985 /* Function Name: MachineToClusterMap
1986 * Description: This Retrieves the mapping between machine and cluster
1987 * Arguments: argc, argv - argv[1] -> machine name or wildcard.
1988 * argv[2] -> cluster name or wildcard.
1992 int MachineToClusterMap(int argc, char **argv)
1994 struct mqelem *elem, *top;
1995 char *tmpname, temp_buf[256];
1997 tmpname = canonicalize_hostname(strdup(argv[1]));
1998 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
2000 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2002 Put_message(temp_buf);
2004 top = elem = GetMCInfo(MAP, tmpname, argv[2]);
2006 Put_message(""); /* blank line on screen */
2009 char **info = elem->q_data;
2011 elem = elem->q_forw;
2019 /* Function Name: MachineByOwner
2020 * Description: This function prints all machines which are owned by
2021 * a given user or group.
2023 * Returns: DM_NORMAL.
2026 int MachineByOwner(int argc, char **argv)
2028 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
2031 type = strdup("USER");
2032 if (GetTypeFromUser("Type of owner", "ace_type", &type) == SUB_ERROR)
2035 sprintf(buf, "Name of %s", type);
2036 name = strdup(user);
2037 if (GetValueFromUser(buf, &name) == SUB_ERROR)
2040 switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE))
2043 sprintf(temp_buf, "R%s", type); /* "USER to "RUSER", etc. */
2045 type = strdup(temp_buf);
2053 top = GetMachineByOwner(type, name);
2054 Loop(top, PrintMachine);
2060 /* Function Name: GetMachineByOwner
2061 * Description: This function stores information retrieved by
2062 * the get_host_by_owner query
2063 * Arguments: type - an ace_type, argv[0] for the query
2064 * name - name of machine, argv[1] for the query
2065 * Returns: the top element of a queue returning the data, or NULL.
2068 struct mqelem *GetMachineByOwner(char *type, char *name)
2071 struct mqelem *elem = NULL;
2076 if ((status = do_mr_query("get_host_by_owner", 2, args, StoreInfo, &elem)))
2078 com_err(program_name, status, " in get_host_by_owner");
2081 return QueueTop(elem);
2084 int MachineByAcctNumber(int argc, char **argv)
2086 char *args[1], *account_number;
2088 struct mqelem *elem = NULL;
2090 account_number = strdup("");
2091 if (GetValueFromUser("Account Number", &account_number) == SUB_ERROR)
2094 args[0] = account_number;
2095 if (status = do_mr_query("get_host_by_account_number", 1, args, StoreInfo,
2098 com_err(program_name, status, " in get_host_by_account_number");
2101 Loop(QueueTop(elem), (void (*)(char **)) PrintMachInfo);
2107 int ShowContainerInfo(int argc, char **argv)
2111 top = GetMCInfo(CONTAINER, argv[1], NULL);
2112 Loop(top, (void (*)(char **)) PrintContainerInfo);
2117 static char *PrintContainerInfo(char **info)
2119 char buf[BUFSIZ], tbuf[256];
2122 sprintf(buf, "Container: %-16s", info[CON_NAME]);
2124 sprintf(buf, "Description: %-16s", info[CON_DESCRIPT]);
2126 sprintf(buf, "Location: %-16s Contact: %s", info[CON_LOCATION],
2129 sprintf(tbuf, "%s %s", info[CON_OWNER_TYPE],
2130 strcmp(info[CON_OWNER_TYPE], "NONE") ? info[CON_OWNER_NAME] : "");
2131 sprintf(buf, "Owner: %-16s", tbuf);
2133 sprintf(tbuf, "%s %s", info[CON_MEMACE_TYPE],
2134 strcmp(info[CON_MEMACE_TYPE], "NONE") ? info[CON_MEMACE_NAME] : "");
2135 sprintf(buf, "Membership ACL: %-16s", tbuf);
2138 sprintf(buf, MOD_FORMAT, info[CON_MODBY], info[CON_MODTIME],
2141 return info[CON_NAME];
2144 static char *PrintContainer(char **info)
2148 sprintf(buf, "Container: %s", info[CON_NAME]);
2153 static char *PrintMContMap(char **info)
2156 sprintf(buf, "Container: %-30s Machine: %-20s",
2162 int AddContainer(int argc, char **argv)
2164 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
2167 /* Can't use ValidName() because spaces are allowed in container names */
2170 Put_message("Please use a non-empty name.");
2174 if (strchr(name, '*') || strchr(name, '?'))
2176 Put_message("Wildcards not accepted here.");
2180 /* Check if this cluster already exists. */
2181 if ((stat = do_mr_query("get_container", 1, &name, NULL, NULL))
2184 Put_message("This container already exists.");
2187 else if (stat != MR_NO_MATCH)
2189 com_err(program_name, stat, " in AddContainer.");
2192 if (!(args = AskMCDInfo(SetContainerDefaults(info, name), CONTAINER, FALSE)))
2194 Put_message("Aborted.");
2199 /* Create the new container. */
2200 if ((stat = do_mr_query("add_container", CountArgs(args), args, NULL, NULL)))
2201 com_err(program_name, stat, " in AddContainer.");
2207 int UpdateContainer(int argc, char **argv)
2210 top = GetMCInfo(CONTAINER, argv[1], NULL);
2211 QueryLoop(top, NullPrint, RealUpdateContainer, "Update the container");
2217 static void RealUpdateContainer(char **info, Bool junk)
2220 char **args = AskMCDInfo(info, CONTAINER, TRUE);
2224 Put_message("Aborted.");
2227 if ((stat = do_mr_query("update_container", CountArgs(args), args,
2229 com_err(program_name, stat, " in UpdateContainer.");
2231 Put_message("Container successfully updated.");
2234 int DeleteContainer(int argc, char **argv)
2238 top = GetMCInfo(CONTAINER, argv[1], NULL);
2239 QueryLoop(top, PrintClusterInfo, RealDeleteContainer,
2240 "Delete the container");
2246 static void RealDeleteContainer(char **info, Bool one_container)
2249 char temp_buf[BUFSIZ];
2252 "Are you sure you want to delete the container %s (y/n) ?",
2254 if (!one_container || Confirm(temp_buf))
2256 if (CheckAndRemoveMachinesFromContainer(info[CON_NAME], TRUE)
2259 if ((stat = do_mr_query("delete_container", 1, &info[CON_NAME],
2262 com_err(program_name, stat, " in delete_container.");
2263 sprintf(temp_buf, "Container %s ** NOT ** deleted.",
2265 Put_message(temp_buf);
2269 sprintf(temp_buf, "Container %s successfully deleted.",
2271 Put_message(temp_buf);
2277 int CheckAndRemoveMachinesFromContainer(char *name, Bool ask_first)
2279 int stat, ret_value;
2281 char *args[10], temp_buf[BUFSIZ], *ptr;
2282 struct mqelem *top, *elem = NULL;
2284 ret_value = SUB_NORMAL;
2287 stat = do_mr_query("get_machines_of_container", 2, args, StoreInfo,
2289 if (stat && stat != MR_NO_MATCH)
2291 com_err(program_name, stat, " in get_machines_of_container");
2294 if (stat == MR_SUCCESS)
2296 elem = top = QueueTop(elem);
2300 "The container %s has the following machines in it:", name);
2301 Put_message(temp_buf);
2304 char **info = elem->q_data;
2305 Print(1, &info[0], (char *) NULL);
2306 elem = elem->q_forw;
2308 ptr = "Remove ** ALL ** these machines from this container?";
2310 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
2314 Put_message("Aborting...");
2327 char **info = elem->q_data;
2328 if ((stat = do_mr_query("delete_machine_from_container",
2329 2, info, NULL, NULL)))
2331 ret_value = SUB_ERROR;
2332 com_err(program_name, stat,
2333 " in delete_machine_from_container.");
2335 "Machine %s ** NOT ** removed from container %s.",
2337 Put_message(temp_buf);
2339 elem = elem->q_forw;
2346 int GetSubContainers(int argc, char **argv)
2349 struct mqelem *elem = NULL, *top = NULL;
2354 if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
2359 if (stat = do_mr_query("get_subcontainers_of_container", 2, args,
2361 com_err(program_name, stat, " in get_subcontainers_of_container");
2363 top = QueueTop(elem);
2364 Loop(top, ((void (*)(char **)) PrintContainer));
2369 int MachineToContainerMap(int argc, char **argv)
2371 struct mqelem *elem, *top;
2372 char *tmpname, temp_buf[256];
2374 tmpname = canonicalize_hostname(strdup(argv[1]));
2375 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
2377 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2379 Put_message(temp_buf);
2381 top = elem = GetMCInfo(CONTMAP, tmpname, NULL);
2386 char **info = elem->q_data;
2387 PrintMContMap(info);
2388 elem = elem->q_forw;
2396 int AddMachineToContainer(int argc, char **argv)
2399 char *machine, *container, temp_buf[BUFSIZ], *args[10];
2400 Bool add_it, one_machine, one_container;
2401 struct mqelem *melem, *mtop, *celem, *ctop;
2403 machine = canonicalize_hostname(strdup(argv[1]));
2404 if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
2406 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2408 Put_message(temp_buf);
2410 container = argv[2];
2412 celem = ctop = GetMCInfo(CONTAINER, container, NULL);
2413 melem = mtop = GetMCInfo(MACHINE, machine, NULL);
2416 one_machine = (QueueCount(mtop) == 1);
2417 one_container = (QueueCount(ctop) == 1);
2421 char **minfo = melem->q_data;
2424 char **cinfo = celem->q_data;
2425 if (one_machine && one_container)
2429 sprintf(temp_buf, "Add machine %s to container %s (y/n/q) ?",
2430 minfo[M_NAME], cinfo[CON_NAME]);
2431 switch (YesNoQuestion(temp_buf, FALSE))
2440 Put_message("Aborting...");
2448 args[0] = minfo[M_NAME];
2449 args[1] = cinfo[CON_NAME];
2450 stat = do_mr_query("add_machine_to_container", 2, args, NULL,
2457 sprintf(temp_buf, "%s is already in container %s",
2458 minfo[M_NAME], cinfo[CON_NAME]);
2459 Put_message(temp_buf);
2462 com_err(program_name, stat, " in AddMachineToContainer.");
2466 celem = celem->q_forw;
2469 melem = melem->q_forw;
2476 int RemoveMachineFromContainer(int argc, char **argv)
2478 struct mqelem *elem = NULL;
2479 char buf[BUFSIZ], *args[10];
2482 args[0] = canonicalize_hostname(strdup(argv[1]));
2483 if (strcasecmp(args[0], argv[1]) && *argv[1] != '"')
2485 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
2492 stat = do_mr_query("get_machine_to_container_map", 1, args, StoreInfo,
2494 if (stat == MR_NO_MATCH)
2496 sprintf(buf, "The machine %s is not in the container %s.",
2502 if (stat != MR_SUCCESS)
2503 com_err(program_name, stat, " in deleter_machine_from_container");
2505 elem = QueueTop(elem);
2506 QueryLoop(elem, PrintMContMap, RealRemoveMachineFromContainer,
2507 "Remove this machine from this container");
2514 static void RealRemoveMachineFromContainer(char **info, Bool one_contmap)
2516 char temp_buf[BUFSIZ];
2519 sprintf(temp_buf, "Remove %s from the container %s",
2521 if (!one_contmap || Confirm(temp_buf))
2523 if ((stat = do_mr_query("delete_machine_from_container", 2,
2525 com_err(program_name, stat, " in delete_machine_from_container");
2528 sprintf(temp_buf, "%s has been removed from the container %s.",
2530 Put_message(temp_buf);
2534 Put_message("Machine not removed.");
2537 int GetMachinesOfContainer(int argc, char **argv)
2540 struct mqelem *elem = NULL, *top = NULL;
2545 if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
2550 if (stat = do_mr_query("get_machines_of_container", 2, args,
2552 com_err(program_name, stat, " in get_machines_of_container");
2554 top = QueueTop(elem);
2555 Loop(top, ((void (*)(char **)) PrintMContMap));
2560 int GetTopLevelCont(int argc, char **argv)
2563 struct mqelem *elem = NULL;
2564 if (status = do_mr_query("get_toplevel_containers", 0, NULL, StoreInfo,
2567 com_err(program_name, status, " in get_toplevel_containers");
2570 Loop(QueueTop(elem), (void(*)(char **)) PrintContainer);