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