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