void __noreturn start_barebox(void) { initcall_t *initcall; int result; struct stat s; if (!IS_ENABLED(CONFIG_SHELL_NONE)) barebox_main = run_shell; for (initcall = __barebox_initcalls_start; initcall < __barebox_initcalls_end; initcall++) { pr_debug("initcall-> %pS\n", *initcall); result = (*initcall)(); if (result) pr_err("initcall %pS failed: %s\n", *initcall, strerror(-result)); } pr_debug("initcalls done\n"); if (IS_ENABLED(CONFIG_ENV_HANDLING)) { int ret; char *default_environment_path = default_environment_path_get(); ret = envfs_load(default_environment_path, "/env", 0); if (ret && IS_ENABLED(CONFIG_DEFAULT_ENVIRONMENT)) { pr_err("no valid environment found on %s. " "Using default environment\n", default_environment_path); defaultenv_load("/env", 0); } } if (IS_ENABLED(CONFIG_COMMAND_SUPPORT)) { pr_info("running /env/bin/init...\n"); if (!stat("/env/bin/init", &s)) { run_command("source /env/bin/init"); } else { pr_err("/env/bin/init not found\n"); if (IS_ENABLED(CONFIG_CMD_LOGIN)) while(run_command("login -t 0")); } } if (!barebox_main) { pr_err("No main function! aborting.\n"); hang(); } /* main_loop() can return to retry autoboot, if so just run it again. */ for (;;) barebox_main(); /* NOTREACHED - no way out of command loop except booting */ }
/** * Make the current environment persistent * @param[in] filename where to store * @param[in] dirname what to store (all files in this dir) * @param[in] flags superblock flags (refer ENVFS_FLAGS_* macros) * @return 0 on success, anything else in case of failure * * Note: This function will also be used on the host! See note in the header * of this file. */ int envfs_save(const char *filename, const char *dirname, unsigned flags) { struct envfs_super *super; int envfd, size, ret; struct action_data data = {}; void *buf = NULL, *wbuf; struct envfs_entry *env; if (!filename) filename = default_environment_path_get(); if (!dirname) dirname = "/env"; data.writep = NULL; data.base = dirname; #ifdef __BAREBOX__ defaultenv_load(TMPDIR, 0); #endif if (flags & ENVFS_FLAGS_FORCE_BUILT_IN) { size = 0; /* force no content */ } else { /* first pass: calculate size */ recursive_action(dirname, ACTION_RECURSE, file_action, NULL, &data, 0); recursive_action("/.defaultenv", ACTION_RECURSE, file_remove_action, NULL, &data, 0); size = 0; for (env = data.env; env; env = env->next) { size += PAD4(env->size); size += sizeof(struct envfs_inode); size += PAD4(strlen(env->name) + 1); size += sizeof(struct envfs_inode_end); } } buf = xzalloc(size + sizeof(struct envfs_super)); data.writep = buf + sizeof(struct envfs_super); super = buf; super->magic = ENVFS_32(ENVFS_MAGIC); super->major = ENVFS_MAJOR; super->minor = ENVFS_MINOR; super->size = ENVFS_32(size); super->flags = ENVFS_32(flags); if (!(flags & ENVFS_FLAGS_FORCE_BUILT_IN)) { /* second pass: copy files to buffer */ env = data.env; while (env) { struct envfs_entry *next = env->next; envfs_save_inode(&data, env); free(env->buf); free(env->name); free(env); env = next; } } super->crc = ENVFS_32(crc32(0, buf + sizeof(struct envfs_super), size)); super->sb_crc = ENVFS_32(crc32(0, buf, sizeof(struct envfs_super) - 4)); envfd = open(filename, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR); if (envfd < 0) { printf("could not open %s: %s\n", filename, errno_str()); ret = -errno; goto out1; } ret = protect(envfd, ~0, 0, 0); /* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */ if (ret && errno != ENOSYS && errno != EOPNOTSUPP) { printf("could not unprotect %s: %s\n", filename, errno_str()); goto out; } ret = erase(envfd, ~0, 0); /* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */ if (ret && errno != ENOSYS && errno != EOPNOTSUPP) { printf("could not erase %s: %s\n", filename, errno_str()); goto out; } size += sizeof(struct envfs_super); wbuf = buf; while (size) { ssize_t now = write(envfd, wbuf, size); if (now < 0) { ret = -errno; goto out; } wbuf += now; size -= now; } ret = protect(envfd, ~0, 0, 1); /* ENOSYS and EOPNOTSUPP aren't errors here, many devices don't need it */ if (ret && errno != ENOSYS && errno != EOPNOTSUPP) { printf("could not protect %s: %s\n", filename, errno_str()); goto out; } ret = 0; out: close(envfd); out1: free(buf); #ifdef __BAREBOX__ unlink_recursive(TMPDIR, NULL); #endif return ret; }
/** * Restore the last environment into the current one * @param[in] filename from where to restore * @param[in] dir where to store the last content * @return 0 on success, anything else in case of failure * * Note: This function will also be used on the host! See note in the header * of this file. */ int envfs_load(const char *filename, const char *dir, unsigned flags) { struct envfs_super super; void *buf = NULL, *rbuf; int envfd; int ret = 0; size_t size, rsize; if (!filename) filename = default_environment_path_get(); if (!dir) dir = "/env"; envfd = open(filename, O_RDONLY); if (envfd < 0) { printf("environment load %s: %s\n", filename, errno_str()); if (errno == ENOENT) printf("Maybe you have to create the partition.\n"); return -1; } /* read superblock */ ret = read(envfd, &super, sizeof(struct envfs_super)); if ( ret < sizeof(struct envfs_super)) { perror("read"); ret = -errno; goto out; } ret = envfs_check_super(&super, &size); if (ret) goto out; if (super.flags & ENVFS_FLAGS_FORCE_BUILT_IN) { printf("found force-builtin environment, using defaultenv\n"); ret = defaultenv_load(dir, 0); if (ret) printf("failed to load default environment: %s\n", strerror(-ret)); goto out; } buf = xmalloc(size); rbuf = buf; rsize = size; while (rsize) { ssize_t now; now = read(envfd, rbuf, rsize); if (now < 0) { perror("read"); ret = -errno; goto out; } if (!now) { printf("%s: premature end of file\n", filename); ret = -EINVAL; goto out; } rbuf += now; rsize -= now; } ret = envfs_check_data(&super, buf, size); if (ret) goto out; ret = envfs_load_data(&super, buf, size, dir, flags); if (ret) goto out; ret = 0; out: close(envfd); free(buf); return ret; }
static int do_loadenv(int argc, char *argv[]) { char *filename = NULL, *dirname; unsigned flags = 0; int opt; int scrub = 0; int defaultenv = 0; while ((opt = getopt(argc, argv, "nsd")) > 0) { switch (opt) { case 'n': flags |= ENV_FLAG_NO_OVERWRITE; break; case 's': scrub = 1; break; case 'd': defaultenv = 1; break; default: return COMMAND_ERROR_USAGE; } } if (argc - optind < 2) dirname = "/env"; else dirname = argv[optind + 1]; if (argc - optind < 1) { filename = default_environment_path_get(); } else { char *str = normalise_path(argv[optind]); /* * /dev/defaultenv use to contain the defaultenvironment. * we do not have this file anymore, but maintain compatibility * to the 'loadenv -s /dev/defaultenv' command to restore the * default environment for some time. */ if (!strcmp(str, "/dev/defaultenv")) defaultenv = 1; else filename = argv[optind]; free(str); } if (scrub) { int ret; ret = unlink_recursive(dirname, NULL); if (ret && ret != -ENOENT) { eprintf("cannot remove %s: %s\n", dirname, strerror(-ret)); return 1; } ret = mkdir(dirname, 0); if (ret) { eprintf("cannot create %s: %s\n", dirname, strerror(-ret)); return ret; } } printf("loading environment from %s\n", defaultenv ? "defaultenv" : filename); if (defaultenv) return defaultenv_load(dirname, flags); else return envfs_load(filename, dirname, flags); }