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)"
97 static char *MacState(int state)
99 static char buf[BUFSIZ];
101 if (state < 0 || state > 3)
103 sprintf(buf, "Unknown (%d)", state);
106 return states[state];
109 static char *SubnetState(int state)
111 static char buf[BUFSIZ];
113 if (state < 0 || state > 7)
115 sprintf(buf, "Unknown (%d)", state);
118 return subnet_states[state];
121 /* -------------------- Set Defaults -------------------- */
123 /* Function Name: SetMachineDefaults
124 * Description: sets machine defaults.
125 * Arguments: info - an array to put the defaults into.
126 * name - Canonacalized name of the machine.
127 * Returns: info - the array.
130 static char **SetMachineDefaults(char **info, char *name)
132 info[M_NAME] = strdup(name);
133 info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
134 info[M_MODEL] = strdup(M_DEFAULT_TYPE);
135 info[M_OS] = strdup(M_DEFAULT_TYPE);
136 info[M_LOC] = strdup(M_DEFAULT_TYPE);
137 info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
138 info[M_BILL_CONTACT] = strdup(M_DEFAULT_TYPE);
139 info[M_ACCT_NUMBER] = strdup("");
140 info[M_USE] = strdup("0");
141 info[M_STAT] = strdup("1");
142 info[M_SUBNET] = strdup("NONE");
143 info[M_ADDR] = strdup("unique");
144 info[M_OWNER_TYPE] = strdup("NONE");
145 info[M_OWNER_NAME] = strdup("NONE");
146 info[M_ACOMMENT] = strdup("");
147 info[M_OCOMMENT] = strdup("");
148 info[17] = info[18] = NULL;
152 /* Function Name: SetClusterDefaults
153 * Description: sets Cluster defaults.
154 * Arguments: info - an array to put the defaults into.
155 * name - name of the Cluster.
156 * Returns: info - the array.
159 static char **SetClusterDefaults(char **info, char *name)
161 info[C_NAME] = strdup(name);
162 info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
163 info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
164 info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
168 static char **SetContainerDefaults(char **info, char *name)
170 info[CON_NAME] = strdup(name);
171 info[CON_DESCRIPT] = strdup(CON_DEFAULT_TYPE);
172 info[CON_LOCATION] = strdup(CON_DEFAULT_TYPE);
173 info[CON_CONTACT] = strdup(CON_DEFAULT_TYPE);
174 info[CON_OWNER_TYPE] = strdup("NONE");
175 info[CON_OWNER_NAME] = strdup("NONE");
176 info[CON_MEMACE_TYPE] = strdup("NONE");
177 info[CON_MEMACE_NAME] = strdup("NONE");
178 info[CON_MODBY] = info[CON_MODTIME] = info[CON_MODWITH] = NULL;
179 info[CON_END] = NULL;
183 /* Function Name: SetSubnetDefaults
184 * Description: sets Subnet defaults.
185 * Arguments: info - an array to put the defaults into.
186 * name - name of the Subnet.
187 * Returns: info - the array.
190 static char **SetSubnetDefaults(char **info, char *name)
194 info[SN_NAME] = strdup(name);
195 info[SN_DESC] = strdup("");
196 info[SN_STATUS] = strdup("1");
197 info[SN_CONTACT] = strdup(DEFAULT_NONE);
198 info[SN_ACCT_NUMBER] = strdup("");
199 sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
200 info[SN_ADDRESS] = strdup(buf);
201 sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
202 info[SN_MASK] = strdup(buf);
203 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
204 info[SN_LOW] = strdup(buf);
205 sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
206 info[SN_HIGH] = strdup(buf);
207 info[SN_PREFIX] = strdup("");
208 info[SN_ACE_TYPE] = strdup("LIST");
209 info[SN_ACE_NAME] = strdup("network");
210 info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
214 /* -------------------- General Functions -------------------- */
216 static char aliasbuf[256];
218 void PrintAliases(char **info)
220 if (strlen(aliasbuf) == 0)
221 sprintf(aliasbuf, "Aliases: %s", info[0]);
224 strcat(aliasbuf, ", ");
225 strcat(aliasbuf, info[0]);
230 /* Function Name: PrintMachInfo
231 * Description: This function Prints out the Machine info in
233 * Arguments: info - array of information about a machine.
234 * Returns: The name of the Machine
237 static char *PrintMachInfo(char **info)
239 char buf[BUFSIZ], tbuf[256];
241 struct mqelem *elem = NULL, *elem2 = NULL;
245 sprintf(buf, "Machine: %s", info[M_NAME]);
248 args[1] = info[M_NAME];
249 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
251 if (stat != MR_NO_MATCH)
252 com_err(program_name, stat, " looking up aliases");
257 Loop(QueueTop(elem), (void (*)(char **)) PrintAliases);
259 Put_message(aliasbuf);
261 sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
262 strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
263 sprintf(buf, "Address: %-16s Network: %-16s",
264 info[M_ADDR], info[M_SUBNET]);
266 sprintf(buf, "Owner: %-16s Use data: %s", tbuf, info[M_INUSE]);
268 sprintf(buf, "Status: %-16s Changed: %s",
269 MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
272 sprintf(buf, "Vendor: %-16s Location: %s", info[M_VENDOR],
275 sprintf(buf, "Model: %-16s Contact: %s", info[M_MODEL],
278 sprintf(buf, "OS: %-16s Billing Contact: %s", info[M_OS],
279 info[M_BILL_CONTACT]);
281 sprintf(buf, "Opt: %-16s Account Number: %s", info[M_USE],
282 info[M_ACCT_NUMBER]);
285 sprintf(buf, "Adm cmt: %s", info[M_ACOMMENT]);
287 sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]);
290 sprintf(buf, "Created by %s on %s", info[M_CREATOR], info[M_CREATED]);
292 sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
294 /* Do a get_subnet for the machine's subnet. We need to know if it's
297 args[0] = info[M_SUBNET];
298 stat = do_mr_query("get_subnet", 1, args, StoreInfo, &elem2);
300 com_err(program_name, stat, " looking up subnet info");
301 else if (atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_10MBPS ||
302 atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_100MBPS ||
303 atoi(((char **)elem2->q_data)[2]) == SNET_STATUS_PRIVATE_1000MBPS)
306 sprintf(buf, "Warning: This host is on a private subnet.");
308 sprintf(buf, "Billing information shown is superseded by billing information for the subnet.");
316 /* Function Name: PrintMachine
317 * Description: Prints the name of a machine record
318 * Arguments: info - array of information about the machine.
322 static void PrintMachine(char **info)
326 sprintf(buf, "Machine: %s", info[M_NAME]);
330 /* Function Name: PrintCname
331 * Description: Prints the Data on a host alias
332 * Arguments: info a pointer to the data array.
333 * Returns: The name of the alias.
336 static char *PrintCname(char **info)
340 sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
345 /* Function Name: PrintClusterInfo
346 * Description: This function Prints out the cluster info
347 * in a coherent form.
348 * Arguments: info - array of information about a cluster.
349 * Returns: The name of the cluster.
352 static char *PrintClusterInfo(char **info)
357 sprintf(buf, "Cluster: %s", info[C_NAME]);
359 sprintf(buf, "Description: %s", info[C_DESCRIPT]);
361 sprintf(buf, "Location: %s", info[C_LOCATION]);
363 sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
368 /* Function Name: PrintClusterData
369 * Description: Prints the Data on a cluster
370 * Arguments: info a pointer to the data array.
371 * Returns: The name of the cluster.
374 static char *PrintClusterData(char **info)
379 sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
380 info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
382 return info[CD_NAME];
385 /* Function Name: PrintMCMap
386 * Description: Prints the data about a machine to cluster mapping.
387 * Arguments: info a pointer to the data array.
391 static char *PrintMCMap(char **info)
394 sprintf(buf, "Cluster: %-30s Machine: %-20s",
395 info[MAP_CLUSTER], info[MAP_MACHINE]);
397 return ""; /* Used by QueryLoop(). */
400 /* Function Name: PrintSubnetInfo
401 * Description: This function Prints out the subnet info
402 * in a coherent form.
403 * Arguments: info - array of information about a subnet.
404 * Returns: The name of the subnet.
407 static char *PrintSubnetInfo(char **info)
410 struct in_addr addr, mask, low, high;
413 sprintf(buf, " Network: %s", info[SN_NAME]);
415 sprintf(buf, " Description: %s", info[SN_DESC]);
417 sprintf(buf, " Status: %s", SubnetState(atoi(info[SN_STATUS])));
419 sprintf(buf, " Contact: %s", info[SN_CONTACT]);
421 sprintf(buf, " Account Number: %s", info[SN_ACCT_NUMBER]);
423 addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
424 mask.s_addr = htonl(atoi(info[SN_MASK]));
425 low.s_addr = htonl(atoi(info[SN_LOW]));
426 high.s_addr = htonl(atoi(info[SN_HIGH]));
427 /* screwy sequence is here because inet_ntoa returns a pointer to
428 a static buf. If it were all one sprintf, the last value would
430 sprintf(buf, " Address: %s Mask: ", inet_ntoa(addr));
431 strcat(buf, inet_ntoa(mask));
432 strcat(buf, "\n High: ");
433 strcat(buf, inet_ntoa(high));
434 strcat(buf, " Low: ");
435 strcat(buf, inet_ntoa(low));
437 sprintf(buf, "Hostname prefix: %s", info[SN_PREFIX]);
439 sprintf(buf, " Owner: %s %s\n", info[SN_ACE_TYPE],
440 strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
442 sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
444 return info[SN_NAME];
447 /* Function Name: GetMCInfo.
448 * Description: This function stores info about a machine.
449 * type - type of data we are trying to retrieve.
450 * name1 - the name of argv[0] for the call.
451 * name2 - the name of argv[1] for the call.
452 * Returns: the top element of a queue containing the data or NULL.
455 struct mqelem *GetMCInfo(int type, char *name1, char *name2)
458 struct mqelem *elem = NULL;
465 args[1] = args[2] = args[3] = "*";
466 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
468 if (stat == MR_NO_MATCH)
471 sprintf(buf, "Machine '%s' is not in the database.", name1);
475 com_err(program_name, stat, " in get_machine.");
482 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
484 com_err(program_name, stat, " in get_hostalias.");
489 if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
491 if (stat == MR_NO_MATCH)
494 sprintf(buf, "Network '%s' is not in the database.", name1);
498 com_err(program_name, stat, " in get_subnet.");
503 if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
505 com_err(program_name, stat, " in get_cluster.");
510 args[MAP_MACHINE] = name1;
511 args[MAP_CLUSTER] = name2;
512 if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
515 com_err(program_name, stat, " in get_machine_to_cluster_map.");
520 args[CD_NAME] = name1;
521 args[CD_LABEL] = name2;
522 if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
524 com_err(program_name, stat, " in get_cluster_data.");
529 args[CON_NAME] = name1;
530 if ((stat = do_mr_query("get_container", 1, &name1, StoreInfo, &elem)))
532 com_err(program_name, stat, " in get_container.");
538 if ((stat = do_mr_query("get_machine_to_container_map", 1, &name1,
541 com_err(program_name, stat, " in get_machine_to_container_map.");
545 return QueueTop(elem);
548 /* Function Name: AskMCDInfo.
549 * Description: This function askes the user for information about a
550 * machine and saves it into a structure.
551 * Arguments: info - a pointer the information to ask about
552 * type - type of information - MACHINE
556 * name - T/F : change the name of this type.
560 char **AskMCDInfo(char **info, int type, Bool name)
562 char temp_buf[BUFSIZ], *newname, *oldnewname;
567 sprintf(temp_buf, "\nSetting the information for the Machine %s...",
571 sprintf(temp_buf, "Setting the information for the Network %s...",
575 sprintf(temp_buf, "Setting the information for the Cluster %s...",
579 sprintf(temp_buf, "Setting the Data for the Cluster %s...",
583 sprintf(temp_buf, "Setting the Data for the Container %s...",
587 Put_message(temp_buf);
594 newname = strdup(info[M_NAME]);
595 if (GetValueFromUser("The new name for this machine? ", &newname) ==
598 oldnewname = strdup(newname);
599 newname = canonicalize_hostname(newname);
600 if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
602 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
603 oldnewname, newname);
604 Put_message(temp_buf);
609 newname = strdup(info[SN_NAME]);
610 if (GetValueFromUser("The new name for this network? ", &newname) ==
615 newname = strdup(info[C_NAME]);
616 if (GetValueFromUser("The new name for this cluster? ", &newname) ==
621 newname = strdup(info[CON_NAME]);
622 if (GetValueFromUser("The new name for this container? ", &newname)
627 Put_message("Unknown type in AskMCDInfo, programmer botch");
635 if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
637 if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
639 if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
642 if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
644 if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
647 if (GetValueFromUser("Machine's billing contact",
648 &info[M_BILL_CONTACT]) == SUB_ERROR)
650 if (GetValueFromUser("Machine's billing account number",
651 &info[M_ACCT_NUMBER]) == SUB_ERROR)
656 if (GetValueFromUser("Machine's status (? for help)",
657 &info[M_STAT]) == SUB_ERROR)
659 if (isdigit(info[M_STAT][0]))
661 Put_message("Valid status numbers:");
662 for (i = 0; i < 4; i++)
663 Put_message(states[i]);
666 /* there appears to be some argument mismatch between the client
667 * and the server.. so here is this argument shuffler.
668 * I have since modified this to always shuffle the arguments..
669 * not just do so when performing a modify all fields request.
670 * The SetMachinedefaults() has been changed to reflect this.
671 * pray for us and may we attain enlightenment through structures.
676 /* info did not come from SetMachineDefaults(), which does not
677 * initialize entry 10 (M_STAT_CHNG), therefore we can
680 /* This is an update of an existing machine and the structure
681 * was filled in thru a query to the db which does fill in this
687 info[10] = info[M_SUBNET];
688 info[11] = info[M_ADDR];
689 info[12] = info[M_OWNER_TYPE];
690 info[13] = info[M_OWNER_NAME];
691 info[14] = info[M_ACOMMENT];
692 info[15] = info[M_OCOMMENT];
696 if (GetValueFromUser("Machine's network (or 'none')", &info[10])
700 if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
701 &info[11]) == SUB_ERROR)
703 if (GetTypeFromUser("Machine's owner type", "ace_type", &info[12]) ==
706 if (strcmp(info[12], "NONE") &&
707 GetValueFromUser("Owner's Name", &info[13]) == SUB_ERROR)
709 if (!strcmp(info[12], "KERBEROS"))
713 mrcl_validate_kerberos_member(info[13], &canon);
714 if (mrcl_get_message())
715 Put_message(mrcl_get_message());
719 if (GetValueFromUser("Administrative comment", &info[14]) == SUB_ERROR)
721 if (GetValueFromUser("Operational comment", &info[15]) == SUB_ERROR)
724 FreeAndClear(&info[17], TRUE);
725 FreeAndClear(&info[18], TRUE);
728 if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
733 if (GetValueFromUser("Network's status (? for help)",
734 &info[SN_STATUS]) == SUB_ERROR)
736 if (isdigit(info[SN_STATUS][0]))
738 Put_message("Valid status numbers:");
739 for (i = 0; i < 8; i++)
740 Put_message(subnet_states[i]);
742 if (GetValueFromUser("Network's contact", &info[SN_CONTACT]) == SUB_ERROR)
744 if (GetValueFromUser("Network's billing account number",
745 &info[SN_ACCT_NUMBER]) == SUB_ERROR)
747 if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
749 if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
751 if (atoi(info[SN_LOW]) == (int)ntohl(inet_addr(S_DEFAULT_LOW)))
754 unsigned long mask, addr;
756 addr = atoi(info[SN_ADDRESS]);
757 mask = atoi(info[SN_MASK]);
758 low.s_addr = atoi(info[SN_LOW]);
759 low.s_addr = (low.s_addr & ~mask) | (addr & mask);
761 sprintf(temp_buf, "%ld", low.s_addr);
762 info[SN_LOW] = strdup(temp_buf);
764 if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
767 if (atoi(info[SN_HIGH]) == (int)ntohl(inet_addr(S_DEFAULT_HIGH)))
770 unsigned long mask, addr;
772 addr = atoi(info[SN_ADDRESS]);
773 mask = atoi(info[SN_MASK]);
774 high.s_addr = atoi(info[SN_HIGH]);
775 high.s_addr = (high.s_addr & ~mask) | (addr & mask);
777 sprintf(temp_buf, "%ld", high.s_addr);
778 info[SN_HIGH] = strdup(temp_buf);
780 if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
783 if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
785 if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
788 if (strcmp(info[SN_ACE_TYPE], "NONE") &&
789 GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
791 if (!strcmp(info[SN_ACE_TYPE], "KERBEROS"))
795 mrcl_validate_kerberos_member(info[SN_ACE_NAME], &canon);
796 if (mrcl_get_message())
797 Put_message(mrcl_get_message());
798 free(info[SN_ACE_NAME]);
799 info[SN_ACE_NAME] = canon;
801 FreeAndClear(&info[SN_MODTIME], TRUE);
802 FreeAndClear(&info[SN_MODBY], TRUE);
803 FreeAndClear(&info[SN_MODWITH], TRUE);
806 if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
809 if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
812 FreeAndClear(&info[C_MODTIME], TRUE);
813 FreeAndClear(&info[C_MODBY], TRUE);
814 FreeAndClear(&info[C_MODWITH], TRUE);
817 if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
820 if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
824 if (GetValueFromUser("Container's Description:", &info[CON_DESCRIPT]) ==
827 if (GetValueFromUser("Container's Location:", &info[CON_LOCATION]) ==
830 if (GetValueFromUser("Container's Contact:", &info[CON_CONTACT]) ==
833 if (GetTypeFromUser("Container's owner type", "ace_type",
834 &info[CON_OWNER_TYPE]) == SUB_ERROR)
836 if (strcmp(info[CON_OWNER_TYPE], "NONE") &&
837 GetValueFromUser("Owner's Name", &info[CON_OWNER_NAME]) == SUB_ERROR)
839 if (!strcmp(info[CON_OWNER_TYPE], "KERBEROS"))
843 mrcl_validate_kerberos_member(info[CON_OWNER_NAME], &canon);
844 if (mrcl_get_message())
845 Put_message(mrcl_get_message());
846 free(info[CON_OWNER_NAME]);
847 info[CON_OWNER_NAME] = canon;
849 if (GetTypeFromUser("Container's Membership ACL", "ace_type",
850 &info[CON_MEMACE_TYPE]) == SUB_ERROR)
852 if (strcmp(info[CON_MEMACE_TYPE], "NONE") &&
853 GetValueFromUser("Membership ACL", &info[CON_MEMACE_NAME])
856 if (!strcmp(info[CON_MEMACE_TYPE], "KERBEROS"))
860 mrcl_validate_kerberos_member(info[CON_MEMACE_NAME], &canon);
861 if (mrcl_get_message())
862 Put_message(mrcl_get_message());
863 free(info[CON_MEMACE_NAME]);
864 info[CON_MEMACE_NAME] = canon;
866 FreeAndClear(&info[CON_MODTIME], TRUE);
867 FreeAndClear(&info[CON_MODBY], TRUE);
868 FreeAndClear(&info[CON_MODWITH], TRUE);
873 * Slide the newname into the #2 slot, this screws up all future references
877 SlipInNewName(info, newname);
882 /* ----------- Machine Menu ----------- */
884 /* Function Name: ShowMachineInfo
885 * Description: This function shows the information about a machine.
886 * Arguments: argc, argv - the name of the machine in argv[1].
887 * Returns: DM_NORMAL.
890 int ShowMachineInfo(int argc, char **argv)
895 tmpname = canonicalize_hostname(strdup(argv[1]));
896 top = GetMCInfo(MACHINE, tmpname, NULL);
897 Loop(top, ((void (*)(char **)) PrintMachInfo));
902 /* Function Name: ShowMachineQuery
903 * Description: This function shows the information about a machine.
904 * or group of machines, which may be selected through a
905 * number of criteria.
906 * Arguments: argc, argv - the name of the machine in argv[1],
907 * the address of the machine in argv[2],
908 * the location of the machine in argv[3],
909 * and the contact name in argv[4].
910 * any of these may be wildcards.
911 * Returns: DM_NORMAL.
914 int ShowMachineQuery(int argc, char **argv)
917 struct mqelem *top, *elem = NULL;
920 if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
921 !strcmp(argv[3], "") && !strcmp(argv[4], ""))
923 Put_message("You must specify at least one parameter of the query.");
928 args[0] = canonicalize_hostname(strdup(argv[1]));
944 if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
946 if (stat == MR_NO_MATCH)
947 Put_message("No machine(s) found matching query in the database.");
949 com_err(program_name, stat, " in get_machine.");
952 top = QueueTop(elem);
953 Loop(top, ((void (*)(char **)) PrintMachInfo));
958 /* Function Name: AddMachine
959 * Description: This function adds a new machine to the database.
960 * Arguments: argc, argv - the name of the network in argv[1].
961 * Returns: DM_NORMAL.
964 int AddMachine(int argc, char **argv)
966 char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
968 struct mqelem *elem = NULL;
971 if (!ValidName(argv[1])) /* Checks for wildcards. */
975 * get the network record
978 if (strcasecmp(argv[1], "none") &&
979 (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
981 if (stat == MR_NO_MATCH)
984 sprintf(buf, "Network '%s' is not in the database.", argv[1]);
987 com_err(program_name, stat, " in get_subnet.");
992 * Check to see if this machine already exists.
995 name = strdup(""); /* want to put prefix here */
996 if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
999 name = canonicalize_hostname(strdup(name));
1002 xargs[1] = xargs[2] = xargs[3] = "*";
1003 if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
1005 sprintf(buf, "The machine '%s' already exists.", name);
1010 else if (stat != MR_NO_MATCH)
1012 com_err(program_name, stat,
1013 " while checking machine '%s' in AddMachine.", name);
1017 rinfo = SetMachineDefaults(info, name);
1018 rinfo[M_SUBNET] = strdup(argv[1]);
1019 if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
1021 Put_message("Aborted.");
1026 * Actually create the new Machine.
1029 if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
1030 com_err(program_name, stat, " in AddMachine.");
1037 /* Function Name: RealUpdateMachine
1038 * Description: Performs the actual update of the machine data.
1039 * Arguments: info - the information on the machine to update.
1040 * junk - an UNUSED Boolean.
1044 static void RealUpdateMachine(char **info, Bool junk)
1047 char **args = AskMCDInfo(info, MACHINE, TRUE);
1050 Put_message("Aborted.");
1053 if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
1054 com_err(program_name, stat, " in UpdateMachine.");
1056 Put_message("Machine successfully updated.");
1059 /* Function Name: UpdateMachine
1060 * Description: This function adds a new machine to the database.
1061 * Arguments: argc, argv - the name of the machine in argv[1].
1062 * Returns: DM_NORMAL.
1065 int UpdateMachine(int argc, char **argv)
1070 tmpname = canonicalize_hostname(strdup(argv[1]));
1071 top = GetMCInfo(MACHINE, tmpname, NULL);
1072 QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
1079 /* Function Name: CheckAndRemoveFromCluster
1080 * Description: This func tests to see if a machine is in a cluster.
1081 * and if so then removes it
1082 * Arguments: name - name of the machine (already Canonicalized).
1083 * ask_user- query the user before removing if from clusters?
1084 * Returns: MR_ERROR if machine left in a cluster, or mr_error.
1087 int CheckAndRemoveFromCluster(char *name, Bool ask_user)
1089 int stat, ret_value;
1091 char *args[10], temp_buf[BUFSIZ], *ptr;
1092 struct mqelem *top, *elem = NULL;
1094 ret_value = SUB_NORMAL; /* initialize ret_value. */
1097 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1098 if (stat && stat != MR_NO_MATCH)
1100 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1103 if (stat == MR_SUCCESS)
1105 elem = top = QueueTop(elem);
1108 sprintf(temp_buf, "%s is assigned to the following clusters.", name);
1109 Put_message(temp_buf);
1110 Loop(top, (void (*)(char **)) PrintMCMap);
1111 ptr = "Remove this machine from ** ALL ** these clusters?";
1112 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1116 Put_message("Aborting...");
1128 char **info = elem->q_data;
1129 if ((stat = do_mr_query("delete_machine_from_cluster",
1130 2, info, NULL, NULL)))
1132 ret_value = SUB_ERROR;
1133 com_err(program_name, stat,
1134 " in delete_machine_from_cluster.");
1136 "Machine %s ** NOT ** removed from cluster %s.",
1137 info[MAP_MACHINE], info[MAP_CLUSTER]);
1138 Put_message(temp_buf);
1140 elem = elem->q_forw;
1147 /* Function Name: CheckAndRemoveCnames
1148 * Description: This func tests to see if a machine has cnames,
1149 * and if so then removes them.
1150 * Arguments: name - name of the machine (already Canonicalized).
1151 * ask_user- query the user before removing cnames?
1152 * Returns: MR_ERROR if machine left with a cname, or mr_error.
1155 int CheckAndRemoveCnames(char *name, Bool ask_user)
1157 int stat, ret_value;
1159 char *args[10], temp_buf[BUFSIZ], *ptr;
1160 struct mqelem *top, *elem = NULL;
1162 ret_value = SUB_NORMAL;
1165 stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem);
1166 if (stat && stat != MR_NO_MATCH)
1168 com_err(program_name, stat, " in get_hostalias.");
1171 if (stat == MR_SUCCESS)
1173 elem = top = QueueTop(elem);
1176 sprintf(temp_buf, "%s has the following cnames.", name);
1177 Put_message(temp_buf);
1178 Loop(top, (void (*)(char **)) PrintCname);
1179 ptr = "Remove ** ALL ** these cnames?";
1180 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1184 Put_message("Aborting...");
1196 char **info = elem->q_data;
1197 if ((stat = do_mr_query("delete_hostalias", 2, info,
1200 ret_value = SUB_ERROR;
1201 com_err(program_name, stat, " in delete_hostalias.");
1203 "Cname %s ** NOT ** removed from host %s.",
1205 Put_message(temp_buf);
1207 elem = elem->q_forw;
1214 /* Function Name: RealDeleteMachine
1215 * Description: Actually Deletes the Machine.
1216 * Arguments: info - nescessary information stored as an array of char *'s
1217 * one_machine - a boolean, true if there is only one item in
1222 static void RealDeleteMachine(char **info, Bool one_machine)
1225 char temp_buf[BUFSIZ];
1227 sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
1229 if (!one_machine || Confirm(temp_buf))
1231 if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
1233 if (CheckAndRemoveCnames(info[M_NAME], TRUE) != SUB_ERROR)
1235 if ((stat = do_mr_query("delete_host", 1,
1236 &info[M_NAME], NULL, NULL)))
1238 com_err(program_name, stat, " in DeleteMachine.");
1239 sprintf(temp_buf, "%s ** NOT ** deleted.",
1241 Put_message(temp_buf);
1245 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
1246 Put_message(temp_buf);
1253 /* Function Name: DeleteMachine
1254 * Description: This function removes a machine from the data base.
1255 * Arguments: argc, argv - the machines name int argv[1].
1256 * Returns: DM_NORMAL.
1259 /* Perhaps we should remove the cluster if it has no machine now. */
1261 int DeleteMachine(int argc, char **argv)
1266 tmpname = canonicalize_hostname(strdup(argv[1]));
1267 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
1268 QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
1275 /* Function Name: ShowCname
1276 * Description: This function shows machine aliases
1277 * Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1278 * Returns: DM_NORMAL.
1281 int ShowCname(int argc, char **argv)
1284 char *tmpalias, *tmpname;
1286 tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
1287 tmpname = canonicalize_hostname(strdup(argv[2]));
1288 top = GetMCInfo(CNAME, tmpalias, tmpname);
1289 Put_message(""); /* blank line on screen */
1290 Loop(top, ((void (*)(char **)) PrintCname));
1296 int AddCname(int argc, char **argv)
1301 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1302 args[1] = canonicalize_hostname(strdup(argv[2]));
1303 stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
1309 Put_message("That alias name is already in use.");
1312 Put_message("Permission denied. "
1313 "(Regular users can only add two aliases to a host.");
1316 com_err(program_name, stat, " in add_hostalias");
1322 int DeleteCname(int argc, char **argv)
1327 args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1328 args[1] = canonicalize_hostname(strdup(argv[2]));
1329 stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
1331 com_err(program_name, stat, " in delete_hostalias");
1336 /* Function Name: AddMachineToCluster
1337 * Description: This function adds a machine to a cluster
1338 * Arguments: argc, argv - The machine name is argv[1].
1339 * The cluster name in argv[2].
1340 * Returns: DM_NORMAL.
1343 int AddMachineToCluster(int argc, char **argv)
1346 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1347 Bool add_it, one_machine, one_cluster;
1348 struct mqelem *melem, *mtop, *celem, *ctop;
1350 machine = canonicalize_hostname(strdup(argv[1]));
1351 if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
1353 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1355 Put_message(temp_buf);
1359 celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
1360 melem = mtop = GetMCInfo(MACHINE, machine, NULL);
1363 one_machine = (QueueCount(mtop) == 1);
1364 one_cluster = (QueueCount(ctop) == 1);
1366 /* No good way to use QueryLoop() here, sigh */
1370 char **minfo = melem->q_data;
1373 char **cinfo = celem->q_data;
1374 if (one_machine && one_cluster)
1378 sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
1379 minfo[M_NAME], cinfo[C_NAME]);
1380 switch (YesNoQuitQuestion(temp_buf, FALSE))
1389 Put_message("Aborting...");
1397 args[0] = minfo[M_NAME];
1398 args[1] = cinfo[C_NAME];
1399 stat = do_mr_query("add_machine_to_cluster", 2, args,
1406 sprintf(temp_buf, "%s is already in cluster %s",
1407 minfo[M_NAME], cinfo[C_NAME]);
1408 Put_message(temp_buf);
1411 com_err(program_name, stat, " in AddMachineToCluster.");
1415 celem = celem->q_forw;
1417 celem = ctop; /* reset cluster element. */
1418 melem = melem->q_forw;
1425 /* Function Name: RealRemoveMachineFromCluster
1426 * Description: This function actually removes the machine from its
1428 * Arguments: info - all information nescessary to perform the removal.
1429 * one_map - True if there is only one case, and we should
1434 static void RealRemoveMachineFromCluster(char **info, Bool one_map)
1436 char temp_buf[BUFSIZ];
1439 sprintf(temp_buf, "Remove %s from the cluster %s",
1440 info[MAP_MACHINE], info[MAP_CLUSTER]);
1441 if (!one_map || Confirm(temp_buf))
1443 if ((stat = do_mr_query("delete_machine_from_cluster", 2,
1445 com_err(program_name, stat, " in delete_machine_from_cluster");
1448 sprintf(temp_buf, "%s has been removed from the cluster %s.",
1449 info[MAP_MACHINE], info[MAP_CLUSTER]);
1450 Put_message(temp_buf);
1454 Put_message("Machine not removed.");
1457 /* Function Name: RemoveMachineFromCluster
1458 * Description: Removes this machine form a specific cluster.
1459 * Arguments: argc, argv - Name of machine in argv[1].
1460 * Name of cluster in argv[2].
1464 int RemoveMachineFromCluster(int argc, char **argv)
1466 struct mqelem *elem = NULL;
1467 char buf[BUFSIZ], *args[10];
1470 args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
1471 if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
1473 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1474 argv[1], args[MAP_MACHINE]);
1477 args[MAP_CLUSTER] = argv[2];
1478 args[MAP_END] = NULL;
1480 stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1482 if (stat == MR_NO_MATCH)
1484 sprintf(buf, "The machine %s is not in the cluster %s.",
1485 args[MAP_MACHINE], args[MAP_CLUSTER]);
1487 free(args[MAP_MACHINE]);
1490 if (stat != MR_SUCCESS)
1491 com_err(program_name, stat, " in delete_machine_from_cluster");
1493 elem = QueueTop(elem);
1494 QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1495 "Remove this machine from this cluster");
1498 free(args[MAP_MACHINE]);
1502 /* ---------- Subnet Menu -------- */
1504 /* Function Name: ShowSubnetInfo
1505 * Description: Gets information about a subnet given its name.
1506 * Arguments: argc, argc - the name of the subnet in in argv[1].
1507 * Returns: DM_NORMAL.
1510 int ShowSubnetInfo(int argc, char **argv)
1514 top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1515 Loop(top, (void (*)(char **)) PrintSubnetInfo);
1520 /* Function Name: AddSubnet
1521 * Description: Creates a new subnet.
1522 * Arguments: argc, argv - the name of the new subnet is argv[1].
1523 * Returns: DM_NORMAL.
1526 int AddSubnet(int argc, char **argv)
1528 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1532 * Check to see if this subnet already exists.
1534 if (!ValidName(name))
1537 if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
1539 Put_message("This subnet already exists.");
1542 else if (stat != MR_NO_MATCH)
1544 com_err(program_name, stat, " in AddSubnet.");
1547 if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
1549 Put_message("Aborted.");
1555 * Actually create the new Subnet.
1557 if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
1558 com_err(program_name, stat, " in AddSubnet.");
1564 /* Function Name: RealUpdateSubnet
1565 * Description: This function actually performs the subnet update.
1566 * Arguments: info - all information nesc. for updating the subnet.
1567 * junk - an UNUSED boolean.
1571 static void RealUpdateSubnet(char **info, Bool junk)
1574 char **args = AskMCDInfo(info, SUBNET, TRUE);
1577 Put_message("Aborted.");
1580 if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
1581 com_err(program_name, stat, " in UpdateSubnet.");
1583 Put_message("Subnet successfully updated.");
1586 /* Function Name: UpdateSubnet
1587 * Description: This Function Updates a subnet
1588 * Arguments: name of the subnet in argv[1].
1589 * Returns: DM_NORMAL.
1592 int UpdateSubnet(int argc, char **argv)
1595 top = GetMCInfo(SUBNET, argv[1], NULL);
1596 QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1602 /* Function Name: RealDeleteSubnet
1603 * Description: Actually performs the subnet deletion.
1604 * Arguments: info - all information about this subnet.
1605 * one_subnet - If true then there was only one subnet in
1606 * the queue, and we should confirm.
1610 static void RealDeleteSubnet(char **info, Bool one_subnet)
1613 char temp_buf[BUFSIZ];
1616 "Are you sure the you want to delete the subnet %s (y/n) ?",
1618 if (!one_subnet || Confirm(temp_buf))
1620 if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
1622 com_err(program_name, stat, " in delete_subnet.");
1623 sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
1624 Put_message(temp_buf);
1628 sprintf(temp_buf, "subnet %s successfully deleted.",
1630 Put_message(temp_buf);
1635 /* Function Name: DeleteSubnet
1636 * Description: This function removes a subnet from the database.
1637 * Arguments: argc, argv - the name of the subnet is stored in argv[1].
1638 * Returns: DM_NORMAL.
1641 int DeleteSubnet(int argc, char **argv)
1645 top = GetMCInfo(SUBNET, argv[1], NULL);
1646 QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1652 /* ---------- Cluster Menu -------- */
1654 /* Function Name: ShowClusterInfo
1655 * Description: Gets information about a cluser given its name.
1656 * Arguments: argc, argc - the name of the cluster in in argv[1].
1657 * Returns: DM_NORMAL.
1660 int ShowClusterInfo(int argc, char **argv)
1664 top = GetMCInfo(CLUSTER, argv[1], NULL);
1665 Loop(top, (void (*)(char **)) PrintClusterInfo);
1670 /* Function Name: AddCluster
1671 * Description: Creates a new cluster.
1672 * Arguments: argc, argv - the name of the new cluster is argv[1].
1673 * Returns: DM_NORMAL.
1676 int AddCluster(int argc, char **argv)
1678 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1682 * Check to see if this cluster already exists.
1684 if (!ValidName(name))
1687 if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
1689 Put_message("This cluster already exists.");
1692 else if (stat != MR_NO_MATCH)
1694 com_err(program_name, stat, " in AddCluster.");
1697 if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
1699 Put_message("Aborted.");
1705 * Actually create the new Cluster.
1707 if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
1708 com_err(program_name, stat, " in AddCluster.");
1714 /* Function Name: RealUpdateCluster
1715 * Description: This function actually performs the cluster update.
1716 * Arguments: info - all information nesc. for updating the cluster.
1717 * junk - an UNUSED boolean.
1721 static void RealUpdateCluster(char **info, Bool junk)
1724 char **args = AskMCDInfo(info, CLUSTER, TRUE);
1728 Put_message("Aborted.");
1731 if ((stat = do_mr_query("update_cluster", CountArgs(args),
1733 com_err(program_name, stat, " in UpdateCluster.");
1735 Put_message("Cluster successfully updated.");
1738 /* Function Name: UpdateCluster
1739 * Description: This Function Updates a cluster
1740 * Arguments: name of the cluster in argv[1].
1741 * Returns: DM_NORMAL.
1744 int UpdateCluster(int argc, char **argv)
1747 top = GetMCInfo(CLUSTER, argv[1], NULL);
1748 QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1754 /* Function Name: CheckAndRemoveMachine
1755 * Description: This function checks and removes all machines from a
1757 * Arguments: name - name of the cluster.
1758 * ask_first - if TRUE, then we will query the user, before
1760 * Returns: SUB_ERROR if all machines not removed.
1763 int CheckAndRemoveMachines(char *name, Bool ask_first)
1765 int stat, ret_value;
1767 char *args[10], temp_buf[BUFSIZ], *ptr;
1768 struct mqelem *top, *elem = NULL;
1770 ret_value = SUB_NORMAL;
1771 args[MAP_MACHINE] = "*";
1772 args[MAP_CLUSTER] = name;
1773 stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1774 if (stat && stat != MR_NO_MATCH)
1776 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1779 if (stat == MR_SUCCESS)
1781 elem = top = QueueTop(elem);
1784 sprintf(temp_buf, "The cluster %s has the following machines in it:",
1786 Put_message(temp_buf);
1789 char **info = elem->q_data;
1790 Print(1, &info[MAP_MACHINE], (char *) NULL);
1791 elem = elem->q_forw;
1793 ptr = "Remove ** ALL ** these machines from this cluster?";
1795 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1799 Put_message("Aborting...");
1812 char **info = elem->q_data;
1813 if ((stat = do_mr_query("delete_machine_from_cluster",
1814 2, info, NULL, NULL)))
1816 ret_value = SUB_ERROR;
1817 com_err(program_name, stat,
1818 " in delete_machine_from_cluster.");
1820 "Machine %s ** NOT ** removed from cluster %s.",
1821 info[MAP_MACHINE], info[MAP_CLUSTER]);
1822 Put_message(temp_buf);
1824 elem = elem->q_forw;
1831 /* Function Name: RealDeleteCluster
1832 * Description: Actually performs the cluster deletion.
1833 * Arguments: info - all information about this cluster.
1834 * one_cluster - If true then there was only one cluster in
1835 * the queue, and we should confirm.
1839 static void RealDeleteCluster(char **info, Bool one_cluster)
1842 char temp_buf[BUFSIZ];
1845 "Are you sure the you want to delete the cluster %s (y/n) ?",
1847 if (!one_cluster || Confirm(temp_buf))
1849 if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
1851 if ((stat = do_mr_query("delete_cluster", 1,
1852 &info[C_NAME], NULL, NULL)))
1854 com_err(program_name, stat, " in delete_cluster.");
1855 sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
1856 Put_message(temp_buf);
1860 sprintf(temp_buf, "cluster %s successfully deleted.",
1862 Put_message(temp_buf);
1868 /* Function Name: DeleteCluster
1869 * Description: This function removes a cluster from the database.
1870 * Arguments: argc, argv - the name of the cluster is stored in argv[1].
1871 * Returns: DM_NORMAL.
1874 int DeleteCluster(int argc, char **argv)
1878 top = GetMCInfo(CLUSTER, argv[1], NULL);
1879 QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1885 /* ----------- Cluster Data Menu -------------- */
1887 /* Function Name: ShowClusterData
1888 * Description: This function shows the services for one cluster.
1889 * Arguments: argc, argv - The name of the cluster is argv[1].
1890 * The label of the data in argv[2].
1891 * Returns: DM_NORMAL.
1894 int ShowClusterData(int argc, char **argv)
1896 struct mqelem *elem, *top;
1899 top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1902 info = elem->q_data;
1903 PrintClusterData(info);
1904 elem = elem->q_forw;
1910 /* Function Name: AddClusterData
1911 * Description: This function adds some data to the cluster.
1912 * Arguments: argv, argc: argv[1] - the name of the cluster.
1913 * argv[2] - the label of the data.
1914 * argv[3] - the data.
1915 * Returns: DM_NORMAL.
1918 int AddClusterData(int argc, char **argv)
1922 for (i = 1; i < 4; i++)
1924 if (IS_EMPTY(argv[i]))
1926 Put_message("Cluster data cannot be an empty string.");
1930 if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
1931 com_err(program_name, stat, " in AddClusterData.");
1935 /* Function Name: RealRemoveClusterData
1936 * Description: actually removes the cluster data.
1937 * Arguments: info - all info necessary to remove the cluster, in an array
1939 * one_item - if true then the queue has only one elem and we
1944 static void RealRemoveClusterData(char **info, Bool one_item)
1950 temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1951 PrintClusterData(info);
1952 if (!one_item || Confirm(temp_ptr))
1954 if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
1956 com_err(program_name, stat, " in DeleteClusterData.");
1957 Put_message("Data not removed.");
1960 Put_message("Removal successful.");
1964 /* Function Name: RemoveClusterData
1965 * Description: This function removes data on a given cluster.
1966 * Arguments: argv, argc: argv[1] - the name of the cluster.
1967 * argv[2] - the label of the data.
1968 * argv[3] - the data.
1969 * Returns: DM_NORMAL.
1972 int RemoveClusterData(int argc, char **argv)
1976 top = GetMCInfo(DATA, argv[1], argv[2]);
1977 QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1978 "Remove data from cluster");
1984 /* Function Name: MachineToClusterMap
1985 * Description: This Retrieves the mapping between machine and cluster
1986 * Arguments: argc, argv - argv[1] -> machine name or wildcard.
1987 * argv[2] -> cluster name or wildcard.
1991 int MachineToClusterMap(int argc, char **argv)
1993 struct mqelem *elem, *top;
1994 char *tmpname, temp_buf[256];
1996 tmpname = canonicalize_hostname(strdup(argv[1]));
1997 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
1999 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2001 Put_message(temp_buf);
2003 top = elem = GetMCInfo(MAP, tmpname, argv[2]);
2005 Put_message(""); /* blank line on screen */
2008 char **info = elem->q_data;
2010 elem = elem->q_forw;
2018 /* Function Name: MachineByOwner
2019 * Description: This function prints all machines which are owned by
2020 * a given user or group.
2022 * Returns: DM_NORMAL.
2025 int MachineByOwner(int argc, char **argv)
2027 char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
2030 type = strdup("USER");
2031 if (GetTypeFromUser("Type of owner", "ace_type", &type) == SUB_ERROR)
2034 sprintf(buf, "Name of %s", type);
2035 name = strdup(user);
2036 if (GetValueFromUser(buf, &name) == SUB_ERROR)
2039 switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE))
2042 sprintf(temp_buf, "R%s", type); /* "USER to "RUSER", etc. */
2044 type = strdup(temp_buf);
2052 top = GetMachineByOwner(type, name);
2053 Loop(top, PrintMachine);
2059 /* Function Name: GetMachineByOwner
2060 * Description: This function stores information retrieved by
2061 * the get_host_by_owner query
2062 * Arguments: type - an ace_type, argv[0] for the query
2063 * name - name of machine, argv[1] for the query
2064 * Returns: the top element of a queue returning the data, or NULL.
2067 struct mqelem *GetMachineByOwner(char *type, char *name)
2070 struct mqelem *elem = NULL;
2075 if ((status = do_mr_query("get_host_by_owner", 2, args, StoreInfo, &elem)))
2077 com_err(program_name, status, " in get_host_by_owner");
2080 return QueueTop(elem);
2083 int MachineByAcctNumber(int argc, char **argv)
2085 char *args[1], *account_number;
2087 struct mqelem *elem = NULL;
2089 account_number = strdup("");
2090 if (GetValueFromUser("Account Number", &account_number) == SUB_ERROR)
2093 args[0] = account_number;
2094 if (status = do_mr_query("get_host_by_account_number", 1, args, StoreInfo,
2097 com_err(program_name, status, " in get_host_by_account_number");
2100 Loop(QueueTop(elem), (void (*)(char **)) PrintMachInfo);
2106 int ShowContainerInfo(int argc, char **argv)
2110 top = GetMCInfo(CONTAINER, argv[1], NULL);
2111 Loop(top, (void (*)(char **)) PrintContainerInfo);
2116 static char *PrintContainerInfo(char **info)
2118 char buf[BUFSIZ], tbuf[256];
2121 sprintf(buf, "Container: %-16s", info[CON_NAME]);
2123 sprintf(buf, "Description: %-16s", info[CON_DESCRIPT]);
2125 sprintf(buf, "Location: %-16s Contact: %s", info[CON_LOCATION],
2128 sprintf(tbuf, "%s %s", info[CON_OWNER_TYPE],
2129 strcmp(info[CON_OWNER_TYPE], "NONE") ? info[CON_OWNER_NAME] : "");
2130 sprintf(buf, "Owner: %-16s", tbuf);
2132 sprintf(tbuf, "%s %s", info[CON_MEMACE_TYPE],
2133 strcmp(info[CON_MEMACE_TYPE], "NONE") ? info[CON_MEMACE_NAME] : "");
2134 sprintf(buf, "Membership ACL: %-16s", tbuf);
2137 sprintf(buf, MOD_FORMAT, info[CON_MODBY], info[CON_MODTIME],
2140 return info[CON_NAME];
2143 static char *PrintContainer(char **info)
2147 sprintf(buf, "Container: %s", info[CON_NAME]);
2152 static char *PrintMContMap(char **info)
2155 sprintf(buf, "Container: %-30s Machine: %-20s",
2161 int AddContainer(int argc, char **argv)
2163 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
2166 /* Can't use ValidName() because spaces are allowed in container names */
2169 Put_message("Please use a non-empty name.");
2173 if (strchr(name, '*') || strchr(name, '?'))
2175 Put_message("Wildcards not accepted here.");
2179 /* Check if this cluster already exists. */
2180 if ((stat = do_mr_query("get_container", 1, &name, NULL, NULL))
2183 Put_message("This container already exists.");
2186 else if (stat != MR_NO_MATCH)
2188 com_err(program_name, stat, " in AddContainer.");
2191 if (!(args = AskMCDInfo(SetContainerDefaults(info, name), CONTAINER, FALSE)))
2193 Put_message("Aborted.");
2198 /* Create the new container. */
2199 if ((stat = do_mr_query("add_container", CountArgs(args), args, NULL, NULL)))
2200 com_err(program_name, stat, " in AddContainer.");
2206 int UpdateContainer(int argc, char **argv)
2209 top = GetMCInfo(CONTAINER, argv[1], NULL);
2210 QueryLoop(top, NullPrint, RealUpdateContainer, "Update the container");
2216 static void RealUpdateContainer(char **info, Bool junk)
2219 char **args = AskMCDInfo(info, CONTAINER, TRUE);
2223 Put_message("Aborted.");
2226 if ((stat = do_mr_query("update_container", CountArgs(args), args,
2228 com_err(program_name, stat, " in UpdateContainer.");
2230 Put_message("Container successfully updated.");
2233 int DeleteContainer(int argc, char **argv)
2237 top = GetMCInfo(CONTAINER, argv[1], NULL);
2238 QueryLoop(top, PrintClusterInfo, RealDeleteContainer,
2239 "Delete the container");
2245 static void RealDeleteContainer(char **info, Bool one_container)
2248 char temp_buf[BUFSIZ];
2251 "Are you sure you want to delete the container %s (y/n) ?",
2253 if (!one_container || Confirm(temp_buf))
2255 if (CheckAndRemoveMachinesFromContainer(info[CON_NAME], TRUE)
2258 if ((stat = do_mr_query("delete_container", 1, &info[CON_NAME],
2261 com_err(program_name, stat, " in delete_container.");
2262 sprintf(temp_buf, "Container %s ** NOT ** deleted.",
2264 Put_message(temp_buf);
2268 sprintf(temp_buf, "Container %s successfully deleted.",
2270 Put_message(temp_buf);
2276 int CheckAndRemoveMachinesFromContainer(char *name, Bool ask_first)
2278 int stat, ret_value;
2280 char *args[10], temp_buf[BUFSIZ], *ptr;
2281 struct mqelem *top, *elem = NULL;
2283 ret_value = SUB_NORMAL;
2286 stat = do_mr_query("get_machines_of_container", 2, args, StoreInfo,
2288 if (stat && stat != MR_NO_MATCH)
2290 com_err(program_name, stat, " in get_machines_of_container");
2293 if (stat == MR_SUCCESS)
2295 elem = top = QueueTop(elem);
2299 "The container %s has the following machines in it:", name);
2300 Put_message(temp_buf);
2303 char **info = elem->q_data;
2304 Print(1, &info[0], (char *) NULL);
2305 elem = elem->q_forw;
2307 ptr = "Remove ** ALL ** these machines from this container?";
2309 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
2313 Put_message("Aborting...");
2326 char **info = elem->q_data;
2327 if ((stat = do_mr_query("delete_machine_from_container",
2328 2, info, NULL, NULL)))
2330 ret_value = SUB_ERROR;
2331 com_err(program_name, stat,
2332 " in delete_machine_from_container.");
2334 "Machine %s ** NOT ** removed from container %s.",
2336 Put_message(temp_buf);
2338 elem = elem->q_forw;
2345 int GetSubContainers(int argc, char **argv)
2348 struct mqelem *elem = NULL, *top = NULL;
2353 if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
2358 if (stat = do_mr_query("get_subcontainers_of_container", 2, args,
2360 com_err(program_name, stat, " in get_subcontainers_of_container");
2362 top = QueueTop(elem);
2363 Loop(top, ((void (*)(char **)) PrintContainer));
2368 int MachineToContainerMap(int argc, char **argv)
2370 struct mqelem *elem, *top;
2371 char *tmpname, temp_buf[256];
2373 tmpname = canonicalize_hostname(strdup(argv[1]));
2374 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
2376 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2378 Put_message(temp_buf);
2380 top = elem = GetMCInfo(CONTMAP, tmpname, NULL);
2385 char **info = elem->q_data;
2386 PrintMContMap(info);
2387 elem = elem->q_forw;
2395 int AddMachineToContainer(int argc, char **argv)
2398 char *machine, *container, temp_buf[BUFSIZ], *args[10];
2399 Bool add_it, one_machine, one_container;
2400 struct mqelem *melem, *mtop, *celem, *ctop;
2402 machine = canonicalize_hostname(strdup(argv[1]));
2403 if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
2405 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2407 Put_message(temp_buf);
2409 container = argv[2];
2411 celem = ctop = GetMCInfo(CONTAINER, container, NULL);
2412 melem = mtop = GetMCInfo(MACHINE, machine, NULL);
2415 one_machine = (QueueCount(mtop) == 1);
2416 one_container = (QueueCount(ctop) == 1);
2420 char **minfo = melem->q_data;
2423 char **cinfo = celem->q_data;
2424 if (one_machine && one_container)
2428 sprintf(temp_buf, "Add machine %s to container %s (y/n/q) ?",
2429 minfo[M_NAME], cinfo[CON_NAME]);
2430 switch (YesNoQuestion(temp_buf, FALSE))
2439 Put_message("Aborting...");
2447 args[0] = minfo[M_NAME];
2448 args[1] = cinfo[CON_NAME];
2449 stat = do_mr_query("add_machine_to_container", 2, args, NULL,
2456 sprintf(temp_buf, "%s is already in container %s",
2457 minfo[M_NAME], cinfo[CON_NAME]);
2458 Put_message(temp_buf);
2461 com_err(program_name, stat, " in AddMachineToContainer.");
2465 celem = celem->q_forw;
2468 melem = melem->q_forw;
2475 int RemoveMachineFromContainer(int argc, char **argv)
2477 struct mqelem *elem = NULL;
2478 char buf[BUFSIZ], *args[10];
2481 args[0] = canonicalize_hostname(strdup(argv[1]));
2482 if (strcasecmp(args[0], argv[1]) && *argv[1] != '"')
2484 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
2491 stat = do_mr_query("get_machine_to_container_map", 1, args, StoreInfo,
2493 if (stat == MR_NO_MATCH)
2495 sprintf(buf, "The machine %s is not in the container %s.",
2501 if (stat != MR_SUCCESS)
2502 com_err(program_name, stat, " in deleter_machine_from_container");
2504 elem = QueueTop(elem);
2505 QueryLoop(elem, PrintMContMap, RealRemoveMachineFromContainer,
2506 "Remove this machine from this container");
2513 static void RealRemoveMachineFromContainer(char **info, Bool one_contmap)
2515 char temp_buf[BUFSIZ];
2518 sprintf(temp_buf, "Remove %s from the container %s",
2520 if (!one_contmap || Confirm(temp_buf))
2522 if ((stat = do_mr_query("delete_machine_from_container", 2,
2524 com_err(program_name, stat, " in delete_machine_from_container");
2527 sprintf(temp_buf, "%s has been removed from the container %s.",
2529 Put_message(temp_buf);
2533 Put_message("Machine not removed.");
2536 int GetMachinesOfContainer(int argc, char **argv)
2539 struct mqelem *elem = NULL, *top = NULL;
2544 if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
2549 if (stat = do_mr_query("get_machines_of_container", 2, args,
2551 com_err(program_name, stat, " in get_machines_of_container");
2553 top = QueueTop(elem);
2554 Loop(top, ((void (*)(char **)) PrintMContMap));
2559 int GetTopLevelCont(int argc, char **argv)
2562 struct mqelem *elem = NULL;
2563 if (status = do_mr_query("get_toplevel_containers", 0, NULL, StoreInfo,
2566 com_err(program_name, status, " in get_toplevel_containers");
2569 Loop(QueueTop(elem), (void(*)(char **)) PrintContainer);