]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/getutxent.c
Import DTS includes from 4.19
[FreeBSD/FreeBSD.git] / lib / libc / gen / getutxent.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include "namespace.h"
33 #include <sys/endian.h>
34 #include <sys/param.h>
35 #include <sys/stat.h>
36 #include <errno.h>
37 #include <stdio.h>
38 #include <string.h>
39 #include <utmpx.h>
40 #include "utxdb.h"
41 #include "un-namespace.h"
42
43 #ifdef __NO_TLS
44 static FILE *uf = NULL;
45 static int udb;
46 #else
47 static _Thread_local FILE *uf = NULL;
48 static _Thread_local int udb;
49 #endif
50
51 int
52 setutxdb(int db, const char *file)
53 {
54         struct stat sb;
55
56         switch (db) {
57         case UTXDB_ACTIVE:
58                 if (file == NULL)
59                         file = _PATH_UTX_ACTIVE;
60                 break;
61         case UTXDB_LASTLOGIN:
62                 if (file == NULL)
63                         file = _PATH_UTX_LASTLOGIN;
64                 break;
65         case UTXDB_LOG:
66                 if (file == NULL)
67                         file = _PATH_UTX_LOG;
68                 break;
69         default:
70                 errno = EINVAL;
71                 return (-1);
72         }
73
74         if (uf != NULL)
75                 fclose(uf);
76         uf = fopen(file, "re");
77         if (uf == NULL)
78                 return (-1);
79
80         if (db != UTXDB_LOG) {
81                 /* Safety check: never use broken files. */
82                 if (_fstat(fileno(uf), &sb) != -1 &&
83                     sb.st_size % sizeof(struct futx) != 0) {
84                         fclose(uf);
85                         uf = NULL;
86                         errno = EFTYPE;
87                         return (-1);
88                 }
89                 /* Prevent reading of partial records. */
90                 (void)setvbuf(uf, NULL, _IOFBF,
91                     rounddown(BUFSIZ, sizeof(struct futx)));
92         }
93
94         udb = db;
95         return (0);
96 }
97
98 void
99 setutxent(void)
100 {
101
102         setutxdb(UTXDB_ACTIVE, NULL);
103 }
104
105 void
106 endutxent(void)
107 {
108
109         if (uf != NULL) {
110                 fclose(uf);
111                 uf = NULL;
112         }
113 }
114
115 static int
116 getfutxent(struct futx *fu)
117 {
118
119         if (uf == NULL)
120                 setutxent();
121         if (uf == NULL)
122                 return (-1);
123
124         if (udb == UTXDB_LOG) {
125                 uint16_t len;
126
127 retry:
128                 if (fread(&len, sizeof(len), 1, uf) != 1)
129                         return (-1);
130                 len = be16toh(len);
131                 if (len == 0) {
132                         /*
133                          * XXX: Though zero-size records are valid in theory,
134                          * they can never occur in practice. Zero-size records
135                          * indicate file corruption. Seek one byte forward, to
136                          * see if we can find a record there.
137                          */
138                         ungetc('\0', uf);
139                         goto retry;
140                 }
141                 if (len > sizeof *fu) {
142                         /* Forward compatibility. */
143                         if (fread(fu, sizeof(*fu), 1, uf) != 1)
144                                 return (-1);
145                         fseek(uf, len - sizeof(*fu), SEEK_CUR);
146                 } else {
147                         /* Partial record. */
148                         memset(fu, 0, sizeof(*fu));
149                         if (fread(fu, len, 1, uf) != 1)
150                                 return (-1);
151                 }
152         } else {
153                 if (fread(fu, sizeof(*fu), 1, uf) != 1)
154                         return (-1);
155         }
156         return (0);
157 }
158
159 struct utmpx *
160 getutxent(void)
161 {
162         struct futx fu;
163
164         if (getfutxent(&fu) != 0)
165                 return (NULL);
166         return (futx_to_utx(&fu));
167 }
168
169 struct utmpx *
170 getutxid(const struct utmpx *id)
171 {
172         struct futx fu;
173
174         for (;;) {
175                 if (getfutxent(&fu) != 0)
176                         return (NULL);
177
178                 switch (fu.fu_type) {
179                 case USER_PROCESS:
180                 case INIT_PROCESS:
181                 case LOGIN_PROCESS:
182                 case DEAD_PROCESS:
183                         switch (id->ut_type) {
184                         case USER_PROCESS:
185                         case INIT_PROCESS:
186                         case LOGIN_PROCESS:
187                         case DEAD_PROCESS:
188                                 if (memcmp(fu.fu_id, id->ut_id,
189                                     MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
190                                     0)
191                                         goto found;
192                         }
193                         break;
194                 default:
195                         if (fu.fu_type == id->ut_type)
196                                 goto found;
197                         break;
198                 }
199         }
200
201 found:
202         return (futx_to_utx(&fu));
203 }
204
205 struct utmpx *
206 getutxline(const struct utmpx *line)
207 {
208         struct futx fu;
209
210         for (;;) {
211                 if (getfutxent(&fu) != 0)
212                         return (NULL);
213
214                 switch (fu.fu_type) {
215                 case USER_PROCESS:
216                 case LOGIN_PROCESS:
217                         if (strncmp(fu.fu_line, line->ut_line,
218                             MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
219                             0)
220                                 goto found;
221                         break;
222                 }
223         }
224
225 found:
226         return (futx_to_utx(&fu));
227 }
228
229 struct utmpx *
230 getutxuser(const char *user)
231 {
232         struct futx fu;
233
234         for (;;) {
235                 if (getfutxent(&fu) != 0)
236                         return (NULL);
237
238                 switch (fu.fu_type) {
239                 case USER_PROCESS:
240                         if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0)
241                                 goto found;
242                         break;
243                 }
244         }
245
246 found:
247         return (futx_to_utx(&fu));
248 }