]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc/gen/getutxent.c
Remove __NO_TLS.
[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 static _Thread_local FILE *uf = NULL;
44 static _Thread_local int udb;
45
46 int
47 setutxdb(int db, const char *file)
48 {
49         struct stat sb;
50
51         switch (db) {
52         case UTXDB_ACTIVE:
53                 if (file == NULL)
54                         file = _PATH_UTX_ACTIVE;
55                 break;
56         case UTXDB_LASTLOGIN:
57                 if (file == NULL)
58                         file = _PATH_UTX_LASTLOGIN;
59                 break;
60         case UTXDB_LOG:
61                 if (file == NULL)
62                         file = _PATH_UTX_LOG;
63                 break;
64         default:
65                 errno = EINVAL;
66                 return (-1);
67         }
68
69         if (uf != NULL)
70                 fclose(uf);
71         uf = fopen(file, "re");
72         if (uf == NULL)
73                 return (-1);
74
75         if (db != UTXDB_LOG) {
76                 /* Safety check: never use broken files. */
77                 if (_fstat(fileno(uf), &sb) != -1 &&
78                     sb.st_size % sizeof(struct futx) != 0) {
79                         fclose(uf);
80                         uf = NULL;
81                         errno = EFTYPE;
82                         return (-1);
83                 }
84                 /* Prevent reading of partial records. */
85                 (void)setvbuf(uf, NULL, _IOFBF,
86                     rounddown(BUFSIZ, sizeof(struct futx)));
87         }
88
89         udb = db;
90         return (0);
91 }
92
93 void
94 setutxent(void)
95 {
96
97         setutxdb(UTXDB_ACTIVE, NULL);
98 }
99
100 void
101 endutxent(void)
102 {
103
104         if (uf != NULL) {
105                 fclose(uf);
106                 uf = NULL;
107         }
108 }
109
110 static int
111 getfutxent(struct futx *fu)
112 {
113
114         if (uf == NULL)
115                 setutxent();
116         if (uf == NULL)
117                 return (-1);
118
119         if (udb == UTXDB_LOG) {
120                 uint16_t len;
121
122 retry:
123                 if (fread(&len, sizeof(len), 1, uf) != 1)
124                         return (-1);
125                 len = be16toh(len);
126                 if (len == 0) {
127                         /*
128                          * XXX: Though zero-size records are valid in theory,
129                          * they can never occur in practice. Zero-size records
130                          * indicate file corruption. Seek one byte forward, to
131                          * see if we can find a record there.
132                          */
133                         ungetc('\0', uf);
134                         goto retry;
135                 }
136                 if (len > sizeof *fu) {
137                         /* Forward compatibility. */
138                         if (fread(fu, sizeof(*fu), 1, uf) != 1)
139                                 return (-1);
140                         fseek(uf, len - sizeof(*fu), SEEK_CUR);
141                 } else {
142                         /* Partial record. */
143                         memset(fu, 0, sizeof(*fu));
144                         if (fread(fu, len, 1, uf) != 1)
145                                 return (-1);
146                 }
147         } else {
148                 if (fread(fu, sizeof(*fu), 1, uf) != 1)
149                         return (-1);
150         }
151         return (0);
152 }
153
154 struct utmpx *
155 getutxent(void)
156 {
157         struct futx fu;
158
159         if (getfutxent(&fu) != 0)
160                 return (NULL);
161         return (futx_to_utx(&fu));
162 }
163
164 struct utmpx *
165 getutxid(const struct utmpx *id)
166 {
167         struct futx fu;
168
169         for (;;) {
170                 if (getfutxent(&fu) != 0)
171                         return (NULL);
172
173                 switch (fu.fu_type) {
174                 case USER_PROCESS:
175                 case INIT_PROCESS:
176                 case LOGIN_PROCESS:
177                 case DEAD_PROCESS:
178                         switch (id->ut_type) {
179                         case USER_PROCESS:
180                         case INIT_PROCESS:
181                         case LOGIN_PROCESS:
182                         case DEAD_PROCESS:
183                                 if (memcmp(fu.fu_id, id->ut_id,
184                                     MIN(sizeof(fu.fu_id), sizeof(id->ut_id))) ==
185                                     0)
186                                         goto found;
187                         }
188                         break;
189                 default:
190                         if (fu.fu_type == id->ut_type)
191                                 goto found;
192                         break;
193                 }
194         }
195
196 found:
197         return (futx_to_utx(&fu));
198 }
199
200 struct utmpx *
201 getutxline(const struct utmpx *line)
202 {
203         struct futx fu;
204
205         for (;;) {
206                 if (getfutxent(&fu) != 0)
207                         return (NULL);
208
209                 switch (fu.fu_type) {
210                 case USER_PROCESS:
211                 case LOGIN_PROCESS:
212                         if (strncmp(fu.fu_line, line->ut_line,
213                             MIN(sizeof(fu.fu_line), sizeof(line->ut_line))) ==
214                             0)
215                                 goto found;
216                         break;
217                 }
218         }
219
220 found:
221         return (futx_to_utx(&fu));
222 }
223
224 struct utmpx *
225 getutxuser(const char *user)
226 {
227         struct futx fu;
228
229         for (;;) {
230                 if (getfutxent(&fu) != 0)
231                         return (NULL);
232
233                 switch (fu.fu_type) {
234                 case USER_PROCESS:
235                         if (strncmp(fu.fu_user, user, sizeof(fu.fu_user)) == 0)
236                                 goto found;
237                         break;
238                 }
239         }
240
241 found:
242         return (futx_to_utx(&fu));
243 }