1 /* 2 * Copyright (c) 2011 The Chromium OS Authors. 3 * SPDX-License-Identifier: GPL-2.0+ 4 */ 5 6 #include <dirent.h> 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <getopt.h> 10 #include <stdio.h> 11 #include <stdint.h> 12 #include <stdlib.h> 13 #include <string.h> 14 #include <termios.h> 15 #include <time.h> 16 #include <unistd.h> 17 #include <sys/mman.h> 18 #include <sys/stat.h> 19 #include <sys/time.h> 20 #include <sys/types.h> 21 #include <linux/types.h> 22 23 #include <asm/getopt.h> 24 #include <asm/sections.h> 25 #include <asm/state.h> 26 #include <os.h> 27 28 /* Operating System Interface */ 29 30 ssize_t os_read(int fd, void *buf, size_t count) 31 { 32 return read(fd, buf, count); 33 } 34 35 ssize_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 43 ssize_t os_write(int fd, const void *buf, size_t count) 44 { 45 return write(fd, buf, count); 46 } 47 48 off_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 61 int os_open(const char *pathname, int os_flags) 62 { 63 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); 84 } 85 86 int os_close(int fd) 87 { 88 return close(fd); 89 } 90 91 void os_exit(int exit_code) 92 { 93 exit(exit_code); 94 } 95 96 /* Restore tty state when we exit */ 97 static struct termios orig_term; 98 99 static 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 */ 105 void 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 } 128 129 void *os_malloc(size_t length) 130 { 131 return mmap(NULL, length, PROT_READ | PROT_WRITE, 132 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 133 } 134 135 void os_usleep(unsigned long usec) 136 { 137 usleep(usec); 138 } 139 140 uint64_t __attribute__((no_instrument_function)) os_get_nsec(void) 141 { 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 } 158 159 static char *short_opts; 160 static struct option *long_opts; 161 162 int os_parse_args(struct sandbox_state *state, int argc, char *argv[]) 163 { 164 struct sandbox_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 } 252 253 void 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 264 int 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 320 done: 321 closedir(dir); 322 return ret; 323 } 324 325 const char *os_dirent_typename[OS_FILET_COUNT] = { 326 " ", 327 "SYM", 328 "DIR", 329 "???", 330 }; 331 332 const 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 340 ssize_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 } 350