utmpx.c (5524B)
1 /* 2 * Copyright (c) 2004 Gunnar Ritter 3 * 4 * This software is provided 'as-is', without any express or implied 5 * warranty. In no event will the authors be held liable for any damages 6 * arising from the use of this software. 7 * 8 * Permission is granted to anyone to use this software for any purpose, 9 * including commercial applications, and to alter it and redistribute 10 * it freely, subject to the following restrictions: 11 * 12 * 1. The origin of this software must not be misrepresented; you must not 13 * claim that you wrote the original software. If you use this software 14 * in a product, an acknowledgment in the product documentation would be 15 * appreciated but is not required. 16 * 17 * 2. Altered source versions must be plainly marked as such, and must not be 18 * misrepresented as being the original software. 19 * 20 * 3. This notice may not be removed or altered from any source distribution. 21 */ 22 /* Sccsid @(#)utmpx.c 1.13 (gritter) 12/16/07 */ 23 24 #include <stdio.h> 25 26 #if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \ 27 defined (__UCLIBC__) || defined (__OpenBSD__) || \ 28 defined (__DragonFly__) || \ 29 defined (__APPLE__) && \ 30 (__MAC_OS_X_VERSION_MIN_REQUIRED < __MAC_OS_X_VERSION_10_5) 31 #include <sys/types.h> 32 #include <sys/time.h> 33 #include <utmp.h> 34 #include <string.h> 35 36 #include "utmpx.h" 37 38 static FILE *utfp; 39 static struct utmpx utx; 40 static const char *utmpfile = _PATH_UTMP; 41 42 static FILE * 43 init(void) 44 { 45 if (utfp == NULL && (utfp = fopen(utmpfile, "r+")) == NULL) 46 if ((utfp = fopen(utmpfile, "r")) == NULL) 47 return NULL; 48 return utfp; 49 } 50 51 static struct utmpx * 52 utmp2utmpx(struct utmpx *ux, const struct utmp *up) 53 { 54 #ifndef __dietlibc__ 55 memset(ux, 0, sizeof *ux); 56 ux->ut_tv.tv_sec = up->ut_time; 57 memcpy(ux->ut_line, up->ut_line, UT_LINESIZE); 58 memcpy(ux->ut_user, up->ut_name, UT_NAMESIZE); 59 memcpy(ux->ut_host, up->ut_host, UT_HOSTSIZE); 60 if (strcmp(up->ut_line, "~") == 0) 61 ux->ut_type = BOOT_TIME; 62 else if (strcmp(up->ut_line, "|") == 0) 63 ux->ut_type = OLD_TIME; 64 else if (strcmp(up->ut_line, "}") == 0) 65 ux->ut_type = NEW_TIME; 66 else if (*up->ut_name == 0) 67 ux->ut_type = DEAD_PROCESS; 68 else 69 ux->ut_type = USER_PROCESS; 70 #else /* __dietlibc__ */ 71 *ux = *up; 72 #endif /* __dietlibc__ */ 73 return ux; 74 } 75 76 static struct utmp * 77 utmpx2utmp(struct utmp *up, const struct utmpx *ux) 78 { 79 #ifndef __dietlibc__ 80 memset(up, 0, sizeof *up); 81 up->ut_time = ux->ut_tv.tv_sec; 82 switch (ux->ut_type) { 83 case DEAD_PROCESS: 84 memcpy(up->ut_line, ux->ut_line, UT_LINESIZE); 85 break; 86 default: 87 case EMPTY: 88 case INIT_PROCESS: 89 case LOGIN_PROCESS: 90 case RUN_LVL: 91 case ACCOUNTING: 92 return NULL; 93 case BOOT_TIME: 94 strcpy(up->ut_name, "reboot"); 95 strcpy(up->ut_line, "~"); 96 break; 97 case OLD_TIME: 98 strcpy(up->ut_name, "date"); 99 strcpy(up->ut_line, "|"); 100 break; 101 case NEW_TIME: 102 strcpy(up->ut_name, "date"); 103 strcpy(up->ut_line, "{"); 104 break; 105 case USER_PROCESS: 106 memcpy(up->ut_line, ux->ut_line, UT_LINESIZE); 107 memcpy(up->ut_name, ux->ut_user, UT_NAMESIZE); 108 memcpy(up->ut_host, ux->ut_host, UT_HOSTSIZE); 109 } 110 #else /* __dietlibc__ */ 111 *up = *ux; 112 #endif /* __dietlibc__ */ 113 return up; 114 } 115 116 struct utmpx * 117 getutxent(void) 118 { 119 static struct utmp zero; 120 struct utmp ut; 121 122 if (init() == NULL) 123 return NULL; 124 do { 125 if (fread(&ut, sizeof ut, 1, utfp) != 1) 126 return NULL; 127 } while (memcmp(&ut, &zero, sizeof ut) == 0); 128 return utmp2utmpx(&utx, &ut); 129 } 130 131 struct utmpx * 132 getutxline(const struct utmpx *ux) 133 { 134 struct utmp ut; 135 136 if (init() == NULL) 137 return NULL; 138 fseek(utfp, 0, SEEK_SET); 139 while (fread(&ut, sizeof ut, 1, utfp) == 1) { 140 utmp2utmpx(&utx, &ut); 141 if ((utx.ut_type == LOGIN_PROCESS || 142 utx.ut_type == USER_PROCESS) && 143 strcmp(ut.ut_line, utx.ut_line) == 0) 144 return &utx; 145 } 146 return NULL; 147 } 148 149 struct utmpx * 150 getutxid(const struct utmpx *ux) 151 { 152 #ifdef __dietlibc__ 153 struct utmp ut; 154 #endif 155 156 if (init() == NULL) 157 return NULL; 158 #ifdef __dietlibc__ 159 fseek(utfp, 0, SEEK_SET); 160 while (fread(&ut, sizeof ut, 1, utfp) == 1) { 161 utmp2utmpx(&utx, &ut); 162 switch (ux->ut_type) { 163 case BOOT_TIME: 164 case OLD_TIME: 165 case NEW_TIME: 166 if (ux->ut_type == utx.ut_type) 167 return &utx; 168 break; 169 case INIT_PROCESS: 170 case LOGIN_PROCESS: 171 case USER_PROCESS: 172 case DEAD_PROCESS: 173 if (ux->ut_type == utx.ut_type && 174 ux->ut_id == utx.ut_id) 175 return &utx; 176 break; 177 } 178 } 179 #endif /* __dietlibc__ */ 180 return NULL; 181 } 182 183 void 184 setutxent(void) 185 { 186 if (init() == NULL) 187 return; 188 fseek(utfp, 0, SEEK_SET); 189 } 190 191 void 192 endutxent(void) 193 { 194 FILE *fp; 195 196 if (init() == NULL) 197 return; 198 fp = utfp; 199 utfp = NULL; 200 fclose(fp); 201 } 202 203 int 204 utmpxname(const char *name) 205 { 206 utmpfile = strdup(name); 207 return 0; 208 } 209 210 extern struct utmpx * 211 pututxline(const struct utmpx *up) 212 { 213 struct utmp ut; 214 struct utmpx *rp; 215 216 if (init() == NULL) 217 return NULL; 218 /* 219 * Cannot use getutxid() because there is no id field. Use 220 * the equivalent of getutxline() instead. 221 */ 222 while (fread(&ut, sizeof ut, 1, utfp) == 1) { 223 if (strncmp(ut.ut_line, up->ut_line, UT_LINESIZE) == 0) { 224 fseek(utfp, -sizeof ut, SEEK_CUR); 225 break; 226 } 227 } 228 fflush(utfp); 229 if (utmpx2utmp(&ut, up) == NULL) 230 rp = NULL; 231 else if (fwrite(&ut, sizeof ut, 1, utfp) == 1) { 232 utx = *up; 233 rp = &utx; 234 } else 235 rp = NULL; 236 fflush(utfp); 237 return rp; 238 } 239 240 extern void 241 updwtmpx(const char *name, const struct utmpx *up) 242 { 243 FILE *fp; 244 245 if ((fp = fopen(name, "a")) == NULL) 246 return; 247 fwrite(up, sizeof *up, 1, fp); 248 fclose(fp); 249 } 250 251 #endif /* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __UCLIBC__ || 252 __OpenBSD__ || __DragonFly__ || __APPLE__ */