home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Unix System Administration Handbook 1997 October
/
usah_oct97.iso
/
news
/
nn.tar
/
nn-6.5.1
/
proto.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-04-29
|
5KB
|
257 lines
/*
* (c) Copyright 1990, Kim Fabricius Storm. All rights reserved.
*
* Master/slave communication and locking.
*/
#include "config.h"
#include <signal.h>
#include <errno.h>
#include <pwd.h>
#include "proto.h"
/* proto.c */
static void write_lock __APROTO((char *lock, char *operation));
static int read_lock __APROTO((char *lock));
#ifndef ACCOUNTING
#ifdef AUTHORIZE
#define ACCOUNTING
#endif
#endif
import char *master_directory, *db_directory;
#define HOSTBUF 80
export char proto_host[HOSTBUF]; /* host having the lock */
/*
* When setting a lock, we must check a little later that
* we really got the lock set, i.e. that another process
* didn't set it at the same time!
*/
#define LOCK_SAFETY 5 /* seconds */
/*
* proto_lock(program, mode)
*
* Returns:
* -1 Not running.
* 0 Running, no permission (PL_WAKEUP_SOFT)
* 0 Lock set (PL_SET)
* 1 Lock not set (PL_SET) (another is running)
* 1 Locked and running (PL_WAKEUP)
* pid Locked and running (PL_CHECK)
*/
static void
write_lock(lock, operation)
char *lock, *operation;
{
FILE *m_pid;
char host[HOSTBUF];
m_pid = open_file(lock, OPEN_CREATE);
if (m_pid == NULL)
sys_error("Cannot %s lock file: %s", operation, lock);
nn_gethostname(host, HOSTBUF);
fprintf(m_pid, "%d\n%s\n", process_id, host);
fclose(m_pid);
}
static int read_lock(lock)
char *lock;
{
FILE *m_pid;
char host[HOSTBUF];
char pid[10];
pid[0] = NUL;
proto_host[0] = NUL;
m_pid = open_file(lock, OPEN_READ);
if (m_pid == NULL) return -2; /* no lock */
fgets(pid, 10, m_pid);
fgets(proto_host, HOSTBUF, m_pid);
fclose(m_pid);
if (pid[0] == NUL) return 0; /* corrupted lock */
if (proto_host[0] != NUL) {
substchr(proto_host, NL, NUL);
nn_gethostname(host, HOSTBUF);
if (strncmp(proto_host, host, HOSTBUF) != 0)
return -1; /* locked by another host */
proto_host[0] = NUL;
}
return atoi(pid);
}
int
proto_lock(prog, command)
int prog;
int command;
{
int try, pid;
char *lock = NULL;
switch (prog) {
case I_AM_MASTER:
case I_AM_EXPIRE:
lock = relative(master_directory, "MPID");
break;
case I_AM_SPEW:
lock = relative(master_directory, "WPID");
break;
#ifdef ACCOUNTING
case I_AM_ACCT:
lock = relative(db_directory, "LCK..acct");
break;
#endif
case I_AM_NN:
lock = relative(nn_directory, "LOCK");
break;
default:
sys_error("Invalid LOCK prog");
}
if (command == PL_TRANSFER) {
write_lock(lock, "transfer");
return 1;
}
if (command == PL_CLEAR)
goto rm_lock;
try = 1;
again:
switch (pid = read_lock(lock)) {
case -2:
goto no_lock;
case -1: /* wrong host */
return 1;
case 0:
case 1:
case 2: /* corrupted lock file */
if (who_am_i == I_AM_NN) goto rm_lock;
if (--try < 0) goto rm_lock;
sleep(LOCK_SAFETY); /* maybe it is being written */
goto again;
default:
break;
}
if (kill(pid, command == PL_TERMINATE ? SIGHUP : SIGALRM) == 0) {
switch (command) {
case PL_SET_QUICK:
sleep(1);
goto again;
case PL_SET_WAIT:
case PL_CLEAR_WAIT:
sleep(30);
goto again;
case PL_CHECK:
return pid;
default:
return 1;
}
}
if (command == PL_CHECK)
return (errno == EPERM) ? pid : -1;
if (command == PL_WAKEUP_SOFT)
return (errno == EPERM) ? 0 : -1;
/* lock file contains a non-existing process, or a process with */
/* wrong owner, ie. neither master or expire, so remove it */
rm_lock:
unlink(lock);
no_lock:
if (command != PL_SET && command != PL_SET_QUICK && command != PL_SET_WAIT)
return -1;
write_lock(lock, "create");
/* a user will not start nn twice at the exact same time! */
if (who_am_i == I_AM_NN || command == PL_SET_QUICK) return 0;
sleep(LOCK_SAFETY);
if (read_lock(lock) != process_id)
return 1; /* somebody stole the lock file */
return 0; /* lock is set */
}
FILE *open_gate_file(mode)
int mode;
{
char *gate, *err;
FILE *gf;
gate = relative(master_directory, "GATE");
gf = open_file(gate, mode);
err = NULL;
switch (mode) {
case OPEN_READ:
if (gf != NULL) {
if (unlink(gate) == 0) break;
err = "unlink";
break;
}
if (errno != ENOENT) err = "read";
break;
default:
if (gf != NULL) chmod(gate, 0644); /* override restrictive umask */
/* caller must complain if cannot open! */
break;
}
if (err != NULL) {
sys_warning("Cannot %s %s (err=%d). Check modes!!", err, gate, errno);
if (gf != NULL) fclose(gf);
return NULL;
}
return gf;
}
void
send_master(command, gh, opt, arg)
char command;
group_header *gh;
char opt;
long arg;
{
FILE *gate;
gate = open_gate_file(OPEN_APPEND);
if (gate == NULL) {
printf("Cannot send to master (check GATE file)\n");
return;
}
fprintf(gate, "%c;%ld;%c;%ld;%s %s;\n",
command, gh == NULL ? -1L : gh->group_num, opt, arg,
user_name(), date_time((time_t)0));
fclose(gate);
log_entry('A', "SEND %c %s %c %ld",
command, gh == NULL ? "(all)" : gh->group_name, opt, arg);
if (who_am_i == I_AM_ADMIN)
proto_lock(I_AM_MASTER, PL_WAKEUP_SOFT);
}