1 /* Copyright (C) 1997 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3 Contributed by Mark Kettenis <kettenis@phys.uva.nl>, 1997.
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.
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.
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. */
31 #include "utmpd-private.h"
35 /* Prototypes for the local functions. */
36 static int initialize_database (utmp_database
*database
);
37 static int store_state_entry (utmp_database
*database
, int old_position
,
38 const struct utmp
*old_entry
);
39 static int store_process_entry (utmp_database
*database
, int old_position
,
40 const struct utmp
*old_entry
);
41 static int replace_entry (utmp_database
*database
, int old_position
,
42 int new_position
, const struct utmp
*entry
);
43 static int store_entry (utmp_database
*database
, int position
,
44 const struct utmp
*entry
);
45 static int get_mtime (int filedes
, time_t *timer
);
48 /* Open the database specified by FILE and merge it with the contents
49 of the old format file specified by OLD_FILE. Returns a pointer to
50 a newly allocated structure describing the database, or NULL on
53 open_database (const char *file
, const char *old_file
)
55 mode_t mode
= S_IWUSR
| S_IRUSR
| S_IRGRP
| S_IROTH
;
56 utmp_database
*database
;
58 /* Allocate memory. */
59 database
= (utmp_database
*) malloc (sizeof (utmp_database
));
62 error (0, 0, _("memory exhausted"));
66 memset (database
, 0, sizeof (utmp_database
));
68 /* Open database, create it if it doesn't exist already. */
69 database
->fd
= open (file
, O_RDWR
| O_CREAT
, mode
);
72 error (0, errno
, "%s", file
);
76 database
->file
= strdup (file
);
77 if (database
->file
== NULL
)
79 error (0, 0, _("memory exhausted"));
85 database
->old_fd
= open (old_file
, O_RDWR
|O_CREAT
, mode
);
86 if (database
->old_fd
< 0)
88 error (0, errno
, "%s", old_file
);
92 database
->old_file
= strdup (old_file
);
93 if (database
->old_file
== NULL
)
95 error (0, 0, _("memory exhausted"));
100 /* Initialize database. */
101 if (initialize_database (database
) < 0)
107 close_database (database
);
112 /* Synchronize DATABASE. */
114 synchronize_database (utmp_database
*database
)
118 /* Check if there is a file in the old format, that we have to
120 if (database
->old_file
)
125 curtime
= time (NULL
);
127 if (get_mtime (database
->old_fd
, &mtime
) < 0)
129 error (0, errno
, _("%s: cannot get modification time"),
134 if (mtime
>= database
->mtime
)
138 struct utmp old_entry
;
142 if (read_old_entry (database
, position
, &old_entry
) < 0)
145 if (read_entry (database
, position
, &entry
) < 0
146 || !compare_entry (&old_entry
, &entry
))
148 if (write_entry (database
, position
, &old_entry
) < 0)
150 error (0, errno
, "%s", database
->file
);
158 database
->mtime
= curtime
;
167 /* Close DATABASE. */
169 close_database (utmp_database
*database
)
173 if (database
->fd
>= 0)
174 close (database
->fd
);
176 if (database
->old_fd
>= 0)
177 close (database
->old_fd
);
179 /* Free allocated memory. */
181 free (database
->file
);
182 if (database
->old_file
)
183 free (database
->old_file
);
188 /* Read the entry at POSITION in DATABASE and store the result in
189 ENTRY. Returns 0 if successful, -1 if not. */
191 read_entry (utmp_database
*database
, int position
, struct utmp
*entry
)
196 offset
= position
* sizeof (struct utmp
);
197 if (lseek (database
->fd
, offset
, SEEK_SET
) < 0)
200 nbytes
= read (database
->fd
, entry
, sizeof (struct utmp
));
201 if (nbytes
!= sizeof (struct utmp
))
208 /* Write ENTRY at POSITION in DATABASE. Returns 0 if successful, -1
211 write_entry (utmp_database
*database
, int position
,
212 const struct utmp
*entry
)
219 /* Try to lock the file. */
220 memset (&fl
, 0, sizeof (struct flock
));
222 fl
.l_whence
= SEEK_SET
;
223 fcntl (database
->fd
, F_SETLKW
, &fl
);
225 offset
= position
* sizeof (struct utmp
);
226 if (lseek (database
->fd
, offset
, SEEK_SET
) < 0)
229 nbytes
= write (database
->fd
, entry
, sizeof (struct utmp
));
230 if (nbytes
!= sizeof (struct utmp
))
232 ftruncate (database
->fd
, offset
);
239 /* And unlock the file. */
241 fcntl (database
->fd
, F_SETLKW
, &fl
);
247 /* Append ENTRY to DATABASE. Returns the position of the appended
248 entry if successful, or -1 on error. */
250 append_entry (utmp_database
*database
, const struct utmp
*entry
)
257 /* Try to lock the file. */
258 memset (&fl
, 0, sizeof (struct flock
));
260 fl
.l_whence
= SEEK_SET
;
261 fcntl (database
->fd
, F_SETLKW
, &fl
);
263 offset
= lseek (database
->fd
, 0, SEEK_END
);
264 if (offset
% sizeof (struct utmp
) != 0)
266 offset
-= offset
% sizeof (struct utmp
);
267 ftruncate (database
->fd
, offset
);
269 if (lseek (database
->fd
, 0, SEEK_END
) < 0)
273 nbytes
= write (database
->fd
, entry
, sizeof (struct utmp
));
274 if (nbytes
!= sizeof (struct utmp
))
276 ftruncate (database
->fd
, offset
);
280 result
= offset
/ sizeof (struct utmp
);
283 /* And unlock the file. */
285 fcntl (database
->fd
, F_SETLKW
, &fl
);
292 read_old_entry (utmp_database
*database
, int position
,
295 struct xtmp old_entry
;
299 offset
= position
* sizeof (struct xtmp
);
300 if (lseek (database
->old_fd
, offset
, SEEK_SET
) < 0)
303 nbytes
= read (database
->old_fd
, &old_entry
, sizeof (struct xtmp
));
304 if (nbytes
!= sizeof (struct xtmp
))
307 xtmp_to_utmp (&old_entry
, entry
);
313 write_old_entry (utmp_database
*database
, int position
,
314 const struct utmp
*entry
)
316 struct xtmp old_entry
;
320 utmp_to_xtmp (entry
, &old_entry
);
322 offset
= position
* sizeof (struct xtmp
);
323 if (lseek (database
->old_fd
, offset
, SEEK_SET
) < 0)
326 nbytes
= write (database
->old_fd
, &old_entry
, sizeof (struct xtmp
));
327 if (nbytes
!= sizeof (struct xtmp
))
334 /* Initialize DATABASE. */
336 initialize_database (utmp_database
*database
)
343 /* Check if there is a file in the old format to read. */
344 if (database
->old_file
)
348 if (read_old_entry (database
, position
, &entry
) < 0)
351 #if _HAVE_UT_TYPE - 0
352 /* If the login type is one of RUN_LVL, BOOT_TIME, OLD_TIME or
353 NEW_TIME, search for an entry of the same type in the
354 database, and replace it if the entry in the file is newer. */
355 if (entry
.ut_type
== RUN_LVL
|| entry
.ut_type
== BOOT_TIME
356 || entry
.ut_type
== OLD_TIME
|| entry
.ut_type
== NEW_TIME
)
358 if (store_state_entry (database
, position
, &entry
) < 0)
360 error (0, errno
, "%s", database
->file
);
367 if (store_process_entry (database
, position
, &entry
) < 0)
369 error (0, errno
, "%s", database
->file
);
374 /* Update position. */
380 if (read_entry (database
, position
, &entry
) < 0)
383 if (write_old_entry (database
, position
, &entry
) < 0)
385 error (0, errno
, "%s", database
->file
);
389 /* Update position. */
394 return synchronize_database (database
);
398 #if _HAVE_UT_TYPE - 0
400 store_state_entry (utmp_database
*database
, int old_position
,
401 const struct utmp
*old_entry
)
403 struct utmp new_entry
;
404 int new_position
= 0;
407 assert (old_entry
->ut_type
== RUN_LVL
408 || old_entry
->ut_type
== BOOT_TIME
409 || old_entry
->ut_type
== OLD_TIME
410 || old_entry
->ut_type
== NEW_TIME
);
414 /* Read the next entry. */
415 if (read_entry (database
, new_position
, &new_entry
) < 0)
418 if (old_entry
->ut_type
== new_entry
.ut_type
)
424 /* Update position. */
430 const struct utmp
*entry
;
434 old_entry
->ut_tv
.tv_sec
> new_entry
.ut_tv
.tv_sec
436 old_entry
->ut_time
> new_entry
.ut_time
443 return replace_entry (database
, old_position
, new_position
, entry
);
446 return store_entry (database
, old_position
, old_entry
);
452 store_process_entry (utmp_database
*database
, int old_position
,
453 const struct utmp
*old_entry
)
455 struct utmp new_entry
;
456 int new_position
= 0;
461 /* Read the next entry. */
462 if (read_entry (database
, new_position
, &new_entry
) < 0)
465 if (proc_utmp_eq (old_entry
, &new_entry
))
471 /* Update position. */
477 const struct utmp
*entry
;
481 old_entry
->ut_tv
.tv_sec
> new_entry
.ut_tv
.tv_sec
483 old_entry
->ut_time
> new_entry
.ut_time
490 return replace_entry (database
, old_position
, new_position
, entry
);
493 return store_entry (database
, old_position
, old_entry
);
498 replace_entry (utmp_database
*database
, int old_position
, int new_position
,
499 const struct utmp
*entry
)
503 if (read_entry (database
, old_position
, &tmp
) < 0
504 || write_entry (database
, old_position
, entry
) < 0
505 || write_entry (database
, new_position
, &tmp
) < 0)
513 store_entry (utmp_database
*database
, int position
,
514 const struct utmp
*entry
)
518 if (read_entry (database
, position
, &tmp
) < 0)
519 return write_entry (database
, position
, entry
);
521 if (write_entry (database
, position
, entry
) < 0
522 || append_entry (database
, &tmp
) < 0)
529 /* Get modification time of the file with file descriptor FILEDES and
530 put it in TIMER. Returns 0 if successful, -1 if not. */
532 get_mtime (int filedes
, time_t *timer
)
536 if (fstat (filedes
, &st
) < 0)
539 *timer
= st
.st_mtime
;