Index: sys/ddb/db_command.c =================================================================== --- sys/ddb/db_command.c +++ sys/ddb/db_command.c @@ -125,6 +125,7 @@ { "where", db_stack_trace, CS_OWN, NULL }, { "bt", db_stack_trace, CS_OWN, NULL }, { "call", db_fncall, CS_OWN, NULL }, + { "nextboot", db_nextboot_cmd, CS_OWN, NULL }, { "show", 0, 0, &db_show_table }, { "ps", db_ps, 0, NULL }, { "gdb", db_gdb, 0, NULL }, Index: sys/ddb/ddb.h =================================================================== --- sys/ddb/ddb.h +++ sys/ddb/ddb.h @@ -237,6 +237,7 @@ db_cmdfcn_t db_findstack_cmd; db_cmdfcn_t db_hwatchpoint_cmd; db_cmdfcn_t db_listbreak_cmd; +db_cmdfcn_t db_nextboot_cmd; db_cmdfcn_t db_scripts_cmd; db_cmdfcn_t db_print_cmd; db_cmdfcn_t db_ps; Index: sys/kern/kern_shutdown.c =================================================================== --- sys/kern/kern_shutdown.c +++ sys/kern/kern_shutdown.c @@ -64,6 +64,7 @@ #include #include #include +#include #include #include #include @@ -72,6 +73,7 @@ #include #include +#include #include #include @@ -978,6 +980,170 @@ } #ifdef DDB +/* + * Configure nextboot. Usage similar to nextboot(8). + * + * Syntax: nextboot [-k kernel] [-e variable=value] [-o -flag] + * + * There are some quirks with ddb's lexer. Kernel and variable names must be C + * identifiers (not the full generality of filesystem and environment variable + * names). Values and flags must be unquoted, single C identifiers. + * + * E.g.: + * + * nextboot -k goodkernel -e abc=def -o -sv + */ +void +db_nextboot_cmd(db_expr_t dummy1 __unused, bool dummy2 __unused, + db_expr_t dummy3 __unused, char *dummy4 __unused) +{ + static char buffer[512]; + static char nextkernelname[128]; + static char options[128]; + static char var[4][32]; + static char value[4][32]; + + unsigned i, nvariables = 0; + bool anyargs, Dflag; + struct sbuf sb; + int t, error; + off_t n; + + anyargs = false; + Dflag = false; + + if (nextbootinfo.nip_write == NULL) { + db_printf("Nextboot unconfigured\n"); + db_skip_to_eol(); + return; + } + + while ((t = db_read_token()) != tEOL) { + if (t != tMINUS) + goto bad_argument; + + t = db_read_token(); + if (t != tIDENT || strlen(db_tok_string) != 1) + goto bad_argument; + + switch (db_tok_string[0]) { + case 'D': + if (anyargs) + goto Dflag_only; + anyargs = true; + Dflag = true; + break; + case 'k': + if (Dflag) + goto Dflag_only; + anyargs = true; + t = db_read_token(); + if (t != tIDENT) + goto bad_argument; + strlcpy(nextkernelname, db_tok_string, + sizeof(nextkernelname)); + break; + case 'e': + if (Dflag) + goto Dflag_only; + anyargs = true; + if (nvariables >= nitems(var)) { + db_printf("Too many variables (>%zu)\n", nitems(var)); + db_flush_lex(); + return; + } + + t = db_read_token(); + if (t != tIDENT) + goto bad_argument; + + strlcpy(var[nvariables], db_tok_string, + sizeof(var[0])); + + t = db_read_token(); + if (t != tEQ) + goto bad_argument; + t = db_read_token(); + if (t != tIDENT) + goto bad_argument; + + strlcpy(value[nvariables++], db_tok_string, + sizeof(value[0])); + break; + case 'o': + if (Dflag) + goto Dflag_only; + anyargs = true; + t = db_read_token(); + if (t != tMINUS) + goto bad_argument; + t = db_read_token(); + if (t != tIDENT) + goto bad_argument; + strlcpy(options, db_tok_string, sizeof(options)); + break; + default: + db_printf("Bad flag '%c'\n", db_tok_string[0]); + goto usage; + } + } + + if (!anyargs) + goto usage; + + sbuf_new(&sb, buffer, sizeof(buffer), SBUF_FIXEDLEN); + if (Dflag) { + for (n = 0; n < nextbootinfo.nip_dumperinfo.mediasize; n++) + sbuf_putc(&sb, ' '); + } else { + sbuf_cat(&sb, "nextboot_enable=\"YES\"\n"); + if (nextkernelname[0] != '\0') + sbuf_printf(&sb, "kernel=\"%s\"\n", nextkernelname); + for (i = 0; i < nvariables; i++) + sbuf_printf(&sb, "%s=\"%s\"\n", var[i], value[i]); + for (i = 0; options[i] != '\0'; i++) + sbuf_printf(&sb, "kernel_options=\"-%c\"\n", options[i]); + } + + error = sbuf_finish(&sb); + if (error != 0) + db_printf("Error printing nextboot.conf: %d\n", error); + else { + size_t dummysize; + + error = dump_write_pad(&nextbootinfo.nip_dumperinfo, + sbuf_data(&sb), 0, nextbootinfo.nip_dumperinfo.mediaoffset, + sbuf_len(&sb), &dummysize); + (void)dummysize; + + if (error != 0) + db_printf("Error writing nextboot.conf: %d\n", error); + } + return; + +bad_argument: + db_printf("Bad argument\n"); + db_flush_lex(); + return; + +Dflag_only: + db_printf("-D flag can't be combined with other options\n"); + db_flush_lex(); + return; + +usage: + db_printf("Usage: nextboot [-k kernelname] [-e var=val] " + "[-o -options] [-D]\n" + " -k kernelname Select this kernel next boot\n" + " -e var=val Set environmental variable 'var' to " + "'val' next boot\n" + " -o -flags Set flags next boot\n" + " -D Clear existing nextboot configuration\n" + ); + db_flush_lex(); + return; +} + DB_SHOW_COMMAND(panic, db_show_panic) {