getutxent.c revision 233345
1294190Sdes/*- 2255581Sdes * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org> 3255581Sdes * All rights reserved. 4255581Sdes * 5255581Sdes * Redistribution and use in source and binary forms, with or without 6255581Sdes * modification, are permitted provided that the following conditions 7255581Sdes * are met: 8255581Sdes * 1. Redistributions of source code must retain the above copyright 9255581Sdes * notice, this list of conditions and the following disclaimer. 10255581Sdes * 2. Redistributions in binary form must reproduce the above copyright 11255581Sdes * notice, this list of conditions and the following disclaimer in the 12255581Sdes * documentation and/or other materials provided with the distribution. 13255581Sdes * 14255581Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15255581Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16255581Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17255581Sdes * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18255581Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19255581Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20255581Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21255581Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22255581Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23255581Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24255581Sdes * SUCH DAMAGE. 25255581Sdes */ 26255581Sdes 27285206Sdes#include <sys/cdefs.h> 28255581Sdes__FBSDID("$FreeBSD: head/lib/libc/gen/getutxent.c 233345 2012-03-23 08:26:31Z ed $"); 29255581Sdes 30255581Sdes#include "namespace.h" 31255581Sdes#include <sys/endian.h> 32255581Sdes#include <sys/param.h> 33255581Sdes#include <sys/stat.h> 34285206Sdes#include <errno.h> 35255581Sdes#include <stdio.h> 36255581Sdes#include <string.h> 37255581Sdes#include <utmpx.h> 38255581Sdes#include "utxdb.h" 39255581Sdes#include "un-namespace.h" 40255581Sdes 41255581Sdes#ifdef __NO_TLS 42255581Sdesstatic FILE *uf = NULL; 43255581Sdesstatic int udb; 44255581Sdes#else 45255581Sdesstatic _Thread_local FILE *uf = NULL; 46255581Sdesstatic _Thread_local int udb; 47255581Sdes#endif 48255581Sdes 49255581Sdesint 50255581Sdessetutxdb(int db, const char *file) 51255581Sdes{ 52255581Sdes struct stat sb; 53255581Sdes 54255581Sdes switch (db) { 55255581Sdes case UTXDB_ACTIVE: 56255581Sdes if (file == NULL) 57255581Sdes file = _PATH_UTX_ACTIVE; 58255581Sdes break; 59255581Sdes case UTXDB_LASTLOGIN: 60255581Sdes if (file == NULL) 61255581Sdes file = _PATH_UTX_LASTLOGIN; 62255581Sdes break; 63255581Sdes case UTXDB_LOG: 64255581Sdes if (file == NULL) 65255581Sdes file = _PATH_UTX_LOG; 66255581Sdes break; 67255581Sdes default: 68255581Sdes errno = EINVAL; 69255581Sdes return (-1); 70255581Sdes } 71255581Sdes 72255581Sdes if (uf != NULL) 73255581Sdes fclose(uf); 74255581Sdes uf = fopen(file, "r"); 75255581Sdes if (uf == NULL) 76255581Sdes return (-1); 77255581Sdes 78255581Sdes if (db != UTXDB_LOG) { 79255581Sdes /* Safety check: never use broken files. */ 80255581Sdes if (_fstat(fileno(uf), &sb) != -1 && 81255581Sdes sb.st_size % sizeof(struct futx) != 0) { 82255581Sdes fclose(uf); 83255581Sdes uf = NULL; 84255581Sdes errno = EFTYPE; 85255581Sdes return (-1); 86255581Sdes } 87255581Sdes /* Prevent reading of partial records. */ 88255581Sdes (void)setvbuf(uf, NULL, _IOFBF, 89255581Sdes rounddown(BUFSIZ, sizeof(struct futx))); 90255581Sdes } 91255581Sdes 92255581Sdes udb = db; 93255581Sdes return (0); 94255581Sdes} 95255581Sdes 96255581Sdesvoid 97255581Sdessetutxent(void) 98255581Sdes{ 99255581Sdes 100255581Sdes setutxdb(UTXDB_ACTIVE, NULL); 101255581Sdes} 102255581Sdes 103255581Sdesvoid 104255581Sdesendutxent(void) 105255581Sdes{ 106255581Sdes 107255581Sdes if (uf != NULL) { 108255581Sdes fclose(uf); 109255581Sdes uf = NULL; 110255581Sdes } 111255581Sdes} 112255581Sdes 113255581Sdesstatic int 114255581Sdesgetfutxent(struct futx *fu) 115255581Sdes{ 116255581Sdes 117255581Sdes if (uf == NULL) 118255581Sdes setutxent(); 119255581Sdes if (uf == NULL) 120255581Sdes return (-1); 121255581Sdes 122255581Sdes if (udb == UTXDB_LOG) { 123255581Sdes uint16_t len; 124255581Sdes 125255581Sdes if (fread(&len, sizeof(len), 1, uf) != 1) 126255581Sdes return (-1); 127255581Sdes len = be16toh(len); 128255581Sdes if (len > sizeof *fu) { 129255581Sdes /* Forward compatibility. */ 130255581Sdes if (fread(fu, sizeof(*fu), 1, uf) != 1) 131255581Sdes return (-1); 132255581Sdes fseek(uf, len - sizeof(*fu), SEEK_CUR); 133255581Sdes } else { 134255581Sdes /* Partial record. */ 135255581Sdes memset(fu, 0, sizeof(*fu)); 136255581Sdes if (fread(fu, len, 1, uf) != 1) 137255581Sdes return (-1); 138255581Sdes } 139255581Sdes } else { 140255581Sdes if (fread(fu, sizeof(*fu), 1, uf) != 1) 141285206Sdes return (-1); 142255581Sdes } 143255581Sdes return (0); 144255581Sdes} 145255581Sdes 146255581Sdesstruct utmpx * 147255581Sdesgetutxent(void) 148255581Sdes{ 149255581Sdes struct futx fu; 150255581Sdes 151255581Sdes if (getfutxent(&fu) != 0) 152255581Sdes return (NULL); 153255581Sdes return (futx_to_utx(&fu)); 154255581Sdes} 155255581Sdes 156255581Sdesstruct utmpx * 157255581Sdesgetutxid(const struct utmpx *id) 158255581Sdes{ 159255581Sdes struct futx fu; 160255581Sdes 161255581Sdes for (;;) { 162255581Sdes if (getfutxent(&fu) != 0) 163255581Sdes return (NULL); 164255581Sdes 165255581Sdes switch (fu.fu_type) { 166255581Sdes case USER_PROCESS: 167255581Sdes case INIT_PROCESS: 168255581Sdes case LOGIN_PROCESS: 169255581Sdes case DEAD_PROCESS: 170255581Sdes switch (id->ut_type) { 171255581Sdes case USER_PROCESS: 172255581Sdes case INIT_PROCESS: 173255581Sdes case LOGIN_PROCESS: 174255581Sdes case DEAD_PROCESS: 175255581Sdes if (memcmp(fu.fu_id, id->ut_id, 176 MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) == 177 0) 178 goto found; 179 } 180 break; 181 default: 182 if (fu.fu_type == id->ut_type) 183 goto found; 184 break; 185 } 186 } 187 188found: 189 return (futx_to_utx(&fu)); 190} 191 192struct utmpx * 193getutxline(const struct utmpx *line) 194{ 195 struct futx fu; 196 197 for (;;) { 198 if (getfutxent(&fu) != 0) 199 return (NULL); 200 201 switch (fu.fu_type) { 202 case USER_PROCESS: 203 case LOGIN_PROCESS: 204 if (strncmp(fu.fu_line, line->ut_line, 205 MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) == 206 0) 207 goto found; 208 break; 209 } 210 } 211 212found: 213 return (futx_to_utx(&fu)); 214} 215 216struct utmpx * 217getutxuser(const char *user) 218{ 219 struct futx fu; 220 221 for (;;) { 222 if (getfutxent(&fu) != 0) 223 return (NULL); 224 225 switch (fu.fu_type) { 226 case USER_PROCESS: 227 if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0) 228 goto found; 229 break; 230 } 231 } 232 233found: 234 return (futx_to_utx(&fu)); 235} 236