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. */