utmpx.c revision 1.1 1 /* $NetBSD: utmpx.c,v 1.1 2002/02/22 20:11:44 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 #include <sys/cdefs.h>
39
40 #if defined(LIBC_SCCS) && !defined(lint)
41 __RCSID("$NetBSD: utmpx.c,v 1.1 2002/02/22 20:11:44 christos Exp $");
42 #endif /* LIBC_SCCS and not lint */
43
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/wait.h>
47 #include <sys/socket.h>
48 #include <sys/time.h>
49 #include <sys/stat.h>
50
51 #include <stdio.h>
52 #include <string.h>
53 #include <vis.h>
54 #include <utmpx.h>
55 #include <unistd.h>
56
57 static FILE *fp;
58 static struct utmpx ut;
59 static char utfile[MAXPATHLEN] = _PATH_UTMPX;
60
61 static struct utmpx *utmp_update(const struct utmpx *);
62
63 static const char vers[] = "utmpx-1.00";
64
65 void
66 setutxent()
67 {
68 (void)memset(&ut, 0, sizeof(ut));
69 if (fp == NULL)
70 return;
71 (void)fseeko(fp, (off_t)sizeof(ut), SEEK_SET);
72 }
73
74
75 void
76 endutxent()
77 {
78 (void)memset(&ut, 0, sizeof(ut));
79 if (fp != NULL)
80 (void)fclose(fp);
81 }
82
83
84 struct utmpx *
85 getutxent()
86 {
87 if (fp == NULL) {
88 struct stat st;
89
90 if ((fp = fopen(utfile, "r+")) == NULL)
91 if ((fp = fopen(utfile, "r")) == NULL)
92 goto fail;
93
94 /* get file size in order to check if new file */
95 if (fstat(fileno(fp), &st) == -1)
96 goto failclose;
97
98 if (st.st_size == 0) {
99 /* new file, add signature record */
100 (void)memset(&ut, 0, sizeof(ut));
101 ut.ut_type = SIGNATURE;
102 (void)memcpy(ut.ut_name, vers, sizeof(vers));
103 if (fwrite(&ut, sizeof(ut), 1, fp) != sizeof(ut))
104 goto failclose;
105 } else {
106 /* old file, read signature record */
107 if (fread(&ut, sizeof(ut), 1, fp) != sizeof(ut))
108 goto failclose;
109 if (memcmp(ut.ut_name, vers, sizeof(vers)) != 0 ||
110 ut.ut_type != SIGNATURE)
111 goto failclose;
112 }
113 }
114
115 if (fread(&ut, sizeof(ut), 1, fp) != sizeof(ut))
116 goto fail;
117
118 return &ut;
119 failclose:
120 (void)fclose(fp);
121 fail:
122 (void)memset(&ut, 0, sizeof(ut));
123 return NULL;
124 }
125
126
127 struct utmpx *
128 getutxid(const struct utmpx *utx)
129 {
130 if (utx->ut_type == EMPTY)
131 return NULL;
132
133 do {
134 if (ut.ut_type == EMPTY)
135 continue;
136 switch (utx->ut_type) {
137 case EMPTY:
138 return NULL;
139 case RUN_LVL:
140 case BOOT_TIME:
141 case OLD_TIME:
142 case NEW_TIME:
143 if (ut.ut_type == utx->ut_type)
144 return &ut;
145 break;
146 case INIT_PROCESS:
147 case LOGIN_PROCESS:
148 case USER_PROCESS:
149 case DEAD_PROCESS:
150 switch (ut.ut_type) {
151 case INIT_PROCESS:
152 case LOGIN_PROCESS:
153 case USER_PROCESS:
154 case DEAD_PROCESS:
155 if (memcmp(ut.ut_id, utx->ut_id,
156 sizeof(ut.ut_id)) == 0)
157 return &ut;
158 break;
159 default:
160 break;
161 }
162 break;
163 default:
164 return NULL;
165 }
166 }
167 while (getutxent() != NULL);
168 return NULL;
169 }
170
171
172 struct utmpx *
173 getutxline(const struct utmpx *utx)
174 {
175 do {
176 switch (ut.ut_type) {
177 case EMPTY:
178 break;
179 case LOGIN_PROCESS:
180 case USER_PROCESS:
181 if (strncmp(ut.ut_line, utx->ut_line,
182 sizeof(ut.ut_line)) == 0)
183 return &ut;
184 break;
185 default:
186 break;
187 }
188 }
189 while (getutxent() != NULL);
190 return NULL;
191 }
192
193
194 struct utmpx *
195 pututxline(const struct utmpx *utx)
196 {
197 struct utmpx temp, *u = NULL;
198 int gotlock = 0;
199
200 if (strcmp(_PATH_UTMPX, utfile) == 0 && geteuid() != 0)
201 return utmp_update(utx);
202
203 if (utx == NULL)
204 return NULL;
205
206 (void)memcpy(&temp, utx, sizeof(temp));
207
208 if (fp == NULL) {
209 (void)getutxent();
210 if (fp == NULL)
211 return NULL;
212 }
213
214 if (getutxid(&temp) == NULL) {
215 setutxent();
216 if (getutxid(&temp) == NULL) {
217 if (lockf(fileno(fp), F_LOCK, (off_t)0) == -1)
218 return NULL;
219 gotlock++;
220 if (fseeko(fp, (off_t)0, SEEK_END) == -1)
221 goto fail;
222 }
223 }
224
225 if (!gotlock) {
226 /* we are not appending */
227 if (fseeko(fp, -(off_t)sizeof(ut), SEEK_CUR) == -1)
228 return NULL;
229 }
230
231 if (fwrite(&temp, sizeof (temp), 1, fp) != 1)
232 goto fail;
233
234 if (fflush(fp) == -1)
235 goto fail;
236
237 u = memcpy(&ut, &temp, sizeof(ut));
238 fail:
239 if (gotlock) {
240 if (lockf(fileno(fp), F_ULOCK, (off_t)0) == -1)
241 return NULL;
242 }
243 return u;
244 }
245
246
247 static struct utmpx *
248 utmp_update(const struct utmpx *utx)
249 {
250 char buf[sizeof(*utx) * 4 + 1];
251 pid_t pid;
252 int status;
253
254 (void)strvisx(buf, (const char *)(const void *)utx, sizeof(*utx),
255 VIS_WHITE);
256 switch (pid = fork()) {
257 case 0:
258 (void)execl(_PATH_UTMP_UPDATE,
259 strrchr(_PATH_UTMP_UPDATE, '/') + 1, buf);
260 exit(1);
261 /*NOTREACHED*/
262 case -1:
263 return NULL;
264 default:
265 if (waitpid(pid, &status, 0) == -1)
266 return NULL;
267 if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
268 return memcpy(&ut, utx, sizeof(ut));
269 return NULL;
270 }
271
272 }
273
274
275 /*
276 * The following are extensions and not part of the X/Open spec
277 */
278 int
279 utmpxname(const char *fname)
280 {
281 size_t len = strlen(fname);
282
283 if (len >= sizeof(utfile))
284 return 0;
285
286 /* must end in x! */
287 if (fname[len - 1] != 'x')
288 return 0;
289
290 (void)strcpy(utfile, fname);
291 endutxent();
292 return 1;
293 }
294