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