(elf_get_dynamic_info): Also relocate DT_HASH entry if necessary.
[glibc.git] / sysdeps / generic / utmp_file.c
blob169f0c736329daff0ab78318a4930bbc1b8bfea7
1 /* Copyright (C) 1996,97,98,99,2000,01,02 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 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.
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.
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. */
21 #include <assert.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <signal.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <utmp.h>
30 #include "utmp-private.h"
31 #include "utmp-equal.h"
34 /* Descriptor for the file and position. */
35 static int file_fd = -1;
36 static off64_t file_offset;
38 /* Cache for the last read entry. */
39 static struct utmp last_entry;
42 /* Locking timeout. */
43 #ifndef TIMEOUT
44 # define TIMEOUT 1
45 #endif
47 /* Do-nothing handler for locking timeout. */
48 static void timeout_handler (int signum) {};
50 #define LOCK_FILE(fd, type) \
51 { \
52 struct flock fl; \
53 struct sigaction action, old_action; \
54 unsigned int old_timeout; \
56 /* Cancel any existing alarm. */ \
57 old_timeout = alarm (0); \
59 /* Establish signal handler. */ \
60 action.sa_handler = timeout_handler; \
61 __sigemptyset (&action.sa_mask); \
62 action.sa_flags = 0; \
63 __sigaction (SIGALRM, &action, &old_action); \
65 alarm (TIMEOUT); \
67 /* Try to get the lock. */ \
68 memset (&fl, '\0', sizeof (struct flock)); \
69 fl.l_type = (type); \
70 fl.l_whence = SEEK_SET; \
71 if (__fcntl ((fd), F_SETLKW, &fl) < 0)
73 #define UNLOCK_FILE(fd) \
74 /* Unlock the file. */ \
75 fl.l_type = F_UNLCK; \
76 __fcntl ((fd), F_SETLKW, &fl); \
78 /* Reset the signal handler and alarm. We must reset the alarm \
79 before resetting the handler so our alarm does not generate a \
80 spurious SIGALRM seen by the user. However, we cannot just set \
81 the user's old alarm before restoring the handler, because then \
82 it's possible our handler could catch the user alarm's SIGARLM \
83 and then the user would never see the signal he expected. */ \
84 alarm (0); \
85 __sigaction (SIGALRM, &old_action, NULL); \
86 if (old_timeout != 0) \
87 alarm (old_timeout); \
88 } while (0)
91 /* Functions defined here. */
92 static int setutent_file (void);
93 static int getutent_r_file (struct utmp *buffer, struct utmp **result);
94 static int getutid_r_file (const struct utmp *key, struct utmp *buffer,
95 struct utmp **result);
96 static int getutline_r_file (const struct utmp *key, struct utmp *buffer,
97 struct utmp **result);
98 static struct utmp *pututline_file (const struct utmp *data);
99 static void endutent_file (void);
100 static int updwtmp_file (const char *file, const struct utmp *utmp);
102 /* Jump table for file functions. */
103 struct utfuncs __libc_utmp_file_functions =
105 setutent_file,
106 getutent_r_file,
107 getutid_r_file,
108 getutline_r_file,
109 pututline_file,
110 endutent_file,
111 updwtmp_file
115 #ifndef TRANSFORM_UTMP_FILE_NAME
116 # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
117 #endif
119 static int
120 setutent_file (void)
122 if (file_fd < 0)
124 const char *file_name;
125 int result;
127 file_name = TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name);
129 file_fd = __open (file_name, O_RDWR);
130 if (file_fd == -1)
132 /* Hhm, read-write access did not work. Try read-only. */
133 file_fd = __open (file_name, O_RDONLY);
134 if (file_fd == -1)
135 return 0;
138 /* We have to make sure the file is `closed on exec'. */
139 result = __fcntl (file_fd, F_GETFD, 0);
140 if (result >= 0)
141 result = __fcntl (file_fd, F_SETFD, result | FD_CLOEXEC);
142 if (result == -1)
144 __close (file_fd);
145 return 0;
149 __lseek64 (file_fd, 0, SEEK_SET);
150 file_offset = 0;
152 /* Make sure the entry won't match. */
153 #if _HAVE_UT_TYPE - 0
154 last_entry.ut_type = -1;
155 #else
156 last_entry.ut_line[0] = '\177';
157 # if _HAVE_UT_ID - 0
158 last_entry.ut_id[0] = '\0';
159 # endif
160 #endif
162 return 1;
166 static int
167 getutent_r_file (struct utmp *buffer, struct utmp **result)
169 ssize_t nbytes;
171 assert (file_fd >= 0);
173 if (file_offset == -1l)
175 /* Not available. */
176 *result = NULL;
177 return -1;
180 LOCK_FILE (file_fd, F_RDLCK)
182 *result = NULL;
183 return -1;
186 /* Read the next entry. */
187 nbytes = __read (file_fd, &last_entry, sizeof (struct utmp));
189 UNLOCK_FILE (file_fd);
191 if (nbytes != sizeof (struct utmp))
193 file_offset = -1l;
194 *result = NULL;
195 return -1;
198 /* Update position pointer. */
199 file_offset += sizeof (struct utmp);
201 memcpy (buffer, &last_entry, sizeof (struct utmp));
202 *result = buffer;
204 return 0;
208 static int
209 internal_getut_r (const struct utmp *id, struct utmp *buffer)
211 int result = -1;
213 LOCK_FILE (file_fd, F_RDLCK)
214 return result;
216 #if _HAVE_UT_TYPE - 0
217 if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
218 || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
220 /* Search for next entry with type RUN_LVL, BOOT_TIME,
221 OLD_TIME, or NEW_TIME. */
223 while (1)
225 /* Read the next entry. */
226 if (__read (file_fd, buffer, sizeof (struct utmp))
227 != sizeof (struct utmp))
229 __set_errno (ESRCH);
230 file_offset = -1l;
231 goto unlock_return;
233 file_offset += sizeof (struct utmp);
235 if (id->ut_type == buffer->ut_type)
236 break;
239 else
240 #endif /* _HAVE_UT_TYPE */
242 /* Search for the next entry with the specified ID and with type
243 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */
245 while (1)
247 /* Read the next entry. */
248 if (__read (file_fd, buffer, sizeof (struct utmp))
249 != sizeof (struct utmp))
251 __set_errno (ESRCH);
252 file_offset = -1l;
253 goto unlock_return;
255 file_offset += sizeof (struct utmp);
257 if (__utmp_equal (buffer, id))
258 break;
262 result = 0;
264 unlock_return:
265 UNLOCK_FILE (file_fd);
267 return result;
271 /* For implementing this function we don't use the getutent_r function
272 because we can avoid the reposition on every new entry this way. */
273 static int
274 getutid_r_file (const struct utmp *id, struct utmp *buffer,
275 struct utmp **result)
277 assert (file_fd >= 0);
279 if (file_offset == -1l)
281 *result = NULL;
282 return -1;
285 if (internal_getut_r (id, &last_entry) < 0)
287 *result = NULL;
288 return -1;
291 memcpy (buffer, &last_entry, sizeof (struct utmp));
292 *result = buffer;
294 return 0;
298 /* For implementing this function we don't use the getutent_r function
299 because we can avoid the reposition on every new entry this way. */
300 static int
301 getutline_r_file (const struct utmp *line, struct utmp *buffer,
302 struct utmp **result)
304 assert (file_fd >= 0);
306 if (file_offset == -1l)
308 *result = NULL;
309 return -1;
312 LOCK_FILE (file_fd, F_RDLCK)
314 *result = NULL;
315 return -1;
318 while (1)
320 /* Read the next entry. */
321 if (__read (file_fd, &last_entry, sizeof (struct utmp))
322 != sizeof (struct utmp))
324 __set_errno (ESRCH);
325 file_offset = -1l;
326 *result = NULL;
327 goto unlock_return;
329 file_offset += sizeof (struct utmp);
331 /* Stop if we found a user or login entry. */
332 if (
333 #if _HAVE_UT_TYPE - 0
334 (last_entry.ut_type == USER_PROCESS
335 || last_entry.ut_type == LOGIN_PROCESS)
337 #endif
338 !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line))
339 break;
342 memcpy (buffer, &last_entry, sizeof (struct utmp));
343 *result = buffer;
345 unlock_return:
346 UNLOCK_FILE (file_fd);
348 return ((*result == NULL) ? -1 : 0);
352 static struct utmp *
353 pututline_file (const struct utmp *data)
355 struct utmp buffer;
356 struct utmp *pbuf;
357 int found;
359 assert (file_fd >= 0);
361 /* Find the correct place to insert the data. */
362 if (file_offset > 0
363 && (
364 #if _HAVE_UT_TYPE - 0
365 (last_entry.ut_type == data->ut_type
366 && (last_entry.ut_type == RUN_LVL
367 || last_entry.ut_type == BOOT_TIME
368 || last_entry.ut_type == OLD_TIME
369 || last_entry.ut_type == NEW_TIME))
371 #endif
372 __utmp_equal (&last_entry, data)))
373 found = 1;
374 else
375 found = internal_getut_r (data, &buffer);
377 LOCK_FILE (file_fd, F_WRLCK)
378 return NULL;
380 if (found < 0)
382 /* We append the next entry. */
383 file_offset = __lseek64 (file_fd, 0, SEEK_END);
384 if (file_offset % sizeof (struct utmp) != 0)
386 file_offset -= file_offset % sizeof (struct utmp);
387 __ftruncate64 (file_fd, file_offset);
389 if (__lseek64 (file_fd, 0, SEEK_END) < 0)
391 pbuf = NULL;
392 goto unlock_return;
396 else
398 /* We replace the just read entry. */
399 file_offset -= sizeof (struct utmp);
400 __lseek64 (file_fd, file_offset, SEEK_SET);
403 /* Write the new data. */
404 if (__write (file_fd, data, sizeof (struct utmp)) != sizeof (struct utmp))
406 /* If we appended a new record this is only partially written.
407 Remove it. */
408 if (found < 0)
409 (void) __ftruncate64 (file_fd, file_offset);
410 pbuf = NULL;
412 else
414 file_offset += sizeof (struct utmp);
415 pbuf = (struct utmp *) data;
418 unlock_return:
419 UNLOCK_FILE (file_fd);
421 return pbuf;
425 static void
426 endutent_file (void)
428 assert (file_fd >= 0);
430 __close (file_fd);
431 file_fd = -1;
435 static int
436 updwtmp_file (const char *file, const struct utmp *utmp)
438 int result = -1;
439 off64_t offset;
440 int fd;
442 /* Open WTMP file. */
443 fd = __open (file, O_WRONLY);
444 if (fd < 0)
445 return -1;
447 LOCK_FILE (fd, F_WRLCK)
449 __close (fd);
450 return result;
453 /* Remember original size of log file. */
454 offset = __lseek64 (fd, 0, SEEK_END);
455 if (offset % sizeof (struct utmp) != 0)
457 offset -= offset % sizeof (struct utmp);
458 __ftruncate64 (fd, offset);
460 if (__lseek64 (fd, 0, SEEK_END) < 0)
461 goto unlock_return;
464 /* Write the entry. If we can't write all the bytes, reset the file
465 size back to the original size. That way, no partial entries
466 will remain. */
467 if (__write (fd, utmp, sizeof (struct utmp)) != sizeof (struct utmp))
469 __ftruncate64 (fd, offset);
470 goto unlock_return;
473 result = 0;
475 unlock_return:
476 UNLOCK_FILE (fd);
478 /* Close WTMP file. */
479 __close (fd);
481 return result;