1 /* $NetBSD: utmpentry.c,v 1.3 2002/08/01 23:51:42 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.3 2002/08/01 23:51:42 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 if (ep == ehead) { 153 ehead = NULL; 154 numutmp = 0; 155 } 156 while (ep) { 157 struct utmpentry *sep = ep; 158 ep = ep->next; 159 free(sep); 160 } 161 } 162 163 int 164 getutentries(const char *fname, struct utmpentry **epp) 165 { 166 #ifdef SUPPORT_UTMPX 167 struct utmpx *utx; 168 #endif 169 #ifdef SUPPORT_UTMP 170 struct utmp *ut; 171 #endif 172 #if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX) 173 struct utmpentry *ep; 174 int what = setup(fname); 175 struct utmpentry **nextp = &ehead; 176 if (what == 0) { 177 *epp = ehead; 178 return numutmp; 179 } else { 180 ehead = NULL; 181 numutmp = 0; 182 } 183 #endif 184 185 #ifdef SUPPORT_UTMPX 186 while ((what & 1) && (utx = getutxent()) != NULL) { 187 if (fname == NULL && utx->ut_type != USER_PROCESS) 188 continue; 189 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) 190 err(1, NULL); 191 getentryx(ep, utx); 192 *nextp = ep; 193 nextp = &(ep->next); 194 } 195 #endif 196 197 #ifdef SUPPORT_UTMP 198 while ((what & 2) && (ut = getutent()) != NULL) { 199 if (fname == NULL && (*ut->ut_name == '\0' || 200 *ut->ut_line == '\0')) 201 continue; 202 /* Don't process entries that we have utmpx for */ 203 for (ep = ehead; ep != NULL; ep = ep->next) { 204 if (strncmp(ep->line, ut->ut_line, 205 sizeof(ut->ut_line)) == 0) 206 break; 207 } 208 if (ep != NULL) 209 continue; 210 if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) 211 err(1, NULL); 212 getentry(ep, ut); 213 *nextp = ep; 214 nextp = &(ep->next); 215 } 216 #endif 217 numutmp = 0; 218 #if defined(SUPPORT_UTMP) && defined(SUPPORT_UTMPX) 219 if (ehead != NULL) { 220 struct utmpentry *from = ehead, *save; 221 222 ehead = NULL; 223 while (from != NULL) { 224 for (nextp = &ehead; 225 (*nextp) && strcmp(from->line, (*nextp)->line) > 0; 226 nextp = &(*nextp)->next) 227 continue; 228 save = from; 229 from = from->next; 230 save->next = *nextp; 231 *nextp = save; 232 numutmp++; 233 } 234 } 235 *epp = ehead; 236 return numutmp; 237 #else 238 *epp = NULL; 239 return 0; 240 #endif 241 } 242 243 #ifdef SUPPORT_UTMP 244 static void 245 getentry(struct utmpentry *e, struct utmp *up) 246 { 247 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); 248 e->name[sizeof(e->name) - 1] = '\0'; 249 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); 250 e->line[sizeof(e->line) - 1] = '\0'; 251 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); 252 e->name[sizeof(e->host) - 1] = '\0'; 253 e->tv.tv_sec = up->ut_time; 254 e->tv.tv_usec = 0; 255 adjust_size(e); 256 } 257 #endif 258 259 #ifdef SUPPORT_UTMPX 260 static void 261 getentryx(struct utmpentry *e, struct utmpx *up) 262 { 263 (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name)); 264 e->name[sizeof(e->name) - 1] = '\0'; 265 (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line)); 266 e->line[sizeof(e->line) - 1] = '\0'; 267 (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host)); 268 e->name[sizeof(e->host) - 1] = '\0'; 269 e->tv = up->ut_tv; 270 adjust_size(e); 271 } 272 #endif 273