]> andersk Git - moira.git/blob - clients/moira/cluster.c
Fixes moira[1791], where extended output from a get_host query would
[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 #define MACHINE  0
53 #define CLUSTER  1
54 #define DATA     2
55 #define MAP      3
56 #define SUBNET   4
57 #define CNAME    5
58
59 #define M_DEFAULT_TYPE     DEFAULT_NONE
60
61 #define C_DEFAULT_DESCRIPT DEFAULT_NONE
62 #define C_DEFAULT_LOCATION DEFAULT_NONE
63
64 #define CD_DEFAULT_LABEL   DEFAULT_NONE
65 #define CD_DEFAULT_DATA    DEFAULT_NONE
66
67 #define S_DEFAULT_LOW   "18.0.0.20"
68 #define S_DEFAULT_HIGH  "18.0.2.249"
69
70 static char *states[] = {
71   "Reserved (0)",
72   "Active (1)",
73   "None (2)",
74   "Deleted (3)"
75 };
76
77 static char *MacState(int state)
78 {
79   static char buf[BUFSIZ];
80
81   if (state < 0 || state > 3)
82     {
83       sprintf(buf, "Unknown (%d)", state);
84       return buf;
85     }
86   return states[state];
87 }
88
89
90
91 /* -------------------- Set Defaults -------------------- */
92
93 /*      Function Name: SetMachineDefaults
94  *      Description: sets machine defaults.
95  *      Arguments: info - an array to put the defaults into.
96  *                 name - Canonacalized name of the machine.
97  *      Returns: info - the array.
98  */
99
100 static char **SetMachineDefaults(char **info, char *name)
101 {
102   info[M_NAME] = strdup(name);
103   info[M_VENDOR] = strdup(M_DEFAULT_TYPE);
104   info[M_MODEL] = strdup(M_DEFAULT_TYPE);
105   info[M_OS] = strdup(M_DEFAULT_TYPE);
106   info[M_LOC] = strdup(M_DEFAULT_TYPE);
107   info[M_CONTACT] = strdup(M_DEFAULT_TYPE);
108   info[M_BILL_CONTACT] = strdup(M_DEFAULT_TYPE);
109   info[M_USE] = strdup("0");
110   info[M_STAT] = strdup("1");
111   info[M_SUBNET] = strdup("NONE");
112   info[M_ADDR] = strdup("unique");
113   info[M_OWNER_TYPE] = strdup("NONE");
114   info[M_OWNER_NAME] = strdup("NONE");
115   info[M_ACOMMENT] = strdup("");
116   info[M_OCOMMENT] = strdup("");
117   info[16] = info[17] = NULL;
118   return info;
119 }
120
121 /*      Function Name: SetClusterDefaults
122  *      Description: sets Cluster defaults.
123  *      Arguments: info - an array to put the defaults into.
124  *                 name - name of the Cluster.
125  *      Returns: info - the array.
126  */
127
128 static char **SetClusterDefaults(char **info, char *name)
129 {
130   info[C_NAME] = strdup(name);
131   info[C_DESCRIPT] = strdup(C_DEFAULT_DESCRIPT);
132   info[C_LOCATION] = strdup(C_DEFAULT_LOCATION);
133   info[C_MODBY] = info[C_MODTIME] = info[C_MODWITH] = info[C_END] = NULL;
134   return info;
135 }
136
137 /*      Function Name: SetSubnetDefaults
138  *      Description: sets Subnet defaults.
139  *      Arguments: info - an array to put the defaults into.
140  *                 name - name of the Subnet.
141  *      Returns: info - the array.
142  */
143
144 static char **SetSubnetDefaults(char **info, char *name)
145 {
146   char buf[256];
147
148   info[C_NAME] = strdup(name);
149   info[SN_DESC] = strdup("");
150   sprintf(buf, "%ld", ntohl(inet_addr("18.255.0.0")));
151   info[SN_ADDRESS] = strdup(buf);
152   sprintf(buf, "%ld", ntohl(inet_addr("255.255.0.0")));
153   info[SN_MASK] = strdup(buf);
154   sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_LOW)));
155   info[SN_LOW] = strdup(buf);
156   sprintf(buf, "%ld", ntohl(inet_addr(S_DEFAULT_HIGH)));
157   info[SN_HIGH] = strdup(buf);
158   info[SN_PREFIX] = strdup("");
159   info[SN_ACE_TYPE] = strdup("LIST");
160   info[SN_ACE_NAME] = strdup("network");
161   info[SN_MODBY] = info[SN_MODTIME] = info[SN_MODWITH] = info[SN_END] = NULL;
162   return info;
163 }
164
165 /* -------------------- General Functions -------------------- */
166
167 static char aliasbuf[256];
168
169 void PrintAliases(char **info)
170 {
171   if (strlen(aliasbuf) == 0)
172     sprintf(aliasbuf, "Aliases:  %s", info[0]);
173   else
174     {
175       strcat(aliasbuf, ", ");
176       strcat(aliasbuf, info[0]);
177     }
178 }
179
180
181 /*      Function Name: PrintMachInfo
182  *      Description: This function Prints out the Machine info in
183  *                   a coherent form.
184  *      Arguments: info - array of information about a machine.
185  *      Returns: The name of the Machine
186  */
187
188 static char *PrintMachInfo(char **info)
189 {
190   char buf[BUFSIZ], tbuf[256];
191   char *args[3];
192   struct mqelem *elem = NULL;
193   int stat;
194
195   Put_message("");
196   sprintf(buf, "Machine:  %s", info[M_NAME]);
197   Put_message(buf);
198   args[0] = "*";
199   args[1] = info[M_NAME];
200   if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
201     {
202       if (stat != MR_NO_MATCH)
203         com_err(program_name, stat, " looking up aliases");
204     }
205   else
206     {
207       aliasbuf[0] = 0;
208       Loop(QueueTop(elem), (void (*)(char **)) PrintAliases);
209       FreeQueue(elem);
210       Put_message(aliasbuf);
211     }
212   sprintf(tbuf, "%s %s", info[M_OWNER_TYPE],
213           strcmp(info[M_OWNER_TYPE], "NONE") ? info[M_OWNER_NAME] : "");
214   sprintf(buf, "Address:  %-16s    Network:    %-16s",
215           info[M_ADDR], info[M_SUBNET]);
216   Put_message(buf);
217   sprintf(buf, "Owner:    %-16s    Use data:   %s", tbuf, info[M_INUSE]);
218   Put_message(buf);
219   sprintf(buf, "Status:   %-16s    Changed:    %s",
220           MacState(atoi(info[M_STAT])), info[M_STAT_CHNG]);
221   Put_message(buf);
222   Put_message("");
223
224   sprintf(buf, "Vendor:   %-16s    Location:        %s", info[M_VENDOR], 
225           info[M_LOC]);
226   Put_message(buf);
227   sprintf(buf, "Model:    %-16s    Contact:         %s", info[M_MODEL], 
228           info[M_CONTACT]);
229   Put_message(buf);
230   sprintf(buf, "OS:       %-16s    Billing Contact: %s", info[M_OS],
231           info[M_BILL_CONTACT]);
232   Put_message(buf);
233   Put_message("");
234   sprintf(buf, "Opt: %s", info[M_USE]);
235   Put_message(buf);
236   Put_message("");
237   sprintf(buf, "Adm cmt: %s", info[M_ACOMMENT]);
238   Put_message(buf);
239   sprintf(buf, "Op cmt:  %s", info[M_OCOMMENT]);
240   Put_message(buf);
241   Put_message("");
242   sprintf(buf, "Created  by %s on %s", info[M_CREATOR], info[M_CREATED]);
243   Put_message(buf);
244   sprintf(buf, MOD_FORMAT, info[M_MODBY], info[M_MODTIME], info[M_MODWITH]);
245   Put_message(buf);
246   return info[M_NAME];
247 }
248
249 /*      Function Name: PrintMachine
250  *      Description: Prints the name of a machine record
251  *      Arguments: info - array of information about the machine.
252  *      Returns: nothing.
253  */
254
255 static void PrintMachine(char **info)
256 {
257      char buf[BUFSIZ];
258
259      sprintf(buf, "Machine: %s", info[M_NAME]);
260      Put_message(buf);
261 }
262
263 /*      Function Name: PrintCname
264  *      Description: Prints the Data on a host alias
265  *      Arguments: info a pointer to the data array.
266  *      Returns: The name of the alias.
267  */
268
269 static char *PrintCname(char **info)
270 {
271   char buf[BUFSIZ];
272
273   sprintf(buf, "Alias: %-32s Canonical Name: %s", info[0], info[1]);
274   Put_message(buf);
275   return info[0];
276 }
277
278 /*      Function Name: PrintClusterInfo
279  *      Description: This function Prints out the cluster info
280  *                   in a coherent form.
281  *      Arguments: info - array of information about a cluster.
282  *      Returns: The name of the cluster.
283  */
284
285 static char *PrintClusterInfo(char **info)
286 {
287   char buf[BUFSIZ];
288
289   Put_message("");
290   sprintf(buf, "Cluster:     %s", info[C_NAME]);
291   Put_message(buf);
292   sprintf(buf, "Description: %s", info[C_DESCRIPT]);
293   Put_message(buf);
294   sprintf(buf, "Location:    %s", info[C_LOCATION]);
295   Put_message(buf);
296   sprintf(buf, MOD_FORMAT, info[C_MODBY], info[C_MODTIME], info[C_MODWITH]);
297   Put_message(buf);
298   return info[C_NAME];
299 }
300
301 /*      Function Name: PrintClusterData
302  *      Description: Prints the Data on a cluster
303  *      Arguments: info a pointer to the data array.
304  *      Returns: The name of the cluster.
305  */
306
307 static char *PrintClusterData(char **info)
308 {
309   char buf[BUFSIZ];
310
311   Put_message("");
312   sprintf(buf, "Cluster: %-20s Label: %-15s Data: %s",
313           info[CD_NAME], info[CD_LABEL], info[CD_DATA]);
314   Put_message(buf);
315   return info[CD_NAME];
316 }
317
318 /*      Function Name: PrintMCMap
319  *      Description: Prints the data about a machine to cluster mapping.
320  *      Arguments: info a pointer to the data array.
321  *      Returns: none
322  */
323
324 static char *PrintMCMap(char **info)
325 {
326   char buf[BUFSIZ];
327   sprintf(buf, "Cluster: %-30s Machine: %-20s",
328           info[MAP_CLUSTER], info[MAP_MACHINE]);
329   Put_message(buf);
330   return "";                    /* Used by QueryLoop(). */
331 }
332
333 /*      Function Name: PrintSubnetInfo
334  *      Description: This function Prints out the subnet info
335  *                   in a coherent form.
336  *      Arguments: info - array of information about a subnet.
337  *      Returns: The name of the subnet.
338  */
339
340 static char *PrintSubnetInfo(char **info)
341 {
342   char buf[BUFSIZ];
343   struct in_addr addr, mask, low, high;
344
345   Put_message("");
346   sprintf(buf, "        Network:  %s", info[SN_NAME]);
347   Put_message(buf);
348   sprintf(buf, "    Description:  %s", info[SN_DESC]);
349   Put_message(buf);
350   addr.s_addr = htonl(atoi(info[SN_ADDRESS]));
351   mask.s_addr = htonl(atoi(info[SN_MASK]));
352   low.s_addr = htonl(atoi(info[SN_LOW]));
353   high.s_addr = htonl(atoi(info[SN_HIGH]));
354   /* screwy sequence is here because inet_ntoa returns a pointer to
355      a static buf.  If it were all one sprintf, the last value would
356      appear 4 times. */
357   sprintf(buf, "        Address:  %s        Mask:  ", inet_ntoa(addr));
358   strcat(buf, inet_ntoa(mask));
359   strcat(buf, "\n           High:  ");
360   strcat(buf, inet_ntoa(high));
361   strcat(buf, "       Low:  ");
362   strcat(buf, inet_ntoa(low));
363   Put_message(buf);
364   sprintf(buf, "Hostname prefix:  %s", info[SN_PREFIX]);
365   Put_message(buf);
366   sprintf(buf, "          Owner:  %s %s\n", info[SN_ACE_TYPE],
367           strcmp(info[SN_ACE_TYPE], "NONE") ? info[SN_ACE_NAME] : "");
368   Put_message(buf);
369   sprintf(buf, MOD_FORMAT, info[SN_MODBY], info[SN_MODTIME], info[SN_MODWITH]);
370   Put_message(buf);
371   return info[SN_NAME];
372 }
373
374 /*      Function Name: GetMCInfo.
375  *      Description: This function stores info about a machine.
376  *                   type - type of data we are trying to retrieve.
377  *                   name1 - the name of argv[0] for the call.
378  *                   name2 - the name of argv[1] for the call.
379  *      Returns: the top element of a queue containing the data or NULL.
380  */
381
382 struct mqelem *GetMCInfo(int type, char *name1, char *name2)
383 {
384   int stat;
385   struct mqelem *elem = NULL;
386   char *args[5];
387
388   switch (type)
389     {
390     case MACHINE:
391       args[0] = name1;
392       args[1] = args[2] = args[3] = "*";
393       if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
394         {
395           if (stat == MR_NO_MATCH)
396             {
397               char buf[128];
398               sprintf(buf, "Machine '%s' is not in the database.", name1);
399               Put_message(buf);
400             }
401           else
402             com_err(program_name, stat, " in get_machine.");
403           return NULL;
404         }
405       break;
406     case CNAME:
407       args[0] = name1;
408       args[1] = name2;
409       if ((stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem)))
410         {
411           com_err(program_name, stat, " in get_hostalias.");
412           return NULL;
413         }
414       break;
415     case SUBNET:
416       if ((stat = do_mr_query("get_subnet", 1, &name1, StoreInfo, &elem)))
417         {
418           if (stat == MR_NO_MATCH)
419             {
420               char buf[128];
421               sprintf(buf, "Network '%s' is not in the database.", name1);
422               Put_message(buf);
423             }
424           else
425             com_err(program_name, stat, " in get_subnet.");
426           return NULL;
427         }
428       break;
429     case CLUSTER:
430       if ((stat = do_mr_query("get_cluster", 1, &name1, StoreInfo, &elem)))
431         {
432           com_err(program_name, stat, " in get_cluster.");
433           return NULL;
434         }
435       break;
436     case MAP:
437       args[MAP_MACHINE] = name1;
438       args[MAP_CLUSTER] = name2;
439       if ((stat = do_mr_query("get_machine_to_cluster_map", 2, args,
440                               StoreInfo, &elem)))
441         {
442           com_err(program_name, stat, " in get_machine_to_cluster_map.");
443           return NULL;
444         }
445       break;
446     case DATA:
447       args[CD_NAME] = name1;
448       args[CD_LABEL] = name2;
449       if ((stat = do_mr_query("get_cluster_data", 2, args, StoreInfo, &elem)))
450         {
451           com_err(program_name, stat, " in get_cluster_data.");
452           return NULL;
453         }
454     }
455   return QueueTop(elem);
456 }
457
458 /*      Function Name: AskMCDInfo.
459  *      Description: This function askes the user for information about a
460  *                   machine and saves it into a structure.
461  *      Arguments: info - a pointer the information to ask about
462  *                 type - type of information - MACHINE
463  *                                              CLUSTER
464  *                                              DATA
465  *                 name - T/F : change the name of this type.
466  *      Returns: none.
467  */
468
469 char **AskMCDInfo(char **info, int type, Bool name)
470 {
471   char temp_buf[BUFSIZ], *newname, *oldnewname;
472
473   switch (type)
474     {
475     case MACHINE:
476       sprintf(temp_buf, "\nSetting the information for the Machine %s...",
477               info[M_NAME]);
478       break;
479     case SUBNET:
480       sprintf(temp_buf, "Setting the information for the Network %s...",
481               info[SN_NAME]);
482       break;
483     case CLUSTER:
484       sprintf(temp_buf, "Setting the information for the Cluster %s...",
485               info[C_NAME]);
486       break;
487     case DATA:
488       sprintf(temp_buf, "Setting the Data for the Cluster %s...",
489               info[CD_NAME]);
490       break;
491     }
492   Put_message(temp_buf);
493
494   if (name)
495     {
496       switch (type)
497         {
498         case MACHINE:
499           newname = strdup(info[M_NAME]);
500           if (GetValueFromUser("The new name for this machine? ", &newname) ==
501               SUB_ERROR)
502             return NULL;
503           oldnewname = strdup(newname);
504           newname = canonicalize_hostname(newname);
505           if (strcasecmp(newname, oldnewname) && *oldnewname != '"')
506             {
507               sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'\n",
508                       oldnewname, newname);
509               Put_message(temp_buf);
510             }
511           free(oldnewname);
512           break;
513         case SUBNET:
514           newname = strdup(info[SN_NAME]);
515           if (GetValueFromUser("The new name for this network? ", &newname) ==
516               SUB_ERROR)
517             return NULL;
518           break;
519         case CLUSTER:
520           newname = strdup(info[C_NAME]);
521           if (GetValueFromUser("The new name for this cluster? ", &newname) ==
522               SUB_ERROR)
523             return NULL;
524           break;
525         default:
526           Put_message("Unknown type in AskMCDInfo, programmer botch");
527           return NULL;
528         }
529     }
530
531   switch (type)
532     {
533     case MACHINE:
534       if (GetValueFromUser("Machine's vendor", &info[M_VENDOR]) == SUB_ERROR)
535         return NULL;
536       if (GetValueFromUser("Machine's model", &info[M_MODEL]) == SUB_ERROR)
537         return NULL;
538       if (GetValueFromUser("Machine's operating system", &info[M_OS]) ==
539           SUB_ERROR)
540         return NULL;
541       if (GetValueFromUser("Machine's location", &info[M_LOC]) == SUB_ERROR)
542         return NULL;
543       if (GetValueFromUser("Machine's contact", &info[M_CONTACT]) ==
544           SUB_ERROR)
545         return NULL;
546       if (GetValueFromUser("Machine's billing contact", 
547                            &info[M_BILL_CONTACT]) == SUB_ERROR)
548         return NULL;
549       while (1)
550         {
551           int i;
552           if (GetValueFromUser("Machine's status (? for help)",
553                                  &info[M_STAT]) == SUB_ERROR)
554             return NULL;
555           if (isdigit(info[M_STAT][0]))
556             break;
557           Put_message("Valid status numbers:");
558           for (i = 0; i < 4; i++)
559             Put_message(states[i]);
560         }
561
562       /* there appears to be some argument mismatch between the client
563        * and the server.. so here is this argument shuffler.
564        * I have since modified this to always shuffle the arguments..
565        * not just do so when performing a modify all fields request.
566        * The SetMachinedefaults() has been changed to reflect this.
567        * pray for us and may we attain enlightenment through structures.
568        */
569
570       if (name)
571         {
572           /* info did not come from SetMachineDefaults(), which does not
573            * initialize entry 8 (M_STAT_CHNG), therefore we can
574            * free it.
575            */
576           /* This is an update of an existing machine and the structure
577            * was filled in thru a query to the db which does fill in this
578            * field.
579            */
580           free(info[9]);
581         }
582
583       info[9] = info[M_SUBNET];
584       info[10] = info[M_ADDR];
585       info[11] = info[M_OWNER_TYPE];
586       info[12] = info[M_OWNER_NAME];
587       info[13] = info[M_ACOMMENT];
588       info[14] = info[M_OCOMMENT];
589
590       if (name)
591         {
592           if (GetValueFromUser("Machine's network (or 'none')", &info[9])
593               == SUB_ERROR)
594             return NULL;
595         }
596       if (GetValueFromUser("Machine's address (or 'unassigned' or 'unique')",
597                            &info[10]) == SUB_ERROR)
598         return NULL;
599       if (GetTypeFromUser("Machine's owner type", "ace_type", &info[11]) ==
600           SUB_ERROR)
601         return NULL;
602       if (strcmp(info[11], "NONE") &&
603           GetValueFromUser("Owner's Name", &info[12]) == SUB_ERROR)
604         return NULL;
605       if (!strcmp(info[11], "KERBEROS"))
606           {
607             char *canon;
608
609             mrcl_validate_kerberos_member(info[12], &canon);
610             if (mrcl_get_message())
611               Put_message(mrcl_get_message());
612             free(info[12]);
613             info[12] = canon;
614           }
615       if (GetValueFromUser("Administrative comment", &info[13]) == SUB_ERROR)
616         return NULL;
617       if (GetValueFromUser("Operational comment", &info[14]) == SUB_ERROR)
618         return NULL;
619       info[15] = NULL;
620       FreeAndClear(&info[16], TRUE);
621       FreeAndClear(&info[17], TRUE);
622       break;
623     case SUBNET:
624       if (GetValueFromUser("Network description", &info[SN_DESC]) == SUB_ERROR)
625         return NULL;
626       if (GetAddressFromUser("Network address", &info[SN_ADDRESS]) == SUB_ERROR)
627         return NULL;
628       if (GetAddressFromUser("Network mask", &info[SN_MASK]) == SUB_ERROR)
629         return NULL;
630       if (atoi(info[SN_LOW]) == (int)ntohl(inet_addr(S_DEFAULT_LOW)))
631         {
632           struct in_addr low;
633           unsigned long mask, addr;
634
635           addr = atoi(info[SN_ADDRESS]);
636           mask = atoi(info[SN_MASK]);
637           low.s_addr = atoi(info[SN_LOW]);
638           low.s_addr = (low.s_addr & ~mask) | (addr & mask);
639           free(info[SN_LOW]);
640           sprintf(temp_buf, "%ld", low.s_addr);
641           info[SN_LOW] = strdup(temp_buf);
642         }
643       if (GetAddressFromUser("Lowest assignable address", &info[SN_LOW]) ==
644           SUB_ERROR)
645         return NULL;
646       if (atoi(info[SN_HIGH]) == (int)ntohl(inet_addr(S_DEFAULT_HIGH)))
647         {
648           struct in_addr high;
649           unsigned long mask, addr;
650
651           addr = atoi(info[SN_ADDRESS]);
652           mask = atoi(info[SN_MASK]);
653           high.s_addr = atoi(info[SN_HIGH]);
654           high.s_addr = (high.s_addr & ~mask) | (addr & mask);
655           free(info[SN_HIGH]);
656           sprintf(temp_buf, "%ld", high.s_addr);
657           info[SN_HIGH] = strdup(temp_buf);
658         }
659       if (GetAddressFromUser("Highest assignable address", &info[SN_HIGH]) ==
660           SUB_ERROR)
661         return NULL;
662       if (GetValueFromUser("Hostname prefix", &info[SN_PREFIX]) == SUB_ERROR)
663         return NULL;
664       if (GetTypeFromUser("Owner type", "ace_type", &info[SN_ACE_TYPE]) ==
665           SUB_ERROR)
666         return NULL;
667       if (strcmp(info[SN_ACE_TYPE], "NONE") &&
668           GetValueFromUser("Owner name", &info[SN_ACE_NAME]) == SUB_ERROR)
669         return NULL;
670       if (!strcmp(info[SN_ACE_TYPE], "KERBEROS"))
671           {
672             char *canon;
673
674             mrcl_validate_kerberos_member(info[SN_ACE_NAME], &canon);
675             if (mrcl_get_message())
676               Put_message(mrcl_get_message());
677             free(info[SN_ACE_NAME]);
678             info[SN_ACE_NAME] = canon;
679           }
680       FreeAndClear(&info[SN_MODTIME], TRUE);
681       FreeAndClear(&info[SN_MODBY], TRUE);
682       FreeAndClear(&info[SN_MODWITH], TRUE);
683       break;
684     case CLUSTER:
685       if (GetValueFromUser("Cluster's Description:", &info[C_DESCRIPT]) ==
686           SUB_ERROR)
687         return NULL;
688       if (GetValueFromUser("Cluster's Location:", &info[C_LOCATION]) ==
689           SUB_ERROR)
690         return NULL;
691       FreeAndClear(&info[C_MODTIME], TRUE);
692       FreeAndClear(&info[C_MODBY], TRUE);
693       FreeAndClear(&info[C_MODWITH], TRUE);
694       break;
695     case DATA:
696       if (GetValueFromUser("Label defining this data?", &info[CD_LABEL]) ==
697           SUB_ERROR)
698         return NULL;
699       if (GetValueFromUser("The data itself ? ", &info[CD_DATA]) == SUB_ERROR)
700         return NULL;
701       break;
702     }
703
704   /*
705    * Slide the newname into the #2 slot, this screws up all future references
706    * to this list.
707    */
708   if (name)
709     SlipInNewName(info, newname);
710
711   return info;
712 }
713
714 /* -----------  Machine Menu ----------- */
715
716 /*      Function Name: ShowMachineInfo
717  *      Description: This function shows the information about a machine.
718  *      Arguments: argc, argv - the name of the machine in argv[1].
719  *      Returns: DM_NORMAL.
720  */
721
722 int ShowMachineInfo(int argc, char **argv)
723 {
724   struct mqelem *top;
725   char *tmpname;
726
727   tmpname = canonicalize_hostname(strdup(argv[1]));
728   top = GetMCInfo(MACHINE, tmpname, NULL);
729   Loop(top, ((void (*)(char **)) PrintMachInfo));
730   FreeQueue(top);
731   return DM_NORMAL;
732 }
733
734 /*      Function Name: ShowMachineQuery
735  *      Description: This function shows the information about a machine.
736  *              or group of machines, which may be selected through a
737  *              number of criteria.
738  *      Arguments: argc, argv - the name of the machine in argv[1],
739  *              the address of the machine in argv[2],
740  *              the location of the machine in argv[3],
741  *              and the contact name in argv[4].
742  *           any of these may be wildcards.
743  *      Returns: DM_NORMAL.
744  */
745
746 int ShowMachineQuery(int argc, char **argv)
747 {
748   int stat;
749   struct mqelem *top, *elem = NULL;
750   char *args[5];
751
752   if (!strcmp(argv[1], "") && !strcmp(argv[2], "") &&
753       !strcmp(argv[3], "") && !strcmp(argv[4], ""))
754     {
755       Put_message("You must specify at least one parameter of the query.");
756       return DM_NORMAL;
757     }
758
759   if (*argv[1])
760     args[0] = canonicalize_hostname(strdup(argv[1]));
761   else
762     args[0] = "*";
763   if (*argv[2])
764     args[1] = argv[2];
765   else
766     args[1] = "*";
767   if (*argv[3])
768     args[2] = argv[3];
769   else
770     args[2] = "*";
771   if (*argv[4])
772     args[3] = argv[4];
773   else
774     args[3] = "*";
775
776   if ((stat = do_mr_query("get_host", 4, args, StoreInfo, &elem)))
777     {
778       if (stat == MR_NO_MATCH)
779         Put_message("No machine(s) found matching query in the database.");
780       else
781         com_err(program_name, stat, " in get_machine.");
782       return DM_NORMAL;
783     }
784   top = QueueTop(elem);
785   Loop(top, ((void (*)(char **)) PrintMachInfo));
786   FreeQueue(top);
787   return DM_NORMAL;
788 }
789
790 /*      Function Name: AddMachine
791  *      Description: This function adds a new machine to the database.
792  *      Arguments: argc, argv - the name of the network in argv[1].
793  *      Returns: DM_NORMAL.
794  */
795
796 int AddMachine(int argc, char **argv)
797 {
798   char **args, *info[MAX_ARGS_SIZE], *name, buf[256], *xargs[5];
799   char **rinfo;
800   struct mqelem *elem = NULL;
801   int stat;
802
803   if (!ValidName(argv[1]))      /* Checks for wildcards. */
804     return DM_NORMAL;
805
806   /*
807    * get the network record
808    */
809
810   if (strcasecmp(argv[1], "none") &&
811       (stat = do_mr_query("get_subnet", 1, &argv[1], StoreInfo, &elem)))
812     {
813       if (stat == MR_NO_MATCH)
814         {
815           char buf[128];
816           sprintf(buf, "Network '%s' is not in the database.", argv[1]);
817           Put_message(buf);
818         } else
819           com_err(program_name, stat, " in get_subnet.");
820       return DM_NORMAL;
821     }
822
823   /*
824    * Check to see if this machine already exists.
825    */
826
827   name = strdup(""); /* want to put prefix here */
828   if (GetValueFromUser("Machine name", &name) == SUB_ERROR)
829     return 0;
830
831   name = canonicalize_hostname(strdup(name));
832
833   xargs[0] = name;
834   xargs[1] = xargs[2] = xargs[3] = "*";
835   if (!(stat = do_mr_query("get_host", 4, xargs, NULL, NULL)))
836     {
837       sprintf(buf, "The machine '%s' already exists.", name);
838       Put_message(buf);
839       free(name);
840       return DM_NORMAL;
841     }
842   else if (stat != MR_NO_MATCH)
843     {
844       com_err(program_name, stat,
845               " while checking machine '%s' in AddMachine.", name);
846       free(name);
847       return DM_NORMAL;
848     }
849   rinfo = SetMachineDefaults(info, name);
850   rinfo[M_SUBNET] = strdup(argv[1]);
851   if (!(args = AskMCDInfo(rinfo, MACHINE, FALSE)))
852     {
853       Put_message("Aborted.");
854       return DM_NORMAL;
855     }
856
857   /*
858    * Actually create the new Machine.
859    */
860
861   if ((stat = do_mr_query("add_host", CountArgs(args), args, NULL, NULL)))
862     com_err(program_name, stat, " in AddMachine.");
863
864   FreeInfo(info);
865   free(name);
866   return DM_NORMAL;
867 }
868
869 /*      Function Name: RealUpdateMachine
870  *      Description: Performs the actual update of the machine data.
871  *      Arguments: info - the information on the machine to update.
872  *                 junk - an UNUSED Boolean.
873  *      Returns: none.
874  */
875
876 static void RealUpdateMachine(char **info, Bool junk)
877 {
878   int stat;
879   char **args = AskMCDInfo(info, MACHINE, TRUE);
880   if (!args)
881     {
882       Put_message("Aborted.");
883       return;
884     }
885   if ((stat = do_mr_query("update_host", CountArgs(args), args, NULL, NULL)))
886     com_err(program_name, stat, " in UpdateMachine.");
887   else
888     Put_message("Machine successfully updated.");
889 }
890
891 /*      Function Name: UpdateMachine
892  *      Description: This function adds a new machine to the database.
893  *      Arguments: argc, argv - the name of the machine in argv[1].
894  *      Returns: DM_NORMAL.
895  */
896
897 int UpdateMachine(int argc, char **argv)
898 {
899   struct mqelem *top;
900   char *tmpname;
901
902   tmpname = canonicalize_hostname(strdup(argv[1]));
903   top = GetMCInfo(MACHINE, tmpname, NULL);
904   QueryLoop(top, NullPrint, RealUpdateMachine, "Update the machine");
905
906   FreeQueue(top);
907   free(tmpname);
908   return DM_NORMAL;
909 }
910
911 /*      Function Name: CheckAndRemoveFromCluster
912  *      Description: This func tests to see if a machine is in a cluster.
913  *                   and if so then removes it
914  *      Arguments: name - name of the machine (already Canonicalized).
915  *                 ask_user- query the user before removing if from clusters?
916  *      Returns: MR_ERROR if machine left in a cluster, or mr_error.
917  */
918
919 int CheckAndRemoveFromCluster(char *name, Bool ask_user)
920 {
921   int stat, ret_value;
922   Bool delete_it;
923   char *args[10], temp_buf[BUFSIZ], *ptr;
924   struct mqelem *top, *elem = NULL;
925
926   ret_value = SUB_NORMAL;       /* initialize ret_value. */
927   args[0] = name;
928   args[1] = "*";
929   stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
930   if (stat && stat != MR_NO_MATCH)
931     {
932       com_err(program_name, stat, " in get_machine_to_cluster_map.");
933       return DM_NORMAL;
934     }
935   if (stat == MR_SUCCESS)
936     {
937       elem = top = QueueTop(elem);
938       if (ask_user)
939         {
940           sprintf(temp_buf, "%s is assigned to the following clusters.", name);
941           Put_message(temp_buf);
942           Loop(top, (void (*)(char **)) PrintMCMap);
943           ptr = "Remove this machine from ** ALL ** these clusters?";
944           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
945             delete_it = TRUE;
946           else
947             {
948               Put_message("Aborting...");
949               FreeQueue(top);
950               return SUB_ERROR;
951             }
952         }
953       else
954         delete_it = TRUE;
955
956       if (delete_it)
957         {
958           while (elem)
959             {
960               char **info = elem->q_data;
961               if ((stat = do_mr_query("delete_machine_from_cluster",
962                                        2, info, NULL, NULL)))
963                 {
964                   ret_value = SUB_ERROR;
965                   com_err(program_name, stat,
966                           " in delete_machine_from_cluster.");
967                   sprintf(temp_buf,
968                           "Machine %s ** NOT ** removed from cluster %s.",
969                           info[MAP_MACHINE], info[MAP_CLUSTER]);
970                   Put_message(temp_buf);
971                 }
972               elem = elem->q_forw;
973             }
974         }
975     }
976   return ret_value;
977 }
978
979 /*      Function Name: CheckAndRemoveCnames
980  *      Description: This func tests to see if a machine has cnames, 
981  *                   and if so then removes them.
982  *      Arguments: name - name of the machine (already Canonicalized).
983  *                 ask_user- query the user before removing cnames?
984  *      Returns: MR_ERROR if machine left with a cname, or mr_error.
985  */
986
987 int CheckAndRemoveCnames(char *name, Bool ask_user)
988 {
989   int stat, ret_value;
990   Bool delete_it;
991   char *args[10], temp_buf[BUFSIZ], *ptr;
992   struct mqelem *top, *elem = NULL;
993
994   ret_value = SUB_NORMAL;
995   args[0] = "*";
996   args[1] = name;
997   stat = do_mr_query("get_hostalias", 2, args, StoreInfo, &elem);
998   if (stat && stat != MR_NO_MATCH)
999     {
1000       com_err(program_name, stat, " in get_hostalias.");
1001       return DM_NORMAL;
1002     }
1003   if (stat == MR_SUCCESS)
1004     {
1005       elem = top = QueueTop(elem);
1006       if (ask_user)
1007         {
1008           sprintf(temp_buf, "%s has the following cnames.", name);
1009           Put_message(temp_buf);
1010           Loop(top, (void (*)(char **)) PrintCname);
1011           ptr = "Remove ** ALL ** these cnames?";
1012           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1013             delete_it = TRUE;
1014           else
1015             {
1016               Put_message("Aborting...");
1017               FreeQueue(top);
1018               return SUB_ERROR;
1019             }
1020         }
1021       else
1022         delete_it = TRUE;
1023
1024       if (delete_it)
1025         {
1026           while (elem)
1027             {
1028               char **info = elem->q_data;
1029               if ((stat = do_mr_query("delete_hostalias", 2, info, 
1030                                       NULL, NULL)))
1031                 {
1032                   ret_value = SUB_ERROR;
1033                   com_err(program_name, stat, " in delete_hostalias.");
1034                   sprintf(temp_buf, 
1035                           "Cname %s ** NOT ** removed from host %s.",
1036                           info[0], info[1]);
1037                   Put_message(temp_buf);
1038                 }
1039               elem = elem->q_forw;
1040             }
1041         }
1042     }
1043   return ret_value;
1044 }
1045
1046 /*      Function Name: RealDeleteMachine
1047  *      Description: Actually Deletes the Machine.
1048  *      Arguments: info - nescessary information stored as an array of char *'s
1049  *                 one_machine - a boolean, true if there is only one item in
1050  *                               the query.
1051  *      Returns: none.
1052  */
1053
1054 static void RealDeleteMachine(char **info, Bool one_machine)
1055 {
1056   int stat;
1057   char temp_buf[BUFSIZ];
1058
1059   sprintf(temp_buf, "Are you sure you want to delete the machine %s (y/n)? ",
1060           info[M_NAME]);
1061   if (!one_machine || Confirm(temp_buf))
1062     {
1063       if (CheckAndRemoveFromCluster(info[M_NAME], TRUE) != SUB_ERROR)
1064         {
1065           if (CheckAndRemoveCnames(info[M_NAME], TRUE) != SUB_ERROR)
1066             {
1067               if ((stat = do_mr_query("delete_host", 1,
1068                                       &info[M_NAME], NULL, NULL)))
1069                 {
1070                   com_err(program_name, stat, " in DeleteMachine.");
1071                   sprintf(temp_buf, "%s ** NOT ** deleted.",
1072                           info[M_NAME]);
1073                   Put_message(temp_buf);
1074                 }
1075               else
1076                 {
1077                   sprintf(temp_buf, "%s successfully Deleted.", info[M_NAME]);
1078                   Put_message(temp_buf);
1079                 }
1080             }
1081         }
1082     }
1083 }
1084
1085 /*      Function Name: DeleteMachine
1086  *      Description: This function removes a machine from the data base.
1087  *      Arguments: argc, argv - the machines name int argv[1].
1088  *      Returns: DM_NORMAL.
1089  */
1090
1091 /* Perhaps we should remove the cluster if it has no machine now. */
1092
1093 int DeleteMachine(int argc, char **argv)
1094 {
1095   struct mqelem *top;
1096   char *tmpname;
1097
1098   tmpname = canonicalize_hostname(strdup(argv[1]));
1099   top = GetMCInfo(MACHINE, tmpname, (char *) NULL);
1100   QueryLoop(top, PrintMachInfo, RealDeleteMachine, "Delete the machine");
1101   FreeQueue(top);
1102   free(tmpname);
1103   return DM_NORMAL;
1104 }
1105
1106
1107 /*      Function Name: ShowCname
1108  *      Description: This function shows machine aliases
1109  *      Arguments: argc, argv - the alias argv[1], the real name in argv[2]
1110  *      Returns: DM_NORMAL.
1111  */
1112
1113 int ShowCname(int argc, char **argv)
1114 {
1115   struct mqelem *top;
1116   char *tmpalias, *tmpname;
1117
1118   tmpalias = partial_canonicalize_hostname(strdup(argv[1]));
1119   tmpname = canonicalize_hostname(strdup(argv[2]));
1120   top = GetMCInfo(CNAME, tmpalias, tmpname);
1121   Put_message("");              /* blank line on screen */
1122   Loop(top, ((void (*)(char **)) PrintCname));
1123   FreeQueue(top);
1124   return DM_NORMAL;
1125 }
1126
1127
1128 int AddCname(int argc, char **argv)
1129 {
1130   int stat;
1131   char *args[10];
1132
1133   args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1134   args[1] = canonicalize_hostname(strdup(argv[2]));
1135   stat = do_mr_query("add_hostalias", 2, args, NULL, NULL);
1136   switch (stat)
1137     {
1138     case MR_SUCCESS:
1139       break;
1140     case MR_EXISTS:
1141       Put_message("That alias name is already in use.");
1142       break;
1143     case MR_PERM:
1144       Put_message("Permission denied.  "
1145                   "(Regular users can only add two aliases to a host.");
1146       break;
1147     default:
1148       com_err(program_name, stat, " in add_hostalias");
1149     }
1150   return DM_NORMAL;
1151 }
1152
1153
1154 int DeleteCname(int argc, char **argv)
1155 {
1156   int stat;
1157   char *args[10];
1158
1159   args[0] = partial_canonicalize_hostname(strdup(argv[1]));
1160   args[1] = canonicalize_hostname(strdup(argv[2]));
1161   stat = do_mr_query("delete_hostalias", 2, args, NULL, NULL);
1162   if (stat)
1163     com_err(program_name, stat, " in delete_hostalias");
1164   return DM_NORMAL;
1165 }
1166
1167
1168 /*      Function Name: AddMachineToCluster
1169  *      Description: This function adds a machine to a cluster
1170  *      Arguments: argc, argv - The machine name is argv[1].
1171  *                              The cluster name in argv[2].
1172  *      Returns: DM_NORMAL.
1173  */
1174
1175 int AddMachineToCluster(int argc, char **argv)
1176 {
1177   int stat;
1178   char *machine, *cluster, temp_buf[BUFSIZ], *args[10];
1179   Bool add_it, one_machine, one_cluster;
1180   struct mqelem *melem, *mtop, *celem, *ctop;
1181
1182   machine = canonicalize_hostname(strdup(argv[1]));
1183   if (strcasecmp(machine, argv[1]) && *argv[1] != '"')
1184     {
1185       sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1186               argv[1], machine);
1187       Put_message(temp_buf);
1188     }
1189   cluster = argv[2];
1190
1191   celem = ctop = GetMCInfo(CLUSTER, cluster, NULL);
1192   melem = mtop = GetMCInfo(MACHINE, machine, NULL);
1193   free(machine);
1194
1195   one_machine = (QueueCount(mtop) == 1);
1196   one_cluster = (QueueCount(ctop) == 1);
1197
1198   /* No good way to use QueryLoop() here, sigh */
1199
1200   while (melem)
1201     {
1202       char **minfo = melem->q_data;
1203       while (celem)
1204         {
1205           char **cinfo = celem->q_data;
1206           if (one_machine && one_cluster)
1207             add_it = TRUE;
1208           else
1209             {
1210               sprintf(temp_buf, "Add machine %s to cluster %s (y/n/q) ?",
1211                       minfo[M_NAME], cinfo[C_NAME]);
1212               switch (YesNoQuitQuestion(temp_buf, FALSE))
1213                 {
1214                 case TRUE:
1215                   add_it = TRUE;
1216                   break;
1217                 case FALSE:
1218                   add_it = FALSE;
1219                   break;
1220                 default:
1221                   Put_message("Aborting...");
1222                   FreeQueue(ctop);
1223                   FreeQueue(mtop);
1224                   return DM_NORMAL;
1225                 }
1226             }
1227           if (add_it)
1228             {
1229               args[0] = minfo[M_NAME];
1230               args[1] = cinfo[C_NAME];
1231               stat = do_mr_query("add_machine_to_cluster", 2, args,
1232                                  NULL, NULL);
1233               switch (stat)
1234                 {
1235                 case MR_SUCCESS:
1236                   break;
1237                 case MR_EXISTS:
1238                   sprintf(temp_buf, "%s is already in cluster %s",
1239                           minfo[M_NAME], cinfo[C_NAME]);
1240                   Put_message(temp_buf);
1241                   break;
1242                 default:
1243                   com_err(program_name, stat, " in AddMachineToCluster.");
1244                   break;
1245                 }
1246             }
1247           celem = celem->q_forw;
1248         }
1249       celem = ctop;             /* reset cluster element. */
1250       melem = melem->q_forw;
1251     }
1252   FreeQueue(ctop);
1253   FreeQueue(mtop);
1254   return DM_NORMAL;
1255 }
1256
1257 /*      Function Name: RealRemoveMachineFromCluster
1258  *      Description: This function actually removes the machine from its
1259  *                   cluster.
1260  *      Arguments: info - all information nescessary to perform the removal.
1261  *                 one_map - True if there is only one case, and we should
1262  *                           confirm.
1263  *      Returns: none.
1264  */
1265
1266 static void RealRemoveMachineFromCluster(char **info, Bool one_map)
1267 {
1268   char temp_buf[BUFSIZ];
1269   int stat;
1270
1271   sprintf(temp_buf, "Remove %s from the cluster %s",
1272           info[MAP_MACHINE], info[MAP_CLUSTER]);
1273   if (!one_map || Confirm(temp_buf))
1274     {
1275       if ((stat = do_mr_query("delete_machine_from_cluster", 2,
1276                               info, NULL, NULL)))
1277         com_err(program_name, stat, " in delete_machine_from_cluster");
1278       else
1279         {
1280           sprintf(temp_buf, "%s has been removed from the cluster %s.",
1281                   info[MAP_MACHINE], info[MAP_CLUSTER]);
1282           Put_message(temp_buf);
1283         }
1284     }
1285   else
1286     Put_message("Machine not removed.");
1287 }
1288
1289 /*      Function Name: RemoveMachineFromCluster
1290  *      Description: Removes this machine form a specific cluster.
1291  *      Arguments: argc, argv - Name of machine in argv[1].
1292  *                              Name of cluster in argv[2].
1293  *      Returns: none.
1294  */
1295
1296 int RemoveMachineFromCluster(int argc, char **argv)
1297 {
1298   struct mqelem *elem = NULL;
1299   char buf[BUFSIZ], * args[10];
1300   int stat;
1301
1302   args[MAP_MACHINE] = canonicalize_hostname(strdup(argv[1]));
1303   if (strcasecmp(args[MAP_MACHINE], argv[1]) && *argv[1] != '"')
1304     {
1305       sprintf(buf, "Warning: '%s' canonicalized to '%s'.",
1306               argv[1], args[MAP_MACHINE]);
1307       Put_message(buf);
1308     }
1309   args[MAP_CLUSTER] = argv[2];
1310   args[MAP_END] = NULL;
1311
1312   stat = do_mr_query("get_machine_to_cluster_map", CountArgs(args), args,
1313                      StoreInfo, &elem);
1314   if (stat == MR_NO_MATCH)
1315     {
1316       sprintf(buf, "The machine %s is not is the cluster %s.",
1317               args[MAP_MACHINE], args[MAP_CLUSTER]);
1318       Put_message(buf);
1319       free(args[MAP_MACHINE]);
1320       return DM_NORMAL;
1321     }
1322   if (stat != MR_SUCCESS)
1323     com_err(program_name, stat, " in delete_machine_from_cluster");
1324
1325   elem = QueueTop(elem);
1326   QueryLoop(elem, PrintMCMap, RealRemoveMachineFromCluster,
1327             "Remove this machine from this cluster");
1328
1329   FreeQueue(elem);
1330   free(args[MAP_MACHINE]);
1331   return DM_NORMAL;
1332 }
1333
1334 /* ---------- Subnet Menu -------- */
1335
1336 /*      Function Name: ShowSubnetInfo
1337  *      Description: Gets information about a subnet given its name.
1338  *      Arguments: argc, argc - the name of the subnet in in argv[1].
1339  *      Returns: DM_NORMAL.
1340  */
1341
1342 int ShowSubnetInfo(int argc, char **argv)
1343 {
1344   struct mqelem *top;
1345
1346   top = GetMCInfo(SUBNET, argv[1], (char *) NULL);
1347   Loop(top, (void (*)(char **)) PrintSubnetInfo);
1348   FreeQueue(top);
1349   return DM_NORMAL;
1350 }
1351
1352 /*      Function Name: AddSubnet
1353  *      Description: Creates a new subnet.
1354  *      Arguments: argc, argv - the name of the new subnet is argv[1].
1355  *      Returns: DM_NORMAL.
1356  */
1357
1358 int AddSubnet(int argc, char **argv)
1359 {
1360   char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1361   int stat;
1362
1363   /*
1364    * Check to see if this subnet already exists.
1365    */
1366   if (!ValidName(name))
1367     return DM_NORMAL;
1368
1369   if ((stat = do_mr_query("get_subnet", 1, &name, NULL, NULL)) == MR_SUCCESS)
1370     {
1371       Put_message("This subnet already exists.");
1372       return DM_NORMAL;
1373     }
1374   else if (stat != MR_NO_MATCH)
1375     {
1376       com_err(program_name, stat, " in AddSubnet.");
1377       return DM_NORMAL;
1378     }
1379   if (!(args = AskMCDInfo(SetSubnetDefaults(info, name), SUBNET, FALSE)))
1380     {
1381       Put_message("Aborted.");
1382       FreeInfo(info);
1383       return DM_NORMAL;
1384     }
1385
1386   /*
1387    * Actually create the new Subnet.
1388    */
1389   if ((stat = do_mr_query("add_subnet", CountArgs(args), args, NULL, NULL)))
1390     com_err(program_name, stat, " in AddSubnet.");
1391
1392   FreeInfo(info);
1393   return DM_NORMAL;
1394 }
1395
1396 /*      Function Name: RealUpdateSubnet
1397  *      Description: This function actually performs the subnet update.
1398  *      Arguments: info - all information nesc. for updating the subnet.
1399  *                 junk - an UNUSED boolean.
1400  *      Returns: none.
1401  */
1402
1403 static void RealUpdateSubnet(char **info, Bool junk)
1404 {
1405   int stat;
1406   char **args = AskMCDInfo(info, SUBNET, TRUE);
1407   if (!args)
1408     {
1409       Put_message("Aborted.");
1410       return;
1411     }
1412   if ((stat = do_mr_query("update_subnet", CountArgs(args), args, NULL, NULL)))
1413     com_err(program_name, stat, " in UpdateSubnet.");
1414   else
1415     Put_message("Subnet successfully updated.");
1416 }
1417
1418 /*      Function Name: UpdateSubnet
1419  *      Description: This Function Updates a subnet
1420  *      Arguments: name of the subnet in argv[1].
1421  *      Returns: DM_NORMAL.
1422  */
1423
1424 int UpdateSubnet(int argc, char **argv)
1425 {
1426   struct mqelem *top;
1427   top = GetMCInfo(SUBNET, argv[1], NULL);
1428   QueryLoop(top, NullPrint, RealUpdateSubnet, "Update the subnet");
1429
1430   FreeQueue(top);
1431   return DM_NORMAL;
1432 }
1433
1434 /*      Function Name: RealDeleteSubnet
1435  *      Description: Actually performs the subnet deletion.
1436  *      Arguments: info - all information about this subnet.
1437  *                 one_subnet - If true then there was only one subnet in
1438  *                               the queue, and we should confirm.
1439  *      Returns: none.
1440  */
1441
1442 static void RealDeleteSubnet(char **info, Bool one_subnet)
1443 {
1444   int stat;
1445   char temp_buf[BUFSIZ];
1446
1447   sprintf(temp_buf,
1448           "Are you sure the you want to delete the subnet %s (y/n) ?",
1449           info[C_NAME]);
1450   if (!one_subnet || Confirm(temp_buf))
1451     {
1452       if ((stat = do_mr_query("delete_subnet", 1, &info[C_NAME], NULL, NULL)))
1453         {
1454           com_err(program_name, stat, " in delete_subnet.");
1455           sprintf(temp_buf, "Subnet %s ** NOT ** deleted.", info[C_NAME]);
1456           Put_message(temp_buf);
1457         }
1458       else
1459         {
1460           sprintf(temp_buf, "subnet %s successfully deleted.",
1461                   info[C_NAME]);
1462           Put_message(temp_buf);
1463         }
1464     }
1465 }
1466
1467 /*      Function Name: DeleteSubnet
1468  *      Description: This function removes a subnet from the database.
1469  *      Arguments: argc, argv - the name of the subnet is stored in argv[1].
1470  *      Returns: DM_NORMAL.
1471  */
1472
1473 int DeleteSubnet(int argc, char **argv)
1474 {
1475   struct mqelem *top;
1476
1477   top = GetMCInfo(SUBNET, argv[1], NULL);
1478   QueryLoop(top, PrintSubnetInfo, RealDeleteSubnet, "Delete the subnet");
1479
1480   FreeQueue(top);
1481   return DM_NORMAL;
1482 }
1483
1484 /* ---------- Cluster Menu -------- */
1485
1486 /*      Function Name: ShowClusterInfo
1487  *      Description: Gets information about a cluser given its name.
1488  *      Arguments: argc, argc - the name of the cluster in in argv[1].
1489  *      Returns: DM_NORMAL.
1490  */
1491
1492 int ShowClusterInfo(int argc, char **argv)
1493 {
1494   struct mqelem *top;
1495
1496   top = GetMCInfo(CLUSTER, argv[1], NULL);
1497   Loop(top, (void (*)(char **)) PrintClusterInfo);
1498   FreeQueue(top);
1499   return DM_NORMAL;
1500 }
1501
1502 /*      Function Name: AddCluster
1503  *      Description: Creates a new cluster.
1504  *      Arguments: argc, argv - the name of the new cluster is argv[1].
1505  *      Returns: DM_NORMAL.
1506  */
1507
1508 int AddCluster(int argc, char **argv)
1509 {
1510   char **args, *info[MAX_ARGS_SIZE], *name = argv[1];
1511   int stat;
1512
1513   /*
1514    * Check to see if this cluster already exists.
1515    */
1516   if (!ValidName(name))
1517     return DM_NORMAL;
1518
1519   if ((stat = do_mr_query("get_cluster", 1, &name, NULL, NULL)) == MR_SUCCESS)
1520     {
1521       Put_message("This cluster already exists.");
1522       return DM_NORMAL;
1523     }
1524   else if (stat != MR_NO_MATCH)
1525     {
1526       com_err(program_name, stat, " in AddCluster.");
1527       return DM_NORMAL;
1528     }
1529   if (!(args = AskMCDInfo(SetClusterDefaults(info, name), CLUSTER, FALSE)))
1530     {
1531       Put_message("Aborted.");
1532       FreeInfo(info);
1533       return DM_NORMAL;
1534     }
1535
1536   /*
1537    * Actually create the new Cluster.
1538    */
1539   if ((stat = do_mr_query("add_cluster", CountArgs(args), args, NULL, NULL)))
1540     com_err(program_name, stat, " in AddCluster.");
1541
1542   FreeInfo(info);
1543   return DM_NORMAL;
1544 }
1545
1546 /*      Function Name: RealUpdateCluster
1547  *      Description: This function actually performs the cluster update.
1548  *      Arguments: info - all information nesc. for updating the cluster.
1549  *                 junk - an UNUSED boolean.
1550  *      Returns: none.
1551  */
1552
1553 static void RealUpdateCluster(char **info, Bool junk)
1554 {
1555   int stat;
1556   char **args = AskMCDInfo(info, CLUSTER, TRUE);
1557
1558   if (!args)
1559     {
1560       Put_message("Aborted.");
1561       return;
1562     }
1563   if ((stat = do_mr_query("update_cluster", CountArgs(args),
1564                           args, NULL, NULL)))
1565     com_err(program_name, stat, " in UpdateCluster.");
1566   else
1567     Put_message("Cluster successfully updated.");
1568 }
1569
1570 /*      Function Name: UpdateCluster
1571  *      Description: This Function Updates a cluster
1572  *      Arguments: name of the cluster in argv[1].
1573  *      Returns: DM_NORMAL.
1574  */
1575
1576 int UpdateCluster(int argc, char **argv)
1577 {
1578   struct mqelem *top;
1579   top = GetMCInfo(CLUSTER, argv[1], NULL);
1580   QueryLoop(top, NullPrint, RealUpdateCluster, "Update the cluster");
1581
1582   FreeQueue(top);
1583   return DM_NORMAL;
1584 }
1585
1586 /*      Function Name: CheckAndRemoveMachine
1587  *      Description: This function checks and removes all machines from a
1588  *                   cluster.
1589  *      Arguments: name - name of the cluster.
1590  *                 ask_first - if TRUE, then we will query the user, before
1591  *                             deletion.
1592  *      Returns: SUB_ERROR if all machines not removed.
1593  */
1594
1595 int CheckAndRemoveMachines(char *name, Bool ask_first)
1596 {
1597   int stat, ret_value;
1598   Bool delete_it;
1599   char *args[10], temp_buf[BUFSIZ], *ptr;
1600   struct mqelem *top, *elem = NULL;
1601
1602   ret_value = SUB_NORMAL;
1603   args[MAP_MACHINE] = "*";
1604   args[MAP_CLUSTER] = name;
1605   stat = do_mr_query("get_machine_to_cluster_map", 2, args, StoreInfo, &elem);
1606   if (stat && stat != MR_NO_MATCH)
1607     {
1608       com_err(program_name, stat, " in get_machine_to_cluster_map.");
1609       return DM_NORMAL;
1610     }
1611   if (stat == MR_SUCCESS)
1612     {
1613       elem = top = QueueTop(elem);
1614       if (ask_first)
1615         {
1616           sprintf(temp_buf, "The cluster %s has the following machines in it:",
1617                   name);
1618           Put_message(temp_buf);
1619           while (elem)
1620             {
1621               char **info = elem->q_data;
1622               Print(1, &info[MAP_MACHINE], (char *) NULL);
1623               elem = elem->q_forw;
1624             }
1625           ptr = "Remove ** ALL ** these machines from this cluster?";
1626
1627           if (YesNoQuestion(ptr, FALSE) == TRUE) /* may return -1. */
1628             delete_it = TRUE;
1629           else
1630             {
1631               Put_message("Aborting...");
1632               FreeQueue(top);
1633               return SUB_ERROR;
1634             }
1635         }
1636       else
1637         delete_it = TRUE;
1638
1639       if (delete_it)
1640         {
1641           elem = top;
1642           while (elem)
1643             {
1644               char **info = elem->q_data;
1645               if ((stat = do_mr_query("delete_machine_from_cluster",
1646                                       2, info, NULL, NULL)))
1647                 {
1648                   ret_value = SUB_ERROR;
1649                   com_err(program_name, stat,
1650                           " in delete_machine_from_cluster.");
1651                   sprintf(temp_buf,
1652                           "Machine %s ** NOT ** removed from cluster %s.",
1653                           info[MAP_MACHINE], info[MAP_CLUSTER]);
1654                   Put_message(temp_buf);
1655                 }
1656               elem = elem->q_forw;
1657             }
1658         }
1659     }
1660   return ret_value;
1661 }
1662
1663 /*      Function Name: RealDeleteCluster
1664  *      Description: Actually performs the cluster deletion.
1665  *      Arguments: info - all information about this cluster.
1666  *                 one_cluster - If true then there was only one cluster in
1667  *                               the queue, and we should confirm.
1668  *      Returns: none.
1669  */
1670
1671 static void RealDeleteCluster(char **info, Bool one_cluster)
1672 {
1673   int stat;
1674   char temp_buf[BUFSIZ];
1675
1676   sprintf(temp_buf,
1677           "Are you sure the you want to delete the cluster %s (y/n) ?",
1678           info[C_NAME]);
1679   if (!one_cluster || Confirm(temp_buf))
1680     {
1681       if (CheckAndRemoveMachines(info[C_NAME], TRUE) != SUB_ERROR)
1682         {
1683           if ((stat = do_mr_query("delete_cluster", 1,
1684                                   &info[C_NAME], NULL, NULL)))
1685             {
1686               com_err(program_name, stat, " in delete_cluster.");
1687               sprintf(temp_buf, "Cluster %s ** NOT ** deleted.", info[C_NAME]);
1688               Put_message(temp_buf);
1689             }
1690           else
1691             {
1692               sprintf(temp_buf, "cluster %s successfully deleted.",
1693                       info[C_NAME]);
1694               Put_message(temp_buf);
1695             }
1696         }
1697     }
1698 }
1699
1700 /*      Function Name: DeleteCluster
1701  *      Description: This function removes a cluster from the database.
1702  *      Arguments: argc, argv - the name of the cluster is stored in argv[1].
1703  *      Returns: DM_NORMAL.
1704  */
1705
1706 int DeleteCluster(int argc, char **argv)
1707 {
1708   struct mqelem *top;
1709
1710   top = GetMCInfo(CLUSTER, argv[1], NULL);
1711   QueryLoop(top, PrintClusterInfo, RealDeleteCluster, "Delete the cluster");
1712
1713   FreeQueue(top);
1714   return DM_NORMAL;
1715 }
1716
1717 /* ----------- Cluster Data Menu -------------- */
1718
1719 /*      Function Name: ShowClusterData
1720  *      Description: This function shows the services for one cluster.
1721  *      Arguments: argc, argv - The name of the cluster is argv[1].
1722  *                              The label of the data in argv[2].
1723  *      Returns: DM_NORMAL.
1724  */
1725
1726 int ShowClusterData(int argc, char **argv)
1727 {
1728   struct mqelem *elem, *top;
1729   char **info;
1730
1731   top = elem = GetMCInfo(DATA, argv[1], argv[2]);
1732   while (elem)
1733     {
1734       info = elem->q_data;
1735       PrintClusterData(info);
1736       elem = elem->q_forw;
1737     }
1738   FreeQueue(top);
1739   return DM_NORMAL;
1740 }
1741
1742 /*      Function Name: AddClusterData
1743  *      Description: This function adds some data to the cluster.
1744  *      Arguments: argv, argc:   argv[1] - the name of the cluster.
1745  *                               argv[2] - the label of the data.
1746  *                               argv[3] - the data.
1747  *      Returns: DM_NORMAL.
1748  */
1749
1750 int AddClusterData(int argc, char **argv)
1751 {
1752   int stat;
1753
1754   if ((stat = do_mr_query("add_cluster_data", 3, argv + 1, NULL, NULL)))
1755     com_err(program_name, stat, " in AddClusterData.");
1756   return DM_NORMAL;
1757 }
1758
1759 /*      Function Name: RealRemoveClusterData
1760  *      Description: actually removes the cluster data.
1761  *      Arguments: info - all info necessary to remove the cluster, in an array
1762  *                        of strings.
1763  *                 one_item - if true then the queue has only one elem and we
1764  *                            should confirm.
1765  *      Returns: none.
1766  */
1767
1768 static void RealRemoveClusterData(char **info, Bool one_item)
1769 {
1770   int stat;
1771   char *temp_ptr;
1772
1773   Put_message(" ");
1774   temp_ptr = "Are you sure that you want to remove this cluster data (y/n) ?";
1775   PrintClusterData(info);
1776   if (!one_item || Confirm(temp_ptr))
1777     {
1778       if ((stat = do_mr_query("delete_cluster_data", 3, info, NULL, NULL)))
1779         {
1780           com_err(program_name, stat, " in DeleteClusterData.");
1781           Put_message("Data not removed.");
1782         }
1783       else
1784         Put_message("Removal successful.");
1785     }
1786 }
1787
1788 /*      Function Name: RemoveClusterData
1789  *      Description: This function removes data on a given cluster.
1790  *      Arguments: argv, argc:   argv[1] - the name of the cluster.
1791  *                               argv[2] - the label of the data.
1792  *                               argv[3] - the data.
1793  *      Returns: DM_NORMAL.
1794  */
1795
1796 int RemoveClusterData(int argc, char **argv)
1797 {
1798   struct mqelem *top;
1799
1800   top = GetMCInfo(DATA, argv[1], argv[2]);
1801   QueryLoop(top, PrintClusterData, RealRemoveClusterData,
1802             "Remove data from cluster");
1803
1804   FreeQueue(top);
1805   return DM_NORMAL;
1806 }
1807
1808 /*      Function Name: MachineToClusterMap
1809  *      Description: This Retrieves the mapping between machine and cluster
1810  *      Arguments: argc, argv - argv[1] -> machine name or wildcard.
1811  *                              argv[2] -> cluster name or wildcard.
1812  *      Returns: none.
1813  */
1814
1815 int MachineToClusterMap(int argc, char **argv)
1816 {
1817   struct mqelem *elem, *top;
1818   char *tmpname, temp_buf[256];
1819
1820   tmpname = canonicalize_hostname(strdup(argv[1]));
1821   if (strcasecmp(tmpname, argv[1]) && *argv[1] != '"')
1822     {
1823       sprintf(temp_buf, "Warning: '%s' canonicalized to '%s'.",
1824               argv[1], tmpname);
1825       Put_message(temp_buf);
1826     }
1827   top = elem = GetMCInfo(MAP, tmpname, argv[2]);
1828
1829   Put_message("");              /* blank line on screen */
1830   while (elem)
1831     {
1832       char **info = elem->q_data;
1833       PrintMCMap(info);
1834       elem = elem->q_forw;
1835     }
1836
1837   FreeQueue(top);
1838   free(tmpname);
1839   return DM_NORMAL;
1840 }
1841
1842 /*        Function Name: MachineByOwner
1843  *        Description: This function prints all machines which are owned by 
1844  *                     a given user or group.
1845  *        Arguments: none.
1846  *        Returns: DM_NORMAL.
1847  */
1848
1849 int MachineByOwner(int argc, char **argv)
1850 {
1851   char buf[BUFSIZ], temp_buf[BUFSIZ], *type, *name;
1852   struct mqelem *top;
1853
1854   type = strdup("USER");
1855   if (GetTypeFromUser("Type of owner", "ace_type", &type) == SUB_ERROR)
1856     return DM_NORMAL;
1857
1858   sprintf(buf, "Name of %s", type);
1859   name = strdup(user);
1860   if (GetValueFromUser(buf, &name) == SUB_ERROR)
1861     return DM_NORMAL;
1862
1863   switch (YesNoQuestion("Do you want a recursive search (y/n)", FALSE))
1864     {
1865     case TRUE:
1866       sprintf(temp_buf, "R%s", type);     /* "USER to "RUSER", etc. */
1867       free(type);
1868       type = strdup(temp_buf);
1869       break;
1870     case FALSE:
1871       break;
1872     default:
1873       return DM_NORMAL;
1874     }
1875
1876   top = GetMachineByOwner(type, name);
1877   Loop(top, PrintMachine);
1878
1879   FreeQueue(top);
1880   return DM_NORMAL;
1881 }
1882
1883 /*         Function Name: GetMachineByOwner
1884  *         Description: This function stores information retrieved by 
1885  *                      the get_host_by_owner query
1886  *         Arguments: type - an ace_type, argv[0] for the query
1887  *                    name - name of machine, argv[1] for the query
1888  *         Returns: the top element of a queue returning the data, or NULL.
1889  */
1890
1891 struct mqelem *GetMachineByOwner(char *type, char *name)
1892 {
1893   char *args[2];
1894   struct mqelem *elem = NULL;
1895   int status;
1896
1897   args[0] = type;
1898   args[1] = name;
1899   if ((status = do_mr_query("get_host_by_owner", 2, args, StoreInfo, &elem)))
1900     {
1901       com_err(program_name, status, " in get_host_by_owner");
1902       return NULL;
1903     }
1904   return QueueTop(elem);
1905 }
This page took 4.486051 seconds and 5 git commands to generate.