2 * The Data Control Manager for MOIRA.
4 * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
5 * For copying and distribution information, see the file
14 static char rcsid_dcm_c[] = "$Header$";
22 #include <sys/param.h>
28 #include <moira_site.h>
30 EXEC SQL INCLUDE sqlca;
31 EXEC SQL WHENEVER SQLERROR DO dbmserr();
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))
36 char whobuf[256], *whoami = whobuf, *db = "moira";
37 extern CONNECTION conn;
39 int main(int argc, char **argv)
42 EXEC SQL BEGIN DECLARE SECTION;
45 EXEC SQL END DECLARE SECTION;
46 struct save_queue *sq;
49 if (strchr(argv[0], '/'))
50 strcpy(whoami, strrchr(argv[0], '/') + 1);
51 else strcpy(whoami, argv[0]);
54 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
55 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
57 initialize_sms_error_table();
58 initialize_krb_error_table();
60 /* if services were specified on the command line, do just those ones */
63 for (i = 1; i < argc; i++)
65 if (generate_service(argv[i], 1))
71 /* if DCM is not enabled, exit after logging */
72 if (!access(NODCMFILE, F_OK))
74 printf("/etc/nodcm exists -- exiting\n");
78 EXEC SQL CONNECT :db IDENTIFIED BY :db;
80 EXEC SQL SELECT value INTO :enable FROM numvalues WHERE name = 'dcm_enable';
83 printf("dcm_enable not set -- exiting\n");
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;
94 EXEC SQL FETCH csr_svc INTO :buf;
98 sq_save_data(sq, strdup(strtrim(buf)));
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;
105 /* Now run through list */
106 while (sq_get_data(sq, &name))
108 if (generate_service(name, 0))
113 fprintf(stderr, "dcm: could not fork for service %s -- exiting",
117 sprintf(strchr(whoami, '\0'), " (%s)", name);
119 com_err(whoami, 0, "exiting");
127 /* wait for children */
128 while (waitpid(0, &status, 0) > 0)
130 com_err(whoami, 0, "exiting");
133 int generate_service(char *name, int force)
135 EXEC SQL BEGIN DECLARE SECTION;
136 int interval, dfcheck, status;
139 EXEC SQL END DECLARE SECTION;
140 char dfgen_prog[64], dfgen_cmd[128];
141 struct sigaction action, prevaction;
144 EXEC SQL CONNECT :db IDENTIFIED BY :db;
146 EXEC SQL SELECT update_int, dfcheck INTO :interval, :dfcheck
147 FROM servers WHERE name = UPPER(:name);
148 if (sqlca.sqlcode == SQL_NO_MATCH)
150 com_err(whoami, 0, "No such service `%s'", name);
151 EXEC SQL COMMIT RELEASE;
157 if ((interval * 60 + dfcheck < now) || force)
159 sprintf(dfgen_prog, "%s/%s.gen", BIN_DIR, name);
160 if (access(dfgen_prog, F_OK) != 0)
162 com_err(whoami, 0, "prog %s doesn't exist", dfgen_prog);
163 EXEC SQL COMMIT RELEASE;
166 sprintf(dfgen_cmd, "exec %s %s/%s.out", dfgen_prog, DCM_DIR, name);
167 com_err(whoami, 0, "running %s", dfgen_prog);
169 EXEC SQL UPDATE servers SET inprogress = 1
170 WHERE name = UPPER(:name);
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))
180 status = MR_COREDUMP;
181 com_err(whoami, status, " %s exited on signal %d",
182 dfgen_prog, WTERMSIG(waits));
184 else if (WEXITSTATUS(waits))
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);
194 if (status == MR_SUCCESS)
196 EXEC SQL UPDATE servers SET dfgen = :now, dfcheck = :now,
197 inprogress = 0 WHERE name = UPPER(:name);
198 EXEC SQL COMMIT RELEASE;
201 else if (status == MR_NO_CHANGE)
203 EXEC SQL UPDATE servers SET dfcheck = :now, inprogress = 0
204 WHERE name = UPPER(:name);
206 else if (SOFT_FAIL(status))
208 errmsg = error_message(status);
209 EXEC SQL UPDATE servers SET errmsg = :errmsg, inprogress = 0
210 WHERE name = UPPER(:name);
212 else /* HARD_FAIL(status) */
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",
221 EXEC SQL COMMIT RELEASE;
225 void do_hosts(char *service)
227 EXEC SQL BEGIN DECLARE SECTION;
228 char type[16], host[73], target[64], script[128], *errmsg;
229 int status = 0, mid, dfgen, replicated;
231 EXEC SQL END DECLARE SECTION;
236 EXEC SQL CONNECT :db IDENTIFIED BY :db;
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);
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;
253 EXEC SQL FETCH csr_hst1 INTO :host;
254 if (sqlca.sqlcode == SQL_NO_MATCH)
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));
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))
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);
278 EXEC SQL CLOSE csr_hst1;
280 if (status == MR_SUCCESS || !replicated)
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;
291 EXEC SQL FETCH csr_hst2 INTO :host;
292 if (sqlca.sqlcode == SQL_NO_MATCH)
295 com_err(whoami, 0, "executing instructions on %s", strtrim(host));
296 status = dcm_execute(service, host, strtrim(script));
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))
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);
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);
321 EXEC SQL UPDATE serverhosts SET inprogress = 0, lts = :now
322 WHERE CURRENT OF csr_hst2;
325 EXEC SQL CLOSE csr_hst2;
328 if (status && replicated)
330 EXEC SQL UPDATE servers SET harderror = :status, errmsg = :errmsg
331 WHERE name = UPPER(:service);
334 EXEC SQL COMMIT RELEASE;
337 int dcm_send_file(char *service, char *host, char *target)
339 char addr[256], data[MAXPATHLEN];
342 sprintf(addr, "%s:moira_update", host);
343 conn = start_server_connection(addr, "");
344 if (!conn || (connection_status(conn) == CON_STOPPED))
346 com_err(whoami, connection_errno(conn), "can't connect to %s", addr);
347 return MR_CANT_CONNECT;
350 code = send_auth(host);
353 com_err(whoami, code, "authenticating to %s", host);
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);
362 com_err(whoami, code, "sending data to %s", host);
366 sever_connection(conn);
370 int dcm_execute(char *service, char *host, char *script)
372 char addr[256], inst[MAXPATHLEN];
375 sprintf(addr, "%s:moira_update", host);
376 conn = start_server_connection(addr, "");
377 if (!conn || (connection_status(conn) == CON_STOPPED))
379 com_err(whoami, connection_errno(conn), "can't connect to %s", addr);
380 return MR_CANT_CONNECT;
383 code = send_auth(host);
386 com_err(whoami, code, "authenticating to %s", host);
390 sprintf(inst, "/tmp/moira-update.XXXXXX");
392 code = send_file(script, inst, 0);
395 com_err(whoami, code, "sending instructions to %s", host);
399 code = execute(inst);
401 com_err(whoami, code, "executing instructions on %s", host);
405 sever_connection(conn);
411 EXEC SQL BEGIN DECLARE SECTION;
413 EXEC SQL END DECLARE SECTION;
414 int bufsize = 256, msglength = 0;
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");