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