1 /* $NetBSD: utmpentry.c,v 1.4 2003/02/12 17:39:36 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.4 2003/02/12 17:39:36 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 98 if (fname == NULL) { 99 #ifdef SUPPORT_UTMPX 100 setutxent(); 101 #endif 102 #ifdef SUPPORT_UTMP 103 setutent(); 104 #endif 105 } else { 106 size_t len = strlen(fname); 107 if (len == 0) 108 errx(1, "Filename cannot be 0 length."); 109 what = fname[len - 1] == 'x' ? 1 : 2; 110 if (what == 1) { 111 #ifdef SUPPORT_UTMPX 112 if (utmpxname(fname) == 0) 113 err(1, "Cannot open `%s'", fname); 114 #else 115 errx(1, "utmpx support not compiled in"); 116 #endif 117 } else { 118 #ifdef SUPPORT_UTMP 119 if (utmpname(fname) == 0) 120 err(1, "Cannot open `%s'", fname); 121 #else 122 errx(1, "utmp support not compiled in"); 123 #endif 124 } 125 } 126 #ifdef SUPPORT_UTMPX 127 if (what & 1) { 128 (void)stat(fname ? fname : _PATH_UTMPX, &st); 129 if (st.st_mtime > utmpxtime) 130 utmpxtime = st.st_mtime; 131 else 132 what &= ~1; 133 } 134 #endif 135 #ifdef SUPPORT_UTMP 136 if (what & 2) { 137 (void)stat(fname ? fname : _PATH_UTMP, &st); 138 if (st.st_mtime > utmptime) 139 utmptime = st.st_mtime; 140 else 141 what &= ~2; 142 } 143 #endif 144 145 return what; 146 } 147 #endif 148 149 void 150 freeutentries(struct utmpentry *ep) 151 { 152 #ifdef SUPPORT_UTMP 153 utmptime = 0; 154 #endif 155 #ifdef SUPPORT_UTMPX 156 utmpxtime = 0; 157 #endif 158 if (ep == ehead) { 159 ehead = NULL; 160 numutmp = 0; 161 } 162 while (ep) { 163 struct utmpentry *sep = ep; 164 ep = ep->next; 165 free(sep); 166 } 167 } 168 169 int 170 getutentries(const char *fname, struct utmpentry **epp) 171 { 172 #ifdef SUPPORT_UTMPX 173 struct utmpx *utx; 174 #endif 175 #ifdef SUPPORT_UTMP 176 struct utmp *ut; 177 #endif 178 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX) 179 struct utmpentry *ep; 180 int what = setup(fname); 181 struct utmpentry **nextp = &ehead; 182 if (what == 0) { 183 *epp = ehead; 184 return numutmp; 185 } else { 186 ehead = NULL; 187 numutmp = 0; 188 } 189 #endif 190 191 #ifdef SUPPORT_UTMPX 192 while ((what & 1) && (utx = getutxent()) != NULL) { 193 if (fname == NULL && utx->ut_type != USER_PROCESS) 194 continue; 195 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) 196 err(1, NULL); 197 getentryx(ep, utx); 198 *nextp = ep; 199 nextp = &(ep->next); 200 } 201 #endif 202 203 #ifdef SUPPORT_UTMP 204 while ((what & 2) && (ut = getutent()) != NULL) { 205 if (fname == NULL && (*ut->ut_name == '\0' || 206 *ut->ut_line == '\0')) 207 continue; 208 /* Don't process entries that we have utmpx for */ 209 for (ep = ehead; ep != NULL; ep = ep->next) { 210 if (strncmp(ep->line, ut->ut_line, 211 sizeof(ut->ut_line)) == 0) 212 break; 213 } 214 if (ep != NULL) 215 continue; 216 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) 217 err(1, NULL); 218 getentry(ep, ut); 219 *nextp = ep; 220 nextp = &(ep->next); 221 } 222 #endif 223 numutmp = 0; 224 #if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX) 225 if (ehead != NULL) { 226 struct utmpentry *from = ehead, *save; 227 228 ehead = NULL; 229 while (from != NULL) { 230 for (nextp = &ehead; 231 (*nextp) && strcmp(from->line, (*nextp)->line) > 0; 232 nextp = &(*nextp)->next) 233 continue; 234 save = from; 235 from = from->next; 236 save->next = *nextp; 237 *nextp = save; 238 numutmp++; 239 } 240 } 241 *epp = ehead; 242 return numutmp; 243 #else 244 *epp = NULL; 245 return 0; 246 #endif 247 } 248 249 #ifdef SUPPORT_UTMP 250 static void 251 getentry(struct utmpentry *e, struct utmp *up) 252 { 253 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); 254 e->name[sizeof(e->name) - 1] = '\0'; 255 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); 256 e->line[sizeof(e->line) - 1] = '\0'; 257 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); 258 e->name[sizeof(e->host) - 1] = '\0'; 259 e->tv.tv_sec = up->ut_time; 260 e->tv.tv_usec = 0; 261 adjust_size(e); 262 } 263 #endif 264 265 #ifdef SUPPORT_UTMPX 266 static void 267 getentryx(struct utmpentry *e, struct utmpx *up) 268 { 269 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); 270 e->name[sizeof(e->name) - 1] = '\0'; 271 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); 272 e->line[sizeof(e->line) - 1] = '\0'; 273 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); 274 e->name[sizeof(e->host) - 1] = '\0'; 275 e->tv = up->ut_tv; 276 adjust_size(e); 277 } 278 #endif 279