]> andersk Git - moira.git/blob - clients/moira/cluster.c
fix RCS IDs
[moira.git] / clients / moira / cluster.c
1 /* $Id$
2  *
3  *      This is the file cluster.c for the Moira Client, which allows users
4  *      to quickly and easily maintain most parts of the Moira database.
5  *      It Contains:
6  *
7  *      Created:        4/22/88
8  *      By:             Chris D. Peterson
9  *
10  * Copyright (C) 1988-1998 by the Massachusetts Institute of Technology.
11  * For copying and distribution information, please see the file
12  * <mit-copyright.h>.
13  */
14
15 /* BTW: for anyone who cares MCD is short for Machine, Cluster, Data. */
16
17 #include <mit-copyright.h>
18 #include <moira.h>
19 #include <moira_site.h>
20
21 #include "defs.h"
22 #include "f_defs.h"
23 #include "globals.h"
24
25 #include <sys/types.h>
26 #include <sys/utsname.h>
27
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30 #include <netdb.h>
31
32 #include <ctype.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 void PrintAliases(char **info);
38 struct mqelem *GetMCInfo(int type, char *name1, char *name2);
39 char **AskMCDInfo(char **info, int type, Bool name);
40 int CheckAndRemoveFromCluster(char *name, Bool ask_user);
41 int CheckAndRemoveMachines(char *name, Bool ask_first);
42 char *partial_canonicalize_hostname(char *s);
43
44 #define MACHINE  0
45 #define CLUSTER  1
46 #define DATA     2
47 #define MAP      3
48 #define SUBNET   4
49 #define CNAME    5
50
51 #define M_DEFAULT_TYPE     DEFAULT_NONE
52
53 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
54 #define C_DEFAULT_LOCATION DEFAULT_NONE
55
56 #define CD_DEFAULT_LABEL   DEFAULT_NONE
57 #define CD_DEFAULT_DATA    DEFAULT_NONE
58
59 #define S_DEFAULT_LOW   "18.0.0.20"
60 #define S_DEFAULT_HIGH  "18.0.2.249"
61
62 static char *states[] = {
63   "Reserved (0)",
64   "Active (1)",
65   "None (2)",
66   "Deleted (3)"
67 };
68
69 static char *MacState(int state)
70 {
71   static char buf[BUFSIZ];
72
73   if (state < 0 || state > 3)
74     {
75       sprintf(buf, "Unknown (%d)", state);
76       return buf;
77     }
78   return states[state];
79 }
80
81
82
83 /* -------------------- Set Defaults -------------------- */
84
85 /*      Function Name: SetMachineDefaults
86  *      Description: sets machine defaults.
87  *      Arguments: info - an array to put the defaults into.
88  *                 name - Canonacalized name of the machine.
89  *      Returns: info - the array.
90  */
91
92 static char **SetMachineDefaults(char **info, char *name)
93 {
94   info[M_NAME] = strdup(name);
95   info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
96   info[M_MODEL] = strdup(M_DEFAULT_TYPE);
97   info[M_OS] = strdup(M_DEFAULT_TYPE);
98   info[M_LOC] = strdup(M_DEFAULT_TYPE);
99   info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
100   info[M_USE] = strdup("0");
101   info[M_STAT] = strdup("1");
102   info[M_SUBNET] = strdup("NONE");
103   info[M_ADDR] = strdup("unique");
104   info[M_OWNER_TYPE] = strdup("NONE");
105   info[M_OWNER_NAME] = strdup("NONE");
106   info[M_ACOMMENT] = strdup("");
107   info[M_OCOMMENT] = strdup("");
108   info[15] = info[16] = NULL;
109   return info;
110 }
111
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.
117  */
118
119 static char **SetClusterDefaults(char **info, char *name)
120 {
121   info[C_NAME] = strdup(name);
122   info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
123   info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
124   info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
125   return info;
126 }
127
128 /*      Function Name: SetSubnetDefaults
129  *      Description: sets Subnet defaults.
130  *      Arguments: info - an array to put the defaults into.
131  *                 name - name of the Subnet.
132  *      Returns: info - the array.
133  */
134
135 static char **SetSubnetDefaults(char **info, char *name)
136 {
137   char buf[256];
138
139   info[C_NAME] = strdup(name);
140   info[SN_DESC] = strdup("");
141   sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
142   info[SN_ADDRESS] = strdup(buf);
143   sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
144   info[SN_MASK] = strdup(buf);
145   sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
146   info[SN_LOW] = strdup(buf);
147   sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
148   info[SN_HIGH] = strdup(buf);
149   info[SN_PREFIX] = strdup("");
150   info[SN_ACE_TYPE] = strdup("LIST");
151   info[SN_ACE_NAME] = strdup("network");
152   info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
153   return info;
154 }
155
156 /* -------------------- General Functions -------------------- */
157
158 static char aliasbuf[256];
159
160 void PrintAliases(char **info)
161 {
162   if (strlen(aliasbuf) == 0)
163     sprintf(aliasbuf, "Aliases:  %s", info[0]);
164   else
165     {
166       strcat(aliasbuf, ", ");
167       strcat(aliasbuf, info[0]);
168     }
169 }
170
171
172 /*      Function Name: PrintMachInfo
173  *      Description: This function Prints out the Machine info in
174  *                   a coherent form.
175  *      Arguments: info - array of information about a machine.
176  *      Returns: The name of the Machine
177  */
178
179 static char *PrintMachInfo(char **info)
180 {
181   char buf[BUFSIZ], tbuf[256];
182   char *args[3];
183   struct mqelem *elem = NULL;
184   int stat;
185
186   Put_message("");
187   sprintf(buf, "Machine:  %s", info[M_NAME]);
188   Put_message(buf);
189   args[0] = "*";
190   args[1] = info[M_NAME];
191   if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
192     {
193       if (stat != MR_NO_MATCH)
194         com_err(program_name, stat, " looking up aliases");
195     }
196   else
197     {
198       aliasbuf[0] = 0;
199       Loop(QueueTop(elem), (void *) PrintAliases);
200       FreeQueue(elem);
201       Put_message(aliasbuf);
202     }
203   sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
204           strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
205   sprintf(buf, "Address:  %-16s    Network:    %-16s",
206           info[M_ADDR], info[M_SUBNET]);
207   Put_message(buf);
208   sprintf(buf, "Owner:    %-16s    Use data:   %s", tbuf, info[M_INUSE]);
209   Put_message(buf);
210   sprintf(buf, "Status:   %-16s    Changed:    %s",
211           MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
212   Put_message(buf);
213   Put_message("");
214
215   sprintf(buf, "Vendor:   %-16s    Model:      %-20s  OS:  %s",
216           info[M_VENDOR], info[M_MODEL], info[M_OS]);
217   Put_message(buf);
218   sprintf(buf, "Location: %-16s    Contact:    %-20s  Opt: %s",
219           info[M_LOC], info[M_CONTACT], info[M_USE]);
220   Put_message(buf);
221   sprintf(buf, "\nAdm cmt: %s", info[M_ACOMMENT]);
222   Put_message(buf);
223   sprintf(buf, "Op cmt:  %s", info[M_OCOMMENT]);
224   Put_message(buf);
225   Put_message("");
226   sprintf(buf, "Created  by %s on %s", info[M_CREATOR], info[M_CREATED]);
227   Put_message(buf);
228   sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
229   Put_message(buf);
230   return info[M_NAME];
231 }
232
233 /*      Function Name: PrintCname
234  *      Description: Prints the Data on a host alias
235  *      Arguments: info a pointer to the data array.
236  *      Returns: The name of the alias.
237  */
238
239 static char *PrintCname(char **info)
240 {
241   char buf[BUFSIZ];
242
243   sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
244   Put_message(buf);
245   return info[0];
246 }
247
248 /*      Function Name: PrintClusterInfo
249  *      Description: This function Prints out the cluster info
250  *                   in a coherent form.
251  *      Arguments: info - array of information about a cluster.
252  *      Returns: The name of the cluster.
253  */
254
255 static char *PrintClusterInfo(char **info)
256 {
257   char buf[BUFSIZ];
258
259   Put_message("");
260   sprintf(buf, "Cluster:     %s", info[C_NAME]);
261   Put_message(buf);
262   sprintf(buf, "Description: %s", info[C_DESCRIPT]);
263   Put_message(buf);
264   sprintf(buf, "Location:    %s", info[C_LOCATION]);
265   Put_message(buf);
266   sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
267   Put_message(buf);
268   return info[C_NAME];
269 }
270
271 /*      Function Name: PrintClusterData
272  *      Description: Prints the Data on a cluster
273  *      Arguments: info a pointer to the data array.
274  *      Returns: The name of the cluster.
275  */
276
277 static char *PrintClusterData(char **info)
278 {
279   char buf[BUFSIZ];
280
281   Put_message("");
282   sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
283           info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
284   Put_message(buf);
285   return info[CD_NAME];
286 }
287
288 /*      Function Name: PrintMCMap
289  *      Description: Prints the data about a machine to cluster mapping.
290  *      Arguments: info a pointer to the data array.
291  *      Returns: none
292  */
293
294 static char *PrintMCMap(char **info)
295 {
296   char buf[BUFSIZ];
297   sprintf(buf, "Cluster: %-30s Machine: %-20s",
298           info[MAP_CLUSTER], info[MAP_MACHINE]);
299   Put_message(buf);
300   return "";                    /* Used by QueryLoop(). */
301 }
302
303 /*      Function Name: PrintSubnetInfo
304  *      Description: This function Prints out the subnet info
305  *                   in a coherent form.
306  *      Arguments: info - array of information about a subnet.
307  *      Returns: The name of the subnet.
308  */
309
310 static char *PrintSubnetInfo(char **info)
311 {
312   char buf[BUFSIZ];
313   struct in_addr addr, mask, low, high;
314
315   Put_message("");
316   sprintf(buf, "        Network:  %s", info[SN_NAME]);
317   Put_message(buf);
318   sprintf(buf, "    Description:  %s", info[SN_DESC]);
319   Put_message(buf);
320   addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
321   mask.s_addr = htonl(atoi(info[SN_MASK]));
322   low.s_addr = htonl(atoi(info[SN_LOW]));
323   high.s_addr = htonl(atoi(info[SN_HIGH]));
324   /* screwy sequence is here because inet_ntoa returns a pointer to
325      a static buf.  If it were all one sprintf, the last value would
326      appear 4 times. */
327   sprintf(buf, "        Address:  %s        Mask:  ", inet_ntoa(addr));
328   strcat(buf, inet_ntoa(mask));
329   strcat(buf, "\n           High:  ");
330   strcat(buf, inet_ntoa(high));
331   strcat(buf, "       Low:  ");
332   strcat(buf, inet_ntoa(low));
333   Put_message(buf);
334   sprintf(buf, "Hostname prefix:  %s", info[SN_PREFIX]);
335   Put_message(buf);
336   sprintf(buf, "          Owner:  %s %s\n", info[SN_ACE_TYPE],
337           strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
338   Put_message(buf);
339   sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
340   Put_message(buf);
341   return info[SN_NAME];
342 }
343
344 /*      Function Name: GetMCInfo.
345  *      Description: This function stores info about a machine.
346  *                   type - type of data we are trying to retrieve.
347  *                   name1 - the name of argv[0] for the call.
348  *                   name2 - the name of argv[1] for the call.
349  *      Returns: the top element of a queue containing the data or NULL.
350  */
351
352 struct mqelem *GetMCInfo(int type, char *name1, char *name2)
353 {
354   int stat;
355   struct mqelem *elem = NULL;
356   char *args[5];
357
358   switch (type)
359     {
360     case MACHINE:
361       args[0] = name1;
362       args[1] = args[2] = args[3] = "*";
363       if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
364         {
365           if (stat == MR_NO_MATCH)
366             {
367               char buf[128];
368               sprintf(buf, "Machine '%s' is not in the database.", name1);
369               Put_message(buf);
370             }
371           else
372             com_err(program_name, stat, " in get_machine.");
373           return NULL;
374         }
375       break;
376     case CNAME:
377       args[0] = name1;
378       args[1] = name2;
379       if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
380         {
381           com_err(program_name, stat, " in get_hostalias.");
382           return NULL;
383         }
384       break;
385     case SUBNET:
386       if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
387         {
388           if (stat == MR_NO_MATCH)
389             {
390               char buf[128];
391               sprintf(buf, "Network '%s' is not in the database.", name1);
392               Put_message(buf);
393             }
394           else
395             com_err(program_name, stat, " in get_subnet.");
396           return NULL;
397         }
398       break;
399     case CLUSTER:
400       if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
401         {
402           com_err(program_name, stat, " in get_cluster.");
403           return NULL;
404         }
405       break;
406     case MAP:
407       args[MAP_MACHINE] = name1;
408       args[MAP_CLUSTER] = name2;
409       if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
410                               StoreInfo, &elem)))
411         {
412           com_err(program_name, stat, " in get_machine_to_cluster_map.");
413           return NULL;
414         }
415       break;
416     case DATA:
417       args[CD_NAME] = name1;
418       args[CD_LABEL] = name2;
419       if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
420         {
421           com_err(program_name, stat, " in get_cluster_data.");
422           return NULL;
423         }
424     }
425   return QueueTop(elem);
426 }
427
428 /*      Function Name: AskMCDInfo.
429  *      Description: This function askes the user for information about a
430  *                   machine and saves it into a structure.
431  *      Arguments: info - a pointer the information to ask about
432  *                 type - type of information - MACHINE
433  *                                              CLUSTER
434  *                                              DATA
435  *                 name - T/F : change the name of this type.
436  *      Returns: none.
437  */
438
439 char **AskMCDInfo(char **info, int type, Bool name)
440 {
441   char temp_buf[BUFSIZ], *newname, *oldnewname;
442
443   switch (type)
444     {
445     case MACHINE:
446       sprintf(temp_buf, "\nSetting the information for the Machine %s...",
447               info[M_NAME]);
448       break;
449     case SUBNET:
450       sprintf(temp_buf, "Setting the information for the Network %s...",
451               info[SN_NAME]);
452       break;
453     case CLUSTER:
454       sprintf(temp_buf, "Setting the information for the Cluster %s...",
455               info[C_NAME]);
456       break;
457     case DATA:
458       sprintf(temp_buf, "Setting the Data for the Cluster %s...",
459               info[CD_NAME]);
460       break;
461     }
462   Put_message(temp_buf);
463
464   if (name)
465     {
466       switch (type)
467         {
468         case MACHINE:
469           newname = strdup(info[M_NAME]);
470           if (GetValueFromUser("The new name for this machine? ", &newname) ==
471               SUB_ERROR)
472             return NULL;
473           oldnewname = strdup(newname);
474           newname = canonicalize_hostname(newname);
475           if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
476             {
477               sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
478                       oldnewname, newname);
479               Put_message(temp_buf);
480             }
481           free(oldnewname);
482           break;
483         case SUBNET:
484           newname = strdup(info[SN_NAME]);
485           if (GetValueFromUser("The new name for this network? ", &newname) ==
486               SUB_ERROR)
487             return NULL;
488           break;
489         case CLUSTER:
490           newname = strdup(info[C_NAME]);
491           if (GetValueFromUser("The new name for this cluster? ", &newname) ==
492               SUB_ERROR)
493             return NULL;
494           break;
495         default:
496           Put_message("Unknown type in AskMCDInfo, programmer botch");
497           return NULL;
498         }
499     }
500
501   switch (type)
502     {
503     case MACHINE:
504       if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
505         return NULL;
506       if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
507         return NULL;
508       if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
509           SUB_ERROR)
510         return NULL;
511       if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
512         return NULL;
513       if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
514           SUB_ERROR)
515         return NULL;
516       while (1)
517         {
518           int i;
519           if (GetValueFromUser("Machine's status (? for help)",
520                                  &info[M_STAT]) == SUB_ERROR)
521             return NULL;
522           if (isdigit(info[M_STAT][0]))
523             break;
524           Put_message("Valid status numbers:");
525           for (i = 0; i < 4; i++)
526             Put_message(states[i]);
527         }
528
529       /* there appears to be some argument mismatch between the client
530        * and the server.. so here is this argument shuffler.
531        * I have since modified this to always shuffle the arguments..
532        * not just do so when performing a modify all fields request.
533        * The SetMachinedefaults() has been changed to reflect this.
534        * pray for us and may we attain enlightenment through structures.
535        */
536
537       if (name)
538         {
539           /* info did not come from SetMachineDefaults(), which does not
540            * initialize entry 8 (M_STAT_CHNG), therefore we can
541            * free it.
542            */
543           /* This is an update of an existing machine and the structure
544            * was filled in thru a query to the db which does fill in this
545            * field.
546            */
547           free(info[8]);
548         }
549
550       info[8] = info[M_SUBNET];
551       info[9] = info[M_ADDR];
552       info[10] = info[M_OWNER_TYPE];
553       info[11] = info[M_OWNER_NAME];
554       info[12] = info[M_ACOMMENT];
555       info[13] = info[M_OCOMMENT];
556
557       if (name)
558         {
559           if (GetValueFromUser("Machine's network (or 'none')", &info[8])
560               == SUB_ERROR)
561             return NULL;
562         }
563       if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
564                            &info[9]) == SUB_ERROR)
565         return NULL;
566       if (GetTypeFromUser("Machine's owner type", "ace_type", &info[10]) ==
567           SUB_ERROR)
568         return NULL;
569       if (strcmp(info[10], "NONE") &&
570           GetValueFromUser("Owner's Name", &info[11]) == SUB_ERROR)
571         return NULL;
572       if (GetValueFromUser("Administrative comment", &info[12]) == SUB_ERROR)
573         return NULL;
574       if (GetValueFromUser("Operational comment", &info[13]) == SUB_ERROR)
575         return NULL;
576       info[14] = NULL;
577       FreeAndClear(&info[15], TRUE);
578       FreeAndClear(&info[16], TRUE);
579       break;
580     case SUBNET:
581       if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
582         return NULL;
583       if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
584         return NULL;
585       if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
586         return NULL;
587       if (atoi(info[SN_LOW]) == ntohl(inet_addr(S_DEFAULT_LOW)))
588         {
589           struct in_addr low;
590           unsigned long mask, addr;
591
592           addr = atoi(info[SN_ADDRESS]);
593           mask = atoi(info[SN_MASK]);
594           low.s_addr = atoi(info[SN_LOW]);
595           low.s_addr = (low.s_addr & ~mask) | (addr & mask);
596           free(info[SN_LOW]);
597           sprintf(temp_buf, "%ld", low.s_addr);
598           info[SN_LOW] = strdup(temp_buf);
599         }
600       if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
601           SUB_ERROR)
602         return NULL;
603       if (atoi(info[SN_HIGH]) == ntohl(inet_addr(S_DEFAULT_HIGH)))
604         {
605           struct in_addr high;
606           unsigned long mask, addr;
607
608           addr = atoi(info[SN_ADDRESS]);
609           mask = atoi(info[SN_MASK]);
610           high.s_addr = atoi(info[SN_HIGH]);
611           high.s_addr = (high.s_addr & ~mask) | (addr & mask);
612           free(info[SN_HIGH]);
613           sprintf(temp_buf, "%ld", high.s_addr);
614           info[SN_HIGH] = strdup(temp_buf);
615         }
616       if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
617           SUB_ERROR)
618         return NULL;
619       if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
620         return NULL;
621       if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
622           SUB_ERROR)
623         return NULL;
624       if (strcmp(info[SN_ACE_TYPE], "NONE") &&
625           GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
626         return NULL;
627       FreeAndClear(&info[SN_MODTIME], TRUE);
628       FreeAndClear(&info[SN_MODBY], TRUE);
629       FreeAndClear(&info[SN_MODWITH], TRUE);
630       break;
631     case CLUSTER:
632       if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
633           SUB_ERROR)
634         return NULL;
635       if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
636           SUB_ERROR)
637         return NULL;
638       FreeAndClear(&info[C_MODTIME], TRUE);
639       FreeAndClear(&info[C_MODBY], TRUE);
640       FreeAndClear(&info[C_MODWITH], TRUE);
641       break;
642     case DATA:
643       if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
644           SUB_ERROR)
645         return NULL;
646       if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
647         return NULL;
648       break;
649     }
650
651   /*
652    * Slide the newname into the #2 slot, this screws up all future references
653    * to this list.
654    */
655   if (name)
656     SlipInNewName(info, newname);
657
658   return info;
659 }
660
661 /* -----------  Machine Menu ----------- */
662
663 /*      Function Name: ShowMachineInfo
664  *      Description: This function shows the information about a machine.
665  *      Arguments: argc, argv - the name of the machine in argv[1].
666  *      Returns: DM_NORMAL.
667  */
668
669 int ShowMachineInfo(int argc, char **argv)
670 {
671   struct mqelem *top;
672   char *tmpname;
673
674   tmpname = canonicalize_hostname(strdup(argv[1]));
675   top = GetMCInfo(MACHINE, tmpname, NULL);
676   Loop(top, ((void *) PrintMachInfo));
677   FreeQueue(top);
678   return DM_NORMAL;
679 }
680
681 /*      Function Name: ShowMachineQuery
682  *      Description: This function shows the information about a machine.
683  *              or group of machines, which may be selected through a
684  *              number of criteria.
685  *      Arguments: argc, argv - the name of the machine in argv[1],
686  *              the address of the machine in argv[2],
687  *              the location of the machine in argv[3],
688  *              and the contact name in argv[4].
689  *           any of these may be wildcards.
690  *      Returns: DM_NORMAL.
691  */
692
693 int ShowMachineQuery(int argc, char **argv)
694 {
695   int stat;
696   struct mqelem *top, *elem = NULL;
697   char *args[5];
698
699   if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
700       !strcmp(argv[3], "") && !strcmp(argv[4], ""))
701     {
702       Put_message("You must specify at least one parameter of the query.");
703       return DM_NORMAL;
704     }
705
706   if (*argv[1])
707     args[0] = canonicalize_hostname(strdup(argv[1]));
708   else
709     args[0] = "*";
710   if (*argv[2])
711     args[1] = argv[2];
712   else
713     args[1] = "*";
714   if (*argv[3])
715     args[2] = argv[3];
716   else
717     args[2] = "*";
718   if (*argv[4])
719     args[3] = argv[4];
720   else
721     args[3] = "*";
722
723   if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
724     {
725       if (stat == MR_NO_MATCH)
726         Put_message("No machine(s) found matching query in the database.");
727       else
728         com_err(program_name, stat, " in get_machine.");
729       return DM_NORMAL;
730     }
731   top = QueueTop(elem);
732   Loop(top, ((void *) PrintMachInfo));
733   FreeQueue(top);
734   return DM_NORMAL;
735 }
736
737 /*      Function Name: AddMachine
738  *      Description: This function adds a new machine to the database.
739  *      Arguments: argc, argv - the name of the network in argv[1].
740  *      Returns: DM_NORMAL.
741  */
742
743 int AddMachine(int argc, char **argv)
744 {
745   char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
746   char **rinfo;
747   struct mqelem *elem = NULL;
748   int stat;
749
750   if (!ValidName(argv[1]))      /* Checks for wildcards. */
751     return DM_NORMAL;
752
753   /*
754    * get the network record
755    */
756
757   if (strcasecmp(argv[1], "none") &&
758       (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
759     {
760       if (stat == MR_NO_MATCH)
761         {
762           char buf[128];
763           sprintf(buf, "Network '%s' is not in the database.", argv[1]);
764           Put_message(buf);
765         } else
766           com_err(program_name, stat, " in get_subnet.");
767       return DM_NORMAL;
768     }
769
770   /*
771    * Check to see if this machine already exists.
772    */
773
774   name = strdup(""); /* want to put prefix here */
775   if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
776     return 0;
777
778   name = canonicalize_hostname(strdup(name));
779
780   xargs[0] = name;
781   xargs[1] = xargs[2] = xargs[3] = "*";
782   if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
783     {
784       sprintf(buf, "The machine '%s' already exists.", name);
785       Put_message(buf);
786       free(name);
787       return DM_NORMAL;
788     }
789   else if (stat != MR_NO_MATCH)
790     {
791       com_err(program_name, stat,
792               " while checking machine '%s' in AddMachine.", name);
793       free(name);
794       return DM_NORMAL;
795     }
796   rinfo = SetMachineDefaults(info, name);
797   rinfo[M_SUBNET] = strdup(argv[1]);
798   if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
799     {
800       Put_message("Aborted.");
801       return DM_NORMAL;
802     }
803
804   /*
805    * Actually create the new Machine.
806    */
807
808   if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
809     com_err(program_name, stat, " in AddMachine.");
810
811   FreeInfo(info);
812   free(name);
813   return DM_NORMAL;
814 }
815
816 /*      Function Name: RealUpdateMachine
817  *      Description: Performs the actual update of the machine data.
818  *      Arguments: info - the information on the machine to update.
819  *                 junk - an UNUSED Boolean.
820  *      Returns: none.
821  */
822
823 static void RealUpdateMachine(char **info, Bool junk)
824 {
825   int stat;
826   char **args = AskMCDInfo(info, MACHINE, TRUE);
827   if (!args)
828     {
829       Put_message("Aborted.");
830       return;
831     }
832   if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
833     com_err(program_name, stat, " in UpdateMachine.");
834   else
835     Put_message("Machine successfully updated.");
836 }
837
838 /*      Function Name: UpdateMachine
839  *      Description: This function adds a new machine to the database.
840  *      Arguments: argc, argv - the name of the machine in argv[1].
841  *      Returns: DM_NORMAL.
842  */
843
844 int UpdateMachine(int argc, char **argv)
845 {
846   struct mqelem *top;
847   char *tmpname;
848
849   tmpname = canonicalize_hostname(strdup(argv[1]));
850   top = GetMCInfo(MACHINE, tmpname, NULL);
851   QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
852
853   FreeQueue(top);
854   free(tmpname);
855   return DM_NORMAL;
856 }
857
858 /*      Function Name: CheckAndRemoveFromCluster
859  *      Description: This func tests to see if a machine is in a cluster.
860  *                   and if so then removes it
861  *      Arguments: name - name of the machine (already Canonocalized).
862  *                 ask_user- query the user before removing if from clusters?
863  *      Returns: MR_ERROR if machine left in a cluster, or mr_error.
864  */
865
866 int CheckAndRemoveFromCluster(char *name, Bool ask_user)
867 {
868   int stat, ret_value;
869   Bool delete_it;
870   char *args[10], temp_buf[BUFSIZ], *ptr;
871   struct mqelem *top, *elem = NULL;
872
873   ret_value = SUB_NORMAL;       /* initialize ret_value. */
874   args[0] = name;
875   args[1] = "*";
876   stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
877   if (stat && stat != MR_NO_MATCH)
878     {
879       com_err(program_name, stat, " in get_machine_to_cluster_map.");
880       return DM_NORMAL;
881     }
882   if (stat == MR_SUCCESS)
883     {
884       elem = top = QueueTop(elem);
885       if (ask_user)
886         {
887           sprintf(temp_buf, "%s is assigned to the following clusters.", name);
888           Put_message(temp_buf);
889           Loop(top, (void *) PrintMCMap);
890           ptr = "Remove this machine from ** ALL ** these clusters?";
891           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
892             delete_it = TRUE;
893           else
894             {
895               Put_message("Aborting...");
896               FreeQueue(top);
897               return SUB_ERROR;
898             }
899         }
900       else
901         delete_it = TRUE;
902
903       if (delete_it)
904         {
905           while (elem)
906             {
907               char **info = elem->q_data;
908               if ((stat = do_mr_query("delete_machine_from_cluster",
909                                        2, info, NULL, NULL)))
910                 {
911                   ret_value = SUB_ERROR;
912                   com_err(program_name, stat,
913                           " in delete_machine_from_cluster.");
914                   sprintf(temp_buf,
915                           "Machine %s ** NOT ** removed from cluster %s.",
916                           info[MAP_MACHINE], info[MAP_CLUSTER]);
917                   Put_message(temp_buf);
918                 }
919               elem = elem->q_forw;
920             }
921         }
922     }
923   return ret_value;
924 }
925
926 /*      Function Name: RealDeleteMachine
927  *      Description: Actually Deletes the Machine.
928  *      Arguments: info - nescessary information stored as an array of char *'s
929  *                 one_machine - a boolean, true if there is only one item in
930  *                               the query.
931  *      Returns: none.
932  */
933
934 static void RealDeleteMachine(char **info, Bool one_machine)
935 {
936   int stat;
937   char temp_buf[BUFSIZ];
938
939   sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
940           info[M_NAME]);
941   if (!one_machine || Confirm(temp_buf))
942     {
943       if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
944         {
945           if ((stat = do_mr_query("delete_host", 1,
946                                   &info[M_NAME], NULL, NULL)))
947             {
948               com_err(program_name, stat, " in DeleteMachine.");
949               sprintf(temp_buf, "%s ** NOT ** deleted.",
950                       info[M_NAME]);
951               Put_message(temp_buf);
952             }
953           else
954             {
955               sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
956               Put_message(temp_buf);
957             }
958         }
959     }
960 }
961
962 /*      Function Name: DeleteMachine
963  *      Description: This function removes a machine from the data base.
964  *      Arguments: argc, argv - the machines name int argv[1].
965  *      Returns: DM_NORMAL.
966  */
967
968 /* Perhaps we should remove the cluster if it has no machine now. */
969
970 int DeleteMachine(int argc, char **argv)
971 {
972   struct mqelem *top;
973   char *tmpname;
974
975   tmpname = canonicalize_hostname(strdup(argv[1]));
976   top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
977   QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
978   FreeQueue(top);
979   free(tmpname);
980   return DM_NORMAL;
981 }
982
983
984 char *partial_canonicalize_hostname(char *s)
985 {
986   char buf[256], *cp;
987   static char *def_domain = NULL;
988   struct hostent *hp;
989   struct utsname name;
990
991   if (!def_domain)
992     {
993       uname(&name);
994       hp = gethostbyname(name.nodename);
995       cp = strchr(hp->h_name, '.');
996       if (cp)
997         def_domain = strdup(++cp);
998       else
999         def_domain = "";
1000     }
1001
1002   if (strchr(s, '.') || strchr(s, '*'))
1003     return s;
1004   sprintf(buf, "%s.%s", s, def_domain);
1005   free(s);
1006   return strdup(buf);
1007 }
1008
1009
1010 /*      Function Name: ShowCname
1011  *      Description: This function shows machine aliases
1012  *      Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1013  *      Returns: DM_NORMAL.
1014  */
1015
1016 int ShowCname(int argc, char **argv)
1017 {
1018   struct mqelem *top;
1019   char *tmpalias, *tmpname;
1020
1021   tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
1022   tmpname = canonicalize_hostname(strdup(argv[2]));
1023   top = GetMCInfo(CNAME, tmpalias, tmpname);
1024   Put_message("");              /* blank line on screen */
1025   Loop(top, ((void *) PrintCname));
1026   FreeQueue(top);
1027   return DM_NORMAL;
1028 }
1029
1030
1031 int AddCname(int argc, char **argv)
1032 {
1033   int stat;
1034   char *args[10];
1035
1036   args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1037   args[1] = canonicalize_hostname(strdup(argv[2]));
1038   stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
1039   switch (stat)
1040     {
1041     case MR_SUCCESS:
1042       break;
1043     case MR_EXISTS:
1044       Put_message("That alias name is already in use.");
1045       break;
1046     case MR_PERM:
1047       Put_message("Permission denied.  "
1048                   "(Regular users can only add two aliases to a host.");
1049       break;
1050     default:
1051       com_err(program_name, stat, " in add_hostalias");
1052     }
1053   return DM_NORMAL;
1054 }
1055
1056
1057 int DeleteCname(int argc, char **argv)
1058 {
1059   int stat;
1060   char *args[10];
1061
1062   args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1063   args[1] = canonicalize_hostname(strdup(argv[2]));
1064   stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
1065   if (stat)
1066     com_err(program_name, stat, " in delete_hostalias");
1067   return DM_NORMAL;
1068 }
1069
1070
1071 /*      Function Name: AddMachineToCluster
1072  *      Description: This function adds a machine to a cluster
1073  *      Arguments: argc, argv - The machine name is argv[1].
1074  *                              The cluster name in argv[2].
1075  *      Returns: DM_NORMAL.
1076  */
1077
1078 int AddMachineToCluster(int argc, char **argv)
1079 {
1080   int stat;
1081   char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1082   Bool add_it, one_machine, one_cluster;
1083   struct mqelem *melem, *mtop, *celem, *ctop;
1084
1085   machine = canonicalize_hostname(strdup(argv[1]));
1086   if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
1087     {
1088       sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1089               argv[1], machine);
1090       Put_message(temp_buf);
1091     }
1092   cluster = argv[2];
1093
1094   celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
1095   melem = mtop = GetMCInfo(MACHINE, machine, NULL);
1096   free(machine);
1097
1098   one_machine = (QueueCount(mtop) == 1);
1099   one_cluster = (QueueCount(ctop) == 1);
1100
1101   /* No good way to use QueryLoop() here, sigh */
1102
1103   while (melem)
1104     {
1105       char **minfo = melem->q_data;
1106       while (celem)
1107         {
1108           char **cinfo = celem->q_data;
1109           if (one_machine && one_cluster)
1110             add_it = TRUE;
1111           else
1112             {
1113               sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
1114                       minfo[M_NAME], cinfo[C_NAME]);
1115               switch (YesNoQuitQuestion(temp_buf, FALSE))
1116                 {
1117                 case TRUE:
1118                   add_it = TRUE;
1119                   break;
1120                 case FALSE:
1121                   add_it = FALSE;
1122                   break;
1123                 default:
1124                   Put_message("Aborting...");
1125                   FreeQueue(ctop);
1126                   FreeQueue(mtop);
1127                   return DM_NORMAL;
1128                 }
1129             }
1130           if (add_it)
1131             {
1132               args[0] = minfo[M_NAME];
1133               args[1] = cinfo[C_NAME];
1134               stat = do_mr_query("add_machine_to_cluster", 2, args,
1135                                  NULL, NULL);
1136               switch (stat)
1137                 {
1138                 case MR_SUCCESS:
1139                   break;
1140                 case MR_EXISTS:
1141                   sprintf(temp_buf, "%s is already in cluster %s",
1142                           minfo[M_NAME], cinfo[C_NAME]);
1143                   Put_message(temp_buf);
1144                   break;
1145                 default:
1146                   com_err(program_name, stat, " in AddMachineToCluster.");
1147                   break;
1148                 }
1149             }
1150           celem = celem->q_forw;
1151         }
1152       celem = ctop;             /* reset cluster element. */
1153       melem = melem->q_forw;
1154     }
1155   FreeQueue(ctop);
1156   FreeQueue(mtop);
1157   return DM_NORMAL;
1158 }
1159
1160 /*      Function Name: RealRemoveMachineFromCluster
1161  *      Description: This function actually removes the machine from its
1162  *                   cluster.
1163  *      Arguments: info - all information nescessary to perform the removal.
1164  *                 one_map - True if there is only one case, and we should
1165  *                           confirm.
1166  *      Returns: none.
1167  */
1168
1169 static void RealRemoveMachineFromCluster(char **info, Bool one_map)
1170 {
1171   char temp_buf[BUFSIZ];
1172   int stat;
1173
1174   sprintf(temp_buf, "Remove %s from the cluster %s",
1175           info[MAP_MACHINE], info[MAP_CLUSTER]);
1176   if (!one_map || Confirm(temp_buf))
1177     {
1178       if ((stat = do_mr_query("delete_machine_from_cluster", 2,
1179                               info, NULL, NULL)))
1180         com_err(program_name, stat, " in delete_machine_from_cluster");
1181       else
1182         {
1183           sprintf(temp_buf, "%s has been removed from the cluster %s.",
1184                   info[MAP_MACHINE], info[MAP_CLUSTER]);
1185           Put_message(temp_buf);
1186         }
1187     }
1188   else
1189     Put_message("Machine not removed.");
1190 }
1191
1192 /*      Function Name: RemoveMachineFromCluster
1193  *      Description: Removes this machine form a specific cluster.
1194  *      Arguments: argc, argv - Name of machine in argv[1].
1195  *                              Name of cluster in argv[2].
1196  *      Returns: none.
1197  */
1198
1199 int RemoveMachineFromCluster(int argc, char **argv)
1200 {
1201   struct mqelem *elem = NULL;
1202   char buf[BUFSIZ], * args[10];
1203   int stat;
1204
1205   args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
1206   if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
1207     {
1208       sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1209               argv[1], args[MAP_MACHINE]);
1210       Put_message(buf);
1211     }
1212   args[MAP_CLUSTER] = argv[2];
1213   args[MAP_END] = NULL;
1214
1215   stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1216                      StoreInfo, &elem);
1217   if (stat == MR_NO_MATCH)
1218     {
1219       sprintf(buf, "The machine %s is not is the cluster %s.",
1220               args[MAP_MACHINE], args[MAP_CLUSTER]);
1221       Put_message(buf);
1222       free(args[MAP_MACHINE]);
1223       return DM_NORMAL;
1224     }
1225   if (stat != MR_SUCCESS)
1226     com_err(program_name, stat, " in delete_machine_from_cluster");
1227
1228   elem = QueueTop(elem);
1229   QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1230             "Remove this machine from this cluster");
1231
1232   FreeQueue(elem);
1233   free(args[MAP_MACHINE]);
1234   return DM_NORMAL;
1235 }
1236
1237 /* ---------- Subnet Menu -------- */
1238
1239 /*      Function Name: ShowSubnetInfo
1240  *      Description: Gets information about a subnet given its name.
1241  *      Arguments: argc, argc - the name of the subnet in in argv[1].
1242  *      Returns: DM_NORMAL.
1243  */
1244
1245 int ShowSubnetInfo(int argc, char **argv)
1246 {
1247   struct mqelem *top;
1248
1249   top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1250   Loop(top, (void *) PrintSubnetInfo);
1251   FreeQueue(top);
1252   return DM_NORMAL;
1253 }
1254
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.
1259  */
1260
1261 int AddSubnet(int argc, char **argv)
1262 {
1263   char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1264   int stat;
1265
1266   /*
1267    * Check to see if this subnet already exists.
1268    */
1269   if (!ValidName(name))
1270     return DM_NORMAL;
1271
1272   if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
1273     {
1274       Put_message("This subnet already exists.");
1275       return DM_NORMAL;
1276     }
1277   else if (stat != MR_NO_MATCH)
1278     {
1279       com_err(program_name, stat, " in AddSubnet.");
1280       return DM_NORMAL;
1281     }
1282   if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
1283     {
1284       Put_message("Aborted.");
1285       FreeInfo(info);
1286       return DM_NORMAL;
1287     }
1288
1289   /*
1290    * Actually create the new Subnet.
1291    */
1292   if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
1293     com_err(program_name, stat, " in AddSubnet.");
1294
1295   FreeInfo(info);
1296   return DM_NORMAL;
1297 }
1298
1299 /*      Function Name: RealUpdateSubnet
1300  *      Description: This function actually performs the subnet update.
1301  *      Arguments: info - all information nesc. for updating the subnet.
1302  *                 junk - an UNUSED boolean.
1303  *      Returns: none.
1304  */
1305
1306 static void RealUpdateSubnet(char **info, Bool junk)
1307 {
1308   int stat;
1309   char **args = AskMCDInfo(info, SUBNET, TRUE);
1310   if (!args)
1311     {
1312       Put_message("Aborted.");
1313       return;
1314     }
1315   if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
1316     com_err(program_name, stat, " in UpdateSubnet.");
1317   else
1318     Put_message("Subnet successfully updated.");
1319 }
1320
1321 /*      Function Name: UpdateSubnet
1322  *      Description: This Function Updates a subnet
1323  *      Arguments: name of the subnet in argv[1].
1324  *      Returns: DM_NORMAL.
1325  */
1326
1327 int UpdateSubnet(int argc, char **argv)
1328 {
1329   struct mqelem *top;
1330   top = GetMCInfo(SUBNET, argv[1], NULL);
1331   QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1332
1333   FreeQueue(top);
1334   return DM_NORMAL;
1335 }
1336
1337 /*      Function Name: RealDeleteSubnet
1338  *      Description: Actually performs the subnet deletion.
1339  *      Arguments: info - all information about this subnet.
1340  *                 one_subnet - If true then there was only one subnet in
1341  *                               the queue, and we should confirm.
1342  *      Returns: none.
1343  */
1344
1345 static void RealDeleteSubnet(char **info, Bool one_subnet)
1346 {
1347   int stat;
1348   char temp_buf[BUFSIZ];
1349
1350   sprintf(temp_buf,
1351           "Are you sure the you want to delete the subnet %s (y/n) ?",
1352           info[C_NAME]);
1353   if (!one_subnet || Confirm(temp_buf))
1354     {
1355       if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
1356         {
1357           com_err(program_name, stat, " in delete_subnet.");
1358           sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
1359           Put_message(temp_buf);
1360         }
1361       else
1362         {
1363           sprintf(temp_buf, "subnet %s successfully deleted.",
1364                   info[C_NAME]);
1365           Put_message(temp_buf);
1366         }
1367     }
1368 }
1369
1370 /*      Function Name: DeleteSubnet
1371  *      Description: This function removes a subnet from the database.
1372  *      Arguments: argc, argv - the name of the subnet is stored in argv[1].
1373  *      Returns: DM_NORMAL.
1374  */
1375
1376 int DeleteSubnet(int argc, char **argv)
1377 {
1378   struct mqelem *top;
1379
1380   top = GetMCInfo(SUBNET, argv[1], NULL);
1381   QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1382
1383   FreeQueue(top);
1384   return DM_NORMAL;
1385 }
1386
1387 /* ---------- Cluster Menu -------- */
1388
1389 /*      Function Name: ShowClusterInfo
1390  *      Description: Gets information about a cluser given its name.
1391  *      Arguments: argc, argc - the name of the cluster in in argv[1].
1392  *      Returns: DM_NORMAL.
1393  */
1394
1395 int ShowClusterInfo(int argc, char **argv)
1396 {
1397   struct mqelem *top;
1398
1399   top = GetMCInfo(CLUSTER, argv[1], NULL);
1400   Loop(top, (void *) PrintClusterInfo);
1401   FreeQueue(top);
1402   return DM_NORMAL;
1403 }
1404
1405 /*      Function Name: AddCluster
1406  *      Description: Creates a new cluster.
1407  *      Arguments: argc, argv - the name of the new cluster is argv[1].
1408  *      Returns: DM_NORMAL.
1409  */
1410
1411 int AddCluster(int argc, char **argv)
1412 {
1413   char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1414   int stat;
1415
1416   /*
1417    * Check to see if this cluster already exists.
1418    */
1419   if (!ValidName(name))
1420     return DM_NORMAL;
1421
1422   if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
1423     {
1424       Put_message("This cluster already exists.");
1425       return DM_NORMAL;
1426     }
1427   else if (stat != MR_NO_MATCH)
1428     {
1429       com_err(program_name, stat, " in AddCluster.");
1430       return DM_NORMAL;
1431     }
1432   if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
1433     {
1434       Put_message("Aborted.");
1435       FreeInfo(info);
1436       return DM_NORMAL;
1437     }
1438
1439   /*
1440    * Actually create the new Cluster.
1441    */
1442   if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
1443     com_err(program_name, stat, " in AddCluster.");
1444
1445   FreeInfo(info);
1446   return DM_NORMAL;
1447 }
1448
1449 /*      Function Name: RealUpdateCluster
1450  *      Description: This function actually performs the cluster update.
1451  *      Arguments: info - all information nesc. for updating the cluster.
1452  *                 junk - an UNUSED boolean.
1453  *      Returns: none.
1454  */
1455
1456 static void RealUpdateCluster(char **info, Bool junk)
1457 {
1458   int stat;
1459   char **args = AskMCDInfo(info, CLUSTER, TRUE);
1460
1461   if (!args)
1462     {
1463       Put_message("Aborted.");
1464       return;
1465     }
1466   if ((stat = do_mr_query("update_cluster", CountArgs(args),
1467                           args, NULL, NULL)))
1468     com_err(program_name, stat, " in UpdateCluster.");
1469   else
1470     Put_message("Cluster successfully updated.");
1471 }
1472
1473 /*      Function Name: UpdateCluster
1474  *      Description: This Function Updates a cluster
1475  *      Arguments: name of the cluster in argv[1].
1476  *      Returns: DM_NORMAL.
1477  */
1478
1479 int UpdateCluster(int argc, char **argv)
1480 {
1481   struct mqelem *top;
1482   top = GetMCInfo(CLUSTER, argv[1], NULL);
1483   QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1484
1485   FreeQueue(top);
1486   return DM_NORMAL;
1487 }
1488
1489 /*      Function Name: CheckAndRemoveMachine
1490  *      Description: This function checks and removes all machines from a
1491  *                   cluster.
1492  *      Arguments: name - name of the cluster.
1493  *                 ask_first - if TRUE, then we will query the user, before
1494  *                             deletion.
1495  *      Returns: SUB_ERROR if all machines not removed.
1496  */
1497
1498 int CheckAndRemoveMachines(char *name, Bool ask_first)
1499 {
1500   int stat, ret_value;
1501   Bool delete_it;
1502   char *args[10], temp_buf[BUFSIZ], *ptr;
1503   struct mqelem *top, *elem = NULL;
1504
1505   ret_value = SUB_NORMAL;
1506   args[MAP_MACHINE] = "*";
1507   args[MAP_CLUSTER] = name;
1508   stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1509   if (stat && stat != MR_NO_MATCH)
1510     {
1511       com_err(program_name, stat, " in get_machine_to_cluster_map.");
1512       return DM_NORMAL;
1513     }
1514   if (stat == MR_SUCCESS)
1515     {
1516       elem = top = QueueTop(elem);
1517       if (ask_first)
1518         {
1519           sprintf(temp_buf, "The cluster %s has the following machines in it:",
1520                   name);
1521           Put_message(temp_buf);
1522           while (elem)
1523             {
1524               char **info = elem->q_data;
1525               Print(1, &info[MAP_MACHINE], (char *) NULL);
1526               elem = elem->q_forw;
1527             }
1528           ptr = "Remove ** ALL ** these machines from this cluster?";
1529
1530           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1531             delete_it = TRUE;
1532           else
1533             {
1534               Put_message("Aborting...");
1535               FreeQueue(top);
1536               return SUB_ERROR;
1537             }
1538         }
1539       else
1540         delete_it = TRUE;
1541
1542       if (delete_it)
1543         {
1544           elem = top;
1545           while (elem)
1546             {
1547               char **info = elem->q_data;
1548               if ((stat = do_mr_query("delete_machine_from_cluster",
1549                                       2, info, NULL, NULL)))
1550                 {
1551                   ret_value = SUB_ERROR;
1552                   com_err(program_name, stat,
1553                           " in delete_machine_from_cluster.");
1554                   sprintf(temp_buf,
1555                           "Machine %s ** NOT ** removed from cluster %s.",
1556                           info[MAP_MACHINE], info[MAP_CLUSTER]);
1557                   Put_message(temp_buf);
1558                 }
1559               elem = elem->q_forw;
1560             }
1561         }
1562     }
1563   return ret_value;
1564 }
1565
1566 /*      Function Name: RealDeleteCluster
1567  *      Description: Actually performs the cluster deletion.
1568  *      Arguments: info - all information about this cluster.
1569  *                 one_cluster - If true then there was only one cluster in
1570  *                               the queue, and we should confirm.
1571  *      Returns: none.
1572  */
1573
1574 static void RealDeleteCluster(char **info, Bool one_cluster)
1575 {
1576   int stat;
1577   char temp_buf[BUFSIZ];
1578
1579   sprintf(temp_buf,
1580           "Are you sure the you want to delete the cluster %s (y/n) ?",
1581           info[C_NAME]);
1582   if (!one_cluster || Confirm(temp_buf))
1583     {
1584       if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
1585         {
1586           if ((stat = do_mr_query("delete_cluster", 1,
1587                                   &info[C_NAME], NULL, NULL)))
1588             {
1589               com_err(program_name, stat, " in delete_cluster.");
1590               sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
1591               Put_message(temp_buf);
1592             }
1593           else
1594             {
1595               sprintf(temp_buf, "cluster %s successfully deleted.",
1596                       info[C_NAME]);
1597               Put_message(temp_buf);
1598             }
1599         }
1600     }
1601 }
1602
1603 /*      Function Name: DeleteCluster
1604  *      Description: This function removes a cluster from the database.
1605  *      Arguments: argc, argv - the name of the cluster is stored in argv[1].
1606  *      Returns: DM_NORMAL.
1607  */
1608
1609 int DeleteCluster(int argc, char **argv)
1610 {
1611   struct mqelem *top;
1612
1613   top = GetMCInfo(CLUSTER, argv[1], NULL);
1614   QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1615
1616   FreeQueue(top);
1617   return DM_NORMAL;
1618 }
1619
1620 /* ----------- Cluster Data Menu -------------- */
1621
1622 /*      Function Name: ShowClusterData
1623  *      Description: This function shows the services for one cluster.
1624  *      Arguments: argc, argv - The name of the cluster is argv[1].
1625  *                              The label of the data in argv[2].
1626  *      Returns: DM_NORMAL.
1627  */
1628
1629 int ShowClusterData(int argc, char **argv)
1630 {
1631   struct mqelem *elem, *top;
1632   char **info;
1633
1634   top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1635   while (elem)
1636     {
1637       info = elem->q_data;
1638       PrintClusterData(info);
1639       elem = elem->q_forw;
1640     }
1641   FreeQueue(top);
1642   return DM_NORMAL;
1643 }
1644
1645 /*      Function Name: AddClusterData
1646  *      Description: This function adds some data to the cluster.
1647  *      Arguments: argv, argc:   argv[1] - the name of the cluster.
1648  *                               argv[2] - the label of the data.
1649  *                               argv[3] - the data.
1650  *      Returns: DM_NORMAL.
1651  */
1652
1653 int AddClusterData(int argc, char **argv)
1654 {
1655   int stat;
1656
1657   if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
1658     com_err(program_name, stat, " in AddClusterData.");
1659   return DM_NORMAL;
1660 }
1661
1662 /*      Function Name: RealRemoveClusterData
1663  *      Description: actually removes the cluster data.
1664  *      Arguments: info - all info necessary to remove the cluster, in an array
1665  *                        of strings.
1666  *                 one_item - if true then the queue has only one elem and we
1667  *                            should confirm.
1668  *      Returns: none.
1669  */
1670
1671 static void RealRemoveClusterData(char **info, Bool one_item)
1672 {
1673   int stat;
1674   char *temp_ptr;
1675
1676   Put_message(" ");
1677   temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1678   PrintClusterData(info);
1679   if (!one_item || Confirm(temp_ptr))
1680     {
1681       if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
1682         {
1683           com_err(program_name, stat, " in DeleteClusterData.");
1684           Put_message("Data not removed.");
1685         }
1686       else
1687         Put_message("Removal successful.");
1688     }
1689 }
1690
1691 /*      Function Name: RemoveClusterData
1692  *      Description: This function removes data on a given cluster.
1693  *      Arguments: argv, argc:   argv[1] - the name of the cluster.
1694  *                               argv[2] - the label of the data.
1695  *                               argv[3] - the data.
1696  *      Returns: DM_NORMAL.
1697  */
1698
1699 int RemoveClusterData(int argc, char **argv)
1700 {
1701   struct mqelem *top;
1702
1703   top = GetMCInfo(DATA, argv[1], argv[2]);
1704   QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1705             "Remove data from cluster");
1706
1707   FreeQueue(top);
1708   return DM_NORMAL;
1709 }
1710
1711 /*      Function Name: MachineToClusterMap
1712  *      Description: This Retrieves the mapping between machine and cluster
1713  *      Arguments: argc, argv - argv[1] -> machine name or wildcard.
1714  *                              argv[2] -> cluster name or wildcard.
1715  *      Returns: none.
1716  */
1717
1718 int MachineToClusterMap(int argc, char **argv)
1719 {
1720   struct mqelem *elem, *top;
1721   char *tmpname, temp_buf[256];
1722
1723   tmpname = canonicalize_hostname(strdup(argv[1]));
1724   if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
1725     {
1726       sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1727               argv[1], tmpname);
1728       Put_message(temp_buf);
1729     }
1730   top = elem = GetMCInfo(MAP, tmpname, argv[2]);
1731
1732   Put_message("");              /* blank line on screen */
1733   while (elem)
1734     {
1735       char **info = elem->q_data;
1736       PrintMCMap(info);
1737       elem = elem->q_forw;
1738     }
1739
1740   FreeQueue(top);
1741   free(tmpname);
1742   return DM_NORMAL;
1743 }
This page took 0.257085 seconds and 5 git commands to generate.