[PATCH 1/2] ui/ncurses: Add ui and functions to send url to server

Samuel Mendoza-Jonas sam.mj at au1.ibm.com
Thu Jul 17 09:58:30 EST 2014


Signed-off-by: Samuel Mendoza-Jonas <sam.mj at au1.ibm.com>
---
 lib/pb-protocol/pb-protocol.c |  18 +++
 lib/pb-protocol/pb-protocol.h |   3 +
 ui/common/discover-client.c   |  18 +++
 ui/common/discover-client.h   |   4 +
 ui/ncurses/Makefile.am        |   5 +-
 ui/ncurses/generic-main.c     |  14 +-
 ui/ncurses/nc-cui.c           |  19 +++
 ui/ncurses/nc-cui.h           |   3 +
 ui/ncurses/nc-retrieve-help.c |   5 +
 ui/ncurses/nc-retrieve.c      | 326 ++++++++++++++++++++++++++++++++++++++++++
 ui/ncurses/nc-retrieve.h      |  31 ++++
 ui/ncurses/nc-scr.h           |   3 +-
 12 files changed, 445 insertions(+), 4 deletions(-)
 create mode 100644 ui/ncurses/nc-retrieve-help.c
 create mode 100644 ui/ncurses/nc-retrieve.c
 create mode 100644 ui/ncurses/nc-retrieve.h

diff --git a/lib/pb-protocol/pb-protocol.c b/lib/pb-protocol/pb-protocol.c
index 67e1f9e..b721c2a 100644
--- a/lib/pb-protocol/pb-protocol.c
+++ b/lib/pb-protocol/pb-protocol.c
@@ -286,6 +286,12 @@ int pb_protocol_config_len(const struct config *config)
 	return len;
 }
 
+int pb_protocol_url_len(const char *url)
+{
+	/* url + length field */
+	return strlen(url) + sizeof(uint32_t);
+}
+
 int pb_protocol_serialise_device(const struct device *dev,
 		char *buf, int buf_len)
 {
@@ -482,6 +488,18 @@ int pb_protocol_serialise_config(const struct config *config,
 	return 0;
 }
 
+int pb_protocol_serialise_retrieve(const char *url, char *buf, int buf_len)
+{
+	char *pos = buf;
+
+	pos += pb_protocol_serialise_string(pos, url);
+
+	assert(pos <=buf+buf_len);
+	(void)buf_len;
+
+	return 0;
+}
+
 int pb_protocol_write_message(int fd, struct pb_protocol_message *message)
 {
 	int total_len, rc;
diff --git a/lib/pb-protocol/pb-protocol.h b/lib/pb-protocol/pb-protocol.h
index d6f149c..2db521f 100644
--- a/lib/pb-protocol/pb-protocol.h
+++ b/lib/pb-protocol/pb-protocol.h
@@ -22,6 +22,7 @@ enum pb_protocol_action {
 	PB_PROTOCOL_ACTION_SYSTEM_INFO		= 0x8,
 	PB_PROTOCOL_ACTION_CONFIG		= 0x9,
 	PB_PROTOCOL_ACTION_REINIT		= 0xa,
+	PB_PROTOCOL_ACTION_RETRIEVE		= 0xb,
 };
 
 struct pb_protocol_message {
@@ -38,6 +39,7 @@ int pb_protocol_boot_len(const struct boot_command *boot);
 int pb_protocol_boot_status_len(const struct boot_status *status);
 int pb_protocol_system_info_len(const struct system_info *sysinfo);
 int pb_protocol_config_len(const struct config *config);
+int pb_protocol_url_len(const char *url);
 int pb_protocol_device_cmp(const struct device *a, const struct device *b);
 
 int pb_protocol_boot_option_cmp(const struct boot_option *a,
@@ -59,6 +61,7 @@ int pb_protocol_serialise_system_info(const struct system_info *sysinfo,
 		char *buf, int buf_len);
 int pb_protocol_serialise_config(const struct config *config,
 		char *buf, int buf_len);
+int pb_protocol_serialise_retrieve(const char *url, char *buf, int buf_len);
 
 int pb_protocol_write_message(int fd, struct pb_protocol_message *message);
 
diff --git a/ui/common/discover-client.c b/ui/common/discover-client.c
index a124f8b..f422cee 100644
--- a/ui/common/discover-client.c
+++ b/ui/common/discover-client.c
@@ -365,3 +365,21 @@ int discover_client_send_config(struct discover_client *client,
 
 	return pb_protocol_write_message(client->fd, message);
 }
+
+int discover_client_send_retrieve(struct discover_client *client,
+		char *url)
+{
+	struct pb_protocol_message *message;
+	int len;
+
+	len = pb_protocol_url_len(url);
+
+	message = pb_protocol_create_message(client,
+				PB_PROTOCOL_ACTION_RETRIEVE, len);
+	if (!message)
+		return -1;
+
+	pb_protocol_serialise_retrieve(url, message->payload, len);
+
+	return pb_protocol_write_message(client->fd, message);
+}
diff --git a/ui/common/discover-client.h b/ui/common/discover-client.h
index 405bd24..0c8f12a 100644
--- a/ui/common/discover-client.h
+++ b/ui/common/discover-client.h
@@ -82,4 +82,8 @@ int discover_client_send_reinit(struct discover_client *client);
 /* Send new configuration data to the discover server */
 int discover_client_send_config(struct discover_client *client,
 		struct config *config);
+
+/* Send url to retrieve config to the discover server */
+int discover_client_send_retrieve(struct discover_client *client,
+		char *url);
 #endif
diff --git a/ui/ncurses/Makefile.am b/ui/ncurses/Makefile.am
index ded3193..f5ffa3a 100644
--- a/ui/ncurses/Makefile.am
+++ b/ui/ncurses/Makefile.am
@@ -49,7 +49,10 @@ libpbnc_la_SOURCES = \
 	nc-textscreen.c \
 	nc-textscreen.h \
 	nc-widgets.c \
-	nc-widgets.h
+	nc-widgets.h \
+	nc-retrieve.c \
+	nc-retrieve.h \
+	nc-retrieve-help.c
 
 sbin_PROGRAMS = petitboot-nc
 
diff --git a/ui/ncurses/generic-main.c b/ui/ncurses/generic-main.c
index fe288ee..9eb19b4 100644
--- a/ui/ncurses/generic-main.c
+++ b/ui/ncurses/generic-main.c
@@ -169,6 +169,12 @@ static int pmenu_config(struct pmenu_item *item)
 	return 0;
 }
 
+static int pmenu_retrieve(struct pmenu_item *item)
+{
+	cui_show_retrieve(cui_from_item(item));
+	return 0;
+}
+
 static int pmenu_reinit(struct pmenu_item *item)
 {
 	cui_send_reinit(cui_from_item(item));
@@ -185,7 +191,7 @@ static struct pmenu *pb_mm_init(struct pb_cui *pb_cui)
 	struct pmenu *m;
 	struct pmenu_item *i;
 
-	m = pmenu_init(pb_cui->cui, 5, cui_on_exit);
+	m = pmenu_init(pb_cui->cui, 6, cui_on_exit);
 
 	if (!m) {
 		pb_log("%s: failed\n", __func__);
@@ -217,9 +223,13 @@ static struct pmenu *pb_mm_init(struct pb_cui *pb_cui)
 	i->on_execute = pmenu_reinit;
 	pmenu_item_insert(m, i, 3);
 
+	i = pmenu_item_create(m, "Retrieve config from URL");
+	i->on_execute = pmenu_retrieve;
+	pmenu_item_insert(m, i, 4);
+
 	i = pmenu_item_create(m, "Exit to shell");
 	i->on_execute = pmenu_exit_cb;
-	pmenu_item_insert(m, i, 4);
+	pmenu_item_insert(m, i, 5);
 
 	result = pmenu_setup(m);
 
diff --git a/ui/ncurses/nc-cui.c b/ui/ncurses/nc-cui.c
index 7200a81..5c64e09 100644
--- a/ui/ncurses/nc-cui.c
+++ b/ui/ncurses/nc-cui.c
@@ -37,6 +37,7 @@
 #include "nc-cui.h"
 #include "nc-boot-editor.h"
 #include "nc-config.h"
+#include "nc-retrieve.h"
 #include "nc-sysinfo.h"
 #include "nc-helpscreen.h"
 
@@ -262,6 +263,19 @@ void cui_show_config(struct cui *cui)
 	cui_set_current(cui, config_screen_scr(cui->config_screen));
 }
 
+static void cui_retrieve_exit(struct cui *cui)
+{
+	cui_set_current(cui, &cui->main->scr);
+	talloc_free(cui->retrieve_screen);
+	cui->retrieve_screen = NULL;
+}
+
+void cui_show_retrieve(struct cui *cui)
+{
+	cui->retrieve_screen = retrieve_screen_init(cui, cui_retrieve_exit);
+	cui_set_current(cui, retrieve_screen_scr(cui->retrieve_screen));
+}
+
 static void cui_help_exit(struct cui *cui)
 {
 	cui_set_current(cui, help_screen_return_scr(cui->help_screen));
@@ -599,6 +613,11 @@ int cui_send_config(struct cui *cui, struct config *config)
 	return discover_client_send_config(cui->client, config);
 }
 
+int cui_send_retrieve(struct cui *cui, char * url)
+{
+	return discover_client_send_retrieve(cui->client, url);
+}
+
 void cui_send_reinit(struct cui *cui)
 {
 	discover_client_send_reinit(cui->client);
diff --git a/ui/ncurses/nc-cui.h b/ui/ncurses/nc-cui.h
index 8632806..1e80928 100644
--- a/ui/ncurses/nc-cui.h
+++ b/ui/ncurses/nc-cui.h
@@ -58,6 +58,7 @@ struct cui {
 	struct sysinfo_screen *sysinfo_screen;
 	struct config *config;
 	struct config_screen *config_screen;
+	struct retrieve_screen *retrieve_screen;
 	struct boot_editor *boot_editor;
 	struct help_screen *help_screen;
 	struct pjs *pjs;
@@ -75,8 +76,10 @@ void cui_item_edit(struct pmenu_item *item);
 void cui_item_new(struct pmenu *menu);
 void cui_show_sysinfo(struct cui *cui);
 void cui_show_config(struct cui *cui);
+void cui_show_retrieve(struct cui *cui);
 void cui_show_help(struct cui *cui, const char *title, const char *text);
 int cui_send_config(struct cui *cui, struct config *config);
+int cui_send_retrieve(struct cui *cui, char *url);
 void cui_send_reinit(struct cui *cui);
 
 /* convenience routines */
diff --git a/ui/ncurses/nc-retrieve-help.c b/ui/ncurses/nc-retrieve-help.c
new file mode 100644
index 0000000..de0e183
--- /dev/null
+++ b/ui/ncurses/nc-retrieve-help.c
@@ -0,0 +1,5 @@
+const char *retrieve_help_text = "\
+Supply a valid URL here to retrieve a remote boot config file,\n\
+(eg: petitboot.conf) and parse it.\n\
+URLs are of the form 'scheme://host/path/to/petitboot.conf',\n\
+such as tftp://host/petitboot.conf or http://host/petitboot.conf";
diff --git a/ui/ncurses/nc-retrieve.c b/ui/ncurses/nc-retrieve.c
new file mode 100644
index 0000000..5878578
--- /dev/null
+++ b/ui/ncurses/nc-retrieve.c
@@ -0,0 +1,326 @@
+/*
+ *  Copyright (C) 2013 IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <talloc/talloc.h>
+#include <types/types.h>
+#include <log/log.h>
+
+#include "nc-cui.h"
+#include "nc-retrieve.h"
+#include "nc-widgets.h"
+
+#define N_FIELDS        5
+
+extern const char *retrieve_help_text;
+
+struct retrieve_screen {
+	struct nc_scr		scr;
+	struct cui		*cui;
+	struct nc_widgetset	*widgetset;
+	WINDOW			*pad;
+
+	bool			exit;
+	bool			show_help;
+	void			(*on_exit)(struct cui *);
+
+	int			scroll_y;
+
+	int			label_x;
+	int			field_x;
+
+	struct {
+		struct nc_widget_textbox	*url_f;
+		struct nc_widget_label		*url_l;
+
+		struct nc_widget_button         *ok_b;
+		struct nc_widget_button         *help_b;
+		struct nc_widget_button         *cancel_b;
+	} widgets;
+};
+
+static struct retrieve_screen *retrieve_screen_from_scr(struct nc_scr *scr)
+{
+	struct retrieve_screen *retrieve_screen;
+
+	assert(scr->sig == pb_retrieve_screen_sig);
+	retrieve_screen = (struct retrieve_screen *)
+		((char *)scr - (size_t)&((struct retrieve_screen *)0)->scr);
+	assert(retrieve_screen->scr.sig == pb_retrieve_screen_sig);
+	return retrieve_screen;
+}
+
+static void pad_refresh(struct retrieve_screen *screen)
+{
+	int y, x, rows, cols;
+
+	getmaxyx(screen->scr.sub_ncw, rows, cols);
+	getbegyx(screen->scr.sub_ncw, y, x);
+
+	prefresh(screen->pad, screen->scroll_y, 0, y, x, rows, cols);
+}
+
+static void retrieve_screen_process_key(struct nc_scr *scr, int key)
+{
+	struct retrieve_screen *screen = retrieve_screen_from_scr(scr);
+	bool handled;
+
+	handled = widgetset_process_key(screen->widgetset, key);
+
+	if (!handled) {
+		switch (key) {
+		case 'x':
+		case 27: /* esc */
+			screen->exit = true;
+			break;
+		case 'h':
+			screen->show_help = true;
+			break;
+		}
+	}
+
+	if (screen->exit) {
+		screen->on_exit(screen->cui);
+
+	} else if (screen->show_help) {
+		screen->show_help = false;
+		cui_show_help(screen->cui, "Retrieve Config",
+			retrieve_help_text);
+
+	} else if (handled) {
+		pad_refresh(screen);
+	}
+}
+
+static void retrieve_screen_resize(struct nc_scr *scr)
+{
+	struct retrieve_screen *screen = retrieve_screen_from_scr(scr);
+	(void)screen;
+}
+
+static int retrieve_screen_post(struct nc_scr *scr)
+{
+	struct retrieve_screen *screen = retrieve_screen_from_scr(scr);
+	widgetset_post(screen->widgetset);
+	nc_scr_frame_draw(scr);
+	redrawwin(scr->main_ncw);
+	wrefresh(screen->scr.main_ncw);
+	pad_refresh(screen);
+	return 0;
+}
+
+static int retrieve_screen_unpost(struct nc_scr *scr)
+{
+	struct retrieve_screen *screen = retrieve_screen_from_scr(scr);
+	widgetset_unpost(screen->widgetset);
+	return 0;
+}
+
+struct nc_scr *retrieve_screen_scr(struct retrieve_screen *screen)
+{
+	return &screen->scr;
+}
+
+static int screen_process_form(struct retrieve_screen *screen)
+{
+	char *url;
+	int rc;
+
+	url = widget_textbox_get_value(screen->widgets.url_f);
+	if (!url || !strlen(url))
+		return 0;
+
+	/* Once we have all the info we need, tell the server */
+	rc = cui_send_retrieve(screen->cui, url);
+
+	if (rc)
+		pb_log("cui_send_retreive failed!\n");
+	else
+		pb_debug("retrieve url sent!\n");
+	return 0;
+}
+
+static void ok_click(void *arg)
+{
+	struct retrieve_screen *screen = arg;
+	if (screen_process_form(screen))
+		/* errors are written to the status line, so we'll need
+		 * to refresh */
+		wrefresh(screen->scr.main_ncw);
+	else
+		screen->exit = true;
+}
+
+static void help_click(void *arg)
+{
+	struct retrieve_screen *screen = arg;
+	screen->show_help = true;
+}
+
+static void cancel_click(void *arg)
+{
+	struct retrieve_screen *screen = arg;
+	screen->exit = true;
+}
+
+static int layout_pair(struct retrieve_screen *screen, int y,
+	struct nc_widget_label *label,
+	struct nc_widget *field)
+{
+	struct nc_widget *label_w = widget_label_base(label);
+	widget_move(label_w, y, screen->label_x);
+	widget_move(field, y, screen->field_x);
+	return max(widget_height(label_w), widget_height(field));
+}
+
+static void retrieve_screen_layout_widgets(struct retrieve_screen *screen)
+{
+	int y = 1;
+
+	/* url field */
+	y += layout_pair(screen, y, screen->widgets.url_l,
+			 widget_textbox_base(screen->widgets.url_f));
+
+	/* ok, help, cancel */
+	y += 1;
+
+	widget_move(widget_button_base(screen->widgets.ok_b),
+		y, screen->field_x);
+	widget_move(widget_button_base(screen->widgets.help_b),
+		y, screen->field_x + 10);
+	widget_move(widget_button_base(screen->widgets.cancel_b),
+		y, screen->field_x + 20);
+}
+
+static void retrieve_screen_widget_focus(struct nc_widget *widget, void *arg)
+{
+	struct retrieve_screen *screen = arg;
+	int w_y, s_max;
+
+	w_y = widget_y(widget) + widget_focus_y(widget);
+	s_max = getmaxy(screen->scr.sub_ncw) - 1;
+
+	if (w_y < screen->scroll_y)
+		screen->scroll_y = w_y;
+
+	else if (w_y + screen->scroll_y + 1 > s_max)
+		screen->scroll_y = 1 + w_y - s_max;
+
+	else
+		return;
+
+	pad_refresh(screen);
+}
+
+static void retrieve_screen_setup_widgets(struct retrieve_screen *screen)
+{
+	struct nc_widgetset *set = screen->widgetset;
+
+	build_assert(sizeof(screen->widgets) / sizeof(struct widget *)
+			== N_FIELDS);
+
+	screen->widgets.url_l = widget_new_label(set, 0, 0,
+			"Configuration URL: ");
+	screen->widgets.url_f = widget_new_textbox(set, 0, 0, 50, NULL);
+
+	screen->widgets.ok_b = widget_new_button(set, 0, 0, 6, "OK",
+			ok_click, screen);
+	screen->widgets.help_b = widget_new_button(set, 0, 0, 6, "Help",
+			help_click, screen);
+	screen->widgets.cancel_b = widget_new_button(set, 0, 0, 6, "Cancel",
+			cancel_click, screen);
+}
+
+
+static void retrieve_screen_draw(struct retrieve_screen *screen)
+{
+	bool repost = false;
+	int height;
+
+	/* No dynamic lists, so the height is just N_FIELDS */
+	height = N_FIELDS;
+	if (!screen->pad || getmaxy(screen->pad) < height) {
+		if (screen->pad)
+			delwin(screen->pad);
+		screen->pad = newpad(height, COLS);
+	}
+
+	if (screen->widgetset) {
+		widgetset_unpost(screen->widgetset);
+		talloc_free(screen->widgetset);
+		repost = true;
+	}
+
+	screen->widgetset = widgetset_create(screen, screen->scr.main_ncw,
+			screen->pad);
+	widgetset_set_widget_focus(screen->widgetset,
+			retrieve_screen_widget_focus, screen);
+
+	retrieve_screen_setup_widgets(screen);
+	retrieve_screen_layout_widgets(screen);
+
+	if (repost)
+		widgetset_post(screen->widgetset);
+}
+
+static int retrieve_screen_destroy(void *arg)
+{
+	struct retrieve_screen *screen = arg;
+	if (screen->pad)
+		delwin(screen->pad);
+	return 0;
+}
+
+struct retrieve_screen *retrieve_screen_init(struct cui *cui,
+		void (*on_exit)(struct cui *))
+{
+	struct retrieve_screen *screen;
+
+	screen = talloc_zero(cui, struct retrieve_screen);
+	talloc_set_destructor(screen, retrieve_screen_destroy);
+
+	screen->cui = cui;
+	screen->on_exit = on_exit;
+	screen->label_x = 2;
+	screen->field_x = 22;
+
+	nc_scr_init(&screen->scr, pb_retrieve_screen_sig, 0,
+		cui, retrieve_screen_process_key,
+		retrieve_screen_post, retrieve_screen_unpost,
+		retrieve_screen_resize);
+
+	screen->scr.frame.ltitle = talloc_strdup(screen,
+			"Petitboot Config Retrieval");
+	screen->scr.frame.rtitle = NULL;
+	screen->scr.frame.help = talloc_strdup(screen,
+			"tab=next, shift+tab=previous, x=exit, h=help");
+	nc_scr_frame_draw(&screen->scr);
+
+	scrollok(screen->scr.sub_ncw, true);
+
+	retrieve_screen_draw(screen);
+
+	return screen;
+}
+
diff --git a/ui/ncurses/nc-retrieve.h b/ui/ncurses/nc-retrieve.h
new file mode 100644
index 0000000..86d6918
--- /dev/null
+++ b/ui/ncurses/nc-retrieve.h
@@ -0,0 +1,31 @@
+/*
+ *  Copyright (C) 2013 IBM Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; version 2 of the License.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _NC_RETRIEVE_H
+#define _NC_RETRIEVE_H
+
+#include "nc-cui.h"
+
+struct retrieve_screen;
+
+struct retrieve_screen *retrieve_screen_init(struct cui *cui,
+                void (*on_exit)(struct cui *));
+
+struct nc_scr *retrieve_screen_scr(struct retrieve_screen *screen);
+void retrieve_screen_update(struct retrieve_screen *screen);
+
+#endif /* defined _NC_RETRIEVE_H */
diff --git a/ui/ncurses/nc-scr.h b/ui/ncurses/nc-scr.h
index 50cce33..f85fb1b 100644
--- a/ui/ncurses/nc-scr.h
+++ b/ui/ncurses/nc-scr.h
@@ -46,7 +46,8 @@ enum pb_nc_sig {
 	pb_boot_editor_sig	= 444,
 	pb_text_screen_sig	= 555,
 	pb_config_screen_sig	= 666,
-	pb_removed_sig		= -777,
+	pb_retrieve_screen_sig	= 777,
+	pb_removed_sig		= -888,
 };
 
 static inline void nc_flush_keys(void)
-- 
1.9.3



More information about the Petitboot mailing list