Update copyright.
[glibc.git] / login / utmp_file.c
bloba52215e74d8eea4ec6f710898b06622f491494bb
1 /* Copyright (C) 1996, 1997, 1998 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 file_fd = open (__libc_utmp_file_name, O_RDWR);
70 if (file_fd == -1)
72 /* Hhm, read-write access did not work. Try read-only. */
73 file_fd = open (__libc_utmp_file_name, O_RDONLY);
74 if (file_fd == -1)
76 perror (_("while opening UTMP file"));
77 return 0;
82 lseek (file_fd, 0, SEEK_SET);
83 file_offset = 0;
85 #if _HAVE_UT_TYPE - 0
86 /* Make sure the entry won't match. */
87 last_entry.ut_type = -1;
88 #endif
90 return 1;
94 static int
95 getutent_r_file (struct utmp *buffer, struct utmp **result)
97 ssize_t nbytes;
98 struct flock fl; /* Information struct for locking. */
100 assert (file_fd >= 0);
102 if (file_offset == -1l)
104 /* Not available. */
105 *result = NULL;
106 return -1;
109 /* XXX The following is not perfect. Instead of locking the file itself
110 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl> suggests to
111 use an extra locking file. */
112 /* XXX I think using an extra locking file does not solve the
113 problems. Instead we should set an alarm, which causes fcntl to
114 fail, as in ../nis/lckcache.c.
115 Mark Kettenis <kettenis@phys.uva.nl>. */
117 /* Try to get the lock. */
118 memset (&fl, '\0', sizeof (struct flock));
119 fl.l_type = F_RDLCK;
120 fl.l_whence = SEEK_SET;
121 fcntl (file_fd, F_SETLK, &fl);
123 /* Read the next entry. */
124 nbytes = read (file_fd, &last_entry, sizeof (struct utmp));
126 /* And unlock the file. */
127 fl.l_type = F_UNLCK;
128 fcntl (file_fd, F_SETLKW, &fl);
130 if (nbytes != sizeof (struct utmp))
132 file_offset = -1l;
133 *result = NULL;
134 return -1;
137 /* Update position pointer. */
138 file_offset += sizeof (struct utmp);
140 memcpy (buffer, &last_entry, sizeof (struct utmp));
141 *result = buffer;
143 return 0;
147 static int
148 proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
150 return
152 #if _HAVE_UT_TYPE - 0
153 (entry->ut_type == INIT_PROCESS
154 || entry->ut_type == LOGIN_PROCESS
155 || entry->ut_type == USER_PROCESS
156 || entry->ut_type == DEAD_PROCESS)
158 (match->ut_type == INIT_PROCESS
159 || match->ut_type == LOGIN_PROCESS
160 || match->ut_type == USER_PROCESS
161 || match->ut_type == DEAD_PROCESS)
163 #endif
164 #if _HAVE_UT_ID - 0
165 (entry->ut_id[0] && match->ut_id[0]
166 ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
167 : strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0)
168 #else
169 strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
170 #endif
174 static int
175 internal_getut_r (const struct utmp *id, struct utmp *buffer)
177 int result = -1;
178 struct flock fl;
180 /* Try to get the lock. */
181 memset (&fl, '\0', sizeof (struct flock));
182 fl.l_type = F_RDLCK;
183 fl.l_whence = SEEK_SET;
184 fcntl (file_fd, F_SETLKW, &fl);
186 #if _HAVE_UT_TYPE - 0
187 if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
188 || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
190 /* Search for next entry with type RUN_LVL, BOOT_TIME,
191 OLD_TIME, or NEW_TIME. */
193 while (1)
195 /* Read the next entry. */
196 if (read (file_fd, buffer, sizeof (struct utmp))
197 != sizeof (struct utmp))
199 __set_errno (ESRCH);
200 file_offset = -1l;
201 goto unlock_return;
203 file_offset += sizeof (struct utmp);
205 if (id->ut_type == buffer->ut_type)
206 break;
209 else
210 #endif /* _HAVE_UT_TYPE */
212 /* Search for the next entry with the specified ID and with type
213 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */
215 while (1)
217 /* Read the next entry. */
218 if (read (file_fd, buffer, sizeof (struct utmp))
219 != sizeof (struct utmp))
221 __set_errno (ESRCH);
222 file_offset = -1l;
223 goto unlock_return;
225 file_offset += sizeof (struct utmp);
227 if (proc_utmp_eq (buffer, id))
228 break;
232 result = 0;
234 unlock_return:
235 /* And unlock the file. */
236 fl.l_type = F_UNLCK;
237 fcntl (file_fd, F_SETLK, &fl);
239 return result;
243 /* For implementing this function we don't use the getutent_r function
244 because we can avoid the reposition on every new entry this way. */
245 static int
246 getutid_r_file (const struct utmp *id, struct utmp *buffer,
247 struct utmp **result)
249 assert (file_fd >= 0);
251 if (file_offset == -1l)
253 *result = NULL;
254 return -1;
257 if (internal_getut_r (id, &last_entry) < 0)
259 *result = NULL;
260 return -1;
263 memcpy (buffer, &last_entry, sizeof (struct utmp));
264 *result = buffer;
266 return 0;
270 /* For implementing this function we don't use the getutent_r function
271 because we can avoid the reposition on every new entry this way. */
272 static int
273 getutline_r_file (const struct utmp *line, struct utmp *buffer,
274 struct utmp **result)
276 struct flock fl;
278 assert (file_fd >= 0);
280 if (file_offset == -1l)
282 *result = NULL;
283 return -1;
286 /* Try to get the lock. */
287 memset (&fl, '\0', sizeof (struct flock));
288 fl.l_type = F_RDLCK;
289 fl.l_whence = SEEK_SET;
290 fcntl (file_fd, F_SETLKW, &fl);
292 while (1)
294 /* Read the next entry. */
295 if (read (file_fd, &last_entry, sizeof (struct utmp))
296 != sizeof (struct utmp))
298 __set_errno (ESRCH);
299 file_offset = -1l;
300 *result = NULL;
301 goto unlock_return;
303 file_offset += sizeof (struct utmp);
305 /* Stop if we found a user or login entry. */
306 if (
307 #if _HAVE_UT_TYPE - 0
308 (last_entry.ut_type == USER_PROCESS
309 || last_entry.ut_type == LOGIN_PROCESS)
311 #endif
312 !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line))
313 break;
316 memcpy (buffer, &last_entry, sizeof (struct utmp));
317 *result = buffer;
319 unlock_return:
320 /* And unlock the file. */
321 fl.l_type = F_UNLCK;
322 fcntl (file_fd, F_SETLK, &fl);
324 return ((*result == NULL) ? -1 : 0);
328 static struct utmp *
329 pututline_file (const struct utmp *data)
331 struct flock fl; /* Information struct for locking. */
332 struct utmp buffer;
333 struct utmp *pbuf;
334 int found;
336 assert (file_fd >= 0);
338 /* Find the correct place to insert the data. */
339 if (file_offset > 0
340 && (
341 #if _HAVE_UT_TYPE - 0
342 (last_entry.ut_type == data->ut_type
343 && (last_entry.ut_type == RUN_LVL
344 || last_entry.ut_type == BOOT_TIME
345 || last_entry.ut_type == OLD_TIME
346 || last_entry.ut_type == NEW_TIME))
348 #endif
349 proc_utmp_eq (&last_entry, data)))
350 found = 1;
351 else
352 found = internal_getut_r (data, &buffer);
354 /* Try to lock the file. */
355 memset (&fl, '\0', sizeof (struct flock));
356 fl.l_type = F_WRLCK;
357 fl.l_whence = SEEK_SET;
358 fcntl (file_fd, F_SETLK, &fl);
360 if (found < 0)
362 /* We append the next entry. */
363 file_offset = lseek (file_fd, 0, SEEK_END);
364 if (file_offset % sizeof (struct utmp) != 0)
366 file_offset -= file_offset % sizeof (struct utmp);
367 ftruncate (file_fd, file_offset);
369 if (lseek (file_fd, 0, SEEK_END) < 0)
371 pbuf = NULL;
372 goto unlock_return;
376 else
378 /* We replace the just read entry. */
379 file_offset -= sizeof (struct utmp);
380 lseek (file_fd, file_offset, SEEK_SET);
383 /* Write the new data. */
384 if (write (file_fd, data, sizeof (struct utmp)) != sizeof (struct utmp))
386 /* If we appended a new record this is only partially written.
387 Remove it. */
388 if (found < 0)
389 (void) ftruncate (file_fd, file_offset);
390 pbuf = NULL;
392 else
394 file_offset += sizeof (struct utmp);
395 pbuf = (struct utmp *) data;
398 unlock_return:
399 /* And unlock the file. */
400 fl.l_type = F_UNLCK;
401 fcntl (file_fd, F_SETLK, &fl);
403 return pbuf;
407 static void
408 endutent_file (void)
410 assert (file_fd >= 0);
412 close (file_fd);
413 file_fd = -1;
417 static int
418 updwtmp_file (const char *file, const struct utmp *utmp)
420 int result = -1;
421 struct flock fl;
422 off_t offset;
423 int fd;
425 /* Open WTMP file. */
426 fd = open (file, O_WRONLY);
427 if (fd < 0)
428 return -1;
430 /* Try to get the lock. */
431 memset (&fl, '\0', sizeof (struct flock));
432 fl.l_type = F_WRLCK;
433 fl.l_whence = SEEK_SET;
434 fcntl (fd, F_SETLK, &fl);
436 /* Remember original size of log file. */
437 offset = lseek (fd, 0, SEEK_END);
438 if (offset % sizeof (struct utmp) != 0)
440 offset -= offset % sizeof (struct utmp);
441 ftruncate (fd, offset);
443 if (lseek (fd, 0, SEEK_END) < 0)
444 goto unlock_return;
447 /* Write the entry. If we can't write all the bytes, reset the file
448 size back to the original size. That way, no partial entries
449 will remain. */
450 if (write (fd, utmp, sizeof (struct utmp)) != sizeof (struct utmp))
452 ftruncate (fd, offset);
453 goto unlock_return;
456 result = 0;
458 unlock_return:
459 /* And unlock the file. */
460 fl.l_type = F_UNLCK;
461 fcntl (fd, F_SETLKW, &fl);
463 /* Close WTMP file. */
464 close (fd);
466 return result;