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

Revision 24319, 12.4 KB checked in by broder, 15 years ago (diff)
New Moira snapshot from SVN.
Line 
1/* $Id: mrtest.c 3956 2010-01-05 20:56:56Z zacheiss $
2 *
3 * Bare-bones Moira client
4 *
5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
8 */
9
10#include <mit-copyright.h>
11#include <moira.h>
12
13#include <errno.h>
14#include <fcntl.h>
15#include <setjmp.h>
16#include <signal.h>
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#ifdef HAVE_UNISTD_H
21#include <unistd.h>
22#endif
23
24#ifdef HAVE_GETOPT_H
25#include <getopt.h>
26#endif
27
28#ifdef _WIN32
29#include <windows.h>
30#include <io.h>
31#define dup    _dup
32#define dup2   _dup2
33#define isatty _isatty
34#define close  _close
35#define open   _open
36#define sigjmp_buf jmp_buf
37#define siglongjmp longjmp
38#define sigsetjmp(env, save) setjmp(env)
39#endif /* _WIN32 */
40
41#ifdef HAVE_READLINE
42#include "readline/readline.h"
43#include "readline/history.h"
44#endif
45
46RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/clients/mrtest/mrtest.c $ $Id: mrtest.c 3956 2010-01-05 20:56:56Z zacheiss $");
47
48int recursion = 0, quote_output = 0, interactive;
49int count, quit = 0, cancel = 0;
50char *whoami;
51
52sigjmp_buf jb;
53
54#define MAXARGS 20
55
56void discard_input(int sig);
57char *mr_gets(char *prompt, char *buf, size_t len);
58void execute_line(char *cmdbuf);
59int parse(char *buf, char *argv[MAXARGS]);
60int print_reply(int argc, char **argv, void *help);
61void test_noop(void);
62void test_connect(int argc, char **argv);
63void test_disconnect(void);
64void test_host(void);
65void test_motd(void);
66void test_query(int argc, char **argv);
67void test_auth(void);
68void test_proxy(int argc, char **argv);
69void test_access(int argc, char **argv);
70void test_dcm(void);
71void test_script(int argc, char **argv);
72void test_list_requests(void);
73void test_version(int argc, char **argv);
74void test_krb5_auth(void);
75void set_signal_handler(int, void (*handler)(int));
76void set_signal_blocking(int, int);
77
78int main(int argc, char **argv)
79{
80  char cmdbuf[BUFSIZ];
81  int c;
82
83  whoami = argv[0];
84  interactive = (isatty(0) && isatty(1));
85
86  while ((c = getopt(argc, argv, "q")) != -1)
87    {
88      switch (c)
89        {
90        case 'q':
91          quote_output = 1;
92          break;
93
94        default:
95          fprintf(stderr, "Usage: mrtest [-q]\n");
96          exit (1);
97        }
98    }
99
100#if defined(__APPLE__) && defined(__MACH__)
101  add_error_table(&et_sms_error_table);
102  add_error_table(&et_krb_error_table);
103#else
104  initialize_sms_error_table();
105  initialize_krb_error_table();
106#endif
107
108#ifdef HAVE_READLINE
109  /* we don't want filename completion */
110  rl_bind_key('\t', rl_insert);
111#endif
112
113  set_signal_handler(SIGINT, discard_input);
114  sigsetjmp(jb, 1);
115
116  while (!quit)
117    {
118      if (!mr_gets("moira:  ", cmdbuf, BUFSIZ))
119        break;
120      execute_line(cmdbuf);
121    }
122  mr_disconnect();
123  exit(0);
124}
125
126void discard_input(int sig)
127{
128  putc('\n', stdout);
129
130  /* if we're inside a script, we have to clean up file descriptors,
131     so don't jump out yet */
132  if (recursion)
133    cancel = 1;
134  else
135    siglongjmp(jb, 1);
136}
137
138char *mr_gets(char *prompt, char *buf, size_t len)
139{
140  char *in;
141#ifdef HAVE_READLINE
142  if (interactive)
143    {
144      in = readline(prompt);
145
146      if (!in)
147        return NULL;
148      if (*in)
149        add_history(in);
150      strncpy(buf, in, len - 1);
151      buf[len] = 0;
152      free(in);
153
154      return buf;
155    }
156#endif
157  printf("%s", prompt);
158  fflush(stdout);
159  in = fgets(buf, len, stdin);
160  if (!in)
161    return in;
162  if (strchr(buf, '\n'))
163    *(strchr(buf, '\n')) = '\0';
164  return buf;
165}
166
167void execute_line(char *cmdbuf)
168{
169  int argc;
170  char *argv[MAXARGS];
171
172  argc = parse(cmdbuf, argv);
173  if (argc == 0)
174    return;
175  if (!strcmp(argv[0], "noop"))
176    test_noop();
177  else if (!strcmp(argv[0], "connect") || !strcmp(argv[0], "c"))
178    test_connect(argc, argv);
179  else if (!strcmp(argv[0], "disconnect") || !strcmp(argv[0], "d"))
180    test_disconnect();
181  else if (!strcmp(argv[0], "host"))
182    test_host();
183  else if (!strcmp(argv[0], "motd") || !strcmp(argv[0], "m"))
184    test_motd();
185  else if (!strcmp(argv[0], "query") || !strcmp(argv[0], "qy"))
186    test_query(argc, argv);
187  else if (!strcmp(argv[0], "auth") || !strcmp(argv[0], "a"))
188    test_krb5_auth();
189  else if (!strcmp(argv[0], "proxy") || !strcmp(argv[0], "p"))
190    test_proxy(argc, argv);
191  else if (!strcmp(argv[0], "access"))
192    test_access(argc, argv);
193  else if (!strcmp(argv[0], "dcm"))
194    test_dcm();
195  else if (!strcmp(argv[0], "script") || !strcmp(argv[0], "s"))
196    test_script(argc, argv);
197  else if (!strcmp(argv[0], "list_requests") ||
198          !strcmp(argv[0], "lr") || !strcmp(argv[0], "?"))
199    test_list_requests();
200  else if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "Q"))
201    quit = 1;
202  else if (!strcmp(argv[0], "version") || !strcmp(argv[0], "v"))
203    test_version(argc, argv);
204  else if (!strcmp(argv[0], "krb4_auth") || !strcmp(argv[0], "4"))
205    test_auth();
206  else
207    {
208      fprintf(stderr, "moira: Unknown request \"%s\".  "
209              "Type \"?\" for a request list.\n", argv[0]);
210    }
211}
212
213int parse(char *buf, char *argv[MAXARGS])
214{
215  char *p;
216  int argc, num;
217
218  if (!*buf)
219    return 0;
220
221  for (p = buf, argc = 0, argv[0] = buf; *p && *p != '\n'; p++)
222    {
223      if (*p == '"')
224        {
225          char *d = p++;
226          /* skip to close-quote, copying back over open-quote */
227          while (*p != '"')
228            {
229              if (!*p || *p == '\n')
230                {
231                  fprintf(stderr,
232                          "moira: Unbalanced quotes in command line\n");
233                  return 0;
234                }
235              /* deal with \### or \\ */
236              if (*p == '\\')
237                {
238                  if (*++p != '"' && (*p < '0' || *p > '9') && (*p != '\\'))
239                    {
240                      fprintf(stderr, "moira: Bad use of \\\n");
241                      return 0;
242                    }
243                  else if (*p >= '0' && *p <= '9')
244                    {
245                      num = (*p - '0') * 64 + (*++p - '0') * 8 + (*++p - '0');
246                      *p = num;
247                    }
248                }
249              *d++ = *p++;
250            }
251          if (p == d + 1)
252            {
253              *d = '\0';
254              p++;
255            }
256          else
257            {
258              while (p >= d)
259                *p-- = ' ';
260            }
261        }
262      if (*p == ' ' || *p == '\t')
263        {
264          /* skip whitespace */
265          for (*p++ = '\0'; *p == ' ' || *p == '\t'; p++)
266            ;
267          if (*p && *p != '\n') {
268            if (++argc >= MAXARGS) {
269              fprintf(stderr,
270                      "moira: Too many command line arguments\n");
271              return 0;
272            }
273            argv[argc] = p--;
274          }
275        }
276    }
277  if (*p == '\n')
278    *p = '\0';
279  return argc + 1;
280}
281
282void test_noop(void)
283{
284  int status = mr_noop();
285  if (status)
286    com_err("moira (noop)", status, "");
287}
288
289void test_connect(int argc, char *argv[])
290{
291  char *server = "";
292  int status;
293
294  if (argc > 1)
295    server = argv[1];
296  status = mr_connect(server);
297  if (status)
298    com_err("moira (connect)", status, "");
299  mr_version(-1);
300}
301
302void test_disconnect(void)
303{
304  int status = mr_disconnect();
305  if (status)
306    com_err("moira (disconnect)", status, "");
307}
308
309void test_host(void)
310{
311  char host[BUFSIZ];
312  int status;
313
314  memset(host, 0, sizeof(host));
315
316  if ((status = mr_host(host, sizeof(host) - 1)))
317    com_err("moira (host)", status, "");
318  else
319    printf("You are connected to host %s\n", host);
320}
321
322void test_auth(void)
323{
324  int status;
325
326  status = mr_auth("mrtest");
327  if (status)
328    com_err("moira (auth)", status, "");
329}
330
331void test_krb5_auth(void)
332{
333  int status;
334
335  status = mr_krb5_auth("mrtest");
336  if (status)
337    com_err("moira (krb5_auth)", status, "");
338}
339
340void test_proxy(int argc, char *argv[])
341{
342  int status;
343
344  if (argc != 3)
345    {
346      com_err("moira (proxy)", 0, "Usage: proxy principal authtype");
347      return;
348    }
349  status = mr_proxy(argv[1], argv[2]);
350  if (status)
351    com_err("moira (proxy)", status, "");
352}
353
354void test_script(int argc, char *argv[])
355{
356  FILE *inp;
357  char input[BUFSIZ], *cp;
358  int status, oldstdout, oldstderr;
359
360  if (recursion > 8)
361    {
362      com_err("moira (script)", 0, "too many levels deep in script files\n");
363      return;
364    }
365
366  if (argc < 2)
367    {
368      com_err("moira (script)", 0, "Usage: script input_file [ output_file ]");
369      return;
370    }
371
372  inp = fopen(argv[1], "r");
373  if (!inp)
374    {
375      sprintf(input, "Cannot open input file %s", argv[1]);
376      com_err("moira (script)", 0, input);
377      return;
378    }
379
380  if (argc == 3)
381    {
382      printf("Redirecting output to %s\n", argv[2]);
383      fflush(stdout);
384      oldstdout = dup(1);
385      close(1);
386      status = open(argv[2], O_CREAT|O_WRONLY|O_APPEND, 0664);
387      if (status != 1)
388        {
389          close(status);
390          dup2(oldstdout, 1);
391          argc = 2;
392          sprintf(input, "Unable to redirect output to %s\n", argv[2]);
393          com_err("moira (script)", errno, input);
394        }
395      else
396        {
397          fflush(stderr);
398          oldstderr = dup(2);
399          close(2);
400          dup2(1, 2);
401        }
402    }
403
404  recursion++;
405
406  while (!cancel)
407    {
408      if (!fgets(input, BUFSIZ, inp))
409        break;
410      if ((cp = strchr(input, '\n')))
411        *cp = '\0';
412      if (input[0] == 0)
413        {
414          printf("\n");
415          continue;
416        }
417      if (input[0] == '%')
418        {
419          for (cp = &input[1]; *cp && isspace(*cp); cp++)
420            ;
421          printf("Comment: %s\n", cp);
422          continue;
423        }
424      printf("Executing: %s\n", input);
425      execute_line(input);
426    }
427
428  recursion--;
429  if (!recursion)
430    cancel = 0;
431
432  fclose(inp);
433  if (argc == 3)
434    {
435      fflush(stdout);
436      close(1);
437      dup2(oldstdout, 1);
438      close(oldstdout);
439      fflush(stderr);
440      close(2);
441      dup2(oldstderr, 2);
442      close(oldstderr);
443    }
444}
445
446int print_reply(int argc, char **argv, void *help)
447{
448  int i;
449  for (i = 0; i < argc; i++)
450    {
451      if (i != 0)
452        printf(", ");
453      if (quote_output && !*(int *)help)
454        {
455          unsigned char *p;
456
457          for (p = (unsigned char *)argv[i]; *p; p++)
458            {
459              if (isprint(*p) && *p != '\\' && *p != ',')
460                putc(*p, stdout);
461              else
462                printf("\\%03o", *p);
463            }
464        }
465      else
466        printf("%s", argv[i]);
467    }
468  printf("\n");
469  count++;
470  return MR_CONT;
471}
472
473void test_query(int argc, char **argv)
474{
475  int status, help;
476
477  if (argc < 2)
478    {
479      com_err("moira (query)", 0, "Usage: query handle [ args ... ]");
480      return;
481    }
482  help = !strcmp(argv[1], "_help");
483
484  count = 0;
485  /* Don't allow ^C during the query: it will confuse libmoira's
486     internal state. (Yay static variables) */
487  set_signal_blocking(SIGINT, 1);
488  status = mr_query(argv[1], argc - 2, argv + 2, print_reply, &help);
489  set_signal_blocking(SIGINT, 0);
490  printf("%d tuple%s\n", count, ((count == 1) ? "" : "s"));
491  if (status)
492    com_err("moira (query)", status, "");
493}
494
495void test_access(int argc, char **argv)
496{
497  int status;
498  if (argc < 2)
499    {
500      com_err("moira (access)", 0, "Usage: access handle [ args ... ]");
501      return;
502    }
503  status = mr_access(argv[1], argc - 2, argv + 2);
504  if (status)
505    com_err("moira (access)", status, "");
506}
507
508void test_dcm()
509{
510  int status;
511
512  if ((status = mr_do_update()))
513    com_err("moira (dcm)", status, " while triggering dcm");
514}
515
516void test_motd()
517{
518  int status;
519  char *motd;
520
521  if ((status = mr_motd(&motd)))
522    com_err("moira (motd)", status, " while getting motd");
523  if (motd)
524    printf("%s\n", motd);
525  else
526    printf("No message of the day.\n");
527}
528
529void test_list_requests(void)
530{
531  printf("Available moira requests:\n");
532  printf("\n");
533  printf("noop\t\t\tAsk Moira to do nothing\n");
534  printf("connect, c\t\tConnect to Moira server\n");
535  printf("disconnect, d\t\tDisconnect from server\n");
536  printf("host\t\t\tIdentify the server host\n");
537  printf("motd, m\t\t\tGet the Message of the Day\n");
538  printf("query, qy\t\tMake a query.\n");
539  printf("auth, a\t\t\tAuthenticate to Moira via krb5.\n");
540  printf("krb4_auth, 4\t\tAuthenticate to Moira via krb4.\n");
541  printf("proxy, p\t\tProxy authenticate to Moira.\n");
542  printf("access\t\t\tCheck access to a Moira query.\n");
543  printf("dcm\t\t\tTrigger the DCM\n");
544  printf("script, s\t\tRead commands from a script.\n");
545  printf("list_requests, lr, ?\tList available commands.\n");
546  printf("quit, Q\t\t\tLeave the subsystem.\n");
547}
548
549void test_version(int argc, char **argv)
550{
551  int status;
552
553  if (argc != 2)
554    {
555      com_err("moira (version)", 0, "Usage: version versionnumber");
556      return;
557    }
558  status = mr_version(atoi(argv[1]));
559  if (status)
560    com_err("moira (version)", status, "");
561}
562
563#ifdef HAVE_POSIX_SIGNALS
564
565void set_signal_handler(int sig, void (*handler)(int))
566{
567  struct sigaction action;
568
569  sigemptyset(&action.sa_mask);
570  action.sa_flags = 0;
571  action.sa_handler = handler;
572  sigaction(sig, &action, NULL);
573}
574
575void set_signal_blocking(int sig, int block)
576{
577  sigset_t sigs;
578  sigemptyset(&sigs);
579  sigaddset(&sigs, sig);
580  sigprocmask(block ? SIG_BLOCK : SIG_UNBLOCK, &sigs, NULL);
581}
582
583#else
584
585void set_signal_handler(int sig, void (*handler)(int))
586{
587  signal(sig, handler);
588}
589
590#ifdef _WIN32
591BOOL WINAPI blocking_handler(DWORD dwCtrlType)
592{
593  return(TRUE);
594}
595
596void set_signal_blocking(int sig, int block)
597{
598  SetConsoleCtrlHandler(blocking_handler, block ? TRUE : FALSE);
599}
600#endif /* _WIN32 */
601
602#endif /* HAVE_POSIX_SIGNALS */
Note: See TracBrowser for help on using the repository browser.