/*
 * need: prerequisites program for mastodon-style init scripts
 *
 *  Copyright (c) 2000 David Parsons. All rights reserved.
 *
 *  This software is released under a berkeley-style copyright; the
 *  details can be found in the file COPYRIGHT.
 */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>

#include "init.h"

extern int   getopt();
extern int   optind;
extern int   opterr;
extern char *optarg;

volatile int refused;
char *pgm;
FILE *ipc;

void
not_talking(int sig)
{
    fprintf(stderr, "init is not talking to us\n");
    exit(1);
}

void
sigusr(int sig)
{
    refused = (sig != SIGUSR1);
}


void
sendcommand(int cmd, char *arg)
{
    int status;

    fprintf(ipc, arg ? "%d %c %s\n" : "%d %c\n", getpid(), cmd, arg);
    fflush(ipc);
    alarm(2);
    while (refused == -1)
	wait(&status);
    alarm(0);
} /* sendcommand */



main(int argc, char ** argv)
{
    int opt, delete=0, j, status;
    char pathname[200];
    char *runlevel = get_runlevel();

    pgm = basename(argv[0]);

    opterr = 1;
    while ( (opt = getopt(argc, argv, "c")) != EOF) {
	switch (opt) {
	case 'c':	delete++;
			break;
	default:	fprintf(stderr, "usage: %s -c\n"
					"       %s token {token ...}\n",
					pgm, pgm);
			exit(1);
	}
    }

    if (runlevel == 0 && (runlevel = getenv("RUNLEVEL")) == 0)
	runlevel = "m";

    signal(SIGALRM, not_talking);

    /* hello, init, are you out there?
     */
    alarm(2);
    if ( (ipc = openfifo(COMMAND)) == 0)
	not_talking(0);
    alarm(0);

    if (delete) {
	signal(SIGUSR1, sigusr);
	signal(SIGUSR2, sigusr);
	sendcommand(UNREGISTER, 0);
	if (refused)
	    fprintf(stderr, "Command refused");
	exit(refused);
    }

    for (j = optind; j < argc; j++) {
	if (strlen(argv[j]) > 20) {
	    fprintf(stderr, "%s: service names must be < 20 chars\n", pgm);
	    exit(1);
	}
	if (strchr(argv[j], '/') != 0) {
	    fprintf(stderr, "%s: service names may not contain ``/''\n", pgm);
	    exit(1);
	}
	signal(SIGUSR1, sigusr);
	signal(SIGUSR2, sigusr);
	refused = -1;

	sendcommand(REGISTER, argv[j]);

	if (!refused) {
	    pid_t pid;

	    pid = fork();
	    if (pid < 0) {
		fprintf(stderr, "%s: cannot fork off %s (%s)\n",
				    pgm, argv[j], strerror(errno));
		continue;
	    }
	    else if (pid == 0) {
		snprintf(pathname, sizeof pathname,
			 PREFIX "/etc/rc.d/rc.%c/%s", runlevel[0], argv[j]);
		execl(pathname, argv[j], "start", 0);
		snprintf(pathname, sizeof pathname,
			 PREFIX "/etc/rc.d/init.d/%s", argv[j]);
		execl(pathname, argv[j], "start", 0);
		fprintf(stderr, "service %s not found\n", argv[j]);
		exit(1);
	    }
	    else {
		int rc;
		waitpid(pid, &status, 0);
		if ( (rc = WEXITSTATUS(status)) != 0)
		    exit(rc);
	    }
	}
    }
    exit(0);
} /* need */
