/* The problem often seems to arise in dealing with terminated xterms. (This is yet another reason for why we need a real session manager.) Rebooting to fix utmp is unduly harsh! Just use a binary editor of some sort or write a single-purpose script to hammer a null at the beginning of the entry. In either case, you'll need to understand the format of utmp(5). Or you could use the following program, written by a younger version of myself long ago and far away. It's aesthetically bothersome in various ways, but it still works well enough to get the job done on the machines I have to deal with, even today. To clear an entry on say ttyp5, as root type: chusr '' ttyp5 --tom */ /* * chusr.c -- change user entry in utmp * * Tom Christiansen (1984), for BSD4.2 systems * * (various minor hacks since then, like 4.3 compat stuff) */ #include #include #include #include #include #include #define SCPYN(to,from) (void) strncpy(to,from,sizeof(to)) #ifndef BSD42 # define BSD43 1 #endif char *strncpy (); char *ttyname (); char *index (); char *rindex (); int strncmp (); main (ac, av) char **av; { struct utmp utmp; /* new utmp entry for utmp file */ int nentries, /* how many we got */ ufd, /* utmp's fd */ tslot, /* where to put the entry */ tflag = 0; /* update time? */ char *mytty = "/dev/ttyXXXX", *ufile = "/etc/utmp", *s; if (ac < 2 || ac > 4) usage (*av); if (!strcmp (av[1], "-t")) { tflag++; av++; ac--; } s = av[2]; if ((ufd = open (ufile, O_RDWR)) < 0) { perror (ufile); exit (EX_OSFILE); } if (ac == 2) { if ((mytty = ttyname (fileno (stdin))) == NULL) { fprintf (stderr, "%s: no tty\n", *av); exit (EX_UNAVAILABLE); } } else { if (strlen (s) == 2) { if (s[0] == 'c' && s[1] == 'o') strcpy (rindex (mytty, '/') + 1, "console"); else if (s[0] == 'e' && s[1] == 'x') strcpy (rindex (mytty, '/') + 1, "express"); else strcpy (index (mytty, 'X'), s); } else { char *i1 = index (mytty, 't'); char *i2 = index (s, 't'); if (!i1) { printf(stderr,"no t in %s\n", mytty); exit(17); } if (!i2) { printf(stderr,"no t in %s\n", s); exit(18); } strncpy (i1, i2, 7); } } mytty += 5; /* skip "/dev/" */ if (!(tslot = ttyslot (mytty))) { fprintf (stderr, "no tty\n"); exit (1); } lseek (ufd, (long) (tslot * sizeof (utmp)), 0); read (ufd, (char *) &utmp, sizeof (utmp)); #ifdef LOG_AUTH openlog ("chusr", LOG_PID | LOG_CONS | LOG_NOWAIT, LOG_AUTH); #else openlog ("chusr", LOG_PID); #endif syslog (LOG_NOTICE, "\"%.*s\" changed to \"%s\" on %s\n", sizeof (utmp.ut_name), utmp.ut_name, av[1], mytty); closelog(); SCPYN (utmp.ut_name, av[1]); SCPYN (utmp.ut_line, mytty); if (ac == 4) SCPYN (utmp.ut_host, av[3]); if (tflag) time (&utmp.ut_time); lseek (ufd, (long) (tslot * sizeof (utmp)), 0); write (ufd, (char *) &utmp, sizeof (utmp)); (void) close (ufd); } usage (name) char *name; { fprintf (stderr, "usage: %s user [-t] [ tty [whence] ]\n", name); exit (EX_USAGE); } /* /* * Return the number of the slot in the utmp file * corresponding to the passed tty. * returns 0 on error. */ char *getttys (); static char ttys[] = "/etc/ttys"; #define NULL 0 ttyslot (tty) register char *tty; { register char *tp, *p; register s; FILE *tf; tp = tty; if ((p = rindex (tp, '/')) == NULL) p = tp; else p++; if ((tf = fopen (ttys, "r")) == NULL) return (0); s = 0; while (tp = getttys (tf)) { s++; if (strncmp (p, tp, strlen (p)) == 0) { fclose (tf); return (s); } } fclose (tf); return (0); } static char * getttys (f) FILE *f; { static char line[256]; register char *lp; do { if (fgets (line, 256, f) == NULL) return NULL; } while (*line == '#'); /* ignore comment lines */ for (lp = line;; lp++) { if ((*lp == '\t') || (*lp == ' ') || (*lp == '\n')) { *lp = '\0'; #ifdef BSD43 return (line); #else return (line + 2); #endif } } }