source: trunk/third/moira/server/increment.pc @ 26024

Revision 26024, 19.5 KB checked in by jdreed, 11 years ago (diff)
In moira: * Snapshot moira at r4113 to pick up new firewall-related changes
Line 
1/* $Id: increment.pc 4110 2013-05-09 15:43:17Z zacheiss $
2 *
3 * Deal with incremental updates
4 *
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>.
8 */
9
10#include <mit-copyright.h>
11#include "mr_server.h"
12#include "query.h"
13#include "qrtn.h"
14
15#include <signal.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
19#include <unistd.h>
20#include <sys/param.h>
21
22EXEC SQL INCLUDE sqlca;
23
24RCSID("$HeadURL: svn+ssh://svn.mit.edu/moira/trunk/moira/server/increment.pc $ $Id: increment.pc 4110 2013-05-09 15:43:17Z zacheiss $");
25
26extern char *whoami;
27extern char *table_name[];
28extern int num_tables;
29
30int inc_pid = 0;
31int inc_running = 0;
32time_t inc_started;
33
34#define MAXARGC 20
35
36EXEC SQL WHENEVER SQLERROR DO dbmserr();
37
38EXEC SQL BEGIN DECLARE SECTION;
39/* structures to save before args */
40static char *before[MAXARGC];
41static int beforec;
42static enum tables beforetable;
43
44/* structures to save after args */
45static char *after[MAXARGC];
46static int afterc;
47EXEC SQL END DECLARE SECTION;
48
49/* structures to save entire sets of incremental changes */
50struct save_queue *incremental_sq = NULL;
51struct save_queue *incremental_exec = NULL;
52struct iupdate {
53  char *table;
54  int beforec;
55  char **before;
56  int afterc;
57  char **after;
58  char *service;
59};
60
61void next_incremental(void);
62char **copy_argv(char **argv, int argc);
63void free_argv(char **argv, int argc);
64int table_num(char *table);
65
66void incremental_init(void)
67{
68  int i;
69
70  if (!incremental_sq)
71    incremental_sq = sq_create();
72  if (!incremental_exec)
73    incremental_exec = sq_create();
74
75  for (i = 0; i < MAXARGC; i++)
76    {
77      before[i] = xmalloc(MAX_FIELD_WIDTH);
78      after[i] = xmalloc(MAX_FIELD_WIDTH);
79    }
80}
81
82
83/* record the state of a table row before it is changed */
84
85void incremental_before(enum tables table, char *qual, char **argv)
86{
87  EXEC SQL BEGIN DECLARE SECTION;
88  int id;
89  EXEC SQL END DECLARE SECTION;
90
91  char *name, *name2;
92
93  beforetable = table;
94
95  switch (table)
96    {
97    case USERS_TABLE:
98      sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
99              "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
100              "u.clearid, u.type, u.users_id, u.winhomedir, u.winprofiledir, "
101              "u.potype FROM users u WHERE %s", qual);
102      dosql(before);
103      beforec = 14;
104      break;
105    case MACHINE_TABLE:
106      sprintf(stmt_buf, "SELECT m.name, m.mach_id, m.vendor, m.model, m.os, m.location, "
107              "m.contact, m.billing_contact, m.account_number, m.status, m.address, "
108              "m.owner_type, m.owner_id, m.acomment, m.ocomment, m.snet_id, m.use, "
109              "TO_CHAR(m.inuse, 'DD-mon-YYYY'), m.ttl FROM machine m "
110              "WHERE %s", qual);
111      dosql(before);
112      beforec = 19;
113      name = xmalloc(0);
114      id = atoi(before[12]);
115      if (!strncmp(before[11], "USER", 4))
116        {
117          id_to_name(id, USERS_TABLE, &name);
118          strcpy(before[12], name);
119        }
120      else if (!strncmp(before[11], "LIST", 4))
121        {
122          id_to_name(id, LIST_TABLE, &name);
123          strcpy(before[12], name);
124        }
125      else if (!strncmp(before[11], "KERBEROS", 8))
126        {
127          id_to_name(id, STRINGS_TABLE, &name);
128          strcpy(before[12], name);
129        }
130      id = atoi(before[13]);
131      id_to_name(id, STRINGS_TABLE, &name);
132      strcpy(before[13], name);
133      id = atoi(before[14]);
134      id_to_name(id, STRINGS_TABLE, &name);
135      strcpy(before[14], name);
136      id = atoi(before[15]);
137      id_to_name(id, SUBNET_TABLE, &name);
138      strcpy(before[15], name);
139      break;
140    case HOSTALIAS_TABLE:
141      strcpy(before[0], argv[0]);
142      strcpy(before[1], argv[1]);
143      name_to_id(before[1], MACHINE_TABLE, &id);
144      sprintf(before[2], "%d", id);
145      beforec = 3;
146      break;
147    case HWADDRMAP_TABLE:
148      strcpy(before[0], argv[0]);
149      strcpy(before[1], argv[1]);
150      name_to_id(before[1], MACHINE_TABLE, &id);
151      sprintf(before[2], "%d", id);
152      beforec = 3;
153      break;
154    case CLUSTERS_TABLE:
155      sprintf(stmt_buf, "SELECT c.name, c.description, c.location, "
156              "c.clu_id FROM clusters c WHERE %s", qual);
157      dosql(before);
158      beforec = 4;
159      break;
160    case CONTAINERS_TABLE:
161      sprintf(stmt_buf, "SELECT c.name, c.description, c.location, c.contact, "
162              "c.acl_type, c.acl_id, c.cnt_id, c.list_id FROM containers c "
163              "WHERE %s", qual);
164      dosql(before);
165      beforec = 8;
166      name = xmalloc(0);
167      id = atoi(before[5]);
168      if (!strncmp(before[4], "USER", 4))
169        {
170          id_to_name(id, USERS_TABLE, &name);
171          strcpy(before[5], name);
172        }
173      else if (!strncmp(before[4], "LIST", 4))
174        {
175          id_to_name(id, LIST_TABLE, &name);
176          strcpy(before[5], name);
177        }
178      else if (!strncmp(before[4], "KERBEROS", 8))
179        {
180          id_to_name(id, STRINGS_TABLE, &name);
181          strcpy(before[5], name);
182        }
183      id = atoi(before[7]);
184      id_to_name(id, LIST_TABLE, &name);
185      strcpy(before[7], name);
186      break;
187    case MCMAP_TABLE:
188      strcpy(before[0], argv[0]);
189      strcpy(before[1], argv[1]);
190      beforec = 2;
191      break;
192    case MCNTMAP_TABLE:
193      strcpy(before[0], argv[0]);
194      strcpy(before[1], argv[1]);
195      name_to_id(before[0], MACHINE_TABLE, &id);
196      sprintf(before[2], "%d", id);
197      name_to_id(before[1], CONTAINERS_TABLE, &id);
198      sprintf(before[3], "%d", id);
199      name = xmalloc(0);
200      EXEC SQL SELECT list_id INTO :before[4] FROM containers
201        WHERE cnt_id = :id;
202      id = atoi(before[4]);
203      id_to_name(id, LIST_TABLE, &name);
204      strcpy(before[4], name);
205      beforec = 5;
206      break;
207    case SVC_TABLE:
208      strcpy(before[0], argv[0]);
209      strcpy(before[1], argv[1]);
210      strcpy(before[2], argv[2]);
211      beforec = 3;
212      break;
213    case FILESYS_TABLE:
214      sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
215              "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
216              "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
217              "WHERE %s", qual);
218      dosql(before);
219      name = xmalloc(0);
220      id = atoi(before[2]);
221      id_to_name(id, MACHINE_TABLE, &name);
222      strcpy(before[2], name);
223      id = atoi(before[7]);
224      id_to_name(id, USERS_TABLE, &name);
225      strcpy(before[7], name);
226      id = atoi(before[8]);
227      id_to_name(id, LIST_TABLE, &name);
228      strcpy(before[8], name);
229      free(name);
230      beforec = 12;
231      break;
232    case QUOTA_TABLE:
233      strcpy(before[0], "?");
234      strcpy(before[1], argv[1]);
235      strcpy(before[2], "?");
236      sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
237              "WHERE %s AND fs.filsys_id = q.filsys_id", qual);
238      dosql(&(before[3]));
239      strcpy(before[2], argv[1]);
240      beforec = 5;
241      break;
242    case LIST_TABLE:
243      sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
244              "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
245              "l.description, l.list_id, l.nfsgroup FROM list l WHERE %s", qual);
246      dosql(before);
247      beforec = 12;
248      break;
249    case IMEMBERS_TABLE:
250      id = (int)(long)argv[0];
251      sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
252              "grouplist, gid, nfsgroup FROM list WHERE list_id = %d", id);
253      dosql(&(before[3]));
254      name = xmalloc(0);
255      id_to_name(id, LIST_TABLE, &name);
256      name2 = xmalloc(0);
257      strcpy(before[0], name);
258      strcpy(before[1], argv[1]);
259      id = (int)(long)argv[2];
260      beforec = 11;
261      if (!strcmp(before[1], "USER"))
262        {
263          id_to_name(id, USERS_TABLE, &name2);
264          EXEC SQL SELECT status, users_id INTO :before[10], :before[12]
265            FROM users WHERE users_id = :id;
266          EXEC SQL SELECT list_id INTO :before[11] FROM list
267            WHERE name = :name;
268          beforec = 13;
269      }
270      else if (!strcmp(before[1], "LIST"))
271        {
272          id_to_name(id, LIST_TABLE, &name2);
273          EXEC SQL SELECT list_id INTO :before[10] FROM list
274            WHERE name = :name;
275          sprintf(before[11], "%d", id);
276          beforec = 12;
277        }
278      else if (!strcmp(before[1], "STRING") || !strcmp(before[1], "KERBEROS"))
279        {
280          id_to_name(id, STRINGS_TABLE, &name2);
281          EXEC SQL SELECT list_id INTO :before[10] FROM list
282            WHERE name = :name;
283        }
284      else if (!strcmp(before[1], "MACHINE"))
285        {
286          id_to_name(id, MACHINE_TABLE, &name2);
287          EXEC SQL SELECT list_id INTO :before[10] FROM list
288            WHERE name = :name;
289          sprintf(before[11], "%d", id);
290          beforec = 12;
291        }
292      strcpy(before[2], name2);
293      free(name);
294      free(name2);
295      break;
296    default:
297        /*
298        com_err(whoami, 0, "requested incremental on unexpected table `%s'",
299                table_name[table]);
300        */
301      break;
302    }
303}
304
305
306void incremental_clear_before(void)
307{
308  beforec = 0;
309}
310
311
312/* add an element to the incremental queue for the changed row */
313
314void incremental_after(enum tables table, char *qual, char **argv)
315{
316  char *name, *name2;
317  EXEC SQL BEGIN DECLARE SECTION;
318  int id;
319  EXEC SQL END DECLARE SECTION;
320  struct iupdate *iu;
321
322  switch (table)
323    {
324    case USERS_TABLE:
325      sprintf(stmt_buf, "SELECT u.login, u.unix_uid, u.shell, "
326              "u.winconsoleshell, u.last, u.first, u.middle, u.status, "
327              "u.clearid, u.type, u.users_id, u.winhomedir, u.winprofiledir, "
328              "u.potype FROM users u WHERE %s", qual);
329      dosql(after);
330      afterc = 14;
331      break;
332    case MACHINE_TABLE:
333      sprintf(stmt_buf, "SELECT m.name, m.mach_id, m.vendor, m.model, m.os, m.location, "
334              "m.contact, m.billing_contact, m.account_number, m.status, m.address, "
335              "m.owner_type, m.owner_id, m.acomment, m.ocomment, m.snet_id, m.use, "
336              "TO_CHAR(m.inuse, 'DD-mon-YYYY'), m.ttl FROM machine m "
337              "WHERE %s", qual);
338      dosql(after);
339      afterc = 19;
340      name = xmalloc(0);
341      id = atoi(after[12]);
342      if (!strncmp(after[11], "USER", 4))
343        {
344          id_to_name(id, USERS_TABLE, &name);
345          strcpy(after[12], name);
346        }
347      else if (!strncmp(after[11], "LIST", 4))
348        {
349          id_to_name(id, LIST_TABLE, &name);
350          strcpy(after[12], name);
351        }
352      else if (!strncmp(after[11], "KERBEROS", 8))
353        {
354          id_to_name(id, STRINGS_TABLE, &name);
355          strcpy(after[12], name);
356        }
357      id = atoi(after[13]);
358      id_to_name(id, STRINGS_TABLE, &name);
359      strcpy(after[13], name);
360      id = atoi(after[14]);
361      id_to_name(id, STRINGS_TABLE, &name);
362      strcpy(after[14], name);
363      id = atoi(after[15]);
364      id_to_name(id, SUBNET_TABLE, &name);
365      strcpy(after[15], name);
366      break;
367    case HOSTALIAS_TABLE:
368      strcpy(after[0], argv[0]);
369      strcpy(after[1], argv[1]);
370      name_to_id(after[1], MACHINE_TABLE, &id);
371      sprintf(after[2], "%d", id);
372      afterc = 3;
373      break;
374    case HWADDRMAP_TABLE:
375      strcpy(after[0], argv[0]);
376      strcpy(after[1], argv[1]);
377      name_to_id(after[1], MACHINE_TABLE, &id);
378      sprintf(after[2], "%d", id);
379      afterc = 3;
380      break;
381    case CLUSTERS_TABLE:
382      sprintf(stmt_buf, "SELECT c.name, c.description, c.location, "
383              "c.clu_id FROM clusters c WHERE %s", qual);
384      dosql(after);
385      afterc = 4;
386      break;
387    case CONTAINERS_TABLE:
388      sprintf(stmt_buf, "SELECT c.name, c.description, c.location, c.contact, "
389              "c.acl_type, c.acl_id, c.cnt_id, c.list_id FROM containers c "
390              "WHERE %s", qual);
391      dosql(after);
392      afterc = 8;
393      name = xmalloc(0);
394      id = atoi(after[5]);
395      if (!strncmp(after[4], "USER", 4))
396        {
397          id_to_name(id, USERS_TABLE, &name);
398          strcpy(after[5], name);
399        }
400      else if (!strncmp(after[4], "LIST", 4))
401        {
402          id_to_name(id, LIST_TABLE, &name);
403          strcpy(after[5], name);
404        }
405      else if (!strncmp(after[4], "KERBEROS", 8))
406        {
407          id_to_name(id, STRINGS_TABLE, &name);
408          strcpy(after[5], name);
409        }
410      id = atoi(after[7]);
411      id_to_name(id, LIST_TABLE, &name);
412      strcpy(after[7], name);
413      break;
414    case MCMAP_TABLE:
415      strcpy(after[0], argv[0]);
416      strcpy(after[1], argv[1]);
417      afterc = 2;
418      break;
419    case MCNTMAP_TABLE:
420      strcpy(after[0], argv[0]);
421      strcpy(after[1], argv[1]);
422      name_to_id(after[0], MACHINE_TABLE, &id);
423      sprintf(after[2], "%d", id);
424      name_to_id(after[1], CONTAINERS_TABLE, &id);
425      sprintf(after[3], "%d", id);
426      name = xmalloc(0);
427      EXEC SQL SELECT list_id INTO :after[4] FROM containers
428        WHERE cnt_id = :id;
429      id = atoi(after[4]);
430      id_to_name(id, LIST_TABLE, &name);
431      strcpy(after[4], name);
432      afterc = 5;
433      break;
434    case SVC_TABLE:
435      strcpy(after[0], argv[0]);
436      strcpy(after[1], argv[1]);
437      strcpy(after[2], argv[2]);
438      afterc = 3;
439      break;
440    case FILESYS_TABLE:
441      sprintf(stmt_buf, "SELECT fs.label, fs.type, fs.mach_id, fs.name, "
442              "fs.mount, fs.rwaccess, fs.comments, fs.owner, fs.owners, "
443              "fs.createflg, fs.lockertype, fs.filsys_id FROM filesys fs "
444              "WHERE %s", qual);
445      dosql(after);
446      name = xmalloc(0);
447      id = atoi(after[2]);
448      id_to_name(id, MACHINE_TABLE, &name);
449      strcpy(after[2], name);
450      id = atoi(after[7]);
451      id_to_name(id, USERS_TABLE, &name);
452      strcpy(after[7], name);
453      id = atoi(after[8]);
454      id_to_name(id, LIST_TABLE, &name);
455      strcpy(after[8], name);
456      free(name);
457      afterc = 12;
458      break;
459    case QUOTA_TABLE:
460      strcpy(after[0], "?");
461      strcpy(after[1], argv[1]);
462      strcpy(after[2], "?");
463      sprintf(stmt_buf, "SELECT q.quota, fs.name FROM quota q, filesys fs "
464              "WHERE %s and fs.filsys_id = q.filsys_id and q.type = '%s'",
465              qual, argv[1]);
466      dosql(&(after[3]));
467      afterc = 5;
468      break;
469    case LIST_TABLE:
470      sprintf(stmt_buf, "SELECT l.name, l.active, l.publicflg, l.hidden, "
471              "l.maillist, l.grouplist, l.gid, l.acl_type, l.acl_id, "
472              "l.description, l.list_id, l.nfsgroup FROM list l WHERE %s", qual);
473      dosql(after);
474      afterc = 12;
475      break;
476    case IMEMBERS_TABLE:
477      id = (int)(long)argv[0];
478      sprintf(stmt_buf, "SELECT active, publicflg, hidden, maillist, "
479              "grouplist, gid, nfsgroup FROM list WHERE list_id = %d", id);
480      dosql(&(after[3]));
481      name = xmalloc(0);
482      id_to_name(id, LIST_TABLE, &name);
483      name2 = xmalloc(0);
484      strcpy(after[0], name);
485      strcpy(after[1], argv[1]);
486      id = (int)(long)argv[2];
487      afterc = 11;
488      if (!strcmp(after[1], "USER"))
489        {
490          id_to_name(id, USERS_TABLE, &name2);
491          EXEC SQL SELECT status, users_id INTO :after[10], :after[12]
492            FROM users WHERE users_id = :id;
493          EXEC SQL SELECT list_id INTO :after[11] FROM list
494            WHERE name = :name;
495          afterc = 13;
496        }
497      else if (!strcmp(after[1], "LIST"))
498        {
499          id_to_name(id, LIST_TABLE, &name2);
500          EXEC SQL SELECT list_id INTO :after[10] FROM list
501            WHERE name = :name;
502          sprintf(after[11], "%d", id);
503          afterc = 12;
504        }
505      else if (!strcmp(after[1], "STRING") || !strcmp(after[1], "KERBEROS"))
506        {
507          id_to_name(id, STRINGS_TABLE, &name2);
508          EXEC SQL SELECT list_id INTO :after[10] FROM list
509            WHERE name = :name;
510        }
511      else if (!strcmp(after[1], "MACHINE"))
512        {
513          id_to_name(id, MACHINE_TABLE, &name2);
514          EXEC SQL SELECT list_id INTO :after[10] FROM list
515            WHERE name = :name;
516          sprintf(after[11], "%d", id);
517          afterc = 12;
518        }
519      strcpy(after[2], name2);
520      free(name);
521      free(name2);
522      break;
523    case NO_TABLE:
524      afterc = 0;
525      table = beforetable;
526      break;
527    default:
528        /*
529        com_err(whoami, 0, "requested incremental on unexpected table `%s'",
530                table_name[table]);
531        */
532      break;
533    }
534
535  iu = xmalloc(sizeof(struct iupdate));
536  iu->table = table_name[table];
537  iu->beforec = beforec;
538  iu->before = copy_argv(before, beforec);
539  iu->afterc = afterc;
540  iu->after = copy_argv(after, afterc);
541  sq_save_data(incremental_sq, iu);
542}
543
544void incremental_clear_after(void)
545{
546  incremental_after(NO_TABLE, NULL, NULL);
547}
548
549
550/* Called when the current transaction is committed to start any queued
551 * incremental updates.  This caches the update table the first time it
552 * is called.
553 */
554
555struct inc_cache {
556  struct inc_cache *next;
557  char *table, *service;
558};
559
560
561void incremental_update(void)
562{
563  static int inited = 0;
564  static struct inc_cache *cache;
565  struct inc_cache *c;
566  EXEC SQL BEGIN DECLARE SECTION;
567  char tab[INCREMENTAL_TABLE_NAME_SIZE], serv[INCREMENTAL_SERVICE_SIZE];
568  EXEC SQL END DECLARE SECTION;
569  struct iupdate *iu, *iu_save;
570
571  if (!inited)
572    {
573      inited++;
574
575      EXEC SQL DECLARE inc CURSOR FOR SELECT table_name, service
576        FROM incremental;
577      EXEC SQL OPEN inc;
578      while (1)
579        {
580          EXEC SQL FETCH inc INTO :tab, :serv;
581          if (sqlca.sqlcode)
582            break;
583          c = xmalloc(sizeof(struct inc_cache));
584          c->next = cache;
585          c->table = xstrdup(strtrim(tab));
586          c->service = xstrdup(strtrim(serv));
587          cache = c;
588        }
589      EXEC SQL CLOSE inc;
590      EXEC SQL COMMIT WORK;
591    }
592
593  while (sq_remove_data(incremental_sq, &iu))
594    {
595      for (c = cache; c; c = c->next)
596        {
597          if (!strcmp(c->table, iu->table))
598            {
599              iu->service = c->service;
600              iu_save = xmalloc(sizeof(struct iupdate));
601              iu_save->service = iu->service;
602              iu_save->table = iu->table;
603              iu_save->beforec = iu->beforec;
604              iu_save->afterc = iu->afterc;
605              iu_save->before = copy_argv(iu->before, iu->beforec);
606              iu_save->after = copy_argv(iu->after, iu->afterc);
607              sq_save_data(incremental_exec, iu_save);
608            }
609        }
610      if (!c)
611        {
612          free_argv(iu->before, iu->beforec);
613          free_argv(iu->after, iu->afterc);
614          free(iu);
615        }
616    }
617  if (inc_running == 0)
618    next_incremental();
619}
620
621/* Pro*C 2.2.4 can't cope with the sigset_t below, at least in Solaris 2.6.
622   We add DEFINE=_PROC_ to the proc invocation and then #ifndef that around
623   this function so proc will pass it through without reading it. */
624
625#ifndef _PROC_
626void next_incremental(void)
627{
628  struct iupdate *iu;
629  char *argv[MAXARGC * 2 + 4], cafter[3], cbefore[3], prog[MAXPATHLEN];
630  int i;
631  sigset_t sigs;
632
633  if (!incremental_exec)
634    incremental_init();
635
636  if (sq_empty(incremental_exec) ||
637      (inc_running && now - inc_started < INC_TIMEOUT))
638    return;
639
640  if (inc_running)
641    critical_alert(whoami, "moirad", "incremental timeout on pid %d", inc_pid);
642
643  sq_remove_data(incremental_exec, &iu);
644  argv[1] = iu->table;
645  sprintf(cbefore, "%d", iu->beforec);
646  argv[2] = cbefore;
647  sprintf(cafter, "%d", iu->afterc);
648  argv[3] = cafter;
649  for (i = 0; i < iu->beforec; i++)
650    argv[4 + i] = iu->before[i];
651  for (i = 0; i < iu->afterc; i++)
652    argv[4 + iu->beforec + i] = iu->after[i];
653
654  sprintf(prog, "%s/%s.incr", BIN_DIR, iu->service);
655  argv[0] = prog;
656  argv[4 + iu->beforec + iu->afterc] = 0;
657
658  sigemptyset(&sigs);
659  sigaddset(&sigs, SIGCHLD);
660  sigprocmask(SIG_BLOCK, &sigs, NULL);
661  inc_pid = vfork();
662  switch (inc_pid)
663    {
664    case 0:
665      execv(prog, argv);
666      _exit(1);
667    case -1:
668      critical_alert(whoami, "moirad", "Failed to start incremental update %s", prog);
669      break;
670    default:
671      inc_running = 1;
672      inc_started = now;
673    }
674  sigprocmask(SIG_UNBLOCK, &sigs, NULL);
675
676  free_argv(iu->before, iu->beforec);
677  free_argv(iu->after, iu->afterc);
678  free(iu);
679}
680#endif
681
682/* Called when the current transaction is aborted to throw away any queued
683 * incremental updates
684 */
685
686void incremental_flush(void)
687{
688  struct iupdate *iu;
689
690  while (sq_get_data(incremental_sq, &iu))
691    {
692      free_argv(iu->before, iu->beforec);
693      free_argv(iu->after, iu->afterc);
694      free(iu);
695    }
696  sq_destroy(incremental_sq);
697  incremental_sq = sq_create();
698}
699
700
701char **copy_argv(char **argv, int argc)
702{
703  char **ret = xmalloc(sizeof(char *) * argc);
704  while (--argc >= 0)
705    ret[argc] = xstrdup(strtrim(argv[argc]));
706  return ret;
707}
708
709void free_argv(char **argv, int argc)
710{
711  while (--argc >= 0)
712    free(argv[argc]);
713  free(argv);
714}
715
716int table_num(char *name)
717{
718  int i;
719
720  for (i = num_tables - 1; i; i--)
721    {
722      if (!strcmp(table_name[i], name))
723        break;
724    }
725
726  return i; /* 0 = "none" if no match */
727}
Note: See TracBrowser for help on using the repository browser.