This is proto.c in view mode; [Download] [Up]
/*
* (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"
#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 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);
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);
gethostname(host, HOSTBUF);
if (strncmp(proto_host, host, HOSTBUF) != 0)
return -1; /* locked by another host */
proto_host[0] = NUL;
}
return atoi(pid);
}
proto_lock(prog, command)
{
FILE *m_pid;
int try, pid;
char buf[10], *any, *lock;
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;
}
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);
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.