]>
Commit | Line | Data |
---|---|---|
7a9219c1 SG |
1 | /* |
2 | * Copyright (c) 2011 The Chromium OS Authors. | |
1a459660 | 3 | * SPDX-License-Identifier: GPL-2.0+ |
7a9219c1 SG |
4 | */ |
5 | ||
62584db1 | 6 | #include <dirent.h> |
e1012472 | 7 | #include <errno.h> |
7a9219c1 | 8 | #include <fcntl.h> |
70db4212 | 9 | #include <getopt.h> |
62584db1 | 10 | #include <stdio.h> |
2a54d159 | 11 | #include <stdint.h> |
7a9219c1 | 12 | #include <stdlib.h> |
62584db1 | 13 | #include <string.h> |
ab06a758 | 14 | #include <termios.h> |
d99a6874 | 15 | #include <time.h> |
e1012472 | 16 | #include <unistd.h> |
21899b10 | 17 | #include <sys/mman.h> |
e1012472 | 18 | #include <sys/stat.h> |
3bdf56b7 | 19 | #include <sys/time.h> |
e1012472 | 20 | #include <sys/types.h> |
d99a6874 | 21 | #include <linux/types.h> |
7a9219c1 | 22 | |
70db4212 SG |
23 | #include <asm/getopt.h> |
24 | #include <asm/sections.h> | |
25 | #include <asm/state.h> | |
7a9219c1 SG |
26 | #include <os.h> |
27 | ||
28 | /* Operating System Interface */ | |
29 | ||
77595c6d SG |
30 | struct os_mem_hdr { |
31 | size_t length; /* number of bytes in the block */ | |
32 | }; | |
33 | ||
7a9219c1 SG |
34 | ssize_t os_read(int fd, void *buf, size_t count) |
35 | { | |
36 | return read(fd, buf, count); | |
37 | } | |
38 | ||
e101550a TH |
39 | ssize_t os_read_no_block(int fd, void *buf, size_t count) |
40 | { | |
41 | const int flags = fcntl(fd, F_GETFL, 0); | |
42 | ||
43 | fcntl(fd, F_SETFL, flags | O_NONBLOCK); | |
44 | return os_read(fd, buf, count); | |
45 | } | |
46 | ||
7a9219c1 SG |
47 | ssize_t os_write(int fd, const void *buf, size_t count) |
48 | { | |
49 | return write(fd, buf, count); | |
50 | } | |
51 | ||
e2dcefcb MF |
52 | off_t os_lseek(int fd, off_t offset, int whence) |
53 | { | |
54 | if (whence == OS_SEEK_SET) | |
55 | whence = SEEK_SET; | |
56 | else if (whence == OS_SEEK_CUR) | |
57 | whence = SEEK_CUR; | |
58 | else if (whence == OS_SEEK_END) | |
59 | whence = SEEK_END; | |
60 | else | |
61 | os_exit(1); | |
62 | return lseek(fd, offset, whence); | |
63 | } | |
64 | ||
d9165153 | 65 | int os_open(const char *pathname, int os_flags) |
7a9219c1 | 66 | { |
d9165153 SG |
67 | int flags; |
68 | ||
69 | switch (os_flags & OS_O_MASK) { | |
70 | case OS_O_RDONLY: | |
71 | default: | |
72 | flags = O_RDONLY; | |
73 | break; | |
74 | ||
75 | case OS_O_WRONLY: | |
76 | flags = O_WRONLY; | |
77 | break; | |
78 | ||
79 | case OS_O_RDWR: | |
80 | flags = O_RDWR; | |
81 | break; | |
82 | } | |
83 | ||
84 | if (os_flags & OS_O_CREAT) | |
85 | flags |= O_CREAT; | |
86 | ||
87 | return open(pathname, flags, 0777); | |
7a9219c1 SG |
88 | } |
89 | ||
90 | int os_close(int fd) | |
91 | { | |
92 | return close(fd); | |
93 | } | |
94 | ||
95 | void os_exit(int exit_code) | |
96 | { | |
97 | exit(exit_code); | |
98 | } | |
ab06a758 MF |
99 | |
100 | /* Restore tty state when we exit */ | |
101 | static struct termios orig_term; | |
102 | ||
103 | static void os_fd_restore(void) | |
104 | { | |
105 | tcsetattr(0, TCSANOW, &orig_term); | |
106 | } | |
107 | ||
108 | /* Put tty into raw mode so <tab> and <ctrl+c> work */ | |
109 | void os_tty_raw(int fd) | |
110 | { | |
111 | static int setup = 0; | |
112 | struct termios term; | |
113 | ||
114 | if (setup) | |
115 | return; | |
116 | setup = 1; | |
117 | ||
118 | /* If not a tty, don't complain */ | |
119 | if (tcgetattr(fd, &orig_term)) | |
120 | return; | |
121 | ||
122 | term = orig_term; | |
123 | term.c_iflag = IGNBRK | IGNPAR; | |
124 | term.c_oflag = OPOST | ONLCR; | |
125 | term.c_cflag = CS8 | CREAD | CLOCAL; | |
126 | term.c_lflag = 0; | |
127 | if (tcsetattr(fd, TCSANOW, &term)) | |
128 | return; | |
129 | ||
130 | atexit(os_fd_restore); | |
131 | } | |
21899b10 MW |
132 | |
133 | void *os_malloc(size_t length) | |
134 | { | |
77595c6d SG |
135 | struct os_mem_hdr *hdr; |
136 | ||
137 | hdr = mmap(NULL, length + sizeof(*hdr), PROT_READ | PROT_WRITE, | |
138 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); | |
139 | if (hdr == MAP_FAILED) | |
140 | return NULL; | |
141 | hdr->length = length; | |
142 | ||
143 | return hdr + 1; | |
144 | } | |
145 | ||
146 | void *os_free(void *ptr) | |
147 | { | |
148 | struct os_mem_hdr *hdr = ptr; | |
149 | ||
150 | hdr--; | |
151 | if (ptr) | |
152 | munmap(hdr, hdr->length + sizeof(*hdr)); | |
153 | } | |
154 | ||
155 | void *os_realloc(void *ptr, size_t length) | |
156 | { | |
157 | struct os_mem_hdr *hdr = ptr; | |
158 | void *buf = NULL; | |
159 | ||
160 | hdr--; | |
161 | if (length != 0) { | |
162 | buf = os_malloc(length); | |
163 | if (!buf) | |
164 | return buf; | |
165 | if (ptr) { | |
166 | if (length > hdr->length) | |
167 | length = hdr->length; | |
168 | memcpy(buf, ptr, length); | |
169 | } | |
170 | } | |
171 | os_free(ptr); | |
172 | ||
173 | return buf; | |
21899b10 | 174 | } |
d99a6874 MW |
175 | |
176 | void os_usleep(unsigned long usec) | |
177 | { | |
178 | usleep(usec); | |
179 | } | |
180 | ||
2a54d159 | 181 | uint64_t __attribute__((no_instrument_function)) os_get_nsec(void) |
d99a6874 MW |
182 | { |
183 | #if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK) | |
184 | struct timespec tp; | |
185 | if (EINVAL == clock_gettime(CLOCK_MONOTONIC, &tp)) { | |
186 | struct timeval tv; | |
187 | ||
188 | gettimeofday(&tv, NULL); | |
189 | tp.tv_sec = tv.tv_sec; | |
190 | tp.tv_nsec = tv.tv_usec * 1000; | |
191 | } | |
192 | return tp.tv_sec * 1000000000ULL + tp.tv_nsec; | |
193 | #else | |
194 | struct timeval tv; | |
195 | gettimeofday(&tv, NULL); | |
196 | return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000; | |
197 | #endif | |
198 | } | |
70db4212 SG |
199 | |
200 | static char *short_opts; | |
201 | static struct option *long_opts; | |
202 | ||
203 | int os_parse_args(struct sandbox_state *state, int argc, char *argv[]) | |
204 | { | |
7b3efc66 | 205 | struct sandbox_cmdline_option **sb_opt = __u_boot_sandbox_option_start; |
70db4212 SG |
206 | size_t num_options = __u_boot_sandbox_option_count(); |
207 | size_t i; | |
208 | ||
209 | int hidden_short_opt; | |
210 | size_t si; | |
211 | ||
212 | int c; | |
213 | ||
214 | if (short_opts || long_opts) | |
215 | return 1; | |
216 | ||
217 | state->argc = argc; | |
218 | state->argv = argv; | |
219 | ||
220 | /* dynamically construct the arguments to the system getopt_long */ | |
221 | short_opts = os_malloc(sizeof(*short_opts) * num_options * 2 + 1); | |
222 | long_opts = os_malloc(sizeof(*long_opts) * num_options); | |
223 | if (!short_opts || !long_opts) | |
224 | return 1; | |
225 | ||
226 | /* | |
227 | * getopt_long requires "val" to be unique (since that is what the | |
228 | * func returns), so generate unique values automatically for flags | |
229 | * that don't have a short option. pick 0x100 as that is above the | |
230 | * single byte range (where ASCII/ISO-XXXX-X charsets live). | |
231 | */ | |
232 | hidden_short_opt = 0x100; | |
233 | si = 0; | |
234 | for (i = 0; i < num_options; ++i) { | |
235 | long_opts[i].name = sb_opt[i]->flag; | |
236 | long_opts[i].has_arg = sb_opt[i]->has_arg ? | |
237 | required_argument : no_argument; | |
238 | long_opts[i].flag = NULL; | |
239 | ||
240 | if (sb_opt[i]->flag_short) { | |
241 | short_opts[si++] = long_opts[i].val = sb_opt[i]->flag_short; | |
242 | if (long_opts[i].has_arg == required_argument) | |
243 | short_opts[si++] = ':'; | |
244 | } else | |
245 | long_opts[i].val = sb_opt[i]->flag_short = hidden_short_opt++; | |
246 | } | |
247 | short_opts[si] = '\0'; | |
248 | ||
249 | /* we need to handle output ourselves since u-boot provides printf */ | |
250 | opterr = 0; | |
251 | ||
252 | /* | |
253 | * walk all of the options the user gave us on the command line, | |
254 | * figure out what u-boot option structure they belong to (via | |
255 | * the unique short val key), and call the appropriate callback. | |
256 | */ | |
257 | while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) { | |
258 | for (i = 0; i < num_options; ++i) { | |
259 | if (sb_opt[i]->flag_short == c) { | |
260 | if (sb_opt[i]->callback(state, optarg)) { | |
261 | state->parse_err = sb_opt[i]->flag; | |
262 | return 0; | |
263 | } | |
264 | break; | |
265 | } | |
266 | } | |
267 | if (i == num_options) { | |
268 | /* | |
269 | * store the faulting flag for later display. we have to | |
270 | * store the flag itself as the getopt parsing itself is | |
271 | * tricky: need to handle the following flags (assume all | |
272 | * of the below are unknown): | |
273 | * -a optopt='a' optind=<next> | |
274 | * -abbbb optopt='a' optind=<this> | |
275 | * -aaaaa optopt='a' optind=<this> | |
276 | * --a optopt=0 optind=<this> | |
277 | * as you can see, it is impossible to determine the exact | |
278 | * faulting flag without doing the parsing ourselves, so | |
279 | * we just report the specific flag that failed. | |
280 | */ | |
281 | if (optopt) { | |
282 | static char parse_err[3] = { '-', 0, '\0', }; | |
283 | parse_err[1] = optopt; | |
284 | state->parse_err = parse_err; | |
285 | } else | |
286 | state->parse_err = argv[optind - 1]; | |
287 | break; | |
288 | } | |
289 | } | |
290 | ||
291 | return 0; | |
292 | } | |
62584db1 SG |
293 | |
294 | void os_dirent_free(struct os_dirent_node *node) | |
295 | { | |
296 | struct os_dirent_node *next; | |
297 | ||
298 | while (node) { | |
299 | next = node->next; | |
300 | free(node); | |
301 | node = next; | |
302 | } | |
303 | } | |
304 | ||
305 | int os_dirent_ls(const char *dirname, struct os_dirent_node **headp) | |
306 | { | |
307 | struct dirent entry, *result; | |
308 | struct os_dirent_node *head, *node, *next; | |
309 | struct stat buf; | |
310 | DIR *dir; | |
311 | int ret; | |
312 | char *fname; | |
313 | int len; | |
314 | ||
315 | *headp = NULL; | |
316 | dir = opendir(dirname); | |
317 | if (!dir) | |
318 | return -1; | |
319 | ||
320 | /* Create a buffer for the maximum filename length */ | |
321 | len = sizeof(entry.d_name) + strlen(dirname) + 2; | |
322 | fname = malloc(len); | |
323 | if (!fname) { | |
324 | ret = -ENOMEM; | |
325 | goto done; | |
326 | } | |
327 | ||
328 | for (node = head = NULL;; node = next) { | |
329 | ret = readdir_r(dir, &entry, &result); | |
330 | if (ret || !result) | |
331 | break; | |
332 | next = malloc(sizeof(*node) + strlen(entry.d_name) + 1); | |
333 | if (!next) { | |
334 | os_dirent_free(head); | |
335 | ret = -ENOMEM; | |
336 | goto done; | |
337 | } | |
338 | strcpy(next->name, entry.d_name); | |
339 | switch (entry.d_type) { | |
340 | case DT_REG: | |
341 | next->type = OS_FILET_REG; | |
342 | break; | |
343 | case DT_DIR: | |
344 | next->type = OS_FILET_DIR; | |
345 | break; | |
346 | case DT_LNK: | |
347 | next->type = OS_FILET_LNK; | |
348 | break; | |
349 | } | |
350 | next->size = 0; | |
351 | snprintf(fname, len, "%s/%s", dirname, next->name); | |
352 | if (!stat(fname, &buf)) | |
353 | next->size = buf.st_size; | |
354 | if (node) | |
355 | node->next = next; | |
356 | if (!head) | |
357 | head = node; | |
358 | } | |
359 | *headp = head; | |
360 | ||
361 | done: | |
362 | closedir(dir); | |
363 | return ret; | |
364 | } | |
365 | ||
366 | const char *os_dirent_typename[OS_FILET_COUNT] = { | |
367 | " ", | |
368 | "SYM", | |
369 | "DIR", | |
370 | "???", | |
371 | }; | |
372 | ||
373 | const char *os_dirent_get_typename(enum os_dirent_t type) | |
374 | { | |
375 | if (type >= 0 && type < OS_FILET_COUNT) | |
376 | return os_dirent_typename[type]; | |
377 | ||
378 | return os_dirent_typename[OS_FILET_UNKNOWN]; | |
379 | } | |
380 | ||
381 | ssize_t os_get_filesize(const char *fname) | |
382 | { | |
383 | struct stat buf; | |
384 | int ret; | |
385 | ||
386 | ret = stat(fname, &buf); | |
387 | if (ret) | |
388 | return ret; | |
389 | return buf.st_size; | |
390 | } | |
91b136c7 SG |
391 | |
392 | void os_putc(int ch) | |
393 | { | |
394 | putchar(ch); | |
395 | } | |
396 | ||
397 | void os_puts(const char *str) | |
398 | { | |
399 | while (*str) | |
400 | os_putc(*str++); | |
401 | } | |
5c2859cd SG |
402 | |
403 | int os_write_ram_buf(const char *fname) | |
404 | { | |
405 | struct sandbox_state *state = state_get_current(); | |
406 | int fd, ret; | |
407 | ||
408 | fd = open(fname, O_CREAT | O_WRONLY, 0777); | |
409 | if (fd < 0) | |
410 | return -ENOENT; | |
411 | ret = write(fd, state->ram_buf, state->ram_size); | |
412 | close(fd); | |
413 | if (ret != state->ram_size) | |
414 | return -EIO; | |
415 | ||
416 | return 0; | |
417 | } | |
418 | ||
419 | int os_read_ram_buf(const char *fname) | |
420 | { | |
421 | struct sandbox_state *state = state_get_current(); | |
422 | int fd, ret; | |
423 | int size; | |
424 | ||
425 | size = os_get_filesize(fname); | |
426 | if (size < 0) | |
427 | return -ENOENT; | |
428 | if (size != state->ram_size) | |
429 | return -ENOSPC; | |
430 | fd = open(fname, O_RDONLY); | |
431 | if (fd < 0) | |
432 | return -ENOENT; | |
433 | ||
434 | ret = read(fd, state->ram_buf, state->ram_size); | |
435 | close(fd); | |
436 | if (ret != state->ram_size) | |
437 | return -EIO; | |
438 | ||
439 | return 0; | |
440 | } |