From patchwork Tue Dec 18 04:19:53 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sam Mendoza-Jonas X-Patchwork-Id: 1014982 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 43JlGQ2X6lz9sBZ for ; Tue, 18 Dec 2018 15:21:50 +1100 (AEDT) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=mendozajonas.com Authentication-Results: ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mendozajonas.com header.i=@mendozajonas.com header.b="FCiiBrz1"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="Ma31LWzU"; dkim-atps=neutral Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 43JlGQ0gDNzDqYh for ; Tue, 18 Dec 2018 15:21:50 +1100 (AEDT) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=mendozajonas.com Authentication-Results: lists.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=mendozajonas.com header.i=@mendozajonas.com header.b="FCiiBrz1"; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="Ma31LWzU"; dkim-atps=neutral X-Original-To: petitboot@lists.ozlabs.org Delivered-To: petitboot@lists.ozlabs.org Authentication-Results: lists.ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=mendozajonas.com (client-ip=66.111.4.25; helo=out1-smtp.messagingengine.com; envelope-from=sam@mendozajonas.com; receiver=) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=mendozajonas.com Authentication-Results: lists.ozlabs.org; dkim=pass (2048-bit key; unprotected) header.d=mendozajonas.com header.i=@mendozajonas.com header.b="FCiiBrz1"; dkim=pass (2048-bit key; unprotected) header.d=messagingengine.com header.i=@messagingengine.com header.b="Ma31LWzU"; dkim-atps=neutral Received: from out1-smtp.messagingengine.com (out1-smtp.messagingengine.com [66.111.4.25]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 43JlDf3vmPzDqXK for ; Tue, 18 Dec 2018 15:20:18 +1100 (AEDT) Received: from compute2.internal (compute2.nyi.internal [10.202.2.42]) by mailout.nyi.internal (Postfix) with ESMTP id 499CF2246E; Mon, 17 Dec 2018 23:20:16 -0500 (EST) Received: from mailfrontend2 ([10.202.2.163]) by compute2.internal (MEProxy); Mon, 17 Dec 2018 23:20:16 -0500 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= mendozajonas.com; h=from:to:cc:subject:date:message-id :in-reply-to:references:mime-version:content-transfer-encoding; s=fm1; bh=qIctfd2U7QoGGLZXc2b+d1AXjn5euWKPrsAsMl+kbEc=; b=FCiiB rz1a4En0C1Rg/jIdNrBPodfI9JoSqWv3KDRo3lIyyXIUSBGdaVugZkUTyMUrQneC grwyd5S40fSyUBnufRzFT/WEU+VppK/FrFj0VqpKPbxKRncN+LiidhoBRN0kHMzr s/RjraUTDZkykz9MSvAFtywJtREfAvidSrPf8+vQ92Cg0oaX+xlBP2QRwdrHcIfX 1RiS/QQ/INrCanS+g9dKyf0XDplJzzYVOuHwoyG8CSM+B2XP4+I8cOYvQDgZlQwo dGZTh9U2zSyjXJXoITtEHbdMPnEX0JN/2duCgwYapUg2fzgP/TqnA+2ocrr25z+6 3zmTTRrW1OG+rwxvQ== DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=cc:content-transfer-encoding:date:from :in-reply-to:message-id:mime-version:references:subject:to :x-me-proxy:x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s= fm1; bh=qIctfd2U7QoGGLZXc2b+d1AXjn5euWKPrsAsMl+kbEc=; b=Ma31LWzU ETWiLov1S+Y7WxqoYznFs95jf+qhD5Qs99Ye25dzRF9jGdLdp9xaVA3qpTkALOtj DpBBMRdidqrnLV1OiPbiTfi9FrpWUNLB5xQ+2+ahMB/IhM5BrQnTG059ijd4uHoi /bj2f04B7n9DUQjgfXov7ZumEyd6/Zq96p+V0U9HMlZ9tm6OC+Gc1AC7H/SqAQZ8 fFcoj/E4h7LEoUW285I7kKO/EBORHE4NxwgXhLMQsaK0MAox6aWlAOE1PDh0jRhd X0qXDFxjZaL1rxbNCkrfs03gqZLXOhpjzPooufnix2rb+cjCxMB8H/TpM2CWntDf UOjA4RGVhNKQ3Q== X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgedtkedrudeigedgjeduucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfquhhtnecuuegrihhlohhuthemucef tddtnecunecujfgurhephffvufffkffojghfggfgsedtkeertdertddtnecuhfhrohhmpe furghmuhgvlhcuofgvnhguohiirgdqlfhonhgrshcuoehsrghmsehmvghnughoiigrjhho nhgrshdrtghomheqnecukfhppeduvddvrdelledrkedvrddutdenucfrrghrrghmpehmrg hilhhfrhhomhepshgrmhesmhgvnhguohiirghjohhnrghsrdgtohhmnecuvehluhhsthgv rhfuihiivgepge X-ME-Proxy: Received: from v4.ozlabs.ibm.com (unknown [122.99.82.10]) by mail.messagingengine.com (Postfix) with ESMTPA id C2B7F10084; Mon, 17 Dec 2018 23:20:14 -0500 (EST) From: Samuel Mendoza-Jonas To: petitboot@lists.ozlabs.org Subject: [RFC PATCH 8/8] ui/ncurses: Present plugin commands in nc-plugin Date: Tue, 18 Dec 2018 15:19:53 +1100 Message-Id: <20181218041953.8960-9-sam@mendozajonas.com> X-Mailer: git-send-email 2.20.0 In-Reply-To: <20181218041953.8960-1-sam@mendozajonas.com> References: <20181218041953.8960-1-sam@mendozajonas.com> MIME-Version: 1.0 X-BeenThere: petitboot@lists.ozlabs.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Petitboot bootloader development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Samuel Mendoza-Jonas Errors-To: petitboot-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Petitboot" Update the Plugin screen to present commands and their arguments if available. The user may modify the arguments and run the commands as displayed in the same way an executable may have been run previously. An extra field is also added to provide arbitrary arguments to a given plugin executable. Signed-off-by: Samuel Mendoza-Jonas --- ui/ncurses/nc-plugin.c | 256 ++++++++++++++++++++++++++++++++++++++--- 1 file changed, 237 insertions(+), 19 deletions(-) diff --git a/ui/ncurses/nc-plugin.c b/ui/ncurses/nc-plugin.c index f897cc8e..84e811a4 100644 --- a/ui/ncurses/nc-plugin.c +++ b/ui/ncurses/nc-plugin.c @@ -36,12 +36,22 @@ #include "process/process.h" #include "system/system.h" -#define N_FIELDS 15 +#define N_FIELDS 17 extern const struct help_text plugin_help_text; static void plugin_run_command(void *arg); +struct command_option { + // TODO If platform doesn't match a) warn, or b) hide? + struct nc_widget_label *name_l; + struct nc_widget_button *cmd_b; /* cmd + args_fmt */ + unsigned int n_args; + struct nc_widget_label **arg_l; + struct nc_widget_textbox **arg_f; + struct nc_widget_label *help_l; +}; + struct plugin_screen { struct nc_scr scr; struct cui *cui; @@ -76,9 +86,13 @@ struct plugin_screen { struct nc_widget_label *commands_l; struct nc_widget_select *commands_f; - + struct nc_widget_label *exec_args_l; + struct nc_widget_textbox *exec_args_f; struct nc_widget_button *run_b; } widgets; + + struct command_option *commands; + unsigned int n_commands; }; static void plugin_screen_draw(struct plugin_screen *screen, @@ -203,7 +217,116 @@ static void plugin_screen_resize(struct nc_scr *scr) plugin_screen_post(scr); } +static void update_arguments(struct plugin_screen *screen, int cmd_idx) +{ + struct command_option *opt; + struct command *cmd; + unsigned int i; + char *field; + + opt = &screen->commands[cmd_idx]; + cmd = &screen->opt->commands[cmd_idx]; + + for (i = 0; i < opt->n_args; i++) { + field = widget_textbox_get_value(opt->arg_f[i]); + + switch (cmd->args[i].type) { + case ARG_STR: + talloc_free(cmd->args[i].arg_str); + cmd->args[i].arg_str = talloc_strdup(screen, field); + break; + case ARG_I64: + { + int64_t val; + val = strtol(field, NULL, 10); + if (!errno) + cmd->args[i].arg_i64 = val; + break; + } + case ARG_F64: + { + double val; + val = strtod(field, NULL); + if (!errno) + cmd->args[i].arg_f64 = val; + break; + } + } + } +} + static void plugin_run_command(void *arg) +{ + struct plugin_screen *screen = arg; + struct nc_widget *current; + struct command_option *opt; + int result, n_var; + unsigned int idx; + char *fmt, *args, *var, *cmd_str; + + + /* Get selected command */ + current = current_widget(screen->widgetset); + if (!current) { + pb_log_fn("No command selected!\n"); + return; + } + + opt = NULL; + for (idx = 0; idx < screen->n_commands; idx++) { + if (widget_button_base(screen->commands[idx].cmd_b) == current) { + opt = &screen->commands[idx]; + break; + } + } + + if (!opt) { + pb_log_fn("Could not find current option\n"); + return; + } + + fmt = talloc_strdup(screen, screen->opt->commands[idx].args_fmt); + cmd_str = talloc_asprintf(screen, "%s ", screen->opt->commands[idx].cmd); + n_var = 0; + args = fmt; + while (args) { + var = strstr(args, "{}"); + if (var) + *var = '\0'; + cmd_str = talloc_asprintf_append(cmd_str, "%s%s", + args, var ? widget_textbox_get_value( + opt->arg_f[n_var++]) : ""); + + args = var ? var + 2 : NULL; + } + + const char *argv[] = { + pb_system_apps.pb_exec, + cmd_str, + NULL, + }; + + /* Drop our pad before running plugin */ + delwin(screen->pad); + screen->pad = NULL; + + result = cui_run_cmd(screen->cui, argv); + + if (result) + pb_log("Failed to run command option %s\n", argv[1]); + else { + update_arguments(screen, idx); + nc_scr_status_printf(screen->cui->current, _("Finished: %s"), + argv[1]); + } + + talloc_free(fmt); + talloc_free(cmd_str); + + plugin_screen_draw(screen, NULL); +} + +static void plugin_run_command_single(void *arg) { struct plugin_screen *screen = arg; char *cmd; @@ -222,6 +345,7 @@ static void plugin_run_command(void *arg) const char *argv[] = { pb_system_apps.pb_exec, cmd, + widget_textbox_get_value(screen->widgets.exec_args_f), NULL }; @@ -246,7 +370,7 @@ static void plugin_run_command_check(void *arg) struct plugin_screen *screen = arg; if (discover_client_authenticated(screen->cui->client)) { - plugin_run_command(screen); + plugin_run_command_single(screen); return; } @@ -283,17 +407,81 @@ static void plugin_screen_setup_widgets(struct plugin_screen *screen) screen->widgets.date_l = widget_new_label(set, 0, 0, _("Date")); screen->widgets.date_f = widget_new_label(set, 0, 0, opt->date); - screen->widgets.commands_l = widget_new_label(set, 0, 0, - _("Commands:")); screen->widgets.commands_f = widget_new_select(set, 0, 0, COLS - screen->field_x - 1); - for (i = 0; i < opt->n_executables; i++) { - widget_select_add_option(screen->widgets.commands_f, i, - basename(opt->executables[i]), i == 0); + if (opt->n_executables) { + screen->widgets.commands_l = widget_new_label(set, 0, 0, + _("Executables:")); + for (i = 0; i < opt->n_executables; i++) { + widget_select_add_option(screen->widgets.commands_f, i, + basename(opt->executables[i]), i == 0); + } + + screen->widgets.exec_args_l = widget_new_label(set, 0, 0, + _("Arguments:")); + screen->widgets.exec_args_f = widget_new_textbox(set, 0, 0, 30, + ""); + + screen->widgets.run_b = widget_new_button(set, 0, 0, 30, + _("Run selected executable"), + plugin_run_command_check, screen); + } + + screen->n_commands = opt->n_commands; + screen->commands = talloc_array(screen, struct command_option, + screen->n_commands); + for (i = 0; i < opt->n_commands; i++) { + unsigned int j; + char *label; + screen->commands[i].name_l = widget_new_label(set, 0, 0, + opt->commands[i].name); + label = talloc_asprintf(screen, "%s %s", + opt->commands[i].cmd, + opt->commands[i].args_fmt); + screen->commands[i].cmd_b = widget_new_button(set, 0, 0, 45, + label, plugin_run_command, screen); + screen->commands[i].n_args = opt->commands[i].n_args; + screen->commands[i].arg_l = talloc_zero_array(screen, + struct nc_widget_label *, + screen->commands[i].n_args); + screen->commands[i].arg_f = talloc_zero_array(screen, + struct nc_widget_textbox *, + screen->commands[i].n_args); + for (j = 0; j < screen->commands[i].n_args; j++) { + screen->commands[i].arg_l[j] = widget_new_label(set, + 0, 0, + opt->commands[i].args[j].name); + switch (opt->commands[i].args[j].type) { + case ARG_STR: + screen->commands[i].arg_f[j] = + widget_new_textbox(set, 0, 0, 20, + opt->commands[i].args[j].arg_str); + break; + case ARG_I64: + label = talloc_asprintf(screen, "%ld", + opt->commands[i].args[j].arg_i64); + screen->commands[i].arg_f[j] = + widget_new_textbox(set, 0, 0, 20, + label); + break; + case ARG_F64: + label = talloc_asprintf(screen, "%f", + opt->commands[i].args[j].arg_f64); + screen->commands[i].arg_f[j] = + widget_new_textbox(set, 0, 0, 20, + label); + break; + default: + label = talloc_asprintf(screen, ""); + screen->commands[i].arg_f[j] = + widget_new_textbox(set, 0, 0, 20, + label); + } + } + screen->commands[i].help_l = widget_new_label(set, 0, 0, + opt->commands[i].help); } - screen->widgets.run_b = widget_new_button(set, 0, 0, 30, - _("Run selected command"), plugin_run_command_check, screen); } static int layout_pair(struct plugin_screen *screen, int y, @@ -308,7 +496,7 @@ static int layout_pair(struct plugin_screen *screen, int y, static void plugin_screen_layout_widgets(struct plugin_screen *screen) { - unsigned int y; + unsigned int y, i; /* list of details (static) */ @@ -329,15 +517,45 @@ static void plugin_screen_layout_widgets(struct plugin_screen *screen) y += 1; - /* available commands */ - widget_move(widget_label_base(screen->widgets.commands_l), y, - screen->label_x); - widget_move(widget_select_base(screen->widgets.commands_f), y, - screen->field_x); + if (widget_select_get_value(screen->widgets.commands_f) != -1) { + /* available executables */ + widget_move(widget_label_base(screen->widgets.commands_l), y, + screen->label_x); + widget_move(widget_select_base(screen->widgets.commands_f), y, + screen->field_x); - y += 2; + y += 1; + + layout_pair(screen, y++, screen->widgets.exec_args_l, + widget_textbox_base(screen->widgets.exec_args_f)); + widget_move(widget_button_base(screen->widgets.run_b), y++, + screen->field_x); + + y += 2; + } + + + for (i = 0; i < screen->n_commands; i++) { + unsigned int j; + widget_move(widget_label_base(screen->commands[i].name_l), y++, + screen->label_x); + widget_move(widget_button_base(screen->commands[i].cmd_b), y++, + screen->field_x); + + for (j = 0; j < screen->commands[i].n_args; j++) { + widget_move(widget_label_base(screen->commands[i].arg_l[j]), + y, screen->field_x); + widget_move(widget_textbox_base(screen->commands[i].arg_f[j]), + y, screen->field_x * 2); + y += 1; + } + + widget_move(widget_label_base(screen->commands[i].help_l), y++, + screen->label_x); + y += 1; + } - widget_move(widget_button_base(screen->widgets.run_b), y++, screen->field_x); + y += 2; } @@ -402,7 +620,7 @@ struct plugin_screen *plugin_screen_init(struct cui *cui, screen->cui = cui; screen->on_exit = on_exit; screen->label_x = 2; - screen->field_x = 25; + screen->field_x = 15; screen->scr.frame.ltitle = talloc_strdup(screen, _("Petitboot Plugin"));