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