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