]> andersk Git - moira.git/blame - server/increment.pc
Check for empty strings in cluster data.
[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;
113 case MCMAP_TABLE:
114 strcpy(before[0], argv[0]);
115 strcpy(before[1], argv[1]);
116 beforec = 2;
117 break;
118 case SVC_TABLE:
119 strcpy(before[0], argv[0]);
120 strcpy(before[1], argv[1]);
121 strcpy(before[2], argv[2]);
122 beforec = 3;
123 break;
124 case FILESYS_TABLE:
125 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
126 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
88acd4d3 127 "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
128 "WHERE %s", qual);
5eaef520 129 dosql(before);
88acd4d3 130 name = xmalloc(0);
5eaef520 131 id = atoi(before[2]);
132 id_to_name(id, MACHINE_TABLE, &name);
133 strcpy(before[2], name);
134 id = atoi(before[7]);
135 id_to_name(id, USERS_TABLE, &name);
136 strcpy(before[7], name);
137 id = atoi(before[8]);
138 id_to_name(id, LIST_TABLE, &name);
139 strcpy(before[8], name);
140 free(name);
88acd4d3 141 beforec = 12;
5eaef520 142 break;
143 case QUOTA_TABLE:
144 strcpy(before[0], "?");
145 strcpy(before[1], argv[1]);
146 strcpy(before[2], "?");
147 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
148 "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
149 dosql(&(before[3]));
150 strcpy(before[2], argv[1]);
151 beforec = 5;
152 break;
153 case LIST_TABLE:
154 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
155 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
88acd4d3 156 "l.description, l.list_id FROM list l WHERE %s", qual);
5eaef520 157 dosql(before);
88acd4d3 158 beforec = 11;
5eaef520 159 break;
160 case IMEMBERS_TABLE:
161 id = (int) argv[0];
162 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
163 "grouplist, gid FROM list WHERE list_id = %d", id);
164 dosql(&(before[3]));
88acd4d3 165 name = xmalloc(0);
5eaef520 166 id_to_name(id, LIST_TABLE, &name);
88acd4d3 167 name2 = xmalloc(0);
5eaef520 168 strcpy(before[0], name);
169 strcpy(before[1], argv[1]);
170 id = (int) argv[2];
88acd4d3 171 beforec = 10;
5eaef520 172 if (!strcmp(before[1], "USER"))
173 {
88acd4d3 174 id_to_name(id, USERS_TABLE, &name2);
175 EXEC SQL SELECT status, users_id INTO :before[9], :before[11]
176 FROM users WHERE users_id = :id;
177 EXEC SQL SELECT list_id INTO :before[10] FROM list
178 WHERE name = :name;
179 beforec = 12;
5eaef520 180 }
181 else if (!strcmp(before[1], "LIST"))
88acd4d3 182 {
183 id_to_name(id, LIST_TABLE, &name2);
184 EXEC SQL SELECT list_id INTO :before[9] FROM list
185 WHERE name = :name;
186 sprintf(before[10], "%d", id);
187 beforec = 11;
188 }
5eaef520 189 else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS"))
88acd4d3 190 {
191 id_to_name(id, STRINGS_TABLE, &name2);
192 EXEC SQL SELECT list_id INTO :before[9] FROM list
193 WHERE name = :name;
194 }
195 strcpy(before[2], name2);
5eaef520 196 free(name);
88acd4d3 197 free(name2);
5eaef520 198 break;
199 default:
03c05291 200 /*
201 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
202 table_name[table]);
203 */
5eaef520 204 break;
205 }
a313cad2 206}
32cfe906 207
208
03c05291 209void incremental_clear_before(void)
32cfe906 210{
5eaef520 211 beforec = 0;
32cfe906 212}
213
32cfe906 214
03c05291 215/* add an element to the incremental queue for the changed row */
32cfe906 216
5eaef520 217void incremental_after(enum tables table, char *qual, char **argv)
a313cad2 218{
88acd4d3 219 char *name, *name2;
5eaef520 220 EXEC SQL BEGIN DECLARE SECTION;
221 int id;
222 EXEC SQL END DECLARE SECTION;
223 struct iupdate *iu;
224
225 switch (table)
226 {
227 case USERS_TABLE:
d6759517 228 sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
229 "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
88acd4d3 230 "u.clearid, u.type, u.users_id FROM users u WHERE %s", qual);
5eaef520 231 dosql(after);
88acd4d3 232 afterc = 11;
5eaef520 233 break;
234 case MACHINE_TABLE:
88acd4d3 235 sprintf(stmt_buf, "SELECT m.name, m.vendor, m.mach_id FROM machine m "
5eaef520 236 "WHERE %s", qual);
237 dosql(after);
88acd4d3 238 afterc = 3;
5eaef520 239 break;
e688520a 240 case CLUSTERS_TABLE:
88acd4d3 241 sprintf(stmt_buf, "SELECT c.name, c.description, c.location, "
242 "c.clu_id FROM clusters c WHERE %s", qual);
5eaef520 243 dosql(after);
88acd4d3 244 afterc = 4;
5eaef520 245 break;
246 case MCMAP_TABLE:
247 strcpy(after[0], argv[0]);
248 strcpy(after[1], argv[1]);
249 afterc = 2;
250 break;
251 case SVC_TABLE:
252 strcpy(after[0], argv[0]);
253 strcpy(after[1], argv[1]);
254 strcpy(after[2], argv[2]);
255 afterc = 3;
256 break;
257 case FILESYS_TABLE:
258 sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
259 "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
88acd4d3 260 "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
261 "WHERE %s", qual);
5eaef520 262 dosql(after);
88acd4d3 263 name = xmalloc(0);
5eaef520 264 id = atoi(after[2]);
265 id_to_name(id, MACHINE_TABLE, &name);
266 strcpy(after[2], name);
267 id = atoi(after[7]);
268 id_to_name(id, USERS_TABLE, &name);
269 strcpy(after[7], name);
270 id = atoi(after[8]);
271 id_to_name(id, LIST_TABLE, &name);
272 strcpy(after[8], name);
273 free(name);
88acd4d3 274 afterc = 12;
5eaef520 275 break;
276 case QUOTA_TABLE:
277 strcpy(after[0], "?");
278 strcpy(after[1], argv[1]);
279 strcpy(after[2], "?");
280 sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
281 "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
282 qual, argv[1]);
283 dosql(&(after[3]));
284 afterc = 5;
285 break;
286 case LIST_TABLE:
287 sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
288 "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
88acd4d3 289 "l.description, l.list_id FROM list l WHERE %s", qual);
5eaef520 290 dosql(after);
88acd4d3 291 afterc = 11;
5eaef520 292 break;
293 case IMEMBERS_TABLE:
294 id = (int) argv[0];
295 sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
296 "grouplist, gid FROM list WHERE list_id = %d", id);
297 dosql(&(after[3]));
88acd4d3 298 name = xmalloc(0);
5eaef520 299 id_to_name(id, LIST_TABLE, &name);
88acd4d3 300 name2 = xmalloc(0);
5eaef520 301 strcpy(after[0], name);
302 strcpy(after[1], argv[1]);
303 id = (int) argv[2];
88acd4d3 304 afterc = 10;
5eaef520 305 if (!strcmp(after[1], "USER"))
306 {
88acd4d3 307 id_to_name(id, USERS_TABLE, &name2);
308 EXEC SQL SELECT status, users_id INTO :after[9], :after[11]
309 FROM users WHERE users_id = :id;
310 EXEC SQL SELECT list_id INTO :after[10] FROM list
311 WHERE name = :name;
312 afterc = 12;
32cfe906 313 }
5eaef520 314 else if (!strcmp(after[1], "LIST"))
88acd4d3 315 {
316 id_to_name(id, LIST_TABLE, &name2);
317 EXEC SQL SELECT list_id INTO :after[9] FROM list
318 WHERE name = :name;
319 sprintf(after[10], "%d", id);
320 afterc = 11;
321 }
5eaef520 322 else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS"))
88acd4d3 323 {
324 id_to_name(id, STRINGS_TABLE, &name2);
325 EXEC SQL SELECT list_id INTO :after[9] FROM list
326 WHERE name = :name;
327 }
328 strcpy(after[2], name2);
5eaef520 329 free(name);
88acd4d3 330 free(name2);
5eaef520 331 break;
332 case NO_TABLE:
333 afterc = 0;
334 table = beforetable;
335 break;
336 default:
03c05291 337 /*
338 com_err(whoami, 0, "requested incremental on unexpected table `%s'",
339 table_name[table]);
340 */
5eaef520 341 break;
32cfe906 342 }
5eaef520 343
e688520a 344 iu = xmalloc(sizeof(struct iupdate));
5eaef520 345 iu->table = table_name[table];
346 iu->beforec = beforec;
fc053494 347 iu->before = copy_argv(before, beforec);
5eaef520 348 iu->afterc = afterc;
fc053494 349 iu->after = copy_argv(after, afterc);
5eaef520 350 sq_save_data(incremental_sq, iu);
a313cad2 351}
32cfe906 352
03c05291 353void incremental_clear_after(void)
354{
5eaef520 355 incremental_after(NO_TABLE, NULL, NULL);
03c05291 356}
357
32cfe906 358
359/* Called when the current transaction is committed to start any queued
360 * incremental updates. This caches the update table the first time it
361 * is called.
362 */
363
364struct inc_cache {
5eaef520 365 struct inc_cache *next;
366 char *table, *service;
32cfe906 367};
368
369
03c05291 370void incremental_update(void)
32cfe906 371{
5eaef520 372 static int inited = 0;
373 static struct inc_cache *cache;
374 struct inc_cache *c;
375 EXEC SQL BEGIN DECLARE SECTION;
e688520a 376 char tab[INCREMENTAL_TABLE_NAME_SIZE], serv[INCREMENTAL_SERVICE_SIZE];
5eaef520 377 EXEC SQL END DECLARE SECTION;
772c26b3 378 struct iupdate *iu, *iu_save;
5eaef520 379
380 if (!inited)
381 {
382 inited++;
383
384 EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service
385 FROM incremental;
386 EXEC SQL OPEN inc;
387 while (1)
388 {
389 EXEC SQL FETCH inc INTO :tab, :serv;
390 if (sqlca.sqlcode)
391 break;
e688520a 392 c = xmalloc(sizeof(struct inc_cache));
5eaef520 393 c->next = cache;
e688520a 394 c->table = xstrdup(strtrim(tab));
395 c->service = xstrdup(strtrim(serv));
5eaef520 396 cache = c;
32cfe906 397 }
5eaef520 398 EXEC SQL CLOSE inc;
399 EXEC SQL COMMIT WORK;
32cfe906 400 }
401
5eaef520 402 while (sq_remove_data(incremental_sq, &iu))
403 {
404 for (c = cache; c; c = c->next)
405 {
406 if (!strcmp(c->table, iu->table))
407 {
408 iu->service = c->service;
772c26b3 409 iu_save = xmalloc(sizeof(struct iupdate));
410 iu_save->service = iu->service;
411 iu_save->table = iu->table;
412 iu_save->beforec = iu->beforec;
413 iu_save->afterc = iu->afterc;
414 iu_save->before = copy_argv(iu->before, iu->beforec);
415 iu_save->after = copy_argv(iu->after, iu->afterc);
416 sq_save_data(incremental_exec, iu_save);
32cfe906 417 }
418 }
e688520a 419 if (!c)
420 {
421 free_argv(iu->before, iu->beforec);
422 free_argv(iu->after, iu->afterc);
423 free(iu);
424 }
32cfe906 425 }
5eaef520 426 if (inc_running == 0)
427 next_incremental();
32cfe906 428}
429
f18a32ee 430/* Pro*C 2.2.4 can't cope with the sigset_t below, at least in Solaris 2.6.
431 We add DEFINE=_PROC_ to the proc invocation and then #ifndef that around
432 this function so proc will pass it through without reading it. */
32cfe906 433
f18a32ee 434#ifndef _PROC_
03c05291 435void next_incremental(void)
32cfe906 436{
5eaef520 437 struct iupdate *iu;
e688520a 438 char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[MAXPATHLEN];
5eaef520 439 int i;
440 sigset_t sigs;
441
442 if (!incremental_exec)
443 incremental_init();
444
445 if (sq_empty(incremental_exec) ||
446 (inc_running && now - inc_started < INC_TIMEOUT))
447 return;
448
449 if (inc_running)
450 com_err(whoami, 0, "incremental timeout on pid %d", inc_pid);
451
452 sq_remove_data(incremental_exec, &iu);
453 argv[1] = iu->table;
454 sprintf(cbefore, "%d", iu->beforec);
455 argv[2] = cbefore;
456 sprintf(cafter, "%d", iu->afterc);
457 argv[3] = cafter;
458 for (i = 0; i < iu->beforec; i++)
459 argv[4 + i] = iu->before[i];
460 for (i = 0; i < iu->afterc; i++)
461 argv[4 + iu->beforec + i] = iu->after[i];
462
463 sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
464 argv[0] = prog;
465 argv[4 + iu->beforec + iu->afterc] = 0;
466
467 sigemptyset(&sigs);
468 sigaddset(&sigs, SIGCHLD);
469 sigprocmask(SIG_BLOCK, &sigs, NULL);
470 inc_pid = vfork();
471 switch (inc_pid)
472 {
32cfe906 473 case 0:
5eaef520 474 execv(prog, argv);
475 _exit(1);
32cfe906 476 case -1:
5eaef520 477 com_err(whoami, 0, "Failed to start incremental update");
478 break;
32cfe906 479 default:
5eaef520 480 inc_running = 1;
481 inc_started = now;
32cfe906 482 }
5eaef520 483 sigprocmask(SIG_UNBLOCK, &sigs, NULL);
32cfe906 484
5eaef520 485 free_argv(iu->before, iu->beforec);
486 free_argv(iu->after, iu->afterc);
487 free(iu);
32cfe906 488}
f18a32ee 489#endif
32cfe906 490
491/* Called when the current transaction is aborted to throw away any queued
492 * incremental updates
493 */
494
03c05291 495void incremental_flush(void)
32cfe906 496{
5eaef520 497 struct iupdate *iu;
32cfe906 498
5eaef520 499 while (sq_get_data(incremental_sq, &iu))
500 {
501 free_argv(iu->before, iu->beforec);
502 free_argv(iu->after, iu->afterc);
503 free(iu);
32cfe906 504 }
5eaef520 505 sq_destroy(incremental_sq);
506 incremental_sq = sq_create();
32cfe906 507}
508
509
fc053494 510char **copy_argv(char **argv, int argc)
511{
512 char **ret = xmalloc(sizeof(char *) * argc);
513 while (--argc >= 0)
514 ret[argc] = xstrdup(strtrim(argv[argc]));
515 return ret;
516}
517
5eaef520 518void free_argv(char **argv, int argc)
32cfe906 519{
5eaef520 520 while (--argc >= 0)
521 free(argv[argc]);
522 free(argv);
32cfe906 523}
03c05291 524
525int table_num(char *name)
526{
527 int i;
528
5eaef520 529 for (i = num_tables - 1; i; i--)
530 {
531 if (!strcmp(table_name[i], name))
532 break;
533 }
03c05291 534
535 return i; /* 0 = "none" if no match */
536}
This page took 0.182175 seconds and 5 git commands to generate.