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