]>
Commit | Line | Data |
---|---|---|
a74aeac6 PR |
1 | /* |
2 | * utmp.c Routines to read/write the utmp and wtmp files. | |
3 | * Basically just wrappers around the library routines. | |
4 | * | |
5 | * Version: @(#)utmp.c 2.77 09-Jun-1999 miquels@cistron.nl | |
6 | * | |
7 | * Copyright (C) 1999 Miquel van Smoorenburg. | |
8 | * | |
9 | * This program is free software; you can redistribute it and/or modify | |
10 | * it under the terms of the GNU General Public License as published by | |
11 | * the Free Software Foundation; either version 2 of the License, or | |
12 | * (at your option) any later version. | |
13 | * | |
14 | * This program is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
17 | * GNU General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with this program; if not, write to the Free Software | |
21 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
22 | * | |
23 | */ | |
24 | #include <sys/types.h> | |
25 | #include <sys/stat.h> | |
26 | #include <sys/ioctl.h> | |
27 | #include <sys/utsname.h> | |
28 | #include <stdlib.h> | |
29 | #include <unistd.h> | |
30 | #include <errno.h> | |
31 | #include <stdio.h> | |
32 | #include <time.h> | |
33 | #include <fcntl.h> | |
34 | #include <string.h> | |
35 | #include <utmp.h> | |
36 | ||
37 | #include "init.h" | |
38 | #include "initreq.h" | |
39 | #include "paths.h" | |
40 | ||
41 | ||
42 | #if defined(__GLIBC__) | |
43 | # if (__GLIBC__ == 2) && (__GLIBC_MINOR__ == 0) && defined(__powerpc__) | |
44 | # define HAVE_UPDWTMP 0 | |
45 | # else | |
46 | # define HAVE_UPDWTMP 1 | |
47 | # endif | |
48 | #else | |
49 | # define HAVE_UPDWTMP 0 | |
50 | #endif | |
51 | ||
52 | ||
53 | /* | |
54 | * Log an event in the wtmp file (reboot, runlevel) | |
55 | */ | |
56 | void write_wtmp( | |
57 | char *user, /* name of user */ | |
58 | char *id, /* inittab ID */ | |
59 | int pid, /* PID of process */ | |
60 | int type, /* TYPE of entry */ | |
61 | char *line) /* Which line is this */ | |
62 | { | |
63 | int fd; | |
64 | struct utmp utmp; | |
65 | struct utsname uname_buf; | |
66 | struct timeval tv; | |
67 | ||
63a2c981 DWF |
68 | /* |
69 | * Can't do much if WTMP_FILE is not present or not writable. | |
70 | */ | |
71 | if (access(WTMP_FILE, W_OK) < 0) | |
72 | return; | |
73 | ||
a74aeac6 PR |
74 | /* |
75 | * Try to open the wtmp file. Note that we even try | |
76 | * this if we have updwtmp() so we can see if the | |
77 | * wtmp file is accessible. | |
78 | */ | |
79 | if ((fd = open(WTMP_FILE, O_WRONLY|O_APPEND)) < 0) return; | |
80 | ||
81 | #ifdef INIT_MAIN | |
82 | /* | |
83 | * Note if we are going to write a boot record. | |
84 | */ | |
85 | if (type == BOOT_TIME) wrote_wtmp_reboot++; | |
86 | ||
87 | /* | |
88 | * See if we need to write a reboot record. The reason that | |
89 | * we are being so paranoid is that when we first tried to | |
90 | * write the reboot record, /var was possibly not mounted | |
91 | * yet. As soon as we can open WTMP we write a delayed boot record. | |
92 | */ | |
93 | if (wrote_wtmp_reboot == 0 && type != BOOT_TIME) | |
94 | write_wtmp("reboot", "~~", 0, BOOT_TIME, "~"); | |
63a2c981 DWF |
95 | |
96 | /* | |
97 | * Note if we are going to write a runlevel record. | |
98 | */ | |
99 | if (type == RUN_LVL) wrote_wtmp_rlevel++; | |
100 | ||
101 | /* | |
102 | * See if we need to write a runlevel record. The reason that | |
103 | * we are being so paranoid is that when we first tried to | |
104 | * write the reboot record, /var was possibly not mounted | |
105 | * yet. As soon as we can open WTMP we write a delayed runlevel record. | |
106 | */ | |
107 | if (wrote_wtmp_rlevel == 0 && type != RUN_LVL) { | |
108 | int runlevel = thislevel; | |
109 | int oldlevel = prevlevel; | |
110 | write_wtmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~"); | |
111 | } | |
a74aeac6 PR |
112 | #endif |
113 | ||
114 | /* | |
115 | * Zero the fields and enter new fields. | |
116 | */ | |
117 | memset(&utmp, 0, sizeof(utmp)); | |
118 | #if defined(__GLIBC__) | |
119 | gettimeofday(&tv, NULL); | |
120 | utmp.ut_tv.tv_sec = tv.tv_sec; | |
121 | utmp.ut_tv.tv_usec = tv.tv_usec; | |
122 | #else | |
123 | time(&utmp.ut_time); | |
124 | #endif | |
125 | utmp.ut_pid = pid; | |
126 | utmp.ut_type = type; | |
127 | strncpy(utmp.ut_name, user, sizeof(utmp.ut_name)); | |
128 | strncpy(utmp.ut_id , id , sizeof(utmp.ut_id )); | |
129 | strncpy(utmp.ut_line, line, sizeof(utmp.ut_line)); | |
130 | ||
131 | /* Put the OS version in place of the hostname */ | |
132 | if (uname(&uname_buf) == 0) | |
133 | strncpy(utmp.ut_host, uname_buf.release, sizeof(utmp.ut_host)); | |
134 | ||
135 | #if HAVE_UPDWTMP | |
136 | updwtmp(WTMP_FILE, &utmp); | |
137 | #else | |
138 | write(fd, (char *)&utmp, sizeof(utmp)); | |
139 | #endif | |
140 | close(fd); | |
141 | } | |
142 | ||
143 | /* | |
144 | * Write an entry to the UTMP file. For DEAD_PROCESS, put | |
145 | * the previous ut_line into oldline if oldline != NULL. | |
146 | */ | |
147 | static void write_utmp( | |
148 | char *user, /* name of user */ | |
149 | char *id, /* inittab ID */ | |
150 | int pid, /* PID of process */ | |
151 | int type, /* TYPE of entry */ | |
152 | char *line, /* LINE if used. */ | |
153 | char *oldline) /* Line of old utmp entry. */ | |
154 | { | |
155 | struct utmp utmp; | |
156 | struct utmp tmp; | |
157 | struct utmp *utmptr; | |
158 | struct timeval tv; | |
159 | ||
160 | /* | |
63a2c981 | 161 | * Can't do much if UTMP_FILE is not present or not writable. |
a74aeac6 | 162 | */ |
63a2c981 | 163 | if (access(UTMP_FILE, W_OK) < 0) |
a74aeac6 PR |
164 | return; |
165 | ||
166 | #ifdef INIT_MAIN | |
167 | /* | |
168 | * Note if we are going to write a boot record. | |
169 | */ | |
170 | if (type == BOOT_TIME) wrote_utmp_reboot++; | |
171 | ||
172 | /* | |
173 | * See if we need to write a reboot record. The reason that | |
174 | * we are being so paranoid is that when we first tried to | |
175 | * write the reboot record, /var was possibly not mounted | |
63a2c981 | 176 | * yet. As soon as we can open UTMP we write a delayed boot record. |
a74aeac6 PR |
177 | */ |
178 | if (wrote_utmp_reboot == 0 && type != BOOT_TIME) | |
179 | write_utmp("reboot", "~~", 0, BOOT_TIME, "~", NULL); | |
63a2c981 DWF |
180 | |
181 | /* | |
182 | * Note if we are going to write a runlevel record. | |
183 | */ | |
184 | if (type == RUN_LVL) wrote_utmp_rlevel++; | |
185 | ||
186 | /* | |
187 | * See if we need to write a runlevel record. The reason that | |
188 | * we are being so paranoid is that when we first tried to | |
189 | * write the reboot record, /var was possibly not mounted | |
190 | * yet. As soon as we can open UTMP we write a delayed runlevel record. | |
191 | */ | |
192 | if (wrote_utmp_rlevel == 0 && type != RUN_LVL) { | |
193 | int runlevel = thislevel; | |
194 | int oldlevel = prevlevel; | |
195 | write_utmp("runlevel", "~~", runlevel + 256 * oldlevel, RUN_LVL, "~", NULL); | |
196 | } | |
a74aeac6 PR |
197 | #endif |
198 | ||
199 | /* | |
200 | * Fill out an utmp struct. | |
201 | */ | |
202 | memset(&utmp, 0, sizeof(utmp)); | |
203 | utmp.ut_type = type; | |
204 | utmp.ut_pid = pid; | |
205 | strncpy(utmp.ut_id, id, sizeof(utmp.ut_id)); | |
206 | #if defined(__GLIBC__) | |
207 | gettimeofday(&tv, NULL); | |
208 | utmp.ut_tv.tv_sec = tv.tv_sec; | |
209 | utmp.ut_tv.tv_usec = tv.tv_usec; | |
210 | #else | |
211 | time(&utmp.ut_time); | |
212 | #endif | |
213 | strncpy(utmp.ut_user, user, UT_NAMESIZE); | |
214 | if (line) strncpy(utmp.ut_line, line, UT_LINESIZE); | |
215 | ||
216 | /* | |
217 | * We might need to find the existing entry first, to | |
218 | * find the tty of the process (for wtmp accounting). | |
219 | */ | |
220 | if (type == DEAD_PROCESS) { | |
221 | /* | |
222 | * Find existing entry for the tty line. | |
223 | */ | |
224 | setutent(); | |
225 | tmp = utmp; | |
226 | if ((utmptr = getutid(&tmp)) != NULL) { | |
227 | strncpy(utmp.ut_line, utmptr->ut_line, UT_LINESIZE); | |
228 | if (oldline) | |
229 | strncpy(oldline, utmptr->ut_line, UT_LINESIZE); | |
230 | } | |
231 | } | |
232 | ||
233 | /* | |
234 | * Update existing utmp file. | |
235 | */ | |
236 | setutent(); | |
237 | pututline(&utmp); | |
238 | endutent(); | |
239 | } | |
240 | ||
241 | /* | |
242 | * Write a record to both utmp and wtmp. | |
243 | */ | |
244 | void write_utmp_wtmp( | |
245 | char *user, /* name of user */ | |
246 | char *id, /* inittab ID */ | |
247 | int pid, /* PID of process */ | |
248 | int type, /* TYPE of entry */ | |
249 | char *line) /* LINE if used. */ | |
250 | { | |
251 | char oldline[UT_LINESIZE]; | |
252 | ||
253 | /* | |
254 | * For backwards compatibility we just return | |
255 | * if user == NULL (means : clean up utmp file). | |
256 | */ | |
257 | if (user == NULL) | |
258 | return; | |
259 | ||
260 | oldline[0] = 0; | |
261 | write_utmp(user, id, pid, type, line, oldline); | |
262 | write_wtmp(user, id, pid, type, line && line[0] ? line : oldline); | |
263 | } | |
264 |