blob: f97cad3c8c7d90314f6a03c361bbb9b629a7da94 [file] [log] [blame]
lh9ed821d2023-04-07 01:36:19 -07001/* utent.c <ndf@linux.mit.edu> */
2/* Let it be known that this is very possibly the worst standard ever. HP-UX
3 does one thing, someone else does another, linux another... If anyone
4 actually has the standard, please send it to me.
5
6 Note that because of the way this stupid stupid standard works, you
7 have to call endutent() to close the file even if you've not called
8 setutent -- getutid and family use the same file descriptor.
9
10 Modified by Erik Andersen for uClibc...
11*/
12
13#include <features.h>
14#include <stdio.h>
15#include <stdlib.h>
16#include <unistd.h>
17#include <fcntl.h>
18#include <paths.h>
19#include <errno.h>
20#include <string.h>
21#include <utmp.h>
22#include <not-cancel.h>
23
24#include <bits/uClibc_mutex.h>
25__UCLIBC_MUTEX_STATIC(utmplock, PTHREAD_MUTEX_INITIALIZER);
26
27
28/* Do not create extra unlocked functions if no locking is needed */
29#if defined __UCLIBC_HAS_THREADS__
30# define static_if_threaded static
31#else
32# define static_if_threaded /* nothing */
33# define __setutent setutent
34# define __getutent getutent
35# define __getutid getutid
36#endif
37
38
39/* Some global crap */
40static int static_fd = -1;
41static struct utmp static_utmp;
42static const char default_file_name[] = _PATH_UTMP;
43static const char *static_ut_name = default_file_name;
44
45
46/* This function must be called with the LOCK held */
47static_if_threaded void __setutent(void)
48{
49 if (static_fd < 0) {
50 static_fd = open_not_cancel_2(static_ut_name, O_RDWR | O_CLOEXEC);
51 if (static_fd < 0) {
52 static_fd = open_not_cancel_2(static_ut_name, O_RDONLY | O_CLOEXEC);
53 if (static_fd < 0) {
54 return; /* static_fd remains < 0 */
55 }
56 }
57#ifndef __ASSUME_O_CLOEXEC
58 /* Make sure the file will be closed on exec() */
59 fcntl_not_cancel(static_fd, F_SETFD, FD_CLOEXEC);
60#endif
61 return;
62 }
63 lseek(static_fd, 0, SEEK_SET);
64}
65#if defined __UCLIBC_HAS_THREADS__
66void setutent(void)
67{
68 __UCLIBC_MUTEX_LOCK(utmplock);
69 __setutent();
70 __UCLIBC_MUTEX_UNLOCK(utmplock);
71}
72#endif
73libc_hidden_def(setutent)
74
75/* This function must be called with the LOCK held */
76static_if_threaded struct utmp *__getutent(void)
77{
78 if (static_fd < 0) {
79 __setutent();
80 if (static_fd < 0) {
81 return NULL;
82 }
83 }
84
85 if (read_not_cancel(static_fd, &static_utmp, sizeof(static_utmp)) == sizeof(static_utmp)) {
86 return &static_utmp;
87 }
88
89 return NULL;
90}
91#if defined __UCLIBC_HAS_THREADS__
92struct utmp *getutent(void)
93{
94 struct utmp *ret;
95
96 __UCLIBC_MUTEX_LOCK(utmplock);
97 ret = __getutent();
98 __UCLIBC_MUTEX_UNLOCK(utmplock);
99 return ret;
100}
101#endif
102libc_hidden_def(getutent)
103
104void endutent(void)
105{
106 __UCLIBC_MUTEX_LOCK(utmplock);
107 if (static_fd >= 0)
108 close_not_cancel_no_status(static_fd);
109 static_fd = -1;
110 __UCLIBC_MUTEX_UNLOCK(utmplock);
111}
112libc_hidden_def(endutent)
113
114/* This function must be called with the LOCK held */
115static_if_threaded struct utmp *__getutid(const struct utmp *utmp_entry)
116{
117 struct utmp *lutmp;
118 unsigned type;
119
120 /* We use the fact that constants we are interested in are: */
121 /* RUN_LVL=1, ... OLD_TIME=4; INIT_PROCESS=5, ... USER_PROCESS=8 */
122 type = utmp_entry->ut_type - 1;
123 type /= 4;
124
125 while ((lutmp = __getutent()) != NULL) {
126 if (type == 0 && lutmp->ut_type == utmp_entry->ut_type) {
127 /* one of RUN_LVL, BOOT_TIME, NEW_TIME, OLD_TIME */
128 return lutmp;
129 }
130 if (type == 1 && strncmp(lutmp->ut_id, utmp_entry->ut_id, sizeof(lutmp->ut_id)) == 0) {
131 /* INIT_PROCESS, LOGIN_PROCESS, USER_PROCESS, DEAD_PROCESS */
132 return lutmp;
133 }
134 }
135
136 return NULL;
137}
138#if defined __UCLIBC_HAS_THREADS__
139struct utmp *getutid(const struct utmp *utmp_entry)
140{
141 struct utmp *ret;
142
143 __UCLIBC_MUTEX_LOCK(utmplock);
144 ret = __getutid(utmp_entry);
145 __UCLIBC_MUTEX_UNLOCK(utmplock);
146 return ret;
147}
148#endif
149libc_hidden_def(getutid)
150
151struct utmp *getutline(const struct utmp *utmp_entry)
152{
153 struct utmp *lutmp;
154
155 __UCLIBC_MUTEX_LOCK(utmplock);
156 while ((lutmp = __getutent()) != NULL) {
157 if (lutmp->ut_type == USER_PROCESS || lutmp->ut_type == LOGIN_PROCESS) {
158 if (strncmp(lutmp->ut_line, utmp_entry->ut_line, sizeof(lutmp->ut_line)) == 0) {
159 break;
160 }
161 }
162 }
163 __UCLIBC_MUTEX_UNLOCK(utmplock);
164 return lutmp;
165}
166libc_hidden_def(getutline)
167
168struct utmp *pututline(const struct utmp *utmp_entry)
169{
170 __UCLIBC_MUTEX_LOCK(utmplock);
171 /* Ignore the return value. That way, if they've already positioned
172 the file pointer where they want it, everything will work out. */
173 lseek(static_fd, (off_t) - sizeof(struct utmp), SEEK_CUR);
174
175 if (__getutid(utmp_entry) != NULL)
176 lseek(static_fd, (off_t) - sizeof(struct utmp), SEEK_CUR);
177 else
178 lseek(static_fd, (off_t) 0, SEEK_END);
179 if (write(static_fd, utmp_entry, sizeof(struct utmp)) != sizeof(struct utmp))
180 utmp_entry = NULL;
181
182 __UCLIBC_MUTEX_UNLOCK(utmplock);
183 return (struct utmp *)utmp_entry;
184}
185libc_hidden_def(pututline)
186
187int utmpname(const char *new_ut_name)
188{
189 __UCLIBC_MUTEX_LOCK(utmplock);
190 if (new_ut_name != NULL) {
191 if (static_ut_name != default_file_name)
192 free((char *)static_ut_name);
193 static_ut_name = strdup(new_ut_name);
194 if (static_ut_name == NULL) {
195 /* We should probably whine about out-of-memory
196 * errors here... Instead just reset to the default */
197 static_ut_name = default_file_name;
198 }
199 }
200
201 if (static_fd >= 0) {
202 close_not_cancel_no_status(static_fd);
203 static_fd = -1;
204 }
205 __UCLIBC_MUTEX_UNLOCK(utmplock);
206 return 0; /* or maybe return -(static_ut_name != new_ut_name)? */
207}
208libc_hidden_def(utmpname)