1 #if (!defined(lint) && !defined(SABER))
2 static char rcsid_module_c[] = "$Header$";
5 /* This is the file cluster.c for the MOIRA Client, which allows a nieve
6 * user to quickly and easily maintain most parts of the MOIRA database.
10 * By: Chris D. Peterson
16 * Copyright 1988 by the Massachusetts Institute of Technology.
18 * For further information on copyright and distribution
19 * see the file mit-copyright.h
22 /* BTW: for anyone who cares MCD is short for Machine, Cluster, Data. */
27 #include <moira_site.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <netinet/in.h>
32 #include <arpa/inet.h>
34 #include <sys/utsname.h>
39 #include "mit-copyright.h"
51 #define M_DEFAULT_TYPE DEFAULT_NONE
53 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
54 #define C_DEFAULT_LOCATION DEFAULT_NONE
56 #define CD_DEFAULT_LABEL DEFAULT_NONE
57 #define CD_DEFAULT_DATA DEFAULT_NONE
59 #define S_DEFAULT_LOW "18.0.0.20"
60 #define S_DEFAULT_HIGH "18.0.2.249"
62 static char *states[] = { "Reserved (0)",
66 static char *uses[] = { "none (0)"};
68 static char *MacState(state)
73 if (state < 0 || state > 3) {
74 sprintf(buf, "Unknown (%d)", state);
77 return(states[state]);
82 /* -------------------- Set Defaults -------------------- */
84 /* Function Name: SetMachineDefaults
85 * Description: sets machine defaults.
86 * Arguments: info - an array to put the defaults into.
87 * name - Canonacalized name of the machine.
88 * Returns: info - the array.
92 SetMachineDefaults(info, name)
95 info[M_NAME] = Strsave(name);
96 info[M_VENDOR] = Strsave(M_DEFAULT_TYPE);
97 info[M_MODEL] = Strsave(M_DEFAULT_TYPE);
98 info[M_OS] = Strsave(M_DEFAULT_TYPE);
99 info[M_LOC] = Strsave(M_DEFAULT_TYPE);
100 info[M_CONTACT] = Strsave(M_DEFAULT_TYPE);
101 info[M_USE] = Strsave("0");
102 info[M_STAT] = Strsave("1");
103 info[M_SUBNET] = Strsave("NONE");
104 info[M_ADDR] = Strsave("unique");
105 info[M_OWNER_TYPE] = Strsave("NONE");
106 info[M_OWNER_NAME] = Strsave("NONE");
107 info[M_ACOMMENT] = Strsave("");
108 info[M_OCOMMENT] = Strsave("");
109 info[15] = info[16] = NULL;
113 /* Function Name: SetClusterDefaults
114 * Description: sets Cluster defaults.
115 * Arguments: info - an array to put the defaults into.
116 * name - name of the Cluster.
117 * Returns: info - the array.
121 SetClusterDefaults(info, name)
124 info[C_NAME] = Strsave(name);
125 info[C_DESCRIPT] = Strsave(C_DEFAULT_DESCRIPT);
126 info[C_LOCATION] = Strsave(C_DEFAULT_LOCATION);
127 info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
131 /* Function Name: SetSubnetDefaults
132 * Description: sets Subnet defaults.
133 * Arguments: info - an array to put the defaults into.
134 * name - name of the Subnet.
135 * Returns: info - the array.
139 SetSubnetDefaults(info, name)
144 info[C_NAME] = Strsave(name);
145 info[SN_DESC] = Strsave("");
146 sprintf(buf, "%d", ntohl(inet_addr("18.255.0.0")));
147 info[SN_ADDRESS] = Strsave(buf);
148 sprintf(buf, "%d", ntohl(inet_addr("255.255.0.0")));
149 info[SN_MASK] = Strsave(buf);
150 sprintf(buf, "%d", ntohl(inet_addr(S_DEFAULT_LOW)));
151 info[SN_LOW] = Strsave(buf);
152 sprintf(buf, "%d", ntohl(inet_addr(S_DEFAULT_HIGH)));
153 info[SN_HIGH] = Strsave(buf);
154 info[SN_PREFIX] = Strsave("");
155 info[SN_ACE_TYPE] = Strsave("LIST");
156 info[SN_ACE_NAME] = Strsave("network");
157 info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
161 /* -------------------- General Functions -------------------- */
163 static char aliasbuf[256];
169 if (strlen(aliasbuf) == 0)
170 sprintf(aliasbuf, "Aliases: %s", info[0]);
172 strcat(aliasbuf, ", ");
173 strcat(aliasbuf, info[0]);
178 /* Function Name: PrintMachInfo
179 * Description: This function Prints out the Machine info in
181 * Arguments: info - array of information about a machine.
182 * Returns: The name of the Machine
189 char buf[BUFSIZ], tbuf[256];
191 struct qelem *elem = NULL;
195 sprintf(buf, "Machine: %s", info[M_NAME]);
198 args[1] = info[M_NAME];
199 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, (char *)&elem))
201 if (stat != MR_NO_MATCH)
202 com_err(program_name, stat, " looking up aliases");
205 Loop(QueueTop(elem), (void *) PrintAliases);
207 Put_message(aliasbuf);
209 sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
210 strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
211 sprintf(buf, "Address: %-16s Network: %-16s",
212 info[M_ADDR], info[M_SUBNET]);
214 sprintf(buf, "Owner: %-16s Use data: %s", tbuf, info[M_INUSE]);
216 sprintf(buf, "Status: %-16s Changed: %s",
217 MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
221 sprintf(buf, "Vendor: %-16s Model: %-20s OS: %s",
222 info[M_VENDOR], info[M_MODEL], info[M_OS]);
224 sprintf(buf, "Location: %-16s Contact: %-20s Opt: %s",
225 info[M_LOC], info[M_CONTACT], info[M_USE]);
227 sprintf(buf, "\nAdm cmt: %s", info[M_ACOMMENT]);
229 sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]);
232 sprintf(buf, "Created by %s on %s", info[M_CREATOR], info[M_CREATED]);
234 sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
236 return(info[M_NAME]);
239 /* Function Name: PrintCname
240 * Description: Prints the Data on a host alias
241 * Arguments: info a pointer to the data array.
242 * Returns: The name of the alias.
251 sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
256 /* Function Name: PrintClusterInfo
257 * Description: This function Prints out the cluster info
258 * in a coherent form.
259 * Arguments: info - array of information about a cluster.
260 * Returns: The name of the cluster.
264 PrintClusterInfo(info)
270 sprintf(buf, "Cluster: %s", info[C_NAME]);
272 sprintf(buf, "Description: %s", info[C_DESCRIPT]);
274 sprintf(buf, "Location: %s", info[C_LOCATION]);
276 sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
278 return(info[C_NAME]);
281 /* Function Name: PrintClusterData
282 * Description: Prints the Data on a cluster
283 * Arguments: info a pointer to the data array.
284 * Returns: The name of the cluster.
288 PrintClusterData(info)
294 sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
295 info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
297 return(info[CD_NAME]);
300 /* Function Name: PrintMCMap
301 * Description: Prints the data about a machine to cluster mapping.
302 * Arguments: info a pointer to the data array.
311 sprintf(buf, "Cluster: %-30s Machine: %-20s",
312 info[MAP_CLUSTER], info[MAP_MACHINE]);
314 return(""); /* Used by QueryLoop(). */
317 /* Function Name: PrintSubnetInfo
318 * Description: This function Prints out the subnet info
319 * in a coherent form.
320 * Arguments: info - array of information about a subnet.
321 * Returns: The name of the subnet.
325 PrintSubnetInfo(info)
329 struct in_addr addr, mask, low, high;
332 sprintf(buf, " Network: %s", info[SN_NAME]);
334 sprintf(buf, " Description: %s", info[SN_DESC]);
336 addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
337 mask.s_addr = htonl(atoi(info[SN_MASK]));
338 low.s_addr = htonl(atoi(info[SN_LOW]));
339 high.s_addr = htonl(atoi(info[SN_HIGH]));
340 /* screwy sequence is here because inet_ntoa returns a pointer to
341 a static buf. If it were all one sprintf, the last value would
343 sprintf(buf, " Address: %s Mask: ", inet_ntoa(addr));
344 strcat(buf, inet_ntoa(mask));
345 strcat(buf, "\n High: ");
346 strcat(buf, inet_ntoa(high));
347 strcat(buf, " Low: ");
348 strcat(buf, inet_ntoa(low));
350 sprintf(buf, "Hostname prefix: %s", info[SN_PREFIX]);
352 sprintf(buf, " Owner: %s %s\n", info[SN_ACE_TYPE],
353 strcmp(info[SN_ACE_TYPE],"NONE") ? info[SN_ACE_NAME] : "");
355 sprintf(buf,MOD_FORMAT,info[SN_MODBY],info[SN_MODTIME],info[SN_MODWITH]);
357 return(info[SN_NAME]);
360 /* Function Name: GetMCInfo.
361 * Description: This function stores info about a machine.
362 * type - type of data we are trying to retrieve.
363 * name1 - the name of argv[0] for the call.
364 * name2 - the name of argv[1] for the call.
365 * Returns: the top element of a queue containing the data or NULL.
369 GetMCInfo(type, name1, name2)
371 char * name1, *name2;
375 struct qelem * elem = NULL;
381 args[1] = args[2] = args[3] = "*";
382 if ( (stat = do_mr_query("get_host", 4, args,
383 StoreInfo, (char *)&elem)) != 0) {
384 if (stat == MR_NO_MATCH) {
386 sprintf(buf, "Machine '%s' is not in the database.", name1);
389 com_err(program_name, stat, " in get_machine.");
396 if ( (stat = do_mr_query("get_hostalias", 2, args,
397 StoreInfo, (char *)&elem)) != 0) {
398 com_err(program_name, stat, " in get_hostalias.");
403 if ( (stat = do_mr_query("get_subnet", 1, &name1,
404 StoreInfo, (char *)&elem)) != 0) {
405 if (stat == MR_NO_MATCH) {
407 sprintf(buf, "Network '%s' is not in the database.", name1);
410 com_err(program_name, stat, " in get_subnet.");
415 if ( (stat = do_mr_query("get_cluster", 1, &name1,
416 StoreInfo, (char *)&elem)) != 0) {
417 com_err(program_name, stat, " in get_cluster.");
422 args[MAP_MACHINE] = name1;
423 args[MAP_CLUSTER] = name2;
424 if ( (stat = do_mr_query("get_machine_to_cluster_map", 2, args,
425 StoreInfo, (char *)&elem)) != 0) {
426 com_err(program_name, stat, " in get_machine_to_cluster_map.");
431 args[CD_NAME] = name1;
432 args[CD_LABEL] = name2;
433 if ( (stat = do_mr_query("get_cluster_data", 2, args,
434 StoreInfo, (char *)&elem)) != 0) {
435 com_err(program_name, stat, " in get_cluster_data.");
439 return(QueueTop(elem));
442 /* Function Name: AskMCDInfo.
443 * Description: This function askes the user for information about a
444 * machine and saves it into a structure.
445 * Arguments: info - a pointer the information to ask about
446 * type - type of information - MACHINE
449 * name - T/F : change the name of this type.
454 AskMCDInfo(info, type, name)
459 char temp_buf[BUFSIZ], *newname, *oldnewname;
463 sprintf(temp_buf, "\nSetting the information for the Machine %s...",
467 sprintf(temp_buf, "Setting the information for the Network %s...",
471 sprintf(temp_buf, "Setting the information for the Cluster %s...",
475 sprintf(temp_buf, "Setting the Data for the Cluster %s...",
479 Put_message(temp_buf);
484 newname = Strsave(info[M_NAME]);
485 if (GetValueFromUser("The new name for this machine? ", &newname) ==
488 oldnewname = Strsave(newname);
489 newname = canonicalize_hostname(newname);
490 if (strcasecmp(newname, oldnewname) && *oldnewname != '"') {
491 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
492 oldnewname, newname);
493 Put_message(temp_buf);
498 newname = Strsave(info[SN_NAME]);
499 if (GetValueFromUser("The new name for this network? ",
500 &newname) == SUB_ERROR)
504 newname = Strsave(info[C_NAME]);
505 if (GetValueFromUser("The new name for this cluster? ",
506 &newname) == SUB_ERROR)
510 Put_message("Unknown type in AskMCDInfo, programmer botch");
517 if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
519 if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
521 if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
524 if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
526 if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
530 if (GetValueFromUser("Machine's use code", &info[M_USE]) == SUB_ERROR)
535 if (GetValueFromUser("Machine's status (? for help)",
536 &info[M_STAT]) == SUB_ERROR)
538 if (isdigit(info[M_STAT][0])) break;
539 Put_message("Valid status numbers:");
540 for (i = 0; i < 4; i++) Put_message(states[i]);
543 /* there appears to be some argument mismatch between the client
544 * and the server.. so here is this argument shuffler.
545 * I have since modified this to always shuffle the arguments..
546 * not just do so when performing a modify all fields request.
547 * The SetMachinedefaults() has been changed to reflect this.
548 * pray for us and may we attain enlightenment through structures.
553 /* info did not come from SetMachineDefaults(), which does not
554 * initialize entry 8 (M_STAT_CHNG), therefore we can
557 /* This is an update of an existing machine and the structure
558 * was filled in thru a query to the db which does fill in this
564 info[8] = info[M_SUBNET];
565 info[9] = info[M_ADDR];
566 info[10] = info[M_OWNER_TYPE];
567 info[11] = info[M_OWNER_NAME];
568 info[12] = info[M_ACOMMENT];
569 info[13] = info[M_OCOMMENT];
572 if (GetValueFromUser("Machine's network (or 'none')", &info[8])
575 if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
576 &info[9]) == SUB_ERROR)
578 if (GetTypeFromUser("Machine's owner type", "ace_type", &info[10]) ==
581 if (strcmp(info[10], "NONE") &&
582 GetValueFromUser("Owner's Name", &info[11]) == SUB_ERROR)
584 if (GetValueFromUser("Administrative comment", &info[12]) == SUB_ERROR)
586 if (GetValueFromUser("Operational comment", &info[13]) == SUB_ERROR)
589 FreeAndClear(&info[15], TRUE);
590 FreeAndClear(&info[16], TRUE);
593 if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
595 if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
597 if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
599 if (atoi(info[SN_LOW]) == ntohl(inet_addr(S_DEFAULT_LOW))) {
601 unsigned long mask, addr;
603 addr = atoi(info[SN_ADDRESS]);
604 mask = atoi(info[SN_MASK]);
605 low.s_addr = atoi(info[SN_LOW]);
606 low.s_addr = (low.s_addr & ~mask) | (addr & mask);
608 sprintf(temp_buf, "%d", low.s_addr);
609 info[SN_LOW] = strsave(temp_buf);
611 if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) == SUB_ERROR)
613 if (atoi(info[SN_HIGH]) == ntohl(inet_addr(S_DEFAULT_HIGH))) {
615 unsigned long mask, addr;
617 addr = atoi(info[SN_ADDRESS]);
618 mask = atoi(info[SN_MASK]);
619 high.s_addr = atoi(info[SN_HIGH]);
620 high.s_addr = (high.s_addr & ~mask) | (addr & mask);
622 sprintf(temp_buf, "%d", high.s_addr);
623 info[SN_HIGH] = strsave(temp_buf);
625 if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) == SUB_ERROR)
627 if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
629 if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) == SUB_ERROR)
631 if (strcmp(info[SN_ACE_TYPE], "NONE") &&
632 GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
634 FreeAndClear(&info[SN_MODTIME], TRUE);
635 FreeAndClear(&info[SN_MODBY], TRUE);
636 FreeAndClear(&info[SN_MODWITH], TRUE);
639 if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
642 if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
645 FreeAndClear(&info[C_MODTIME], TRUE);
646 FreeAndClear(&info[C_MODBY], TRUE);
647 FreeAndClear(&info[C_MODWITH], TRUE);
650 if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
653 if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
659 * Slide the newname into the #2 slot, this screws up all future references
663 SlipInNewName(info, newname);
668 /* ----------- Machine Menu ----------- */
670 /* Function Name: ShowMachineInfo
671 * Description: This function shows the information about a machine.
672 * Arguments: argc, argv - the name of the machine in argv[1].
673 * Returns: DM_NORMAL.
678 ShowMachineInfo(argc, argv)
685 tmpname = canonicalize_hostname(strsave(argv[1]));
686 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
687 Loop(top, ( (void *) PrintMachInfo) );
692 /* Function Name: ShowMachineQuery
693 * Description: This function shows the information about a machine.
694 * or group of machines, which may be selected through a
695 * number of criteria.
696 * Arguments: argc, argv - the name of the machine in argv[1],
697 * the address of the machine in argv[2],
698 * the location of the machine in argv[3],
699 * and the contact name in argv[4].
700 * any of these may be wildcards.
701 * Returns: DM_NORMAL.
706 ShowMachineQuery(argc, argv)
711 struct qelem *top, *elem = NULL;
714 if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
715 !strcmp(argv[3], "") && !strcmp(argv[4], "")) {
716 Put_message("You must specify at least one parameter of the query.");
721 args[0] = canonicalize_hostname(strsave(argv[1]));
737 if ((stat = do_mr_query("get_host", 4, args, StoreInfo,
738 (char *)&elem)) != 0) {
739 if (stat == MR_NO_MATCH)
740 Put_message("No machine(s) found matching query in the database.");
742 com_err(program_name, stat, " in get_machine.");
745 top = QueueTop(elem);
746 Loop(top, ( (void *) PrintMachInfo) );
751 /* Function Name: AddMachine
752 * Description: This function adds a new machine to the database.
753 * Arguments: argc, argv - the name of the network in argv[1].
754 * Returns: DM_NORMAL.
759 AddMachine(argc, argv)
763 char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
765 struct qelem * elem = NULL;
768 if (!ValidName(argv[1])) /* Checks for wildcards. */
772 * get the network record
775 if (strcasecmp(argv[1], "none") &&
776 (stat = do_mr_query("get_subnet", 1, &argv[1],
777 StoreInfo, (char *)&elem)) != 0) {
778 if (stat == MR_NO_MATCH) {
780 sprintf(buf, "Network '%s' is not in the database.", argv[1]);
783 com_err(program_name, stat, " in get_subnet.");
788 * Check to see if this machine already exists.
791 name = strsave(""); /* want to put prefix here */
792 if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
795 name = canonicalize_hostname(strsave(name));
798 xargs[1] = xargs[2] = xargs[3] = "*";
799 if ( (stat = do_mr_query("get_host", 4, xargs, NullFunc, NULL)) == 0) {
800 sprintf(buf, "The machine '%s' already exists.", name);
805 else if (stat != MR_NO_MATCH) {
806 com_err(program_name, stat,
807 " while checking machine '%s' in AddMachine.", name);
811 rinfo = SetMachineDefaults(info, name);
812 rinfo[M_SUBNET] = argv[1];
813 if ((args = AskMCDInfo(rinfo, MACHINE, FALSE)) == NULL) {
814 Put_message("Aborted.");
819 * Actually create the new Machine.
822 if ( (stat = do_mr_query("add_host", CountArgs(args),
823 args, Scream, NULL)) != 0)
824 com_err(program_name, stat, " in AddMachine.");
831 /* Function Name: RealUpdateMachine
832 * Description: Performs the actual update of the machine data.
833 * Arguments: info - the information on the machine to update.
834 * junk - an UNUSED Boolean.
840 RealUpdateMachine(info, junk)
845 char ** args = AskMCDInfo(info, MACHINE, TRUE);
847 Put_message("Aborted.");
850 if ( (stat = do_mr_query("update_host", CountArgs(args),
851 args, Scream, NULL)) != 0)
852 com_err(program_name, stat, " in UpdateMachine.");
854 Put_message("Machine sucessfully updated.");
857 /* Function Name: UpdateMachine
858 * Description: This function adds a new machine to the database.
859 * Arguments: argc, argv - the name of the machine in argv[1].
860 * Returns: DM_NORMAL.
865 UpdateMachine(argc, argv)
872 tmpname = canonicalize_hostname(strsave(argv[1]));
873 top = GetMCInfo( MACHINE, tmpname, (char *) NULL);
874 QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
881 /* Function Name: CheckAndRemoveFromCluster
882 * Description: This func tests to see if a machine is in a cluster.
883 * and if so then removes it
884 * Arguments: name - name of the machine (already Canonocalized).
885 * ask_user- query the user before removing if from clusters?
886 * Returns: MR_ERROR if machine left in a cluster, or mr_error.
890 CheckAndRemoveFromCluster(name, ask_user)
894 register int stat, ret_value;
896 char *args[10], temp_buf[BUFSIZ], *ptr;
897 struct qelem *top, *elem = NULL;
899 ret_value = SUB_NORMAL; /* initialize ret_value. */
902 stat = do_mr_query("get_machine_to_cluster_map", 2, args,
903 StoreInfo, (char *)&elem);
904 if (stat && stat != MR_NO_MATCH) {
905 com_err(program_name, stat, " in get_machine_to_cluster_map.");
908 if (stat == MR_SUCCESS) {
909 elem = top = QueueTop(elem);
911 sprintf(temp_buf, "%s is assigned to the following clusters.",
913 Put_message(temp_buf);
914 Loop(top, (void *) PrintMCMap);
915 ptr = "Remove this machine from ** ALL ** these clusters?";
916 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
919 Put_message("Aborting...");
928 while (elem != NULL) {
929 char **info = (char **) elem->q_data;
930 if ( (stat = do_mr_query( "delete_machine_from_cluster",
931 2, info, Scream, NULL)) != 0) {
932 ret_value = SUB_ERROR;
933 com_err(program_name, stat,
934 " in delete_machine_from_cluster.");
936 "Machine %s ** NOT ** removed from cluster %s.",
937 info[MAP_MACHINE], info[MAP_CLUSTER]);
938 Put_message(temp_buf);
947 /* Function Name: RealDeleteMachine
948 * Description: Actually Deletes the Machine.
949 * Arguments: info - nescessary information stored as an array of char *'s
950 * one_machine - a boolean, true if there is only one item in
956 RealDeleteMachine(info, one_machine)
961 char temp_buf[BUFSIZ];
963 sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
965 if(!one_machine || Confirm(temp_buf)) {
966 if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR) {
967 if ( (stat = do_mr_query("delete_host", 1,
968 &info[M_NAME], Scream, NULL)) != 0) {
969 com_err(program_name, stat, " in DeleteMachine.");
970 sprintf(temp_buf, "%s ** NOT ** deleted.",
972 Put_message(temp_buf);
975 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
976 Put_message(temp_buf);
982 /* Function Name: DeleteMachine
983 * Description: This function removes a machine from the data base.
984 * Arguments: argc, argv - the machines name int argv[1].
985 * Returns: DM_NORMAL.
988 /* Perhaps we should remove the cluster if it has no machine now. */
992 DeleteMachine(argc, argv)
999 tmpname = canonicalize_hostname(strsave(argv[1]));
1000 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
1001 QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
1008 char *partial_canonicalize_hostname(s)
1012 static char *def_domain = NULL;
1015 struct utsname name;
1020 (void) uname(&name);
1021 strncpy(buf, name.nodename, sizeof(buf));
1023 gethostname(buf, sizeof(buf));
1025 hp = gethostbyname(buf);
1026 cp = (char *) strchr(hp->h_name, '.');
1028 def_domain = strsave(++cp);
1033 if (strchr(s, '.') || strchr(s, '*'))
1035 sprintf(buf, "%s.%s", s, def_domain);
1037 return(strsave(buf));
1041 /* Function Name: ShowCname
1042 * Description: This function shows machine aliases
1043 * Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1044 * Returns: DM_NORMAL.
1049 ShowCname(argc, argv)
1054 char *tmpalias, *tmpname;
1056 tmpalias = partial_canonicalize_hostname(strsave(argv[1]));
1057 tmpname = canonicalize_hostname(strsave(argv[2]));
1058 top = GetMCInfo(CNAME, tmpalias, tmpname);
1059 Put_message(""); /* blank line on screen */
1060 Loop(top, ( (void *) PrintCname) );
1068 AddCname(argc, argv)
1073 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1074 Bool add_it, one_machine, one_cluster;
1075 struct qelem * melem, *mtop, *celem, *ctop;
1077 args[0] = partial_canonicalize_hostname(strsave(argv[1]));
1078 args[1] = canonicalize_hostname(strsave(argv[2]));
1079 stat = do_mr_query("add_hostalias", 2, args, Scream, NULL);
1084 Put_message("That alias name is already in use.");
1087 Put_message("Permission denied. (Regular users can only add two aliases to a host.");
1090 com_err(program_name, stat, " in add_hostalias");
1098 DeleteCname(argc, argv)
1103 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1104 Bool add_it, one_machine, one_cluster;
1105 struct qelem * melem, *mtop, *celem, *ctop;
1107 args[0] = partial_canonicalize_hostname(strsave(argv[1]));
1108 args[1] = canonicalize_hostname(strsave(argv[2]));
1109 stat = do_mr_query("delete_hostalias", 2, args, Scream, NULL);
1111 com_err(program_name, stat, " in delete_hostalias");
1116 /* Function Name: AddMachineToCluster
1117 * Description: This function adds a machine to a cluster
1118 * Arguments: argc, argv - The machine name is argv[1].
1119 * The cluster name in argv[2].
1120 * Returns: DM_NORMAL.
1125 AddMachineToCluster(argc, argv)
1130 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1131 Bool add_it, one_machine, one_cluster;
1132 struct qelem * melem, *mtop, *celem, *ctop;
1134 machine = canonicalize_hostname(strsave(argv[1]));
1135 if (strcasecmp(machine, argv[1]) && *argv[1] != '"') {
1136 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1138 Put_message(temp_buf);
1142 celem = ctop = GetMCInfo(CLUSTER, cluster, (char *) NULL);
1143 melem = mtop = GetMCInfo(MACHINE, machine, (char *) NULL);
1146 one_machine = (QueueCount(mtop) == 1);
1147 one_cluster = (QueueCount(ctop) == 1);
1149 /* No good way to use QueryLoop() here, sigh */
1151 while (melem != NULL) {
1152 char ** minfo = (char **) melem->q_data;
1153 while (celem != NULL) {
1154 char ** cinfo = (char **) celem->q_data;
1155 if (one_machine && one_cluster)
1158 sprintf(temp_buf,"Add machine %s to cluster %s (y/n/q) ?",
1159 minfo[M_NAME], cinfo[C_NAME]);
1160 switch (YesNoQuitQuestion(temp_buf, FALSE)) {
1168 Put_message("Aborting...");
1175 args[0] = minfo[M_NAME];
1176 args[1] = cinfo[C_NAME];
1177 stat = do_mr_query("add_machine_to_cluster", 2, args,
1183 sprintf(temp_buf, "%s is already in cluster %s",
1184 minfo[M_NAME], cinfo[C_NAME]);
1185 Put_message(temp_buf);
1188 com_err(program_name, stat, " in AddMachineToCluster.");
1192 celem = celem->q_forw;
1194 celem = ctop; /* reset cluster element. */
1195 melem = melem->q_forw;
1202 /* Function Name: RealRemoveMachineFromCluster
1203 * Description: This function actually removes the machine from its
1205 * Arguments: info - all information nescessary to perform the removal.
1206 * one_map - True if there is only one case, and we should
1212 RealRemoveMachineFromCluster(info, one_map)
1216 char temp_buf[BUFSIZ];
1219 sprintf(temp_buf, "Remove %s from the cluster %s",
1220 info[MAP_MACHINE], info[MAP_CLUSTER]);
1221 if (!one_map || Confirm(temp_buf)) {
1222 if ( (stat = do_mr_query("delete_machine_from_cluster", 2,
1223 info, Scream, NULL)) != 0 )
1224 com_err(program_name, stat, " in delete_machine_from_cluster");
1226 sprintf(temp_buf, "%s has been removed from the cluster %s.",
1227 info[MAP_MACHINE], info[MAP_CLUSTER]);
1228 Put_message(temp_buf);
1232 Put_message("Machine not removed.");
1235 /* Function Name: RemoveMachineFromCluster
1236 * Description: Removes this machine form a specific cluster.
1237 * Arguments: argc, argv - Name of machine in argv[1].
1238 * Name of cluster in argv[2].
1244 RemoveMachineFromCluster(argc, argv)
1248 struct qelem *elem = NULL;
1249 char buf[BUFSIZ], * args[10];
1252 args[MAP_MACHINE] = canonicalize_hostname(strsave(argv[1]));
1253 if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"') {
1254 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1255 argv[1], args[MAP_MACHINE]);
1258 args[MAP_CLUSTER] = argv[2];
1259 args[MAP_END] = NULL;
1261 stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1262 StoreInfo, (char *)&elem);
1263 if (stat == MR_NO_MATCH) {
1264 sprintf(buf, "The machine %s is not is the cluster %s.",
1265 args[MAP_MACHINE], args[MAP_CLUSTER]);
1267 free(args[MAP_MACHINE]);
1270 if (stat != MR_SUCCESS)
1271 com_err(program_name, stat, " in delete_machine_from_cluster");
1273 elem = QueueTop(elem);
1274 QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1275 "Remove this machine from this cluster");
1278 free(args[MAP_MACHINE]);
1282 /* ---------- Subnet Menu -------- */
1284 /* Function Name: ShowSubnetInfo
1285 * Description: Gets information about a subnet given its name.
1286 * Arguments: argc, argc - the name of the subnet in in argv[1].
1287 * Returns: DM_NORMAL.
1292 ShowSubnetInfo(argc, argv)
1298 top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1299 Loop(top, (void *) PrintSubnetInfo);
1304 /* Function Name: AddSubnet
1305 * Description: Creates a new subnet.
1306 * Arguments: argc, argv - the name of the new subnet is argv[1].
1307 * Returns: DM_NORMAL.
1312 AddSubnet(argc, argv)
1316 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1319 * Check to see if this subnet already exists.
1321 if (!ValidName(name))
1324 if ( (stat = do_mr_query("get_subnet", 1, &name,
1325 NullFunc, NULL)) == MR_SUCCESS) {
1326 Put_message("This subnet already exists.");
1329 else if (stat != MR_NO_MATCH) {
1330 com_err(program_name, stat, " in AddSubnet.");
1333 if ((args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)) ==
1335 Put_message("Aborted.");
1341 * Actually create the new Subnet.
1343 if ( (stat = do_mr_query("add_subnet", CountArgs(args),
1344 args, Scream, NULL)) != 0)
1345 com_err(program_name, stat, " in AddSubnet.");
1351 /* Function Name: RealUpdateSubnet
1352 * Description: This function actually performs the subnet update.
1353 * Arguments: info - all information nesc. for updating the subnet.
1354 * junk - an UNUSED boolean.
1360 RealUpdateSubnet(info, junk)
1365 char ** args = AskMCDInfo(info, SUBNET, TRUE);
1367 Put_message("Aborted.");
1370 if ( (stat = do_mr_query("update_subnet", CountArgs(args),
1371 args, Scream, NULL)) != 0)
1372 com_err(program_name, stat, " in UpdateSubnet.");
1374 Put_message("Subnet successfully updated.");
1377 /* Function Name: UpdateSubnet
1378 * Description: This Function Updates a subnet
1379 * Arguments: name of the subnet in argv[1].
1380 * Returns: DM_NORMAL.
1385 UpdateSubnet(argc, argv)
1390 top = GetMCInfo( SUBNET, argv[1], (char *) NULL );
1391 QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1397 /* Function Name: RealDeleteSubnet
1398 * Description: Actually performs the subnet deletion.
1399 * Arguments: info - all information about this subnet.
1400 * one_subnet - If true then there was only one subnet in
1401 * the queue, and we should confirm.
1406 RealDeleteSubnet(info, one_subnet)
1411 char temp_buf[BUFSIZ];
1414 "Are you sure the you want to delete the subnet %s (y/n) ?",
1416 if (!one_subnet || Confirm(temp_buf)) {
1417 if ( (stat = do_mr_query("delete_subnet", 1,
1418 &info[C_NAME], Scream, NULL)) != 0) {
1419 com_err(program_name, stat, " in delete_subnet.");
1420 sprintf(temp_buf, "Subnet %s ** NOT ** deleted.",
1422 Put_message(temp_buf);
1425 sprintf(temp_buf, "subnet %s sucesfully deleted.",
1427 Put_message(temp_buf);
1432 /* Function Name: DeleteSubnet
1433 * Description: This function removes a subnet from the database.
1434 * Arguments: argc, argv - the name of the subnet is stored in argv[1].
1435 * Returns: DM_NORMAL.
1440 DeleteSubnet(argc, argv)
1446 top = GetMCInfo( SUBNET, argv[1], (char *) NULL );
1447 QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1453 /* ---------- Cluster Menu -------- */
1455 /* Function Name: ShowClusterInfo
1456 * Description: Gets information about a cluser given its name.
1457 * Arguments: argc, argc - the name of the cluster in in argv[1].
1458 * Returns: DM_NORMAL.
1463 ShowClusterInfo(argc, argv)
1469 top = GetMCInfo(CLUSTER, argv[1], (char *) NULL);
1470 Loop(top, (void *) PrintClusterInfo);
1475 /* Function Name: AddCluster
1476 * Description: Creates a new cluster.
1477 * Arguments: argc, argv - the name of the new cluster is argv[1].
1478 * Returns: DM_NORMAL.
1483 AddCluster(argc, argv)
1487 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1490 * Check to see if this cluster already exists.
1492 if (!ValidName(name))
1495 if ( (stat = do_mr_query("get_cluster", 1, &name,
1496 NullFunc, NULL)) == MR_SUCCESS) {
1497 Put_message("This cluster already exists.");
1500 else if (stat != MR_NO_MATCH) {
1501 com_err(program_name, stat, " in AddCluster.");
1504 if ((args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)) ==
1506 Put_message("Aborted.");
1512 * Actually create the new Cluster.
1514 if ( (stat = do_mr_query("add_cluster", CountArgs(args),
1515 args, Scream, NULL)) != 0)
1516 com_err(program_name, stat, " in AddCluster.");
1522 /* Function Name: RealUpdateCluster
1523 * Description: This function actually performs the cluster update.
1524 * Arguments: info - all information nesc. for updating the cluster.
1525 * junk - an UNUSED boolean.
1531 RealUpdateCluster(info, junk)
1536 char ** args = AskMCDInfo(info, CLUSTER, TRUE);
1538 Put_message("Aborted.");
1541 if ( (stat = do_mr_query("update_cluster", CountArgs(args),
1542 args, Scream, NULL)) != 0)
1543 com_err(program_name, stat, " in UpdateCluster.");
1545 Put_message("Cluster successfully updated.");
1548 /* Function Name: UpdateCluster
1549 * Description: This Function Updates a cluster
1550 * Arguments: name of the cluster in argv[1].
1551 * Returns: DM_NORMAL.
1556 UpdateCluster(argc, argv)
1561 top = GetMCInfo( CLUSTER, argv[1], (char *) NULL );
1562 QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1568 /* Function Name: CheckAndRemoveMachine
1569 * Description: This function checks and removes all machines from a
1571 * Arguments: name - name of the cluster.
1572 * ask_first - if TRUE, then we will query the user, before
1574 * Returns: SUB_ERROR if all machines not removed.
1578 CheckAndRemoveMachines(name, ask_first)
1582 register int stat, ret_value;
1584 char *args[10], temp_buf[BUFSIZ], *ptr;
1585 struct qelem *top, *elem = NULL;
1587 ret_value = SUB_NORMAL;
1588 args[MAP_MACHINE] = "*";
1589 args[MAP_CLUSTER] = name;
1590 stat = do_mr_query("get_machine_to_cluster_map", 2, args,
1591 StoreInfo, (char *)&elem);
1592 if (stat && stat != MR_NO_MATCH) {
1593 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1597 elem = top = QueueTop(elem);
1600 "The cluster %s has the following machines in it:",
1602 Put_message(temp_buf);
1603 while (elem != NULL) {
1604 char **info = (char **) elem->q_data;
1605 Print(1, &info[MAP_MACHINE], (char *) NULL);
1606 elem = elem->q_forw;
1608 ptr = "Remove ** ALL ** these machines from this cluster?";
1610 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1613 Put_message("Aborting...");
1624 char **info = (char **) elem->q_data;
1625 if ( (stat = do_mr_query("delete_machine_from_cluster",
1626 2, info, Scream, NULL)) != 0) {
1627 ret_value = SUB_ERROR;
1628 com_err(program_name, stat,
1629 " in delete_machine_from_cluster.");
1631 "Machine %s ** NOT ** removed from cluster %s.",
1632 info[MAP_MACHINE], info[MAP_CLUSTER]);
1633 Put_message(temp_buf);
1635 elem = elem->q_forw;
1642 /* Function Name: RealDeleteCluster
1643 * Description: Actually performs the cluster deletion.
1644 * Arguments: info - all information about this cluster.
1645 * one_cluster - If true then there was only one cluster in
1646 * the queue, and we should confirm.
1651 RealDeleteCluster(info, one_cluster)
1656 char temp_buf[BUFSIZ];
1659 "Are you sure the you want to delete the cluster %s (y/n) ?",
1661 if (!one_cluster || Confirm(temp_buf)) {
1662 if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR) {
1663 if ( (stat = do_mr_query("delete_cluster", 1,
1664 &info[C_NAME], Scream, NULL)) != 0) {
1665 com_err(program_name, stat, " in delete_cluster.");
1666 sprintf(temp_buf, "Cluster %s ** NOT ** deleted.",
1668 Put_message(temp_buf);
1671 sprintf(temp_buf, "cluster %s sucesfully deleted.",
1673 Put_message(temp_buf);
1679 /* Function Name: DeleteCluster
1680 * Description: This function removes a cluster from the database.
1681 * Arguments: argc, argv - the name of the cluster is stored in argv[1].
1682 * Returns: DM_NORMAL.
1687 DeleteCluster(argc, argv)
1693 top = GetMCInfo( CLUSTER, argv[1], (char *) NULL );
1694 QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1700 /* ----------- Cluster Data Menu -------------- */
1702 /* Function Name: ShowClusterData
1703 * Description: This function shows the services for one cluster.
1704 * Arguments: argc, argv - The name of the cluster is argv[1].
1705 * The label of the data in argv[2].
1706 * Returns: DM_NORMAL.
1711 ShowClusterData(argc, argv)
1715 struct qelem *elem, *top;
1718 top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1719 while (elem != NULL) {
1720 info = (char **) elem->q_data;
1721 PrintClusterData(info);
1722 elem = elem->q_forw;
1728 /* Function Name: AddClusterData
1729 * Description: This function adds some data to the cluster.
1730 * Arguments: argv, argc: argv[1] - the name of the cluster.
1731 * argv[2] - the label of the data.
1732 * argv[3] - the data.
1733 * Returns: DM_NORMAL.
1738 AddClusterData(argc, argv)
1744 if( (stat = do_mr_query("add_cluster_data", 3, argv + 1,
1745 Scream, (char *) NULL)) != 0)
1746 com_err(program_name, stat, " in AddClusterData.");
1750 /* Function Name: RealRemoveClusterData
1751 * Description: actually removes the cluster data.
1752 * Arguments: info - all info necessary to remove the cluster, in an array
1754 * one_item - if true then the queue has only one elem and we
1760 RealRemoveClusterData(info, one_item)
1768 temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1769 PrintClusterData(info);
1770 if (!one_item || Confirm(temp_ptr)) {
1771 if( (stat = do_mr_query("delete_cluster_data", 3, info,
1772 Scream, (char *) NULL)) != 0) {
1773 com_err(program_name, stat, " in DeleteClusterData.");
1774 Put_message("Data not removed.");
1777 Put_message("Removal sucessful.");
1781 /* Function Name: RemoveClusterData
1782 * Description: This function removes data on a given cluster.
1783 * Arguments: argv, argc: argv[1] - the name of the cluster.
1784 * argv[2] - the label of the data.
1785 * argv[3] - the data.
1786 * Returns: DM_NORMAL.
1791 RemoveClusterData(argc, argv)
1797 top = GetMCInfo(DATA, argv[1], argv[2]);
1798 QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1799 "Remove data from cluster");
1805 /* Function Name: MachineToClusterMap
1806 * Description: This Retrieves the mapping between machine and cluster
1807 * Arguments: argc, argv - argv[1] -> machine name or wildcard.
1808 * argv[2] -> cluster name or wildcard.
1814 MachineToClusterMap(argc,argv)
1818 struct qelem *elem, *top;
1819 char *tmpname, temp_buf[256];
1821 tmpname = canonicalize_hostname(strsave(argv[1]));
1822 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"') {
1823 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1825 Put_message(temp_buf);
1827 top = elem = GetMCInfo(MAP, tmpname, argv[2]);
1829 Put_message(""); /* blank line on screen */
1830 while (elem != NULL) {
1831 char ** info = (char **) elem->q_data;
1833 elem = elem->q_forw;