1 /* Copyright (C) 1996, 1997 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. */
31 #include "utmp-private.h"
34 /* Descriptor for the file and position. */
35 static int file_fd = INT_MIN;
36 static off_t file_offset;
38 static struct utmp last_entry;
41 /* Functions defined here. */
42 static int setutent_file (int reset);
43 static int getutent_r_file (struct utmp *buffer, struct utmp **result);
44 static int getutid_r_file (const struct utmp *key, struct utmp *buffer,
45 struct utmp **result);
46 static int getutline_r_file (const struct utmp *key, struct utmp *buffer,
47 struct utmp **result);
48 static struct utmp *pututline_file (const struct utmp *data);
49 static void endutent_file (void);
50 static int updwtmp_file (const char *file, const struct utmp *utmp);
52 /* Jump table for file functions. */
53 struct utfuncs __libc_utmp_file_functions =
66 setutent_file (int reset)
68 if (file_fd == INT_MIN)
70 file_fd = open (__libc_utmp_file_name, O_RDWR);
73 /* Hhm, read-write access did not work. Try read-only. */
74 file_fd = open (__libc_utmp_file_name, O_RDONLY);
77 perror (_("while opening UTMP file"));
84 /* Make sure the entry won't match. */
85 last_entry.ut_type = -1;
90 lseek (file_fd, 0, SEEK_SET);
92 /* Remember we are at beginning of file. */
96 /* Make sure the entry won't match. */
97 last_entry.ut_type = -1;
116 getutent_r_file (struct utmp *buffer, struct utmp **result)
119 struct flock fl; /* Information struct for locking. */
121 /* Open utmp file if not already done. */
122 if (file_fd == INT_MIN)
125 if (file_fd == -1 || file_offset == -1l)
132 /* XXX The following is not perfect. Instead of locking the file itself
133 Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl> suggests to
134 use an extra locking file. */
136 /* Try to get the lock. */
137 memset (&fl, '\0', sizeof (struct flock));
139 fl.l_whence = SEEK_SET;
140 fcntl (file_fd, F_SETLKW, &fl);
142 /* Read the next entry. */
143 nbytes = read (file_fd, &last_entry, sizeof (struct utmp));
145 /* And unlock the file. */
147 fcntl (file_fd, F_SETLKW, &fl);
149 if (nbytes != sizeof (struct utmp))
156 /* Update position pointer. */
157 file_offset += sizeof (struct utmp);
159 memcpy (buffer, &last_entry, sizeof (struct utmp));
166 /* For implementing this function we don't use the getutent_r function
167 because we can avoid the reposition on every new entry this way. */
169 getutline_r_file (const struct utmp *line, struct utmp *buffer,
170 struct utmp **result)
174 if (file_fd < 0 || file_offset == -1l)
180 /* Try to get the lock. */
181 memset (&fl, '\0', sizeof (struct flock));
183 fl.l_whence = SEEK_SET;
184 fcntl (file_fd, F_SETLKW, &fl);
188 /* Read the next entry. */
189 if (read (file_fd, &last_entry, sizeof (struct utmp))
190 != sizeof (struct utmp))
197 file_offset += sizeof (struct utmp);
199 /* Stop if we found a user or login entry. */
201 #if _HAVE_UT_TYPE - 0
202 (last_entry.ut_type == USER_PROCESS
203 || last_entry.ut_type == LOGIN_PROCESS)
206 !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line))
210 memcpy (buffer, &last_entry, sizeof (struct utmp));
214 /* And unlock the file. */
216 fcntl (file_fd, F_SETLKW, &fl);
218 return ((result == NULL) ? -1 : 0);
223 proc_utmp_eq (const struct utmp *entry, const struct utmp *match)
227 #if _HAVE_UT_TYPE - 0
228 (entry->ut_type == INIT_PROCESS
229 || entry->ut_type == LOGIN_PROCESS
230 || entry->ut_type == USER_PROCESS
231 || entry->ut_type == DEAD_PROCESS)
233 (match->ut_type == INIT_PROCESS
234 || match->ut_type == LOGIN_PROCESS
235 || match->ut_type == USER_PROCESS
236 || match->ut_type == DEAD_PROCESS)
240 (entry->ut_id[0] && match->ut_id[0]
241 ? strncmp (entry->ut_id, match->ut_id, sizeof match->ut_id) == 0
242 : strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0)
244 strncmp (entry->ut_line, match->ut_line, sizeof match->ut_line) == 0
250 internal_getut_r (const struct utmp *id, struct utmp *buffer)
255 /* Try to get the lock. */
256 memset (&fl, '\0', sizeof (struct flock));
258 fl.l_whence = SEEK_SET;
259 fcntl (file_fd, F_SETLKW, &fl);
261 #if _HAVE_UT_TYPE - 0
262 if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
263 || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
265 /* Search for next entry with type RUN_LVL, BOOT_TIME,
266 OLD_TIME, or NEW_TIME. */
270 /* Read the next entry. */
271 if (read (file_fd, buffer, sizeof (struct utmp))
272 != sizeof (struct utmp))
278 file_offset += sizeof (struct utmp);
280 if (id->ut_type == buffer->ut_type)
285 #endif /* _HAVE_UT_TYPE */
287 /* Search for the next entry with the specified ID and with type
288 INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, or DEAD_PROCESS. */
292 /* Read the next entry. */
293 if (read (file_fd, buffer, sizeof (struct utmp))
294 != sizeof (struct utmp))
300 file_offset += sizeof (struct utmp);
302 if (proc_utmp_eq (buffer, id))
310 /* And unlock the file. */
312 fcntl (file_fd, F_SETLKW, &fl);
318 /* For implementing this function we don't use the getutent_r function
319 because we can avoid the reposition on every new entry this way. */
321 getutid_r_file (const struct utmp *id, struct utmp *buffer,
322 struct utmp **result)
324 if (file_fd < 0 || file_offset == -1l)
330 if (internal_getut_r (id, &last_entry) < 0)
336 memcpy (buffer, &last_entry, sizeof (struct utmp));
344 pututline_file (const struct utmp *data)
346 struct flock fl; /* Information struct for locking. */
352 /* Something went wrong. */
355 if (file_fd == INT_MIN)
356 /* The file is closed. Open it again. */
359 /* Find the correct place to insert the data. */
362 #if _HAVE_UT_TYPE - 0
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))
370 proc_utmp_eq (&last_entry, data)))
373 found = internal_getut_r (data, &buffer);
375 /* Try to lock the file. */
376 memset (&fl, '\0', sizeof (struct flock));
378 fl.l_whence = SEEK_SET;
379 fcntl (file_fd, F_SETLKW, &fl);
383 /* We append the next entry. */
384 file_offset = lseek (file_fd, 0, SEEK_END);
385 if (file_offset % sizeof (struct utmp) != 0)
387 file_offset -= file_offset % sizeof (struct utmp);
388 ftruncate (file_fd, file_offset);
390 if (lseek (file_fd, 0, SEEK_END) < 0)
399 /* We replace the just read entry. */
400 file_offset -= sizeof (struct utmp);
401 lseek (file_fd, file_offset, SEEK_SET);
404 /* Write the new data. */
405 if (write (file_fd, data, sizeof (struct utmp)) != sizeof (struct utmp)
406 /* If we appended a new record this is only partially written.
410 (void) ftruncate (file_fd, file_offset);
415 file_offset += sizeof (struct utmp);
416 pbuf = (struct utmp *) data;
420 /* And unlock the file. */
422 fcntl (file_fd, F_SETLKW, &fl);
429 updwtmp_file (const char *file, const struct utmp *utmp)
436 /* Open WTMP file. */
437 fd = open (file, O_WRONLY);
441 /* Try to get the lock. */
442 memset (&fl, '\0', sizeof (struct flock));
444 fl.l_whence = SEEK_SET;
445 fcntl (fd, F_SETLKW, &fl);
447 /* Remember original size of log file. */
448 offset = lseek (fd, 0, SEEK_END);
449 if (offset % sizeof (struct utmp) != 0)
451 offset -= offset % sizeof (struct utmp);
452 ftruncate (fd, offset);
454 if (lseek (fd, 0, SEEK_END) < 0)
458 /* Write the entry. If we can't write all the bytes, reset the file
459 size back to the original size. That way, no partial entries
461 if (write (fd, utmp, sizeof (struct utmp)) != sizeof (struct utmp))
463 ftruncate (fd, offset);
470 /* And unlock the file. */
472 fcntl (fd, F_SETLKW, &fl);
474 /* Close WTMP file. */