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