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