utmp

simple login manager
git clone git://git.suckless.org/utmp
Log | Files | Refs | README | LICENSE

posix.c (2790B)


      1 
      2 #define _POSIX_C_SOURCE	200112L
      3 
      4 #include <errno.h>
      5 #include <ctype.h>
      6 #include <stdlib.h>
      7 #include <stdio.h>
      8 #include <string.h>
      9 #include <time.h>
     10 
     11 #include <sys/types.h>
     12 #include <unistd.h>
     13 #include <pwd.h>
     14 #include <grp.h>
     15 
     16 #ifdef UTMP_SYSTEMV
     17 #include <utmp.h>
     18 #define getutxent getutent
     19 #define getutxid getutid
     20 #define getutxline getutline
     21 #define pututxline pututline
     22 #define setutxent setutent
     23 #define endutxent endutent
     24 #define utmpx utmp
     25 #else
     26 #include <utmpx.h>
     27 #endif
     28 
     29 extern void die(const char *fmt, ...);
     30 static struct utmpx utmp;
     31 extern struct passwd *pw;
     32 extern gid_t egid, gid;
     33 
     34 
     35 /*
     36  * From utmp(5)
     37  * xterm and other terminal emulators directly create a USER_PROCESS
     38  * record and generate the ut_id  by using the string that suffix part of
     39  * the terminal name (the characters  following  /dev/[pt]ty). If they find
     40  * a DEAD_PROCESS for this ID, they recycle it, otherwise they create a new
     41  * entry.  If they can, they will mark it as DEAD_PROCESS on exiting and it
     42  * is advised that they null ut_line, ut_time, ut_user, and ut_host as well.
     43  */
     44 
     45 struct utmpx *
     46 findutmp(int type)
     47 {
     48 	struct utmpx *r;
     49 
     50 	utmp.ut_type = type;
     51 	setutxent();
     52 	for(;;) {
     53 	       /*
     54 		* we can not use getutxline because we can search in
     55 		* DEAD_PROCESS to
     56 		*/
     57 	       if(!(r = getutxid(&utmp)))
     58 		       break;
     59 	       if(!strcmp(r->ut_line, utmp.ut_line))
     60 		       break;
     61 	       memset(r, 0, sizeof(*r)); /* for Solaris, IRIX64 and HPUX */
     62 	}
     63 	return r;
     64 }
     65 
     66 void
     67 addutmp(void)
     68 {
     69 	unsigned ptyid;
     70 	char *pts, *cp, buf[5] = {'x'};
     71 
     72 	if (strlen(pw->pw_name) > sizeof(utmp.ut_user))
     73 		die("utmp:incorrect username %s", pw->pw_name);
     74 
     75 	if ((pts = ttyname(STDIN_FILENO)) == NULL)
     76 		die("utmp:error getting pty name\n");
     77 
     78 	for (cp = pts + strlen(pts) - 1; isdigit(*cp); --cp)
     79 		/* nothing */;
     80 
     81 	ptyid = atoi(++cp);
     82 	if (ptyid > 999 || strlen(pts + 5) > sizeof(utmp.ut_line))
     83 		die("utmp:Incorrect pts name %s\n", pts);
     84 	sprintf(buf + 1, "%03d", ptyid);
     85 	strncpy(utmp.ut_id, buf, 4);
     86 
     87 	/* remove /dev/ part of the string */
     88 	strncpy(utmp.ut_line, pts + 5, sizeof(utmp.ut_line));
     89 
     90 	if(!findutmp(DEAD_PROCESS))
     91 		findutmp(USER_PROCESS);
     92 
     93 	utmp.ut_type = USER_PROCESS;
     94 	strncpy(utmp.ut_user, pw->pw_name, sizeof(utmp.ut_user));
     95 	utmp.ut_pid = getpid();
     96 	utmp.ut_tv.tv_sec = time(NULL);
     97 	utmp.ut_tv.tv_usec = 0;
     98 	 /* don't use no standard fields host and session */
     99 
    100 	setegid(egid);
    101 	if(!pututxline(&utmp))
    102 		die("utmp:error adding utmp entry:%s", strerror(errno));
    103 	setegid(gid);
    104 	endutxent();
    105 }
    106 
    107 void
    108 delutmp(void)
    109 {
    110 	struct utmpx *r;
    111 
    112 	setutxent();
    113 	if((r = getutxline(&utmp)) != NULL) {
    114 		r->ut_type = DEAD_PROCESS;
    115 		r->ut_tv.tv_usec = r->ut_tv.tv_sec = 0;
    116 		setgid(egid);
    117 		if (!pututxline(r))
    118 			die("utmp:error removing utmp entry:%s", strerror(errno));
    119 		setgid(gid);
    120 	}
    121 	endutxent();
    122 }
    123