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>
38 #include "mit-copyright.h"
50 #define M_DEFAULT_TYPE DEFAULT_NONE
52 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
53 #define C_DEFAULT_LOCATION DEFAULT_NONE
55 #define CD_DEFAULT_LABEL DEFAULT_NONE
56 #define CD_DEFAULT_DATA DEFAULT_NONE
58 #define S_DEFAULT_LOW "18.0.0.10"
59 #define S_DEFAULT_HIGH "18.0.2.252"
61 static char *states[] = { "Reserved (0)",
66 static char *MacState(state)
71 if (state < 0 || state > 3) {
72 sprintf(buf, "Unknown (%d)", state);
75 return(states[state]);
80 /* -------------------- Set Defaults -------------------- */
82 /* Function Name: SetMachineDefaults
83 * Description: sets machine defaults.
84 * Arguments: info - an array to put the defaults into.
85 * name - Canonacalized name of the machine.
86 * Returns: info - the array.
90 SetMachineDefaults(info, name)
93 info[M_NAME] = Strsave(name);
94 info[M_VENDOR] = Strsave(M_DEFAULT_TYPE);
95 info[M_MODEL] = Strsave(M_DEFAULT_TYPE);
96 info[M_OS] = Strsave(M_DEFAULT_TYPE);
97 info[M_LOC] = Strsave(M_DEFAULT_TYPE);
98 info[M_CONTACT] = Strsave(M_DEFAULT_TYPE);
99 info[M_USE] = Strsave("0");
100 info[M_STAT] = Strsave("1");
101 info[8] = Strsave("NONE");
102 info[9] = Strsave("unique");
103 info[10] = Strsave("NONE");
104 info[11] = Strsave("NONE");
105 info[12] = Strsave("");
106 info[13] = Strsave("");
107 info[14] = info[15] = info[16] = NULL;
111 /* Function Name: SetClusterDefaults
112 * Description: sets Cluster defaults.
113 * Arguments: info - an array to put the defaults into.
114 * name - name of the Cluster.
115 * Returns: info - the array.
119 SetClusterDefaults(info, name)
122 info[C_NAME] = Strsave(name);
123 info[C_DESCRIPT] = Strsave(C_DEFAULT_DESCRIPT);
124 info[C_LOCATION] = Strsave(C_DEFAULT_LOCATION);
125 info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
129 /* Function Name: SetSubnetDefaults
130 * Description: sets Subnet defaults.
131 * Arguments: info - an array to put the defaults into.
132 * name - name of the Subnet.
133 * Returns: info - the array.
137 SetSubnetDefaults(info, name)
142 info[C_NAME] = Strsave(name);
143 info[SN_DESC] = Strsave("");
144 sprintf(buf, "%d", ntohl(inet_addr("18.255.0.0")));
145 info[SN_ADDRESS] = Strsave(buf);
146 sprintf(buf, "%d", ntohl(inet_addr("255.255.0.0")));
147 info[SN_MASK] = Strsave(buf);
148 sprintf(buf, "%d", ntohl(inet_addr(S_DEFAULT_LOW)));
149 info[SN_LOW] = Strsave(buf);
150 sprintf(buf, "%d", ntohl(inet_addr(S_DEFAULT_HIGH)));
151 info[SN_HIGH] = Strsave(buf);
152 info[SN_PREFIX] = Strsave("");
153 info[SN_ACE_TYPE] = Strsave("LIST");
154 info[SN_ACE_NAME] = Strsave("network_acl");
155 info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
159 /* -------------------- General Functions -------------------- */
161 static char aliasbuf[256];
167 if (strlen(aliasbuf) == 0)
168 sprintf(aliasbuf, "Aliases: %s", info[0]);
170 strcat(aliasbuf, ", ");
171 strcat(aliasbuf, info[0]);
176 /* Function Name: PrintMachInfo
177 * Description: This function Prints out the Machine info in
179 * Arguments: info - array of information about a machine.
180 * Returns: The name of the Machine
187 char buf[BUFSIZ], tbuf[256];
189 struct qelem *elem = NULL;
193 sprintf(buf, "Machine: %s", info[M_NAME]);
196 args[1] = info[M_NAME];
197 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, (char *)&elem))
199 if (stat != MR_NO_MATCH)
200 com_err(program_name, stat, " looking up aliases");
203 Loop(QueueTop(elem), (void *) PrintAliases);
205 Put_message(aliasbuf);
207 sprintf(buf, "Address: %-16s Subnet: %s",
208 info[M_ADDR], info[M_SUBNET]);
210 sprintf(buf, "Status: %-16s Changed: %s",
211 MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
213 sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
214 strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
215 sprintf(buf, "Owner: %-16s Last poll: %s", tbuf, info[M_INUSE]);
219 sprintf(buf, "Vendor: %-16s Model: %-24s OS: %s",
220 info[M_VENDOR], info[M_MODEL], info[M_OS]);
222 sprintf(buf, "Location: %-16s Contact: %s Use code: %s",
223 info[M_LOC], info[M_CONTACT], info[M_USE]);
225 sprintf(buf, "Admn cmt: %s", info[M_ACOMMENT]);
227 sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]);
230 sprintf(buf, "Created by %s on %s", info[M_CREATOR], info[M_CREATED]);
232 sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
234 return(info[M_NAME]);
237 /* Function Name: PrintCname
238 * Description: Prints the Data on a host alias
239 * Arguments: info a pointer to the data array.
240 * Returns: The name of the alias.
249 sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
254 /* Function Name: PrintClusterInfo
255 * Description: This function Prints out the cluster info
256 * in a coherent form.
257 * Arguments: info - array of information about a cluster.
258 * Returns: The name of the cluster.
262 PrintClusterInfo(info)
268 sprintf(buf, "Cluster: %s", info[C_NAME]);
270 sprintf(buf, "Description: %s", info[C_DESCRIPT]);
272 sprintf(buf, "Location: %s", info[C_LOCATION]);
274 sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
276 return(info[C_NAME]);
279 /* Function Name: PrintClusterData
280 * Description: Prints the Data on a cluster
281 * Arguments: info a pointer to the data array.
282 * Returns: The name of the cluster.
286 PrintClusterData(info)
292 sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
293 info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
295 return(info[CD_NAME]);
298 /* Function Name: PrintMCMap
299 * Description: Prints the data about a machine to cluster mapping.
300 * Arguments: info a pointer to the data array.
309 sprintf(buf, "Cluster: %-30s Machine: %-20s",
310 info[MAP_CLUSTER], info[MAP_MACHINE]);
312 return(""); /* Used by QueryLoop(). */
315 /* Function Name: PrintSubnetInfo
316 * Description: This function Prints out the subnet info
317 * in a coherent form.
318 * Arguments: info - array of information about a subnet.
319 * Returns: The name of the subnet.
323 PrintSubnetInfo(info)
327 struct in_addr addr, mask, low, high;
330 sprintf(buf, "Subnet: %s", info[SN_NAME]);
332 sprintf(buf, "Description: %s", info[SN_DESC]);
334 addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
335 mask.s_addr = htonl(atoi(info[SN_MASK]));
336 low.s_addr = htonl(atoi(info[SN_LOW]));
337 high.s_addr = htonl(atoi(info[SN_HIGH]));
338 /* screwy sequence is here because inet_ntoa returns a pointer to
339 a static buf. If it were all one sprintf, the last value would
341 sprintf(buf, "Address %s, Mask ", inet_ntoa(addr));
342 strcat(buf, inet_ntoa(mask));
343 strcat(buf, ", High ");
344 strcat(buf, inet_ntoa(high));
345 strcat(buf, ", Low ");
346 strcat(buf, inet_ntoa(low));
348 sprintf(buf, "Hostname prefix: %s", info[SN_PREFIX]);
350 sprintf(buf, "Owner: %s %s", info[SN_ACE_TYPE],
351 strcmp(info[SN_ACE_TYPE],"NONE") ? info[SN_ACE_NAME] : "");
353 sprintf(buf,MOD_FORMAT,info[SN_MODBY],info[SN_MODTIME],info[SN_MODWITH]);
355 return(info[SN_NAME]);
358 /* Function Name: GetMCInfo.
359 * Description: This function stores info about a machine.
360 * type - type of data we are trying to retrieve.
361 * name1 - the name of argv[0] for the call.
362 * name2 - the name of argv[1] for the call.
363 * Returns: the top element of a queue containing the data or NULL.
367 GetMCInfo(type, name1, name2)
369 char * name1, *name2;
373 struct qelem * elem = NULL;
379 args[1] = args[2] = args[3] = "*";
380 if ( (stat = do_mr_query("get_host", 4, args,
381 StoreInfo, (char *)&elem)) != 0) {
382 if (stat == MR_NO_MATCH) {
384 sprintf(buf, "Machine '%s' is not in the database.", name1);
387 com_err(program_name, stat, " in get_machine.");
394 if ( (stat = do_mr_query("get_hostalias", 2, args,
395 StoreInfo, (char *)&elem)) != 0) {
396 com_err(program_name, stat, " in get_hostalias.");
401 if ( (stat = do_mr_query("get_subnet", 1, &name1,
402 StoreInfo, (char *)&elem)) != 0) {
403 if (stat == MR_NO_MATCH) {
405 sprintf(buf, "Subnet '%s' is not in the database.", name1);
408 com_err(program_name, stat, " in get_subnet.");
413 if ( (stat = do_mr_query("get_cluster", 1, &name1,
414 StoreInfo, (char *)&elem)) != 0) {
415 com_err(program_name, stat, " in get_cluster.");
420 args[MAP_MACHINE] = name1;
421 args[MAP_CLUSTER] = name2;
422 if ( (stat = do_mr_query("get_machine_to_cluster_map", 2, args,
423 StoreInfo, (char *)&elem)) != 0) {
424 com_err(program_name, stat, " in get_machine_to_cluster_map.");
429 args[CD_NAME] = name1;
430 args[CD_LABEL] = name2;
431 if ( (stat = do_mr_query("get_cluster_data", 2, args,
432 StoreInfo, (char *)&elem)) != 0) {
433 com_err(program_name, stat, " in get_cluster_data.");
437 return(QueueTop(elem));
440 /* Function Name: AskMCDInfo.
441 * Description: This function askes the user for information about a
442 * machine and saves it into a structure.
443 * Arguments: info - a pointer the information to ask about
444 * type - type of information - MACHINE
447 * name - T/F : change the name of this type.
452 AskMCDInfo(info, type, name)
457 char temp_buf[BUFSIZ], *newname, *oldnewname;
461 sprintf(temp_buf, "Setting the information for the Machine %s.",
465 sprintf(temp_buf, "Setting the information for the Subnet %s.",
469 sprintf(temp_buf, "Setting the information for the Cluster %s.",
473 sprintf(temp_buf, "Setting the Data for the Cluster %s.",
477 Put_message(temp_buf);
482 newname = Strsave(info[M_NAME]);
483 if (GetValueFromUser("The new name for this machine? ", &newname) ==
486 oldnewname = Strsave(newname);
487 newname = canonicalize_hostname(newname);
488 if (strcasecmp(newname, oldnewname) && *oldnewname != '"') {
489 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
490 oldnewname, newname);
491 Put_message(temp_buf);
496 newname = Strsave(info[SN_NAME]);
497 if (GetValueFromUser("The new name for this subnet? ",
498 &newname) == SUB_ERROR)
502 newname = Strsave(info[C_NAME]);
503 if (GetValueFromUser("The new name for this cluster? ",
504 &newname) == SUB_ERROR)
508 Put_message("Unknown type in AskMCDInfo, programmer botch");
515 if (GetValueFromUser("Machine's Vendor", &info[M_VENDOR]) == SUB_ERROR)
517 if (GetValueFromUser("Machine's Model", &info[M_MODEL]) == SUB_ERROR)
519 if (GetValueFromUser("Machine's Operating System", &info[M_OS]) ==
522 if (GetValueFromUser("Location of Machine", &info[M_LOC]) == SUB_ERROR)
524 if (GetValueFromUser("Contact for Machine", &info[M_CONTACT]) ==
527 if (GetValueFromUser("Machine's Use Code", &info[M_USE]) == SUB_ERROR)
531 if (GetValueFromUser("Machine's Status (? for help)",
532 &info[M_STAT]) == SUB_ERROR)
534 if (isdigit(info[M_STAT][0])) break;
535 Put_message("Valid status numbers:");
536 for (i = 0; i < 4; i++) Put_message(states[i]);
540 info[8] = info[M_SUBNET];
541 info[9] = info[M_ADDR];
542 info[10] = info[M_OWNER_TYPE];
543 info[11] = info[M_OWNER_NAME];
544 info[12] = info[M_ACOMMENT];
545 info[13] = info[M_OCOMMENT];
547 if (GetValueFromUser("Machine's subnet (or 'none')", &info[8])
550 if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
551 &info[9]) == SUB_ERROR)
553 if (GetTypeFromUser("Machine's Owner Type", "ace_type", &info[10]) ==
556 if (strcmp(info[10], "NONE") &&
557 GetValueFromUser("Owner's Name", &info[11]) == SUB_ERROR)
559 if (GetValueFromUser("Administrative Comment", &info[12]) == SUB_ERROR)
561 if (GetValueFromUser("Operational Comment", &info[13]) == SUB_ERROR)
564 FreeAndClear(&info[15], TRUE);
565 FreeAndClear(&info[16], TRUE);
568 if (GetValueFromUser("Subnet Description", &info[SN_DESC]) == SUB_ERROR)
570 if (GetAddressFromUser("Subnet Address", &info[SN_ADDRESS]) == SUB_ERROR)
572 if (GetAddressFromUser("Subnet Mask", &info[SN_MASK]) == SUB_ERROR)
574 if (atoi(info[SN_LOW]) == ntohl(inet_addr(S_DEFAULT_LOW))) {
576 unsigned long mask, addr;
578 addr = atoi(info[SN_ADDRESS]);
579 mask = atoi(info[SN_MASK]);
580 low.s_addr = atoi(info[SN_LOW]);
581 low.s_addr = (low.s_addr & ~mask) | (addr & mask);
583 sprintf(temp_buf, "%d", low.s_addr);
584 info[SN_LOW] = strsave(temp_buf);
586 if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) == SUB_ERROR)
588 if (atoi(info[SN_HIGH]) == ntohl(inet_addr(S_DEFAULT_HIGH))) {
590 unsigned long mask, addr;
592 addr = atoi(info[SN_ADDRESS]);
593 mask = atoi(info[SN_MASK]);
594 high.s_addr = atoi(info[SN_HIGH]);
595 high.s_addr = (high.s_addr & ~mask) | (addr & mask);
597 sprintf(temp_buf, "%d", high.s_addr);
598 info[SN_HIGH] = strsave(temp_buf);
600 if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) == SUB_ERROR)
602 if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
604 if (GetTypeFromUser("Owner Type", "ace_type", &info[SN_ACE_TYPE]) == SUB_ERROR)
606 if (strcmp(info[SN_ACE_TYPE], "NONE") &&
607 GetValueFromUser("Owner Name", &info[SN_ACE_NAME]) == SUB_ERROR)
609 FreeAndClear(&info[SN_MODTIME], TRUE);
610 FreeAndClear(&info[SN_MODBY], TRUE);
611 FreeAndClear(&info[SN_MODWITH], TRUE);
614 if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
617 if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
620 FreeAndClear(&info[C_MODTIME], TRUE);
621 FreeAndClear(&info[C_MODBY], TRUE);
622 FreeAndClear(&info[C_MODWITH], TRUE);
625 if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
628 if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
634 * Slide the newname into the #2 slot, this screws up all future references
638 SlipInNewName(info, newname);
643 /* ----------- Machine Menu ----------- */
645 /* Function Name: ShowMachineInfo
646 * Description: This function shows the information about a machine.
647 * Arguments: argc, argv - the name of the machine in argv[1].
648 * Returns: DM_NORMAL.
653 ShowMachineInfo(argc, argv)
660 tmpname = canonicalize_hostname(strsave(argv[1]));
661 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
662 Loop(top, ( (void *) PrintMachInfo) );
667 /* Function Name: ShowMachineQuery
668 * Description: This function shows the information about a machine.
669 * or group of machines, which may be selected through a
670 * number of criteria.
671 * Arguments: argc, argv - the name of the machine in argv[1],
672 * the address of the machine in argv[2],
673 * the location of the machine in argv[3],
674 * and the contact name in argv[4].
675 * any of these may be wildcards.
676 * Returns: DM_NORMAL.
681 ShowMachineQuery(argc, argv)
686 struct qelem *top, *elem = NULL;
689 if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
690 !strcmp(argv[3], "") && !strcmp(argv[4], "")) {
691 Put_message("You must specify at least one parameter of the query.");
696 args[0] = canonicalize_hostname(strsave(argv[1]));
712 if ((stat = do_mr_query("get_host", 4, args, StoreInfo,
713 (char *)&elem)) != 0) {
714 if (stat == MR_NO_MATCH)
715 Put_message("No machine(s) found matching query in the database.");
717 com_err(program_name, stat, " in get_machine.");
720 top = QueueTop(elem);
721 Loop(top, ( (void *) PrintMachInfo) );
726 /* Function Name: AddMachine
727 * Description: This function adds a new machine to the database.
728 * Arguments: argc, argv - the name of the machine in argv[1].
729 * Returns: DM_NORMAL.
734 AddMachine(argc, argv)
738 char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
741 if (!ValidName(argv[1])) /* Checks for wildcards. */
744 * Check to see if this machine already exists.
746 name = canonicalize_hostname(strsave(argv[1]));
749 xargs[1] = xargs[2] = xargs[3] = "*";
750 if ( (stat = do_mr_query("get_host", 4, xargs, NullFunc, NULL)) == 0) {
751 sprintf(buf, "The machine '%s' already exists.", name);
756 else if (stat != MR_NO_MATCH) {
757 com_err(program_name, stat,
758 " while checking machine '%s' in AddMachine.", name);
763 if ((args = AskMCDInfo(SetMachineDefaults(info, name), MACHINE, FALSE)) ==
765 Put_message("Aborted.");
770 * Actually create the new Machine.
773 if ( (stat = do_mr_query("add_host", CountArgs(args),
774 args, Scream, NULL)) != 0)
775 com_err(program_name, stat, " in AddMachine.");
782 /* Function Name: RealUpdateMachine
783 * Description: Performs the actual update of the machine data.
784 * Arguments: info - the information on the machine to update.
785 * junk - an UNUSED Boolean.
791 RealUpdateMachine(info, junk)
796 char ** args = AskMCDInfo(info, MACHINE, TRUE);
798 Put_message("Aborted.");
801 if ( (stat = do_mr_query("update_host", CountArgs(args),
802 args, Scream, NULL)) != 0)
803 com_err(program_name, stat, " in UpdateMachine.");
805 Put_message("Machine sucessfully updated.");
808 /* Function Name: UpdateMachine
809 * Description: This function adds a new machine to the database.
810 * Arguments: argc, argv - the name of the machine in argv[1].
811 * Returns: DM_NORMAL.
816 UpdateMachine(argc, argv)
823 tmpname = canonicalize_hostname(strsave(argv[1]));
824 top = GetMCInfo( MACHINE, tmpname, (char *) NULL);
825 QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
832 /* Function Name: CheckAndRemoveFromCluster
833 * Description: This func tests to see if a machine is in a cluster.
834 * and if so then removes it
835 * Arguments: name - name of the machine (already Canonocalized).
836 * ask_user- query the user before removing if from clusters?
837 * Returns: MR_ERROR if machine left in a cluster, or mr_error.
841 CheckAndRemoveFromCluster(name, ask_user)
845 register int stat, ret_value;
847 char *args[10], temp_buf[BUFSIZ], *ptr;
848 struct qelem *top, *elem = NULL;
850 ret_value = SUB_NORMAL; /* initialize ret_value. */
853 stat = do_mr_query("get_machine_to_cluster_map", 2, args,
854 StoreInfo, (char *)&elem);
855 if (stat && stat != MR_NO_MATCH) {
856 com_err(program_name, stat, " in get_machine_to_cluster_map.");
859 if (stat == MR_SUCCESS) {
860 elem = top = QueueTop(elem);
862 sprintf(temp_buf, "%s is assigned to the following clusters.",
864 Put_message(temp_buf);
865 Loop(top, (void *) PrintMCMap);
866 ptr = "Remove this machine from ** ALL ** these clusters?";
867 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
870 Put_message("Aborting...");
879 while (elem != NULL) {
880 char **info = (char **) elem->q_data;
881 if ( (stat = do_mr_query( "delete_machine_from_cluster",
882 2, info, Scream, NULL)) != 0) {
883 ret_value = SUB_ERROR;
884 com_err(program_name, stat,
885 " in delete_machine_from_cluster.");
887 "Machine %s ** NOT ** removed from cluster %s.",
888 info[MAP_MACHINE], info[MAP_CLUSTER]);
889 Put_message(temp_buf);
898 /* Function Name: RealDeleteMachine
899 * Description: Actually Deletes the Machine.
900 * Arguments: info - nescessary information stored as an array of char *'s
901 * one_machine - a boolean, true if there is only one item in
907 RealDeleteMachine(info, one_machine)
912 char temp_buf[BUFSIZ];
914 sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
916 if(!one_machine || Confirm(temp_buf)) {
917 if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR) {
918 if ( (stat = do_mr_query("delete_host", 1,
919 &info[M_NAME], Scream, NULL)) != 0) {
920 com_err(program_name, stat, " in DeleteMachine.");
921 sprintf(temp_buf, "%s ** NOT ** deleted.",
923 Put_message(temp_buf);
926 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
927 Put_message(temp_buf);
933 /* Function Name: DeleteMachine
934 * Description: This function removes a machine from the data base.
935 * Arguments: argc, argv - the machines name int argv[1].
936 * Returns: DM_NORMAL.
939 /* Perhaps we should remove the cluster if it has no machine now. */
943 DeleteMachine(argc, argv)
950 tmpname = canonicalize_hostname(strsave(argv[1]));
951 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
952 QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
959 char *partial_canonicalize_hostname(s)
963 static char *def_domain = NULL;
972 strncpy(buf, name.nodename, sizeof(buf));
974 gethostname(buf, sizeof(buf));
976 hp = gethostbyname(buf);
977 cp = strchr(hp->h_name, '.');
979 def_domain = strsave(++cp);
984 if (strchr(s, '.') || strchr(s, '*'))
986 sprintf(buf, "%s.%s", s, def_domain);
988 return(strsave(buf));
992 /* Function Name: ShowCname
993 * Description: This function shows machine aliases
994 * Arguments: argc, argv - the alias argv[1], the real name in argv[2]
995 * Returns: DM_NORMAL.
1000 ShowCname(argc, argv)
1005 char *tmpalias, *tmpname;
1007 tmpalias = partial_canonicalize_hostname(strsave(argv[1]));
1008 tmpname = canonicalize_hostname(strsave(argv[2]));
1009 top = GetMCInfo(CNAME, tmpalias, tmpname);
1010 Put_message(""); /* blank line on screen */
1011 Loop(top, ( (void *) PrintCname) );
1019 AddCname(argc, argv)
1024 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1025 Bool add_it, one_machine, one_cluster;
1026 struct qelem * melem, *mtop, *celem, *ctop;
1028 args[0] = partial_canonicalize_hostname(strsave(argv[1]));
1029 args[1] = canonicalize_hostname(strsave(argv[2]));
1030 stat = do_mr_query("add_hostalias", 2, args, Scream, NULL);
1035 Put_message("That alias name is already in use.");
1038 Put_message("Permission denied. (Regular users can only add two aliases to a host.");
1041 com_err(program_name, stat, " in add_hostalias");
1049 DeleteCname(argc, argv)
1054 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1055 Bool add_it, one_machine, one_cluster;
1056 struct qelem * melem, *mtop, *celem, *ctop;
1058 args[0] = partial_canonicalize_hostname(strsave(argv[1]));
1059 args[1] = canonicalize_hostname(strsave(argv[2]));
1060 stat = do_mr_query("delete_hostalias", 2, args, Scream, NULL);
1062 com_err(program_name, stat, " in delete_hostalias");
1067 /* Function Name: AddMachineToCluster
1068 * Description: This function adds a machine to a cluster
1069 * Arguments: argc, argv - The machine name is argv[1].
1070 * The cluster name in argv[2].
1071 * Returns: DM_NORMAL.
1076 AddMachineToCluster(argc, argv)
1081 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1082 Bool add_it, one_machine, one_cluster;
1083 struct qelem * melem, *mtop, *celem, *ctop;
1085 machine = canonicalize_hostname(strsave(argv[1]));
1086 if (strcasecmp(machine, argv[1]) && *argv[1] != '"') {
1087 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1089 Put_message(temp_buf);
1093 celem = ctop = GetMCInfo(CLUSTER, cluster, (char *) NULL);
1094 melem = mtop = GetMCInfo(MACHINE, machine, (char *) NULL);
1097 one_machine = (QueueCount(mtop) == 1);
1098 one_cluster = (QueueCount(ctop) == 1);
1100 /* No good way to use QueryLoop() here, sigh */
1102 while (melem != NULL) {
1103 char ** minfo = (char **) melem->q_data;
1104 while (celem != NULL) {
1105 char ** cinfo = (char **) celem->q_data;
1106 if (one_machine && one_cluster)
1109 sprintf(temp_buf,"Add machine %s to cluster %s (y/n/q) ?",
1110 minfo[M_NAME], cinfo[C_NAME]);
1111 switch (YesNoQuitQuestion(temp_buf, FALSE)) {
1119 Put_message("Aborting...");
1126 args[0] = minfo[M_NAME];
1127 args[1] = cinfo[C_NAME];
1128 stat = do_mr_query("add_machine_to_cluster", 2, args,
1134 sprintf(temp_buf, "%s is already in cluster %s",
1135 minfo[M_NAME], cinfo[C_NAME]);
1136 Put_message(temp_buf);
1139 com_err(program_name, stat, " in AddMachineToCluster.");
1143 celem = celem->q_forw;
1145 celem = ctop; /* reset cluster element. */
1146 melem = melem->q_forw;
1153 /* Function Name: RealRemoveMachineFromCluster
1154 * Description: This function actually removes the machine from its
1156 * Arguments: info - all information nescessary to perform the removal.
1157 * one_map - True if there is only one case, and we should
1163 RealRemoveMachineFromCluster(info, one_map)
1167 char temp_buf[BUFSIZ];
1170 sprintf(temp_buf, "Remove %s from the cluster %s",
1171 info[MAP_MACHINE], info[MAP_CLUSTER]);
1172 if (!one_map || Confirm(temp_buf)) {
1173 if ( (stat = do_mr_query("delete_machine_from_cluster", 2,
1174 info, Scream, NULL)) != 0 )
1175 com_err(program_name, stat, " in delete_machine_from_cluster");
1177 sprintf(temp_buf, "%s has been removed from the cluster %s.",
1178 info[MAP_MACHINE], info[MAP_CLUSTER]);
1179 Put_message(temp_buf);
1183 Put_message("Machine not removed.");
1186 /* Function Name: RemoveMachineFromCluster
1187 * Description: Removes this machine form a specific cluster.
1188 * Arguments: argc, argv - Name of machine in argv[1].
1189 * Name of cluster in argv[2].
1195 RemoveMachineFromCluster(argc, argv)
1199 struct qelem *elem = NULL;
1200 char buf[BUFSIZ], * args[10];
1203 args[MAP_MACHINE] = canonicalize_hostname(strsave(argv[1]));
1204 if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"') {
1205 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1206 argv[1], args[MAP_MACHINE]);
1209 args[MAP_CLUSTER] = argv[2];
1210 args[MAP_END] = NULL;
1212 stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1213 StoreInfo, (char *)&elem);
1214 if (stat == MR_NO_MATCH) {
1215 sprintf(buf, "The machine %s is not is the cluster %s.",
1216 args[MAP_MACHINE], args[MAP_CLUSTER]);
1218 free(args[MAP_MACHINE]);
1221 if (stat != MR_SUCCESS)
1222 com_err(program_name, stat, " in delete_machine_from_cluster");
1224 elem = QueueTop(elem);
1225 QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1226 "Remove this machine from this cluster");
1229 free(args[MAP_MACHINE]);
1233 /* ---------- Subnet Menu -------- */
1235 /* Function Name: ShowSubnetInfo
1236 * Description: Gets information about a subnet given its name.
1237 * Arguments: argc, argc - the name of the subnet in in argv[1].
1238 * Returns: DM_NORMAL.
1243 ShowSubnetInfo(argc, argv)
1249 top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1250 Loop(top, (void *) PrintSubnetInfo);
1255 /* Function Name: AddSubnet
1256 * Description: Creates a new subnet.
1257 * Arguments: argc, argv - the name of the new subnet is argv[1].
1258 * Returns: DM_NORMAL.
1263 AddSubnet(argc, argv)
1267 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1270 * Check to see if this subnet already exists.
1272 if (!ValidName(name))
1275 if ( (stat = do_mr_query("get_subnet", 1, &name,
1276 NullFunc, NULL)) == MR_SUCCESS) {
1277 Put_message("This subnet already exists.");
1280 else if (stat != MR_NO_MATCH) {
1281 com_err(program_name, stat, " in AddSubnet.");
1284 if ((args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)) ==
1286 Put_message("Aborted.");
1292 * Actually create the new Subnet.
1294 if ( (stat = do_mr_query("add_subnet", CountArgs(args),
1295 args, Scream, NULL)) != 0)
1296 com_err(program_name, stat, " in AddSubnet.");
1302 /* Function Name: RealUpdateSubnet
1303 * Description: This function actually performs the subnet update.
1304 * Arguments: info - all information nesc. for updating the subnet.
1305 * junk - an UNUSED boolean.
1311 RealUpdateSubnet(info, junk)
1316 char ** args = AskMCDInfo(info, SUBNET, TRUE);
1318 Put_message("Aborted.");
1321 if ( (stat = do_mr_query("update_subnet", CountArgs(args),
1322 args, Scream, NULL)) != 0)
1323 com_err(program_name, stat, " in UpdateSubnet.");
1325 Put_message("Subnet successfully updated.");
1328 /* Function Name: UpdateSubnet
1329 * Description: This Function Updates a subnet
1330 * Arguments: name of the subnet in argv[1].
1331 * Returns: DM_NORMAL.
1336 UpdateSubnet(argc, argv)
1341 top = GetMCInfo( SUBNET, argv[1], (char *) NULL );
1342 QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1348 /* Function Name: RealDeleteSubnet
1349 * Description: Actually performs the subnet deletion.
1350 * Arguments: info - all information about this subnet.
1351 * one_subnet - If true then there was only one subnet in
1352 * the queue, and we should confirm.
1357 RealDeleteSubnet(info, one_subnet)
1362 char temp_buf[BUFSIZ];
1365 "Are you sure the you want to delete the subnet %s (y/n) ?",
1367 if (!one_subnet || Confirm(temp_buf)) {
1368 if ( (stat = do_mr_query("delete_subnet", 1,
1369 &info[C_NAME], Scream, NULL)) != 0) {
1370 com_err(program_name, stat, " in delete_subnet.");
1371 sprintf(temp_buf, "Subnet %s ** NOT ** deleted.",
1373 Put_message(temp_buf);
1376 sprintf(temp_buf, "subnet %s sucesfully deleted.",
1378 Put_message(temp_buf);
1383 /* Function Name: DeleteSubnet
1384 * Description: This function removes a subnet from the database.
1385 * Arguments: argc, argv - the name of the subnet is stored in argv[1].
1386 * Returns: DM_NORMAL.
1391 DeleteSubnet(argc, argv)
1397 top = GetMCInfo( SUBNET, argv[1], (char *) NULL );
1398 QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1404 /* ---------- Cluster Menu -------- */
1406 /* Function Name: ShowClusterInfo
1407 * Description: Gets information about a cluser given its name.
1408 * Arguments: argc, argc - the name of the cluster in in argv[1].
1409 * Returns: DM_NORMAL.
1414 ShowClusterInfo(argc, argv)
1420 top = GetMCInfo(CLUSTER, argv[1], (char *) NULL);
1421 Loop(top, (void *) PrintClusterInfo);
1426 /* Function Name: AddCluster
1427 * Description: Creates a new cluster.
1428 * Arguments: argc, argv - the name of the new cluster is argv[1].
1429 * Returns: DM_NORMAL.
1434 AddCluster(argc, argv)
1438 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1441 * Check to see if this cluster already exists.
1443 if (!ValidName(name))
1446 if ( (stat = do_mr_query("get_cluster", 1, &name,
1447 NullFunc, NULL)) == MR_SUCCESS) {
1448 Put_message("This cluster already exists.");
1451 else if (stat != MR_NO_MATCH) {
1452 com_err(program_name, stat, " in AddCluster.");
1455 if ((args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)) ==
1457 Put_message("Aborted.");
1463 * Actually create the new Cluster.
1465 if ( (stat = do_mr_query("add_cluster", CountArgs(args),
1466 args, Scream, NULL)) != 0)
1467 com_err(program_name, stat, " in AddCluster.");
1473 /* Function Name: RealUpdateCluster
1474 * Description: This function actually performs the cluster update.
1475 * Arguments: info - all information nesc. for updating the cluster.
1476 * junk - an UNUSED boolean.
1482 RealUpdateCluster(info, junk)
1487 char ** args = AskMCDInfo(info, CLUSTER, TRUE);
1489 Put_message("Aborted.");
1492 if ( (stat = do_mr_query("update_cluster", CountArgs(args),
1493 args, Scream, NULL)) != 0)
1494 com_err(program_name, stat, " in UpdateCluster.");
1496 Put_message("Cluster successfully updated.");
1499 /* Function Name: UpdateCluster
1500 * Description: This Function Updates a cluster
1501 * Arguments: name of the cluster in argv[1].
1502 * Returns: DM_NORMAL.
1507 UpdateCluster(argc, argv)
1512 top = GetMCInfo( CLUSTER, argv[1], (char *) NULL );
1513 QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1519 /* Function Name: CheckAndRemoveMachine
1520 * Description: This function checks and removes all machines from a
1522 * Arguments: name - name of the cluster.
1523 * ask_first - if TRUE, then we will query the user, before
1525 * Returns: SUB_ERROR if all machines not removed.
1529 CheckAndRemoveMachines(name, ask_first)
1533 register int stat, ret_value;
1535 char *args[10], temp_buf[BUFSIZ], *ptr;
1536 struct qelem *top, *elem = NULL;
1538 ret_value = SUB_NORMAL;
1539 args[MAP_MACHINE] = "*";
1540 args[MAP_CLUSTER] = name;
1541 stat = do_mr_query("get_machine_to_cluster_map", 2, args,
1542 StoreInfo, (char *)&elem);
1543 if (stat && stat != MR_NO_MATCH) {
1544 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1548 elem = top = QueueTop(elem);
1551 "The cluster %s has the following machines in it:",
1553 Put_message(temp_buf);
1554 while (elem != NULL) {
1555 char **info = (char **) elem->q_data;
1556 Print(1, &info[MAP_MACHINE], (char *) NULL);
1557 elem = elem->q_forw;
1559 ptr = "Remove ** ALL ** these machines from this cluster?";
1561 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1564 Put_message("Aborting...");
1575 char **info = (char **) elem->q_data;
1576 if ( (stat = do_mr_query("delete_machine_from_cluster",
1577 2, info, Scream, NULL)) != 0) {
1578 ret_value = SUB_ERROR;
1579 com_err(program_name, stat,
1580 " in delete_machine_from_cluster.");
1582 "Machine %s ** NOT ** removed from cluster %s.",
1583 info[MAP_MACHINE], info[MAP_CLUSTER]);
1584 Put_message(temp_buf);
1586 elem = elem->q_forw;
1593 /* Function Name: RealDeleteCluster
1594 * Description: Actually performs the cluster deletion.
1595 * Arguments: info - all information about this cluster.
1596 * one_cluster - If true then there was only one cluster in
1597 * the queue, and we should confirm.
1602 RealDeleteCluster(info, one_cluster)
1607 char temp_buf[BUFSIZ];
1610 "Are you sure the you want to delete the cluster %s (y/n) ?",
1612 if (!one_cluster || Confirm(temp_buf)) {
1613 if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR) {
1614 if ( (stat = do_mr_query("delete_cluster", 1,
1615 &info[C_NAME], Scream, NULL)) != 0) {
1616 com_err(program_name, stat, " in delete_cluster.");
1617 sprintf(temp_buf, "Cluster %s ** NOT ** deleted.",
1619 Put_message(temp_buf);
1622 sprintf(temp_buf, "cluster %s sucesfully deleted.",
1624 Put_message(temp_buf);
1630 /* Function Name: DeleteCluster
1631 * Description: This function removes a cluster from the database.
1632 * Arguments: argc, argv - the name of the cluster is stored in argv[1].
1633 * Returns: DM_NORMAL.
1638 DeleteCluster(argc, argv)
1644 top = GetMCInfo( CLUSTER, argv[1], (char *) NULL );
1645 QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1651 /* ----------- Cluster Data Menu -------------- */
1653 /* Function Name: ShowClusterData
1654 * Description: This function shows the services for one cluster.
1655 * Arguments: argc, argv - The name of the cluster is argv[1].
1656 * The label of the data in argv[2].
1657 * Returns: DM_NORMAL.
1662 ShowClusterData(argc, argv)
1666 struct qelem *elem, *top;
1669 top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1670 while (elem != NULL) {
1671 info = (char **) elem->q_data;
1672 PrintClusterData(info);
1673 elem = elem->q_forw;
1679 /* Function Name: AddClusterData
1680 * Description: This function adds some data to the cluster.
1681 * Arguments: argv, argc: argv[1] - the name of the cluster.
1682 * argv[2] - the label of the data.
1683 * argv[3] - the data.
1684 * Returns: DM_NORMAL.
1689 AddClusterData(argc, argv)
1695 if( (stat = do_mr_query("add_cluster_data", 3, argv + 1,
1696 Scream, (char *) NULL)) != 0)
1697 com_err(program_name, stat, " in AddClusterData.");
1701 /* Function Name: RealRemoveClusterData
1702 * Description: actually removes the cluster data.
1703 * Arguments: info - all info necessary to remove the cluster, in an array
1705 * one_item - if true then the queue has only one elem and we
1711 RealRemoveClusterData(info, one_item)
1719 temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1720 PrintClusterData(info);
1721 if (!one_item || Confirm(temp_ptr)) {
1722 if( (stat = do_mr_query("delete_cluster_data", 3, info,
1723 Scream, (char *) NULL)) != 0) {
1724 com_err(program_name, stat, " in DeleteClusterData.");
1725 Put_message("Data not removed.");
1728 Put_message("Removal sucessful.");
1732 /* Function Name: RemoveClusterData
1733 * Description: This function removes data on a given cluster.
1734 * Arguments: argv, argc: argv[1] - the name of the cluster.
1735 * argv[2] - the label of the data.
1736 * argv[3] - the data.
1737 * Returns: DM_NORMAL.
1742 RemoveClusterData(argc, argv)
1748 top = GetMCInfo(DATA, argv[1], argv[2]);
1749 QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1750 "Remove data from cluster");
1756 /* Function Name: MachineToClusterMap
1757 * Description: This Retrieves the mapping between machine and cluster
1758 * Arguments: argc, argv - argv[1] -> machine name or wildcard.
1759 * argv[2] -> cluster name or wildcard.
1765 MachineToClusterMap(argc,argv)
1769 struct qelem *elem, *top;
1770 char *tmpname, temp_buf[256];
1772 tmpname = canonicalize_hostname(strsave(argv[1]));
1773 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"') {
1774 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1776 Put_message(temp_buf);
1778 top = elem = GetMCInfo(MAP, tmpname, argv[2]);
1780 Put_message(""); /* blank line on screen */
1781 while (elem != NULL) {
1782 char ** info = (char **) elem->q_data;
1784 elem = elem->q_forw;