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