This source file includes following definitions.
- get_boot_time_uncached
- get_boot_time
- get_boot_time
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20
21
22 #include "boot-time.h"
23
24 #include <stddef.h>
25 #include <stdio.h>
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #if defined __linux__ || defined __ANDROID__
31 # include <sys/sysinfo.h>
32 # include <time.h>
33 #endif
34
35 #if HAVE_SYS_SYSCTL_H && !(defined __GLIBC__ && defined __linux__) && !defined __minix
36 # if HAVE_SYS_PARAM_H
37 # include <sys/param.h>
38 # endif
39 # include <sys/sysctl.h>
40 #endif
41
42 #if HAVE_OS_H
43 # include <OS.h>
44 #endif
45
46 #include "idx.h"
47 #include "readutmp.h"
48 #include "stat-time.h"
49
50
51 #include "unlocked-io.h"
52
53
54 #include "boot-time-aux.h"
55
56
57
58 #undef UT_USER
59
60
61 #if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_NAME \
62 : HAVE_UTMP_H && HAVE_STRUCT_UTMP_UT_NAME)
63 # define UT_USER(UT) ((UT)->ut_name)
64 #else
65 # define UT_USER(UT) ((UT)->ut_user)
66 #endif
67
68 #if !HAVE_UTMPX_H && HAVE_UTMP_H && defined UTMP_NAME_FUNCTION
69 # if !HAVE_DECL_ENDUTENT
70 void endutent (void);
71 # endif
72 #endif
73
74 #if defined __linux__ || HAVE_UTMPX_H || HAVE_UTMP_H || defined __CYGWIN__ || defined _WIN32
75
76 static int
77 get_boot_time_uncached (struct timespec *p_boot_time)
78 {
79 struct timespec found_boot_time = {0};
80
81 # if (HAVE_UTMPX_H ? HAVE_STRUCT_UTMPX_UT_TYPE : HAVE_STRUCT_UTMP_UT_TYPE)
82
83
84
85 # if defined UTMP_NAME_FUNCTION
86
87
88
89
90
91 UTMP_NAME_FUNCTION ((char *) UTMP_FILE);
92
93 SET_UTMP_ENT ();
94
95 # if (defined __linux__ && !defined __ANDROID__) || defined __minix
96
97 struct timespec runlevel_ts = {0};
98 # endif
99
100 void const *entry;
101
102 while ((entry = GET_UTMP_ENT ()) != NULL)
103 {
104 struct UTMP_STRUCT_NAME const *ut = (struct UTMP_STRUCT_NAME const *) entry;
105
106 struct timespec ts =
107 #if (HAVE_UTMPX_H ? 1 : HAVE_STRUCT_UTMP_UT_TV)
108 { .tv_sec = ut->ut_tv.tv_sec, .tv_nsec = ut->ut_tv.tv_usec * 1000 };
109 #else
110 { .tv_sec = ut->ut_time, .tv_nsec = 0 };
111 #endif
112
113 if (ut->ut_type == BOOT_TIME)
114 found_boot_time = ts;
115
116 # if defined __linux__ && !defined __ANDROID__
117 if (memcmp (UT_USER (ut), "runlevel", strlen ("runlevel") + 1) == 0
118 && memcmp (ut->ut_line, "~", strlen ("~") + 1) == 0)
119 runlevel_ts = ts;
120 # endif
121 # if defined __minix
122 if (UT_USER (ut)[0] == '\0'
123 && memcmp (ut->ut_line, "run-level ", strlen ("run-level ")) == 0)
124 runlevel_ts = ts;
125 # endif
126 }
127
128 END_UTMP_ENT ();
129
130 # if defined __linux__ && !defined __ANDROID__
131
132
133
134
135
136
137
138
139
140
141 if (found_boot_time.tv_sec <= 60 && runlevel_ts.tv_sec != 0)
142 found_boot_time = runlevel_ts;
143 if (found_boot_time.tv_sec == 0)
144 {
145
146 get_linux_boot_time_fallback (&found_boot_time);
147 }
148 # endif
149
150 # if defined __ANDROID__
151 if (found_boot_time.tv_sec == 0)
152 {
153
154 get_android_boot_time (&found_boot_time);
155 }
156 # endif
157
158 # if defined __minix
159
160
161
162
163
164
165
166 if (found_boot_time.tv_sec <= 60 && runlevel_ts.tv_sec != 0)
167 found_boot_time = runlevel_ts;
168 # endif
169
170 # else
171
172 FILE *f = fopen (UTMP_FILE, "re");
173
174 if (f != NULL)
175 {
176 for (;;)
177 {
178 struct UTMP_STRUCT_NAME ut;
179
180 if (fread (&ut, sizeof ut, 1, f) == 0)
181 break;
182
183 struct timespec ts =
184 #if (HAVE_UTMPX_H ? 1 : HAVE_STRUCT_UTMP_UT_TV)
185 { .tv_sec = ut.ut_tv.tv_sec, .tv_nsec = ut.ut_tv.tv_usec * 1000 };
186 #else
187 { .tv_sec = ut.ut_time, .tv_nsec = 0 };
188 #endif
189
190 if (ut.ut_type == BOOT_TIME)
191 found_boot_time = ts;
192 }
193
194 fclose (f);
195 }
196
197 # endif
198
199 # if defined __linux__ && !defined __ANDROID__
200 if (found_boot_time.tv_sec == 0)
201 {
202 get_linux_boot_time_final_fallback (&found_boot_time);
203 }
204 # endif
205
206 # else
207
208 # if defined __OpenBSD__
209
210 get_openbsd_boot_time (&found_boot_time);
211 # endif
212
213 # endif
214
215 # if HAVE_SYS_SYSCTL_H && HAVE_SYSCTL \
216 && defined CTL_KERN && defined KERN_BOOTTIME \
217 && !defined __minix
218 if (found_boot_time.tv_sec == 0)
219 {
220 get_bsd_boot_time_final_fallback (&found_boot_time);
221 }
222 # endif
223
224 # if defined __HAIKU__
225 if (found_boot_time.tv_sec == 0)
226 {
227 get_haiku_boot_time (&found_boot_time);
228 }
229 # endif
230
231 # if HAVE_OS_H
232 if (found_boot_time.tv_sec == 0)
233 {
234 get_haiku_boot_time_final_fallback (&found_boot_time);
235 }
236 # endif
237
238 # if defined __CYGWIN__ || defined _WIN32
239 if (found_boot_time.tv_sec == 0)
240 {
241
242 get_windows_boot_time (&found_boot_time);
243 }
244 # endif
245
246 if (found_boot_time.tv_sec != 0)
247 {
248 *p_boot_time = found_boot_time;
249 return 0;
250 }
251 else
252 return -1;
253 }
254
255 int
256 get_boot_time (struct timespec *p_boot_time)
257 {
258
259 static int volatile cached_result = -1;
260 static struct timespec volatile cached_boot_time;
261
262 if (cached_result < 0)
263 {
264 struct timespec boot_time;
265 int result = get_boot_time_uncached (&boot_time);
266 cached_boot_time = boot_time;
267 cached_result = result;
268 }
269
270 if (cached_result == 0)
271 {
272 *p_boot_time = cached_boot_time;
273 return 0;
274 }
275 else
276 return -1;
277 }
278
279 #else
280
281 int
282 get_boot_time (struct timespec *p_boot_time)
283 {
284 return -1;
285 }
286
287 #endif