]> andersk Git - moira.git/blob - clients/moira/cluster.c
Non void function should actually return something. Thank you, Irix cc.
[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 #include <mrclient.h>
21
22 #include "defs.h"
23 #include "f_defs.h"
24 #include "globals.h"
25
26 #include <sys/types.h>
27
28 #ifdef HAVE_UNAME
29 #include <sys/utsname.h>
30 #endif
31
32 #ifndef _WIN32
33 #include <netinet/in.h>
34 #include <arpa/inet.h>
35 #include <netdb.h>
36 #endif /* _WIN32 */
37
38 #include <ctype.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42
43 void PrintAliases(char **info);
44 static void PrintMachine(char **info);
45 struct mqelem *GetMCInfo(int type, char *name1, char *name2);
46 struct mqelem *GetMachineByOwner(char *type, char *name);
47 char **AskMCDInfo(char **info, int type, Bool name);
48 int CheckAndRemoveFromCluster(char *name, Bool ask_user);
49 int CheckAndRemoveCnames(char *name, Bool ask_user);
50 int CheckAndRemoveMachines(char *name, Bool ask_first);
51
52 static char *PrintContainerInfo(char **info);
53 static void RealUpdateContainer(char **info, Bool junk);
54 static void RealDeleteContainer(char **info, Bool one_container);
55 static void RealRemoveMachineFromContainer(char **info, Bool one_contmap);
56
57 #define MACHINE   0
58 #define CLUSTER   1
59 #define DATA      2
60 #define MAP       3
61 #define SUBNET    4
62 #define CNAME     5
63 #define CONTAINER 6
64 #define CONTMAP   7
65
66 #define M_DEFAULT_TYPE     DEFAULT_NONE
67
68 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
69 #define C_DEFAULT_LOCATION DEFAULT_NONE
70
71 #define CON_DEFAULT_TYPE   DEFAULT_NONE
72
73 #define CD_DEFAULT_LABEL   DEFAULT_NONE
74 #define CD_DEFAULT_DATA    DEFAULT_NONE
75
76 #define S_DEFAULT_LOW   "18.0.0.20"
77 #define S_DEFAULT_HIGH  "18.0.2.249"
78
79 static char *states[] = {
80   "Reserved (0)",
81   "Active (1)",
82   "None (2)",
83   "Deleted (3)"
84 };
85
86 static char *MacState(int state)
87 {
88   static char buf[BUFSIZ];
89
90   if (state < 0 || state > 3)
91     {
92       sprintf(buf, "Unknown (%d)", state);
93       return buf;
94     }
95   return states[state];
96 }
97
98
99
100 /* -------------------- Set Defaults -------------------- */
101
102 /*      Function Name: SetMachineDefaults
103  *      Description: sets machine defaults.
104  *      Arguments: info - an array to put the defaults into.
105  *                 name - Canonacalized name of the machine.
106  *      Returns: info - the array.
107  */
108
109 static char **SetMachineDefaults(char **info, char *name)
110 {
111   info[M_NAME] = strdup(name);
112   info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
113   info[M_MODEL] = strdup(M_DEFAULT_TYPE);
114   info[M_OS] = strdup(M_DEFAULT_TYPE);
115   info[M_LOC] = strdup(M_DEFAULT_TYPE);
116   info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
117   info[M_BILL_CONTACT] = strdup(M_DEFAULT_TYPE);
118   info[M_USE] = strdup("0");
119   info[M_STAT] = strdup("1");
120   info[M_SUBNET] = strdup("NONE");
121   info[M_ADDR] = strdup("unique");
122   info[M_OWNER_TYPE] = strdup("NONE");
123   info[M_OWNER_NAME] = strdup("NONE");
124   info[M_ACOMMENT] = strdup("");
125   info[M_OCOMMENT] = strdup("");
126   info[16] = info[17] = NULL;
127   return info;
128 }
129
130 /*      Function Name: SetClusterDefaults
131  *      Description: sets Cluster defaults.
132  *      Arguments: info - an array to put the defaults into.
133  *                 name - name of the Cluster.
134  *      Returns: info - the array.
135  */
136
137 static char **SetClusterDefaults(char **info, char *name)
138 {
139   info[C_NAME] = strdup(name);
140   info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
141   info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
142   info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
143   return info;
144 }
145
146 static char **SetContainerDefaults(char **info, char *name)
147 {
148   info[CON_NAME] = strdup(name);
149   info[CON_DESCRIPT] = strdup(CON_DEFAULT_TYPE);
150   info[CON_LOCATION] = strdup(CON_DEFAULT_TYPE);
151   info[CON_CONTACT] = strdup(CON_DEFAULT_TYPE);
152   info[CON_OWNER_TYPE] = strdup("NONE");
153   info[CON_OWNER_NAME] = strdup("NONE");
154   info[CON_MEMACE_TYPE] = strdup("NONE");
155   info[CON_MEMACE_NAME] = strdup("NONE");
156   info[CON_MODBY] = info[CON_MODTIME] = info[CON_MODWITH] = NULL;
157   info[CON_END] = NULL;
158   return info;
159 }
160
161 /*      Function Name: SetSubnetDefaults
162  *      Description: sets Subnet defaults.
163  *      Arguments: info - an array to put the defaults into.
164  *                 name - name of the Subnet.
165  *      Returns: info - the array.
166  */
167
168 static char **SetSubnetDefaults(char **info, char *name)
169 {
170   char buf[256];
171
172   info[C_NAME] = strdup(name);
173   info[SN_DESC] = strdup("");
174   sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
175   info[SN_ADDRESS] = strdup(buf);
176   sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
177   info[SN_MASK] = strdup(buf);
178   sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
179   info[SN_LOW] = strdup(buf);
180   sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
181   info[SN_HIGH] = strdup(buf);
182   info[SN_PREFIX] = strdup("");
183   info[SN_ACE_TYPE] = strdup("LIST");
184   info[SN_ACE_NAME] = strdup("network");
185   info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
186   return info;
187 }
188
189 /* -------------------- General Functions -------------------- */
190
191 static char aliasbuf[256];
192
193 void PrintAliases(char **info)
194 {
195   if (strlen(aliasbuf) == 0)
196     sprintf(aliasbuf, "Aliases:  %s", info[0]);
197   else
198     {
199       strcat(aliasbuf, ", ");
200       strcat(aliasbuf, info[0]);
201     }
202 }
203
204
205 /*      Function Name: PrintMachInfo
206  *      Description: This function Prints out the Machine info in
207  *                   a coherent form.
208  *      Arguments: info - array of information about a machine.
209  *      Returns: The name of the Machine
210  */
211
212 static char *PrintMachInfo(char **info)
213 {
214   char buf[BUFSIZ], tbuf[256];
215   char *args[3];
216   struct mqelem *elem = NULL;
217   int stat;
218
219   Put_message("");
220   sprintf(buf, "Machine:  %s", info[M_NAME]);
221   Put_message(buf);
222   args[0] = "*";
223   args[1] = info[M_NAME];
224   if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
225     {
226       if (stat != MR_NO_MATCH)
227         com_err(program_name, stat, " looking up aliases");
228     }
229   else
230     {
231       aliasbuf[0] = 0;
232       Loop(QueueTop(elem), (void (*)(char **)) PrintAliases);
233       FreeQueue(elem);
234       Put_message(aliasbuf);
235     }
236   sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
237           strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
238   sprintf(buf, "Address:  %-16s    Network:    %-16s",
239           info[M_ADDR], info[M_SUBNET]);
240   Put_message(buf);
241   sprintf(buf, "Owner:    %-16s    Use data:   %s", tbuf, info[M_INUSE]);
242   Put_message(buf);
243   sprintf(buf, "Status:   %-16s    Changed:    %s",
244           MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
245   Put_message(buf);
246   Put_message("");
247
248   sprintf(buf, "Vendor:   %-16s    Location:        %s", info[M_VENDOR], 
249           info[M_LOC]);
250   Put_message(buf);
251   sprintf(buf, "Model:    %-16s    Contact:         %s", info[M_MODEL], 
252           info[M_CONTACT]);
253   Put_message(buf);
254   sprintf(buf, "OS:       %-16s    Billing Contact: %s", info[M_OS],
255           info[M_BILL_CONTACT]);
256   Put_message(buf);
257   Put_message("");
258   sprintf(buf, "Opt: %s", info[M_USE]);
259   Put_message(buf);
260   Put_message("");
261   sprintf(buf, "Adm cmt: %s", info[M_ACOMMENT]);
262   Put_message(buf);
263   sprintf(buf, "Op cmt:  %s", info[M_OCOMMENT]);
264   Put_message(buf);
265   Put_message("");
266   sprintf(buf, "Created  by %s on %s", info[M_CREATOR], info[M_CREATED]);
267   Put_message(buf);
268   sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
269   Put_message(buf);
270   return info[M_NAME];
271 }
272
273 /*      Function Name: PrintMachine
274  *      Description: Prints the name of a machine record
275  *      Arguments: info - array of information about the machine.
276  *      Returns: nothing.
277  */
278
279 static void PrintMachine(char **info)
280 {
281      char buf[BUFSIZ];
282
283      sprintf(buf, "Machine: %s", info[M_NAME]);
284      Put_message(buf);
285 }
286
287 /*      Function Name: PrintCname
288  *      Description: Prints the Data on a host alias
289  *      Arguments: info a pointer to the data array.
290  *      Returns: The name of the alias.
291  */
292
293 static char *PrintCname(char **info)
294 {
295   char buf[BUFSIZ];
296
297   sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
298   Put_message(buf);
299   return info[0];
300 }
301
302 /*      Function Name: PrintClusterInfo
303  *      Description: This function Prints out the cluster info
304  *                   in a coherent form.
305  *      Arguments: info - array of information about a cluster.
306  *      Returns: The name of the cluster.
307  */
308
309 static char *PrintClusterInfo(char **info)
310 {
311   char buf[BUFSIZ];
312
313   Put_message("");
314   sprintf(buf, "Cluster:     %s", info[C_NAME]);
315   Put_message(buf);
316   sprintf(buf, "Description: %s", info[C_DESCRIPT]);
317   Put_message(buf);
318   sprintf(buf, "Location:    %s", info[C_LOCATION]);
319   Put_message(buf);
320   sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
321   Put_message(buf);
322   return info[C_NAME];
323 }
324
325 /*      Function Name: PrintClusterData
326  *      Description: Prints the Data on a cluster
327  *      Arguments: info a pointer to the data array.
328  *      Returns: The name of the cluster.
329  */
330
331 static char *PrintClusterData(char **info)
332 {
333   char buf[BUFSIZ];
334
335   Put_message("");
336   sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
337           info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
338   Put_message(buf);
339   return info[CD_NAME];
340 }
341
342 /*      Function Name: PrintMCMap
343  *      Description: Prints the data about a machine to cluster mapping.
344  *      Arguments: info a pointer to the data array.
345  *      Returns: none
346  */
347
348 static char *PrintMCMap(char **info)
349 {
350   char buf[BUFSIZ];
351   sprintf(buf, "Cluster: %-30s Machine: %-20s",
352           info[MAP_CLUSTER], info[MAP_MACHINE]);
353   Put_message(buf);
354   return "";                    /* Used by QueryLoop(). */
355 }
356
357 /*      Function Name: PrintSubnetInfo
358  *      Description: This function Prints out the subnet info
359  *                   in a coherent form.
360  *      Arguments: info - array of information about a subnet.
361  *      Returns: The name of the subnet.
362  */
363
364 static char *PrintSubnetInfo(char **info)
365 {
366   char buf[BUFSIZ];
367   struct in_addr addr, mask, low, high;
368
369   Put_message("");
370   sprintf(buf, "        Network:  %s", info[SN_NAME]);
371   Put_message(buf);
372   sprintf(buf, "    Description:  %s", info[SN_DESC]);
373   Put_message(buf);
374   addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
375   mask.s_addr = htonl(atoi(info[SN_MASK]));
376   low.s_addr = htonl(atoi(info[SN_LOW]));
377   high.s_addr = htonl(atoi(info[SN_HIGH]));
378   /* screwy sequence is here because inet_ntoa returns a pointer to
379      a static buf.  If it were all one sprintf, the last value would
380      appear 4 times. */
381   sprintf(buf, "        Address:  %s        Mask:  ", inet_ntoa(addr));
382   strcat(buf, inet_ntoa(mask));
383   strcat(buf, "\n           High:  ");
384   strcat(buf, inet_ntoa(high));
385   strcat(buf, "       Low:  ");
386   strcat(buf, inet_ntoa(low));
387   Put_message(buf);
388   sprintf(buf, "Hostname prefix:  %s", info[SN_PREFIX]);
389   Put_message(buf);
390   sprintf(buf, "          Owner:  %s %s\n", info[SN_ACE_TYPE],
391           strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
392   Put_message(buf);
393   sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
394   Put_message(buf);
395   return info[SN_NAME];
396 }
397
398 /*      Function Name: GetMCInfo.
399  *      Description: This function stores info about a machine.
400  *                   type - type of data we are trying to retrieve.
401  *                   name1 - the name of argv[0] for the call.
402  *                   name2 - the name of argv[1] for the call.
403  *      Returns: the top element of a queue containing the data or NULL.
404  */
405
406 struct mqelem *GetMCInfo(int type, char *name1, char *name2)
407 {
408   int stat;
409   struct mqelem *elem = NULL;
410   char *args[5];
411
412   switch (type)
413     {
414     case MACHINE:
415       args[0] = name1;
416       args[1] = args[2] = args[3] = "*";
417       if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
418         {
419           if (stat == MR_NO_MATCH)
420             {
421               char buf[128];
422               sprintf(buf, "Machine '%s' is not in the database.", name1);
423               Put_message(buf);
424             }
425           else
426             com_err(program_name, stat, " in get_machine.");
427           return NULL;
428         }
429       break;
430     case CNAME:
431       args[0] = name1;
432       args[1] = name2;
433       if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
434         {
435           com_err(program_name, stat, " in get_hostalias.");
436           return NULL;
437         }
438       break;
439     case SUBNET:
440       if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
441         {
442           if (stat == MR_NO_MATCH)
443             {
444               char buf[128];
445               sprintf(buf, "Network '%s' is not in the database.", name1);
446               Put_message(buf);
447             }
448           else
449             com_err(program_name, stat, " in get_subnet.");
450           return NULL;
451         }
452       break;
453     case CLUSTER:
454       if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
455         {
456           com_err(program_name, stat, " in get_cluster.");
457           return NULL;
458         }
459       break;
460     case MAP:
461       args[MAP_MACHINE] = name1;
462       args[MAP_CLUSTER] = name2;
463       if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
464                               StoreInfo, &elem)))
465         {
466           com_err(program_name, stat, " in get_machine_to_cluster_map.");
467           return NULL;
468         }
469       break;
470     case DATA:
471       args[CD_NAME] = name1;
472       args[CD_LABEL] = name2;
473       if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
474         {
475           com_err(program_name, stat, " in get_cluster_data.");
476           return NULL;
477         }
478       break;
479     case CONTAINER:
480       args[CON_NAME] = name1;
481       if ((stat = do_mr_query("get_container", 1, &name1, StoreInfo, &elem)))
482         {
483           com_err(program_name, stat, " in get_container.");
484           return NULL;
485         }
486       break;
487     case CONTMAP:
488       args[0] = name1;
489       if ((stat = do_mr_query("get_machine_to_container_map", 1, &name1,
490                               StoreInfo, &elem)))
491         {
492           com_err(program_name, stat, " in get_machine_to_container_map.");
493           return NULL;
494         }
495     }
496   return QueueTop(elem);
497 }
498
499 /*      Function Name: AskMCDInfo.
500  *      Description: This function askes the user for information about a
501  *                   machine and saves it into a structure.
502  *      Arguments: info - a pointer the information to ask about
503  *                 type - type of information - MACHINE
504  *                                              CLUSTER
505  *                                              DATA
506  *                                              CONTAINER
507  *                 name - T/F : change the name of this type.
508  *      Returns: none.
509  */
510
511 char **AskMCDInfo(char **info, int type, Bool name)
512 {
513   char temp_buf[BUFSIZ], *newname, *oldnewname;
514
515   switch (type)
516     {
517     case MACHINE:
518       sprintf(temp_buf, "\nSetting the information for the Machine %s...",
519               info[M_NAME]);
520       break;
521     case SUBNET:
522       sprintf(temp_buf, "Setting the information for the Network %s...",
523               info[SN_NAME]);
524       break;
525     case CLUSTER:
526       sprintf(temp_buf, "Setting the information for the Cluster %s...",
527               info[C_NAME]);
528       break;
529     case DATA:
530       sprintf(temp_buf, "Setting the Data for the Cluster %s...",
531               info[CD_NAME]);
532       break;
533     case CONTAINER:
534       sprintf(temp_buf, "Setting the Data for the Container %s...",
535               info[CON_NAME]);
536       break;
537     }
538   Put_message(temp_buf);
539
540   if (name)
541     {
542       switch (type)
543         {
544         case MACHINE:
545           newname = strdup(info[M_NAME]);
546           if (GetValueFromUser("The new name for this machine? ", &newname) ==
547               SUB_ERROR)
548             return NULL;
549           oldnewname = strdup(newname);
550           newname = canonicalize_hostname(newname);
551           if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
552             {
553               sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
554                       oldnewname, newname);
555               Put_message(temp_buf);
556             }
557           free(oldnewname);
558           break;
559         case SUBNET:
560           newname = strdup(info[SN_NAME]);
561           if (GetValueFromUser("The new name for this network? ", &newname) ==
562               SUB_ERROR)
563             return NULL;
564           break;
565         case CLUSTER:
566           newname = strdup(info[C_NAME]);
567           if (GetValueFromUser("The new name for this cluster? ", &newname) ==
568               SUB_ERROR)
569             return NULL;
570           break;
571         case CONTAINER:
572           newname = strdup(info[CON_NAME]);
573           if (GetValueFromUser("The new name for this container? ", &newname)
574               == SUB_ERROR)
575             return NULL;
576           break;
577         default:
578           Put_message("Unknown type in AskMCDInfo, programmer botch");
579           return NULL;
580         }
581     }
582
583   switch (type)
584     {
585     case MACHINE:
586       if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
587         return NULL;
588       if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
589         return NULL;
590       if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
591           SUB_ERROR)
592         return NULL;
593       if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
594         return NULL;
595       if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
596           SUB_ERROR)
597         return NULL;
598       if (GetValueFromUser("Machine's billing contact", 
599                            &info[M_BILL_CONTACT]) == SUB_ERROR)
600         return NULL;
601       while (1)
602         {
603           int i;
604           if (GetValueFromUser("Machine's status (? for help)",
605                                  &info[M_STAT]) == SUB_ERROR)
606             return NULL;
607           if (isdigit(info[M_STAT][0]))
608             break;
609           Put_message("Valid status numbers:");
610           for (i = 0; i < 4; i++)
611             Put_message(states[i]);
612         }
613
614       /* there appears to be some argument mismatch between the client
615        * and the server.. so here is this argument shuffler.
616        * I have since modified this to always shuffle the arguments..
617        * not just do so when performing a modify all fields request.
618        * The SetMachinedefaults() has been changed to reflect this.
619        * pray for us and may we attain enlightenment through structures.
620        */
621
622       if (name)
623         {
624           /* info did not come from SetMachineDefaults(), which does not
625            * initialize entry 8 (M_STAT_CHNG), therefore we can
626            * free it.
627            */
628           /* This is an update of an existing machine and the structure
629            * was filled in thru a query to the db which does fill in this
630            * field.
631            */
632           free(info[9]);
633         }
634
635       info[9] = info[M_SUBNET];
636       info[10] = info[M_ADDR];
637       info[11] = info[M_OWNER_TYPE];
638       info[12] = info[M_OWNER_NAME];
639       info[13] = info[M_ACOMMENT];
640       info[14] = info[M_OCOMMENT];
641
642       if (name)
643         {
644           if (GetValueFromUser("Machine's network (or 'none')", &info[9])
645               == SUB_ERROR)
646             return NULL;
647         }
648       if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
649                            &info[10]) == SUB_ERROR)
650         return NULL;
651       if (GetTypeFromUser("Machine's owner type", "ace_type", &info[11]) ==
652           SUB_ERROR)
653         return NULL;
654       if (strcmp(info[11], "NONE") &&
655           GetValueFromUser("Owner's Name", &info[12]) == SUB_ERROR)
656         return NULL;
657       if (!strcmp(info[11], "KERBEROS"))
658           {
659             char *canon;
660
661             mrcl_validate_kerberos_member(info[12], &canon);
662             if (mrcl_get_message())
663               Put_message(mrcl_get_message());
664             free(info[12]);
665             info[12] = canon;
666           }
667       if (GetValueFromUser("Administrative comment", &info[13]) == SUB_ERROR)
668         return NULL;
669       if (GetValueFromUser("Operational comment", &info[14]) == SUB_ERROR)
670         return NULL;
671       info[15] = NULL;
672       FreeAndClear(&info[16], TRUE);
673       FreeAndClear(&info[17], TRUE);
674       break;
675     case SUBNET:
676       if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
677         return NULL;
678       if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
679         return NULL;
680       if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
681         return NULL;
682       if (atoi(info[SN_LOW]) == (int)ntohl(inet_addr(S_DEFAULT_LOW)))
683         {
684           struct in_addr low;
685           unsigned long mask, addr;
686
687           addr = atoi(info[SN_ADDRESS]);
688           mask = atoi(info[SN_MASK]);
689           low.s_addr = atoi(info[SN_LOW]);
690           low.s_addr = (low.s_addr & ~mask) | (addr & mask);
691           free(info[SN_LOW]);
692           sprintf(temp_buf, "%ld", low.s_addr);
693           info[SN_LOW] = strdup(temp_buf);
694         }
695       if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
696           SUB_ERROR)
697         return NULL;
698       if (atoi(info[SN_HIGH]) == (int)ntohl(inet_addr(S_DEFAULT_HIGH)))
699         {
700           struct in_addr high;
701           unsigned long mask, addr;
702
703           addr = atoi(info[SN_ADDRESS]);
704           mask = atoi(info[SN_MASK]);
705           high.s_addr = atoi(info[SN_HIGH]);
706           high.s_addr = (high.s_addr & ~mask) | (addr & mask);
707           free(info[SN_HIGH]);
708           sprintf(temp_buf, "%ld", high.s_addr);
709           info[SN_HIGH] = strdup(temp_buf);
710         }
711       if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
712           SUB_ERROR)
713         return NULL;
714       if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
715         return NULL;
716       if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
717           SUB_ERROR)
718         return NULL;
719       if (strcmp(info[SN_ACE_TYPE], "NONE") &&
720           GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
721         return NULL;
722       if (!strcmp(info[SN_ACE_TYPE], "KERBEROS"))
723           {
724             char *canon;
725
726             mrcl_validate_kerberos_member(info[SN_ACE_NAME], &canon);
727             if (mrcl_get_message())
728               Put_message(mrcl_get_message());
729             free(info[SN_ACE_NAME]);
730             info[SN_ACE_NAME] = canon;
731           }
732       FreeAndClear(&info[SN_MODTIME], TRUE);
733       FreeAndClear(&info[SN_MODBY], TRUE);
734       FreeAndClear(&info[SN_MODWITH], TRUE);
735       break;
736     case CLUSTER:
737       if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
738           SUB_ERROR)
739         return NULL;
740       if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
741           SUB_ERROR)
742         return NULL;
743       FreeAndClear(&info[C_MODTIME], TRUE);
744       FreeAndClear(&info[C_MODBY], TRUE);
745       FreeAndClear(&info[C_MODWITH], TRUE);
746       break;
747     case DATA:
748       if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
749           SUB_ERROR)
750         return NULL;
751       if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
752         return NULL;
753       break;
754     case CONTAINER:
755       if (GetValueFromUser("Container's Description:", &info[CON_DESCRIPT]) ==
756           SUB_ERROR)
757         return NULL;
758       if (GetValueFromUser("Container's Location:", &info[CON_LOCATION]) ==
759           SUB_ERROR)
760         return NULL;
761       if (GetValueFromUser("Container's Contact:", &info[CON_CONTACT]) == 
762           SUB_ERROR)
763         return NULL;
764       if (GetTypeFromUser("Container's owner type", "ace_type", 
765                           &info[CON_OWNER_TYPE]) == SUB_ERROR)
766         return NULL;
767       if (strcmp(info[CON_OWNER_TYPE], "NONE") &&
768           GetValueFromUser("Owner's Name", &info[CON_OWNER_NAME]) == SUB_ERROR)
769         return NULL;
770       if (!strcmp(info[CON_OWNER_TYPE], "KERBEROS"))
771         {
772           char *canon;
773
774           mrcl_validate_kerberos_member(info[CON_OWNER_NAME], &canon);
775           if (mrcl_get_message())
776             Put_message(mrcl_get_message());
777           free(info[CON_OWNER_NAME]);
778           info[CON_OWNER_NAME] = canon;
779         }
780       if (GetTypeFromUser("Container's Membership ACL", "ace_type",
781                           &info[CON_MEMACE_TYPE]) == SUB_ERROR)
782         return NULL;
783       if (strcmp(info[CON_MEMACE_TYPE], "NONE") &&
784           GetValueFromUser("Membership ACL", &info[CON_MEMACE_NAME])
785           == SUB_ERROR)
786         return NULL;
787       if (!strcmp(info[CON_MEMACE_TYPE], "KERBEROS"))
788         {
789           char *canon;
790
791           mrcl_validate_kerberos_member(info[CON_MEMACE_NAME], &canon);
792           if (mrcl_get_message())
793             Put_message(mrcl_get_message());
794           free(info[CON_MEMACE_NAME]);
795           info[CON_MEMACE_NAME] = canon;
796         }
797       FreeAndClear(&info[CON_MODTIME], TRUE);
798       FreeAndClear(&info[CON_MODBY], TRUE);
799       FreeAndClear(&info[CON_MODWITH], TRUE);
800       break;
801     }
802
803   /*
804    * Slide the newname into the #2 slot, this screws up all future references
805    * to this list.
806    */
807   if (name)
808     SlipInNewName(info, newname);
809
810   return info;
811 }
812
813 /* -----------  Machine Menu ----------- */
814
815 /*      Function Name: ShowMachineInfo
816  *      Description: This function shows the information about a machine.
817  *      Arguments: argc, argv - the name of the machine in argv[1].
818  *      Returns: DM_NORMAL.
819  */
820
821 int ShowMachineInfo(int argc, char **argv)
822 {
823   struct mqelem *top;
824   char *tmpname;
825
826   tmpname = canonicalize_hostname(strdup(argv[1]));
827   top = GetMCInfo(MACHINE, tmpname, NULL);
828   Loop(top, ((void (*)(char **)) PrintMachInfo));
829   FreeQueue(top);
830   return DM_NORMAL;
831 }
832
833 /*      Function Name: ShowMachineQuery
834  *      Description: This function shows the information about a machine.
835  *              or group of machines, which may be selected through a
836  *              number of criteria.
837  *      Arguments: argc, argv - the name of the machine in argv[1],
838  *              the address of the machine in argv[2],
839  *              the location of the machine in argv[3],
840  *              and the contact name in argv[4].
841  *           any of these may be wildcards.
842  *      Returns: DM_NORMAL.
843  */
844
845 int ShowMachineQuery(int argc, char **argv)
846 {
847   int stat;
848   struct mqelem *top, *elem = NULL;
849   char *args[5];
850
851   if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
852       !strcmp(argv[3], "") && !strcmp(argv[4], ""))
853     {
854       Put_message("You must specify at least one parameter of the query.");
855       return DM_NORMAL;
856     }
857
858   if (*argv[1])
859     args[0] = canonicalize_hostname(strdup(argv[1]));
860   else
861     args[0] = "*";
862   if (*argv[2])
863     args[1] = argv[2];
864   else
865     args[1] = "*";
866   if (*argv[3])
867     args[2] = argv[3];
868   else
869     args[2] = "*";
870   if (*argv[4])
871     args[3] = argv[4];
872   else
873     args[3] = "*";
874
875   if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
876     {
877       if (stat == MR_NO_MATCH)
878         Put_message("No machine(s) found matching query in the database.");
879       else
880         com_err(program_name, stat, " in get_machine.");
881       return DM_NORMAL;
882     }
883   top = QueueTop(elem);
884   Loop(top, ((void (*)(char **)) PrintMachInfo));
885   FreeQueue(top);
886   return DM_NORMAL;
887 }
888
889 /*      Function Name: AddMachine
890  *      Description: This function adds a new machine to the database.
891  *      Arguments: argc, argv - the name of the network in argv[1].
892  *      Returns: DM_NORMAL.
893  */
894
895 int AddMachine(int argc, char **argv)
896 {
897   char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
898   char **rinfo;
899   struct mqelem *elem = NULL;
900   int stat;
901
902   if (!ValidName(argv[1]))      /* Checks for wildcards. */
903     return DM_NORMAL;
904
905   /*
906    * get the network record
907    */
908
909   if (strcasecmp(argv[1], "none") &&
910       (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
911     {
912       if (stat == MR_NO_MATCH)
913         {
914           char buf[128];
915           sprintf(buf, "Network '%s' is not in the database.", argv[1]);
916           Put_message(buf);
917         } else
918           com_err(program_name, stat, " in get_subnet.");
919       return DM_NORMAL;
920     }
921
922   /*
923    * Check to see if this machine already exists.
924    */
925
926   name = strdup(""); /* want to put prefix here */
927   if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
928     return 0;
929
930   name = canonicalize_hostname(strdup(name));
931
932   xargs[0] = name;
933   xargs[1] = xargs[2] = xargs[3] = "*";
934   if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
935     {
936       sprintf(buf, "The machine '%s' already exists.", name);
937       Put_message(buf);
938       free(name);
939       return DM_NORMAL;
940     }
941   else if (stat != MR_NO_MATCH)
942     {
943       com_err(program_name, stat,
944               " while checking machine '%s' in AddMachine.", name);
945       free(name);
946       return DM_NORMAL;
947     }
948   rinfo = SetMachineDefaults(info, name);
949   rinfo[M_SUBNET] = strdup(argv[1]);
950   if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
951     {
952       Put_message("Aborted.");
953       return DM_NORMAL;
954     }
955
956   /*
957    * Actually create the new Machine.
958    */
959
960   if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
961     com_err(program_name, stat, " in AddMachine.");
962
963   FreeInfo(info);
964   free(name);
965   return DM_NORMAL;
966 }
967
968 /*      Function Name: RealUpdateMachine
969  *      Description: Performs the actual update of the machine data.
970  *      Arguments: info - the information on the machine to update.
971  *                 junk - an UNUSED Boolean.
972  *      Returns: none.
973  */
974
975 static void RealUpdateMachine(char **info, Bool junk)
976 {
977   int stat;
978   char **args = AskMCDInfo(info, MACHINE, TRUE);
979   if (!args)
980     {
981       Put_message("Aborted.");
982       return;
983     }
984   if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
985     com_err(program_name, stat, " in UpdateMachine.");
986   else
987     Put_message("Machine successfully updated.");
988 }
989
990 /*      Function Name: UpdateMachine
991  *      Description: This function adds a new machine to the database.
992  *      Arguments: argc, argv - the name of the machine in argv[1].
993  *      Returns: DM_NORMAL.
994  */
995
996 int UpdateMachine(int argc, char **argv)
997 {
998   struct mqelem *top;
999   char *tmpname;
1000
1001   tmpname = canonicalize_hostname(strdup(argv[1]));
1002   top = GetMCInfo(MACHINE, tmpname, NULL);
1003   QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
1004
1005   FreeQueue(top);
1006   free(tmpname);
1007   return DM_NORMAL;
1008 }
1009
1010 /*      Function Name: CheckAndRemoveFromCluster
1011  *      Description: This func tests to see if a machine is in a cluster.
1012  *                   and if so then removes it
1013  *      Arguments: name - name of the machine (already Canonicalized).
1014  *                 ask_user- query the user before removing if from clusters?
1015  *      Returns: MR_ERROR if machine left in a cluster, or mr_error.
1016  */
1017
1018 int CheckAndRemoveFromCluster(char *name, Bool ask_user)
1019 {
1020   int stat, ret_value;
1021   Bool delete_it;
1022   char *args[10], temp_buf[BUFSIZ], *ptr;
1023   struct mqelem *top, *elem = NULL;
1024
1025   ret_value = SUB_NORMAL;       /* initialize ret_value. */
1026   args[0] = name;
1027   args[1] = "*";
1028   stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1029   if (stat && stat != MR_NO_MATCH)
1030     {
1031       com_err(program_name, stat, " in get_machine_to_cluster_map.");
1032       return DM_NORMAL;
1033     }
1034   if (stat == MR_SUCCESS)
1035     {
1036       elem = top = QueueTop(elem);
1037       if (ask_user)
1038         {
1039           sprintf(temp_buf, "%s is assigned to the following clusters.", name);
1040           Put_message(temp_buf);
1041           Loop(top, (void (*)(char **)) PrintMCMap);
1042           ptr = "Remove this machine from ** ALL ** these clusters?";
1043           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1044             delete_it = TRUE;
1045           else
1046             {
1047               Put_message("Aborting...");
1048               FreeQueue(top);
1049               return SUB_ERROR;
1050             }
1051         }
1052       else
1053         delete_it = TRUE;
1054
1055       if (delete_it)
1056         {
1057           while (elem)
1058             {
1059               char **info = elem->q_data;
1060               if ((stat = do_mr_query("delete_machine_from_cluster",
1061                                        2, info, NULL, NULL)))
1062                 {
1063                   ret_value = SUB_ERROR;
1064                   com_err(program_name, stat,
1065                           " in delete_machine_from_cluster.");
1066                   sprintf(temp_buf,
1067                           "Machine %s ** NOT ** removed from cluster %s.",
1068                           info[MAP_MACHINE], info[MAP_CLUSTER]);
1069                   Put_message(temp_buf);
1070                 }
1071               elem = elem->q_forw;
1072             }
1073         }
1074     }
1075   return ret_value;
1076 }
1077
1078 /*      Function Name: CheckAndRemoveCnames
1079  *      Description: This func tests to see if a machine has cnames, 
1080  *                   and if so then removes them.
1081  *      Arguments: name - name of the machine (already Canonicalized).
1082  *                 ask_user- query the user before removing cnames?
1083  *      Returns: MR_ERROR if machine left with a cname, or mr_error.
1084  */
1085
1086 int CheckAndRemoveCnames(char *name, Bool ask_user)
1087 {
1088   int stat, ret_value;
1089   Bool delete_it;
1090   char *args[10], temp_buf[BUFSIZ], *ptr;
1091   struct mqelem *top, *elem = NULL;
1092
1093   ret_value = SUB_NORMAL;
1094   args[0] = "*";
1095   args[1] = name;
1096   stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem);
1097   if (stat && stat != MR_NO_MATCH)
1098     {
1099       com_err(program_name, stat, " in get_hostalias.");
1100       return DM_NORMAL;
1101     }
1102   if (stat == MR_SUCCESS)
1103     {
1104       elem = top = QueueTop(elem);
1105       if (ask_user)
1106         {
1107           sprintf(temp_buf, "%s has the following cnames.", name);
1108           Put_message(temp_buf);
1109           Loop(top, (void (*)(char **)) PrintCname);
1110           ptr = "Remove ** ALL ** these cnames?";
1111           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1112             delete_it = TRUE;
1113           else
1114             {
1115               Put_message("Aborting...");
1116               FreeQueue(top);
1117               return SUB_ERROR;
1118             }
1119         }
1120       else
1121         delete_it = TRUE;
1122
1123       if (delete_it)
1124         {
1125           while (elem)
1126             {
1127               char **info = elem->q_data;
1128               if ((stat = do_mr_query("delete_hostalias", 2, info, 
1129                                       NULL, NULL)))
1130                 {
1131                   ret_value = SUB_ERROR;
1132                   com_err(program_name, stat, " in delete_hostalias.");
1133                   sprintf(temp_buf, 
1134                           "Cname %s ** NOT ** removed from host %s.",
1135                           info[0], info[1]);
1136                   Put_message(temp_buf);
1137                 }
1138               elem = elem->q_forw;
1139             }
1140         }
1141     }
1142   return ret_value;
1143 }
1144
1145 /*      Function Name: RealDeleteMachine
1146  *      Description: Actually Deletes the Machine.
1147  *      Arguments: info - nescessary information stored as an array of char *'s
1148  *                 one_machine - a boolean, true if there is only one item in
1149  *                               the query.
1150  *      Returns: none.
1151  */
1152
1153 static void RealDeleteMachine(char **info, Bool one_machine)
1154 {
1155   int stat;
1156   char temp_buf[BUFSIZ];
1157
1158   sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
1159           info[M_NAME]);
1160   if (!one_machine || Confirm(temp_buf))
1161     {
1162       if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
1163         {
1164           if (CheckAndRemoveCnames(info[M_NAME], TRUE) != SUB_ERROR)
1165             {
1166               if ((stat = do_mr_query("delete_host", 1,
1167                                       &info[M_NAME], NULL, NULL)))
1168                 {
1169                   com_err(program_name, stat, " in DeleteMachine.");
1170                   sprintf(temp_buf, "%s ** NOT ** deleted.",
1171                           info[M_NAME]);
1172                   Put_message(temp_buf);
1173                 }
1174               else
1175                 {
1176                   sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
1177                   Put_message(temp_buf);
1178                 }
1179             }
1180         }
1181     }
1182 }
1183
1184 /*      Function Name: DeleteMachine
1185  *      Description: This function removes a machine from the data base.
1186  *      Arguments: argc, argv - the machines name int argv[1].
1187  *      Returns: DM_NORMAL.
1188  */
1189
1190 /* Perhaps we should remove the cluster if it has no machine now. */
1191
1192 int DeleteMachine(int argc, char **argv)
1193 {
1194   struct mqelem *top;
1195   char *tmpname;
1196
1197   tmpname = canonicalize_hostname(strdup(argv[1]));
1198   top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
1199   QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
1200   FreeQueue(top);
1201   free(tmpname);
1202   return DM_NORMAL;
1203 }
1204
1205
1206 /*      Function Name: ShowCname
1207  *      Description: This function shows machine aliases
1208  *      Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1209  *      Returns: DM_NORMAL.
1210  */
1211
1212 int ShowCname(int argc, char **argv)
1213 {
1214   struct mqelem *top;
1215   char *tmpalias, *tmpname;
1216
1217   tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
1218   tmpname = canonicalize_hostname(strdup(argv[2]));
1219   top = GetMCInfo(CNAME, tmpalias, tmpname);
1220   Put_message("");              /* blank line on screen */
1221   Loop(top, ((void (*)(char **)) PrintCname));
1222   FreeQueue(top);
1223   return DM_NORMAL;
1224 }
1225
1226
1227 int AddCname(int argc, char **argv)
1228 {
1229   int stat;
1230   char *args[10];
1231
1232   args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1233   args[1] = canonicalize_hostname(strdup(argv[2]));
1234   stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
1235   switch (stat)
1236     {
1237     case MR_SUCCESS:
1238       break;
1239     case MR_EXISTS:
1240       Put_message("That alias name is already in use.");
1241       break;
1242     case MR_PERM:
1243       Put_message("Permission denied.  "
1244                   "(Regular users can only add two aliases to a host.");
1245       break;
1246     default:
1247       com_err(program_name, stat, " in add_hostalias");
1248     }
1249   return DM_NORMAL;
1250 }
1251
1252
1253 int DeleteCname(int argc, char **argv)
1254 {
1255   int stat;
1256   char *args[10];
1257
1258   args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1259   args[1] = canonicalize_hostname(strdup(argv[2]));
1260   stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
1261   if (stat)
1262     com_err(program_name, stat, " in delete_hostalias");
1263   return DM_NORMAL;
1264 }
1265
1266
1267 /*      Function Name: AddMachineToCluster
1268  *      Description: This function adds a machine to a cluster
1269  *      Arguments: argc, argv - The machine name is argv[1].
1270  *                              The cluster name in argv[2].
1271  *      Returns: DM_NORMAL.
1272  */
1273
1274 int AddMachineToCluster(int argc, char **argv)
1275 {
1276   int stat;
1277   char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1278   Bool add_it, one_machine, one_cluster;
1279   struct mqelem *melem, *mtop, *celem, *ctop;
1280
1281   machine = canonicalize_hostname(strdup(argv[1]));
1282   if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
1283     {
1284       sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1285               argv[1], machine);
1286       Put_message(temp_buf);
1287     }
1288   cluster = argv[2];
1289
1290   celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
1291   melem = mtop = GetMCInfo(MACHINE, machine, NULL);
1292   free(machine);
1293
1294   one_machine = (QueueCount(mtop) == 1);
1295   one_cluster = (QueueCount(ctop) == 1);
1296
1297   /* No good way to use QueryLoop() here, sigh */
1298
1299   while (melem)
1300     {
1301       char **minfo = melem->q_data;
1302       while (celem)
1303         {
1304           char **cinfo = celem->q_data;
1305           if (one_machine && one_cluster)
1306             add_it = TRUE;
1307           else
1308             {
1309               sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
1310                       minfo[M_NAME], cinfo[C_NAME]);
1311               switch (YesNoQuitQuestion(temp_buf, FALSE))
1312                 {
1313                 case TRUE:
1314                   add_it = TRUE;
1315                   break;
1316                 case FALSE:
1317                   add_it = FALSE;
1318                   break;
1319                 default:
1320                   Put_message("Aborting...");
1321                   FreeQueue(ctop);
1322                   FreeQueue(mtop);
1323                   return DM_NORMAL;
1324                 }
1325             }
1326           if (add_it)
1327             {
1328               args[0] = minfo[M_NAME];
1329               args[1] = cinfo[C_NAME];
1330               stat = do_mr_query("add_machine_to_cluster", 2, args,
1331                                  NULL, NULL);
1332               switch (stat)
1333                 {
1334                 case MR_SUCCESS:
1335                   break;
1336                 case MR_EXISTS:
1337                   sprintf(temp_buf, "%s is already in cluster %s",
1338                           minfo[M_NAME], cinfo[C_NAME]);
1339                   Put_message(temp_buf);
1340                   break;
1341                 default:
1342                   com_err(program_name, stat, " in AddMachineToCluster.");
1343                   break;
1344                 }
1345             }
1346           celem = celem->q_forw;
1347         }
1348       celem = ctop;             /* reset cluster element. */
1349       melem = melem->q_forw;
1350     }
1351   FreeQueue(ctop);
1352   FreeQueue(mtop);
1353   return DM_NORMAL;
1354 }
1355
1356 /*      Function Name: RealRemoveMachineFromCluster
1357  *      Description: This function actually removes the machine from its
1358  *                   cluster.
1359  *      Arguments: info - all information nescessary to perform the removal.
1360  *                 one_map - True if there is only one case, and we should
1361  *                           confirm.
1362  *      Returns: none.
1363  */
1364
1365 static void RealRemoveMachineFromCluster(char **info, Bool one_map)
1366 {
1367   char temp_buf[BUFSIZ];
1368   int stat;
1369
1370   sprintf(temp_buf, "Remove %s from the cluster %s",
1371           info[MAP_MACHINE], info[MAP_CLUSTER]);
1372   if (!one_map || Confirm(temp_buf))
1373     {
1374       if ((stat = do_mr_query("delete_machine_from_cluster", 2,
1375                               info, NULL, NULL)))
1376         com_err(program_name, stat, " in delete_machine_from_cluster");
1377       else
1378         {
1379           sprintf(temp_buf, "%s has been removed from the cluster %s.",
1380                   info[MAP_MACHINE], info[MAP_CLUSTER]);
1381           Put_message(temp_buf);
1382         }
1383     }
1384   else
1385     Put_message("Machine not removed.");
1386 }
1387
1388 /*      Function Name: RemoveMachineFromCluster
1389  *      Description: Removes this machine form a specific cluster.
1390  *      Arguments: argc, argv - Name of machine in argv[1].
1391  *                              Name of cluster in argv[2].
1392  *      Returns: none.
1393  */
1394
1395 int RemoveMachineFromCluster(int argc, char **argv)
1396 {
1397   struct mqelem *elem = NULL;
1398   char buf[BUFSIZ], *args[10];
1399   int stat;
1400
1401   args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
1402   if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
1403     {
1404       sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1405               argv[1], args[MAP_MACHINE]);
1406       Put_message(buf);
1407     }
1408   args[MAP_CLUSTER] = argv[2];
1409   args[MAP_END] = NULL;
1410
1411   stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1412                      StoreInfo, &elem);
1413   if (stat == MR_NO_MATCH)
1414     {
1415       sprintf(buf, "The machine %s is not in the cluster %s.",
1416               args[MAP_MACHINE], args[MAP_CLUSTER]);
1417       Put_message(buf);
1418       free(args[MAP_MACHINE]);
1419       return DM_NORMAL;
1420     }
1421   if (stat != MR_SUCCESS)
1422     com_err(program_name, stat, " in delete_machine_from_cluster");
1423
1424   elem = QueueTop(elem);
1425   QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1426             "Remove this machine from this cluster");
1427
1428   FreeQueue(elem);
1429   free(args[MAP_MACHINE]);
1430   return DM_NORMAL;
1431 }
1432
1433 /* ---------- Subnet Menu -------- */
1434
1435 /*      Function Name: ShowSubnetInfo
1436  *      Description: Gets information about a subnet given its name.
1437  *      Arguments: argc, argc - the name of the subnet in in argv[1].
1438  *      Returns: DM_NORMAL.
1439  */
1440
1441 int ShowSubnetInfo(int argc, char **argv)
1442 {
1443   struct mqelem *top;
1444
1445   top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1446   Loop(top, (void (*)(char **)) PrintSubnetInfo);
1447   FreeQueue(top);
1448   return DM_NORMAL;
1449 }
1450
1451 /*      Function Name: AddSubnet
1452  *      Description: Creates a new subnet.
1453  *      Arguments: argc, argv - the name of the new subnet is argv[1].
1454  *      Returns: DM_NORMAL.
1455  */
1456
1457 int AddSubnet(int argc, char **argv)
1458 {
1459   char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1460   int stat;
1461
1462   /*
1463    * Check to see if this subnet already exists.
1464    */
1465   if (!ValidName(name))
1466     return DM_NORMAL;
1467
1468   if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
1469     {
1470       Put_message("This subnet already exists.");
1471       return DM_NORMAL;
1472     }
1473   else if (stat != MR_NO_MATCH)
1474     {
1475       com_err(program_name, stat, " in AddSubnet.");
1476       return DM_NORMAL;
1477     }
1478   if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
1479     {
1480       Put_message("Aborted.");
1481       FreeInfo(info);
1482       return DM_NORMAL;
1483     }
1484
1485   /*
1486    * Actually create the new Subnet.
1487    */
1488   if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
1489     com_err(program_name, stat, " in AddSubnet.");
1490
1491   FreeInfo(info);
1492   return DM_NORMAL;
1493 }
1494
1495 /*      Function Name: RealUpdateSubnet
1496  *      Description: This function actually performs the subnet update.
1497  *      Arguments: info - all information nesc. for updating the subnet.
1498  *                 junk - an UNUSED boolean.
1499  *      Returns: none.
1500  */
1501
1502 static void RealUpdateSubnet(char **info, Bool junk)
1503 {
1504   int stat;
1505   char **args = AskMCDInfo(info, SUBNET, TRUE);
1506   if (!args)
1507     {
1508       Put_message("Aborted.");
1509       return;
1510     }
1511   if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
1512     com_err(program_name, stat, " in UpdateSubnet.");
1513   else
1514     Put_message("Subnet successfully updated.");
1515 }
1516
1517 /*      Function Name: UpdateSubnet
1518  *      Description: This Function Updates a subnet
1519  *      Arguments: name of the subnet in argv[1].
1520  *      Returns: DM_NORMAL.
1521  */
1522
1523 int UpdateSubnet(int argc, char **argv)
1524 {
1525   struct mqelem *top;
1526   top = GetMCInfo(SUBNET, argv[1], NULL);
1527   QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1528
1529   FreeQueue(top);
1530   return DM_NORMAL;
1531 }
1532
1533 /*      Function Name: RealDeleteSubnet
1534  *      Description: Actually performs the subnet deletion.
1535  *      Arguments: info - all information about this subnet.
1536  *                 one_subnet - If true then there was only one subnet in
1537  *                               the queue, and we should confirm.
1538  *      Returns: none.
1539  */
1540
1541 static void RealDeleteSubnet(char **info, Bool one_subnet)
1542 {
1543   int stat;
1544   char temp_buf[BUFSIZ];
1545
1546   sprintf(temp_buf,
1547           "Are you sure the you want to delete the subnet %s (y/n) ?",
1548           info[C_NAME]);
1549   if (!one_subnet || Confirm(temp_buf))
1550     {
1551       if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
1552         {
1553           com_err(program_name, stat, " in delete_subnet.");
1554           sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
1555           Put_message(temp_buf);
1556         }
1557       else
1558         {
1559           sprintf(temp_buf, "subnet %s successfully deleted.",
1560                   info[C_NAME]);
1561           Put_message(temp_buf);
1562         }
1563     }
1564 }
1565
1566 /*      Function Name: DeleteSubnet
1567  *      Description: This function removes a subnet from the database.
1568  *      Arguments: argc, argv - the name of the subnet is stored in argv[1].
1569  *      Returns: DM_NORMAL.
1570  */
1571
1572 int DeleteSubnet(int argc, char **argv)
1573 {
1574   struct mqelem *top;
1575
1576   top = GetMCInfo(SUBNET, argv[1], NULL);
1577   QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1578
1579   FreeQueue(top);
1580   return DM_NORMAL;
1581 }
1582
1583 /* ---------- Cluster Menu -------- */
1584
1585 /*      Function Name: ShowClusterInfo
1586  *      Description: Gets information about a cluser given its name.
1587  *      Arguments: argc, argc - the name of the cluster in in argv[1].
1588  *      Returns: DM_NORMAL.
1589  */
1590
1591 int ShowClusterInfo(int argc, char **argv)
1592 {
1593   struct mqelem *top;
1594
1595   top = GetMCInfo(CLUSTER, argv[1], NULL);
1596   Loop(top, (void (*)(char **)) PrintClusterInfo);
1597   FreeQueue(top);
1598   return DM_NORMAL;
1599 }
1600
1601 /*      Function Name: AddCluster
1602  *      Description: Creates a new cluster.
1603  *      Arguments: argc, argv - the name of the new cluster is argv[1].
1604  *      Returns: DM_NORMAL.
1605  */
1606
1607 int AddCluster(int argc, char **argv)
1608 {
1609   char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1610   int stat;
1611
1612   /*
1613    * Check to see if this cluster already exists.
1614    */
1615   if (!ValidName(name))
1616     return DM_NORMAL;
1617
1618   if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
1619     {
1620       Put_message("This cluster already exists.");
1621       return DM_NORMAL;
1622     }
1623   else if (stat != MR_NO_MATCH)
1624     {
1625       com_err(program_name, stat, " in AddCluster.");
1626       return DM_NORMAL;
1627     }
1628   if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
1629     {
1630       Put_message("Aborted.");
1631       FreeInfo(info);
1632       return DM_NORMAL;
1633     }
1634
1635   /*
1636    * Actually create the new Cluster.
1637    */
1638   if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
1639     com_err(program_name, stat, " in AddCluster.");
1640
1641   FreeInfo(info);
1642   return DM_NORMAL;
1643 }
1644
1645 /*      Function Name: RealUpdateCluster
1646  *      Description: This function actually performs the cluster update.
1647  *      Arguments: info - all information nesc. for updating the cluster.
1648  *                 junk - an UNUSED boolean.
1649  *      Returns: none.
1650  */
1651
1652 static void RealUpdateCluster(char **info, Bool junk)
1653 {
1654   int stat;
1655   char **args = AskMCDInfo(info, CLUSTER, TRUE);
1656
1657   if (!args)
1658     {
1659       Put_message("Aborted.");
1660       return;
1661     }
1662   if ((stat = do_mr_query("update_cluster", CountArgs(args),
1663                           args, NULL, NULL)))
1664     com_err(program_name, stat, " in UpdateCluster.");
1665   else
1666     Put_message("Cluster successfully updated.");
1667 }
1668
1669 /*      Function Name: UpdateCluster
1670  *      Description: This Function Updates a cluster
1671  *      Arguments: name of the cluster in argv[1].
1672  *      Returns: DM_NORMAL.
1673  */
1674
1675 int UpdateCluster(int argc, char **argv)
1676 {
1677   struct mqelem *top;
1678   top = GetMCInfo(CLUSTER, argv[1], NULL);
1679   QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1680
1681   FreeQueue(top);
1682   return DM_NORMAL;
1683 }
1684
1685 /*      Function Name: CheckAndRemoveMachine
1686  *      Description: This function checks and removes all machines from a
1687  *                   cluster.
1688  *      Arguments: name - name of the cluster.
1689  *                 ask_first - if TRUE, then we will query the user, before
1690  *                             deletion.
1691  *      Returns: SUB_ERROR if all machines not removed.
1692  */
1693
1694 int CheckAndRemoveMachines(char *name, Bool ask_first)
1695 {
1696   int stat, ret_value;
1697   Bool delete_it;
1698   char *args[10], temp_buf[BUFSIZ], *ptr;
1699   struct mqelem *top, *elem = NULL;
1700
1701   ret_value = SUB_NORMAL;
1702   args[MAP_MACHINE] = "*";
1703   args[MAP_CLUSTER] = name;
1704   stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1705   if (stat && stat != MR_NO_MATCH)
1706     {
1707       com_err(program_name, stat, " in get_machine_to_cluster_map.");
1708       return DM_NORMAL;
1709     }
1710   if (stat == MR_SUCCESS)
1711     {
1712       elem = top = QueueTop(elem);
1713       if (ask_first)
1714         {
1715           sprintf(temp_buf, "The cluster %s has the following machines in it:",
1716                   name);
1717           Put_message(temp_buf);
1718           while (elem)
1719             {
1720               char **info = elem->q_data;
1721               Print(1, &info[MAP_MACHINE], (char *) NULL);
1722               elem = elem->q_forw;
1723             }
1724           ptr = "Remove ** ALL ** these machines from this cluster?";
1725
1726           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1727             delete_it = TRUE;
1728           else
1729             {
1730               Put_message("Aborting...");
1731               FreeQueue(top);
1732               return SUB_ERROR;
1733             }
1734         }
1735       else
1736         delete_it = TRUE;
1737
1738       if (delete_it)
1739         {
1740           elem = top;
1741           while (elem)
1742             {
1743               char **info = elem->q_data;
1744               if ((stat = do_mr_query("delete_machine_from_cluster",
1745                                       2, info, NULL, NULL)))
1746                 {
1747                   ret_value = SUB_ERROR;
1748                   com_err(program_name, stat,
1749                           " in delete_machine_from_cluster.");
1750                   sprintf(temp_buf,
1751                           "Machine %s ** NOT ** removed from cluster %s.",
1752                           info[MAP_MACHINE], info[MAP_CLUSTER]);
1753                   Put_message(temp_buf);
1754                 }
1755               elem = elem->q_forw;
1756             }
1757         }
1758     }
1759   return ret_value;
1760 }
1761
1762 /*      Function Name: RealDeleteCluster
1763  *      Description: Actually performs the cluster deletion.
1764  *      Arguments: info - all information about this cluster.
1765  *                 one_cluster - If true then there was only one cluster in
1766  *                               the queue, and we should confirm.
1767  *      Returns: none.
1768  */
1769
1770 static void RealDeleteCluster(char **info, Bool one_cluster)
1771 {
1772   int stat;
1773   char temp_buf[BUFSIZ];
1774
1775   sprintf(temp_buf,
1776           "Are you sure the you want to delete the cluster %s (y/n) ?",
1777           info[C_NAME]);
1778   if (!one_cluster || Confirm(temp_buf))
1779     {
1780       if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
1781         {
1782           if ((stat = do_mr_query("delete_cluster", 1,
1783                                   &info[C_NAME], NULL, NULL)))
1784             {
1785               com_err(program_name, stat, " in delete_cluster.");
1786               sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
1787               Put_message(temp_buf);
1788             }
1789           else
1790             {
1791               sprintf(temp_buf, "cluster %s successfully deleted.",
1792                       info[C_NAME]);
1793               Put_message(temp_buf);
1794             }
1795         }
1796     }
1797 }
1798
1799 /*      Function Name: DeleteCluster
1800  *      Description: This function removes a cluster from the database.
1801  *      Arguments: argc, argv - the name of the cluster is stored in argv[1].
1802  *      Returns: DM_NORMAL.
1803  */
1804
1805 int DeleteCluster(int argc, char **argv)
1806 {
1807   struct mqelem *top;
1808
1809   top = GetMCInfo(CLUSTER, argv[1], NULL);
1810   QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1811
1812   FreeQueue(top);
1813   return DM_NORMAL;
1814 }
1815
1816 /* ----------- Cluster Data Menu -------------- */
1817
1818 /*      Function Name: ShowClusterData
1819  *      Description: This function shows the services for one cluster.
1820  *      Arguments: argc, argv - The name of the cluster is argv[1].
1821  *                              The label of the data in argv[2].
1822  *      Returns: DM_NORMAL.
1823  */
1824
1825 int ShowClusterData(int argc, char **argv)
1826 {
1827   struct mqelem *elem, *top;
1828   char **info;
1829
1830   top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1831   while (elem)
1832     {
1833       info = elem->q_data;
1834       PrintClusterData(info);
1835       elem = elem->q_forw;
1836     }
1837   FreeQueue(top);
1838   return DM_NORMAL;
1839 }
1840
1841 /*      Function Name: AddClusterData
1842  *      Description: This function adds some data to the cluster.
1843  *      Arguments: argv, argc:   argv[1] - the name of the cluster.
1844  *                               argv[2] - the label of the data.
1845  *                               argv[3] - the data.
1846  *      Returns: DM_NORMAL.
1847  */
1848
1849 int AddClusterData(int argc, char **argv)
1850 {
1851   int stat, i;
1852
1853   for (i = 1; i < 4; i++)
1854     {
1855       if (IS_EMPTY(argv[i]))
1856         {
1857           Put_message("Cluster data cannot be an empty string.");
1858           return DM_NORMAL;
1859         }
1860     }
1861   if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
1862     com_err(program_name, stat, " in AddClusterData.");
1863   return DM_NORMAL;
1864 }
1865
1866 /*      Function Name: RealRemoveClusterData
1867  *      Description: actually removes the cluster data.
1868  *      Arguments: info - all info necessary to remove the cluster, in an array
1869  *                        of strings.
1870  *                 one_item - if true then the queue has only one elem and we
1871  *                            should confirm.
1872  *      Returns: none.
1873  */
1874
1875 static void RealRemoveClusterData(char **info, Bool one_item)
1876 {
1877   int stat;
1878   char *temp_ptr;
1879
1880   Put_message(" ");
1881   temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1882   PrintClusterData(info);
1883   if (!one_item || Confirm(temp_ptr))
1884     {
1885       if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
1886         {
1887           com_err(program_name, stat, " in DeleteClusterData.");
1888           Put_message("Data not removed.");
1889         }
1890       else
1891         Put_message("Removal successful.");
1892     }
1893 }
1894
1895 /*      Function Name: RemoveClusterData
1896  *      Description: This function removes data on a given cluster.
1897  *      Arguments: argv, argc:   argv[1] - the name of the cluster.
1898  *                               argv[2] - the label of the data.
1899  *                               argv[3] - the data.
1900  *      Returns: DM_NORMAL.
1901  */
1902
1903 int RemoveClusterData(int argc, char **argv)
1904 {
1905   struct mqelem *top;
1906
1907   top = GetMCInfo(DATA, argv[1], argv[2]);
1908   QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1909             "Remove data from cluster");
1910
1911   FreeQueue(top);
1912   return DM_NORMAL;
1913 }
1914
1915 /*      Function Name: MachineToClusterMap
1916  *      Description: This Retrieves the mapping between machine and cluster
1917  *      Arguments: argc, argv - argv[1] -> machine name or wildcard.
1918  *                              argv[2] -> cluster name or wildcard.
1919  *      Returns: none.
1920  */
1921
1922 int MachineToClusterMap(int argc, char **argv)
1923 {
1924   struct mqelem *elem, *top;
1925   char *tmpname, temp_buf[256];
1926
1927   tmpname = canonicalize_hostname(strdup(argv[1]));
1928   if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
1929     {
1930       sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1931               argv[1], tmpname);
1932       Put_message(temp_buf);
1933     }
1934   top = elem = GetMCInfo(MAP, tmpname, argv[2]);
1935
1936   Put_message("");              /* blank line on screen */
1937   while (elem)
1938     {
1939       char **info = elem->q_data;
1940       PrintMCMap(info);
1941       elem = elem->q_forw;
1942     }
1943
1944   FreeQueue(top);
1945   free(tmpname);
1946   return DM_NORMAL;
1947 }
1948
1949 /*        Function Name: MachineByOwner
1950  *        Description: This function prints all machines which are owned by 
1951  *                     a given user or group.
1952  *        Arguments: none.
1953  *        Returns: DM_NORMAL.
1954  */
1955
1956 int MachineByOwner(int argc, char **argv)
1957 {
1958   char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
1959   struct mqelem *top;
1960
1961   type = strdup("USER");
1962   if (GetTypeFromUser("Type of owner", "ace_type", &type) == SUB_ERROR)
1963     return DM_NORMAL;
1964
1965   sprintf(buf, "Name of %s", type);
1966   name = strdup(user);
1967   if (GetValueFromUser(buf, &name) == SUB_ERROR)
1968     return DM_NORMAL;
1969
1970   switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE))
1971     {
1972     case TRUE:
1973       sprintf(temp_buf, "R%s", type);     /* "USER to "RUSER", etc. */
1974       free(type);
1975       type = strdup(temp_buf);
1976       break;
1977     case FALSE:
1978       break;
1979     default:
1980       return DM_NORMAL;
1981     }
1982
1983   top = GetMachineByOwner(type, name);
1984   Loop(top, PrintMachine);
1985
1986   FreeQueue(top);
1987   return DM_NORMAL;
1988 }
1989
1990 /*         Function Name: GetMachineByOwner
1991  *         Description: This function stores information retrieved by 
1992  *                      the get_host_by_owner query
1993  *         Arguments: type - an ace_type, argv[0] for the query
1994  *                    name - name of machine, argv[1] for the query
1995  *         Returns: the top element of a queue returning the data, or NULL.
1996  */
1997
1998 struct mqelem *GetMachineByOwner(char *type, char *name)
1999 {
2000   char *args[2];
2001   struct mqelem *elem = NULL;
2002   int status;
2003
2004   args[0] = type;
2005   args[1] = name;
2006   if ((status = do_mr_query("get_host_by_owner", 2, args, StoreInfo, &elem)))
2007     {
2008       com_err(program_name, status, " in get_host_by_owner");
2009       return NULL;
2010     }
2011   return QueueTop(elem);
2012 }
2013
2014 int ShowContainerInfo(int argc, char **argv)
2015 {
2016   struct mqelem *top;
2017
2018   top = GetMCInfo(CONTAINER, argv[1], NULL);
2019   Loop(top, (void (*)(char **)) PrintContainerInfo);
2020   FreeQueue(top);
2021   return DM_NORMAL;
2022 }
2023
2024 static char *PrintContainerInfo(char **info)
2025 {
2026   char buf[BUFSIZ], tbuf[256];
2027
2028   Put_message("");
2029   sprintf(buf, "Container:      %-16s", info[CON_NAME]);
2030   Put_message(buf);
2031   sprintf(buf, "Description:    %-16s", info[CON_DESCRIPT]);
2032   Put_message(buf);
2033   sprintf(buf, "Location:       %-16s    Contact:     %s", info[CON_LOCATION],
2034           info[CON_CONTACT]);
2035   Put_message(buf);
2036   sprintf(tbuf, "%s %s", info[CON_OWNER_TYPE],
2037           strcmp(info[CON_OWNER_TYPE], "NONE") ? info[CON_OWNER_NAME] : "");
2038   sprintf(buf, "Owner:          %-16s", tbuf);
2039   Put_message(buf);
2040   sprintf(tbuf, "%s %s", info[CON_MEMACE_TYPE],
2041           strcmp(info[CON_MEMACE_TYPE], "NONE") ? info[CON_MEMACE_NAME] : "");
2042   sprintf(buf, "Membership ACL: %-16s", tbuf);
2043   Put_message(buf);
2044   Put_message("");
2045   sprintf(buf, MOD_FORMAT, info[CON_MODBY], info[CON_MODTIME], 
2046           info[CON_MODWITH]);
2047   Put_message(buf);
2048   return info[CON_NAME];
2049 }
2050
2051 static char *PrintContainer(char **info)
2052 {
2053   char buf[BUFSIZ];
2054
2055   sprintf(buf, "Container: %s", info[CON_NAME]);
2056   Put_message(buf);
2057   return "";
2058 }
2059
2060 static char *PrintMContMap(char **info)
2061 {
2062   char buf[BUFSIZ];
2063   sprintf(buf, "Container: %-30s Machine: %-20s",
2064           info[1], info[0]);
2065   Put_message(buf);
2066   return "";
2067 }
2068
2069 int AddContainer(int argc, char **argv)
2070 {
2071   char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
2072   int stat;
2073
2074   /* Can't use ValidName() because spaces are allowed in container names */
2075   if (IS_EMPTY(name))
2076     {
2077       Put_message("Please use a non-empty name.");
2078       return DM_NORMAL;
2079     }
2080
2081   if (strchr(name, '*') || strchr(name, '?'))
2082     {
2083       Put_message("Wildcards not accepted here.");
2084       return DM_NORMAL;
2085     }
2086
2087   /* Check if this cluster already exists. */
2088   if ((stat = do_mr_query("get_container", 1, &name, NULL, NULL))
2089       == MR_SUCCESS)
2090     {
2091       Put_message("This container already exists.");
2092       return DM_NORMAL;
2093     }
2094   else if (stat != MR_NO_MATCH)
2095     {
2096       com_err(program_name, stat, " in AddContainer.");
2097       return DM_NORMAL;
2098     }
2099   if (!(args = AskMCDInfo(SetContainerDefaults(info, name), CONTAINER, FALSE)))
2100     {
2101       Put_message("Aborted.");
2102       FreeInfo(info);
2103       return DM_NORMAL;
2104     }
2105
2106   /* Create the new container. */
2107   if ((stat = do_mr_query("add_container", CountArgs(args), args, NULL, NULL)))
2108     com_err(program_name, stat, " in AddContainer.");
2109
2110   FreeInfo(info);
2111   return DM_NORMAL;
2112 }
2113
2114 int UpdateContainer(int argc, char **argv)
2115 {
2116   struct mqelem *top;
2117   top = GetMCInfo(CONTAINER, argv[1], NULL);
2118   QueryLoop(top, NullPrint, RealUpdateContainer, "Update the container");
2119
2120   FreeQueue(top);
2121   return DM_NORMAL;
2122 }
2123
2124 static void RealUpdateContainer(char **info, Bool junk)
2125 {
2126   int stat;
2127   char **args = AskMCDInfo(info, CONTAINER, TRUE);
2128
2129   if (!args)
2130     {
2131       Put_message("Aborted.");
2132       return;
2133     }
2134   if ((stat = do_mr_query("update_container", CountArgs(args), args,
2135                           NULL, NULL)))
2136     com_err(program_name, stat, " in UpdateContainer.");
2137   else
2138     Put_message("Container successfully updated.");
2139 }
2140
2141 int DeleteContainer(int argc, char **argv)
2142 {
2143   struct mqelem *top;
2144
2145   top = GetMCInfo(CONTAINER, argv[1], NULL);
2146   QueryLoop(top, PrintClusterInfo, RealDeleteContainer, 
2147             "Delete the container");
2148
2149   FreeQueue(top);
2150   return DM_NORMAL;
2151 }
2152
2153 static void RealDeleteContainer(char **info, Bool one_container)
2154 {
2155   int stat;
2156   char temp_buf[BUFSIZ];
2157
2158   sprintf(temp_buf,
2159           "Are you sure you want to delete the container %s (y/n) ?",
2160           info[CON_NAME]);
2161   if (!one_container || Confirm(temp_buf))
2162     {
2163       if (CheckAndRemoveMachinesFromContainer(info[CON_NAME], TRUE) 
2164           != SUB_ERROR)
2165         {
2166           if ((stat = do_mr_query("delete_container", 1, &info[CON_NAME],
2167                                   NULL, NULL)))
2168             {
2169               com_err(program_name, stat, " in delete_container.");
2170               sprintf(temp_buf, "Container %s ** NOT ** deleted.", 
2171                       info[CON_NAME]);
2172               Put_message(temp_buf);
2173             }
2174           else
2175             {
2176               sprintf(temp_buf, "Container %s successfully deleted.",
2177                       info[CON_NAME]);
2178               Put_message(temp_buf);
2179             }
2180         }
2181     }
2182 }
2183
2184 int CheckAndRemoveMachinesFromContainer(char *name, Bool ask_first)
2185 {
2186   int stat, ret_value;
2187   Bool delete_it;
2188   char *args[10], temp_buf[BUFSIZ], *ptr;
2189   struct mqelem *top, *elem = NULL;
2190   
2191   ret_value = SUB_NORMAL;
2192   args[0] = name;
2193   args[1] = "0";
2194   stat = do_mr_query("get_machines_of_container", 2, args, StoreInfo, 
2195                      &elem);
2196   if (stat && stat != MR_NO_MATCH)
2197     {
2198       com_err(program_name, stat, " in get_machines_of_container");
2199       return DM_NORMAL;
2200     }
2201   if (stat == MR_SUCCESS)
2202     {
2203       elem = top = QueueTop(elem);
2204       if (ask_first)
2205         {
2206           sprintf(temp_buf,
2207                   "The container %s has the following machines in it:", name);
2208           Put_message(temp_buf);
2209           while (elem)
2210             {
2211               char **info = elem->q_data;
2212               Print(1, &info[0], (char *) NULL);
2213               elem = elem->q_forw;
2214             }
2215           ptr = "Remove ** ALL ** these machines from this container?";
2216
2217           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
2218             delete_it = TRUE;
2219           else
2220             {
2221               Put_message("Aborting...");
2222               FreeQueue(top);
2223               return SUB_ERROR;
2224             }
2225         }
2226       else
2227         delete_it = TRUE;
2228
2229       if (delete_it)
2230         {
2231           elem = top;
2232           while (elem)
2233             {
2234               char **info = elem->q_data;
2235               if ((stat = do_mr_query("delete_machine_from_container",
2236                                       2, info, NULL, NULL)))
2237                 {
2238                   ret_value = SUB_ERROR;
2239                   com_err(program_name, stat, 
2240                           " in delete_machine_from_container.");
2241                   sprintf(temp_buf, 
2242                           "Machine %s ** NOT ** removed from container %s.",
2243                           info[0], info[1]);
2244                   Put_message(temp_buf);
2245                 }
2246               elem = elem->q_forw;
2247             }
2248         }
2249     }
2250   return ret_value;
2251 }
2252
2253 int GetSubContainers(int argc, char **argv)
2254 {
2255   char *args[2];
2256   struct mqelem *elem = NULL, *top = NULL;
2257   int stat;
2258
2259   args[0] = argv[1];
2260
2261   if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
2262     args[1] = "1";
2263   else
2264     args[1] = "0";
2265
2266   if (stat = do_mr_query("get_subcontainers_of_container", 2, args,
2267                          StoreInfo, &elem))
2268     com_err(program_name, stat, " in get_subcontainers_of_container");
2269
2270   top = QueueTop(elem);
2271   Loop(top, ((void (*)(char **)) PrintContainer));
2272   FreeQueue(top);
2273   return DM_NORMAL;
2274 }
2275
2276 int MachineToContainerMap(int argc, char **argv)
2277 {
2278   struct mqelem *elem, *top;
2279   char *tmpname, temp_buf[256];
2280
2281   tmpname = canonicalize_hostname(strdup(argv[1]));
2282   if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
2283     {
2284       sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2285               argv[1], tmpname);
2286       Put_message(temp_buf);
2287     }
2288   top = elem = GetMCInfo(CONTMAP, tmpname, NULL);
2289
2290   Put_message("");
2291   while (elem)
2292     {
2293       char **info = elem->q_data;
2294       PrintMContMap(info);
2295       elem = elem->q_forw;
2296     }
2297
2298   FreeQueue(top);
2299   free(tmpname);
2300   return DM_NORMAL;
2301 }
2302
2303 int AddMachineToContainer(int argc, char **argv)
2304 {
2305   int stat;
2306   char *machine, *container, temp_buf[BUFSIZ], *args[10];
2307   Bool add_it, one_machine, one_container;
2308   struct mqelem *melem, *mtop, *celem, *ctop;
2309
2310   machine = canonicalize_hostname(strdup(argv[1]));
2311   if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
2312     {
2313       sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
2314               argv[1], machine);
2315       Put_message(temp_buf);
2316     }
2317   container = argv[2];
2318
2319   celem = ctop = GetMCInfo(CONTAINER, container, NULL);
2320   melem = mtop = GetMCInfo(MACHINE, machine, NULL);
2321   free(machine);
2322
2323   one_machine = (QueueCount(mtop) == 1);
2324   one_container = (QueueCount(ctop) == 1);
2325
2326   while (melem)
2327     {
2328       char **minfo = melem->q_data;
2329       while (celem)
2330         {
2331           char **cinfo = celem->q_data;
2332           if (one_machine && one_container)
2333             add_it = TRUE;
2334           else
2335             {
2336               sprintf(temp_buf, "Add machine %s to container %s (y/n/q) ?",
2337                       minfo[M_NAME], cinfo[CON_NAME]);
2338               switch (YesNoQuestion(temp_buf, FALSE))
2339                 {
2340                 case TRUE:
2341                   add_it = TRUE;
2342                   break;
2343                 case FALSE:
2344                   add_it = FALSE;
2345                   break;
2346             default:
2347               Put_message("Aborting...");
2348               FreeQueue(ctop);
2349               FreeQueue(mtop);
2350               return DM_NORMAL;
2351                 }
2352             }
2353           if (add_it)
2354             {
2355               args[0] = minfo[M_NAME];
2356               args[1] = cinfo[CON_NAME];
2357               stat = do_mr_query("add_machine_to_container", 2, args, NULL, 
2358                                  NULL);
2359               switch (stat)
2360                 {
2361                 case MR_SUCCESS:
2362                   break;
2363                 case MR_EXISTS:
2364                   sprintf(temp_buf, "%s is already in container %s",
2365                           minfo[M_NAME], cinfo[CON_NAME]);
2366                   Put_message(temp_buf);
2367                   break;
2368                 default:
2369                   com_err(program_name, stat, " in AddMachineToContainer.");
2370                   break;
2371                 }
2372             }
2373           celem = celem->q_forw;
2374         }
2375       celem = ctop;
2376       melem = melem->q_forw;
2377     }
2378   FreeQueue(ctop);
2379   FreeQueue(mtop);
2380   return DM_NORMAL;
2381 }
2382
2383 int RemoveMachineFromContainer(int argc, char **argv)
2384 {
2385   struct mqelem *elem = NULL;
2386   char buf[BUFSIZ], *args[10];
2387   int stat;
2388
2389   args[0] = canonicalize_hostname(strdup(argv[1]));
2390   if (strcasecmp(args[0], argv[1]) && *argv[1] != '"')
2391     {
2392       sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
2393               argv[1], args[0]);
2394       Put_message(buf);
2395     }
2396   args[1] = argv[2];
2397   args[2] = NULL;
2398
2399   stat = do_mr_query("get_machine_to_container_map", 1, args, StoreInfo, 
2400                      &elem);
2401   if (stat == MR_NO_MATCH)
2402     {
2403       sprintf(buf, "The machine %s is not in the container %s.",
2404               args[0], args[1]);
2405       Put_message(buf);
2406       free(args[0]);
2407       return DM_NORMAL;
2408     }
2409   if (stat != MR_SUCCESS)
2410     com_err(program_name, stat, " in deleter_machine_from_container");
2411
2412   elem = QueueTop(elem);
2413   QueryLoop(elem, PrintMContMap, RealRemoveMachineFromContainer, 
2414             "Remove this machine from this container");
2415   
2416   FreeQueue(elem);
2417   free(args[0]);
2418   return DM_NORMAL;
2419 }
2420
2421 static void RealRemoveMachineFromContainer(char **info, Bool one_contmap)
2422 {
2423   char temp_buf[BUFSIZ];
2424   int stat;
2425
2426   sprintf(temp_buf, "Remove %s from the container %s",
2427           info[0], info[1]);
2428   if (!one_contmap || Confirm(temp_buf))
2429     {
2430       if ((stat = do_mr_query("delete_machine_from_container", 2,
2431                               info, NULL, NULL)))
2432         com_err(program_name, stat, " in delete_machine_from_container");
2433       else
2434         {
2435           sprintf(temp_buf, "%s has been removed from the container %s.",
2436                   info[0], info[1]);
2437           Put_message(temp_buf);
2438         }
2439     }
2440   else
2441     Put_message("Machine not removed.");
2442 }
2443
2444 int GetMachinesOfContainer(int argc, char **argv)
2445 {
2446   char *args[2];
2447   struct mqelem *elem = NULL, *top = NULL;
2448   int stat;
2449
2450   args[0] = argv[1];
2451
2452   if (YesNoQuestion("Do you want a recursive search?", TRUE) == TRUE)
2453     args[1] = "1";
2454   else
2455     args[1] = "0";
2456
2457   if (stat = do_mr_query("get_machines_of_container", 2, args,
2458                          StoreInfo, &elem))
2459     com_err(program_name, stat, " in get_machines_of_container");
2460
2461   top = QueueTop(elem);
2462   Loop(top, ((void (*)(char **)) PrintMContMap));
2463   FreeQueue(top);
2464   return DM_NORMAL;
2465 }
2466
2467 int GetTopLevelCont(int argc, char **argv)
2468 {
2469   int status;
2470   struct mqelem *elem = NULL;
2471   if (status = do_mr_query("get_toplevel_containers", 0, NULL, StoreInfo, 
2472                            &elem))
2473     {
2474       com_err(program_name, status, " in get_toplevel_containers");
2475       return DM_NORMAL;
2476     }
2477   Loop(QueueTop(elem), (void(*)(char **)) PrintContainer);
2478   FreeQueue(elem);
2479   return DM_NORMAL;
2480 }
This page took 0.99949 seconds and 5 git commands to generate.