(_IO_init): Set _vtable_offset to 0.
[glibc/history.git] / login / utmp_file.c
blobbea63644f76442e2d7c0772df944ce67648ce9f4
1 /* Copyright (C) 1996, 1997 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Ulrich Drepper <drepper@cygnus.com>
4 and Paul Janzen <pcj@primenet.com>, 1996.
6 The GNU C Library is free software; you can redistribute it and/or
7 modify it under the terms of the GNU Library General Public License as
8 published by the Free Software Foundation; either version 2 of the
9 License, or (at your option) any later version.
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 Library General Public License for more details.
16 You should have received a copy of the GNU Library General Public
17 License along with the GNU C Library; see the file COPYING.LIB. If not,
18 write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 #include <assert.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <unistd.h>
27 #include <utmp.h>
29 #include "utmp-private.h"
32 /* Descriptor for the file and position. */
33 static int file_fd = -1;
34 static off_t file_offset;
36 /* Cache for the last read entry. */
37 static struct utmp last_entry;
40 /* Functions defined here. */
41 static int setutent_file (void);
42 static int getutent_r_file (struct utmp *buffer, struct utmp **result);
43 static int getutid_r_file (const struct utmp *key, struct utmp *buffer,
44 struct utmp **result);
45 static int getutline_r_file (const struct utmp *key, struct utmp *buffer,
46 struct utmp **result);
47 static struct utmp *pututline_file (const struct utmp *data);
48 static void endutent_file (void);
49 static int updwtmp_file (const char *file, const struct utmp *utmp);
51 /* Jump table for file functions. */
52 struct utfuncs __libc_utmp_file_functions =
54 setutent_file,
55 getutent_r_file,
56 getutid_r_file,
57 getutline_r_file,
58 pututline_file,
59 endutent_file,
60 updwtmp_file
64 static int
65 setutent_file (void)
67 if (file_fd < 0)
69 const char *file_name = __libc_utmp_file_name;
71 if (strcmp (__libc_utmp_file_name, _PATH_UTMP) == 0
72 && __access (_PATH_UTMP "x", F_OK) == 0)
73 file_name = _PATH_UTMP "x";
74 else if (strcmp (__libc_utmp_file_name, _PATH_WTMP) == 0
75 && __access (_PATH_WTMP "x", F_OK) == 0)
76 file_name = _PATH_WTMP "x";
78 file_fd = open (file_name, O_RDWR);
79 if (file_fd == -1)
81 /* Hhm, read-write access did not work. Try read-only. */
82 file_fd = open (file_name, O_RDONLY);
83 if (file_fd == -1)
85 perror (_("while opening UTMP file"));
86 return 0;
91 lseek (file_fd, 0, SEEK_SET);
92 file_offset = 0;
94 #if _HAVE_UT_TYPE - 0
95 /* Make sure the entry won't match. */
96 last_entry.ut_type = -1;
97 #endif
99 return 1;
103 static int
104 getutent_r_file (struct utmp *buffer, struct utmp **result)
106 ssize_t nbytes;
107 struct flock fl; /* Information struct for locking. */
109 assert (file_fd >= 0);
111 if (file_offset == -1l)
113 /* Not available. */
114 *result = NULL;
115 return -1;
118 /* XXX The following is not perfect. Instead of locking the file itself
119 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl> suggests to
120 use an extra locking file. */
121 /* XXX I think using an extra locking file does not solve the
122 problems. Instead we should set an alarm, which causes fcntl to
123 fail, as in ../nis/lckcache.c.
124 Mark Kettenis <kettenis@phys.uva.nl>. */
126 /* Try to get the lock. */
127 memset (&fl, '\0', sizeof (struct flock));
128 fl.l_type = F_RDLCK;
129 fl.l_whence = SEEK_SET;
130 fcntl (file_fd, F_SETLK, &fl);
132 /* Read the next entry. */
133 nbytes = read (file_fd, &last_entry, sizeof (struct utmp));
135 /* And unlock the file. */
136 fl.l_type = F_UNLCK;
137 fcntl (file_fd, F_SETLKW, &fl);
139 if (nbytes != sizeof (struct utmp))
141 file_offset = -1l;
142 *result = NULL;
143 return -1;
146 /* Update position pointer. */
147 file_offset += sizeof (struct utmp);
149 memcpy (buffer, &last_entry, sizeof (struct utmp));
150 *result = buffer;
152 return 0;
156 static int
157 proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
159 return
161 #if _HAVE_UT_TYPE - 0
162 (entry->ut_type == INIT_PROCESS
163 || entry->ut_type == LOGIN_PROCESS
164 || entry->ut_type == USER_PROCESS
165 || entry->ut_type == DEAD_PROCESS)
167 (match->ut_type == INIT_PROCESS
168 || match->ut_type == LOGIN_PROCESS
169 || match->ut_type == USER_PROCESS
170 || match->ut_type == DEAD_PROCESS)
172 #endif
173 #if _HAVE_UT_ID - 0
174 (entry->ut_id[0] && match->ut_id[0]
175 ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
176 : strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0)
177 #else
178 strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
179 #endif
183 static int
184 internal_getut_r (const struct utmp *id, struct utmp *buffer)
186 int result = -1;
187 struct flock fl;
189 /* Try to get the lock. */
190 memset (&fl, '\0', sizeof (struct flock));
191 fl.l_type = F_RDLCK;
192 fl.l_whence = SEEK_SET;
193 fcntl (file_fd, F_SETLKW, &fl);
195 #if _HAVE_UT_TYPE - 0
196 if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
197 || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
199 /* Search for next entry with type RUN_LVL, BOOT_TIME,
200 OLD_TIME, or NEW_TIME. */
202 while (1)
204 /* Read the next entry. */
205 if (read (file_fd, buffer, sizeof (struct utmp))
206 != sizeof (struct utmp))
208 __set_errno (ESRCH);
209 file_offset = -1l;
210 goto unlock_return;
212 file_offset += sizeof (struct utmp);
214 if (id->ut_type == buffer->ut_type)
215 break;
218 else
219 #endif /* _HAVE_UT_TYPE */
221 /* Search for the next entry with the specified ID and with type
222 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */
224 while (1)
226 /* Read the next entry. */
227 if (read (file_fd, buffer, sizeof (struct utmp))
228 != sizeof (struct utmp))
230 __set_errno (ESRCH);
231 file_offset = -1l;
232 goto unlock_return;
234 file_offset += sizeof (struct utmp);
236 if (proc_utmp_eq (buffer, id))
237 break;
241 result = 0;
243 unlock_return:
244 /* And unlock the file. */
245 fl.l_type = F_UNLCK;
246 fcntl (file_fd, F_SETLK, &fl);
248 return result;
252 /* For implementing this function we don't use the getutent_r function
253 because we can avoid the reposition on every new entry this way. */
254 static int
255 getutid_r_file (const struct utmp *id, struct utmp *buffer,
256 struct utmp **result)
258 assert (file_fd >= 0);
260 if (file_offset == -1l)
262 *result = NULL;
263 return -1;
266 if (internal_getut_r (id, &last_entry) < 0)
268 *result = NULL;
269 return -1;
272 memcpy (buffer, &last_entry, sizeof (struct utmp));
273 *result = buffer;
275 return 0;
279 /* For implementing this function we don't use the getutent_r function
280 because we can avoid the reposition on every new entry this way. */
281 static int
282 getutline_r_file (const struct utmp *line, struct utmp *buffer,
283 struct utmp **result)
285 struct flock fl;
287 assert (file_fd >= 0);
289 if (file_offset == -1l)
291 *result = NULL;
292 return -1;
295 /* Try to get the lock. */
296 memset (&fl, '\0', sizeof (struct flock));
297 fl.l_type = F_RDLCK;
298 fl.l_whence = SEEK_SET;
299 fcntl (file_fd, F_SETLKW, &fl);
301 while (1)
303 /* Read the next entry. */
304 if (read (file_fd, &last_entry, sizeof (struct utmp))
305 != sizeof (struct utmp))
307 __set_errno (ESRCH);
308 file_offset = -1l;
309 *result = NULL;
310 goto unlock_return;
312 file_offset += sizeof (struct utmp);
314 /* Stop if we found a user or login entry. */
315 if (
316 #if _HAVE_UT_TYPE - 0
317 (last_entry.ut_type == USER_PROCESS
318 || last_entry.ut_type == LOGIN_PROCESS)
320 #endif
321 !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line))
322 break;
325 memcpy (buffer, &last_entry, sizeof (struct utmp));
326 *result = buffer;
328 unlock_return:
329 /* And unlock the file. */
330 fl.l_type = F_UNLCK;
331 fcntl (file_fd, F_SETLK, &fl);
333 return ((*result == NULL) ? -1 : 0);
337 static struct utmp *
338 pututline_file (const struct utmp *data)
340 struct flock fl; /* Information struct for locking. */
341 struct utmp buffer;
342 struct utmp *pbuf;
343 int found;
345 assert (file_fd >= 0);
347 /* Find the correct place to insert the data. */
348 if (file_offset > 0
349 && (
350 #if _HAVE_UT_TYPE - 0
351 (last_entry.ut_type == data->ut_type
352 && (last_entry.ut_type == RUN_LVL
353 || last_entry.ut_type == BOOT_TIME
354 || last_entry.ut_type == OLD_TIME
355 || last_entry.ut_type == NEW_TIME))
357 #endif
358 proc_utmp_eq (&last_entry, data)))
359 found = 1;
360 else
361 found = internal_getut_r (data, &buffer);
363 /* Try to lock the file. */
364 memset (&fl, '\0', sizeof (struct flock));
365 fl.l_type = F_WRLCK;
366 fl.l_whence = SEEK_SET;
367 fcntl (file_fd, F_SETLK, &fl);
369 if (found < 0)
371 /* We append the next entry. */
372 file_offset = lseek (file_fd, 0, SEEK_END);
373 if (file_offset % sizeof (struct utmp) != 0)
375 file_offset -= file_offset % sizeof (struct utmp);
376 ftruncate (file_fd, file_offset);
378 if (lseek (file_fd, 0, SEEK_END) < 0)
380 pbuf = NULL;
381 goto unlock_return;
385 else
387 /* We replace the just read entry. */
388 file_offset -= sizeof (struct utmp);
389 lseek (file_fd, file_offset, SEEK_SET);
392 /* Write the new data. */
393 if (write (file_fd, data, sizeof (struct utmp)) != sizeof (struct utmp)
394 /* If we appended a new record this is only partially written.
395 Remove it. */
396 && found < 0)
398 (void) ftruncate (file_fd, file_offset);
399 pbuf = NULL;
401 else
403 file_offset += sizeof (struct utmp);
404 pbuf = (struct utmp *) data;
407 unlock_return:
408 /* And unlock the file. */
409 fl.l_type = F_UNLCK;
410 fcntl (file_fd, F_SETLK, &fl);
412 return pbuf;
416 static void
417 endutent_file (void)
419 assert (file_fd >= 0);
421 close (file_fd);
422 file_fd = -1;
426 static int
427 updwtmp_file (const char *file, const struct utmp *utmp)
429 int result = -1;
430 struct flock fl;
431 off_t offset;
432 int fd;
434 /* Open WTMP file. */
435 fd = open (file, O_WRONLY);
436 if (fd < 0)
437 return -1;
439 /* Try to get the lock. */
440 memset (&fl, '\0', sizeof (struct flock));
441 fl.l_type = F_WRLCK;
442 fl.l_whence = SEEK_SET;
443 fcntl (fd, F_SETLK, &fl);
445 /* Remember original size of log file. */
446 offset = lseek (fd, 0, SEEK_END);
447 if (offset % sizeof (struct utmp) != 0)
449 offset -= offset % sizeof (struct utmp);
450 ftruncate (fd, offset);
452 if (lseek (fd, 0, SEEK_END) < 0)
453 goto unlock_return;
456 /* Write the entry. If we can't write all the bytes, reset the file
457 size back to the original size. That way, no partial entries
458 will remain. */
459 if (write (fd, utmp, sizeof (struct utmp)) != sizeof (struct utmp))
461 ftruncate (fd, offset);
462 goto unlock_return;
465 result = 0;
467 unlock_return:
468 /* And unlock the file. */
469 fl.l_type = F_UNLCK;
470 fcntl (fd, F_SETLKW, &fl);
472 /* Close WTMP file. */
473 close (fd);
475 return result;