utmp.c (1737B)
1 2 3 #include <errno.h> 4 #include <stdarg.h> 5 #include <stdlib.h> 6 #include <stdio.h> 7 #include <string.h> 8 #include <signal.h> 9 10 #include <sys/types.h> 11 #include <unistd.h> 12 #include <pwd.h> 13 #include <grp.h> 14 #include <sys/wait.h> 15 16 17 struct passwd *pw; 18 gid_t egid, gid; 19 20 21 void 22 die(const char *fmt, ...) 23 { 24 va_list va; 25 va_start(va, fmt); 26 vfprintf(stderr, fmt, va); 27 putc('\n', stderr); 28 va_end(va); 29 exit(EXIT_FAILURE); 30 } 31 32 int 33 main(int argc, char *argv[]) 34 { 35 int status; 36 size_t len; 37 uid_t uid; 38 sigset_t set; 39 char *p, argv0[FILENAME_MAX], *sh; 40 extern void addutmp(void), delutmp(void); 41 42 egid = getegid(); 43 gid = getgid(); 44 setgid(gid); 45 46 errno = 0; 47 if ((pw = getpwuid(uid = getuid())) == NULL) { 48 if(errno) 49 die("utmp:getpwuid:%s", strerror(errno)); 50 else 51 die("utmp:who are you?"); 52 } 53 54 setenv("LOGNAME", pw->pw_name, 1); 55 setenv("USER", pw->pw_name, 1); 56 setenv("SHELL", pw->pw_shell, 1); 57 setenv("HOME", pw->pw_dir, 1); 58 59 if ((p = strrchr(pw->pw_shell, '/')) == NULL) 60 die("incorrect shell field of passwd"); 61 if ((len = strlen(++p)) > sizeof(argv0) - 2) 62 die("shell name too long"); 63 argv0[0] = '-'; 64 memcpy(&argv0[1], p, len); 65 66 sigfillset(&set); 67 sigprocmask(SIG_BLOCK, &set, NULL); 68 69 switch (fork()) { 70 case 0: 71 sigprocmask(SIG_UNBLOCK, &set, NULL); 72 sh = pw->pw_shell; 73 argv[0] = argv0; 74 execv(sh, argv); 75 die("error executing shell(%s):%s", sh, strerror(errno)); 76 case -1: 77 die("error spawning child:%s", strerror(errno)); 78 default: 79 addutmp(); 80 signal(SIGINT, SIG_IGN); 81 signal(SIGTERM, SIG_IGN); 82 signal(SIGHUP, SIG_IGN); 83 sigprocmask(SIG_UNBLOCK, &set, NULL); 84 85 if (wait(&status) == -1) 86 perror("utmp:error waiting child"); 87 delutmp(); 88 } 89 return (WIFEXITED(status)) ? WEXITSTATUS(status) : EXIT_FAILURE; 90 }