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