-/*
- * The Data Control Manager for MOIRA.
+/* $Id$
*
- * Copyright 1987, 1988 by the Massachusetts Institute of Technology.
- * For copying and distribution information, see the file
- * "mit-copyright.h".
+ * The Data Control Manager for Moira.
*
- * $Source$
- * $Author$
- * $Header$
+ * Copyright (C) 1987-1998 by the Massachusetts Institute of Technology.
+ * For copying and distribution information, see the file
+ * <mit-copyright.h>.
*/
-#ifndef lint
-static char rcsid_dcm_c[] = "$Header$";
-#endif lint
+#include <mit-copyright.h>
+#include <moira.h>
+#include <moira_site.h>
+#include <moira_schema.h>
+#include "update.h"
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+
+#include <errno.h>
#include <signal.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
-#include <time.h>
#include <unistd.h>
-#include <sys/param.h>
-#include <sys/wait.h>
-
-#include <com_err.h>
-#include <gdb.h>
-#include <moira.h>
-#include <moira_site.h>
EXEC SQL INCLUDE sqlca;
-EXEC SQL WHENEVER SQLERROR DO dbmserr();
+void sqlglm(char *, unsigned int *, unsigned int *);
+
+RCSID("$Header$");
+
+int generate_service(char *name, int force);
+void do_hosts(char *service);
+int dcm_send_file(char *service, char *host, char *target);
+int dcm_execute(char *service, char *host, char *script);
+void dbmserr(void);
#define SQL_NO_MATCH 1403
#define SOFT_FAIL(x) (((x) == MR_NO_MEM) || ((x) == MR_CANT_CONNECT) || ((x) == MR_CCONFIG) || ((x) == MR_DEADLOCK) || ((x) == MR_BUSY) || ((x) == MR_ABORT))
char whobuf[256], *whoami = whobuf, *db = "moira";
-extern CONNECTION conn;
int main(int argc, char **argv)
{
int i;
EXEC SQL BEGIN DECLARE SECTION;
- char buf[16], *name;
+ char buf[SERVERS_NAME_SIZE], *name;
int enable;
EXEC SQL END DECLARE SECTION;
struct save_queue *sq;
exit(1);
}
+ EXEC SQL WHENEVER SQLERROR DO dbmserr();
+
EXEC SQL CONNECT :db IDENTIFIED BY :db;
EXEC SQL SELECT value INTO :enable FROM numvalues WHERE name = 'dcm_enable';
switch (fork())
{
case -1:
- fprintf(stderr, "dcm: could not fork for service %s -- exiting",
+ com_err(whoami, errno, "forking for service %s -- exiting",
name);
exit(1);
case 0:
- sprintf(strchr(whoami, '\0'), " (%s)", name);
+ sprintf(strchr(whoami, '\0'), " (%s:%ld)", name, (long)getpid());
do_hosts(name);
com_err(whoami, 0, "exiting");
exit(0);
}
}
- /* wait for children */
+ com_err(whoami, 0, "All files generated. Waiting for children to exit");
while (waitpid(0, &status, 0) > 0)
;
com_err(whoami, 0, "exiting");
+ exit(0);
}
int generate_service(char *name, int force)
EXEC SQL BEGIN DECLARE SECTION;
int interval, dfcheck, status;
time_t now;
- char *errmsg;
+ const char *errmsg;
EXEC SQL END DECLARE SECTION;
- char dfgen_prog[64], dfgen_cmd[128];
+ char dfgen_prog[MAXPATHLEN], dfgen_cmd[2 * MAXPATHLEN];
struct sigaction action, prevaction;
int waits;
EXEC SQL CONNECT :db IDENTIFIED BY :db;
- EXEC SQL SELECT update_int, dfcheck INTO :interval, :dfcheck
+ EXEC SQL SELECT update_int, dfcheck INTO :interval, :dfcheck
FROM servers WHERE name = UPPER(:name);
if (sqlca.sqlcode == SQL_NO_MATCH)
{
sprintf(dfgen_cmd, "exec %s %s/%s.out", dfgen_prog, DCM_DIR, name);
com_err(whoami, 0, "running %s", dfgen_prog);
+ EXEC SQL WHENEVER SQLERROR GOTO gen_cleanup;
+
EXEC SQL UPDATE servers SET inprogress = 1
WHERE name = UPPER(:name);
+ EXEC SQL COMMIT;
action.sa_flags = 0;
sigemptyset(&action.sa_mask);
else /* HARD_FAIL(status) */
{
errmsg = error_message(status);
- EXEC SQL UPDATE servers SET dfcheck = :now, harderror = :status,
- errmsg = :errmsg, inprogress = 0 WHERE name = UPPER(:name);
+ EXEC SQL UPDATE servers SET harderror = :status, errmsg = :errmsg,
+ inprogress = 0 WHERE name = UPPER(:name);
critical_alert("DCM", "DCM building config files for %s: %s",
name, errmsg);
}
}
EXEC SQL COMMIT RELEASE;
return 0;
+
+gen_cleanup:
+ EXEC SQL WHENEVER SQLERROR DO dbmserr();
+ EXEC SQL UPDATE servers SET inprogress = 0, harderror = MR_INTERNAL,
+ errmsg = 'DBMS Internal Error' WHERE name = UPPER(:name);
+ dbmserr();
}
void do_hosts(char *service)
{
EXEC SQL BEGIN DECLARE SECTION;
- char type[16], host[73], target[64], script[128], *errmsg;
- int status = 0, mid, dfgen, replicated;
+ char type[SERVERS_TYPE_SIZE], host[MACHINE_NAME_SIZE], *name;
+ char target[SERVERS_TARGET_FILE_SIZE], script[SERVERS_SCRIPT_SIZE];
+ const char *errmsg;
+ int status = 0, dfgen, replicated, mid;
time_t now;
EXEC SQL END DECLARE SECTION;
+ struct save_queue *sq;
time(&now);
- gdb_init();
+ mr_init();
EXEC SQL CONNECT :db IDENTIFIED BY :db;
INTO :dfgen, :type, :target, :script
FROM servers WHERE name = UPPER(:service);
replicated = !strncmp(type, "REPLICAT", 8);
+ strtrim(target);
+ strtrim(script);
EXEC SQL DECLARE csr_hst1 CURSOR FOR
- SELECT m.name FROM machine m, serverhosts sh
+ SELECT m.name, m.mach_id FROM machine m, serverhosts sh
WHERE sh.service = UPPER(:service)
AND sh.enable = 1 AND sh.hosterror = 0
- AND sh.lts < :dfgen AND sh.mach_id = m.mach_id
- FOR UPDATE OF sh.inprogress, sh.hosterror, sh.hosterrmsg;
+ AND sh.lts < :dfgen AND sh.mach_id = m.mach_id;
EXEC SQL OPEN csr_hst1;
-
+ sq = sq_create();
while (1)
{
- EXEC SQL FETCH csr_hst1 INTO :host;
+ EXEC SQL FETCH csr_hst1 INTO :host, mid;
if (sqlca.sqlcode == SQL_NO_MATCH)
break;
- com_err(whoami, 0, "sending %s data to %s", service, strtrim(host));
+ sq_save_data(sq, strdup(strtrim(host)));
+ sq_save_data(sq, (void *)mid);
+ }
+ EXEC SQL CLOSE csr_hst1;
+
+ EXEC SQL WHENEVER SQLERROR GOTO host_cleanup;
+ while (sq_get_data(sq, &name))
+ {
+ sq_get_data(sq, &mid);
+ com_err(whoami, 0, "sending %s data to %s", service, name);
EXEC SQL UPDATE serverhosts SET inprogress = 1
- WHERE CURRENT OF csr_hst1;
- status = dcm_send_file(service, host, strtrim(target));
+ WHERE service = UPPER(:service) AND mach_id = :mid;
+ EXEC SQL COMMIT;
+ status = dcm_send_file(service, name, target);
if (status)
{
errmsg = error_message(status);
EXEC SQL UPDATE serverhosts SET hosterrmsg = :errmsg,
- inprogress = 0 WHERE CURRENT OF csr_hst1;
+ inprogress = 0, success = 0, ltt = :now
+ WHERE service = UPPER(:service) AND mach_id = :mid;
if (!SOFT_FAIL(status))
{
EXEC SQL UPDATE serverhosts SET hosterror = :status
- WHERE CURRENT OF csr_hst1;
+ WHERE service = UPPER(:service) AND mach_id = :mid;
critical_alert("DCM", "DCM updating %s:%s: %s",
- service, host, errmsg);
+ service, name, errmsg);
}
+ EXEC SQL COMMIT;
if (replicated)
break;
}
}
- EXEC SQL CLOSE csr_hst1;
+ sq_destroy(sq);
if (status == MR_SUCCESS || !replicated)
{
EXEC SQL DECLARE csr_hst2 CURSOR FOR
- SELECT m.name FROM machine m, serverhosts sh
+ SELECT m.name, m.mach_id FROM machine m, serverhosts sh
WHERE sh.service = UPPER(:service) AND sh.inprogress = 1
- AND sh.mach_id = m.mach_id
- FOR UPDATE OF sh.hosterror, sh.hosterrmsg, sh.inprogress;
+ AND sh.mach_id = m.mach_id;
EXEC SQL OPEN csr_hst2;
+ sq = sq_create();
while (1)
{
- EXEC SQL FETCH csr_hst2 INTO :host;
+ EXEC SQL FETCH csr_hst2 INTO :host, :mid;
if (sqlca.sqlcode == SQL_NO_MATCH)
break;
- com_err(whoami, 0, "executing instructions on %s", strtrim(host));
- status = dcm_execute(service, host, strtrim(script));
+ sq_save_data(sq, strdup(strtrim(host)));
+ sq_save_data(sq, (void *)mid);
+ }
+ EXEC SQL CLOSE csr_hst2;
+
+ while (sq_get_data(sq, &name))
+ {
+ sq_get_data(sq, &mid);
+
+ com_err(whoami, 0, "executing instructions on %s", name);
+ status = dcm_execute(service, name, script);
if (status)
{
errmsg = error_message(status);
EXEC SQL UPDATE serverhosts SET hosterrmsg = :errmsg,
- inprogress = 0 WHERE CURRENT OF csr_hst2;
+ inprogress = 0, success = 0, ltt = :now
+ WHERE service = UPPER(:service) AND mach_id = :mid;
if (!SOFT_FAIL(status))
{
EXEC SQL UPDATE serverhosts SET hosterror = :status
- WHERE CURRENT OF csr_hst2;
+ WHERE service = UPPER(:service) AND mach_id = :mid;
critical_alert("DCM", "DCM updating %s:%s: %s",
service, host, errmsg);
}
}
else
{
- EXEC SQL UPDATE serverhosts SET inprogress = 0, lts = :now
- WHERE CURRENT OF csr_hst2;
+ EXEC SQL UPDATE serverhosts SET inprogress = 0, ltt = :now,
+ lts = :now, success = 1 WHERE service = UPPER(:service)
+ AND mach_id = :mid;
}
+ EXEC SQL COMMIT;
}
EXEC SQL CLOSE csr_hst2;
}
+ EXEC SQL WHENEVER SQLERROR DO dbmserr();
if (status && replicated)
{
EXEC SQL UPDATE servers SET harderror = :status, errmsg = :errmsg
}
EXEC SQL COMMIT RELEASE;
+ return;
+
+host_cleanup:
+ EXEC SQL UPDATE serverhosts SET inprogress = 0, success = 0, ltt = :now,
+ hosterror = MR_INTERNAL, hosterrmsg = 'DBMS Internal Error'
+ WHERE service = UPPER(:service) AND mach_id = :mid;
+ if (replicated)
+ {
+ EXEC SQL UPDATE servers SET harderror = MR_INTERNAL,
+ errmsg = 'DBMS Internal Error' WHERE name = UPPER(:service);
+ }
}
int dcm_send_file(char *service, char *host, char *target)
{
- char addr[256], data[MAXPATHLEN];
- int code;
+ char data[MAXPATHLEN];
+ int code, conn;
- sprintf(addr, "%s:moira_update", host);
- conn = start_server_connection(addr, "");
- if (!conn || (connection_status(conn) == CON_STOPPED))
+ conn = mr_connect_internal(host, "moira_update");
+ if (!conn)
{
- com_err(whoami, connection_errno(conn), "can't connect to %s", addr);
+ com_err(whoami, errno, "can't connect to %s", host);
return MR_CANT_CONNECT;
}
- code = send_auth(host);
+ code = send_auth(conn, host);
if (code)
{
com_err(whoami, code, "authenticating to %s", host);
}
sprintf(data, "%s/%s.out", DCM_DIR, service);
- code = send_file(data, target, 1);
- if (code == MR_UNKNOWN_PROC)
- code = send_file(data, target, 0);
+ code = send_file(conn, data, target, 0);
if (code)
com_err(whoami, code, "sending data to %s", host);
done:
- send_quit();
- sever_connection(conn);
+ send_quit(conn);
+ close(conn);
return code;
}
int dcm_execute(char *service, char *host, char *script)
{
- char addr[256], inst[MAXPATHLEN];
- int code;
+ char inst[MAXPATHLEN];
+ int code, conn;
- sprintf(addr, "%s:moira_update", host);
- conn = start_server_connection(addr, "");
- if (!conn || (connection_status(conn) == CON_STOPPED))
+ conn = mr_connect_internal(host, "moira_update");
+ if (!conn)
{
- com_err(whoami, connection_errno(conn), "can't connect to %s", addr);
+ com_err(whoami, errno, "can't connect to %s", host);
return MR_CANT_CONNECT;
}
- code = send_auth(host);
+ code = send_auth(conn, host);
if (code)
{
com_err(whoami, code, "authenticating to %s", host);
sprintf(inst, "/tmp/moira-update.XXXXXX");
mktemp(inst);
- code = send_file(script, inst, 0);
+ code = send_file(conn, script, inst, 0);
if (code)
{
com_err(whoami, code, "sending instructions to %s", host);
goto done;
}
- code = execute(inst);
+ code = execute(conn, inst);
if (code)
com_err(whoami, code, "executing instructions on %s", host);
done:
- send_quit();
- sever_connection(conn);
+ send_quit(conn);
+ close(conn);
return code;
}