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