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 (const char *file
, time_t *timer
);
48 /* Open the database specified by FILE and merge it with the
49 contents of the old format file specified by OLD_FILE. Returns a
50 pointer to a newly allocated structure describing the database, or
53 open_database (const char *file
, const char *old_file
)
55 utmp_database
*database
;
57 /* Allocate memory. */
58 database
= (utmp_database
*) malloc (sizeof (utmp_database
));
62 memset (database
, 0, sizeof (utmp_database
));
65 database
->fd
= open (file
, O_RDWR
);
69 database
->old_fd
= open (old_file
, O_RDWR
);
70 if (database
->old_fd
< 0)
73 if ((file
&& !(database
->file
= strdup (file
)))
74 || (old_file
&& !(database
->old_file
= strdup (old_file
))))
77 if (initialize_database (database
) < 0
78 || synchronize_database (database
) < 0)
84 close_database (database
);
88 /* Synchronize DATABASE. */
90 synchronize_database (utmp_database
*database
)
94 /* Check if there is a file in the old format, that we have to
96 if (database
->old_file
)
101 curtime
= time (NULL
);
103 if (get_mtime (database
->old_file
, &mtime
) < 0)
106 if (mtime
>= database
->mtime
)
110 struct utmp old_entry
;
114 if (read_old_entry (database
, position
, &old_entry
) < 0)
117 if (read_entry (database
, position
, &entry
) < 0
118 || !compare_entry (&old_entry
, &entry
))
120 if (write_entry (database
, position
, &old_entry
) < 0)
127 database
->mtime
= curtime
;
136 /* Close DATABASE. */
138 close_database (utmp_database
*database
)
142 if (database
->fd
>= 0)
143 close (database
->fd
);
145 if (database
->old_fd
>= 0)
146 close (database
->old_fd
);
148 /* Free allocated memory. */
150 free (database
->file
);
151 if (database
->old_file
)
152 free (database
->old_file
);
157 /* Read the entry at POSITION in DATABASE and store the result in
158 ENTRY. Returns 0 if successful, -1 if not. */
160 read_entry (utmp_database
*database
, int position
, struct utmp
*entry
)
165 offset
= position
* sizeof (struct utmp
);
166 if (lseek (database
->fd
, offset
, SEEK_SET
) < 0)
169 nbytes
= read (database
->fd
, entry
, sizeof (struct utmp
));
170 if (nbytes
!= sizeof (struct utmp
))
177 /* Write ENTRY at POSITION in DATABASE. Returns 0 if successful, -1
180 write_entry (utmp_database
*database
, int position
,
181 const struct utmp
*entry
)
188 /* Try to lock the file. */
189 memset (&fl
, 0, sizeof (struct flock
));
191 fl
.l_whence
= SEEK_SET
;
192 fcntl (database
->fd
, F_SETLKW
, &fl
);
194 offset
= position
* sizeof (struct utmp
);
195 if (lseek (database
->fd
, offset
, SEEK_SET
) < 0)
198 nbytes
= write (database
->fd
, entry
, sizeof (struct utmp
));
199 if (nbytes
!= sizeof (struct utmp
))
201 ftruncate (database
->fd
, offset
);
208 /* And unlock the file. */
210 fcntl (database
->fd
, F_SETLKW
, &fl
);
216 /* Append ENTRY to DATABASE. Returns the position of the appended
217 entry if successful, or -1 on error. */
219 append_entry (utmp_database
*database
, const struct utmp
*entry
)
226 /* Try to lock the file. */
227 memset (&fl
, 0, sizeof (struct flock
));
229 fl
.l_whence
= SEEK_SET
;
230 fcntl (database
->fd
, F_SETLKW
, &fl
);
232 offset
= lseek (database
->fd
, 0, SEEK_END
);
233 if (offset
% sizeof (struct utmp
) != 0)
235 offset
-= offset
% sizeof (struct utmp
);
236 ftruncate (database
->fd
, offset
);
238 if (lseek (database
->fd
, 0, SEEK_END
) < 0)
242 nbytes
= write (database
->fd
, entry
, sizeof (struct utmp
));
243 if (nbytes
!= sizeof (struct utmp
))
245 ftruncate (database
->fd
, offset
);
249 result
= offset
/ sizeof (struct utmp
);
252 /* And unlock the file. */
254 fcntl (database
->fd
, F_SETLKW
, &fl
);
261 read_old_entry (utmp_database
*database
, int position
,
264 struct xtmp old_entry
;
268 offset
= position
* sizeof (struct xtmp
);
269 if (lseek (database
->old_fd
, offset
, SEEK_SET
) < 0)
272 nbytes
= read (database
->old_fd
, &old_entry
, sizeof (struct xtmp
));
273 if (nbytes
!= sizeof (struct xtmp
))
276 xtmp_to_utmp (&old_entry
, entry
);
282 write_old_entry (utmp_database
*database
, int position
,
283 const struct utmp
*entry
)
285 struct xtmp old_entry
;
289 utmp_to_xtmp (entry
, &old_entry
);
291 offset
= position
* sizeof (struct xtmp
);
292 if (lseek (database
->old_fd
, offset
, SEEK_SET
) < 0)
295 nbytes
= write (database
->old_fd
, &old_entry
, sizeof (struct xtmp
));
296 if (nbytes
!= sizeof (struct xtmp
))
303 /* Initialize DATABASE. */
305 initialize_database (utmp_database
*database
)
312 /* Check if there is a file in the old format to read. */
313 if (database
->old_file
)
317 if (read_old_entry (database
, position
, &entry
) < 0)
320 #if _HAVE_UT_TYPE - 0
321 /* If the login type is one of RUN_LVL, BOOT_TIME, OLD_TIME or
322 NEW_TIME, search for an entry of the same type in the
323 database, and replace it if the entry in the file is newer. */
324 if (entry
.ut_type
== RUN_LVL
|| entry
.ut_type
== BOOT_TIME
325 || entry
.ut_type
== OLD_TIME
|| entry
.ut_type
== NEW_TIME
)
327 if (store_state_entry (database
, position
, &entry
) < 0)
333 if (store_process_entry (database
, position
, &entry
) < 0)
337 /* Update position. */
343 if (read_entry (database
, position
, &entry
) < 0)
346 if (write_old_entry (database
, position
, &entry
) < 0)
349 /* Update position. */
359 store_state_entry (utmp_database
*database
, int old_position
,
360 const struct utmp
*old_entry
)
362 struct utmp new_entry
;
363 int new_position
= 0;
366 assert (old_entry
->ut_type
== RUN_LVL
367 || old_entry
->ut_type
== BOOT_TIME
368 || old_entry
->ut_type
== OLD_TIME
369 || old_entry
->ut_type
== NEW_TIME
);
373 /* Read the next entry. */
374 if (read_entry (database
, new_position
, &new_entry
) < 0)
377 if (old_entry
->ut_type
== new_entry
.ut_type
)
383 /* Update position. */
389 const struct utmp
*entry
;
391 if (old_entry
->ut_time
> new_entry
.ut_time
)
396 return replace_entry (database
, old_position
, new_position
, entry
);
399 return store_entry (database
, old_position
, old_entry
);
404 store_process_entry (utmp_database
*database
, int old_position
,
405 const struct utmp
*old_entry
)
407 struct utmp new_entry
;
408 int new_position
= 0;
413 /* Read the next entry. */
414 if (read_entry (database
, new_position
, &new_entry
) < 0)
417 if (proc_utmp_eq (old_entry
, &new_entry
))
423 /* Update position. */
429 const struct utmp
*entry
;
431 if (old_entry
->ut_time
> new_entry
.ut_time
)
436 return replace_entry (database
, old_position
, new_position
, entry
);
439 return store_entry (database
, old_position
, old_entry
);
444 replace_entry (utmp_database
*database
, int old_position
, int new_position
,
445 const struct utmp
*entry
)
449 if (read_entry (database
, old_position
, &tmp
) < 0
450 || write_entry (database
, old_position
, entry
) < 0
451 || write_entry (database
, new_position
, &tmp
) < 0)
459 store_entry (utmp_database
*database
, int position
,
460 const struct utmp
*entry
)
464 if (read_entry (database
, position
, &tmp
) < 0)
465 return write_entry (database
, position
, entry
);
467 if (write_entry (database
, position
, entry
) < 0
468 || append_entry (database
, &tmp
) < 0)
475 /* Get modification time of FILE and put it in TIMER. returns 0 if
476 successful, -1 if not. */
478 get_mtime (const char *file
, time_t *timer
)
482 if (stat (file
, &st
) < 0)
485 *timer
= st
.st_mtime
;