(in_dso): Make sure the TLS variable access is not moved ahead of the
[kopensolaris-gnu/glibc.git] / login / tst-utmp.c
1 /* Tests for UTMP functions.
2    Copyright (C) 1998, 2001 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
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
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.
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
14    Lesser General Public License for more details.
15
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.  */
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
75 struct utmp entry[] =
76 {
77 #if _HAVE_UT_TV || defined UTMPX
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) },
86   { ut_type: LOGIN_PROCESS, ut_pid: 23, ut_line: "tty1", ut_id: "1",
87     ut_user: "LOGIN", UT(4000) },
88   { ut_type: USER_PROCESS, ut_pid: 24, ut_line: "tty2", ut_id: "2",
89     ut_user: "albert", UT(8000) },
90   { ut_type: USER_PROCESS, ut_pid: 196, ut_line: "ttyp0", ut_id: "p0",
91     ut_user: "niels", UT(10000) },
92   { ut_type: DEAD_PROCESS, ut_line: "ttyp1", ut_id: "p1", UT(16000) },
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);
169 #if _HAVE_UT_TV - 0 || defined UTMPX
170           entry[n].ut_tv.tv_sec = (entry_time += 1000);
171 #else
172           entry[n].ut_time = (entry_time += 1000);
173 #endif
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';
203 #if _HAVE_UT_TV - 0 || defined UTMPX
204           entry[n].ut_tv.tv_sec = (entry_time += 1000);
205 #else
206           entry[n].ut_time = (entry_time += 1000);
207 #endif
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 }