]> andersk Git - moira.git/blob - server/qrtn.qc
make sure we use proper table names for caching;
[moira.git] / server / qrtn.qc
1 /*
2  *      $Source$
3  *      $Author$
4  *      $Header$
5  *
6  *      Copyright (C) 1987, 1988 by the Massachusetts Institute of Technology
7  *      For copying and distribution information, please see the file
8  *      <mit-copyright.h>.
9  * 
10  */
11
12 #ifndef lint
13 static char *rcsid_qrtn_qc = "$Header$";
14 #endif lint
15
16 #include <mit-copyright.h>
17 #include "query.h"
18 #include "sms_server.h"
19
20 char *Argv[16];
21
22 int ingres_errno = 0;
23 int sms_errcode = 0;
24 ## int query_timeout = 30;
25 extern char *whoami;
26 extern FILE *journal;
27
28 #define INGRES_BAD_INT 4111
29 #define INGRES_BAD_DATE 4302
30 #define INGRES_DEADLOCK 4700
31 #define INGRES_TIMEOUT 4702
32
33 /*
34  * ingerr: (supposedly) called when Ingres indicates an error.
35  * I have not yet been able to get this to work to intercept a
36  * database open error.
37  */
38
39 static int ingerr(num)
40     int *num;
41 {
42     ingres_errno = *num;
43
44     switch (*num) {
45     case INGRES_BAD_INT:
46         sms_errcode = SMS_INTEGER;
47         break;
48     case INGRES_BAD_DATE:
49         sms_errcode = SMS_DATE;
50         break;
51     case INGRES_DEADLOCK:
52         sms_errcode = SMS_DEADLOCK;
53         com_err(whoami, 0, "INGRES deadlock detected");
54         break;
55     case INGRES_TIMEOUT:
56         sms_errcode = SMS_BUSY;
57         com_err(whoami, 0, "timed out getting lock");
58         break;
59     default:
60         sms_errcode = SMS_INGRES_ERR;
61         com_err(whoami, SMS_INGRES_ERR, " code %d\n", *num);
62         critical_alert("SMS", "SMS server encountered INGRES ERROR %d", *num);
63         return (*num);
64     }
65     return (0);
66 }
67
68 int sms_open_database()
69 {
70     register int i;
71     char *malloc();
72     static first_open = 1;
73
74     if (first_open) {
75         first_open = 0;
76
77         /* initialize local argv */
78         for (i = 0; i < 16; i++)
79           Argv[i] = malloc(ARGLEN);
80
81         IIseterr(ingerr);
82         incremental_init();
83         flush_cache();
84     }
85         
86     ingres_errno = 0;
87
88     /* open the database */
89 ##  ingres sms
90 ##  set lockmode session where level = table, timeout = query_timeout
91 ##  set lockmode on capacls where readlock = shared
92 ##  set lockmode on alias where readlock = shared
93     return ingres_errno;
94 }
95
96 int sms_close_database()
97 {
98     flush_cache();
99 ##  exit
100 }
101
102 sms_check_access(cl, name, argc, argv_ro)
103     client *cl;
104     char *name;
105     int argc;
106     char *argv_ro[];
107 {
108     struct query *q;
109     struct query *get_query_by_name();
110
111     ingres_errno = 0;
112
113     q = get_query_by_name(name, cl->args->sms_version_no);
114     if (q == (struct query *)0)
115         return(SMS_NO_HANDLE);
116
117     return(sms_verify_query(cl, q, argc, argv_ro));
118 }
119
120 sms_process_query(cl, name, argc, argv_ro, action, actarg)
121     client *cl;
122     char *name;
123     int argc;
124     char *argv_ro[];
125     int (*action)();
126     char *actarg;
127 {
128     register struct query *q;
129     register int status;
130     register struct validate *v;
131     char qual[256];
132     char sort[32];
133     char *pqual;
134     char *psort;
135 ##  char *table, *rvar;
136     struct save_queue *sq;
137     struct query *get_query_by_name();
138     int sq_save_args();
139     struct save_queue *sq_create();
140     char *build_sort();
141
142     ingres_errno = 0;
143
144     /* list queries command */
145     if (!strcmp(name, "_list_queries")) {
146         list_queries(cl->args->sms_version_no, action, actarg);
147         return(SMS_SUCCESS);
148     }
149
150     /* help query command */
151     if (!strcmp(name, "_help")) {
152         if (argc < 1)
153             return(SMS_ARGS);
154         q = get_query_by_name(argv_ro[0], cl->args->sms_version_no);
155         if (q == (struct query *)0) return(SMS_NO_HANDLE);
156         help_query(q, action, actarg);
157         return(SMS_SUCCESS);
158     }
159
160     /* get query structure, return error if named query does not exist */
161     q = get_query_by_name(name, cl->args->sms_version_no);
162     if (q == (struct query *)0) return(SMS_NO_HANDLE);
163     v = q->validate;
164
165     if (q->type != RETRIEVE) {
166 ##      begin transaction
167     }
168
169     /* setup argument vector, verify access and arguments */
170     if ((status = sms_verify_query(cl, q, argc, argv_ro)) != SMS_SUCCESS)
171         goto out;
172
173     /* perform any special query pre-processing */
174     if (v && v->pre_rtn) {
175         status = (*v->pre_rtn)(q, Argv, cl, 0);
176         if (status != SMS_SUCCESS)
177             goto out;
178     }
179
180     switch (q->type) {
181     case RETRIEVE:
182         /* for queries that do not permit wildcarding, check if row
183            uniquely exists */
184         if (v && v->field) {
185             status = validate_row(q, Argv, v);
186             if (status != SMS_EXISTS) break;
187         }
188
189         /* build "where" clause if needed */
190         if (q->qual) {
191             build_qual(q->qual, q->argc, Argv, qual);
192             pqual = qual;
193         } else {
194             pqual = 0;
195         }
196
197         /* build "sort" clause if needed */
198         if (v && v->valobj) {
199             psort = build_sort(v, sort);
200         } else {
201             psort = 0;
202         }
203
204         /* if there is a followup routine, then we must save the results */
205         /* of the first query for use by the followup routine */
206         /* if q->rvar = NULL, perform post_rtn only */
207         if (q->rvar) {
208             if (v && v->post_rtn) {
209                 sq = sq_create();
210                 status = do_retrieve(q, pqual, psort, sq_save_args, sq);
211                 if (status != SMS_SUCCESS) {
212                     sq_destroy(sq);
213                     break;
214                 }
215                 status = (*v->post_rtn)(q, sq, v, action, actarg, cl);
216             } else {
217                 /* normal retrieve */
218                 status = do_retrieve(q, pqual, psort, action, actarg);
219             }
220             if (status != SMS_SUCCESS) break;
221         } else {
222             status = (*v->post_rtn)(q, Argv, cl, action, actarg);
223         }
224
225         break;
226
227     case UPDATE:
228         /* see if row already exists */
229         if (v->field) {
230             status = validate_row(q, Argv, v);
231             if (status != SMS_EXISTS) break;
232         }
233
234         /* build "where" clause and perform update */
235         /* if q->rvar = NULL, perform post_rtn only */
236         if (q->rvar) {
237             build_qual(q->qual, q->argc, Argv, qual);
238             incremental_before(q->rtable, qual, argv_ro);
239             status = do_update(q, &Argv[q->argc], qual, action, actarg);
240             incremental_after(q->rtable, qual, argv_ro);
241             if (status != SMS_SUCCESS) break;
242             flush_name(argv_ro[0], q->rtable);
243             table = q->rtable;
244             if (strcmp(q->shortname, "sshi") && strcmp(q->shortname, "ssif")) {
245 ##              repeat replace tblstats (updates = tblstats.updates + 1,
246 ##                                       modtime = "now")
247 ##                  where tblstats.#table = @table
248             }
249         }
250
251         /* execute followup routine (if any) */
252         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
253
254         break;
255
256     case APPEND:
257         /* see if row already exists */
258         if (v->field) {
259             status = validate_row(q, Argv, v);
260             if (status != SMS_NO_MATCH) break;
261         }
262
263         /* increment id number if necessary */
264         if (v->object_id) {
265             status = set_next_object_id(v->object_id, q->rtable);
266             if (status != SMS_SUCCESS) break;
267         }
268
269         /* build "where" clause if needed */
270         if (q->qual) {
271             build_qual(q->qual, q->argc, Argv, qual);
272             pqual = qual;
273         } else {
274             pqual = 0;
275         }
276
277         /* perform the append */
278         /* if q->rvar = NULL, perform post_rtn only */
279         if (q->rvar) {
280             incremental_clear_before();
281             status = do_append(q, &Argv[q->argc], pqual, action, actarg);
282             if (status != SMS_SUCCESS) break;
283             if (v && v->object_id) {
284                 sprintf(qual, "%s.%s = values.value and values.name = \"%s\"",
285                         q->rvar, v->object_id, v->object_id);
286                 incremental_after(q->rtable, qual, argv_ro);
287             } else
288               incremental_after(q->rtable, pqual, argv_ro);
289
290             table = q->rtable;
291 ##          repeat replace tblstats (appends = tblstats.appends + 1,
292 ##                                   modtime = "now")
293 ##              where tblstats.#table = @table
294         }
295         
296         /* execute followup routine */
297         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
298         break;
299
300     case DELETE:
301         /* see if row already exists */
302         if (v->field) {
303             status = validate_row(q, Argv, v);
304             if (status != SMS_EXISTS) break;
305         }
306
307         /* build "where" clause and perform delete */
308         /* if q->rvar = NULL, perform post_rtn only */
309         if (q->rvar) {
310             build_qual(q->qual, q->argc, Argv, qual);
311             table = q->rtable;
312             rvar = q->rvar;
313 ##          range of rvar is table
314             incremental_before(q->rtable, qual, argv_ro);
315             status = do_delete(q, qual, action, actarg);
316             incremental_clear_after();
317             if (status != SMS_SUCCESS) break;
318             flush_name(argv_ro[0], q->rtable);
319 ##          repeat replace tblstats (deletes = tblstats.deletes + 1,
320 ##                                   modtime = "now")
321 ##              where tblstats.#table = @table
322         }
323
324         /* execute followup routine */
325         if (v->post_rtn) status = (*v->post_rtn)(q, Argv, cl);
326         break;
327
328     }
329
330 out:
331     if (status == SMS_SUCCESS && ingres_errno != 0) {
332         com_err(whoami, SMS_INTERNAL, "Server didn't notice INGRES ERROR %d",
333                        ingres_errno);
334         status = sms_errcode;
335     }
336
337     if (q->type != RETRIEVE) {
338         if (status == SMS_SUCCESS) {
339 ##          end transaction     /* commit to this */
340             if (journal) {
341                 char buf[1024], *bp;
342                 int i;
343                 extern time_t now;
344
345                 fprintf(journal, "%% %s %s %s",
346                         cl->clname, cl->entity, ctime(&now));
347                 fprintf(journal, "%s[%d] ", q->name, cl->args->sms_version_no);
348                 for (i = 0; i < argc; i++) {
349                     if (i != 0) {
350                         putc(' ', journal);
351                     }
352                     requote(buf, argv_ro[i], sizeof(buf));
353                     fputs(buf, journal);
354                 }
355                 putc('\n', journal);
356                 fflush(journal);
357             }
358             incremental_update();
359         } else {
360             if (ingres_errno != INGRES_DEADLOCK) {
361 ##              abort           /* it never happened */
362             }
363             incremental_flush();
364         }
365 ##      set lockmode session where readlock = system
366     }
367
368     if (status != SMS_SUCCESS && log_flags & LOG_RES)
369         com_err(whoami, status, " (Query failed)");
370     return(status);
371 }
372
373 build_qual(fmt, argc, argv, qual)
374         char *fmt;
375         int argc;
376         char *argv[];
377         char *qual;
378 {
379     register char *c;
380     register int i;
381     char *args[4];
382     char *index();
383
384     c = fmt;
385     for (i = 0; i < argc; i++) {
386         c = index(c, '%');
387         if (c++ == (char *)0) return(SMS_ARGS);
388         if (*c == 's')
389             args[i] = argv[i];
390         else if (*c == 'd')
391             *(int *)&args[i] = *(int *)argv[i]; /* sigh */
392         else
393             return(SMS_INGRES_ERR);
394     }
395
396     switch (argc) {
397     case 0:
398         strcpy(qual, fmt);
399         break;
400
401     case 1:
402         sprintf(qual, fmt, args[0]);
403         break;
404
405     case 2:
406         sprintf(qual, fmt, args[0], args[1]);
407         break;
408
409     case 3:
410         sprintf(qual, fmt, args[0], args[1], args[2]);
411         break;
412
413     case 4:
414         sprintf(qual, fmt, args[0], args[1], args[2], args[3]);
415         break;
416     }
417     return(SMS_SUCCESS);
418 }
419
420 char *
421 build_sort(v, sort)
422     register struct validate *v;
423     char *sort;
424 {
425     register struct valobj *vo;
426     register int n;
427     char elem[16];
428
429     n = v->objcnt;
430     vo = v->valobj;
431     *sort = 0;
432
433     while (--n >= 0) {
434         if (vo->type == V_SORT) {
435             sprintf(elem, "RET_VAR%d", vo->index + 1);
436             if (*sort) strcat(sort, ", ");
437             strcat(sort, elem);
438         }
439         vo++;
440     }
441
442     return ((*sort) ? sort : 0);
443 }
444
445
446 /* Build arguement vector, verify query and arguments */
447
448 sms_verify_query(cl, q, argc, argv_ro)
449     client *cl;
450     struct query *q;
451     int argc;
452     char *argv_ro[];
453 {
454     register int argreq;
455     register int status;
456     register struct validate *v = q->validate;
457     register int i;
458     register int privileged = 0;
459     int len;
460
461     /* copy the arguments into a local argv that we can modify */
462     if (argc >= QMAXARGS)
463       return(SMS_ARGS);
464     for (i = 0; i < argc; i++) {
465         if ((len = strlen(argv_ro[i])) < ARGLEN)
466             strcpy(Argv[i], argv_ro[i]);
467         else
468             return(SMS_ARG_TOO_LONG);
469         if (Argv[i][len-1] == '\\')
470           return(SMS_BAD_CHAR);
471     }
472
473     /* check initial query access */
474     status = check_query_access(q, Argv, cl);
475     if (status != SMS_SUCCESS && status != SMS_PERM)
476         return(status);
477     if (status == SMS_SUCCESS)
478         privileged++;
479
480     /* check argument count */
481     argreq = q->argc;
482     if (q->type == UPDATE || q->type == APPEND) argreq += q->vcnt;
483     if (argc != argreq) return(SMS_ARGS);
484
485     /* validate arguments */
486     if (v && v->valobj) {
487         status = validate_fields(q, Argv, v->valobj, v->objcnt);
488         if (status != SMS_SUCCESS) return(status);
489     }
490
491     /* perform special query access check */
492     if (!privileged && v && v->acs_rtn) {
493         status = (*v->acs_rtn)(q, Argv, cl);
494         if (status != SMS_SUCCESS && status != SMS_PERM)
495             return(status);
496         if (status == SMS_SUCCESS)
497             privileged++;
498     }
499
500     return(privileged ? SMS_SUCCESS : SMS_PERM);
501 }
502
503
504 /* This routine caches info from the database.  Each query acl is stored
505  * in the query structure, and whether that acl contains everybody.
506  */
507
508 check_query_access(q, argv, cl)
509     struct query *q;
510     char *argv[];
511     client *cl;
512 ##{
513 ##  char *name;
514 ##  int acl_id;
515 ##  int exists;
516 ##  int rowcount;
517 ##  int errorno;
518 ##  static int def_uid;
519     int status;
520     int client_id;
521     char *client_type;
522
523     /* initialize default uid */
524     if (def_uid == 0) {
525 ##      retrieve (def_uid = users.users_id) where users.login = "default"
526     }
527
528     /* get query access control list */
529     if (q->acl != 0)
530       acl_id = q->acl;
531     else {
532         name = q->shortname;
533 ##      retrieve (acl_id = capacls.list_id) where capacls.tag = name
534 ##      inquire_equel (rowcount = "rowcount", errorno = "errorno")
535         if (errorno != 0) return(SMS_INGRES_ERR);
536         if (rowcount == 0) return(SMS_PERM);
537         q->acl = acl_id;
538
539         /* check for default access */
540 ##      retrieve (exists = any(imembers.#member_id where
541 ##                             imembers.list_id = acl_id and
542 ##                             imembers.member_type = "USER" and
543 ##                             imembers.#member_id = def_uid))
544         q->everybody = exists;
545     }
546
547     if (q->everybody)
548       return(SMS_SUCCESS);
549
550     if (get_client(cl, &client_type, &client_id) != SMS_SUCCESS)
551       return(SMS_PERM);
552     if (find_member("LIST", acl_id, client_type, client_id, 0))
553       return(SMS_SUCCESS);
554     else
555       return(SMS_PERM);
556 ##}
557
558
559 get_client(cl, client_type, client_id)
560     client *cl;
561     char **client_type;
562     int *client_id;
563 {
564     if (cl->users_id > 0) {
565         *client_id = cl->users_id;
566         *client_type = "USER";
567         return(SMS_SUCCESS);
568     }
569
570     if (cl->client_id < 0) {
571         *client_id = -cl->users_id;
572         *client_type = "KERBEROS";
573         return(SMS_SUCCESS);
574     }
575
576     return(SMS_PERM);
577 }
578
579 ##find_member(list_type, list_id, member_type, member_id)
580     char *list_type;
581 ##  int list_id;
582 ##  char *member_type;
583 ##  int member_id;
584 ##{
585 ##  int exists, errorno;
586
587     if (!strcmp(strtrim(list_type), strtrim(member_type)) &&
588         list_id == member_id)
589         return(1);
590
591     /* see if client is a direct member of list */
592 ##  repeat retrieve (exists = any(imembers.#member_id where 
593 ##                                imembers.#list_id = @list_id and
594 ##                                imembers.#member_type = @member_type and 
595 ##                                imembers.#member_id = @member_id))
596 ##  inquire_equel(errorno = "errorno")
597     if (errorno == 0)
598       return(exists);
599     else
600       return(0);
601 ##}
602
603
604 do_retrieve(q, pqual, psort, action, actarg)
605     register struct query *q;
606     char *pqual;
607     char *psort;
608     int (*action)();
609     char *actarg;
610 ##{
611 ##  char *rvar;
612 ##  char *rtable;
613 ##  char *cqual;
614 ##  char *csort;
615 ##  int rowcount;
616 ##  int errorno;
617     static char **vaddrs = (char **)NULL;
618
619     if (!vaddrs) {
620         register int i;
621
622         if ((vaddrs = (char **)malloc(sizeof(char *) * QMAXARGS)) == NULL) {
623             com_err(whoami, SMS_NO_MEM, "setting up static argv");
624             exit(1);
625         }
626         for (i = 0; i < QMAXARGS; i++) {
627             if ((vaddrs[i] = malloc(QMAXARGSIZE)) == NULL) {
628                 com_err(whoami, SMS_NO_MEM, "setting up static argv");
629                 exit(1);
630             }
631         }
632     }
633
634     if (q->rvar) {
635         rvar = q->rvar;
636         rtable = q->rtable;
637 ##      range of rvar is rtable
638     }
639
640     if (psort) {
641         csort = psort;
642         if (pqual) {
643             cqual = pqual;
644 ##          retrieve unique (param (q->tlist, vaddrs)) where cqual
645 ##                   sort by csort
646 ##          {
647                  (*action)(q->vcnt, vaddrs, actarg);
648 ##          }
649         } else {
650 ##          retrieve unique (param (q->tlist, vaddrs))
651 ##                   sort by csort
652 ##          {
653                  (*action)(q->vcnt, vaddrs, actarg);
654 ##          }
655         }
656
657     } else {
658         if (pqual) {
659             cqual = pqual;
660 ##          retrieve unique (param (q->tlist, vaddrs)) where cqual
661 ##          {
662                  (*action)(q->vcnt, vaddrs, actarg);
663 ##          }
664         } else {
665 ##          retrieve unique (param (q->tlist, vaddrs))
666 ##          {
667                  (*action)(q->vcnt, vaddrs, actarg);
668 ##          }
669         }
670     }
671
672     if (sms_errcode) return(sms_errcode);
673 ##  inquire_equel (rowcount = "rowcount")
674     return ((rowcount == 0) ? SMS_NO_MATCH : SMS_SUCCESS);
675 ##}
676
677 do_update(q, argv, qual, action, actarg)
678     register struct query *q;
679     char *argv[];
680     char *qual;
681     int (*action)();
682     char *actarg;
683 ##{
684 ##  char *rvar;
685 ##  char *rtable;
686 ##  char *cqual;
687 ##  int errorno;
688       
689     rvar = q->rvar;
690     rtable = q->rtable;
691 ##  range of rvar is rtable
692
693     cqual = qual;
694 ##  replace rvar (param (q->tlist, argv))
695 ##  where cqual
696
697     if (sms_errcode) return(sms_errcode);
698     return(SMS_SUCCESS);
699 ##}
700
701 do_append(q, argv, pqual, action, actarg)
702     register struct query *q;
703     char *argv[];
704     char *pqual;
705     int (*action)();
706     char *actarg;
707 ##{
708 ##  char *rvar;
709 ##  char *rtable;
710 ##  char *cqual;
711 ##  int errorno;
712
713     rvar = q->rvar;
714     rtable = q->rtable;
715 ##  range of rvar is rtable
716
717     if (pqual) {
718         cqual = pqual;
719 ##      append to rtable (param (q->tlist, argv)) where cqual
720     } else {
721 ##      append to rtable (param (q->tlist, argv))
722     }
723
724     if (sms_errcode) return(sms_errcode);
725     return(SMS_SUCCESS);
726 ##}
727
728 do_delete(q, qual, action, actarg)
729     register struct query *q;
730     char *qual;
731     int (*action)();
732     char *actarg;
733 ##{
734 ##  char *rvar;
735 ##  char *rtable;
736 ##  char *cqual;
737 ##  int errorno;
738
739     rvar = q->rvar;
740     rtable = q->rtable;
741 ##  range of rvar is rtable
742
743     cqual = qual;
744 ##  delete rvar where cqual
745
746     if (sms_errcode) return(sms_errcode);
747     return(SMS_SUCCESS);
748 ##}
749
750
751 /**
752  ** set_next_object_id - set next object id in values table
753  **
754  ** Inputs: object - object name in values table and in objects
755  **         table - name of table objects are found in
756  **
757  ** - called before an APPEND operation to set the next object id to
758  **   be used for the new record to the next free value
759  **
760  **/
761
762 set_next_object_id(object, table)
763     char *object;
764     char *table;
765 ##{
766 ##  char *name, *tbl;
767 ##  int rowcount, exists, value;
768
769     name = object;
770     tbl = table;
771 ##  repeat retrieve (value = values.#value) where values.#name = @name
772 ##  inquire_equel(rowcount = "rowcount")
773     if (rowcount != 1)
774         return(SMS_NO_ID);
775
776 ##  retrieve (exists = any(tbl.name where tbl.name = value))
777 ##  inquire_equel(rowcount = "rowcount")
778     if (rowcount != 1)
779         return(SMS_NO_ID);
780     while (exists) {
781         value++;
782         if (value > MAX_ID_VALUE)
783             value = MIN_ID_VALUE;
784 ##      retrieve (exists = any(tbl.name where tbl.name = value))
785     }
786
787     if (LOG_RES)
788         com_err(whoami, 0, "setting ID %s to %d", name, value);
789 ##  repeat replace values (#value = @value) where values.#name = @name
790     return(SMS_SUCCESS);
791 ##}
792
793
794 /* Turn a kerberos name into the user's ID of the account that principal
795  * owns.  Sets the kerberos ID and user ID.
796  */
797
798 set_krb_mapping(name, login, ok, kid, uid)
799 char *name;
800 char *login;
801 int ok;
802 int *kid;
803 int *uid;
804 ##{
805 ##  int u_id, k_id, rowcount;
806 ##  char *krbname;
807
808     krbname = name;
809     *kid = 0;
810     *uid = 0;
811
812 ##  repeat retrieve (u_id = krbmap.#users_id, k_id = krbmap.#string_id)
813 ##      where krbmap.string_id = strings.string_id and strings.string = @krbname
814 ##  inquire_equel (rowcount = "rowcount")
815     
816     if (rowcount == 1) {
817         *kid = -k_id;
818         *uid = u_id;
819         return;
820     }
821
822     if (name_to_id(name, "STRINGS", &k_id) == SMS_SUCCESS)
823       *kid = -k_id;
824
825     if (!ok) {
826         *uid = *kid;
827         return;
828     }
829
830     if (name_to_id(login, "USERS", uid) != SMS_SUCCESS)
831       *uid = 0;
832
833     if (*kid == 0)
834       *kid = *uid;
835 ##}
836
837
838 /* For now this just checks the argc's.  It should also see that there
839  * are no duplicate names.
840  */
841
842 sanity_check_queries()
843 {
844     register int i;
845     int maxv = 0, maxa = 0;
846 #ifdef MULTIPROTOCOLS
847     extern int QueryCount1, QueryCount2;
848     extern struct query Queries1[], Queries2[];
849 #else
850     extern int QueryCount2;
851     extern struct query Queries2[];
852 #endif MULTIPROTOCOLS
853
854 #define MAX(x,y) ((x) > (y) ? (x) : (y))
855
856 #ifdef MULTIPROTOCOLS
857     for (i = 0; i < QueryCount1; i++) {
858         maxv = MAX(maxv, Queries1[i].vcnt);
859         maxa = MAX(maxa, Queries1[i].argc);
860     }
861 #endif MULTIPROTOCOLS
862     for (i = 0; i < QueryCount2; i++) {
863         maxv = MAX(maxv, Queries2[i].vcnt);
864         maxa = MAX(maxa, Queries2[i].argc);
865     }
866     if (MAX(maxv, maxa) > QMAXARGS) {
867         com_err(whoami, 0, "A query has more args than QMAXARGS");
868         exit(1);
869     }
870 }
This page took 0.303144 seconds and 5 git commands to generate.