]>
git.ipfire.org Git - thirdparty/glibc.git/blob - login/utmp_file.c
2d0548f6fa29d4e7f7f9d6e10d4025c189928fad
1 /* Copyright (C) 1996-2019 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, see
18 <http://www.gnu.org/licenses/>. */
29 #include <not-cancel.h>
30 #include <kernel-features.h>
31 #include <sigsetops.h>
32 #include <not-cancel.h>
34 #include "utmp-private.h"
35 #include "utmp-equal.h"
38 /* Descriptor for the file and position. */
39 static int file_fd
= -1;
40 static bool file_writable
;
41 static off64_t file_offset
;
43 /* Cache for the last read entry. */
44 static struct utmp last_entry
;
47 /* Locking timeout. */
52 /* Do-nothing handler for locking timeout. */
53 static void timeout_handler (int signum
) {};
56 /* try_file_lock (LOCKING, FD, TYPE) returns true if the locking
57 operation failed and recovery needs to be performed.
59 file_unlock (FD) removes the lock (which must have been
60 successfully acquired). */
63 try_file_lock (int fd
, int type
)
65 /* Cancel any existing alarm. */
66 int old_timeout
= alarm (0);
68 /* Establish signal handler. */
69 struct sigaction old_action
;
70 struct sigaction action
;
71 action
.sa_handler
= timeout_handler
;
72 __sigemptyset (&action
.sa_mask
);
74 __sigaction (SIGALRM
, &action
, &old_action
);
78 /* Try to get the lock. */
82 fl
.l_whence
= SEEK_SET
,
85 bool status
= __fcntl64_nocancel (fd
, F_SETLKW
, &fl
) < 0;
86 int saved_errno
= errno
;
88 /* Reset the signal handler and alarm. We must reset the alarm
89 before resetting the handler so our alarm does not generate a
90 spurious SIGALRM seen by the user. However, we cannot just set
91 the user's old alarm before restoring the handler, because then
92 it's possible our handler could catch the user alarm's SIGARLM and
93 then the user would never see the signal he expected. */
95 __sigaction (SIGALRM
, &old_action
, NULL
);
99 __set_errno (saved_errno
);
110 __fcntl64_nocancel (fd
, F_SETLKW
, &fl
);
113 #ifndef TRANSFORM_UTMP_FILE_NAME
114 # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
118 __libc_setutent (void)
122 const char *file_name
;
124 file_name
= TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name
);
126 file_writable
= false;
127 file_fd
= __open_nocancel
128 (file_name
, O_RDONLY
| O_LARGEFILE
| O_CLOEXEC
);
133 __lseek64 (file_fd
, 0, SEEK_SET
);
136 /* Make sure the entry won't match. */
137 last_entry
.ut_type
= -1;
142 /* Preform initialization if necessary. */
144 maybe_setutent (void)
146 return file_fd
>= 0 || __libc_setutent ();
150 __libc_getutent_r (struct utmp
*buffer
, struct utmp
**result
)
154 if (!maybe_setutent () || file_offset
== -1l)
161 if (try_file_lock (file_fd
, F_RDLCK
))
165 /* Read the next entry. */
166 nbytes
= __read_nocancel (file_fd
, &last_entry
, sizeof (struct utmp
));
167 file_unlock (file_fd
);
170 if (nbytes
!= sizeof (struct utmp
))
178 /* Update position pointer. */
179 file_offset
+= sizeof (struct utmp
);
181 memcpy (buffer
, &last_entry
, sizeof (struct utmp
));
188 /* Search for *ID, updating last_entry and file_offset. Return 0 on
189 success and -1 on failure. If the locking operation failed, write
190 true to *LOCK_FAILED. */
192 internal_getut_r (const struct utmp
*id
, bool *lock_failed
)
196 if (try_file_lock (file_fd
, F_RDLCK
))
202 if (id
->ut_type
== RUN_LVL
|| id
->ut_type
== BOOT_TIME
203 || id
->ut_type
== OLD_TIME
|| id
->ut_type
== NEW_TIME
)
205 /* Search for next entry with type RUN_LVL, BOOT_TIME,
206 OLD_TIME, or NEW_TIME. */
210 /* Read the next entry. */
211 if (__read_nocancel (file_fd
, &last_entry
, sizeof (struct utmp
))
212 != sizeof (struct utmp
))
218 file_offset
+= sizeof (struct utmp
);
220 if (id
->ut_type
== last_entry
.ut_type
)
226 /* Search for the next entry with the specified ID and with type
227 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */
231 /* Read the next entry. */
232 if (__read_nocancel (file_fd
, &last_entry
, sizeof (struct utmp
))
233 != sizeof (struct utmp
))
239 file_offset
+= sizeof (struct utmp
);
241 if (__utmp_equal (&last_entry
, id
))
249 file_unlock (file_fd
);
255 /* For implementing this function we don't use the getutent_r function
256 because we can avoid the reposition on every new entry this way. */
258 __libc_getutid_r (const struct utmp
*id
, struct utmp
*buffer
,
259 struct utmp
**result
)
261 if (!maybe_setutent () || file_offset
== -1l)
267 /* We don't have to distinguish whether we can lock the file or
268 whether there is no entry. */
269 bool lock_failed
= false;
270 if (internal_getut_r (id
, &lock_failed
) < 0)
276 memcpy (buffer
, &last_entry
, sizeof (struct utmp
));
283 /* For implementing this function we don't use the getutent_r function
284 because we can avoid the reposition on every new entry this way. */
286 __libc_getutline_r (const struct utmp
*line
, struct utmp
*buffer
,
287 struct utmp
**result
)
289 if (!maybe_setutent () || file_offset
== -1l)
295 if (try_file_lock (file_fd
, F_RDLCK
))
303 /* Read the next entry. */
304 if (__read_nocancel (file_fd
, &last_entry
, sizeof (struct utmp
))
305 != sizeof (struct utmp
))
312 file_offset
+= sizeof (struct utmp
);
314 /* Stop if we found a user or login entry. */
315 if ((last_entry
.ut_type
== USER_PROCESS
316 || last_entry
.ut_type
== LOGIN_PROCESS
)
317 && (strncmp (line
->ut_line
, last_entry
.ut_line
, sizeof line
->ut_line
)
322 memcpy (buffer
, &last_entry
, sizeof (struct utmp
));
326 file_unlock (file_fd
);
328 return ((*result
== NULL
) ? -1 : 0);
333 __libc_pututline (const struct utmp
*data
)
335 if (!maybe_setutent () || file_offset
== -1l)
343 /* We must make the file descriptor writable before going on. */
344 const char *file_name
= TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name
);
346 int new_fd
= __open_nocancel
347 (file_name
, O_RDWR
| O_LARGEFILE
| O_CLOEXEC
);
351 if (__lseek64 (new_fd
, __lseek64 (file_fd
, 0, SEEK_CUR
), SEEK_SET
) == -1
352 || __dup2 (new_fd
, file_fd
) < 0)
354 __close_nocancel_nostatus (new_fd
);
357 __close_nocancel_nostatus (new_fd
);
358 file_writable
= true;
361 /* Find the correct place to insert the data. */
363 && ((last_entry
.ut_type
== data
->ut_type
364 && (last_entry
.ut_type
== RUN_LVL
365 || last_entry
.ut_type
== BOOT_TIME
366 || last_entry
.ut_type
== OLD_TIME
367 || last_entry
.ut_type
== NEW_TIME
))
368 || __utmp_equal (&last_entry
, data
)))
372 bool lock_failed
= false;
373 found
= internal_getut_r (data
, &lock_failed
);
375 if (__builtin_expect (lock_failed
, false))
377 __set_errno (EAGAIN
);
382 if (try_file_lock (file_fd
, F_WRLCK
))
387 /* We append the next entry. */
388 file_offset
= __lseek64 (file_fd
, 0, SEEK_END
);
389 if (file_offset
% sizeof (struct utmp
) != 0)
391 file_offset
-= file_offset
% sizeof (struct utmp
);
392 __ftruncate64 (file_fd
, file_offset
);
394 if (__lseek64 (file_fd
, 0, SEEK_END
) < 0)
403 /* We replace the just read entry. */
404 file_offset
-= sizeof (struct utmp
);
405 __lseek64 (file_fd
, file_offset
, SEEK_SET
);
408 /* Write the new data. */
409 if (__write_nocancel (file_fd
, data
, sizeof (struct utmp
))
410 != sizeof (struct utmp
))
412 /* If we appended a new record this is only partially written.
415 (void) __ftruncate64 (file_fd
, file_offset
);
420 file_offset
+= sizeof (struct utmp
);
421 pbuf
= (struct utmp
*) data
;
425 file_unlock (file_fd
);
432 __libc_endutent (void)
436 __close_nocancel_nostatus (file_fd
);
443 __libc_updwtmp (const char *file
, const struct utmp
*utmp
)
449 /* Open WTMP file. */
450 fd
= __open_nocancel (file
, O_WRONLY
| O_LARGEFILE
);
454 if (try_file_lock (fd
, F_WRLCK
))
456 __close_nocancel_nostatus (fd
);
460 /* Remember original size of log file. */
461 offset
= __lseek64 (fd
, 0, SEEK_END
);
462 if (offset
% sizeof (struct utmp
) != 0)
464 offset
-= offset
% sizeof (struct utmp
);
465 __ftruncate64 (fd
, offset
);
467 if (__lseek64 (fd
, 0, SEEK_END
) < 0)
471 /* Write the entry. If we can't write all the bytes, reset the file
472 size back to the original size. That way, no partial entries
474 if (__write_nocancel (fd
, utmp
, sizeof (struct utmp
))
475 != sizeof (struct utmp
))
477 __ftruncate64 (fd
, offset
);
486 /* Close WTMP file. */
487 __close_nocancel_nostatus (fd
);