1 /*
2 * Copyright (c) 2004 Gunnar Ritter
3 *
4 * This software is provided 'as-is', without any express or implied
5 * warranty. In no event will the authors be held liable for any damages
6 * arising from the use of this software.
7 *
8 * Permission is granted to anyone to use this software for any purpose,
9 * including commercial applications, and to alter it and redistribute
10 * it freely, subject to the following restrictions:
11 *
12 * 1. The origin of this software must not be misrepresented; you must not
13 * claim that you wrote the original software. If you use this software
14 * in a product, an acknowledgment in the product documentation would be
15 * appreciated but is not required.
16 *
17 * 2. Altered source versions must be plainly marked as such, and must not be
18 * misrepresented as being the original software.
19 *
20 * 3. This notice may not be removed or altered from any source distribution.
21 */
22 /* Sccsid @(#)utmpx.c 1.12 (gritter) 1/22/06 */
23
24 #include <stdio.h>
25
26 #if defined (__FreeBSD__) || defined (__dietlibc__) || defined (__NetBSD__) || \
27 defined (__UCLIBC__) || defined (__OpenBSD__) || \
28 defined (__DragonFly__) || defined (__APPLE__)
29 #include <sys/types.h>
30 #include <sys/time.h>
31 #include <string.h>
32
33 #include "utmpx.h"
34
35 static FILE *utfp;
36 static struct utmpx utx;
37 static const char *utmpfile = NULL;
38
39 #include <sys/param.h>
40 #if !(defined(__FreeBSD__) && __FreeBSD_version >= 900007) && !defined(__DragonFly__)
41
42 static FILE *
init(void)43 init(void)
44 {
45 if (utfp == NULL && (utfp = fopen(utmpfile, "r+")) == NULL)
46 if ((utfp = fopen(utmpfile, "r")) == NULL)
47 return NULL;
48 return utfp;
49 }
50
51 static struct utmpx *
utmp2utmpx(struct utmpx * ux,const struct utmp * up)52 utmp2utmpx(struct utmpx *ux, const struct utmp *up)
53 {
54 #ifndef __dietlibc__
55 memset(ux, 0, sizeof *ux);
56 ux->ut_tv.tv_sec = up->ut_time;
57 memcpy(ux->ut_line, up->ut_line, UT_LINESIZE);
58 memcpy(ux->ut_user, up->ut_name, UT_NAMESIZE);
59 memcpy(ux->ut_host, up->ut_host, UT_HOSTSIZE);
60 if (strcmp(up->ut_line, "~") == 0)
61 ux->ut_type = BOOT_TIME;
62 else if (strcmp(up->ut_line, "|") == 0)
63 ux->ut_type = OLD_TIME;
64 else if (strcmp(up->ut_line, "}") == 0)
65 ux->ut_type = NEW_TIME;
66 else if (*up->ut_name == 0)
67 ux->ut_type = DEAD_PROCESS;
68 else
69 ux->ut_type = USER_PROCESS;
70 #else /* __dietlibc__ */
71 *ux = *up;
72 #endif /* __dietlibc__ */
73 return ux;
74 }
75
76 static struct utmp *
utmpx2utmp(struct utmp * up,const struct utmpx * ux)77 utmpx2utmp(struct utmp *up, const struct utmpx *ux)
78 {
79 #ifndef __dietlibc__
80 memset(up, 0, sizeof *up);
81 up->ut_time = ux->ut_tv.tv_sec;
82 switch (ux->ut_type) {
83 case DEAD_PROCESS:
84 memcpy(up->ut_line, ux->ut_line, UT_LINESIZE);
85 break;
86 default:
87 case EMPTY:
88 case INIT_PROCESS:
89 case LOGIN_PROCESS:
90 case RUN_LVL:
91 case ACCOUNTING:
92 return NULL;
93 case BOOT_TIME:
94 strcpy(up->ut_name, "reboot");
95 strcpy(up->ut_line, "~");
96 break;
97 case OLD_TIME:
98 strcpy(up->ut_name, "date");
99 strcpy(up->ut_line, "|");
100 break;
101 case NEW_TIME:
102 strcpy(up->ut_name, "date");
103 strcpy(up->ut_line, "{");
104 break;
105 case USER_PROCESS:
106 memcpy(up->ut_line, ux->ut_line, UT_LINESIZE);
107 memcpy(up->ut_name, ux->ut_user, UT_NAMESIZE);
108 memcpy(up->ut_host, ux->ut_host, UT_HOSTSIZE);
109 }
110 #else /* __dietlibc__ */
111 *up = *ux;
112 #endif /* __dietlibc__ */
113 return up;
114 }
115
116 struct utmpx *
getutxent(void)117 getutxent(void)
118 {
119 static struct utmp zero;
120 struct utmp ut;
121
122 if (init() == NULL)
123 return NULL;
124 do {
125 if (fread(&ut, sizeof ut, 1, utfp) != 1)
126 return NULL;
127 } while (memcmp(&ut, &zero, sizeof ut) == 0);
128 return utmp2utmpx(&utx, &ut);
129 }
130
131 struct utmpx *
getutxline(const struct utmpx * ux)132 getutxline(const struct utmpx *ux)
133 {
134 struct utmp ut;
135
136 if (init() == NULL)
137 return NULL;
138 fseek(utfp, 0, SEEK_SET);
139 while (fread(&ut, sizeof ut, 1, utfp) == 1) {
140 utmp2utmpx(&utx, &ut);
141 if ((utx.ut_type == LOGIN_PROCESS ||
142 utx.ut_type == USER_PROCESS) &&
143 strcmp(ut.ut_line, utx.ut_line) == 0)
144 return &utx;
145 }
146 return NULL;
147 }
148
149 struct utmpx *
getutxid(const struct utmpx * ux)150 getutxid(const struct utmpx *ux)
151 {
152 #ifdef __dietlibc__
153 struct utmp ut;
154 #endif
155
156 if (init() == NULL)
157 return NULL;
158 #ifdef __dietlibc__
159 fseek(utfp, 0, SEEK_SET);
160 while (fread(&ut, sizeof ut, 1, utfp) == 1) {
161 utmp2utmpx(&utx, &ut);
162 switch (ux->ut_type) {
163 case BOOT_TIME:
164 case OLD_TIME:
165 case NEW_TIME:
166 if (ux->ut_type == utx.ut_type)
167 return &utx;
168 break;
169 case INIT_PROCESS:
170 case LOGIN_PROCESS:
171 case USER_PROCESS:
172 case DEAD_PROCESS:
173 if (ux->ut_type == utx.ut_type &&
174 ux->ut_id == utx.ut_id)
175 return &utx;
176 break;
177 }
178 }
179 #endif /* __dietlibc__ */
180 return NULL;
181 }
182
183 void
setutxent(void)184 setutxent(void)
185 {
186 if (init() == NULL)
187 return;
188 fseek(utfp, 0, SEEK_SET);
189 }
190
191 void
endutxent(void)192 endutxent(void)
193 {
194 FILE *fp;
195
196 if (init() == NULL)
197 return;
198 fp = utfp;
199 utfp = NULL;
200 fclose(fp);
201 }
202
203 extern struct utmpx *
pututxline(const struct utmpx * up)204 pututxline(const struct utmpx *up)
205 {
206 struct utmp ut;
207 struct utmpx *rp;
208
209 if (init() == NULL)
210 return NULL;
211 /*
212 * Cannot use getutxid() because there is no id field. Use
213 * the equivalent of getutxline() instead.
214 */
215 while (fread(&ut, sizeof ut, 1, utfp) == 1) {
216 if (strncmp(ut.ut_line, up->ut_line, UT_LINESIZE) == 0) {
217 fseek(utfp, -sizeof ut, SEEK_CUR);
218 break;
219 }
220 }
221 fflush(utfp);
222 if (utmpx2utmp(&ut, up) == NULL)
223 rp = NULL;
224 else if (fwrite(&ut, sizeof ut, 1, utfp) == 1) {
225 utx = *up;
226 rp = &utx;
227 } else
228 rp = NULL;
229 fflush(utfp);
230 return rp;
231 }
232
233 #endif /*!__FreeBSD__ && __FreeBSD_version >= 900007*/
234
235 int
utmpxname(const char * name)236 utmpxname(const char *name)
237 {
238 utmpfile = strdup(name);
239 return 0;
240 }
241
242 extern void
updwtmpx(const char * name,const struct utmpx * up)243 updwtmpx(const char *name, const struct utmpx *up)
244 {
245 FILE *fp;
246
247 if ((fp = fopen(name, "a")) == NULL)
248 return;
249 fwrite(up, sizeof *up, 1, fp);
250 fclose(fp);
251 }
252
253 #endif /* __FreeBSD__ || __dietlibc__ || __NetBSD__ || __UCLIBC__ ||
254 __OpenBSD__ || __DragonFly__ || __APPLE__ */
255