1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21: #include <assert.h>
22: #include <errno.h>
23: #include <fcntl.h>
24: #include <signal.h>
25: #include <stdio.h>
26: #include <string.h>
27: #include <unistd.h>
28: #include <utmp.h>
29: #include <not-cancel.h>
30: #include <kernel-features.h>
31:
32: #include "utmp-private.h"
33: #include "utmp-equal.h"
34:
35:
36:
37: static int file_fd = -1;
38: static off64_t file_offset;
39:
40:
41: static struct utmp last_entry;
42:
43:
44:
45: #ifndef TIMEOUT
46: # define TIMEOUT 1
47: #endif
48:
49:
50: static void timeout_handler (int signum) {};
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61: #define LOCK_FILE(fd, type) \
62: { \
63: struct flock fl; \
64: struct sigaction action, old_action; \
65: unsigned int old_timeout; \
66: \
67: \
68: old_timeout = alarm (0); \
69: \
70: \
71: action.sa_handler = timeout_handler; \
72: __sigemptyset (&action.sa_mask); \
73: action.sa_flags = 0; \
74: __sigaction (SIGALRM, &action, &old_action); \
75: \
76: alarm (TIMEOUT); \
77: \
78: \
79: memset (&fl, '\0', sizeof (struct flock)); \
80: fl.l_type = (type); \
81: fl.l_whence = SEEK_SET; \
82: if (fcntl_not_cancel ((fd), F_SETLKW, &fl) < 0)
83:
84: #define LOCKING_FAILED() \
85: goto unalarm_return
86:
87: #define UNLOCK_FILE(fd) \
88: \
89: fl.l_type = F_UNLCK; \
90: fcntl_not_cancel ((fd), F_SETLKW, &fl); \
91: \
92: unalarm_return: \
93:
94:
95:
96:
97:
98: \
99: alarm (0); \
100: __sigaction (SIGALRM, &old_action, NULL); \
101: if (old_timeout != 0) \
102: alarm (old_timeout); \
103: } while (0)
104:
105:
106:
107: static int setutent_file (void);
108: static int getutent_r_file (struct utmp *buffer, struct utmp **result);
109: static int getutid_r_file (const struct utmp *key, struct utmp *buffer,
110: struct utmp **result);
111: static int getutline_r_file (const struct utmp *key, struct utmp *buffer,
112: struct utmp **result);
113: static struct utmp *pututline_file (const struct utmp *data);
114: static void endutent_file (void);
115: static int updwtmp_file (const char *file, const struct utmp *utmp);
116:
117:
118: const struct utfuncs __libc_utmp_file_functions =
119: {
120: setutent_file,
121: getutent_r_file,
122: getutid_r_file,
123: getutline_r_file,
124: pututline_file,
125: endutent_file,
126: updwtmp_file
127: };
128:
129:
130: #ifndef TRANSFORM_UTMP_FILE_NAME
131: # define TRANSFORM_UTMP_FILE_NAME(file_name) (file_name)
132: #endif
133:
134: static int
135: setutent_file (void)
136: {
137: if (file_fd < 0)
138: {
139: const char *file_name;
140: int result;
141:
142: file_name = TRANSFORM_UTMP_FILE_NAME (__libc_utmp_file_name);
143:
144: #ifdef O_CLOEXEC
145: # define O_flags O_LARGEFILE | O_CLOEXEC
146: #else
147: # define O_flags O_LARGEFILE
148: #endif
149: file_fd = open_not_cancel_2 (file_name, O_RDWR | O_flags);
150: if (file_fd == -1)
151: {
152:
153: file_fd = open_not_cancel_2 (file_name, O_RDONLY | O_flags);
154: if (file_fd == -1)
155: return 0;
156: }
157:
158: #ifndef __ASSUME_O_CLOEXEC
159: # ifdef O_CLOEXEC
160: if (__have_o_cloexec <= 0)
161: # endif
162: {
163:
164: result = fcntl_not_cancel (file_fd, F_GETFD, 0);
165: if (result >= 0)
166: {
167: # ifdef O_CLOEXEC
168: if (__have_o_cloexec == 0)
169: __have_o_cloexec = (result & FD_CLOEXEC) ? 1 : -1;
170: # endif
171:
172: result = fcntl_not_cancel (file_fd, F_SETFD,
173: result | FD_CLOEXEC);
174: }
175:
176: if (result == -1)
177: {
178: close_not_cancel_no_status (file_fd);
179: return 0;
180: }
181: }
182: #endif
183: }
184:
185: __lseek64 (file_fd, 0, SEEK_SET);
186: file_offset = 0;
187:
188:
189: #if _HAVE_UT_TYPE - 0
190: last_entry.ut_type = -1;
191: #else
192: last_entry.ut_line[0] = '\177';
193: # if _HAVE_UT_ID - 0
194: last_entry.ut_id[0] = '\0';
195: # endif
196: #endif
197:
198: return 1;
199: }
200:
201:
202: static int
203: getutent_r_file (struct utmp *buffer, struct utmp **result)
204: {
205: ssize_t nbytes;
206:
207: assert (file_fd >= 0);
208:
209: if (file_offset == -1l)
210: {
211:
212: *result = NULL;
213: return -1;
214: }
215:
216: LOCK_FILE (file_fd, F_RDLCK)
217: {
218: nbytes = 0;
219: LOCKING_FAILED ();
220: }
221:
222:
223: nbytes = read_not_cancel (file_fd, &last_entry, sizeof (struct utmp));
224:
225: UNLOCK_FILE (file_fd);
226:
227: if (nbytes != sizeof (struct utmp))
228: {
229: if (nbytes != 0)
230: file_offset = -1l;
231: *result = NULL;
232: return -1;
233: }
234:
235:
236: file_offset += sizeof (struct utmp);
237:
238: memcpy (buffer, &last_entry, sizeof (struct utmp));
239: *result = buffer;
240:
241: return 0;
242: }
243:
244:
245: static int
246: internal_getut_r (const struct utmp *id, struct utmp *buffer)
247: {
248: int result = -1;
249:
250: LOCK_FILE (file_fd, F_RDLCK)
251: LOCKING_FAILED ();
252:
253: #if _HAVE_UT_TYPE - 0
254: if (id->ut_type == RUN_LVL || id->ut_type == BOOT_TIME
255: || id->ut_type == OLD_TIME || id->ut_type == NEW_TIME)
256: {
257:
258:
259:
260: while (1)
261: {
262:
263: if (read_not_cancel (file_fd, buffer, sizeof (struct utmp))
264: != sizeof (struct utmp))
265: {
266: __set_errno (ESRCH);
267: file_offset = -1l;
268: goto unlock_return;
269: }
270: file_offset += sizeof (struct utmp);
271:
272: if (id->ut_type == buffer->ut_type)
273: break;
274: }
275: }
276: else
277: #endif
278: {
279:
280:
281:
282: while (1)
283: {
284:
285: if (read_not_cancel (file_fd, buffer, sizeof (struct utmp))
286: != sizeof (struct utmp))
287: {
288: __set_errno (ESRCH);
289: file_offset = -1l;
290: goto unlock_return;
291: }
292: file_offset += sizeof (struct utmp);
293:
294: if (__utmp_equal (buffer, id))
295: break;
296: }
297: }
298:
299: result = 0;
300:
301: unlock_return:
302: UNLOCK_FILE (file_fd);
303:
304: return result;
305: }
306:
307:
308:
309:
310: static int
311: getutid_r_file (const struct utmp *id, struct utmp *buffer,
312: struct utmp **result)
313: {
314: assert (file_fd >= 0);
315:
316: if (file_offset == -1l)
317: {
318: *result = NULL;
319: return -1;
320: }
321:
322: if (internal_getut_r (id, &last_entry) < 0)
323: {
324: *result = NULL;
325: return -1;
326: }
327:
328: memcpy (buffer, &last_entry, sizeof (struct utmp));
329: *result = buffer;
330:
331: return 0;
332: }
333:
334:
335:
336:
337: static int
338: getutline_r_file (const struct utmp *line, struct utmp *buffer,
339: struct utmp **result)
340: {
341: assert (file_fd >= 0);
342:
343: if (file_offset == -1l)
344: {
345: *result = NULL;
346: return -1;
347: }
348:
349: LOCK_FILE (file_fd, F_RDLCK)
350: {
351: *result = NULL;
352: LOCKING_FAILED ();
353: }
354:
355: while (1)
356: {
357:
358: if (read_not_cancel (file_fd, &last_entry, sizeof (struct utmp))
359: != sizeof (struct utmp))
360: {
361: __set_errno (ESRCH);
362: file_offset = -1l;
363: *result = NULL;
364: goto unlock_return;
365: }
366: file_offset += sizeof (struct utmp);
367:
368:
369: if (
370: #if _HAVE_UT_TYPE - 0
371: (last_entry.ut_type == USER_PROCESS
372: || last_entry.ut_type == LOGIN_PROCESS)
373: &&
374: #endif
375: !strncmp (line->ut_line, last_entry.ut_line, sizeof line->ut_line))
376: break;
377: }
378:
379: memcpy (buffer, &last_entry, sizeof (struct utmp));
380: *result = buffer;
381:
382: unlock_return:
383: UNLOCK_FILE (file_fd);
384:
385: return ((*result == NULL) ? -1 : 0);
386: }
387:
388:
389: static struct utmp *
390: pututline_file (const struct utmp *data)
391: {
392: struct utmp buffer;
393: struct utmp *pbuf;
394: int found;
395:
396: assert (file_fd >= 0);
397:
398:
399: if (file_offset > 0
400: && (
401: #if _HAVE_UT_TYPE - 0
402: (last_entry.ut_type == data->ut_type
403: && (last_entry.ut_type == RUN_LVL
404: || last_entry.ut_type == BOOT_TIME
405: || last_entry.ut_type == OLD_TIME
406: || last_entry.ut_type == NEW_TIME))
407: ||
408: #endif
409: __utmp_equal (&last_entry, data)))
410: found = 1;
411: else
412: found = internal_getut_r (data, &buffer);
413:
414: LOCK_FILE (file_fd, F_WRLCK)
415: {
416: pbuf = NULL;
417: LOCKING_FAILED ();
418: }
419:
420: if (found < 0)
421: {
422:
423: file_offset = __lseek64 (file_fd, 0, SEEK_END);
424: if (file_offset % sizeof (struct utmp) != 0)
425: {
426: file_offset -= file_offset % sizeof (struct utmp);
427: __ftruncate64 (file_fd, file_offset);
428:
429: if (__lseek64 (file_fd, 0, SEEK_END) < 0)
430: {
431: pbuf = NULL;
432: goto unlock_return;
433: }
434: }
435: }
436: else
437: {
438:
439: file_offset -= sizeof (struct utmp);
440: __lseek64 (file_fd, file_offset, SEEK_SET);
441: }
442:
443:
444: if (write_not_cancel (file_fd, data, sizeof (struct utmp))
445: != sizeof (struct utmp))
446: {
447:
448:
449: if (found < 0)
450: (void) __ftruncate64 (file_fd, file_offset);
451: pbuf = NULL;
452: }
453: else
454: {
455: file_offset += sizeof (struct utmp);
456: pbuf = (struct utmp *) data;
457: }
458:
459: unlock_return:
460: UNLOCK_FILE (file_fd);
461:
462: return pbuf;
463: }
464:
465:
466: static void
467: endutent_file (void)
468: {
469: assert (file_fd >= 0);
470:
471: close_not_cancel_no_status (file_fd);
472: file_fd = -1;
473: }
474:
475:
476: static int
477: updwtmp_file (const char *file, const struct utmp *utmp)
478: {
479: int result = -1;
480: off64_t offset;
481: int fd;
482:
483:
484: fd = open_not_cancel_2 (file, O_WRONLY | O_LARGEFILE);
485: if (fd < 0)
486: return -1;
487:
488: LOCK_FILE (fd, F_WRLCK)
489: LOCKING_FAILED ();
490:
491:
492: offset = __lseek64 (fd, 0, SEEK_END);
493: if (offset % sizeof (struct utmp) != 0)
494: {
495: offset -= offset % sizeof (struct utmp);
496: __ftruncate64 (fd, offset);
497:
498: if (__lseek64 (fd, 0, SEEK_END) < 0)
499: goto unlock_return;
500: }
501:
502:
503:
504:
505: if (write_not_cancel (fd, utmp, sizeof (struct utmp))
506: != sizeof (struct utmp))
507: {
508: __ftruncate64 (fd, offset);
509: goto unlock_return;
510: }
511:
512: result = 0;
513:
514: unlock_return:
515: UNLOCK_FILE (fd);
516:
517:
518: close_not_cancel_no_status (fd);
519:
520: return result;
521: }