1 /* $NetBSD: utmpentry.c,v 1.11 2006/11/27 16:54:10 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 2002 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Christos Zoulas. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 #ifndef lint 41 __RCSID("$NetBSD: utmpentry.c,v 1.11 2006/11/27 16:54:10 christos Exp $"); 42 #endif 43 44 #include <sys/stat.h> 45 46 #include <time.h> 47 #include <string.h> 48 #include <err.h> 49 #include <stdlib.h> 50 51 #ifdef SUPPORT_UTMP 52 #include <utmp.h> 53 #endif 54 #ifdef SUPPORT_UTMPX 55 #include <utmpx.h> 56 #endif 57 58 #include "utmpentry.h" 59 60 61 #ifdef SUPPORT_UTMP 62 static void getentry(struct utmpentry *, struct utmp *); 63 static struct timespec utmptime = {0, 0}; 64 #endif 65 #ifdef SUPPORT_UTMPX 66 static void getentryx(struct utmpentry *, struct utmpx *); 67 static struct timespec utmpxtime = {0, 0}; 68 #endif 69 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) 70 static int setup(const char *); 71 static void adjust_size(struct utmpentry *e); 72 #endif 73 74 int maxname = 8, maxline = 8, maxhost = 16; 75 int etype = 1 << USER_PROCESS; 76 static int numutmp = 0; 77 static struct utmpentry *ehead; 78 79 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) 80 static void 81 adjust_size(struct utmpentry *e) 82 { 83 int max; 84 85 if ((max = strlen(e->name)) > maxname) 86 maxname = max; 87 if ((max = strlen(e->line)) > maxline) 88 maxline = max; 89 if ((max = strlen(e->host)) > maxhost) 90 maxhost = max; 91 } 92 93 static int 94 setup(const char *fname) 95 { 96 int what = 3; 97 struct stat st; 98 const char *sfname; 99 100 if (fname == NULL) { 101 #ifdef SUPPORT_UTMPX 102 setutxent(); 103 #endif 104 #ifdef SUPPORT_UTMP 105 setutent(); 106 #endif 107 } else { 108 size_t len = strlen(fname); 109 if (len == 0) 110 errx(1, "Filename cannot be 0 length."); 111 what = fname[len - 1] == 'x' ? 1 : 2; 112 if (what == 1) { 113 #ifdef SUPPORT_UTMPX 114 if (utmpxname(fname) == 0) 115 warnx("Cannot set utmpx file to `%s'", 116 fname); 117 #else 118 warnx("utmpx support not compiled in"); 119 #endif 120 } else { 121 #ifdef SUPPORT_UTMP 122 if (utmpname(fname) == 0) 123 warnx("Cannot set utmp file to `%s'", 124 fname); 125 #else 126 warnx("utmp support not compiled in"); 127 #endif 128 } 129 } 130 #ifdef SUPPORT_UTMPX 131 if (what & 1) { 132 sfname = fname ? fname : _PATH_UTMPX; 133 if (stat(sfname, &st) == -1) { 134 warn("Cannot stat `%s'", sfname); 135 what &= ~1; 136 } else { 137 if (timespeccmp(&st.st_mtimespec, &utmpxtime, >)) 138 utmpxtime = st.st_mtimespec; 139 else 140 what &= ~1; 141 } 142 } 143 #endif 144 #ifdef SUPPORT_UTMP 145 if (what & 2) { 146 sfname = fname ? fname : _PATH_UTMP; 147 if (stat(sfname, &st) == -1) { 148 warn("Cannot stat `%s'", sfname); 149 what &= ~2; 150 } else { 151 if (timespeccmp(&st.st_mtimespec, &utmptime, >)) 152 utmptime = st.st_mtimespec; 153 else 154 what &= ~2; 155 } 156 } 157 #endif 158 return what; 159 } 160 #endif 161 162 void 163 freeutentries(struct utmpentry *ep) 164 { 165 #ifdef SUPPORT_UTMP 166 timespecclear(&utmptime); 167 #endif 168 #ifdef SUPPORT_UTMPX 169 timespecclear(&utmpxtime); 170 #endif 171 if (ep == ehead) { 172 ehead = NULL; 173 numutmp = 0; 174 } 175 while (ep) { 176 struct utmpentry *sep = ep; 177 ep = ep->next; 178 free(sep); 179 } 180 } 181 182 int 183 getutentries(const char *fname, struct utmpentry **epp) 184 { 185 #ifdef SUPPORT_UTMPX 186 struct utmpx *utx; 187 #endif 188 #ifdef SUPPORT_UTMP 189 struct utmp *ut; 190 #endif 191 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX) 192 struct utmpentry *ep; 193 int what = setup(fname); 194 struct utmpentry **nextp = &ehead; 195 switch (what) { 196 case 0: 197 /* No updates */ 198 *epp = ehead; 199 return numutmp; 200 default: 201 /* Need to re-scan */ 202 ehead = NULL; 203 numutmp = 0; 204 } 205 #endif 206 207 #ifdef SUPPORT_UTMPX 208 while ((what & 1) && (utx = getutxent()) != NULL) { 209 if (fname == NULL && ((1 << utx->ut_type) & etype) == 0) 210 continue; 211 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) { 212 warn(NULL); 213 return 0; 214 } 215 getentryx(ep, utx); 216 *nextp = ep; 217 nextp = &(ep->next); 218 } 219 #endif 220 221 #ifdef SUPPORT_UTMP 222 if ((etype & (1 << USER_PROCESS)) != 0) { 223 while ((what & 2) && (ut = getutent()) != NULL) { 224 if (fname == NULL && (*ut->ut_name == '\0' || 225 *ut->ut_line == '\0')) 226 continue; 227 /* Don't process entries that we have utmpx for */ 228 for (ep = ehead; ep != NULL; ep = ep->next) { 229 if (strncmp(ep->line, ut->ut_line, 230 sizeof(ut->ut_line)) == 0) 231 break; 232 } 233 if (ep != NULL) 234 continue; 235 if ((ep = calloc(1, sizeof(*ep))) == NULL) { 236 warn(NULL); 237 return 0; 238 } 239 getentry(ep, ut); 240 *nextp = ep; 241 nextp = &(ep->next); 242 } 243 } 244 #endif 245 numutmp = 0; 246 #if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX) 247 if (ehead != NULL) { 248 struct utmpentry *from = ehead, *save; 249 250 ehead = NULL; 251 while (from != NULL) { 252 for (nextp = &ehead; 253 (*nextp) && strcmp(from->line, (*nextp)->line) > 0; 254 nextp = &(*nextp)->next) 255 continue; 256 save = from; 257 from = from->next; 258 save->next = *nextp; 259 *nextp = save; 260 numutmp++; 261 } 262 } 263 *epp = ehead; 264 return numutmp; 265 #else 266 *epp = NULL; 267 return 0; 268 #endif 269 } 270 271 #ifdef SUPPORT_UTMP 272 static void 273 getentry(struct utmpentry *e, struct utmp *up) 274 { 275 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); 276 e->name[sizeof(e->name) - 1] = '\0'; 277 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); 278 e->line[sizeof(e->line) - 1] = '\0'; 279 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); 280 e->name[sizeof(e->name) - 1] = '\0'; 281 e->tv.tv_sec = up->ut_time; 282 e->tv.tv_usec = 0; 283 e->pid = 0; 284 e->term = 0; 285 e->exit = 0; 286 e->sess = 0; 287 e->type = USER_PROCESS; 288 adjust_size(e); 289 } 290 #endif 291 292 #ifdef SUPPORT_UTMPX 293 static void 294 getentryx(struct utmpentry *e, struct utmpx *up) 295 { 296 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); 297 e->name[sizeof(e->name) - 1] = '\0'; 298 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); 299 e->line[sizeof(e->line) - 1] = '\0'; 300 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); 301 e->name[sizeof(e->name) - 1] = '\0'; 302 e->tv = up->ut_tv; 303 e->pid = up->ut_pid; 304 e->term = up->ut_exit.e_termination; 305 e->exit = up->ut_exit.e_exit; 306 e->sess = up->ut_session; 307 e->type = up->ut_type; 308 adjust_size(e); 309 } 310 #endif 311