]> andersk Git - moira.git/blob - clients/mrtest/mrtest.c
redo the readline stuff again to make the 8.3 /usr/athena install work
[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 #include <unistd.h>
21
22 #ifdef HAVE_READLINE
23 #include "readline/readline.h"
24 #include "readline/history.h"
25 #endif
26
27 RCSID("$Header$");
28
29 int recursion = 0, quote_output = 0, interactive;
30 int count, quit = 0, cancel = 0;
31 char *whoami;
32 sigjmp_buf jb;
33
34 #define MAXARGS 20
35
36 void discard_input(void);
37 char *mr_gets(char *prompt, char *buf, size_t len);
38 void execute_line(char *cmdbuf);
39 int parse(char *buf, char *argv[MAXARGS]);
40 int print_reply(int argc, char **argv, void *help);
41 void test_noop(void);
42 void test_connect(int argc, char **argv);
43 void test_disconnect(void);
44 void test_host(void);
45 void test_motd(void);
46 void test_query(int argc, char **argv);
47 void test_auth(void);
48 void test_access(int argc, char **argv);
49 void test_dcm(void);
50 void test_script(int argc, char **argv);
51 void test_list_requests(void);
52
53 int main(int argc, char **argv)
54 {
55   char cmdbuf[BUFSIZ];
56   struct sigaction action;
57   int c;
58
59   whoami = argv[0];
60   interactive = (isatty(0) && isatty(1));
61
62   while ((c = getopt(argc, argv, "q")) != -1)
63     {
64       switch (c)
65         {
66         case 'q':
67           quote_output = 1;
68           break;
69
70         default:
71           fprintf(stderr, "Usage: mrtest [-q]\n");
72           exit (1);
73         }
74     }
75
76   initialize_sms_error_table();
77   initialize_krb_error_table();
78
79 #ifdef HAVE_READLINE
80   /* we don't want filename completion */
81   rl_bind_key('\t', rl_insert);
82 #endif
83
84   action.sa_handler = discard_input;
85   action.sa_flags = 0;
86   sigemptyset(&action.sa_mask);
87   sigaction(SIGINT, &action, NULL);
88   sigsetjmp(jb, 1);
89
90   while (!quit)
91     {
92       if (!mr_gets("moira:  ", cmdbuf, BUFSIZ))
93         break;
94       execute_line(cmdbuf);
95     }
96   mr_disconnect();
97   exit(0);
98 }
99
100 void discard_input(void)
101 {
102   putc('\n', stdout);
103
104   /* if we're inside a script, we have to clean up file descriptors,
105      so don't jump out yet */
106   if (recursion)
107     cancel = 1;
108   else
109     siglongjmp(jb, 1);
110 }
111
112 char *mr_gets(char *prompt, char *buf, size_t len)
113 {
114   char *in;
115 #ifdef HAVE_READLINE
116   if (interactive)
117     {
118       in = readline(prompt);
119
120       if (!in)
121         return NULL;
122       if (*in)
123         add_history(in);
124       strncpy(buf, in, len - 1);
125       buf[len] = 0;
126       free(in);
127
128       return buf;
129     }
130 #endif
131   printf("%s", prompt);
132   fflush(stdout);
133   in = fgets(buf, len, stdin);
134   if (!in)
135     return in;
136   if (strchr(buf, '\n'))
137     *(strchr(buf, '\n')) = '\0';
138   return buf;
139 }
140
141 void execute_line(char *cmdbuf)
142 {
143   int argc;
144   char *argv[MAXARGS];
145
146   argc = parse(cmdbuf, argv);
147   if (argc == 0)
148     return;
149   if (!strcmp(argv[0], "noop"))
150     test_noop();
151   else if (!strcmp(argv[0], "connect") || !strcmp(argv[0], "c"))
152     test_connect(argc, argv);
153   else if (!strcmp(argv[0], "disconnect") || !strcmp(argv[0], "d"))
154     test_disconnect();
155   else if (!strcmp(argv[0], "host"))
156     test_host();
157   else if (!strcmp(argv[0], "motd"))
158     test_motd();
159   else if (!strcmp(argv[0], "query") || !strcmp(argv[0], "qy"))
160     test_query(argc, argv);
161   else if (!strcmp(argv[0], "auth") || !strcmp(argv[0], "a"))
162     test_auth();
163   else if (!strcmp(argv[0], "access"))
164     test_access(argc, argv);
165   else if (!strcmp(argv[0], "dcm"))
166     test_dcm();
167   else if (!strcmp(argv[0], "script") || !strcmp(argv[0], "s"))
168     test_script(argc, argv);
169   else if (!strcmp(argv[0], "list_requests") ||
170           !strcmp(argv[0], "lr") || !strcmp(argv[0], "?"))
171     test_list_requests();
172   else if (!strcmp(argv[0], "quit") || !strcmp(argv[0], "Q"))
173     quit = 1;
174   else
175     {
176       fprintf(stderr, "moira: Unknown request \"%s\".  "
177               "Type \"?\" for a request list.\n", argv[0]);
178     }
179 }
180
181 int parse(char *buf, char *argv[MAXARGS])
182 {
183   char *p;
184   int argc, num;
185
186   if (!*buf)
187     return 0;
188
189   for (p = buf, argc = 0, argv[0] = buf; *p && *p != '\n'; p++)
190     {
191       if (*p == '"')
192         {
193           char *d = p++;
194           /* skip to close-quote, copying back over open-quote */
195           while (*p != '"')
196             {
197               if (!*p || *p == '\n')
198                 {
199                   fprintf(stderr,
200                           "moira: Unbalanced quotes in command line\n");
201                   return 0;
202                 }
203               /* deal with \### or \\ */
204               if (*p == '\\')
205                 {
206                   if (*++p != '"' && (*p < '0' || *p > '9') && (*p != '\\'))
207                     {
208                       fprintf(stderr, "moira: Bad use of \\\n");
209                       return 0;
210                     }
211                   else if (*p >= '0' && *p <= '9')
212                     {
213                       num = (*p - '0') * 64 + (*++p - '0') * 8 + (*++p - '0');
214                       *p = num;
215                     }
216                 }
217               *d++ = *p++;
218             }
219           if (p == d + 1)
220             {
221               *d = '\0';
222               p++;
223             }
224           else
225             {
226               while (p >= d)
227                 *p-- = ' ';
228             }
229         }
230       if (*p == ' ' || *p == '\t')
231         {
232           /* skip whitespace */
233           for (*p++ = '\0'; *p == ' ' || *p == '\t'; p++)
234             ;
235           if (*p && *p != '\n')
236             argv[++argc] = p--;
237         }
238     }
239   if (*p == '\n')
240     *p = '\0';
241   return argc + 1;
242 }
243
244 void test_noop(void)
245 {
246   int status = mr_noop();
247   if (status)
248     com_err("moira (noop)", status, "");
249 }
250
251 void test_connect(int argc, char *argv[])
252 {
253   char *server = "";
254   int status;
255
256   if (argc > 1)
257     server = argv[1];
258   status = mr_connect(server);
259   if (status)
260     com_err("moira (connect)", status, "");
261 }
262
263 void test_disconnect(void)
264 {
265   int status = mr_disconnect();
266   if (status)
267     com_err("moira (disconnect)", status, "");
268 }
269
270 void test_host(void)
271 {
272   char host[BUFSIZ];
273   int status;
274
275   memset(host, 0, sizeof(host));
276
277   if ((status = mr_host(host, sizeof(host) - 1)))
278     com_err("moira (host)", status, "");
279   else
280     printf("You are connected to host %s\n", host);
281 }
282
283 void test_auth(void)
284 {
285   int status;
286
287   status = mr_auth("mrtest");
288   if (status)
289     com_err("moira (auth)", status, "");
290 }
291
292 void test_script(int argc, char *argv[])
293 {
294   FILE *inp;
295   char input[BUFSIZ], *cp;
296   int status, oldstdout, oldstderr;
297
298   if (recursion > 8)
299     {
300       com_err("moira (script)", 0, "too many levels deep in script files\n");
301       return;
302     }
303
304   if (argc < 2)
305     {
306       com_err("moira (script)", 0, "Usage: script input_file [ output_file ]");
307       return;
308     }
309
310   inp = fopen(argv[1], "r");
311   if (!inp)
312     {
313       sprintf(input, "Cannot open input file %s", argv[1]);
314       com_err("moira (script)", 0, input);
315       return;
316     }
317
318   if (argc == 3)
319     {
320       printf("Redirecting output to %s\n", argv[2]);
321       fflush(stdout);
322       oldstdout = dup(1);
323       close(1);
324       status = open(argv[2], O_CREAT|O_WRONLY|O_APPEND, 0664);
325       if (status != 1)
326         {
327           close(status);
328           dup2(oldstdout, 1);
329           argc = 2;
330           sprintf(input, "Unable to redirect output to %s\n", argv[2]);
331           com_err("moira (script)", errno, input);
332         }
333       else
334         {
335           fflush(stderr);
336           oldstderr = dup(2);
337           close(2);
338           dup2(1, 2);
339         }
340     }
341
342   recursion++;
343
344   while (!cancel)
345     {
346       if (!fgets(input, BUFSIZ, inp))
347         break;
348       if ((cp = strchr(input, '\n')))
349         *cp = '\0';
350       if (input[0] == 0)
351         {
352           printf("\n");
353           continue;
354         }
355       if (input[0] == '%')
356         {
357           for (cp = &input[1]; *cp && isspace(*cp); cp++)
358             ;
359           printf("Comment: %s\n", cp);
360           continue;
361         }
362       printf("Executing: %s\n", input);
363       execute_line(input);
364     }
365
366   recursion--;
367   if (!recursion)
368     cancel = 0;
369
370   fclose(inp);
371   if (argc == 3)
372     {
373       fflush(stdout);
374       close(1);
375       dup2(oldstdout, 1);
376       close(oldstdout);
377       fflush(stderr);
378       close(2);
379       dup2(oldstderr, 2);
380       close(oldstderr);
381     }
382 }
383
384 int print_reply(int argc, char **argv, void *help)
385 {
386   int i;
387   for (i = 0; i < argc; i++)
388     {
389       if (i != 0)
390         printf(", ");
391       if (quote_output && !*(int *)help)
392         {
393           unsigned char *p;
394
395           for (p = (unsigned char *)argv[i]; *p; p++)
396             {
397               if (isprint(*p) && *p != '\\' && *p != ',')
398                 putc(*p, stdout);
399               else
400                 printf("\\%03o", *p);
401             }
402         }
403       else
404         printf("%s", argv[i]);
405     }
406   printf("\n");
407   count++;
408   return MR_CONT;
409 }
410
411 void test_query(int argc, char **argv)
412 {
413   int status, help = !strcmp(argv[1], "_help");
414   sigset_t sigs;
415
416   if (argc < 2)
417     {
418       com_err("moira (query)", 0, "Usage: query handle [ args ... ]");
419       return;
420     }
421
422   count = 0;
423   /* Don't allow ^C during the query: it will confuse libmoira's
424      internal state. (Yay static variables) */
425   sigemptyset(&sigs);
426   sigaddset(&sigs, SIGINT);
427   sigprocmask(SIG_BLOCK, &sigs, NULL);
428   status = mr_query(argv[1], argc - 2, argv + 2, print_reply, &help);
429   sigprocmask(SIG_UNBLOCK, &sigs, NULL);
430   printf("%d tuple%s\n", count, ((count == 1) ? "" : "s"));
431   if (status)
432     com_err("moira (query)", status, "");
433 }
434
435 void test_access(int argc, char **argv)
436 {
437   int status;
438   if (argc < 2)
439     {
440       com_err("moira (access)", 0, "Usage: access handle [ args ... ]");
441       return;
442     }
443   status = mr_access(argv[1], argc - 2, argv + 2);
444   if (status)
445     com_err("moira (access)", status, "");
446 }
447
448 void test_dcm()
449 {
450   int status;
451
452   if ((status = mr_do_update()))
453     com_err("moira (dcm)", status, " while triggering dcm");
454 }
455
456 void test_motd()
457 {
458   int status;
459   char *motd;
460
461   if ((status = mr_motd(&motd)))
462     com_err("moira (motd)", status, " while getting motd");
463   if (motd)
464     printf("%s\n", motd);
465   else
466     printf("No message of the day.\n");
467 }
468
469 void test_list_requests(void)
470 {
471   printf("Available moira requests:\n");
472   printf("\n");
473   printf("noop\t\t\tAsk Moira to do nothing\n");
474   printf("connect, c\t\tConnect to Moira server\n");
475   printf("disconnect, d\t\tDisconnect from server\n");
476   printf("host\t\t\tIdentify the server host\n");
477   printf("motd, m\t\t\tGet the Message of the Day\n");
478   printf("query, qy\t\tMake a query.\n");
479   printf("auth, a\t\t\tAuthenticate to Moira.\n");
480   printf("access\t\t\tCheck access to a Moira query.\n");
481   printf("dcm\t\t\tTrigger the DCM\n");
482   printf("script, s\t\tRead commands from a script.\n");
483   printf("list_requests, lr, ?\tList available commands.\n");
484   printf("quit, Q\t\t\tLeave the subsystem.\n");
485 }
This page took 0.073284 seconds and 5 git commands to generate.