source: trunk/third/moira/clients/mitch/mitch.c @ 24319

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