]> andersk Git - moira.git/blame - server/increment.pc
register_user() on a registered Kerberos-only account should provide you
[moira.git] / server / increment.pc
CommitLineData
7ac48069 1/* $Id$
32cfe906 2 *
7ac48069 3 * Deal with incremental updates
5eaef520 4 *
7ac48069 5 * Copyright (C) 1989-1998 by the Massachusetts Institute of Technology
6 * For copying and distribution information, please see the file
7 * <mit-copyright.h>.
32cfe906 8 */
9
32cfe906 10#include <mit-copyright.h>
32cfe906 11#include "mr_server.h"
03c05291 12#include "query.h"
13#include "qrtn.h"
7ac48069 14
15#include <signal.h>
85330553 16#include <stdio.h>
7ac48069 17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20
45bf7573 21EXEC SQL INCLUDE sqlca;
32cfe906 22
7ac48069 23RCSID("$Header$");
24
32cfe906 25extern char *whoami;
03c05291 26extern char *table_name[];
27extern int num_tables;
32cfe906 28
29int inc_pid = 0;
30int inc_running = 0;
31time_t inc_started;
32
33#define MAXARGC 15
34
03c05291 35EXEC SQL WHENEVER SQLERROR DO dbmserr();
45bf7573 36
32cfe906 37/* structures to save before args */
32cfe906 38static char *before[MAXARGC];
32cfe906 39static int beforec;
03c05291 40static enum tables beforetable;
32cfe906 41
42/* structures to save after args */
32cfe906 43static char *after[MAXARGC];
32cfe906 44static int afterc;
45
46/* structures to save entire sets of incremental changes */
47struct save_queue *incremental_sq = NULL;
48struct save_queue *incremental_exec = NULL;
49struct iupdate {
5eaef520 50 char *table;
51 int beforec;
52 char **before;
53 int afterc;
54 char **after;
55 char *service;
32cfe906 56};
57
03c05291 58void next_incremental(void);
fc053494 59char **copy_argv(char **argv, int argc);
03c05291 60void free_argv(char **argv, int argc);
61int table_num(char *table);
32cfe906 62
03c05291 63void incremental_init(void)
32cfe906 64{
5eaef520 65 int i;
32cfe906 66
5eaef520 67 if (!incremental_sq)
68 incremental_sq = sq_create();
69 if (!incremental_exec)
70 incremental_exec = sq_create();
03c05291 71
5eaef520 72 for (i = 0; i < MAXARGC; i++)
73 {
e688520a 74 before[i] = xmalloc(MAX_FIELD_WIDTH);
75 after[i] = xmalloc(MAX_FIELD_WIDTH);
03c05291 76 }
32cfe906 77}
78
79
03c05291 80/* record the state of a table row before it is changed */
81
5eaef520 82void incremental_before(enum tables table, char *qual, char **argv)
32cfe906 83{
5eaef520 84 EXEC SQL BEGIN DECLARE SECTION;
85 int id;
86 EXEC SQL END DECLARE SECTION;
87
88acd4d3 88 char *name, *name2;
5eaef520 89
90 beforetable = table;
91
92 switch (table)
93 {
94 case USERS_TABLE:
d6759517 95 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
96 "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
88acd4d3 97 "u.clearid, u.type, u.users_id FROM users u WHERE %s", qual);
5eaef520 98 dosql(before);
88acd4d3 99 beforec = 11;
5eaef520 100 break;
101 case MACHINE_TABLE:
88acd4d3 102 sprintf(stmt_buf, "SELECT m.name, m.vendor, m.mach_id FROM machine m "
5eaef520 103 "WHERE %s", qual);
104 dosql(before);
88acd4d3 105 beforec = 3;
5eaef520 106 break;
e688520a 107 case CLUSTERS_TABLE:
88acd4d3 108 sprintf(stmt_buf, "SELECT c.name, c.description, c.location, "
109 "c.clu_id FROM clusters c WHERE %s", qual);
5eaef520 110 dosql(before);
88acd4d3 111 beforec = 4;
5eaef520 112 break;
bb5c9457 113 case CONTAINERS_TABLE:
114 sprintf(stmt_buf, "SELECT c.name, c.description, c.location, c.contact, "
115 "c.acl_type, c.acl_id, c.cnt_id FROM containers c WHERE %s",
116 qual);
117 dosql(before);
118 beforec = 7;
429aec78 119 name = xmalloc(0);
120 id = atoi(before[5]);
121 if (!strncmp(before[4], "USER", 4))
122 {
123 id_to_name(id, USERS_TABLE, &name);
124 strcpy(before[5], name);
125 }
126 else if (!strncmp(before[4], "LIST", 4))
127 {
128 id_to_name(id, LIST_TABLE, &name);
129 strcpy(before[5], name);
130 }
131 else if (!strncmp(before[4], "KERBEROS", 8))
132 {
133 id_to_name(id, STRINGS_TABLE, &name);
134 strcpy(before[5], name);
135 }
bb5c9457 136 break;
5eaef520 137 case MCMAP_TABLE:
138 strcpy(before[0], argv[0]);
139 strcpy(before[1], argv[1]);
140 beforec = 2;
141 break;
142 case SVC_TABLE:
143 strcpy(before[0], argv[0]);
144 strcpy(before[1], argv[1]);
145 strcpy(before[2], argv[2]);
146 beforec = 3;
147 break;
148 case FILESYS_TABLE:
149 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
150 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
88acd4d3 151 "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
152 "WHERE %s", qual);
5eaef520 153 dosql(before);
88acd4d3 154 name = xmalloc(0);
5eaef520 155 id = atoi(before[2]);
156 id_to_name(id, MACHINE_TABLE, &name);
157 strcpy(before[2], name);
158 id = atoi(before[7]);
159 id_to_name(id, USERS_TABLE, &name);
160 strcpy(before[7], name);
161 id = atoi(before[8]);
162 id_to_name(id, LIST_TABLE, &name);
163 strcpy(before[8], name);
164 free(name);
88acd4d3 165 beforec = 12;
5eaef520 166 break;
167 case QUOTA_TABLE:
168 strcpy(before[0], "?");
169 strcpy(before[1], argv[1]);
170 strcpy(before[2], "?");
171 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
172 "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
173 dosql(&(before[3]));
174 strcpy(before[2], argv[1]);
175 beforec = 5;
176 break;
177 case LIST_TABLE:
178 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
179 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
88acd4d3 180 "l.description, l.list_id FROM list l WHERE %s", qual);
5eaef520 181 dosql(before);
88acd4d3 182 beforec = 11;
5eaef520 183 break;
184 case IMEMBERS_TABLE:
185 id = (int) argv[0];
186 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
187 "grouplist, gid FROM list WHERE list_id = %d", id);
188 dosql(&(before[3]));
88acd4d3 189 name = xmalloc(0);
5eaef520 190 id_to_name(id, LIST_TABLE, &name);
88acd4d3 191 name2 = xmalloc(0);
5eaef520 192 strcpy(before[0], name);
193 strcpy(before[1], argv[1]);
194 id = (int) argv[2];
88acd4d3 195 beforec = 10;
5eaef520 196 if (!strcmp(before[1], "USER"))
197 {
88acd4d3 198 id_to_name(id, USERS_TABLE, &name2);
199 EXEC SQL SELECT status, users_id INTO :before[9], :before[11]
200 FROM users WHERE users_id = :id;
201 EXEC SQL SELECT list_id INTO :before[10] FROM list
202 WHERE name = :name;
203 beforec = 12;
5eaef520 204 }
205 else if (!strcmp(before[1], "LIST"))
88acd4d3 206 {
207 id_to_name(id, LIST_TABLE, &name2);
208 EXEC SQL SELECT list_id INTO :before[9] FROM list
209 WHERE name = :name;
210 sprintf(before[10], "%d", id);
211 beforec = 11;
212 }
5eaef520 213 else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS"))
88acd4d3 214 {
215 id_to_name(id, STRINGS_TABLE, &name2);
216 EXEC SQL SELECT list_id INTO :before[9] FROM list
217 WHERE name = :name;
218 }
5f7b0741 219 else if (!strcmp(before[1], "MACHINE"))
220 {
221 id_to_name(id, MACHINE_TABLE, &name2);
53a1afb6 222 EXEC SQL SELECT list_id INTO :before[9] FROM list
5f7b0741 223 WHERE name = :name;
53a1afb6 224 sprintf(before[10], "%d", id);
225 beforec = 11;
5f7b0741 226 }
88acd4d3 227 strcpy(before[2], name2);
5eaef520 228 free(name);
88acd4d3 229 free(name2);
5eaef520 230 break;
231 default:
03c05291 232 /*
233 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
234 table_name[table]);
235 */
5eaef520 236 break;
237 }
a313cad2 238}
32cfe906 239
240
03c05291 241void incremental_clear_before(void)
32cfe906 242{
5eaef520 243 beforec = 0;
32cfe906 244}
245
32cfe906 246
03c05291 247/* add an element to the incremental queue for the changed row */
32cfe906 248
5eaef520 249void incremental_after(enum tables table, char *qual, char **argv)
a313cad2 250{
88acd4d3 251 char *name, *name2;
5eaef520 252 EXEC SQL BEGIN DECLARE SECTION;
253 int id;
254 EXEC SQL END DECLARE SECTION;
255 struct iupdate *iu;
256
257 switch (table)
258 {
259 case USERS_TABLE:
d6759517 260 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
261 "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
88acd4d3 262 "u.clearid, u.type, u.users_id FROM users u WHERE %s", qual);
5eaef520 263 dosql(after);
88acd4d3 264 afterc = 11;
5eaef520 265 break;
266 case MACHINE_TABLE:
88acd4d3 267 sprintf(stmt_buf, "SELECT m.name, m.vendor, m.mach_id FROM machine m "
5eaef520 268 "WHERE %s", qual);
269 dosql(after);
88acd4d3 270 afterc = 3;
5eaef520 271 break;
e688520a 272 case CLUSTERS_TABLE:
88acd4d3 273 sprintf(stmt_buf, "SELECT c.name, c.description, c.location, "
274 "c.clu_id FROM clusters c WHERE %s", qual);
5eaef520 275 dosql(after);
88acd4d3 276 afterc = 4;
5eaef520 277 break;
bb5c9457 278 case CONTAINERS_TABLE:
279 sprintf(stmt_buf, "SELECT c.name, c.description, c.location, c.contact, "
280 "c.acl_type, c.acl_id, c.cnt_id FROM containers c WHERE %s",
281 qual);
282 dosql(after);
283 afterc = 7;
429aec78 284 name = xmalloc(0);
285 id = atoi(after[5]);
286 if (!strncmp(after[4], "USER", 4))
287 {
288 id_to_name(id, USERS_TABLE, &name);
289 strcpy(after[5], name);
290 }
291 else if (!strncmp(after[4], "LIST", 4))
292 {
293 id_to_name(id, LIST_TABLE, &name);
294 strcpy(after[5], name);
295 }
296 else if (!strncmp(after[4], "KERBEROS", 8))
297 {
298 id_to_name(id, STRINGS_TABLE, &name);
299 strcpy(after[5], name);
300 }
bb5c9457 301 break;
5eaef520 302 case MCMAP_TABLE:
303 strcpy(after[0], argv[0]);
304 strcpy(after[1], argv[1]);
305 afterc = 2;
306 break;
307 case SVC_TABLE:
308 strcpy(after[0], argv[0]);
309 strcpy(after[1], argv[1]);
310 strcpy(after[2], argv[2]);
311 afterc = 3;
312 break;
313 case FILESYS_TABLE:
314 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
315 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
88acd4d3 316 "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
317 "WHERE %s", qual);
5eaef520 318 dosql(after);
88acd4d3 319 name = xmalloc(0);
5eaef520 320 id = atoi(after[2]);
321 id_to_name(id, MACHINE_TABLE, &name);
322 strcpy(after[2], name);
323 id = atoi(after[7]);
324 id_to_name(id, USERS_TABLE, &name);
325 strcpy(after[7], name);
326 id = atoi(after[8]);
327 id_to_name(id, LIST_TABLE, &name);
328 strcpy(after[8], name);
329 free(name);
88acd4d3 330 afterc = 12;
5eaef520 331 break;
332 case QUOTA_TABLE:
333 strcpy(after[0], "?");
334 strcpy(after[1], argv[1]);
335 strcpy(after[2], "?");
336 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
337 "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
338 qual, argv[1]);
339 dosql(&(after[3]));
340 afterc = 5;
341 break;
342 case LIST_TABLE:
343 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
344 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
88acd4d3 345 "l.description, l.list_id FROM list l WHERE %s", qual);
5eaef520 346 dosql(after);
88acd4d3 347 afterc = 11;
5eaef520 348 break;
349 case IMEMBERS_TABLE:
350 id = (int) argv[0];
351 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
352 "grouplist, gid FROM list WHERE list_id = %d", id);
353 dosql(&(after[3]));
88acd4d3 354 name = xmalloc(0);
5eaef520 355 id_to_name(id, LIST_TABLE, &name);
88acd4d3 356 name2 = xmalloc(0);
5eaef520 357 strcpy(after[0], name);
358 strcpy(after[1], argv[1]);
359 id = (int) argv[2];
88acd4d3 360 afterc = 10;
5eaef520 361 if (!strcmp(after[1], "USER"))
362 {
88acd4d3 363 id_to_name(id, USERS_TABLE, &name2);
364 EXEC SQL SELECT status, users_id INTO :after[9], :after[11]
365 FROM users WHERE users_id = :id;
366 EXEC SQL SELECT list_id INTO :after[10] FROM list
367 WHERE name = :name;
368 afterc = 12;
32cfe906 369 }
5eaef520 370 else if (!strcmp(after[1], "LIST"))
88acd4d3 371 {
372 id_to_name(id, LIST_TABLE, &name2);
373 EXEC SQL SELECT list_id INTO :after[9] FROM list
374 WHERE name = :name;
375 sprintf(after[10], "%d", id);
376 afterc = 11;
377 }
5eaef520 378 else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS"))
88acd4d3 379 {
380 id_to_name(id, STRINGS_TABLE, &name2);
381 EXEC SQL SELECT list_id INTO :after[9] FROM list
382 WHERE name = :name;
383 }
5f7b0741 384 else if (!strcmp(after[1], "MACHINE"))
385 {
386 id_to_name(id, MACHINE_TABLE, &name2);
53a1afb6 387 EXEC SQL SELECT list_id INTO :after[9] FROM list
5f7b0741 388 WHERE name = :name;
53a1afb6 389 sprintf(after[10], "%d", id);
390 afterc = 11;
5f7b0741 391 }
88acd4d3 392 strcpy(after[2], name2);
5eaef520 393 free(name);
88acd4d3 394 free(name2);
5eaef520 395 break;
396 case NO_TABLE:
397 afterc = 0;
398 table = beforetable;
399 break;
400 default:
03c05291 401 /*
402 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
403 table_name[table]);
404 */
5eaef520 405 break;
32cfe906 406 }
5eaef520 407
e688520a 408 iu = xmalloc(sizeof(struct iupdate));
5eaef520 409 iu->table = table_name[table];
410 iu->beforec = beforec;
fc053494 411 iu->before = copy_argv(before, beforec);
5eaef520 412 iu->afterc = afterc;
fc053494 413 iu->after = copy_argv(after, afterc);
5eaef520 414 sq_save_data(incremental_sq, iu);
a313cad2 415}
32cfe906 416
03c05291 417void incremental_clear_after(void)
418{
5eaef520 419 incremental_after(NO_TABLE, NULL, NULL);
03c05291 420}
421
32cfe906 422
423/* Called when the current transaction is committed to start any queued
424 * incremental updates. This caches the update table the first time it
425 * is called.
426 */
427
428struct inc_cache {
5eaef520 429 struct inc_cache *next;
430 char *table, *service;
32cfe906 431};
432
433
03c05291 434void incremental_update(void)
32cfe906 435{
5eaef520 436 static int inited = 0;
437 static struct inc_cache *cache;
438 struct inc_cache *c;
439 EXEC SQL BEGIN DECLARE SECTION;
e688520a 440 char tab[INCREMENTAL_TABLE_NAME_SIZE], serv[INCREMENTAL_SERVICE_SIZE];
5eaef520 441 EXEC SQL END DECLARE SECTION;
772c26b3 442 struct iupdate *iu, *iu_save;
5eaef520 443
444 if (!inited)
445 {
446 inited++;
447
448 EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service
449 FROM incremental;
450 EXEC SQL OPEN inc;
451 while (1)
452 {
453 EXEC SQL FETCH inc INTO :tab, :serv;
454 if (sqlca.sqlcode)
455 break;
e688520a 456 c = xmalloc(sizeof(struct inc_cache));
5eaef520 457 c->next = cache;
e688520a 458 c->table = xstrdup(strtrim(tab));
459 c->service = xstrdup(strtrim(serv));
5eaef520 460 cache = c;
32cfe906 461 }
5eaef520 462 EXEC SQL CLOSE inc;
463 EXEC SQL COMMIT WORK;
32cfe906 464 }
465
5eaef520 466 while (sq_remove_data(incremental_sq, &iu))
467 {
468 for (c = cache; c; c = c->next)
469 {
470 if (!strcmp(c->table, iu->table))
471 {
472 iu->service = c->service;
772c26b3 473 iu_save = xmalloc(sizeof(struct iupdate));
474 iu_save->service = iu->service;
475 iu_save->table = iu->table;
476 iu_save->beforec = iu->beforec;
477 iu_save->afterc = iu->afterc;
478 iu_save->before = copy_argv(iu->before, iu->beforec);
479 iu_save->after = copy_argv(iu->after, iu->afterc);
480 sq_save_data(incremental_exec, iu_save);
32cfe906 481 }
482 }
e688520a 483 if (!c)
484 {
485 free_argv(iu->before, iu->beforec);
486 free_argv(iu->after, iu->afterc);
487 free(iu);
488 }
32cfe906 489 }
5eaef520 490 if (inc_running == 0)
491 next_incremental();
32cfe906 492}
493
f18a32ee 494/* Pro*C 2.2.4 can't cope with the sigset_t below, at least in Solaris 2.6.
495 We add DEFINE=_PROC_ to the proc invocation and then #ifndef that around
496 this function so proc will pass it through without reading it. */
32cfe906 497
f18a32ee 498#ifndef _PROC_
03c05291 499void next_incremental(void)
32cfe906 500{
5eaef520 501 struct iupdate *iu;
e688520a 502 char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[MAXPATHLEN];
5eaef520 503 int i;
504 sigset_t sigs;
505
506 if (!incremental_exec)
507 incremental_init();
508
509 if (sq_empty(incremental_exec) ||
510 (inc_running && now - inc_started < INC_TIMEOUT))
511 return;
512
513 if (inc_running)
514 com_err(whoami, 0, "incremental timeout on pid %d", inc_pid);
515
516 sq_remove_data(incremental_exec, &iu);
517 argv[1] = iu->table;
518 sprintf(cbefore, "%d", iu->beforec);
519 argv[2] = cbefore;
520 sprintf(cafter, "%d", iu->afterc);
521 argv[3] = cafter;
522 for (i = 0; i < iu->beforec; i++)
523 argv[4 + i] = iu->before[i];
524 for (i = 0; i < iu->afterc; i++)
525 argv[4 + iu->beforec + i] = iu->after[i];
526
527 sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
528 argv[0] = prog;
529 argv[4 + iu->beforec + iu->afterc] = 0;
530
531 sigemptyset(&sigs);
532 sigaddset(&sigs, SIGCHLD);
533 sigprocmask(SIG_BLOCK, &sigs, NULL);
534 inc_pid = vfork();
535 switch (inc_pid)
536 {
32cfe906 537 case 0:
5eaef520 538 execv(prog, argv);
539 _exit(1);
32cfe906 540 case -1:
5eaef520 541 com_err(whoami, 0, "Failed to start incremental update");
542 break;
32cfe906 543 default:
5eaef520 544 inc_running = 1;
545 inc_started = now;
32cfe906 546 }
5eaef520 547 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
32cfe906 548
5eaef520 549 free_argv(iu->before, iu->beforec);
550 free_argv(iu->after, iu->afterc);
551 free(iu);
32cfe906 552}
f18a32ee 553#endif
32cfe906 554
555/* Called when the current transaction is aborted to throw away any queued
556 * incremental updates
557 */
558
03c05291 559void incremental_flush(void)
32cfe906 560{
5eaef520 561 struct iupdate *iu;
32cfe906 562
5eaef520 563 while (sq_get_data(incremental_sq, &iu))
564 {
565 free_argv(iu->before, iu->beforec);
566 free_argv(iu->after, iu->afterc);
567 free(iu);
32cfe906 568 }
5eaef520 569 sq_destroy(incremental_sq);
570 incremental_sq = sq_create();
32cfe906 571}
572
573
fc053494 574char **copy_argv(char **argv, int argc)
575{
576 char **ret = xmalloc(sizeof(char *) * argc);
577 while (--argc >= 0)
578 ret[argc] = xstrdup(strtrim(argv[argc]));
579 return ret;
580}
581
5eaef520 582void free_argv(char **argv, int argc)
32cfe906 583{
5eaef520 584 while (--argc >= 0)
585 free(argv[argc]);
586 free(argv);
32cfe906 587}
03c05291 588
589int table_num(char *name)
590{
591 int i;
592
5eaef520 593 for (i = num_tables - 1; i; i--)
594 {
595 if (!strcmp(table_name[i], name))
596 break;
597 }
03c05291 598
599 return i; /* 0 = "none" if no match */
600}
This page took 0.396791 seconds and 5 git commands to generate.