utmp entry -- we're not doing something right -- can you help?

Irving Wolfe irv at happym.wa.com
Sat Jul 7 04:09:19 AEST 1990


The following program is intended to create a process and re-create it if it 
dies, as if it had been listed in inittab with respawn set, but later, so that 
(for example) a privileged process could start up something which would be 
re-created as often as necessary during a two hour observation period, then 
after 2 hours kill the "gspawn" process and finally kill the most recent 
instance of the process gspawn had created. 

It seems to work, but it doesn't work perfectly in that "ps -f" no longer can 
find the command string associated with many of the processes that are running 
on the system and resorts to showing things like "[ ps ]" instead of "ps 
-fuirv" in the command field. 

Can anyone explain why, preferably (but not necessarily) with a fix?

Thanks!


/* gspawn [ -c prog ] tty [ args... ] */
/* vi:se ts=4 wm=0 sw=4: */

#include <stdio.h>
#include <errno.h>
#include <pwd.h>
#include <string.h>
#include <sys/types.h>
#include <utmp.h>
#include <signal.h>

#define MAXARGS		5
#define ERRTTY		"/dev/console"
#define DEFAULTARG0	"/bin/true"
#define DEFAULTARG2	"9600"

char *Argv[MAXARGS] = {
DEFAULTARG0,
"/dev/null",
DEFAULTARG2,
(char *)0,
};

char *Gettyprog = DEFAULTARG0;
char *Tty;
int Pid = -1;
char *Progname = "gspawn";


/* not entirely portable, but probably more so than varargs :-( */
conerr(msg,a1,a2,a3,a4,a5,a6)
char *msg;
int a1,a2,a3,a4,a5,a6;
{
	char buf[BUFSIZ];
	FILE *f = fopen(ERRTTY, "w");
	if (!f) pause(); /* foo */
	setbuf(f, NULL);
	strcat(buf, Progname);
	sprintf(buf+strlen(buf), msg, a1,a2,a3,a4,a5,a6);
	strcat(buf,"\r\n");
	fputs(buf, f);
	fclose(f);
}

usage() {
fprintf(stderr, "usage: %s [ -c cmd ] tty [ args ... ]\n", Progname);
}

char *
basename(s)
char *s;
{
	char *p = strrchr(s, '/');
	if (p) return ++p;
	return s;
}

cleanup()
{
	/* the heck with it.  */
	exit(0);
}


main(argc, argv)
char **argv;
{
	int c;
	int forks;

	extern char *optarg;
	extern int optind;
	extern int errno;

	Progname = basename(argv[0]);

	while ((c = getopt(argc, argv, "c:")) != EOF)
	switch(c) {
		case 'c':	Argv[0] = optarg; break;
		default:	usage(); exit(1);
	}

	if (optind >= argc) {
		usage();
		exit(2);
	}


	c = 1;
	while (optind < argc)
		Argv[c++] = argv[optind++];
	Argv[c] = 0;
	Tty = Argv[1];

/* if not started by init, daemonize us */
	if (getppid() != 1) {
		Pid = fork();
		if (Pid < 0) {
			perror("fork");
			exit(3);
		} else if (Pid > 0) {
			exit(0);
		} else {
			close(0);
			close(1);
			close(2);
		}
	}
	setpgrp();


	signal(SIGTERM, cleanup);

	forks = 0;

	/* only go away if we're all hosed */
	while (forks < 10) {

		/* fork, make new pgrp, exec cmd */
		Pid = fork();

		if (Pid == 0) {
			/* Make an INIT_PROCESS in utmp */
			do_utmp(Tty);
			for (c = 0; c < _NFILE; c++) close(c);
			setpgrp();
			execv(Argv[0], Argv);
			conerr("Failed miserably");
			exit(1); /* STOP IMMEDIATELY */ 
		} else if (Pid < 0) {
			conerr("couldn't fork in %s\n", argv[0]);
			++forks;
			sleep(200);	/* alarm(20); pause(); */
			continue;
		}

		forks = 0;
		while ((c=wait((int *)0)) != Pid && (c!= -1 || errno==EINTR))
		 ;
		Pid = -1;
	}
}

do_utmp(tty)
char *tty;
{
/* diddling /etc/utmp...   When a cmd process is created, make utmp */
/* entry for new process.  Leave the old one alone so init can find it. */

	extern struct utmp *getutent(), *pututline();
	register struct utmp *u;
	struct utmp ut;
	register FILE *fp;
	char id[4];
	int oldpid = getppid();
	int newpid = getpid();

/* Look in "utmp" for our parent's entry.  It will be an INIT_PROCESS.  */
/* Leave it alone and make a similar entry for us (the child).  There */
/* may already be an entry, but it has the wrong pid. */

/* MAGIC RULE:  id tags should be e.g. p1, p2, p3 and new ones will */
/* be created: P1, P2, P3. */

/* find parent's line, just remember id */
	while ((u = getutent()) != NULL) {
		if (u->ut_type == INIT_PROCESS && u->ut_pid == oldpid) {
			strncpy(id, u->ut_id, sizeof(u->ut_id));
			break;
		}
	}

/* look for child's line */
	if (u != NULL) {
		id[0] = 'P';	/* cheat */
	} else {
		/* testing - not run by init */
		strcpy(id, "PX");
	}

	setutent();

	while ((u = getutent()) != NULL) {
		if (strncmp(u->ut_id, id, sizeof(u->ut_id)) == 0)
			break;
	}

/* regardless of whether we found one, fix it up and write it. */
	if (u == NULL) u = &ut;

	strncpy(u->ut_user, "GETTY", sizeof(u->ut_user));
	strncpy(u->ut_id, id, sizeof(u->ut_user));
	strncpy(u->ut_line, Tty, sizeof(u->ut_line));
	u->ut_pid = newpid;
	u->ut_type = INIT_PROCESS;
	time(&u->ut_time);
	pututline(u);

/* If we were successful in finding an entry for ourself in the */
/* utmp file, then attempt to append to the end of the wtmp file. */
	if (u != NULL && (fp = fopen(WTMP_FILE,"r+")) != NULL) {
		fseek(fp,0L,2);	/* Seek to end of file */
		fwrite(u,sizeof(*u),1,fp);
		fclose(fp);
	}

/* Close the utmp file. */
	endutent();
}

-- 
 Irving Wolfe    Happy Man Corp.   irv at happym.wa.com    206/463-9399 ext.101
 SOLID VALUE, the investment letter for Benj. Graham's intelligent investors
 Information (not sample) free: email patty at happym.wa.com with US mail addr.



More information about the Comp.unix.wizards mailing list