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