1 /* $NetBSD: utmpentry.c,v 1.5 2004/10/22 15:50:47 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.5 2004/10/22 15:50:47 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 time_t utmptime = 0; 64 #endif 65 #ifdef SUPPORT_UTMPX 66 static void getentryx(struct utmpentry *, struct utmpx *); 67 static time_t utmpxtime = 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 static int numutmp = 0; 76 static struct utmpentry *ehead; 77 78 #if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP) 79 static void 80 adjust_size(struct utmpentry *e) 81 { 82 int max; 83 84 if ((max = strlen(e->name)) > maxname) 85 maxname = max; 86 if ((max = strlen(e->line)) > maxline) 87 maxline = max; 88 if ((max = strlen(e->host)) > maxhost) 89 maxhost = max; 90 } 91 92 static int 93 setup(const char *fname) 94 { 95 int what = 3; 96 struct stat st; 97 const char *sfname; 98 99 if (fname == NULL) { 100 #ifdef SUPPORT_UTMPX 101 setutxent(); 102 #endif 103 #ifdef SUPPORT_UTMP 104 setutent(); 105 #endif 106 } else { 107 size_t len = strlen(fname); 108 if (len == 0) 109 errx(1, "Filename cannot be 0 length."); 110 what = fname[len - 1] == 'x' ? 1 : 2; 111 if (what == 1) { 112 #ifdef SUPPORT_UTMPX 113 if (utmpxname(fname) == 0) 114 warnx("Cannot set utmpx file to `%s'", 115 fname); 116 #else 117 warnx("utmpx support not compiled in"); 118 #endif 119 } else { 120 #ifdef SUPPORT_UTMP 121 if (utmpname(fname) == 0) 122 warnx("Cannot set utmp file to `%s'", 123 fname); 124 #else 125 warnx("utmp support not compiled in"); 126 #endif 127 } 128 } 129 #ifdef SUPPORT_UTMPX 130 if (what & 1) { 131 sfname = fname ? fname : _PATH_UTMPX; 132 if (stat(sfname, &st) == -1) { 133 warn("Cannot stat `%s'", sfname); 134 what &= ~1; 135 } else { 136 if (st.st_mtime > utmpxtime) 137 utmpxtime = st.st_mtime; 138 else 139 what &= ~1; 140 } 141 } 142 #endif 143 #ifdef SUPPORT_UTMP 144 if (what & 2) { 145 sfname = fname ? fname : _PATH_UTMP; 146 if (stat(sfname, &st) == -1) { 147 warn("Cannot stat `%s'", sfname); 148 what &= ~2; 149 } else { 150 if (st.st_mtime > utmptime) 151 utmptime = st.st_mtime; 152 else 153 what &= ~2; 154 } 155 } 156 #endif 157 return what; 158 } 159 #endif 160 161 void 162 freeutentries(struct utmpentry *ep) 163 { 164 #ifdef SUPPORT_UTMP 165 utmptime = 0; 166 #endif 167 #ifdef SUPPORT_UTMPX 168 utmpxtime = 0; 169 #endif 170 if (ep == ehead) { 171 ehead = NULL; 172 numutmp = 0; 173 } 174 while (ep) { 175 struct utmpentry *sep = ep; 176 ep = ep->next; 177 free(sep); 178 } 179 } 180 181 int 182 getutentries(const char *fname, struct utmpentry **epp) 183 { 184 #ifdef SUPPORT_UTMPX 185 struct utmpx *utx; 186 #endif 187 #ifdef SUPPORT_UTMP 188 struct utmp *ut; 189 #endif 190 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX) 191 struct utmpentry *ep; 192 int what = setup(fname); 193 struct utmpentry **nextp = &ehead; 194 switch (what) { 195 case 0: 196 /* No updates */ 197 *epp = ehead; 198 return numutmp; 199 default: 200 /* Need to re-scan */ 201 ehead = NULL; 202 numutmp = 0; 203 } 204 #endif 205 206 #ifdef SUPPORT_UTMPX 207 while ((what & 1) && (utx = getutxent()) != NULL) { 208 if (fname == NULL && utx->ut_type != USER_PROCESS) 209 continue; 210 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) { 211 warn(NULL); 212 return 0; 213 } 214 getentryx(ep, utx); 215 *nextp = ep; 216 nextp = &(ep->next); 217 } 218 #endif 219 220 #ifdef SUPPORT_UTMP 221 while ((what & 2) && (ut = getutent()) != NULL) { 222 if (fname == NULL && (*ut->ut_name == '\0' || 223 *ut->ut_line == '\0')) 224 continue; 225 /* Don't process entries that we have utmpx for */ 226 for (ep = ehead; ep != NULL; ep = ep->next) { 227 if (strncmp(ep->line, ut->ut_line, 228 sizeof(ut->ut_line)) == 0) 229 break; 230 } 231 if (ep != NULL) 232 continue; 233 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) { 234 warn(NULL); 235 return 0; 236 } 237 getentry(ep, ut); 238 *nextp = ep; 239 nextp = &(ep->next); 240 } 241 #endif 242 numutmp = 0; 243 #if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX) 244 if (ehead != NULL) { 245 struct utmpentry *from = ehead, *save; 246 247 ehead = NULL; 248 while (from != NULL) { 249 for (nextp = &ehead; 250 (*nextp) && strcmp(from->line, (*nextp)->line) > 0; 251 nextp = &(*nextp)->next) 252 continue; 253 save = from; 254 from = from->next; 255 save->next = *nextp; 256 *nextp = save; 257 numutmp++; 258 } 259 } 260 *epp = ehead; 261 return numutmp; 262 #else 263 *epp = NULL; 264 return 0; 265 #endif 266 } 267 268 #ifdef SUPPORT_UTMP 269 static void 270 getentry(struct utmpentry *e, struct utmp *up) 271 { 272 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); 273 e->name[sizeof(e->name) - 1] = '\0'; 274 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); 275 e->line[sizeof(e->line) - 1] = '\0'; 276 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); 277 e->name[sizeof(e->host) - 1] = '\0'; 278 e->tv.tv_sec = up->ut_time; 279 e->tv.tv_usec = 0; 280 adjust_size(e); 281 } 282 #endif 283 284 #ifdef SUPPORT_UTMPX 285 static void 286 getentryx(struct utmpentry *e, struct utmpx *up) 287 { 288 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); 289 e->name[sizeof(e->name) - 1] = '\0'; 290 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); 291 e->line[sizeof(e->line) - 1] = '\0'; 292 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); 293 e->name[sizeof(e->host) - 1] = '\0'; 294 e->tv = up->ut_tv; 295 adjust_size(e); 296 } 297 #endif 298