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