From d2e28c6c1051c5cf90a5e787acda4b825423ebb2 Mon Sep 17 00:00:00 2001 From: Kiita Date: Tue, 15 Jun 2021 20:59:03 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9Etoybox=20reboot?= =?UTF-8?q?=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 【背景】liteos_a测试套需要reboot命令 【修改方案】 在third_party/toybox/porting新增reboot.c文件,并作自定义修改。 新增reboot命令的支持说明 re #I3YQ7S Signed-off-by: yansira Change-Id: I7bf0fc20d4b1cdf9f9fcbbff2b9a12ee644241d8 --- porting/liteos_a/main.c | 263 +++++++++++++++++++++++++++ porting/liteos_a/toys.h | 3 + porting/liteos_a/toys/other/reboot.c | 35 ++++ 3 files changed, 301 insertions(+) create mode 100644 porting/liteos_a/main.c create mode 100644 porting/liteos_a/toys/other/reboot.c diff --git a/porting/liteos_a/main.c b/porting/liteos_a/main.c new file mode 100644 index 0000000..edc9803 --- /dev/null +++ b/porting/liteos_a/main.c @@ -0,0 +1,263 @@ +/* Toybox infrastructure. + * + * Copyright 2006 Rob Landley + */ + +#include "toys.h" + +#ifndef TOYBOX_VERSION +#ifndef TOYBOX_VENDOR +#define TOYBOX_VENDOR "" +#endif +#define TOYBOX_VERSION "0.8.2"TOYBOX_VENDOR +#endif + +// Populate toy_list[]. + +#undef NEWTOY +#undef OLDTOY +#define NEWTOY(name, opts, flags) {#name, name##_main, OPTSTR_##name, flags}, +#define OLDTOY(name, oldname, flags) \ + {#name, oldname##_main, OPTSTR_##oldname, flags}, + +struct toy_list toy_list[] = { +#include "generated/newtoys.h" +}; + +// global context for this command. + +struct toy_context toys; +union global_union this; +char toybuf[4096], libbuf[4096]; + +struct toy_list *toy_find(char *name) +{ + int top, bottom, middle; + + if (!CFG_TOYBOX || strchr(name, '/')) return 0; + + // If the name starts with "toybox" accept that as a match. Otherwise + // skip the first entry, which is out of order. + + if (!strncmp(name, "toybox", 6)) return toy_list; + bottom = 1; + + // Binary search to find this command. + + top = ARRAY_LEN(toy_list)-1; + for (;;) { + int result; + + middle = (top+bottom)/2; + if (middletop) return 0; + result = strcmp(name,toy_list[middle].name); + if (!result) return toy_list+middle; + if (result<0) top = --middle; + else bottom = ++middle; + } +} + +// Figure out whether or not anything is using the option parsing logic, +// because the compiler can't figure out whether or not to optimize it away +// on its' own. NEED_OPTIONS becomes a constant allowing if() to optimize +// stuff out via dead code elimination. + +#undef NEWTOY +#undef OLDTOY +#define NEWTOY(name, opts, flags) opts || +#define OLDTOY(name, oldname, flags) OPTSTR_##oldname || +static const int NEED_OPTIONS = +#include "generated/newtoys.h" +0; // Ends the opts || opts || opts... + +static void unknown(char *name) +{ + toys.exitval = 127; + toys.which = toy_list; + error_exit("Unknown command %s", name); +} + +// Setup toybox global state for this command. +static void toy_singleinit(struct toy_list *which, char *argv[]) +{ + toys.which = which; + toys.argv = argv; + + if (CFG_TOYBOX_I18N) setlocale(LC_CTYPE, "C.UTF-8"); + setlinebuf(stdout); + + // Parse --help and --version for (almost) all commands + if (CFG_TOYBOX_HELP_DASHDASH && !(which->flags & TOYFLAG_NOHELP) && argv[1]) { + if (!strcmp(argv[1], "--help")) { + if (CFG_TOYBOX && toys.which == toy_list && toys.argv[2]) + if (!(toys.which = toy_find(toys.argv[2]))) unknown(toys.argv[2]); + show_help(stdout); + xexit(); + } + + if (!strcmp(argv[1], "--version")) { + xputs("toybox "TOYBOX_VERSION); + xexit(); + } + } + + if (NEED_OPTIONS && which->options) get_optflags(); + else { + toys.optargs = argv+1; + for (toys.optc = 0; toys.optargs[toys.optc]; toys.optc++); + } + toys.old_umask = umask(0); + if (!(which->flags & TOYFLAG_UMASK)) umask(toys.old_umask); + toys.signalfd--; + toys.toycount = ARRAY_LEN(toy_list); +} + +// Full init needed by multiplexer or reentrant calls, calls singleinit at end +void toy_init(struct toy_list *which, char *argv[]) +{ + void *oldwhich = toys.which; + + // Drop permissions for non-suid commands. + + if (CFG_TOYBOX_SUID) { + if (!toys.which) toys.which = toy_list; + + uid_t uid = getuid(), euid = geteuid(); + + if (!(which->flags & TOYFLAG_STAYROOT)) { + if (uid != euid) { + if (setuid(uid)) perror_exit("setuid %d->%d", euid, uid); // drop root + euid = uid; + toys.wasroot++; + } + } else if (CFG_TOYBOX_DEBUG && uid && which != toy_list) + error_msg("Not installed suid root"); + + if ((which->flags & TOYFLAG_NEEDROOT) && euid != KERNEL_PROCESS_GROUP) help_exit("Not root"); + } + + // Free old toys contents (to be reentrant), but leave rebound if any + // don't blank old optargs if our new argc lives in the old optargs. + if (argvtoys.optargs+toys.optc) free(toys.optargs); + memset(&toys, 0, offsetof(struct toy_context, rebound)); + if (oldwhich) memset(&this, 0, sizeof(this)); + + // Continue to portion of init needed by standalone commands + toy_singleinit(which, argv); +} + +// Run an internal toybox command. +// Only returns if it can't run command internally, otherwise xexit() when done. +void toy_exec_which(struct toy_list *which, char *argv[]) +{ + // Return if we can't find it (which includes no multiplexer case), + if (!which) return; + + // Return if stack depth getting noticeable (proxy for leaked heap, etc). + + // Compiler writers have decided subtracting char * is undefined behavior, + // so convert to integers. (LP64 says sizeof(long)==sizeof(pointer).) + // Signed typecast so stack growth direction is irrelevant: we're measuring + // the distance between two pointers on the same stack, hence the labs(). + if (!CFG_TOYBOX_NORECURSE && toys.stacktop) + if (labs((long)toys.stacktop-(long)&which)>6000) return; + + // Return if we need to re-exec to acquire root via suid bit. + if (toys.which && (which->flags&TOYFLAG_ROOTONLY) && toys.wasroot) return; + + // Run command + toy_init(which, argv); + if (toys.which) toys.which->toy_main(); + xexit(); +} + +// Lookup internal toybox command to run via argv[0] +void toy_exec(char *argv[]) +{ + toy_exec_which(toy_find(basename(*argv)), argv); +} + +// Multiplexer command, first argument is command to run, rest are args to that. +// If first argument starts with - output list of command install paths. +void toybox_main(void) +{ + static char *toy_paths[]={"usr/","bin/","sbin/",0}; + int i, len = 0; + + // fast path: try to exec immediately. + // (Leave toys.which null to disable suid return logic.) + // Try dereferencing one layer of symlink + if (toys.argv[1]) { + toy_exec(toys.argv+1); + if (0 65) len = 0; + xputc(len ? ' ' : '\n'); + } + } + xputc('\n'); +} + +int main(int argc, char *argv[]) +{ + if (!*argv) return 127; + + // Snapshot stack location so we can detect recursion depth later. + // This is its own block so probe doesn't permanently consume stack. + else { + int stack; + + toys.stacktop = &stack; + } + + // Up to and including Android M, bionic's dynamic linker added a handler to + // cause a crash dump on SIGPIPE. That was removed in Android N, but adbd + // was still setting the SIGPIPE disposition to SIG_IGN, and its children + // were inheriting that. In Android O, adbd is fixed, but manually asking + // for the default disposition is harmless, and it'll be a long time before + // no one's using anything older than O! + if (CFG_TOYBOX_ON_ANDROID) signal(SIGPIPE, SIG_DFL); + + // If nommu can't fork, special reentry path. + // Use !stacktop to signal "vfork happened", both before and after xexec() + if (!CFG_TOYBOX_FORK) { + if (0x80 & **argv) { + **argv &= 0x7f; + toys.stacktop = 0; + } + } + + if (CFG_TOYBOX) { + // Call the multiplexer, adjusting this argv[] to be its' argv[1]. + // (It will adjust it back before calling toy_exec().) + toys.argv = argv-1; + toybox_main(); + } else { + // a single toybox command built standalone with no multiplexer + toy_singleinit(toy_list, argv); + toy_list->toy_main(); + } + + xexit(); +} diff --git a/porting/liteos_a/toys.h b/porting/liteos_a/toys.h index cdfad86..5b30606 100644 --- a/porting/liteos_a/toys.h +++ b/porting/liteos_a/toys.h @@ -83,6 +83,9 @@ // These live in main.c +#define USER_PRIVILEGE_PROCESS_GROUP 1U +#define KERNEL_PROCESS_GROUP 2U + struct toy_list *toy_find(char *name); void toy_init(struct toy_list *which, char *argv[]); void toy_exec(char *argv[]); diff --git a/porting/liteos_a/toys/other/reboot.c b/porting/liteos_a/toys/other/reboot.c new file mode 100644 index 0000000..77693be --- /dev/null +++ b/porting/liteos_a/toys/other/reboot.c @@ -0,0 +1,35 @@ +/* reboot.c - Restart, halt or powerdown the system. + * + * Copyright 2013 Elie De Brauwer + +USE_REBOOT(NEWTOY(reboot, "fn", TOYFLAG_SBIN|TOYFLAG_NEEDROOT)) +USE_REBOOT(OLDTOY(halt, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT)) +USE_REBOOT(OLDTOY(poweroff, reboot, TOYFLAG_SBIN|TOYFLAG_NEEDROOT)) + +config REBOOT + bool "reboot" + default y + help + usage: reboot/halt/poweroff [-fn] + + Restart, halt or powerdown the system. + + -f Don't signal init + -n Don't sync before stopping the system +*/ + +#define FOR_reboot +#include "toys.h" +#include + +void reboot_main(void) +{ + int types[] = {RB_AUTOBOOT, RB_HALT_SYSTEM, RB_POWER_OFF}, + sigs[] = {SIGTERM, SIGUSR1, SIGUSR2}, idx; + + if (!*toys.optargs) help_exit("missing argument"); + if (!(toys.optflags & FLAG_n)) sync(); + + idx = stridx("hp", *toys.which->name)+1; + if (toys.optflags & FLAG_f) toys.exitval = reboot(types[idx]); +} -- Gitee