blob: db66fd31f254cd733abaadb7db0a0b4c5390dc43 [file] [log] [blame]
Simon Glass7a9219c2011-10-03 19:26:44 +00001/*
2 * Copyright (c) 2011 The Chromium OS Authors.
Wolfgang Denk1a459662013-07-08 09:37:19 +02003 * SPDX-License-Identifier: GPL-2.0+
Simon Glass7a9219c2011-10-03 19:26:44 +00004 */
5
Simon Glass62584db2012-12-26 09:53:34 +00006#include <dirent.h>
Simon Glasse1012472012-01-10 15:54:05 -08007#include <errno.h>
Simon Glass7a9219c2011-10-03 19:26:44 +00008#include <fcntl.h>
Simon Glass70db4212012-02-15 15:51:16 -08009#include <getopt.h>
Simon Glass62584db2012-12-26 09:53:34 +000010#include <stdio.h>
Simon Glass2a54d152013-05-19 16:45:35 -070011#include <stdint.h>
Simon Glass7a9219c2011-10-03 19:26:44 +000012#include <stdlib.h>
Simon Glass62584db2012-12-26 09:53:34 +000013#include <string.h>
Mike Frysingerab06a752011-10-26 00:21:29 +000014#include <termios.h>
Matthias Weisserd99a6872011-11-29 12:16:40 +010015#include <time.h>
Simon Glasse1012472012-01-10 15:54:05 -080016#include <unistd.h>
Matthias Weisser21899b12011-11-05 11:40:34 +010017#include <sys/mman.h>
Simon Glasse1012472012-01-10 15:54:05 -080018#include <sys/stat.h>
Simon Glass3bdf56b2012-01-10 15:54:06 -080019#include <sys/time.h>
Simon Glasse1012472012-01-10 15:54:05 -080020#include <sys/types.h>
Matthias Weisserd99a6872011-11-29 12:16:40 +010021#include <linux/types.h>
Simon Glass7a9219c2011-10-03 19:26:44 +000022
Simon Glass70db4212012-02-15 15:51:16 -080023#include <asm/getopt.h>
24#include <asm/sections.h>
25#include <asm/state.h>
Simon Glass7a9219c2011-10-03 19:26:44 +000026#include <os.h>
27
28/* Operating System Interface */
29
30ssize_t os_read(int fd, void *buf, size_t count)
31{
32 return read(fd, buf, count);
33}
34
Taylor Hutte1015502013-02-24 17:33:13 +000035ssize_t os_read_no_block(int fd, void *buf, size_t count)
36{
37 const int flags = fcntl(fd, F_GETFL, 0);
38
39 fcntl(fd, F_SETFL, flags | O_NONBLOCK);
40 return os_read(fd, buf, count);
41}
42
Simon Glass7a9219c2011-10-03 19:26:44 +000043ssize_t os_write(int fd, const void *buf, size_t count)
44{
45 return write(fd, buf, count);
46}
47
Mike Frysingere2dcefc2011-10-25 13:02:58 +020048off_t os_lseek(int fd, off_t offset, int whence)
49{
50 if (whence == OS_SEEK_SET)
51 whence = SEEK_SET;
52 else if (whence == OS_SEEK_CUR)
53 whence = SEEK_CUR;
54 else if (whence == OS_SEEK_END)
55 whence = SEEK_END;
56 else
57 os_exit(1);
58 return lseek(fd, offset, whence);
59}
60
Simon Glassd9165152012-02-20 23:56:58 -050061int os_open(const char *pathname, int os_flags)
Simon Glass7a9219c2011-10-03 19:26:44 +000062{
Simon Glassd9165152012-02-20 23:56:58 -050063 int flags;
64
65 switch (os_flags & OS_O_MASK) {
66 case OS_O_RDONLY:
67 default:
68 flags = O_RDONLY;
69 break;
70
71 case OS_O_WRONLY:
72 flags = O_WRONLY;
73 break;
74
75 case OS_O_RDWR:
76 flags = O_RDWR;
77 break;
78 }
79
80 if (os_flags & OS_O_CREAT)
81 flags |= O_CREAT;
82
83 return open(pathname, flags, 0777);
Simon Glass7a9219c2011-10-03 19:26:44 +000084}
85
86int os_close(int fd)
87{
88 return close(fd);
89}
90
91void os_exit(int exit_code)
92{
93 exit(exit_code);
94}
Mike Frysingerab06a752011-10-26 00:21:29 +000095
96/* Restore tty state when we exit */
97static struct termios orig_term;
98
99static void os_fd_restore(void)
100{
101 tcsetattr(0, TCSANOW, &orig_term);
102}
103
104/* Put tty into raw mode so <tab> and <ctrl+c> work */
105void os_tty_raw(int fd)
106{
107 static int setup = 0;
108 struct termios term;
109
110 if (setup)
111 return;
112 setup = 1;
113
114 /* If not a tty, don't complain */
115 if (tcgetattr(fd, &orig_term))
116 return;
117
118 term = orig_term;
119 term.c_iflag = IGNBRK | IGNPAR;
120 term.c_oflag = OPOST | ONLCR;
121 term.c_cflag = CS8 | CREAD | CLOCAL;
122 term.c_lflag = 0;
123 if (tcsetattr(fd, TCSANOW, &term))
124 return;
125
126 atexit(os_fd_restore);
127}
Matthias Weisser21899b12011-11-05 11:40:34 +0100128
129void *os_malloc(size_t length)
130{
131 return mmap(NULL, length, PROT_READ | PROT_WRITE,
132 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
133}
Matthias Weisserd99a6872011-11-29 12:16:40 +0100134
135void os_usleep(unsigned long usec)
136{
137 usleep(usec);
138}
139
Simon Glass2a54d152013-05-19 16:45:35 -0700140uint64_t __attribute__((no_instrument_function)) os_get_nsec(void)
Matthias Weisserd99a6872011-11-29 12:16:40 +0100141{
142#if defined(CLOCK_MONOTONIC) && defined(_POSIX_MONOTONIC_CLOCK)
143 struct timespec tp;
144 if (EINVAL == clock_gettime(CLOCK_MONOTONIC, &tp)) {
145 struct timeval tv;
146
147 gettimeofday(&tv, NULL);
148 tp.tv_sec = tv.tv_sec;
149 tp.tv_nsec = tv.tv_usec * 1000;
150 }
151 return tp.tv_sec * 1000000000ULL + tp.tv_nsec;
152#else
153 struct timeval tv;
154 gettimeofday(&tv, NULL);
155 return tv.tv_sec * 1000000000ULL + tv.tv_usec * 1000;
156#endif
157}
Simon Glass70db4212012-02-15 15:51:16 -0800158
159static char *short_opts;
160static struct option *long_opts;
161
162int os_parse_args(struct sandbox_state *state, int argc, char *argv[])
163{
164 struct sb_cmdline_option **sb_opt = __u_boot_sandbox_option_start;
165 size_t num_options = __u_boot_sandbox_option_count();
166 size_t i;
167
168 int hidden_short_opt;
169 size_t si;
170
171 int c;
172
173 if (short_opts || long_opts)
174 return 1;
175
176 state->argc = argc;
177 state->argv = argv;
178
179 /* dynamically construct the arguments to the system getopt_long */
180 short_opts = os_malloc(sizeof(*short_opts) * num_options * 2 + 1);
181 long_opts = os_malloc(sizeof(*long_opts) * num_options);
182 if (!short_opts || !long_opts)
183 return 1;
184
185 /*
186 * getopt_long requires "val" to be unique (since that is what the
187 * func returns), so generate unique values automatically for flags
188 * that don't have a short option. pick 0x100 as that is above the
189 * single byte range (where ASCII/ISO-XXXX-X charsets live).
190 */
191 hidden_short_opt = 0x100;
192 si = 0;
193 for (i = 0; i < num_options; ++i) {
194 long_opts[i].name = sb_opt[i]->flag;
195 long_opts[i].has_arg = sb_opt[i]->has_arg ?
196 required_argument : no_argument;
197 long_opts[i].flag = NULL;
198
199 if (sb_opt[i]->flag_short) {
200 short_opts[si++] = long_opts[i].val = sb_opt[i]->flag_short;
201 if (long_opts[i].has_arg == required_argument)
202 short_opts[si++] = ':';
203 } else
204 long_opts[i].val = sb_opt[i]->flag_short = hidden_short_opt++;
205 }
206 short_opts[si] = '\0';
207
208 /* we need to handle output ourselves since u-boot provides printf */
209 opterr = 0;
210
211 /*
212 * walk all of the options the user gave us on the command line,
213 * figure out what u-boot option structure they belong to (via
214 * the unique short val key), and call the appropriate callback.
215 */
216 while ((c = getopt_long(argc, argv, short_opts, long_opts, NULL)) != -1) {
217 for (i = 0; i < num_options; ++i) {
218 if (sb_opt[i]->flag_short == c) {
219 if (sb_opt[i]->callback(state, optarg)) {
220 state->parse_err = sb_opt[i]->flag;
221 return 0;
222 }
223 break;
224 }
225 }
226 if (i == num_options) {
227 /*
228 * store the faulting flag for later display. we have to
229 * store the flag itself as the getopt parsing itself is
230 * tricky: need to handle the following flags (assume all
231 * of the below are unknown):
232 * -a optopt='a' optind=<next>
233 * -abbbb optopt='a' optind=<this>
234 * -aaaaa optopt='a' optind=<this>
235 * --a optopt=0 optind=<this>
236 * as you can see, it is impossible to determine the exact
237 * faulting flag without doing the parsing ourselves, so
238 * we just report the specific flag that failed.
239 */
240 if (optopt) {
241 static char parse_err[3] = { '-', 0, '\0', };
242 parse_err[1] = optopt;
243 state->parse_err = parse_err;
244 } else
245 state->parse_err = argv[optind - 1];
246 break;
247 }
248 }
249
250 return 0;
251}
Simon Glass62584db2012-12-26 09:53:34 +0000252
253void os_dirent_free(struct os_dirent_node *node)
254{
255 struct os_dirent_node *next;
256
257 while (node) {
258 next = node->next;
259 free(node);
260 node = next;
261 }
262}
263
264int os_dirent_ls(const char *dirname, struct os_dirent_node **headp)
265{
266 struct dirent entry, *result;
267 struct os_dirent_node *head, *node, *next;
268 struct stat buf;
269 DIR *dir;
270 int ret;
271 char *fname;
272 int len;
273
274 *headp = NULL;
275 dir = opendir(dirname);
276 if (!dir)
277 return -1;
278
279 /* Create a buffer for the maximum filename length */
280 len = sizeof(entry.d_name) + strlen(dirname) + 2;
281 fname = malloc(len);
282 if (!fname) {
283 ret = -ENOMEM;
284 goto done;
285 }
286
287 for (node = head = NULL;; node = next) {
288 ret = readdir_r(dir, &entry, &result);
289 if (ret || !result)
290 break;
291 next = malloc(sizeof(*node) + strlen(entry.d_name) + 1);
292 if (!next) {
293 os_dirent_free(head);
294 ret = -ENOMEM;
295 goto done;
296 }
297 strcpy(next->name, entry.d_name);
298 switch (entry.d_type) {
299 case DT_REG:
300 next->type = OS_FILET_REG;
301 break;
302 case DT_DIR:
303 next->type = OS_FILET_DIR;
304 break;
305 case DT_LNK:
306 next->type = OS_FILET_LNK;
307 break;
308 }
309 next->size = 0;
310 snprintf(fname, len, "%s/%s", dirname, next->name);
311 if (!stat(fname, &buf))
312 next->size = buf.st_size;
313 if (node)
314 node->next = next;
315 if (!head)
316 head = node;
317 }
318 *headp = head;
319
320done:
321 closedir(dir);
322 return ret;
323}
324
325const char *os_dirent_typename[OS_FILET_COUNT] = {
326 " ",
327 "SYM",
328 "DIR",
329 "???",
330};
331
332const char *os_dirent_get_typename(enum os_dirent_t type)
333{
334 if (type >= 0 && type < OS_FILET_COUNT)
335 return os_dirent_typename[type];
336
337 return os_dirent_typename[OS_FILET_UNKNOWN];
338}
339
340ssize_t os_get_filesize(const char *fname)
341{
342 struct stat buf;
343 int ret;
344
345 ret = stat(fname, &buf);
346 if (ret)
347 return ret;
348 return buf.st_size;
349}