Deleted Added
full compact
pututxline.c (215310) pututxline.c (218846)
1/*-
2 * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
1/*-
2 * Copyright (c) 2010 Ed Schouten <ed@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright

--- 11 unchanged lines hidden (view full) ---

20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/lib/libc/gen/pututxline.c 215310 2010-11-14 18:42:39Z ed $");
28__FBSDID("$FreeBSD: head/lib/libc/gen/pututxline.c 218846 2011-02-19 11:31:56Z ed $");
29
30#include "namespace.h"
31#include <sys/endian.h>
32#include <sys/stat.h>
33#include <sys/uio.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <string.h>
38#include <unistd.h>
39#include <utmpx.h>
40#include "utxdb.h"
41#include "un-namespace.h"
42
43static FILE *
44futx_open(const char *file)
45{
29
30#include "namespace.h"
31#include <sys/endian.h>
32#include <sys/stat.h>
33#include <sys/uio.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <stdio.h>
37#include <string.h>
38#include <unistd.h>
39#include <utmpx.h>
40#include "utxdb.h"
41#include "un-namespace.h"
42
43static FILE *
44futx_open(const char *file)
45{
46 int fd;
47 FILE *fp;
48 struct stat sb;
46 struct stat sb;
47 FILE *fp;
48 int fd;
49
50 fd = _open(file, O_CREAT|O_RDWR|O_EXLOCK, 0644);
51 if (fd < 0)
52 return (NULL);
53
54 /* Safety check: never use broken files. */
55 if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) {
56 _close(fd);
49
50 fd = _open(file, O_CREAT|O_RDWR|O_EXLOCK, 0644);
51 if (fd < 0)
52 return (NULL);
53
54 /* Safety check: never use broken files. */
55 if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0) {
56 _close(fd);
57 errno = EINVAL;
57 errno = EFTYPE;
58 return (NULL);
59 }
60
61 fp = fdopen(fd, "r+");
62 if (fp == NULL) {
63 _close(fd);
64 return (NULL);
65 }
58 return (NULL);
59 }
60
61 fp = fdopen(fd, "r+");
62 if (fp == NULL) {
63 _close(fd);
64 return (NULL);
65 }
66
67 return (fp);
68}
69
70static int
71utx_active_add(const struct futx *fu)
72{
66 return (fp);
67}
68
69static int
70utx_active_add(const struct futx *fu)
71{
73 FILE *fp;
74 struct futx fe;
72 struct futx fe;
73 FILE *fp;
75 off_t partial = -1;
74 off_t partial = -1;
75 int error, ret;
76
77 /*
78 * Register user login sessions. Overwrite entries of sessions
79 * that have already been terminated.
80 */
81 fp = futx_open(_PATH_UTX_ACTIVE);
82 if (fp == NULL)
76
77 /*
78 * Register user login sessions. Overwrite entries of sessions
79 * that have already been terminated.
80 */
81 fp = futx_open(_PATH_UTX_ACTIVE);
82 if (fp == NULL)
83 return (1);
84 while (fread(&fe, sizeof fe, 1, fp) == 1) {
83 return (-1);
84 while (fread(&fe, sizeof(fe), 1, fp) == 1) {
85 switch (fe.fu_type) {
86 case USER_PROCESS:
87 case INIT_PROCESS:
88 case LOGIN_PROCESS:
89 case DEAD_PROCESS:
90 /* Overwrite when ut_id matches. */
85 switch (fe.fu_type) {
86 case USER_PROCESS:
87 case INIT_PROCESS:
88 case LOGIN_PROCESS:
89 case DEAD_PROCESS:
90 /* Overwrite when ut_id matches. */
91 if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) == 0) {
92 fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
91 if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) ==
92 0) {
93 ret = fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR);
93 goto exact;
94 }
95 if (fe.fu_type != DEAD_PROCESS)
96 break;
97 /* FALLTHROUGH */
98 default:
99 /* Allow us to overwrite unused records. */
94 goto exact;
95 }
96 if (fe.fu_type != DEAD_PROCESS)
97 break;
98 /* FALLTHROUGH */
99 default:
100 /* Allow us to overwrite unused records. */
100 if (partial == -1)
101 partial = ftello(fp) - (off_t)sizeof fe;
101 if (partial == -1) {
102 partial = ftello(fp);
103 /*
104 * Distinguish errors from valid values so we
105 * don't overwrite good data by accident.
106 */
107 if (partial != -1)
108 partial -= (off_t)sizeof(fe);
109 }
102 break;
103 }
104 }
110 break;
111 }
112 }
105
113
106 /*
107 * No exact match found. Use the partial match. If no partial
108 * match was found, just append a new record.
109 */
110 if (partial != -1)
114 /*
115 * No exact match found. Use the partial match. If no partial
116 * match was found, just append a new record.
117 */
118 if (partial != -1)
111 fseeko(fp, partial, SEEK_SET);
119 ret = fseeko(fp, partial, SEEK_SET);
112exact:
120exact:
113 fwrite(fu, sizeof *fu, 1, fp);
121 if (ret == -1)
122 error = errno;
123 else if (fwrite(fu, sizeof(*fu), 1, fp) < 1)
124 error = errno;
125 else
126 error = 0;
114 fclose(fp);
127 fclose(fp);
115 return (0);
128 errno = error;
129 return (error == 0 ? 0 : 1);
116}
117
118static int
119utx_active_remove(struct futx *fu)
120{
130}
131
132static int
133utx_active_remove(struct futx *fu)
134{
121 FILE *fp;
122 struct futx fe;
135 struct futx fe;
136 FILE *fp;
137 int error, ret;
123
124 /*
125 * Remove user login sessions, having the same ut_id.
126 */
127 fp = futx_open(_PATH_UTX_ACTIVE);
128 if (fp == NULL)
138
139 /*
140 * Remove user login sessions, having the same ut_id.
141 */
142 fp = futx_open(_PATH_UTX_ACTIVE);
143 if (fp == NULL)
129 return (1);
130 while (fread(&fe, sizeof fe, 1, fp) == 1) {
144 return (-1);
145 error = ESRCH;
146 ret = -1;
147 while (fread(&fe, sizeof(fe), 1, fp) == 1 && ret != 0)
131 switch (fe.fu_type) {
132 case USER_PROCESS:
133 case INIT_PROCESS:
134 case LOGIN_PROCESS:
148 switch (fe.fu_type) {
149 case USER_PROCESS:
150 case INIT_PROCESS:
151 case LOGIN_PROCESS:
135 if (memcmp(fu->fu_id, fe.fu_id, sizeof fe.fu_id) != 0)
152 if (memcmp(fu->fu_id, fe.fu_id, sizeof(fe.fu_id)) != 0)
136 continue;
137
138 /* Terminate session. */
153 continue;
154
155 /* Terminate session. */
139 fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
140 fwrite(fu, sizeof *fu, 1, fp);
141 fclose(fp);
142 return (0);
156 if (fseeko(fp, -(off_t)sizeof(fe), SEEK_CUR) == -1)
157 error = errno;
158 else if (fwrite(fu, sizeof(*fu), 1, fp) < 1)
159 error = errno;
160 else
161 ret = 0;
162
143 }
163 }
144 }
145
146 fclose(fp);
164
165 fclose(fp);
147 errno = ESRCH;
148 return (1);
166 errno = error;
167 return (ret);
149}
150
151static void
152utx_active_purge(void)
153{
154
155 truncate(_PATH_UTX_ACTIVE, 0);
156}
157
158static int
159utx_lastlogin_add(const struct futx *fu)
160{
168}
169
170static void
171utx_active_purge(void)
172{
173
174 truncate(_PATH_UTX_ACTIVE, 0);
175}
176
177static int
178utx_lastlogin_add(const struct futx *fu)
179{
161 FILE *fp;
162 struct futx fe;
180 struct futx fe;
181 FILE *fp;
182 int error, ret;
163
183
184 ret = 0;
185
164 /*
165 * Write an entry to lastlogin. Overwrite the entry if the
166 * current user already has an entry. If not, append a new
167 * entry.
168 */
169 fp = futx_open(_PATH_UTX_LASTLOGIN);
170 if (fp == NULL)
186 /*
187 * Write an entry to lastlogin. Overwrite the entry if the
188 * current user already has an entry. If not, append a new
189 * entry.
190 */
191 fp = futx_open(_PATH_UTX_LASTLOGIN);
192 if (fp == NULL)
171 return (1);
193 return (-1);
172 while (fread(&fe, sizeof fe, 1, fp) == 1) {
173 if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0)
174 continue;
194 while (fread(&fe, sizeof fe, 1, fp) == 1) {
195 if (strncmp(fu->fu_user, fe.fu_user, sizeof fe.fu_user) != 0)
196 continue;
175
197
176 /* Found a previous lastlogin entry for this user. */
198 /* Found a previous lastlogin entry for this user. */
177 fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
199 ret = fseeko(fp, -(off_t)sizeof fe, SEEK_CUR);
178 break;
179 }
200 break;
201 }
180 fwrite(fu, sizeof *fu, 1, fp);
202 if (ret == -1)
203 error = errno;
204 else if (fwrite(fu, sizeof *fu, 1, fp) < 1) {
205 error = errno;
206 ret = -1;
207 }
181 fclose(fp);
208 fclose(fp);
182 return (0);
209 errno = error;
210 return (ret);
183}
184
185static void
186utx_lastlogin_upgrade(void)
187{
211}
212
213static void
214utx_lastlogin_upgrade(void)
215{
188 int fd;
189 struct stat sb;
216 struct stat sb;
217 int fd;
190
191 fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR, 0644);
192 if (fd < 0)
193 return;
194
195 /*
196 * Truncate broken lastlogin files. In the future we should
197 * check for older versions of the file format here and try to
198 * upgrade it.
199 */
200 if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0)
201 ftruncate(fd, 0);
202 _close(fd);
203}
204
205static int
206utx_log_add(const struct futx *fu)
207{
218
219 fd = _open(_PATH_UTX_LASTLOGIN, O_RDWR, 0644);
220 if (fd < 0)
221 return;
222
223 /*
224 * Truncate broken lastlogin files. In the future we should
225 * check for older versions of the file format here and try to
226 * upgrade it.
227 */
228 if (_fstat(fd, &sb) != -1 && sb.st_size % sizeof(struct futx) != 0)
229 ftruncate(fd, 0);
230 _close(fd);
231}
232
233static int
234utx_log_add(const struct futx *fu)
235{
208 int fd;
209 uint16_t l;
210 struct iovec vec[2];
236 struct iovec vec[2];
237 int error, fd;
238 uint16_t l;
211
212 /*
213 * Append an entry to the log file. We only need to append
214 * records to this file, so to conserve space, trim any trailing
215 * zero-bytes. Prepend a length field, indicating the length of
216 * the record, excluding the length field itself.
217 */
239
240 /*
241 * Append an entry to the log file. We only need to append
242 * records to this file, so to conserve space, trim any trailing
243 * zero-bytes. Prepend a length field, indicating the length of
244 * the record, excluding the length field itself.
245 */
218 for (l = sizeof *fu; l > 0 && ((const char *)fu)[l - 1] == '\0'; l--);
246 for (l = sizeof(*fu); l > 0 && ((const char *)fu)[l - 1] == '\0'; l--) ;
219 vec[0].iov_base = &l;
247 vec[0].iov_base = &l;
220 vec[0].iov_len = sizeof l;
248 vec[0].iov_len = sizeof(l);
221 vec[1].iov_base = __DECONST(void *, fu);
222 vec[1].iov_len = l;
223 l = htobe16(l);
224
225 fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND, 0644);
226 if (fd < 0)
249 vec[1].iov_base = __DECONST(void *, fu);
250 vec[1].iov_len = l;
251 l = htobe16(l);
252
253 fd = _open(_PATH_UTX_LOG, O_CREAT|O_WRONLY|O_APPEND, 0644);
254 if (fd < 0)
227 return (1);
228 _writev(fd, vec, 2);
255 return (-1);
256 if (_writev(fd, vec, 2) == -1)
257 error = errno;
258 else
259 error = 0;
229 _close(fd);
260 _close(fd);
230 return (0);
261 errno = error;
262 return (error == 0 ? 0 : 1);
231}
232
233struct utmpx *
234pututxline(const struct utmpx *utmpx)
235{
236 struct futx fu;
237 int bad = 0;
238
239 utx_to_futx(utmpx, &fu);
263}
264
265struct utmpx *
266pututxline(const struct utmpx *utmpx)
267{
268 struct futx fu;
269 int bad = 0;
270
271 utx_to_futx(utmpx, &fu);
240
272
241 switch (fu.fu_type) {
242 case BOOT_TIME:
243 case SHUTDOWN_TIME:
244 utx_active_purge();
245 utx_lastlogin_upgrade();
246 break;
247 case OLD_TIME:
248 case NEW_TIME:

--- 13 unchanged lines hidden (view full) ---

262 * In case writing a logout entry fails, never attempt
263 * to write it to utx.log. The logout entry's ut_id
264 * might be invalid.
265 */
266 if (utx_active_remove(&fu) != 0)
267 return (NULL);
268 break;
269 default:
273 switch (fu.fu_type) {
274 case BOOT_TIME:
275 case SHUTDOWN_TIME:
276 utx_active_purge();
277 utx_lastlogin_upgrade();
278 break;
279 case OLD_TIME:
280 case NEW_TIME:

--- 13 unchanged lines hidden (view full) ---

294 * In case writing a logout entry fails, never attempt
295 * to write it to utx.log. The logout entry's ut_id
296 * might be invalid.
297 */
298 if (utx_active_remove(&fu) != 0)
299 return (NULL);
300 break;
301 default:
302 errno = EINVAL;
270 return (NULL);
271 }
272
273 bad |= utx_log_add(&fu);
274 return (bad ? NULL : futx_to_utx(&fu));
275}
303 return (NULL);
304 }
305
306 bad |= utx_log_add(&fu);
307 return (bad ? NULL : futx_to_utx(&fu));
308}