]> andersk Git - moira.git/blame - dcm/dcm.pc
punt mrgdb
[moira.git] / dcm / dcm.pc
CommitLineData
7ac48069 1/* $Id$
2a2a3914 2 *
7ac48069 3 * The Data Control Manager for Moira.
2a2a3914 4 *
7ac48069 5 * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology.
6 * For copying and distribution information, see the file
7 * <mit-copyright.h>.
2a2a3914 8 */
9
7ac48069 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>
2a2a3914 18
85330553 19#include <errno.h>
2a2a3914 20#include <signal.h>
21#include <stdio.h>
7ac48069 22#include <stdlib.h>
2a2a3914 23#include <string.h>
2a2a3914 24#include <unistd.h>
2a2a3914 25
2a2a3914 26EXEC SQL INCLUDE sqlca;
7ac48069 27void sqlglm(char *, unsigned int *, unsigned int *);
28
29RCSID("$Header$");
30
31int generate_service(char *name, int force);
32void do_hosts(char *service);
33int dcm_send_file(char *service, char *host, char *target);
34int dcm_execute(char *service, char *host, char *script);
35void dbmserr(void);
36
2a2a3914 37EXEC SQL WHENEVER SQLERROR DO dbmserr();
38
39#define SQL_NO_MATCH 1403
5eaef520 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))
2a2a3914 41
5eaef520 42char whobuf[256], *whoami = whobuf, *db = "moira";
2a2a3914 43
5eaef520 44int main(int argc, char **argv)
2a2a3914 45{
5eaef520 46 int i;
47 EXEC SQL BEGIN DECLARE SECTION;
48 char buf[16], *name;
49 int enable;
50 EXEC SQL END DECLARE SECTION;
51 struct save_queue *sq;
52 int status;
53
54 if (strchr(argv[0], '/'))
55 strcpy(whoami, strrchr(argv[0], '/') + 1);
56 else strcpy(whoami, argv[0]);
57 umask(7);
58
59 setvbuf(stderr, NULL, _IOLBF, BUFSIZ);
60 setvbuf(stdout, NULL, _IOLBF, BUFSIZ);
61
62 initialize_sms_error_table();
63 initialize_krb_error_table();
64
65 /* if services were specified on the command line, do just those ones */
66 if (argc > 1)
67 {
68 for (i = 1; i < argc; i++)
69 {
70 if (generate_service(argv[i], 1))
71 do_hosts(argv[i]);
2a2a3914 72 }
5eaef520 73 exit(0);
2a2a3914 74 }
75
5eaef520 76 /* if DCM is not enabled, exit after logging */
77 if (!access(NODCMFILE, F_OK))
78 {
79 printf("/etc/nodcm exists -- exiting\n");
80 exit(1);
2a2a3914 81 }
5eaef520 82
83 EXEC SQL CONNECT :db IDENTIFIED BY :db;
84
85 EXEC SQL SELECT value INTO :enable FROM numvalues WHERE name = 'dcm_enable';
86 if (enable == 0)
87 {
88 printf("dcm_enable not set -- exiting\n");
89 exit(1);
2a2a3914 90 }
5eaef520 91
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;
96 sq = sq_create();
97 while (1)
98 {
99 EXEC SQL FETCH csr_svc INTO :buf;
100 if (sqlca.sqlcode)
101 break;
102
103 sq_save_data(sq, strdup(strtrim(buf)));
2a2a3914 104 }
5eaef520 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;
109
110 /* Now run through list */
111 while (sq_get_data(sq, &name))
112 {
113 if (generate_service(name, 0))
114 {
115 switch (fork())
116 {
117 case -1:
118 fprintf(stderr, "dcm: could not fork for service %s -- exiting",
119 name);
120 exit(1);
121 case 0:
122 sprintf(strchr(whoami, '\0'), " (%s)", name);
123 do_hosts(name);
124 com_err(whoami, 0, "exiting");
125 exit(0);
126 default:
127 break;
2a2a3914 128 }
129 }
130 }
5eaef520 131
132 /* wait for children */
133 while (waitpid(0, &status, 0) > 0)
134 ;
135 com_err(whoami, 0, "exiting");
7ac48069 136 exit(0);
2a2a3914 137}
138
139int generate_service(char *name, int force)
140{
5eaef520 141 EXEC SQL BEGIN DECLARE SECTION;
142 int interval, dfcheck, status;
143 time_t now;
7ac48069 144 const char *errmsg;
5eaef520 145 EXEC SQL END DECLARE SECTION;
146 char dfgen_prog[64], dfgen_cmd[128];
147 struct sigaction action, prevaction;
148 int waits;
149
150 EXEC SQL CONNECT :db IDENTIFIED BY :db;
151
152 EXEC SQL SELECT update_int, dfcheck INTO :interval, :dfcheck
153 FROM servers WHERE name = UPPER(:name);
154 if (sqlca.sqlcode == SQL_NO_MATCH)
155 {
156 com_err(whoami, 0, "No such service `%s'", name);
157 EXEC SQL COMMIT RELEASE;
158 return 0;
2a2a3914 159 }
5eaef520 160
161 time(&now);
162
163 if ((interval * 60 + dfcheck < now) || force)
164 {
165 sprintf(dfgen_prog, "%s/%s.gen", BIN_DIR, name);
166 if (access(dfgen_prog, F_OK) != 0)
167 {
168 com_err(whoami, 0, "prog %s doesn't exist", dfgen_prog);
169 EXEC SQL COMMIT RELEASE;
170 return 0;
2a2a3914 171 }
5eaef520 172 sprintf(dfgen_cmd, "exec %s %s/%s.out", dfgen_prog, DCM_DIR, name);
173 com_err(whoami, 0, "running %s", dfgen_prog);
174
175 EXEC SQL UPDATE servers SET inprogress = 1
176 WHERE name = UPPER(:name);
177
178 action.sa_flags = 0;
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))
185 {
186 status = MR_COREDUMP;
187 com_err(whoami, status, " %s exited on signal %d",
188 dfgen_prog, WTERMSIG(waits));
189 }
190 else if (WEXITSTATUS(waits))
191 {
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);
196 }
197 else
198 status = MR_SUCCESS;
199
200 if (status == MR_SUCCESS)
201 {
202 EXEC SQL UPDATE servers SET dfgen = :now, dfcheck = :now,
203 inprogress = 0 WHERE name = UPPER(:name);
204 EXEC SQL COMMIT RELEASE;
205 return 1;
206 }
207 else if (status == MR_NO_CHANGE)
208 {
209 EXEC SQL UPDATE servers SET dfcheck = :now, inprogress = 0
210 WHERE name = UPPER(:name);
211 }
212 else if (SOFT_FAIL(status))
213 {
214 errmsg = error_message(status);
215 EXEC SQL UPDATE servers SET errmsg = :errmsg, inprogress = 0
216 WHERE name = UPPER(:name);
217 }
218 else /* HARD_FAIL(status) */
219 {
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",
224 name, errmsg);
2a2a3914 225 }
226 }
5eaef520 227 EXEC SQL COMMIT RELEASE;
228 return 0;
2a2a3914 229}
230
231void do_hosts(char *service)
232{
5eaef520 233 EXEC SQL BEGIN DECLARE SECTION;
7ac48069 234 char type[16], host[73], target[64], script[128];
235 const char *errmsg;
236 int status = 0, dfgen, replicated;
5eaef520 237 time_t now;
238 EXEC SQL END DECLARE SECTION;
239
240 time(&now);
85330553 241 mr_init();
5eaef520 242
243 EXEC SQL CONNECT :db IDENTIFIED BY :db;
244
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);
249
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;
257
258 while (1)
259 {
260 EXEC SQL FETCH csr_hst1 INTO :host;
261 if (sqlca.sqlcode == SQL_NO_MATCH)
262 break;
263
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));
268 if (status)
269 {
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))
274 {
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);
2a2a3914 279 }
5eaef520 280
281 if (replicated)
282 break;
2a2a3914 283 }
284 }
5eaef520 285 EXEC SQL CLOSE csr_hst1;
286
287 if (status == MR_SUCCESS || !replicated)
288 {
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;
295
296 while (1)
297 {
298 EXEC SQL FETCH csr_hst2 INTO :host;
299 if (sqlca.sqlcode == SQL_NO_MATCH)
300 break;
301
302 com_err(whoami, 0, "executing instructions on %s", strtrim(host));
303 status = dcm_execute(service, host, strtrim(script));
304 if (status)
305 {
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))
310 {
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);
2a2a3914 315 }
5eaef520 316
317 if (replicated)
318 {
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);
323 break;
2a2a3914 324 }
5eaef520 325 }
326 else
327 {
328 EXEC SQL UPDATE serverhosts SET inprogress = 0, lts = :now
329 WHERE CURRENT OF csr_hst2;
2a2a3914 330 }
331 }
5eaef520 332 EXEC SQL CLOSE csr_hst2;
2a2a3914 333 }
334
5eaef520 335 if (status && replicated)
336 {
337 EXEC SQL UPDATE servers SET harderror = :status, errmsg = :errmsg
338 WHERE name = UPPER(:service);
2a2a3914 339 }
340
5eaef520 341 EXEC SQL COMMIT RELEASE;
2a2a3914 342}
343
344int dcm_send_file(char *service, char *host, char *target)
345{
85330553 346 char data[MAXPATHLEN];
347 int code, conn;
5eaef520 348
85330553 349 conn = mr_connect_internal(host, "moira_update");
350 if (!conn)
5eaef520 351 {
85330553 352 com_err(whoami, errno, "can't connect to %s", host);
5eaef520 353 return MR_CANT_CONNECT;
2a2a3914 354 }
355
85330553 356 code = send_auth(conn, host);
5eaef520 357 if (code)
358 {
359 com_err(whoami, code, "authenticating to %s", host);
360 goto done;
2a2a3914 361 }
362
5eaef520 363 sprintf(data, "%s/%s.out", DCM_DIR, service);
85330553 364 code = send_file(conn, data, target, 0);
5eaef520 365 if (code)
366 com_err(whoami, code, "sending data to %s", host);
2a2a3914 367
368done:
85330553 369 send_quit(conn);
370 close(conn);
5eaef520 371 return code;
2a2a3914 372}
373
374int dcm_execute(char *service, char *host, char *script)
375{
85330553 376 char inst[MAXPATHLEN];
377 int code, conn;
5eaef520 378
85330553 379 conn = mr_connect_internal(host, "moira_update");
380 if (!conn)
5eaef520 381 {
85330553 382 com_err(whoami, errno, "can't connect to %s", host);
5eaef520 383 return MR_CANT_CONNECT;
2a2a3914 384 }
385
85330553 386 code = send_auth(conn, host);
5eaef520 387 if (code)
388 {
389 com_err(whoami, code, "authenticating to %s", host);
390 goto done;
2a2a3914 391 }
392
5eaef520 393 sprintf(inst, "/tmp/moira-update.XXXXXX");
394 mktemp(inst);
85330553 395 code = send_file(conn, script, inst, 0);
5eaef520 396 if (code)
397 {
398 com_err(whoami, code, "sending instructions to %s", host);
399 goto done;
2a2a3914 400 }
401
85330553 402 code = execute(conn, inst);
5eaef520 403 if (code)
404 com_err(whoami, code, "executing instructions on %s", host);
2a2a3914 405
406done:
85330553 407 send_quit(conn);
408 close(conn);
5eaef520 409 return code;
410}
2a2a3914 411
412void dbmserr(void)
413{
5eaef520 414 EXEC SQL BEGIN DECLARE SECTION;
415 char err_msg[256];
416 EXEC SQL END DECLARE SECTION;
417 int bufsize = 256, msglength = 0;
418
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");
423 exit(1);
2a2a3914 424}
This page took 0.125614 seconds and 5 git commands to generate.