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