]> andersk Git - moira.git/blob - dcm/dcm.pc
second code style cleanup: void/void * usage, proper #includes. try to
[moira.git] / dcm / dcm.pc
1 /* $Id$
2  *
3  * The Data Control Manager for Moira.
4  *
5  * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology.
6  * For copying and distribution information, see the file
7  * <mit-copyright.h>.
8  */
9
10 #include <mit-copyright.h>
11 #include <moira.h>
12 #include <moira_site.h>
13 #include "update.h"
14
15 #include <sys/param.h>
16 #include <sys/stat.h>
17 #include <sys/wait.h>
18
19 #include <signal.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #include <gdb.h>
26
27 EXEC SQL INCLUDE sqlca;
28 void sqlglm(char *, unsigned int *, unsigned int *);
29
30 RCSID("$Header$");
31
32 int generate_service(char *name, int force);
33 void do_hosts(char *service);
34 int dcm_send_file(char *service, char *host, char *target);
35 int dcm_execute(char *service, char *host, char *script);
36 void dbmserr(void);
37
38 EXEC SQL WHENEVER SQLERROR DO dbmserr();
39
40 #define SQL_NO_MATCH 1403
41 #define SOFT_FAIL(x) (((x) == MR_NO_MEM) || ((x) == MR_CANT_CONNECT) || ((x) == MR_CCONFIG) || ((x) == MR_DEADLOCK) || ((x) == MR_BUSY) || ((x) == MR_ABORT))
42
43 char whobuf[256], *whoami = whobuf, *db = "moira";
44 extern CONNECTION conn;
45
46 int main(int argc, char **argv)
47 {
48   int i;
49   EXEC SQL BEGIN DECLARE SECTION;
50   char buf[16], *name;
51   int enable;
52   EXEC SQL END DECLARE SECTION;
53   struct save_queue *sq;
54   int status;
55
56   if (strchr(argv[0], '/'))
57     strcpy(whoami, strrchr(argv[0], '/') + 1);
58   else strcpy(whoami, argv[0]);
59   umask(7);
60
61   setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
62   setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
63
64   initialize_sms_error_table();
65   initialize_krb_error_table();
66
67   /* if services were specified on the command line, do just those ones */
68   if (argc > 1)
69     {
70       for (i = 1; i < argc; i++)
71         {
72           if (generate_service(argv[i], 1))
73             do_hosts(argv[i]);
74         }
75       exit(0);
76     }
77
78   /* if DCM is not enabled, exit after logging */
79   if (!access(NODCMFILE, F_OK))
80     {
81       printf("/etc/nodcm exists -- exiting\n");
82       exit(1);
83     }
84
85   EXEC SQL CONNECT :db IDENTIFIED BY :db;
86
87   EXEC SQL SELECT value INTO :enable FROM numvalues WHERE name = 'dcm_enable';
88   if (enable == 0)
89     {
90       printf("dcm_enable not set -- exiting\n");
91       exit(1);
92     }
93
94   /* fetch list of services */
95   EXEC SQL DECLARE csr_svc CURSOR FOR SELECT LOWER(name) FROM servers
96     WHERE enable = 1 AND harderror = 0 AND update_int > 0;
97   EXEC SQL OPEN csr_svc;
98   sq = sq_create();
99   while (1)
100     {
101       EXEC SQL FETCH csr_svc INTO :buf;
102       if (sqlca.sqlcode)
103         break;
104
105       sq_save_data(sq, strdup(strtrim(buf)));
106     }
107   EXEC SQL CLOSE csr_svc;
108   /* we will repeatedly open and close the db since it seems to get
109      upset if you keep it open across a fork */
110   EXEC SQL COMMIT RELEASE;
111
112   /* Now run through list */
113   while (sq_get_data(sq, &name))
114     {
115       if (generate_service(name, 0))
116         {
117           switch (fork())
118             {
119             case -1:
120               fprintf(stderr, "dcm: could not fork for service %s -- exiting",
121                       name);
122               exit(1);
123             case 0:
124               sprintf(strchr(whoami, '\0'), " (%s)", name);
125               do_hosts(name);
126               com_err(whoami, 0, "exiting");
127               exit(0);
128             default:
129               break;
130             }
131         }
132     }
133
134   /* wait for children */
135   while (waitpid(0, &status, 0) > 0)
136     ;
137   com_err(whoami, 0, "exiting");
138   exit(0);
139 }
140
141 int generate_service(char *name, int force)
142 {
143   EXEC SQL BEGIN DECLARE SECTION;
144   int interval, dfcheck, status;
145   time_t now;
146   const char *errmsg;
147   EXEC SQL END DECLARE SECTION;
148   char dfgen_prog[64], dfgen_cmd[128];
149   struct sigaction action, prevaction;
150   int waits;
151
152   EXEC SQL CONNECT :db IDENTIFIED BY :db;
153
154   EXEC SQL SELECT update_int, dfcheck   INTO :interval, :dfcheck
155     FROM servers WHERE name = UPPER(:name);
156   if (sqlca.sqlcode == SQL_NO_MATCH)
157     {
158       com_err(whoami, 0, "No such service `%s'", name);
159       EXEC SQL COMMIT RELEASE;
160       return 0;
161     }
162
163   time(&now);
164
165   if ((interval * 60 + dfcheck < now) || force)
166     {
167       sprintf(dfgen_prog, "%s/%s.gen", BIN_DIR, name);
168       if (access(dfgen_prog, F_OK) != 0)
169         {
170           com_err(whoami, 0, "prog %s doesn't exist", dfgen_prog);
171           EXEC SQL COMMIT RELEASE;
172           return 0;
173         }
174       sprintf(dfgen_cmd, "exec %s %s/%s.out", dfgen_prog, DCM_DIR, name);
175       com_err(whoami, 0, "running %s", dfgen_prog);
176
177       EXEC SQL UPDATE servers SET inprogress = 1
178         WHERE name = UPPER(:name);
179
180       action.sa_flags = 0;
181       sigemptyset(&action.sa_mask);
182       action.sa_handler = SIG_DFL;
183       sigaction(SIGCHLD, &action, &prevaction);
184       waits = system(dfgen_cmd);
185       sigaction(SIGCHLD, &prevaction, NULL);
186       if (WIFSIGNALED(waits))
187         {
188           status = MR_COREDUMP;
189           com_err(whoami, status, " %s exited on signal %d",
190                   dfgen_prog, WTERMSIG(waits));
191         }
192       else if (WEXITSTATUS(waits))
193         {
194           /* extract the process's exit value */
195           status = WEXITSTATUS(waits) + ERROR_TABLE_BASE_sms;
196           if (status != MR_NO_CHANGE)
197             com_err(whoami, status, "in %s", dfgen_prog);
198         }
199       else
200         status = MR_SUCCESS;
201
202       if (status == MR_SUCCESS)
203         {
204           EXEC SQL UPDATE servers SET dfgen = :now, dfcheck = :now,
205             inprogress = 0 WHERE name = UPPER(:name);
206           EXEC SQL COMMIT RELEASE;
207           return 1;
208         }
209       else if (status == MR_NO_CHANGE)
210         {
211           EXEC SQL UPDATE servers SET dfcheck = :now, inprogress = 0
212             WHERE name = UPPER(:name);
213         }
214       else if (SOFT_FAIL(status))
215         {
216           errmsg = error_message(status);
217           EXEC SQL UPDATE servers SET errmsg = :errmsg, inprogress = 0
218             WHERE name = UPPER(:name);
219         }
220       else /* HARD_FAIL(status) */
221         {
222           errmsg = error_message(status);
223           EXEC SQL UPDATE servers SET dfcheck = :now, harderror = :status,
224             errmsg = :errmsg, inprogress = 0 WHERE name = UPPER(:name);
225           critical_alert("DCM", "DCM building config files for %s: %s",
226                          name, errmsg);
227         }
228     }
229   EXEC SQL COMMIT RELEASE;
230   return 0;
231 }
232
233 void do_hosts(char *service)
234 {
235   EXEC SQL BEGIN DECLARE SECTION;
236   char type[16], host[73], target[64], script[128];
237   const char *errmsg;
238   int status = 0, dfgen, replicated;
239   time_t now;
240   EXEC SQL END DECLARE SECTION;
241
242   time(&now);
243   gdb_init();
244
245   EXEC SQL CONNECT :db IDENTIFIED BY :db;
246
247   EXEC SQL SELECT dfgen, type, target_file, script
248     INTO :dfgen, :type, :target, :script
249     FROM servers WHERE name = UPPER(:service);
250   replicated = !strncmp(type, "REPLICAT", 8);
251
252   EXEC SQL DECLARE csr_hst1 CURSOR FOR
253     SELECT m.name FROM machine m, serverhosts sh
254     WHERE sh.service = UPPER(:service)
255     AND sh.enable = 1 AND sh.hosterror = 0
256     AND sh.lts < :dfgen AND sh.mach_id = m.mach_id
257     FOR UPDATE OF sh.inprogress, sh.hosterror, sh.hosterrmsg;
258   EXEC SQL OPEN csr_hst1;
259
260   while (1)
261     {
262       EXEC SQL FETCH csr_hst1 INTO :host;
263       if (sqlca.sqlcode == SQL_NO_MATCH)
264         break;
265
266       com_err(whoami, 0, "sending %s data to %s", service, strtrim(host));
267       EXEC SQL UPDATE serverhosts SET inprogress = 1
268         WHERE CURRENT OF csr_hst1;
269       status = dcm_send_file(service, host, strtrim(target));
270       if (status)
271         {
272           errmsg = error_message(status);
273           EXEC SQL UPDATE serverhosts SET hosterrmsg = :errmsg,
274             inprogress = 0 WHERE CURRENT OF csr_hst1;
275           if (!SOFT_FAIL(status))
276             {
277               EXEC SQL UPDATE serverhosts SET hosterror = :status
278                 WHERE CURRENT OF csr_hst1;
279               critical_alert("DCM", "DCM updating %s:%s: %s",
280                              service, host, errmsg);
281             }
282
283           if (replicated)
284             break;
285         }
286     }
287   EXEC SQL CLOSE csr_hst1;
288
289   if (status == MR_SUCCESS || !replicated)
290     {
291       EXEC SQL DECLARE csr_hst2 CURSOR FOR
292         SELECT m.name FROM machine m, serverhosts sh
293         WHERE sh.service = UPPER(:service) AND sh.inprogress = 1
294         AND sh.mach_id = m.mach_id
295         FOR UPDATE OF sh.hosterror, sh.hosterrmsg, sh.inprogress;
296       EXEC SQL OPEN csr_hst2;
297
298       while (1)
299         {
300           EXEC SQL FETCH csr_hst2 INTO :host;
301           if (sqlca.sqlcode == SQL_NO_MATCH)
302             break;
303
304           com_err(whoami, 0, "executing instructions on %s", strtrim(host));
305           status = dcm_execute(service, host, strtrim(script));
306           if (status)
307             {
308               errmsg = error_message(status);
309               EXEC SQL UPDATE serverhosts SET hosterrmsg = :errmsg,
310                 inprogress = 0 WHERE CURRENT OF csr_hst2;
311               if (!SOFT_FAIL(status))
312                 {
313                   EXEC SQL UPDATE serverhosts SET hosterror = :status
314                     WHERE CURRENT OF csr_hst2;
315                   critical_alert("DCM", "DCM updating %s:%s: %s",
316                                  service, host, errmsg);
317                 }
318
319               if (replicated)
320                 {
321                   /* We're giving up, so clear the inprogress flag on
322                      any hosts in this service we haven't gotten to yet */
323                   EXEC SQL UPDATE serverhosts SET inprogress = 0
324                     WHERE service = UPPER(:service);
325                   break;
326                 }
327             }
328           else
329             {
330               EXEC SQL UPDATE serverhosts SET inprogress = 0, lts = :now
331                 WHERE CURRENT OF csr_hst2;
332             }
333         }
334       EXEC SQL CLOSE csr_hst2;
335     }
336
337   if (status && replicated)
338     {
339       EXEC SQL UPDATE servers SET harderror = :status, errmsg = :errmsg
340         WHERE name = UPPER(:service);
341     }
342
343   EXEC SQL COMMIT RELEASE;
344 }
345
346 int dcm_send_file(char *service, char *host, char *target)
347 {
348   char addr[256], data[MAXPATHLEN];
349   int code;
350
351   sprintf(addr, "%s:moira_update", host);
352   conn = start_server_connection(addr, "");
353   if (!conn || (connection_status(conn) == CON_STOPPED))
354     {
355       com_err(whoami, connection_errno(conn), "can't connect to %s", addr);
356       return MR_CANT_CONNECT;
357     }
358
359   code = send_auth(host);
360   if (code)
361     {
362       com_err(whoami, code, "authenticating to %s", host);
363       goto done;
364     }
365
366   sprintf(data, "%s/%s.out", DCM_DIR, service);
367   code = send_file(data, target, 1);
368   if (code == MR_UNKNOWN_PROC)
369     code = send_file(data, target, 0);
370   if (code)
371     com_err(whoami, code, "sending data to %s", host);
372
373 done:
374   send_quit();
375   sever_connection(conn);
376   return code;
377 }
378
379 int dcm_execute(char *service, char *host, char *script)
380 {
381   char addr[256], inst[MAXPATHLEN];
382   int code;
383
384   sprintf(addr, "%s:moira_update", host);
385   conn = start_server_connection(addr, "");
386   if (!conn || (connection_status(conn) == CON_STOPPED))
387     {
388       com_err(whoami, connection_errno(conn), "can't connect to %s", addr);
389       return MR_CANT_CONNECT;
390     }
391
392   code = send_auth(host);
393   if (code)
394     {
395       com_err(whoami, code, "authenticating to %s", host);
396       goto done;
397     }
398
399   sprintf(inst, "/tmp/moira-update.XXXXXX");
400   mktemp(inst);
401   code = send_file(script, inst, 0);
402   if (code)
403     {
404       com_err(whoami, code, "sending instructions to %s", host);
405       goto done;
406     }
407
408   code = execute(inst);
409   if (code)
410     com_err(whoami, code, "executing instructions on %s", host);
411
412 done:
413   send_quit();
414   sever_connection(conn);
415   return code;
416 }
417
418 void dbmserr(void)
419 {
420   EXEC SQL BEGIN DECLARE SECTION;
421   char err_msg[256];
422   EXEC SQL END DECLARE SECTION;
423   int bufsize = 256, msglength = 0;
424
425   sqlglm(err_msg, &bufsize, &msglength);
426   err_msg[msglength] = '\0';
427   com_err(whoami, 0, "Encountered SQL error:\n%s", err_msg);
428   com_err(whoami, 0, "exiting");
429   exit(1);
430 }
This page took 0.108807 seconds and 5 git commands to generate.