]>
Commit | Line | Data |
---|---|---|
7ba4fcfc | 1 | /* Tests for UTMP functions. |
f128331c | 2 | Copyright (C) 1998, 2001 Free Software Foundation, Inc. |
41bdb6e2 | 3 | This file is part of the GNU C Library. |
7ba4fcfc UD |
4 | Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1998. |
5 | ||
6 | The GNU C Library is free software; you can redistribute it and/or | |
41bdb6e2 AJ |
7 | modify it under the terms of the GNU Lesser General Public |
8 | License as published by the Free Software Foundation; either | |
9 | version 2.1 of the License, or (at your option) any later version. | |
7ba4fcfc UD |
10 | |
11 | The GNU C Library is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
41bdb6e2 | 14 | Lesser General Public License for more details. |
7ba4fcfc | 15 | |
41bdb6e2 AJ |
16 | You should have received a copy of the GNU Lesser General Public |
17 | License along with the GNU C Library; if not, write to the Free | |
18 | Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |
19 | 02111-1307 USA. */ | |
7ba4fcfc UD |
20 | |
21 | #include <errno.h> | |
22 | #include <error.h> | |
23 | #include <stdlib.h> | |
24 | #include <string.h> | |
25 | #include <sys/types.h> | |
26 | #include <time.h> | |
27 | ||
28 | #ifdef UTMPX | |
29 | # include <utmpx.h> | |
30 | # define utmp utmpx | |
31 | # define utmpname utmpxname | |
32 | # define setutent setutxent | |
33 | # define getutent getutxent | |
34 | # define endutent endutxent | |
35 | # define getutline getutxline | |
36 | # define getutid getutxid | |
37 | # define pututline pututxline | |
38 | #else | |
39 | # include <utmp.h> | |
40 | #endif | |
41 | ||
42 | ||
43 | /* Prototype for our test function. */ | |
44 | static int do_test (int argc, char *argv[]); | |
45 | ||
46 | /* We have a preparation function. */ | |
47 | static void do_prepare (int argc, char *argv[]); | |
48 | #define PREPARE do_prepare | |
49 | ||
50 | /* This defines the `main' function and some more. */ | |
51 | #include <test-skeleton.c> | |
52 | ||
53 | ||
54 | /* These are for the temporary file we generate. */ | |
55 | char *name; | |
56 | int fd; | |
57 | ||
58 | static void | |
59 | do_prepare (int argc, char *argv[]) | |
60 | { | |
61 | size_t name_len; | |
62 | ||
63 | name_len = strlen (test_dir); | |
64 | name = malloc (name_len + sizeof ("/utmpXXXXXX")); | |
65 | mempcpy (mempcpy (name, test_dir, name_len), | |
66 | "/utmpXXXXXX", sizeof ("/utmpXXXXXX")); | |
67 | add_temp_file (name); | |
68 | ||
69 | /* Open our test file. */ | |
70 | fd = mkstemp (name); | |
71 | if (fd == -1) | |
72 | error (EXIT_FAILURE, errno, "cannot open test file `%s'", name); | |
73 | } | |
74 | ||
7ba4fcfc UD |
75 | struct utmp entry[] = |
76 | { | |
f128331c | 77 | #if _HAVE_UT_TV || defined UTMPX |
46894673 UD |
78 | #define UT(a) ut_tv:{tv_sec:(a)} |
79 | #else | |
80 | #define UT(a) ut_time:(a) | |
81 | #endif | |
82 | ||
83 | { ut_type: BOOT_TIME, ut_pid: 1, UT(1000) }, | |
84 | { ut_type: RUN_LVL, ut_pid: 1, UT(2000) }, | |
85 | { ut_type: INIT_PROCESS, ut_pid: 5, ut_id: "si", UT(3000) }, | |
7ba4fcfc | 86 | { ut_type: LOGIN_PROCESS, ut_pid: 23, ut_line: "tty1", ut_id: "1", |
46894673 | 87 | ut_user: "LOGIN", UT(4000) }, |
7ba4fcfc | 88 | { ut_type: USER_PROCESS, ut_pid: 24, ut_line: "tty2", ut_id: "2", |
46894673 | 89 | ut_user: "albert", UT(8000) }, |
7ba4fcfc | 90 | { ut_type: USER_PROCESS, ut_pid: 196, ut_line: "ttyp0", ut_id: "p0", |
46894673 UD |
91 | ut_user: "niels", UT(10000) }, |
92 | { ut_type: DEAD_PROCESS, ut_line: "ttyp1", ut_id: "p1", UT(16000) }, | |
7ba4fcfc UD |
93 | { ut_type: EMPTY }, |
94 | { ut_type: EMPTY } | |
95 | }; | |
96 | int num_entries = sizeof entry / sizeof (struct utmp); | |
97 | ||
98 | time_t entry_time = 20000; | |
99 | pid_t entry_pid = 234; | |
100 | ||
101 | static int | |
102 | do_init (void) | |
103 | { | |
104 | int n; | |
105 | ||
106 | setutent (); | |
107 | ||
108 | for (n = 0; n < num_entries; n++) | |
109 | { | |
110 | if (pututline (&entry[n]) == NULL) | |
111 | { | |
112 | error (0, errno, "cannot write UTMP entry"); | |
113 | return 1; | |
114 | } | |
115 | } | |
116 | ||
117 | endutent (); | |
118 | ||
119 | return 0; | |
120 | } | |
121 | ||
122 | ||
123 | static int | |
124 | do_check (void) | |
125 | { | |
126 | struct utmp *ut; | |
127 | int n; | |
128 | ||
129 | setutent (); | |
130 | ||
131 | n = 0; | |
132 | while ((ut = getutent ())) | |
133 | { | |
134 | if (n < num_entries && | |
135 | memcmp (ut, &entry[n], sizeof (struct utmp))) | |
136 | { | |
137 | error (0, 0, "UTMP entry does not match"); | |
138 | return 1; | |
139 | } | |
140 | ||
141 | n++; | |
142 | } | |
143 | ||
144 | if (n != num_entries) | |
145 | { | |
146 | error (0, 0, "number of UTMP entries is incorrect"); | |
147 | return 1; | |
148 | } | |
149 | ||
150 | endutent (); | |
151 | ||
152 | return 0; | |
153 | } | |
154 | ||
155 | static int | |
156 | simulate_login (const char *line, const char *user) | |
157 | { | |
158 | int n; | |
159 | ||
160 | for (n = 0; n < num_entries; n++) | |
161 | { | |
162 | if (strcmp (line, entry[n].ut_line) == 0 || | |
163 | entry[n].ut_type == DEAD_PROCESS) | |
164 | { | |
165 | if (entry[n].ut_pid == DEAD_PROCESS) | |
166 | entry[n].ut_pid = (entry_pid += 27); | |
167 | entry[n].ut_type = USER_PROCESS; | |
168 | strcpy (entry[n].ut_user, user); | |
f128331c | 169 | #if _HAVE_UT_TV - 0 || defined UTMPX |
7ba4fcfc | 170 | entry[n].ut_tv.tv_sec = (entry_time += 1000); |
46894673 UD |
171 | #else |
172 | entry[n].ut_time = (entry_time += 1000); | |
173 | #endif | |
7ba4fcfc UD |
174 | setutent (); |
175 | ||
176 | if (pututline (&entry[n]) == NULL) | |
177 | { | |
178 | error (0, errno, "cannot write UTMP entry"); | |
179 | return 1; | |
180 | } | |
181 | ||
182 | endutent (); | |
183 | ||
184 | return 0; | |
185 | } | |
186 | } | |
187 | ||
188 | error (0, 0, "no entries available"); | |
189 | return 1; | |
190 | } | |
191 | ||
192 | static int | |
193 | simulate_logout (const char *line) | |
194 | { | |
195 | int n; | |
196 | ||
197 | for (n = 0; n < num_entries; n++) | |
198 | { | |
199 | if (strcmp (line, entry[n].ut_line) == 0) | |
200 | { | |
201 | entry[n].ut_type = DEAD_PROCESS; | |
202 | entry[n].ut_user[0] = '\0'; | |
f128331c | 203 | #if _HAVE_UT_TV - 0 || defined UTMPX |
46894673 UD |
204 | entry[n].ut_tv.tv_sec = (entry_time += 1000); |
205 | #else | |
206 | entry[n].ut_time = (entry_time += 1000); | |
207 | #endif | |
7ba4fcfc UD |
208 | setutent (); |
209 | ||
210 | if (pututline (&entry[n]) == NULL) | |
211 | { | |
212 | error (0, errno, "cannot write UTMP entry"); | |
213 | return 1; | |
214 | } | |
215 | ||
216 | endutent (); | |
217 | ||
218 | return 0; | |
219 | } | |
220 | } | |
221 | ||
222 | error (0, 0, "no entry found for `%s'", line); | |
223 | return 1; | |
224 | } | |
225 | ||
226 | static int | |
227 | check_login (const char *line) | |
228 | { | |
229 | struct utmp *up; | |
230 | struct utmp ut; | |
231 | int n; | |
232 | ||
233 | setutent (); | |
234 | ||
235 | strcpy (ut.ut_line, line); | |
236 | up = getutline (&ut); | |
237 | if (up == NULL) | |
238 | { | |
239 | error (0, errno, "cannot get entry for line `%s'", line); | |
240 | return 1; | |
241 | } | |
242 | ||
243 | endutent (); | |
244 | ||
245 | for (n = 0; n < num_entries; n++) | |
246 | { | |
247 | if (strcmp (line, entry[n].ut_line) == 0) | |
248 | { | |
249 | if (memcmp (up, &entry[n], sizeof (struct utmp))) | |
250 | { | |
251 | error (0, 0, "UTMP entry does not match"); | |
252 | return 1; | |
253 | } | |
254 | ||
255 | return 0; | |
256 | } | |
257 | } | |
258 | ||
259 | error (0, 0, "bogus entry for line `%s'", line); | |
260 | return 1; | |
261 | } | |
262 | ||
263 | static int | |
264 | check_logout (const char *line) | |
265 | { | |
266 | struct utmp ut; | |
267 | ||
268 | setutent (); | |
269 | ||
270 | strcpy (ut.ut_line, line); | |
271 | if (getutline (&ut) != NULL) | |
272 | { | |
273 | error (0, 0, "bogus login entry for `%s'", line); | |
274 | return 1; | |
275 | } | |
276 | ||
277 | endutent (); | |
278 | ||
279 | return 0; | |
280 | } | |
281 | ||
282 | static int | |
283 | check_id (const char *id) | |
284 | { | |
285 | struct utmp *up; | |
286 | struct utmp ut; | |
287 | int n; | |
288 | ||
289 | setutent (); | |
290 | ||
291 | ut.ut_type = USER_PROCESS; | |
292 | strcpy (ut.ut_id, id); | |
293 | up = getutid (&ut); | |
294 | if (up == NULL) | |
295 | { | |
296 | error (0, errno, "cannot get entry for ID `%s'", id); | |
297 | return 1; | |
298 | } | |
299 | ||
300 | endutent (); | |
301 | ||
302 | for (n = 0; n < num_entries; n++) | |
303 | { | |
304 | if (strcmp (id, entry[n].ut_id) == 0) | |
305 | { | |
306 | if (memcmp (up, &entry[n], sizeof (struct utmp))) | |
307 | { | |
308 | error (0, 0, "UTMP entry does not match"); | |
309 | return 1; | |
310 | } | |
311 | ||
312 | return 0; | |
313 | } | |
314 | } | |
315 | ||
316 | error (0, 0, "bogus entry for ID `%s'", id); | |
317 | return 1; | |
318 | } | |
319 | ||
320 | static int | |
321 | check_type (int type) | |
322 | { | |
323 | struct utmp *up; | |
324 | struct utmp ut; | |
325 | int n; | |
326 | ||
327 | setutent (); | |
328 | ||
329 | ut.ut_type = type; | |
330 | up = getutid (&ut); | |
331 | if (up == NULL) | |
332 | { | |
333 | error (0, errno, "cannot get entry for type `%d'", type); | |
334 | return 1; | |
335 | } | |
336 | ||
337 | endutent (); | |
338 | ||
339 | for (n = 0; n < num_entries; n++) | |
340 | { | |
341 | if (type == entry[n].ut_type) | |
342 | { | |
343 | if (memcmp (up, &entry[n], sizeof (struct utmp))) | |
344 | { | |
345 | error (0, 0, "UTMP entry does not match"); | |
346 | return 1; | |
347 | } | |
348 | ||
349 | return 0; | |
350 | } | |
351 | } | |
352 | ||
353 | error (0, 0, "bogus entry for type `%d'", type); | |
354 | return 1; | |
355 | } | |
356 | ||
357 | static int | |
358 | do_test (int argc, char *argv[]) | |
359 | { | |
360 | int result = 0; | |
361 | ||
362 | utmpname (name); | |
363 | ||
364 | result |= do_init (); | |
365 | result |= do_check (); | |
366 | ||
367 | result |= simulate_login ("tty1", "erwin"); | |
368 | result |= do_check (); | |
369 | ||
370 | result |= simulate_login ("ttyp1", "paul"); | |
371 | result |= do_check (); | |
372 | ||
373 | result |= simulate_logout ("tty2"); | |
374 | result |= do_check (); | |
375 | ||
376 | result |= simulate_logout ("ttyp0"); | |
377 | result |= do_check (); | |
378 | ||
379 | result |= simulate_login ("ttyp2", "richard"); | |
380 | result |= do_check (); | |
381 | ||
382 | result |= check_login ("tty1"); | |
383 | result |= check_logout ("ttyp0"); | |
384 | result |= check_id ("p1"); | |
385 | result |= check_id ("2"); | |
386 | result |= check_id ("si"); | |
387 | result |= check_type (BOOT_TIME); | |
388 | result |= check_type (RUN_LVL); | |
389 | ||
390 | return result; | |
391 | } |