]> andersk Git - moira.git/blob - clients/mitch/mitch.c
bella becomes mitch to stay consistant with our naming scheme
[moira.git] / clients / mitch / mitch.c
1 /*
2  * Command line oriented Moira containers tool.
3  *
4  * Garry Zacheiss <zacheiss@mit.edu>, January 2003
5  *
6  * Inspired by blanche
7  *
8  * Copyright (C) 2002 by the Massachusetts Institute of Technology.
9  * For copying and distribution information, please see the file
10  * <mit-copyright.h>.
11  */
12
13 #include <mit-copyright.h>
14 #include <moira.h>
15 #include <moira_site.h>
16 #include <mrclient.h>
17
18 #include <ctype.h>
19 #include <errno.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23
24 RCSID("$Id$");
25
26 struct owner_type {
27   int type;
28   char *name;
29 };
30
31 struct mqelem {
32   struct mqelem *q_forw;
33   struct mqelem *q_back;
34   void *q_data;
35 };
36
37 struct string_list {
38   char *string;
39   struct string_list *next;
40 };
41
42 #define M_ANY           0
43 #define M_USER          1
44 #define M_LIST          2
45 #define M_KERBEROS      3
46 #define M_NONE          4
47
48 char *typename[] = { "ANY", "USER", "LIST", "KERBEROS", "NONE" };
49
50 /* argument parsing macro */
51 #define argis(a, b) (!strcmp(*arg + 1, a) || !strcmp(*arg + 1, b))
52
53 /* flags from command line */
54 int info_flag, update_flag, create_flag, delete_flag, list_subcon_flag;
55 int list_mach_flag, update_mach_flag, verbose, noauth, unformatted_flag;
56 int recurse_flag;
57
58 struct string_list *container_add_queue, *container_remove_queue;
59
60 char *containername, *whoami;
61
62 char *newname, *desc, *location, *contact;
63 int public;
64 struct owner_type *owner, *memacl;
65
66 void usage(char **argv);
67 int store_container_info(int argc, char **argv, void *hint);
68 void show_container_info(char **argv);
69 int show_container_list(int argc, char **argv, void *hint);
70 void show_container_info_unformatted(char **argv);
71 int show_container_list_unformatted(int argc, char **argv, void *hint);
72 int show_machine_in_container(int argc, char **argv, void *hint);
73 int show_subcontainers_of_container(int argc, char **argv, void *hint);
74 struct owner_type *parse_member(char *s);
75 struct string_list *add_to_string_list(struct string_list *old_list, char *s);
76 int wrap_mr_query(char *handle, int argc, char **argv,
77                   int (*callback)(int, char **, void *), void *callarg);
78 void print_query(char *query_name, int argc, char **argv);
79
80 int main(int argc, char **argv)
81 {
82   int status, success;
83   char **arg = argv;
84   char *server = NULL;
85
86   /* clear all flags & lists */
87   info_flag = update_flag = create_flag = delete_flag = list_subcon_flag = 0;
88   list_mach_flag = update_mach_flag = verbose = noauth = unformatted_flag = 0;
89   recurse_flag = 0;
90   public = -1;
91   container_add_queue = container_remove_queue = NULL;
92   newname = desc = location = contact = NULL;
93   owner = memacl = NULL;
94   whoami = argv[0];
95
96   success = 1;
97
98   /* parse args */
99   while (++arg - argv < argc)
100     {
101       if (**arg == '-')
102         {
103           if (argis("i", "info"))
104             info_flag++;
105           else if (argis("C", "create"))
106             create_flag++;
107           else if (argis("D", "delete"))
108             delete_flag++;
109           else if (argis("R", "rename")) {
110             if (arg - argv < argc - 1) {
111               arg++;
112               update_flag++;
113               newname = *arg;
114             } else
115               usage(argv);
116           }
117           else if (argis("d", "desc")) {
118             if (arg - argv < argc - 1) {
119               arg++;
120               update_flag++;
121               desc = *arg;
122             } else
123               usage(argv);
124           }
125           else if (argis("L", "location")) {
126             if (arg - argv < argc - 1) {
127               arg++;
128               update_flag++;
129               location = *arg;
130             } else
131               usage(argv);
132           }
133           else if (argis("c", "contact")) {
134             if (arg - argv < argc - 1) {
135               arg++;
136               update_flag++;
137               contact = *arg;
138             } else
139               usage(argv);
140           }
141           else if (argis("P", "public"))
142             {
143               update_flag++;
144               public = 1;
145             }
146           else if (argis("NP", "private"))
147             {
148               update_flag++;
149               public = 0;
150             }
151           else if (argis("O", "owner")) {
152             if (arg - argv < argc - 1) {
153               arg++;
154               update_flag++;
155               owner = parse_member(*arg);
156             } else
157               usage(argv);
158           }
159           else if (argis("MA", "memacl")) {
160             if (arg - argv < argc - 1) {
161               arg++;
162               update_flag++;
163               memacl = parse_member(*arg);
164             } else
165               usage(argv);
166           }
167           else if (argis("ls", "listsub"))
168             list_subcon_flag++;
169           else if (argis("lm", "listmach"))
170             list_mach_flag++;
171           else if (argis("am", "addmach")) {
172             if (arg - argv < argc - 1) {
173               arg++;
174               container_add_queue = 
175                 add_to_string_list(container_add_queue, *arg);
176             } else
177               usage(argv);
178             update_mach_flag++;
179           }
180           else if (argis("dm", "deletemach")) {
181             if (arg - argv < argc - 1) {
182               arg++;
183               container_remove_queue =
184                 add_to_string_list(container_remove_queue, *arg);
185             } else
186               usage(argv);
187             update_mach_flag++;
188           }
189           else if (argis("r", "recursive"))
190             recurse_flag++;
191           else if (argis("u", "unformatted"))
192             unformatted_flag++;
193           else if (argis("n", "noauth"))
194             noauth++;
195           else if (argis("v", "verbose"))
196             verbose++;
197           else if (argis("db", "database"))
198             {
199               if (arg - argv < argc - 1)
200                 {
201                   ++arg;
202                   server = *arg;
203                 }
204               else
205                 usage(argv);
206             }
207           else
208             usage(argv);
209         }
210       else if (containername == NULL)
211         containername = *arg;
212       else
213         usage(argv);
214     }
215   if (containername == NULL)
216     usage(argv);
217
218   /* default to info_flag if nothing else was specified */
219   if(!(info_flag        || update_flag    || create_flag || delete_flag || \
220        list_subcon_flag || list_mach_flag || update_mach_flag)) {
221     info_flag++;
222   }
223
224   /* fire up Moira */
225   status = mrcl_connect(server, "mitch", 9, !noauth);
226   if (status == MRCL_AUTH_ERROR)
227     {
228       com_err(whoami, 0, "Try the -noauth flag if you don't "
229               "need authentication.");
230     }
231   if (status)
232     exit(2);
233
234   /* create if needed */
235   if (create_flag)
236     {
237       char *argv[15];
238       int cnt;
239
240       for (cnt = 0; cnt < 11; cnt ++) {
241         argv[cnt] = "";
242       }
243
244       argv[CON_NAME] = containername;
245       argv[CON_PUBLIC] = (public == 1) ? "1" : "0";
246       argv[CON_DESCRIPT] = desc ? desc : "none";
247       if (location)
248         argv[CON_LOCATION] = location;
249       if (contact)
250         argv[CON_CONTACT] = contact;
251
252       if (memacl)
253         {
254           if (memacl->type == M_ANY)
255             {
256               status = wrap_mr_query("get_user_account_by_login", 1,
257                                      &memacl->name, NULL, NULL);
258               if (status == MR_NO_MATCH)
259                 memacl->type = M_LIST;
260               else
261                 memacl->type = M_USER;
262             }
263           argv[CON_MEMACE_TYPE] = typename[memacl->type];
264           argv[CON_MEMACE_NAME] = memacl->name;
265           if (memacl->type == M_KERBEROS)
266             {
267               status = mrcl_validate_kerberos_member(argv[CON_MEMACE_NAME],
268                                                      &argv[CON_MEMACE_NAME]);
269               if (mrcl_get_message())
270                 mrcl_com_err(whoami);
271               if (status == MRCL_REJECT)
272                 exit(1);
273             }
274         }
275       else
276         argv[CON_MEMACE_TYPE] = argv[CON_MEMACE_NAME] = "NONE";
277
278       if (owner)
279         {
280           argv[CON_OWNER_NAME] = owner->name;
281           switch (owner->type)
282             {
283             case M_ANY:
284             case M_USER:
285               argv[CON_OWNER_TYPE] = "USER";
286               status = wrap_mr_query("add_container", 9, argv, NULL, NULL);
287               if (owner->type != M_ANY || status != MR_USER)
288                 break;
289
290             case M_LIST:
291               argv[CON_OWNER_TYPE] = "LIST";
292               status = wrap_mr_query("add_container", 9, argv, NULL, NULL);
293               break;
294
295             case M_KERBEROS:
296               argv[CON_OWNER_TYPE] = "KERBEROS";
297               status = mrcl_validate_kerberos_member(argv[CON_OWNER_TYPE],
298                                                      &argv[CON_OWNER_TYPE]);
299               if (mrcl_get_message())
300                 mrcl_com_err(whoami);
301               if (status == MRCL_REJECT)
302                 exit(1);
303               status = wrap_mr_query("add_container", 9, argv, NULL, NULL);
304               break;
305             case M_NONE:
306               argv[CON_OWNER_TYPE] = argv[CON_OWNER_NAME] = "NONE";
307               status = wrap_mr_query("add_containr", 9, argv, NULL, NULL);
308               break;
309             }
310         }
311       else
312         {
313           argv[CON_OWNER_TYPE] = argv[CON_OWNER_NAME] = "NONE";
314           status = wrap_mr_query("add_container", 9, argv, NULL, NULL);
315         }
316
317       if (status)
318         {
319           com_err(whoami, status, "while creating container.");
320           exit(1);
321         }
322     }
323   else if (update_flag)
324     {
325       char *old_argv[15];
326       char *argv[15];
327       char *args[2];
328
329       args[0] = containername;
330
331       status = wrap_mr_query("get_container", 1, args, store_container_info,
332                              old_argv);
333       if (status)
334         {
335           com_err(whoami, status, "while getting container information.");
336           exit(1);
337         }
338
339       argv[1] = old_argv[0];
340       argv[2] = old_argv[1];
341       argv[3] = old_argv[2];
342       argv[4] = old_argv[3];
343       argv[5] = old_argv[4];
344       argv[6] = old_argv[5];
345       argv[7] = old_argv[6];
346       argv[8] = old_argv[7];
347       argv[9] = old_argv[8];
348
349       argv[CON_NAME] = containername;
350       if (newname)
351         argv[CON_NAME + 1] = newname;
352       argv[CON_PUBLIC + 1] = (public == 1) ? "1" : "0";
353       if (desc)
354         argv[CON_DESCRIPT + 1] = desc;
355       if (location)
356         argv[CON_LOCATION + 1] = location;
357       if (contact)
358         argv[CON_CONTACT + 1] = contact;
359
360       if (memacl)
361         {
362           if (memacl->type == M_ANY)
363             {
364               status = wrap_mr_query("get_user_account_by_login", 1,
365                                      &memacl->name, NULL, NULL);
366               if (status == MR_NO_MATCH)
367                 memacl->type = M_LIST;
368               else
369                 memacl->type = M_USER;
370             }
371           argv[CON_MEMACE_TYPE + 1] = typename[memacl->type];
372           argv[CON_MEMACE_NAME + 1] = memacl->name;
373           if (memacl->type == M_KERBEROS)
374             {
375               status = mrcl_validate_kerberos_member(argv[CON_MEMACE_NAME + 1],
376                                                      &argv[CON_MEMACE_NAME + 1]);
377               if (mrcl_get_message())
378                 mrcl_com_err(whoami);
379               if (status == MRCL_REJECT)
380                 exit(1);
381             }
382         }
383
384       if (owner)
385         {
386           argv[CON_OWNER_NAME + 1] = owner->name;
387           switch (owner->type)
388             {
389             case M_ANY:
390             case M_USER:
391               argv[CON_OWNER_TYPE + 1] = "USER";
392               status = wrap_mr_query("update_container", 10, argv, NULL, NULL);
393               if (owner->type != M_ANY || status != MR_USER)
394                 break;
395
396             case M_LIST:
397               argv[CON_OWNER_TYPE + 1] = "LIST";
398               status = wrap_mr_query("update_container", 10, argv, NULL, NULL);
399               break;
400
401             case M_KERBEROS:
402               argv[CON_OWNER_TYPE + 1] = "KERBEROS";
403               status = mrcl_validate_kerberos_member(argv[CON_OWNER_NAME + 1],
404                                                      &argv[CON_OWNER_NAME + 1]);
405               if (mrcl_get_message())
406                 mrcl_com_err(whoami);
407               if (status == MRCL_REJECT)
408                 exit(1);
409               status = wrap_mr_query("update_container", 10, argv, NULL, NULL);
410               break;
411               
412             case M_NONE:
413               argv[CON_OWNER_TYPE + 1] = argv[CON_OWNER_NAME + 1] = "NONE";
414               status = wrap_mr_query("update_container", 10, argv, NULL, NULL);
415               break;
416             }
417         }
418       else
419         status = wrap_mr_query("update_container", 10, argv, NULL, NULL);
420
421       if (status)
422         {
423           com_err(whoami, status, "while updating container.");
424           success = 0;
425         }
426       else if (newname)
427         containername = newname;
428     }
429
430   /* add machines to container */
431   if (container_add_queue) {
432     struct string_list *q = container_add_queue;
433
434     while (q) {
435       char *args[2];
436
437       args[0] = canonicalize_hostname(strdup(q->string));
438       args[1] = containername;
439       status = wrap_mr_query("add_machine_to_container", 2, args, NULL, NULL);
440       if (status)
441         {
442           com_err(whoami, status, "while adding machine to container.");
443           exit(1);
444         }
445
446       q = q->next;
447     }
448   }
449
450   /* delete machines from container */
451   if (container_remove_queue) {
452     struct string_list *q = container_remove_queue;
453
454     while (q) {
455       char *args[2];
456
457       args[0] = canonicalize_hostname(strdup(q->string));
458       args[1] = containername;
459       status = wrap_mr_query("delete_machine_from_container", 2, args, NULL,
460                              NULL);
461       if (status)
462         {
463           com_err(whoami, status, "while removing machine from container.");
464           exit(1);
465         }
466
467       q = q->next;
468     }
469   }
470
471   if (info_flag)
472     {
473       char *args[2];
474       char *argv[20];
475
476       args[0] = containername;
477       status = wrap_mr_query("get_container", 1, args, store_container_info,
478                              argv);
479       if (status)
480         {
481           com_err(whoami, status, "while getting container information.");
482           exit(1);
483         }
484
485       if (unformatted_flag)
486         show_container_info_unformatted(argv);
487       else
488         show_container_info(argv);
489     }
490
491   if (delete_flag)
492     {
493       char *args[2];
494
495       args[0] = containername;
496       status = wrap_mr_query("delete_container", 1, args, NULL, NULL);
497       if (status)
498         {
499           com_err(whoami, status, "while deleting container.");
500           exit(1);
501         }
502     }
503
504   if (list_mach_flag)
505     {
506       char *args[3];
507
508       args[0] = containername;
509       args[1] = (recurse_flag == 1) ? "1" : "0";
510       status = wrap_mr_query("get_machines_of_container", 2, args,
511                              show_machine_in_container, NULL);
512       if (status)
513         {
514           com_err(whoami, status, "while getting machines of container.");
515           exit(1);
516         }
517     }
518
519   if (list_subcon_flag)
520     {
521       char *args[3];
522
523       args[0] = containername;
524       args[1] = (recurse_flag == 1) ? "1" : "0";
525       status = wrap_mr_query("get_subcontainers_of_container", 2, args,
526                              show_subcontainers_of_container, NULL);
527       if (status)
528         {
529           com_err(whoami, status, "while getting subcontainers of container.");
530           exit(1);
531         }
532     }
533
534   mr_disconnect();
535   exit(success ? 0 : 1);
536 }
537
538 void usage(char **argv)
539 {
540 #define USAGE_OPTIONS_FORMAT "  %-39s%s\n"
541   fprintf(stderr, "Usage: %s containername [options]\n", argv[0]);
542   fprintf(stderr, "Options are\n");
543   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-C   | -create",
544           "-O   | -owner owner");
545   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-D   | -delete",
546           "-d   | -desc description");
547   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-R   | -rename newname",
548           "-L   | -location location");
549   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-i   | -info",
550           "-c   | -contact contact");
551   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-P   | -public",
552           "-NP  | -private");
553   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-O   | -owner owner",
554           "-MA  | -memacl membership_acl");
555   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-ls  | -listsub",
556           "-lm  | -listmach");
557   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-am  | -addmach hostname",
558           "-dm  | -deletemach hostname");
559   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-r   | -recursive",
560           "-u   | -unformatted");
561   fprintf(stderr, USAGE_OPTIONS_FORMAT, "-v   | -verbose",
562           "-n   | -noauth");
563   fprintf(stderr, "  %-39s\n" , "-db  | -database host[:port]");
564   exit(1);
565 }
566
567 /* Retrieve information about a container */
568 int store_container_info(int argc, char **argv, void *hint)
569 {
570   int i;
571   char **nargv = hint;
572
573   for(i = 0; i < argc; i++)
574     nargv[i] = strdup(argv[i]);
575
576   return MR_CONT;
577 }
578
579 void show_container_info(char **argv)
580 {
581   char tbuf[256];
582   char *args[2];
583   struct mqelem *elem = NULL;
584   int status;
585
586   printf("Container:      %-16s    Public:      %s\n", argv[CON_NAME], 
587          argv[CON_PUBLIC]);
588   args[0] = argv[CON_NAME];
589   status = wrap_mr_query("get_container_list", 1, args, show_container_list,
590                          &elem);
591   if (status && status != MR_NO_MATCH)
592     com_err(whoami, status, "while getting container list.");
593   printf("Description:    %-16s\n", argv[CON_DESCRIPT]);
594   printf("Location:       %-16s    Contact:     %s\n", argv[CON_LOCATION],
595          argv[CON_CONTACT]);
596   sprintf(tbuf, "%s %s", argv[CON_OWNER_TYPE],
597           strcmp(argv[CON_OWNER_TYPE], "NONE") ? argv[CON_OWNER_NAME] : "");
598   printf("Owner:          %-16s\n", tbuf);
599   sprintf(tbuf, "%s %s", argv[CON_MEMACE_TYPE],
600           strcmp(argv[CON_MEMACE_TYPE], "NONE") ? argv[CON_MEMACE_NAME] : "");
601   printf("Membership ACL: %-16s\n", tbuf);
602   printf("\n");
603   printf("Last mod by %s at %s with %s.\n", argv[CON_MODBY], argv[CON_MODTIME],
604          argv[CON_MODWITH]);
605 }
606
607 int show_container_list(int argc, char **argv, void *hint)
608 {
609   printf("Container's associated list is: LIST %s\n", argv[1]);
610
611   return MR_CONT;
612 }
613
614 void show_container_info_unformatted(char **argv)
615 {
616   char *args[2];
617   struct mqelem *elem = NULL;
618   int status;
619
620   printf("Container:       %s\n", argv[CON_NAME]);
621   args[0] = argv[CON_NAME];
622   status = wrap_mr_query("get_container_list", 1, args,
623                          show_container_list_unformatted, &elem);
624   if (status && status != MR_NO_MATCH)
625     com_err(whoami, status, "while getting container list.");
626   else
627     printf("\n");
628   printf("Public:          %s\n", argv[CON_PUBLIC]);
629   printf("Description:     %s\n", argv[CON_DESCRIPT]);
630   printf("Location:        %s\n", argv[CON_LOCATION]);
631   printf("Contact:         %s\n", argv[CON_CONTACT]);
632   printf("Owner Type:      %s\n", argv[CON_OWNER_TYPE]);
633   printf("Owner:           %s\n", argv[CON_OWNER_NAME]);
634   printf("Memacl Type:     %s\n", argv[CON_MEMACE_TYPE]);
635   printf("Memacl:          %s\n", argv[CON_MEMACE_NAME]);
636   printf("Last mod by:     %s\n", argv[CON_MODBY]);
637   printf("Last mod on:     %s\n", argv[CON_MODTIME]);
638   printf("Last mod with:   %s\n", argv[CON_MODWITH]);
639 }
640
641 int show_container_list_unformatted(int argc, char **argv, void *hint)
642 {
643   printf("Associated list: %s", argv[1]);
644
645   return MR_CONT;
646 }
647
648 int show_machine_in_container(int argc, char **argv, void *hint)
649 {
650   printf("Machine: %-30s Container: %-25s\n", argv[0], argv[1]); 
651
652   return MR_CONT;
653 }
654
655 int show_subcontainers_of_container(int argc, char **argv, void *hint)
656 {
657   printf("Container: %-25s\n", argv[0]);
658
659   return MR_CONT;
660 }
661
662 /* Parse a line of input, fetching a member.  NULL is returned if a member
663  * is not found.  ';' is a comment character.
664  */
665
666 struct owner_type *parse_member(char *s)
667 {
668   struct owner_type *m;
669   char *p, *lastchar;
670
671   while (*s && isspace(*s))
672     s++;
673   lastchar = p = s;
674   while (*p && *p != '\n' && *p != ';')
675     {
676       if (isprint(*p) && !isspace(*p))
677         lastchar = p++;
678       else
679         p++;
680     }
681   lastchar++;
682   *lastchar = '\0';
683   if (p == s || strlen(s) == 0)
684     return NULL;
685
686   if (!(m = malloc(sizeof(struct owner_type))))
687     return NULL;
688
689   if ((p = strchr(s, ':')))
690     {
691       *p = '\0';
692       m->name = ++p;
693       if (!strcasecmp("user", s))
694         m->type = M_USER;
695       else if (!strcasecmp("list", s))
696         m->type = M_LIST;
697       else if (!strcasecmp("kerberos", s))
698         m->type = M_KERBEROS;
699       else if (!strcasecmp("none", s))
700         m->type = M_NONE;
701       else
702         {
703           m->type = M_ANY;
704           *(--p) = ':';
705           m->name = s;
706         }
707       m->name = strdup(m->name);
708     }
709   else
710     {
711       m->name = strdup(s);
712       m->type = strcasecmp(s, "none") ? M_ANY : M_NONE;
713     }
714   return m;
715 }
716
717 struct string_list *add_to_string_list(struct string_list *old_list, char *s) {
718   struct string_list *new_list;
719
720   new_list = (struct string_list *)malloc(sizeof(struct string_list *));
721   new_list->next = old_list;
722   new_list->string = s;
723
724   return new_list;
725 }
726
727 int wrap_mr_query(char *handle, int argc, char **argv,
728                   int (*callback)(int, char **, void *), void *callarg) {
729   if (verbose)
730     print_query(handle, argc, argv);
731
732   return mr_query(handle, argc, argv, callback, callarg);
733 }
734
735 void print_query(char *query_name, int argc, char **argv) {
736   int cnt;
737
738   printf("qy %s", query_name);
739   for(cnt=0; cnt<argc; cnt++)
740     printf(" <%s>", argv[cnt]);
741   printf("\n");
742 }
This page took 0.111913 seconds and 5 git commands to generate.