3 * The Data Control Manager for Moira.
5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology.
6 * For copying and distribution information, see the file
10 #include <mit-copyright.h>
12 #include <moira_site.h>
15 #include <sys/param.h>
26 EXEC SQL INCLUDE sqlca;
27 void sqlglm(char *, unsigned int *, unsigned int *);
31 int generate_service(char *name, int force);
32 void do_hosts(char *service);
33 int dcm_send_file(char *service, char *host, char *target);
34 int dcm_execute(char *service, char *host, char *script);
37 EXEC SQL WHENEVER SQLERROR DO dbmserr();
39 #define SQL_NO_MATCH 1403
40 #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 char whobuf[256], *whoami = whobuf, *db = "moira";
44 int main(int argc, char **argv)
47 EXEC SQL BEGIN DECLARE SECTION;
50 EXEC SQL END DECLARE SECTION;
51 struct save_queue *sq;
54 if (strchr(argv[0], '/'))
55 strcpy(whoami, strrchr(argv[0], '/') + 1);
56 else strcpy(whoami, argv[0]);
59 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
60 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
62 initialize_sms_error_table();
63 initialize_krb_error_table();
65 /* if services were specified on the command line, do just those ones */
68 for (i = 1; i < argc; i++)
70 if (generate_service(argv[i], 1))
76 /* if DCM is not enabled, exit after logging */
77 if (!access(NODCMFILE, F_OK))
79 printf("/etc/nodcm exists -- exiting\n");
83 EXEC SQL CONNECT :db IDENTIFIED BY :db;
85 EXEC SQL SELECT value INTO :enable FROM numvalues WHERE name = 'dcm_enable';
88 printf("dcm_enable not set -- exiting\n");
92 /* fetch list of services */
93 EXEC SQL DECLARE csr_svc CURSOR FOR SELECT LOWER(name) FROM servers
94 WHERE enable = 1 AND harderror = 0 AND update_int > 0;
95 EXEC SQL OPEN csr_svc;
99 EXEC SQL FETCH csr_svc INTO :buf;
103 sq_save_data(sq, strdup(strtrim(buf)));
105 EXEC SQL CLOSE csr_svc;
106 /* we will repeatedly open and close the db since it seems to get
107 upset if you keep it open across a fork */
108 EXEC SQL COMMIT RELEASE;
110 /* Now run through list */
111 while (sq_get_data(sq, &name))
113 if (generate_service(name, 0))
118 fprintf(stderr, "dcm: could not fork for service %s -- exiting",
122 sprintf(strchr(whoami, '\0'), " (%s)", name);
124 com_err(whoami, 0, "exiting");
132 /* wait for children */
133 while (waitpid(0, &status, 0) > 0)
135 com_err(whoami, 0, "exiting");
139 int generate_service(char *name, int force)
141 EXEC SQL BEGIN DECLARE SECTION;
142 int interval, dfcheck, status;
145 EXEC SQL END DECLARE SECTION;
146 char dfgen_prog[64], dfgen_cmd[128];
147 struct sigaction action, prevaction;
150 EXEC SQL CONNECT :db IDENTIFIED BY :db;
152 EXEC SQL SELECT update_int, dfcheck INTO :interval, :dfcheck
153 FROM servers WHERE name = UPPER(:name);
154 if (sqlca.sqlcode == SQL_NO_MATCH)
156 com_err(whoami, 0, "No such service `%s'", name);
157 EXEC SQL COMMIT RELEASE;
163 if ((interval * 60 + dfcheck < now) || force)
165 sprintf(dfgen_prog, "%s/%s.gen", BIN_DIR, name);
166 if (access(dfgen_prog, F_OK) != 0)
168 com_err(whoami, 0, "prog %s doesn't exist", dfgen_prog);
169 EXEC SQL COMMIT RELEASE;
172 sprintf(dfgen_cmd, "exec %s %s/%s.out", dfgen_prog, DCM_DIR, name);
173 com_err(whoami, 0, "running %s", dfgen_prog);
175 EXEC SQL UPDATE servers SET inprogress = 1
176 WHERE name = UPPER(:name);
179 sigemptyset(&action.sa_mask);
180 action.sa_handler = SIG_DFL;
181 sigaction(SIGCHLD, &action, &prevaction);
182 waits = system(dfgen_cmd);
183 sigaction(SIGCHLD, &prevaction, NULL);
184 if (WIFSIGNALED(waits))
186 status = MR_COREDUMP;
187 com_err(whoami, status, " %s exited on signal %d",
188 dfgen_prog, WTERMSIG(waits));
190 else if (WEXITSTATUS(waits))
192 /* extract the process's exit value */
193 status = WEXITSTATUS(waits) + ERROR_TABLE_BASE_sms;
194 if (status != MR_NO_CHANGE)
195 com_err(whoami, status, "in %s", dfgen_prog);
200 if (status == MR_SUCCESS)
202 EXEC SQL UPDATE servers SET dfgen = :now, dfcheck = :now,
203 inprogress = 0 WHERE name = UPPER(:name);
204 EXEC SQL COMMIT RELEASE;
207 else if (status == MR_NO_CHANGE)
209 EXEC SQL UPDATE servers SET dfcheck = :now, inprogress = 0
210 WHERE name = UPPER(:name);
212 else if (SOFT_FAIL(status))
214 errmsg = error_message(status);
215 EXEC SQL UPDATE servers SET errmsg = :errmsg, inprogress = 0
216 WHERE name = UPPER(:name);
218 else /* HARD_FAIL(status) */
220 errmsg = error_message(status);
221 EXEC SQL UPDATE servers SET dfcheck = :now, harderror = :status,
222 errmsg = :errmsg, inprogress = 0 WHERE name = UPPER(:name);
223 critical_alert("DCM", "DCM building config files for %s: %s",
227 EXEC SQL COMMIT RELEASE;
231 void do_hosts(char *service)
233 EXEC SQL BEGIN DECLARE SECTION;
234 char type[16], host[73], target[64], script[128];
236 int status = 0, dfgen, replicated;
238 EXEC SQL END DECLARE SECTION;
243 EXEC SQL CONNECT :db IDENTIFIED BY :db;
245 EXEC SQL SELECT dfgen, type, target_file, script
246 INTO :dfgen, :type, :target, :script
247 FROM servers WHERE name = UPPER(:service);
248 replicated = !strncmp(type, "REPLICAT", 8);
250 EXEC SQL DECLARE csr_hst1 CURSOR FOR
251 SELECT m.name FROM machine m, serverhosts sh
252 WHERE sh.service = UPPER(:service)
253 AND sh.enable = 1 AND sh.hosterror = 0
254 AND sh.lts < :dfgen AND sh.mach_id = m.mach_id
255 FOR UPDATE OF sh.inprogress, sh.hosterror, sh.hosterrmsg;
256 EXEC SQL OPEN csr_hst1;
260 EXEC SQL FETCH csr_hst1 INTO :host;
261 if (sqlca.sqlcode == SQL_NO_MATCH)
264 com_err(whoami, 0, "sending %s data to %s", service, strtrim(host));
265 EXEC SQL UPDATE serverhosts SET inprogress = 1
266 WHERE CURRENT OF csr_hst1;
267 status = dcm_send_file(service, host, strtrim(target));
270 errmsg = error_message(status);
271 EXEC SQL UPDATE serverhosts SET hosterrmsg = :errmsg,
272 inprogress = 0 WHERE CURRENT OF csr_hst1;
273 if (!SOFT_FAIL(status))
275 EXEC SQL UPDATE serverhosts SET hosterror = :status
276 WHERE CURRENT OF csr_hst1;
277 critical_alert("DCM", "DCM updating %s:%s: %s",
278 service, host, errmsg);
285 EXEC SQL CLOSE csr_hst1;
287 if (status == MR_SUCCESS || !replicated)
289 EXEC SQL DECLARE csr_hst2 CURSOR FOR
290 SELECT m.name FROM machine m, serverhosts sh
291 WHERE sh.service = UPPER(:service) AND sh.inprogress = 1
292 AND sh.mach_id = m.mach_id
293 FOR UPDATE OF sh.hosterror, sh.hosterrmsg, sh.inprogress;
294 EXEC SQL OPEN csr_hst2;
298 EXEC SQL FETCH csr_hst2 INTO :host;
299 if (sqlca.sqlcode == SQL_NO_MATCH)
302 com_err(whoami, 0, "executing instructions on %s", strtrim(host));
303 status = dcm_execute(service, host, strtrim(script));
306 errmsg = error_message(status);
307 EXEC SQL UPDATE serverhosts SET hosterrmsg = :errmsg,
308 inprogress = 0 WHERE CURRENT OF csr_hst2;
309 if (!SOFT_FAIL(status))
311 EXEC SQL UPDATE serverhosts SET hosterror = :status
312 WHERE CURRENT OF csr_hst2;
313 critical_alert("DCM", "DCM updating %s:%s: %s",
314 service, host, errmsg);
319 /* We're giving up, so clear the inprogress flag on
320 any hosts in this service we haven't gotten to yet */
321 EXEC SQL UPDATE serverhosts SET inprogress = 0
322 WHERE service = UPPER(:service);
328 EXEC SQL UPDATE serverhosts SET inprogress = 0, lts = :now
329 WHERE CURRENT OF csr_hst2;
332 EXEC SQL CLOSE csr_hst2;
335 if (status && replicated)
337 EXEC SQL UPDATE servers SET harderror = :status, errmsg = :errmsg
338 WHERE name = UPPER(:service);
341 EXEC SQL COMMIT RELEASE;
344 int dcm_send_file(char *service, char *host, char *target)
346 char data[MAXPATHLEN];
349 conn = mr_connect_internal(host, "moira_update");
352 com_err(whoami, errno, "can't connect to %s", host);
353 return MR_CANT_CONNECT;
356 code = send_auth(conn, host);
359 com_err(whoami, code, "authenticating to %s", host);
363 sprintf(data, "%s/%s.out", DCM_DIR, service);
364 code = send_file(conn, data, target, 0);
366 com_err(whoami, code, "sending data to %s", host);
374 int dcm_execute(char *service, char *host, char *script)
376 char inst[MAXPATHLEN];
379 conn = mr_connect_internal(host, "moira_update");
382 com_err(whoami, errno, "can't connect to %s", host);
383 return MR_CANT_CONNECT;
386 code = send_auth(conn, host);
389 com_err(whoami, code, "authenticating to %s", host);
393 sprintf(inst, "/tmp/moira-update.XXXXXX");
395 code = send_file(conn, script, inst, 0);
398 com_err(whoami, code, "sending instructions to %s", host);
402 code = execute(conn, inst);
404 com_err(whoami, code, "executing instructions on %s", host);
414 EXEC SQL BEGIN DECLARE SECTION;
416 EXEC SQL END DECLARE SECTION;
417 int bufsize = 256, msglength = 0;
419 sqlglm(err_msg, &bufsize, &msglength);
420 err_msg[msglength] = '\0';
421 com_err(whoami, 0, "Encountered SQL error:\n%s", err_msg);
422 com_err(whoami, 0, "exiting");