ftp.nice.ch/pub/next/unix/network/news/nn.6.4.16.s.tar.gz#/nn/proto.c

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.