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.10"
60 #define S_DEFAULT_HIGH "18.0.2.252"
62 static char *states[] = { "Reserved (0)",
67 static char *MacState(state)
72 if (state < 0 || state > 3) {
73 sprintf(buf, "Unknown (%d)", state);
76 return(states[state]);
81 /* -------------------- Set Defaults -------------------- */
83 /* Function Name: SetMachineDefaults
84 * Description: sets machine defaults.
85 * Arguments: info - an array to put the defaults into.
86 * name - Canonacalized name of the machine.
87 * Returns: info - the array.
91 SetMachineDefaults(info, name)
94 info[M_NAME] = Strsave(name);
95 info[M_VENDOR] = Strsave(M_DEFAULT_TYPE);
96 info[M_MODEL] = Strsave(M_DEFAULT_TYPE);
97 info[M_OS] = Strsave(M_DEFAULT_TYPE);
98 info[M_LOC] = Strsave(M_DEFAULT_TYPE);
99 info[M_CONTACT] = Strsave(M_DEFAULT_TYPE);
100 info[M_USE] = Strsave("0");
101 info[M_STAT] = Strsave("1");
102 info[8] = Strsave("NONE");
103 info[9] = Strsave("unique");
104 info[10] = Strsave("NONE");
105 info[11] = Strsave("NONE");
106 info[12] = Strsave("");
107 info[13] = Strsave("");
108 info[14] = info[15] = info[16] = NULL;
112 /* Function Name: SetClusterDefaults
113 * Description: sets Cluster defaults.
114 * Arguments: info - an array to put the defaults into.
115 * name - name of the Cluster.
116 * Returns: info - the array.
120 SetClusterDefaults(info, name)
123 info[C_NAME] = Strsave(name);
124 info[C_DESCRIPT] = Strsave(C_DEFAULT_DESCRIPT);
125 info[C_LOCATION] = Strsave(C_DEFAULT_LOCATION);
126 info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
130 /* Function Name: SetSubnetDefaults
131 * Description: sets Subnet defaults.
132 * Arguments: info - an array to put the defaults into.
133 * name - name of the Subnet.
134 * Returns: info - the array.
138 SetSubnetDefaults(info, name)
143 info[C_NAME] = Strsave(name);
144 info[SN_DESC] = Strsave("");
145 sprintf(buf, "%d", ntohl(inet_addr("18.255.0.0")));
146 info[SN_ADDRESS] = Strsave(buf);
147 sprintf(buf, "%d", ntohl(inet_addr("255.255.0.0")));
148 info[SN_MASK] = Strsave(buf);
149 sprintf(buf, "%d", ntohl(inet_addr(S_DEFAULT_LOW)));
150 info[SN_LOW] = Strsave(buf);
151 sprintf(buf, "%d", ntohl(inet_addr(S_DEFAULT_HIGH)));
152 info[SN_HIGH] = Strsave(buf);
153 info[SN_PREFIX] = Strsave("");
154 info[SN_ACE_TYPE] = Strsave("LIST");
155 info[SN_ACE_NAME] = Strsave("network_acl");
156 info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
160 /* -------------------- General Functions -------------------- */
162 static char aliasbuf[256];
168 if (strlen(aliasbuf) == 0)
169 sprintf(aliasbuf, "Aliases: %s", info[0]);
171 strcat(aliasbuf, ", ");
172 strcat(aliasbuf, info[0]);
177 /* Function Name: PrintMachInfo
178 * Description: This function Prints out the Machine info in
180 * Arguments: info - array of information about a machine.
181 * Returns: The name of the Machine
188 char buf[BUFSIZ], tbuf[256];
190 struct qelem *elem = NULL;
194 sprintf(buf, "Machine: %s", info[M_NAME]);
197 args[1] = info[M_NAME];
198 if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, (char *)&elem))
200 if (stat != MR_NO_MATCH)
201 com_err(program_name, stat, " looking up aliases");
204 Loop(QueueTop(elem), (void *) PrintAliases);
206 Put_message(aliasbuf);
208 sprintf(buf, "Address: %-16s Subnet: %s",
209 info[M_ADDR], info[M_SUBNET]);
211 sprintf(buf, "Status: %-16s Changed: %s",
212 MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
214 sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
215 strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
216 sprintf(buf, "Owner: %-16s Last poll: %s", tbuf, info[M_INUSE]);
220 sprintf(buf, "Vendor: %-16s Model: %-24s OS: %s",
221 info[M_VENDOR], info[M_MODEL], info[M_OS]);
223 sprintf(buf, "Location: %-16s Contact: %s Use code: %s",
224 info[M_LOC], info[M_CONTACT], info[M_USE]);
226 sprintf(buf, "Admn cmt: %s", info[M_ACOMMENT]);
228 sprintf(buf, "Op cmt: %s", info[M_OCOMMENT]);
231 sprintf(buf, "Created by %s on %s", info[M_CREATOR], info[M_CREATED]);
233 sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
235 return(info[M_NAME]);
238 /* Function Name: PrintCname
239 * Description: Prints the Data on a host alias
240 * Arguments: info a pointer to the data array.
241 * Returns: The name of the alias.
250 sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
255 /* Function Name: PrintClusterInfo
256 * Description: This function Prints out the cluster info
257 * in a coherent form.
258 * Arguments: info - array of information about a cluster.
259 * Returns: The name of the cluster.
263 PrintClusterInfo(info)
269 sprintf(buf, "Cluster: %s", info[C_NAME]);
271 sprintf(buf, "Description: %s", info[C_DESCRIPT]);
273 sprintf(buf, "Location: %s", info[C_LOCATION]);
275 sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
277 return(info[C_NAME]);
280 /* Function Name: PrintClusterData
281 * Description: Prints the Data on a cluster
282 * Arguments: info a pointer to the data array.
283 * Returns: The name of the cluster.
287 PrintClusterData(info)
293 sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
294 info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
296 return(info[CD_NAME]);
299 /* Function Name: PrintMCMap
300 * Description: Prints the data about a machine to cluster mapping.
301 * Arguments: info a pointer to the data array.
310 sprintf(buf, "Cluster: %-30s Machine: %-20s",
311 info[MAP_CLUSTER], info[MAP_MACHINE]);
313 return(""); /* Used by QueryLoop(). */
316 /* Function Name: PrintSubnetInfo
317 * Description: This function Prints out the subnet info
318 * in a coherent form.
319 * Arguments: info - array of information about a subnet.
320 * Returns: The name of the subnet.
324 PrintSubnetInfo(info)
328 struct in_addr addr, mask, low, high;
331 sprintf(buf, "Subnet: %s", info[SN_NAME]);
333 sprintf(buf, "Description: %s", info[SN_DESC]);
335 addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
336 mask.s_addr = htonl(atoi(info[SN_MASK]));
337 low.s_addr = htonl(atoi(info[SN_LOW]));
338 high.s_addr = htonl(atoi(info[SN_HIGH]));
339 /* screwy sequence is here because inet_ntoa returns a pointer to
340 a static buf. If it were all one sprintf, the last value would
342 sprintf(buf, "Address %s, Mask ", inet_ntoa(addr));
343 strcat(buf, inet_ntoa(mask));
344 strcat(buf, ", High ");
345 strcat(buf, inet_ntoa(high));
346 strcat(buf, ", Low ");
347 strcat(buf, inet_ntoa(low));
349 sprintf(buf, "Hostname prefix: %s", info[SN_PREFIX]);
351 sprintf(buf, "Owner: %s %s", info[SN_ACE_TYPE],
352 strcmp(info[SN_ACE_TYPE],"NONE") ? info[SN_ACE_NAME] : "");
354 sprintf(buf,MOD_FORMAT,info[SN_MODBY],info[SN_MODTIME],info[SN_MODWITH]);
356 return(info[SN_NAME]);
359 /* Function Name: GetMCInfo.
360 * Description: This function stores info about a machine.
361 * type - type of data we are trying to retrieve.
362 * name1 - the name of argv[0] for the call.
363 * name2 - the name of argv[1] for the call.
364 * Returns: the top element of a queue containing the data or NULL.
368 GetMCInfo(type, name1, name2)
370 char * name1, *name2;
374 struct qelem * elem = NULL;
380 args[1] = args[2] = args[3] = "*";
381 if ( (stat = do_mr_query("get_host", 4, args,
382 StoreInfo, (char *)&elem)) != 0) {
383 if (stat == MR_NO_MATCH) {
385 sprintf(buf, "Machine '%s' is not in the database.", name1);
388 com_err(program_name, stat, " in get_machine.");
395 if ( (stat = do_mr_query("get_hostalias", 2, args,
396 StoreInfo, (char *)&elem)) != 0) {
397 com_err(program_name, stat, " in get_hostalias.");
402 if ( (stat = do_mr_query("get_subnet", 1, &name1,
403 StoreInfo, (char *)&elem)) != 0) {
404 if (stat == MR_NO_MATCH) {
406 sprintf(buf, "Subnet '%s' is not in the database.", name1);
409 com_err(program_name, stat, " in get_subnet.");
414 if ( (stat = do_mr_query("get_cluster", 1, &name1,
415 StoreInfo, (char *)&elem)) != 0) {
416 com_err(program_name, stat, " in get_cluster.");
421 args[MAP_MACHINE] = name1;
422 args[MAP_CLUSTER] = name2;
423 if ( (stat = do_mr_query("get_machine_to_cluster_map", 2, args,
424 StoreInfo, (char *)&elem)) != 0) {
425 com_err(program_name, stat, " in get_machine_to_cluster_map.");
430 args[CD_NAME] = name1;
431 args[CD_LABEL] = name2;
432 if ( (stat = do_mr_query("get_cluster_data", 2, args,
433 StoreInfo, (char *)&elem)) != 0) {
434 com_err(program_name, stat, " in get_cluster_data.");
438 return(QueueTop(elem));
441 /* Function Name: AskMCDInfo.
442 * Description: This function askes the user for information about a
443 * machine and saves it into a structure.
444 * Arguments: info - a pointer the information to ask about
445 * type - type of information - MACHINE
448 * name - T/F : change the name of this type.
453 AskMCDInfo(info, type, name)
458 char temp_buf[BUFSIZ], *newname, *oldnewname;
462 sprintf(temp_buf, "Setting the information for the Machine %s.",
466 sprintf(temp_buf, "Setting the information for the Subnet %s.",
470 sprintf(temp_buf, "Setting the information for the Cluster %s.",
474 sprintf(temp_buf, "Setting the Data for the Cluster %s.",
478 Put_message(temp_buf);
483 newname = Strsave(info[M_NAME]);
484 if (GetValueFromUser("The new name for this machine? ", &newname) ==
487 oldnewname = Strsave(newname);
488 newname = canonicalize_hostname(newname);
489 if (strcasecmp(newname, oldnewname) && *oldnewname != '"') {
490 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
491 oldnewname, newname);
492 Put_message(temp_buf);
497 newname = Strsave(info[SN_NAME]);
498 if (GetValueFromUser("The new name for this subnet? ",
499 &newname) == SUB_ERROR)
503 newname = Strsave(info[C_NAME]);
504 if (GetValueFromUser("The new name for this cluster? ",
505 &newname) == SUB_ERROR)
509 Put_message("Unknown type in AskMCDInfo, programmer botch");
516 if (GetValueFromUser("Machine's Vendor", &info[M_VENDOR]) == SUB_ERROR)
518 if (GetValueFromUser("Machine's Model", &info[M_MODEL]) == SUB_ERROR)
520 if (GetValueFromUser("Machine's Operating System", &info[M_OS]) ==
523 if (GetValueFromUser("Location of Machine", &info[M_LOC]) == SUB_ERROR)
525 if (GetValueFromUser("Contact for Machine", &info[M_CONTACT]) ==
528 if (GetValueFromUser("Machine's Use Code", &info[M_USE]) == SUB_ERROR)
532 if (GetValueFromUser("Machine's Status (? for help)",
533 &info[M_STAT]) == SUB_ERROR)
535 if (isdigit(info[M_STAT][0])) break;
536 Put_message("Valid status numbers:");
537 for (i = 0; i < 4; i++) Put_message(states[i]);
541 info[8] = info[M_SUBNET];
542 info[9] = info[M_ADDR];
543 info[10] = info[M_OWNER_TYPE];
544 info[11] = info[M_OWNER_NAME];
545 info[12] = info[M_ACOMMENT];
546 info[13] = info[M_OCOMMENT];
548 if (GetValueFromUser("Machine's subnet (or 'none')", &info[8])
551 if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
552 &info[9]) == SUB_ERROR)
554 if (GetTypeFromUser("Machine's Owner Type", "ace_type", &info[10]) ==
557 if (strcmp(info[10], "NONE") &&
558 GetValueFromUser("Owner's Name", &info[11]) == SUB_ERROR)
560 if (GetValueFromUser("Administrative Comment", &info[12]) == SUB_ERROR)
562 if (GetValueFromUser("Operational Comment", &info[13]) == SUB_ERROR)
565 FreeAndClear(&info[15], TRUE);
566 FreeAndClear(&info[16], TRUE);
569 if (GetValueFromUser("Subnet Description", &info[SN_DESC]) == SUB_ERROR)
571 if (GetAddressFromUser("Subnet Address", &info[SN_ADDRESS]) == SUB_ERROR)
573 if (GetAddressFromUser("Subnet Mask", &info[SN_MASK]) == SUB_ERROR)
575 if (atoi(info[SN_LOW]) == ntohl(inet_addr(S_DEFAULT_LOW))) {
577 unsigned long mask, addr;
579 addr = atoi(info[SN_ADDRESS]);
580 mask = atoi(info[SN_MASK]);
581 low.s_addr = atoi(info[SN_LOW]);
582 low.s_addr = (low.s_addr & ~mask) | (addr & mask);
584 sprintf(temp_buf, "%d", low.s_addr);
585 info[SN_LOW] = strsave(temp_buf);
587 if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) == SUB_ERROR)
589 if (atoi(info[SN_HIGH]) == ntohl(inet_addr(S_DEFAULT_HIGH))) {
591 unsigned long mask, addr;
593 addr = atoi(info[SN_ADDRESS]);
594 mask = atoi(info[SN_MASK]);
595 high.s_addr = atoi(info[SN_HIGH]);
596 high.s_addr = (high.s_addr & ~mask) | (addr & mask);
598 sprintf(temp_buf, "%d", high.s_addr);
599 info[SN_HIGH] = strsave(temp_buf);
601 if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) == SUB_ERROR)
603 if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
605 if (GetTypeFromUser("Owner Type", "ace_type", &info[SN_ACE_TYPE]) == SUB_ERROR)
607 if (strcmp(info[SN_ACE_TYPE], "NONE") &&
608 GetValueFromUser("Owner Name", &info[SN_ACE_NAME]) == SUB_ERROR)
610 FreeAndClear(&info[SN_MODTIME], TRUE);
611 FreeAndClear(&info[SN_MODBY], TRUE);
612 FreeAndClear(&info[SN_MODWITH], TRUE);
615 if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
618 if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
621 FreeAndClear(&info[C_MODTIME], TRUE);
622 FreeAndClear(&info[C_MODBY], TRUE);
623 FreeAndClear(&info[C_MODWITH], TRUE);
626 if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
629 if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
635 * Slide the newname into the #2 slot, this screws up all future references
639 SlipInNewName(info, newname);
644 /* ----------- Machine Menu ----------- */
646 /* Function Name: ShowMachineInfo
647 * Description: This function shows the information about a machine.
648 * Arguments: argc, argv - the name of the machine in argv[1].
649 * Returns: DM_NORMAL.
654 ShowMachineInfo(argc, argv)
661 tmpname = canonicalize_hostname(strsave(argv[1]));
662 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
663 Loop(top, ( (void *) PrintMachInfo) );
668 /* Function Name: ShowMachineQuery
669 * Description: This function shows the information about a machine.
670 * or group of machines, which may be selected through a
671 * number of criteria.
672 * Arguments: argc, argv - the name of the machine in argv[1],
673 * the address of the machine in argv[2],
674 * the location of the machine in argv[3],
675 * and the contact name in argv[4].
676 * any of these may be wildcards.
677 * Returns: DM_NORMAL.
682 ShowMachineQuery(argc, argv)
687 struct qelem *top, *elem = NULL;
690 if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
691 !strcmp(argv[3], "") && !strcmp(argv[4], "")) {
692 Put_message("You must specify at least one parameter of the query.");
697 args[0] = canonicalize_hostname(strsave(argv[1]));
713 if ((stat = do_mr_query("get_host", 4, args, StoreInfo,
714 (char *)&elem)) != 0) {
715 if (stat == MR_NO_MATCH)
716 Put_message("No machine(s) found matching query in the database.");
718 com_err(program_name, stat, " in get_machine.");
721 top = QueueTop(elem);
722 Loop(top, ( (void *) PrintMachInfo) );
727 /* Function Name: AddMachine
728 * Description: This function adds a new machine to the database.
729 * Arguments: argc, argv - the name of the machine in argv[1].
730 * Returns: DM_NORMAL.
735 AddMachine(argc, argv)
739 char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
742 if (!ValidName(argv[1])) /* Checks for wildcards. */
745 * Check to see if this machine already exists.
747 name = canonicalize_hostname(strsave(argv[1]));
750 xargs[1] = xargs[2] = xargs[3] = "*";
751 if ( (stat = do_mr_query("get_host", 4, xargs, NullFunc, NULL)) == 0) {
752 sprintf(buf, "The machine '%s' already exists.", name);
757 else if (stat != MR_NO_MATCH) {
758 com_err(program_name, stat,
759 " while checking machine '%s' in AddMachine.", name);
764 if ((args = AskMCDInfo(SetMachineDefaults(info, name), MACHINE, FALSE)) ==
766 Put_message("Aborted.");
771 * Actually create the new Machine.
774 if ( (stat = do_mr_query("add_host", CountArgs(args),
775 args, Scream, NULL)) != 0)
776 com_err(program_name, stat, " in AddMachine.");
783 /* Function Name: RealUpdateMachine
784 * Description: Performs the actual update of the machine data.
785 * Arguments: info - the information on the machine to update.
786 * junk - an UNUSED Boolean.
792 RealUpdateMachine(info, junk)
797 char ** args = AskMCDInfo(info, MACHINE, TRUE);
799 Put_message("Aborted.");
802 if ( (stat = do_mr_query("update_host", CountArgs(args),
803 args, Scream, NULL)) != 0)
804 com_err(program_name, stat, " in UpdateMachine.");
806 Put_message("Machine sucessfully updated.");
809 /* Function Name: UpdateMachine
810 * Description: This function adds a new machine to the database.
811 * Arguments: argc, argv - the name of the machine in argv[1].
812 * Returns: DM_NORMAL.
817 UpdateMachine(argc, argv)
824 tmpname = canonicalize_hostname(strsave(argv[1]));
825 top = GetMCInfo( MACHINE, tmpname, (char *) NULL);
826 QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
833 /* Function Name: CheckAndRemoveFromCluster
834 * Description: This func tests to see if a machine is in a cluster.
835 * and if so then removes it
836 * Arguments: name - name of the machine (already Canonocalized).
837 * ask_user- query the user before removing if from clusters?
838 * Returns: MR_ERROR if machine left in a cluster, or mr_error.
842 CheckAndRemoveFromCluster(name, ask_user)
846 register int stat, ret_value;
848 char *args[10], temp_buf[BUFSIZ], *ptr;
849 struct qelem *top, *elem = NULL;
851 ret_value = SUB_NORMAL; /* initialize ret_value. */
854 stat = do_mr_query("get_machine_to_cluster_map", 2, args,
855 StoreInfo, (char *)&elem);
856 if (stat && stat != MR_NO_MATCH) {
857 com_err(program_name, stat, " in get_machine_to_cluster_map.");
860 if (stat == MR_SUCCESS) {
861 elem = top = QueueTop(elem);
863 sprintf(temp_buf, "%s is assigned to the following clusters.",
865 Put_message(temp_buf);
866 Loop(top, (void *) PrintMCMap);
867 ptr = "Remove this machine from ** ALL ** these clusters?";
868 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
871 Put_message("Aborting...");
880 while (elem != NULL) {
881 char **info = (char **) elem->q_data;
882 if ( (stat = do_mr_query( "delete_machine_from_cluster",
883 2, info, Scream, NULL)) != 0) {
884 ret_value = SUB_ERROR;
885 com_err(program_name, stat,
886 " in delete_machine_from_cluster.");
888 "Machine %s ** NOT ** removed from cluster %s.",
889 info[MAP_MACHINE], info[MAP_CLUSTER]);
890 Put_message(temp_buf);
899 /* Function Name: RealDeleteMachine
900 * Description: Actually Deletes the Machine.
901 * Arguments: info - nescessary information stored as an array of char *'s
902 * one_machine - a boolean, true if there is only one item in
908 RealDeleteMachine(info, one_machine)
913 char temp_buf[BUFSIZ];
915 sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
917 if(!one_machine || Confirm(temp_buf)) {
918 if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR) {
919 if ( (stat = do_mr_query("delete_host", 1,
920 &info[M_NAME], Scream, NULL)) != 0) {
921 com_err(program_name, stat, " in DeleteMachine.");
922 sprintf(temp_buf, "%s ** NOT ** deleted.",
924 Put_message(temp_buf);
927 sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
928 Put_message(temp_buf);
934 /* Function Name: DeleteMachine
935 * Description: This function removes a machine from the data base.
936 * Arguments: argc, argv - the machines name int argv[1].
937 * Returns: DM_NORMAL.
940 /* Perhaps we should remove the cluster if it has no machine now. */
944 DeleteMachine(argc, argv)
951 tmpname = canonicalize_hostname(strsave(argv[1]));
952 top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
953 QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
960 char *partial_canonicalize_hostname(s)
964 static char *def_domain = NULL;
973 strncpy(buf, name.nodename, sizeof(buf));
975 gethostname(buf, sizeof(buf));
977 hp = gethostbyname(buf);
978 cp = strchr(hp->h_name, '.');
980 def_domain = strsave(++cp);
985 if (strchr(s, '.') || strchr(s, '*'))
987 sprintf(buf, "%s.%s", s, def_domain);
989 return(strsave(buf));
993 /* Function Name: ShowCname
994 * Description: This function shows machine aliases
995 * Arguments: argc, argv - the alias argv[1], the real name in argv[2]
996 * Returns: DM_NORMAL.
1001 ShowCname(argc, argv)
1006 char *tmpalias, *tmpname;
1008 tmpalias = partial_canonicalize_hostname(strsave(argv[1]));
1009 tmpname = canonicalize_hostname(strsave(argv[2]));
1010 top = GetMCInfo(CNAME, tmpalias, tmpname);
1011 Put_message(""); /* blank line on screen */
1012 Loop(top, ( (void *) PrintCname) );
1020 AddCname(argc, argv)
1025 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1026 Bool add_it, one_machine, one_cluster;
1027 struct qelem * melem, *mtop, *celem, *ctop;
1029 args[0] = partial_canonicalize_hostname(strsave(argv[1]));
1030 args[1] = canonicalize_hostname(strsave(argv[2]));
1031 stat = do_mr_query("add_hostalias", 2, args, Scream, NULL);
1036 Put_message("That alias name is already in use.");
1039 Put_message("Permission denied. (Regular users can only add two aliases to a host.");
1042 com_err(program_name, stat, " in add_hostalias");
1050 DeleteCname(argc, argv)
1055 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1056 Bool add_it, one_machine, one_cluster;
1057 struct qelem * melem, *mtop, *celem, *ctop;
1059 args[0] = partial_canonicalize_hostname(strsave(argv[1]));
1060 args[1] = canonicalize_hostname(strsave(argv[2]));
1061 stat = do_mr_query("delete_hostalias", 2, args, Scream, NULL);
1063 com_err(program_name, stat, " in delete_hostalias");
1068 /* Function Name: AddMachineToCluster
1069 * Description: This function adds a machine to a cluster
1070 * Arguments: argc, argv - The machine name is argv[1].
1071 * The cluster name in argv[2].
1072 * Returns: DM_NORMAL.
1077 AddMachineToCluster(argc, argv)
1082 char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1083 Bool add_it, one_machine, one_cluster;
1084 struct qelem * melem, *mtop, *celem, *ctop;
1086 machine = canonicalize_hostname(strsave(argv[1]));
1087 if (strcasecmp(machine, argv[1]) && *argv[1] != '"') {
1088 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1090 Put_message(temp_buf);
1094 celem = ctop = GetMCInfo(CLUSTER, cluster, (char *) NULL);
1095 melem = mtop = GetMCInfo(MACHINE, machine, (char *) NULL);
1098 one_machine = (QueueCount(mtop) == 1);
1099 one_cluster = (QueueCount(ctop) == 1);
1101 /* No good way to use QueryLoop() here, sigh */
1103 while (melem != NULL) {
1104 char ** minfo = (char **) melem->q_data;
1105 while (celem != NULL) {
1106 char ** cinfo = (char **) celem->q_data;
1107 if (one_machine && one_cluster)
1110 sprintf(temp_buf,"Add machine %s to cluster %s (y/n/q) ?",
1111 minfo[M_NAME], cinfo[C_NAME]);
1112 switch (YesNoQuitQuestion(temp_buf, FALSE)) {
1120 Put_message("Aborting...");
1127 args[0] = minfo[M_NAME];
1128 args[1] = cinfo[C_NAME];
1129 stat = do_mr_query("add_machine_to_cluster", 2, args,
1135 sprintf(temp_buf, "%s is already in cluster %s",
1136 minfo[M_NAME], cinfo[C_NAME]);
1137 Put_message(temp_buf);
1140 com_err(program_name, stat, " in AddMachineToCluster.");
1144 celem = celem->q_forw;
1146 celem = ctop; /* reset cluster element. */
1147 melem = melem->q_forw;
1154 /* Function Name: RealRemoveMachineFromCluster
1155 * Description: This function actually removes the machine from its
1157 * Arguments: info - all information nescessary to perform the removal.
1158 * one_map - True if there is only one case, and we should
1164 RealRemoveMachineFromCluster(info, one_map)
1168 char temp_buf[BUFSIZ];
1171 sprintf(temp_buf, "Remove %s from the cluster %s",
1172 info[MAP_MACHINE], info[MAP_CLUSTER]);
1173 if (!one_map || Confirm(temp_buf)) {
1174 if ( (stat = do_mr_query("delete_machine_from_cluster", 2,
1175 info, Scream, NULL)) != 0 )
1176 com_err(program_name, stat, " in delete_machine_from_cluster");
1178 sprintf(temp_buf, "%s has been removed from the cluster %s.",
1179 info[MAP_MACHINE], info[MAP_CLUSTER]);
1180 Put_message(temp_buf);
1184 Put_message("Machine not removed.");
1187 /* Function Name: RemoveMachineFromCluster
1188 * Description: Removes this machine form a specific cluster.
1189 * Arguments: argc, argv - Name of machine in argv[1].
1190 * Name of cluster in argv[2].
1196 RemoveMachineFromCluster(argc, argv)
1200 struct qelem *elem = NULL;
1201 char buf[BUFSIZ], * args[10];
1204 args[MAP_MACHINE] = canonicalize_hostname(strsave(argv[1]));
1205 if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"') {
1206 sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1207 argv[1], args[MAP_MACHINE]);
1210 args[MAP_CLUSTER] = argv[2];
1211 args[MAP_END] = NULL;
1213 stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1214 StoreInfo, (char *)&elem);
1215 if (stat == MR_NO_MATCH) {
1216 sprintf(buf, "The machine %s is not is the cluster %s.",
1217 args[MAP_MACHINE], args[MAP_CLUSTER]);
1219 free(args[MAP_MACHINE]);
1222 if (stat != MR_SUCCESS)
1223 com_err(program_name, stat, " in delete_machine_from_cluster");
1225 elem = QueueTop(elem);
1226 QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1227 "Remove this machine from this cluster");
1230 free(args[MAP_MACHINE]);
1234 /* ---------- Subnet Menu -------- */
1236 /* Function Name: ShowSubnetInfo
1237 * Description: Gets information about a subnet given its name.
1238 * Arguments: argc, argc - the name of the subnet in in argv[1].
1239 * Returns: DM_NORMAL.
1244 ShowSubnetInfo(argc, argv)
1250 top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1251 Loop(top, (void *) PrintSubnetInfo);
1256 /* Function Name: AddSubnet
1257 * Description: Creates a new subnet.
1258 * Arguments: argc, argv - the name of the new subnet is argv[1].
1259 * Returns: DM_NORMAL.
1264 AddSubnet(argc, argv)
1268 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1271 * Check to see if this subnet already exists.
1273 if (!ValidName(name))
1276 if ( (stat = do_mr_query("get_subnet", 1, &name,
1277 NullFunc, NULL)) == MR_SUCCESS) {
1278 Put_message("This subnet already exists.");
1281 else if (stat != MR_NO_MATCH) {
1282 com_err(program_name, stat, " in AddSubnet.");
1285 if ((args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)) ==
1287 Put_message("Aborted.");
1293 * Actually create the new Subnet.
1295 if ( (stat = do_mr_query("add_subnet", CountArgs(args),
1296 args, Scream, NULL)) != 0)
1297 com_err(program_name, stat, " in AddSubnet.");
1303 /* Function Name: RealUpdateSubnet
1304 * Description: This function actually performs the subnet update.
1305 * Arguments: info - all information nesc. for updating the subnet.
1306 * junk - an UNUSED boolean.
1312 RealUpdateSubnet(info, junk)
1317 char ** args = AskMCDInfo(info, SUBNET, TRUE);
1319 Put_message("Aborted.");
1322 if ( (stat = do_mr_query("update_subnet", CountArgs(args),
1323 args, Scream, NULL)) != 0)
1324 com_err(program_name, stat, " in UpdateSubnet.");
1326 Put_message("Subnet successfully updated.");
1329 /* Function Name: UpdateSubnet
1330 * Description: This Function Updates a subnet
1331 * Arguments: name of the subnet in argv[1].
1332 * Returns: DM_NORMAL.
1337 UpdateSubnet(argc, argv)
1342 top = GetMCInfo( SUBNET, argv[1], (char *) NULL );
1343 QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1349 /* Function Name: RealDeleteSubnet
1350 * Description: Actually performs the subnet deletion.
1351 * Arguments: info - all information about this subnet.
1352 * one_subnet - If true then there was only one subnet in
1353 * the queue, and we should confirm.
1358 RealDeleteSubnet(info, one_subnet)
1363 char temp_buf[BUFSIZ];
1366 "Are you sure the you want to delete the subnet %s (y/n) ?",
1368 if (!one_subnet || Confirm(temp_buf)) {
1369 if ( (stat = do_mr_query("delete_subnet", 1,
1370 &info[C_NAME], Scream, NULL)) != 0) {
1371 com_err(program_name, stat, " in delete_subnet.");
1372 sprintf(temp_buf, "Subnet %s ** NOT ** deleted.",
1374 Put_message(temp_buf);
1377 sprintf(temp_buf, "subnet %s sucesfully deleted.",
1379 Put_message(temp_buf);
1384 /* Function Name: DeleteSubnet
1385 * Description: This function removes a subnet from the database.
1386 * Arguments: argc, argv - the name of the subnet is stored in argv[1].
1387 * Returns: DM_NORMAL.
1392 DeleteSubnet(argc, argv)
1398 top = GetMCInfo( SUBNET, argv[1], (char *) NULL );
1399 QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1405 /* ---------- Cluster Menu -------- */
1407 /* Function Name: ShowClusterInfo
1408 * Description: Gets information about a cluser given its name.
1409 * Arguments: argc, argc - the name of the cluster in in argv[1].
1410 * Returns: DM_NORMAL.
1415 ShowClusterInfo(argc, argv)
1421 top = GetMCInfo(CLUSTER, argv[1], (char *) NULL);
1422 Loop(top, (void *) PrintClusterInfo);
1427 /* Function Name: AddCluster
1428 * Description: Creates a new cluster.
1429 * Arguments: argc, argv - the name of the new cluster is argv[1].
1430 * Returns: DM_NORMAL.
1435 AddCluster(argc, argv)
1439 char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1442 * Check to see if this cluster already exists.
1444 if (!ValidName(name))
1447 if ( (stat = do_mr_query("get_cluster", 1, &name,
1448 NullFunc, NULL)) == MR_SUCCESS) {
1449 Put_message("This cluster already exists.");
1452 else if (stat != MR_NO_MATCH) {
1453 com_err(program_name, stat, " in AddCluster.");
1456 if ((args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)) ==
1458 Put_message("Aborted.");
1464 * Actually create the new Cluster.
1466 if ( (stat = do_mr_query("add_cluster", CountArgs(args),
1467 args, Scream, NULL)) != 0)
1468 com_err(program_name, stat, " in AddCluster.");
1474 /* Function Name: RealUpdateCluster
1475 * Description: This function actually performs the cluster update.
1476 * Arguments: info - all information nesc. for updating the cluster.
1477 * junk - an UNUSED boolean.
1483 RealUpdateCluster(info, junk)
1488 char ** args = AskMCDInfo(info, CLUSTER, TRUE);
1490 Put_message("Aborted.");
1493 if ( (stat = do_mr_query("update_cluster", CountArgs(args),
1494 args, Scream, NULL)) != 0)
1495 com_err(program_name, stat, " in UpdateCluster.");
1497 Put_message("Cluster successfully updated.");
1500 /* Function Name: UpdateCluster
1501 * Description: This Function Updates a cluster
1502 * Arguments: name of the cluster in argv[1].
1503 * Returns: DM_NORMAL.
1508 UpdateCluster(argc, argv)
1513 top = GetMCInfo( CLUSTER, argv[1], (char *) NULL );
1514 QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1520 /* Function Name: CheckAndRemoveMachine
1521 * Description: This function checks and removes all machines from a
1523 * Arguments: name - name of the cluster.
1524 * ask_first - if TRUE, then we will query the user, before
1526 * Returns: SUB_ERROR if all machines not removed.
1530 CheckAndRemoveMachines(name, ask_first)
1534 register int stat, ret_value;
1536 char *args[10], temp_buf[BUFSIZ], *ptr;
1537 struct qelem *top, *elem = NULL;
1539 ret_value = SUB_NORMAL;
1540 args[MAP_MACHINE] = "*";
1541 args[MAP_CLUSTER] = name;
1542 stat = do_mr_query("get_machine_to_cluster_map", 2, args,
1543 StoreInfo, (char *)&elem);
1544 if (stat && stat != MR_NO_MATCH) {
1545 com_err(program_name, stat, " in get_machine_to_cluster_map.");
1549 elem = top = QueueTop(elem);
1552 "The cluster %s has the following machines in it:",
1554 Put_message(temp_buf);
1555 while (elem != NULL) {
1556 char **info = (char **) elem->q_data;
1557 Print(1, &info[MAP_MACHINE], (char *) NULL);
1558 elem = elem->q_forw;
1560 ptr = "Remove ** ALL ** these machines from this cluster?";
1562 if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1565 Put_message("Aborting...");
1576 char **info = (char **) elem->q_data;
1577 if ( (stat = do_mr_query("delete_machine_from_cluster",
1578 2, info, Scream, NULL)) != 0) {
1579 ret_value = SUB_ERROR;
1580 com_err(program_name, stat,
1581 " in delete_machine_from_cluster.");
1583 "Machine %s ** NOT ** removed from cluster %s.",
1584 info[MAP_MACHINE], info[MAP_CLUSTER]);
1585 Put_message(temp_buf);
1587 elem = elem->q_forw;
1594 /* Function Name: RealDeleteCluster
1595 * Description: Actually performs the cluster deletion.
1596 * Arguments: info - all information about this cluster.
1597 * one_cluster - If true then there was only one cluster in
1598 * the queue, and we should confirm.
1603 RealDeleteCluster(info, one_cluster)
1608 char temp_buf[BUFSIZ];
1611 "Are you sure the you want to delete the cluster %s (y/n) ?",
1613 if (!one_cluster || Confirm(temp_buf)) {
1614 if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR) {
1615 if ( (stat = do_mr_query("delete_cluster", 1,
1616 &info[C_NAME], Scream, NULL)) != 0) {
1617 com_err(program_name, stat, " in delete_cluster.");
1618 sprintf(temp_buf, "Cluster %s ** NOT ** deleted.",
1620 Put_message(temp_buf);
1623 sprintf(temp_buf, "cluster %s sucesfully deleted.",
1625 Put_message(temp_buf);
1631 /* Function Name: DeleteCluster
1632 * Description: This function removes a cluster from the database.
1633 * Arguments: argc, argv - the name of the cluster is stored in argv[1].
1634 * Returns: DM_NORMAL.
1639 DeleteCluster(argc, argv)
1645 top = GetMCInfo( CLUSTER, argv[1], (char *) NULL );
1646 QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1652 /* ----------- Cluster Data Menu -------------- */
1654 /* Function Name: ShowClusterData
1655 * Description: This function shows the services for one cluster.
1656 * Arguments: argc, argv - The name of the cluster is argv[1].
1657 * The label of the data in argv[2].
1658 * Returns: DM_NORMAL.
1663 ShowClusterData(argc, argv)
1667 struct qelem *elem, *top;
1670 top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1671 while (elem != NULL) {
1672 info = (char **) elem->q_data;
1673 PrintClusterData(info);
1674 elem = elem->q_forw;
1680 /* Function Name: AddClusterData
1681 * Description: This function adds some data to the cluster.
1682 * Arguments: argv, argc: argv[1] - the name of the cluster.
1683 * argv[2] - the label of the data.
1684 * argv[3] - the data.
1685 * Returns: DM_NORMAL.
1690 AddClusterData(argc, argv)
1696 if( (stat = do_mr_query("add_cluster_data", 3, argv + 1,
1697 Scream, (char *) NULL)) != 0)
1698 com_err(program_name, stat, " in AddClusterData.");
1702 /* Function Name: RealRemoveClusterData
1703 * Description: actually removes the cluster data.
1704 * Arguments: info - all info necessary to remove the cluster, in an array
1706 * one_item - if true then the queue has only one elem and we
1712 RealRemoveClusterData(info, one_item)
1720 temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1721 PrintClusterData(info);
1722 if (!one_item || Confirm(temp_ptr)) {
1723 if( (stat = do_mr_query("delete_cluster_data", 3, info,
1724 Scream, (char *) NULL)) != 0) {
1725 com_err(program_name, stat, " in DeleteClusterData.");
1726 Put_message("Data not removed.");
1729 Put_message("Removal sucessful.");
1733 /* Function Name: RemoveClusterData
1734 * Description: This function removes data on a given cluster.
1735 * Arguments: argv, argc: argv[1] - the name of the cluster.
1736 * argv[2] - the label of the data.
1737 * argv[3] - the data.
1738 * Returns: DM_NORMAL.
1743 RemoveClusterData(argc, argv)
1749 top = GetMCInfo(DATA, argv[1], argv[2]);
1750 QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1751 "Remove data from cluster");
1757 /* Function Name: MachineToClusterMap
1758 * Description: This Retrieves the mapping between machine and cluster
1759 * Arguments: argc, argv - argv[1] -> machine name or wildcard.
1760 * argv[2] -> cluster name or wildcard.
1766 MachineToClusterMap(argc,argv)
1770 struct qelem *elem, *top;
1771 char *tmpname, temp_buf[256];
1773 tmpname = canonicalize_hostname(strsave(argv[1]));
1774 if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"') {
1775 sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1777 Put_message(temp_buf);
1779 top = elem = GetMCInfo(MAP, tmpname, argv[2]);
1781 Put_message(""); /* blank line on screen */
1782 while (elem != NULL) {
1783 char ** info = (char **) elem->q_data;
1785 elem = elem->q_forw;