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