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