All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode
@ 2018-02-26 15:53 Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 01/14] shared/shell: Add bt_shell_{noninteractive_}quit Luiz Augusto von Dentz
                   ` (13 more replies)
  0 siblings, 14 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This adds functionally to bt_shell to properly handle non-interactive
mode making all command line tools handle commands given as argument:

>./bluetoothctl power on
[CHG] Controller B8:8A:60:D8:17:D7 Class: 0x002c010c
Changing power on succeded

While on non-interactive mode readline will not be used and only the
command line arguments will be processed, in addition to that there
is now bt_shell_noninteractive_quit which shall be used by the command
handler to quit when it is done with the command execution.

Luiz Augusto von Dentz (14):
  shared/shell: Add bt_shell_{noninteractive_}quit
  shared/shell: Fix not reseting optind
  shared/shell: Fix timeout parameter
  shared/shell: Do not quit immediatelly on noninteractive mode
  shared/shell: Fix not handling sort options
  shared/shell: Disable bt_shell_prompt_input in noninteractive mode
  shared/shell: Disable readline while in noninteractive mode
  sharead/mainloop-glib: Fix mainloop_exit*
  shared/mainloop-glib: Fix calling g_main_loop_quit with NULL
  shared/shell: Allow executing submenu commands
  client: Call bt_shell_noninteractive_quit when done with command
  shared/shell: Add bt_shell_usage
  shared/shell: Fix parsing of mandatory arguments
  tools/btmgmt: Port to use bt_shell

 client/advertising.c       |   84 ++-
 client/gatt.c              |  113 ++--
 client/main.c              |  153 +++--
 src/shared/mainloop-glib.c |    5 +
 src/shared/shell.c         |  130 +++-
 src/shared/shell.h         |    4 +
 tools/btmgmt.c             | 1560 ++++++++++++++++----------------------------
 7 files changed, 905 insertions(+), 1144 deletions(-)

-- 
2.14.3


^ permalink raw reply	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 01/14] shared/shell: Add bt_shell_{noninteractive_}quit
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 02/14] shared/shell: Fix not reseting optind Luiz Augusto von Dentz
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

The functions can be used to tell the shell to stop running.
---
 src/shared/shell.c | 16 ++++++++++++++++
 src/shared/shell.h |  3 +++
 2 files changed, 19 insertions(+)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index 6cc797cdb..9ecb4c7be 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -866,6 +866,22 @@ void bt_shell_run(void)
 	data.init = false;
 }
 
+void bt_shell_quit(int status)
+{
+	if (status == EXIT_SUCCESS)
+		mainloop_exit_success();
+	else
+		mainloop_exit_failure();
+}
+
+void bt_shell_noninteractive_quit(int status)
+{
+	if (!data.mode || data.timeout)
+		return;
+
+	bt_shell_quit(status);
+}
+
 bool bt_shell_set_menu(const struct bt_shell_menu *menu)
 {
 	if (!menu)
diff --git a/src/shared/shell.h b/src/shared/shell.h
index 359629896..10747c955 100644
--- a/src/shared/shell.h
+++ b/src/shared/shell.h
@@ -68,6 +68,9 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt);
 
 void bt_shell_run(void);
 
+void bt_shell_quit(int status);
+void bt_shell_noninteractive_quit(int status);
+
 bool bt_shell_set_menu(const struct bt_shell_menu *menu);
 
 bool bt_shell_add_submenu(const struct bt_shell_menu *menu);
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 02/14] shared/shell: Fix not reseting optind
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 01/14] shared/shell: Add bt_shell_{noninteractive_}quit Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 03/14] shared/shell: Fix timeout parameter Luiz Augusto von Dentz
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Not reseting optind may crash the tool if getopt and variants are
called a second time.
---
 src/shared/shell.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index 9ecb4c7be..0653c0ea1 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -817,6 +817,7 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt)
 
 	data.argc = argc - optind;
 	data.argv = argv + optind;
+	optind = 0;
 	data.mode = (data.argc > 0);
 
 	if (data.mode)
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 03/14] shared/shell: Fix timeout parameter
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 01/14] shared/shell: Add bt_shell_{noninteractive_}quit Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 02/14] shared/shell: Fix not reseting optind Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 04/14] shared/shell: Do not quit immediatelly on noninteractive mode Luiz Augusto von Dentz
                   ` (10 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Fix help message and add proper optstr modifier so both -t/--timeout
work properly.
---
 src/shared/shell.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index 0653c0ea1..e82307d6f 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -768,7 +768,7 @@ static void usage(int argc, char **argv, const struct bt_shell_opt *opt)
 	for (i = 0; opt && opt->options[i].name; i++)
 		printf("\t--%s \t%s\n", opt->options[i].name, opt->help[i]);
 
-	printf("\t--timeout \t\tTimeout in seconds for non-interactive mode\n"
+	printf("\t--timeout \tTimeout in seconds for non-interactive mode\n"
 		"\t--version \tDisplay version\n"
 		"\t--help \t\tDisplay help\n");
 }
@@ -787,9 +787,9 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt)
 	if (opt) {
 		memcpy(options + offset, opt->options,
 				sizeof(struct option) * opt->optno);
-		snprintf(optstr, sizeof(optstr), "+hv%s", opt->optstr);
+		snprintf(optstr, sizeof(optstr), "+hvt:%s", opt->optstr);
 	} else
-		snprintf(optstr, sizeof(optstr), "+hv");
+		snprintf(optstr, sizeof(optstr), "+hvt:");
 
 	while ((c = getopt_long(argc, argv, optstr, options, &index)) != -1) {
 		switch (c) {
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 04/14] shared/shell: Do not quit immediatelly on noninteractive mode
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (2 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 03/14] shared/shell: Fix timeout parameter Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 05/14] shared/shell: Fix not handling sort options Luiz Augusto von Dentz
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

The command handler shall be able to tell when it is done by calling
bt_shell_noninteractive_quit.
---
 src/shared/shell.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index e82307d6f..eae4ffbdd 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -951,10 +951,7 @@ bool bt_shell_attach(int fd)
 	if (data.mode) {
 		shell_exec(data.argc, data.argv);
 
-		if (!data.timeout) {
-			bt_shell_detach();
-			mainloop_quit();
-		} else
+		if (data.timeout)
 			timeout_add(data.timeout * 1000, shell_quit, NULL,
 								NULL);
 	}
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 05/14] shared/shell: Fix not handling sort options
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (3 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 04/14] shared/shell: Do not quit immediatelly on noninteractive mode Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 06/14] shared/shell: Disable bt_shell_prompt_input in noninteractive mode Luiz Augusto von Dentz
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

getopt_long index is only valid for long options.
---
 src/shared/shell.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index eae4ffbdd..7f726c2dd 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -775,7 +775,7 @@ static void usage(int argc, char **argv, const struct bt_shell_opt *opt)
 
 void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt)
 {
-	int c, index = 0;
+	int c, index = -1;
 	struct option options[256];
 	char optstr[256];
 	size_t offset;
@@ -805,6 +805,13 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt)
 			data.timeout = atoi(optarg);
 			break;
 		default:
+			if (index < 0) {
+				for (index = 0; options[index].val; index++) {
+					if (c == options[index].val)
+						break;
+				}
+			}
+
 			if (c != opt->options[index - offset].val) {
 				usage(argc, argv, opt);
 				exit(EXIT_SUCCESS);
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 06/14] shared/shell: Disable bt_shell_prompt_input in noninteractive mode
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (4 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 05/14] shared/shell: Fix not handling sort options Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 07/14] shared/shell: Disable readline while " Luiz Augusto von Dentz
                   ` (7 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

Only the input given as argument shall be processed, all the rest shall
be ignored.
---
 src/shared/shell.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index 7f726c2dd..bf07d034f 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -417,6 +417,9 @@ void bt_shell_hexdump(const unsigned char *buf, size_t len)
 void bt_shell_prompt_input(const char *label, const char *msg,
 			bt_shell_prompt_input_func func, void *user_data)
 {
+	if (!data.init || data.mode)
+		return;
+
 	/* Normal use should not prompt for user input to the value a second
 	 * time before it releases the prompt, but we take a safe action. */
 	if (data.saved_prompt)
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 07/14] shared/shell: Disable readline while in noninteractive mode
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (5 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 06/14] shared/shell: Disable bt_shell_prompt_input in noninteractive mode Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 08/14] sharead/mainloop-glib: Fix mainloop_exit* Luiz Augusto von Dentz
                   ` (6 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

User shall not be able to interact with the shell while in
noninteractive mode.
---
 src/shared/shell.c | 25 +++++++++++++++++++++----
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index bf07d034f..b5556a288 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -381,6 +381,13 @@ void bt_shell_printf(const char *fmt, ...)
 	if (!data.input)
 		return;
 
+	if (data.mode) {
+		va_start(args, fmt);
+		vprintf(fmt, args);
+		va_end(args);
+		return;
+	}
+
 	save_input = !RL_ISSTATE(RL_STATE_DONE);
 
 	if (save_input) {
@@ -683,7 +690,7 @@ static bool signal_read(struct io *io, void *user_data)
 
 	switch (si.ssi_signo) {
 	case SIGINT:
-		if (data.input) {
+		if (data.input && !data.mode) {
 			rl_replace_line("", 0);
 			rl_crlf();
 			rl_on_new_line();
@@ -701,8 +708,10 @@ static bool signal_read(struct io *io, void *user_data)
 		/* fall through */
 	case SIGTERM:
 		if (!terminated) {
-			rl_replace_line("", 0);
-			rl_crlf();
+			if (!data.mode) {
+				rl_replace_line("", 0);
+				rl_crlf();
+			}
 			mainloop_quit();
 		}
 
@@ -745,6 +754,9 @@ static struct io *setup_signalfd(void)
 
 static void rl_init(void)
 {
+	if (data.mode)
+		return;
+
 	setlinebuf(stdout);
 	rl_attempted_completion_function = shell_completion;
 
@@ -842,6 +854,9 @@ void bt_shell_init(int argc, char **argv, const struct bt_shell_opt *opt)
 
 static void rl_cleanup(void)
 {
+	if (data.mode)
+		return;
+
 	rl_message("");
 	rl_callback_handler_remove();
 }
@@ -953,7 +968,9 @@ bool bt_shell_attach(int fd)
 
 	io = io_new(fd);
 
-	io_set_read_handler(io, input_read, NULL, NULL);
+	if (!data.mode)
+		io_set_read_handler(io, input_read, NULL, NULL);
+
 	io_set_disconnect_handler(io, io_hup, NULL, NULL);
 
 	data.input = io;
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 08/14] sharead/mainloop-glib: Fix mainloop_exit*
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (6 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 07/14] shared/shell: Disable readline while " Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 09/14] shared/mainloop-glib: Fix calling g_main_loop_quit with NULL Luiz Augusto von Dentz
                   ` (5 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

These function shall cause the mainloop to quit.
---
 src/shared/mainloop-glib.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/shared/mainloop-glib.c b/src/shared/mainloop-glib.c
index 14d43207a..1bbac5d11 100644
--- a/src/shared/mainloop-glib.c
+++ b/src/shared/mainloop-glib.c
@@ -53,11 +53,13 @@ void mainloop_quit(void)
 void mainloop_exit_success(void)
 {
 	exit_status = EXIT_SUCCESS;
+	mainloop_quit();
 }
 
 void mainloop_exit_failure(void)
 {
 	exit_status = EXIT_FAILURE;
+	mainloop_quit();
 }
 
 int mainloop_run(void)
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 09/14] shared/mainloop-glib: Fix calling g_main_loop_quit with NULL
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (7 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 08/14] sharead/mainloop-glib: Fix mainloop_exit* Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 10/14] shared/shell: Allow executing submenu commands Luiz Augusto von Dentz
                   ` (4 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This produces warnings such as:

(process:5122): GLib-CRITICAL **: g_main_loop_quit: assertion 'loop != NULL' failed
---
 src/shared/mainloop-glib.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/shared/mainloop-glib.c b/src/shared/mainloop-glib.c
index 1bbac5d11..8436969bb 100644
--- a/src/shared/mainloop-glib.c
+++ b/src/shared/mainloop-glib.c
@@ -47,6 +47,9 @@ void mainloop_init(void)
 
 void mainloop_quit(void)
 {
+	if (!main_loop)
+		return;
+
 	g_main_loop_quit(main_loop);
 }
 
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 10/14] shared/shell: Allow executing submenu commands
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (8 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 09/14] shared/mainloop-glib: Fix calling g_main_loop_quit with NULL Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 11/14] client: Call bt_shell_noninteractive_quit when done with command Luiz Augusto von Dentz
                   ` (3 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This makes it possible to execute submenu commands directly from the
main menu by using the format <submenu>.<command>:

[bluetooth]# advertise.uuids 0x1820
[bluetooth]# advertise.name blah
[bluetooth]# advertise on
Advertising object registered
UUID: Internet Protocol Support(0x1820)
Tx Power: off
LocalName: blah
Apperance: off
---
 src/shared/shell.c | 34 ++++++++++++++++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index b5556a288..cd46532fe 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -356,6 +356,34 @@ static int menu_exec(const struct bt_shell_menu_entry *entry,
 	return -ENOENT;
 }
 
+static int submenu_exec(int argc, char *argv[])
+{
+	char *name;
+	int len, tlen;
+	const struct bt_shell_menu *submenu;
+
+	if (data.menu != data.main)
+		return -ENOENT;
+
+	name = strchr(argv[0], '.');
+	if (!name)
+		return -ENOENT;
+
+	tlen = strlen(argv[0]);
+	len = name - argv[0];
+	name[0] = '\0';
+
+	submenu = find_menu(argv[0]);
+	if (!submenu)
+		return -ENOENT;
+
+	/* Replace submenu.command with command */
+	memmove(argv[0], argv[0] + len + 1, tlen - len - 1);
+	memset(argv[0] + tlen - len - 1, 0, len + 1);
+
+	return menu_exec(submenu->entries, argc, argv);
+}
+
 static void shell_exec(int argc, char *argv[])
 {
 	if (!data.menu || !argv[0])
@@ -363,10 +391,12 @@ static void shell_exec(int argc, char *argv[])
 
 	if (menu_exec(default_menu, argc, argv) == -ENOENT) {
 		if (menu_exec(data.menu->entries, argc, argv) == -ENOENT) {
-			print_text(COLOR_HIGHLIGHT,
+			if (submenu_exec(argc, argv) == -ENOENT) {
+				print_text(COLOR_HIGHLIGHT,
 					"Invalid command in menu %s: %s",
 					data.menu->name , argv[0]);
-			shell_print_help();
+				shell_print_help();
+			}
 		}
 	}
 }
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 11/14] client: Call bt_shell_noninteractive_quit when done with command
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (9 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 10/14] shared/shell: Allow executing submenu commands Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 12/14] shared/shell: Add bt_shell_usage Luiz Augusto von Dentz
                   ` (2 subsequent siblings)
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

This ensures that the commands don't stay hanging since bt_shell no
longer quits immediatelly after executing a command.
---
 client/advertising.c |  84 +++++++++++++++++++---------
 client/gatt.c        | 113 ++++++++++++++++++++++++-------------
 client/main.c        | 153 ++++++++++++++++++++++++++++++++++-----------------
 3 files changed, 235 insertions(+), 115 deletions(-)

diff --git a/client/advertising.c b/client/advertising.c
index 3cfc318ba..2be96483a 100644
--- a/client/advertising.c
+++ b/client/advertising.c
@@ -190,6 +190,7 @@ static void register_reply(DBusMessage *message, void *user_data)
 		ad.registered = true;
 		bt_shell_printf("Advertising object registered\n");
 		print_ad();
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	} else {
 		bt_shell_printf("Failed to register advertisement: %s\n", error.name);
 		dbus_error_free(&error);
@@ -197,6 +198,7 @@ static void register_reply(DBusMessage *message, void *user_data)
 		if (g_dbus_unregister_interface(conn, AD_PATH,
 						AD_IFACE) == FALSE)
 			bt_shell_printf("Failed to unregister advertising object\n");
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -441,7 +443,7 @@ void ad_register(DBusConnection *conn, GDBusProxy *manager, const char *type)
 {
 	if (ad.registered) {
 		bt_shell_printf("Advertisement is already registered\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	g_free(ad.type);
@@ -450,14 +452,14 @@ void ad_register(DBusConnection *conn, GDBusProxy *manager, const char *type)
 	if (g_dbus_register_interface(conn, AD_PATH, AD_IFACE, ad_methods,
 					NULL, ad_props, NULL, NULL) == FALSE) {
 		bt_shell_printf("Failed to register advertising object\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (g_dbus_proxy_method_call(manager, "RegisterAdvertisement",
 					register_setup, register_reply,
 					conn, NULL) == FALSE) {
 		bt_shell_printf("Failed to register advertising\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -481,10 +483,12 @@ static void unregister_reply(DBusMessage *message, void *user_data)
 		if (g_dbus_unregister_interface(conn, AD_PATH,
 							AD_IFACE) == FALSE)
 			bt_shell_printf("Failed to unregister advertising object\n");
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	} else {
 		bt_shell_printf("Failed to unregister advertisement: %s\n",
 								error.name);
 		dbus_error_free(&error);
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -494,7 +498,7 @@ void ad_unregister(DBusConnection *conn, GDBusProxy *manager)
 		ad_release(conn);
 
 	if (!ad.registered)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	g_free(ad.type);
 	ad.type = NULL;
@@ -503,7 +507,7 @@ void ad_unregister(DBusConnection *conn, GDBusProxy *manager)
 					unregister_setup, unregister_reply,
 					conn, NULL) == FALSE) {
 		bt_shell_printf("Failed to unregister advertisement method\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -518,7 +522,7 @@ void ad_advertise_uuids(DBusConnection *conn, int argc, char *argv[])
 {
 	if (argc < 2 || !strlen(argv[1])) {
 		print_ad_uuids();
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	}
 
 	ad_clear_uuids();
@@ -526,27 +530,33 @@ void ad_advertise_uuids(DBusConnection *conn, int argc, char *argv[])
 	ad.uuids = g_strdupv(&argv[1]);
 	if (!ad.uuids) {
 		bt_shell_printf("Failed to parse input\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	ad.uuids_len = g_strv_length(ad.uuids);
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "ServiceUUIDs");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_disable_uuids(DBusConnection *conn)
 {
 	if (!ad.uuids)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	ad_clear_uuids();
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "ServiceUUIDs");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void ad_clear_service(void)
 {
 	g_free(ad.service.uuid);
 	memset(&ad.service, 0, sizeof(ad.service));
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_advertise_service(DBusConnection *conn, int argc, char *argv[])
@@ -560,7 +570,7 @@ void ad_advertise_service(DBusConnection *conn, int argc, char *argv[])
 			bt_shell_hexdump(ad.service.data.data,
 						ad.service.data.len);
 		}
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	}
 
 	ad_clear_service();
@@ -590,20 +600,26 @@ void ad_advertise_service(DBusConnection *conn, int argc, char *argv[])
 	}
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "ServiceData");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_disable_service(DBusConnection *conn)
 {
 	if (!ad.service.uuid)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	ad_clear_service();
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "ServiceData");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void ad_clear_manufacturer(void)
 {
 	memset(&ad.manufacturer, 0, sizeof(ad.manufacturer));
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_advertise_manufacturer(DBusConnection *conn, int argc, char *argv[])
@@ -621,7 +637,7 @@ void ad_advertise_manufacturer(DBusConnection *conn, int argc, char *argv[])
 						ad.manufacturer.data.len);
 		}
 
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	}
 
 	ad_clear_manufacturer();
@@ -629,7 +645,7 @@ void ad_advertise_manufacturer(DBusConnection *conn, int argc, char *argv[])
 	val = strtol(argv[1], &endptr, 0);
 	if (!endptr || *endptr != '\0' || val > UINT16_MAX) {
 		bt_shell_printf("Invalid manufacture id\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	ad.manufacturer.id = val;
@@ -639,14 +655,14 @@ void ad_advertise_manufacturer(DBusConnection *conn, int argc, char *argv[])
 		if (i >= G_N_ELEMENTS(data->data)) {
 			bt_shell_printf("Too much data\n");
 			ad_clear_manufacturer();
-			return;
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 
 		val = strtol(argv[i], &endptr, 0);
 		if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
 			bt_shell_printf("Invalid value at index %d\n", i);
 			ad_clear_manufacturer();
-			return;
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 
 		data->data[data->len] = val;
@@ -655,23 +671,27 @@ void ad_advertise_manufacturer(DBusConnection *conn, int argc, char *argv[])
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE,
 							"ManufacturerData");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_disable_manufacturer(DBusConnection *conn)
 {
 	if (!ad.manufacturer.id && !ad.manufacturer.data.len)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	ad_clear_manufacturer();
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE,
 							"ManufacturerData");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_advertise_tx_power(DBusConnection *conn, dbus_bool_t *value)
 {
 	if (!value) {
 		bt_shell_printf("Tx Power: %s\n", ad.tx_power ? "on" : "off");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	}
 
 	if (ad.tx_power == *value)
@@ -680,12 +700,14 @@ void ad_advertise_tx_power(DBusConnection *conn, dbus_bool_t *value)
 	ad.tx_power = *value;
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_advertise_name(DBusConnection *conn, bool value)
 {
 	if (ad.name == value)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	ad.name = value;
 
@@ -695,6 +717,8 @@ void ad_advertise_name(DBusConnection *conn, bool value)
 	}
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_advertise_local_name(DBusConnection *conn, const char *name)
@@ -705,7 +729,7 @@ void ad_advertise_local_name(DBusConnection *conn, const char *name)
 		else
 			bt_shell_printf("Name: %s\n", ad.name ? "on" : "off");
 
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	}
 
 	if (ad.local_name && !strcmp(name, ad.local_name))
@@ -715,12 +739,14 @@ void ad_advertise_local_name(DBusConnection *conn, const char *name)
 	ad.local_name = strdup(name);
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "LocalName");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_advertise_appearance(DBusConnection *conn, bool value)
 {
 	if (ad.appearance == value)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	ad.appearance = value;
 
@@ -728,6 +754,8 @@ void ad_advertise_appearance(DBusConnection *conn, bool value)
 		ad.local_appearance = UINT16_MAX;
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Includes");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_advertise_local_appearance(DBusConnection *conn, long int *value)
@@ -741,15 +769,17 @@ void ad_advertise_local_appearance(DBusConnection *conn, long int *value)
 			bt_shell_printf("Apperance: %s\n",
 					ad.appearance ? "on" : "off");
 
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	}
 
 	if (ad.local_appearance == *value)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	ad.local_appearance = *value;
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Appearance");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_advertise_duration(DBusConnection *conn, long int *value)
@@ -757,15 +787,17 @@ void ad_advertise_duration(DBusConnection *conn, long int *value)
 	if (!value) {
 		if (ad.duration)
 			bt_shell_printf("Duration: %u sec\n", ad.duration);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	}
 
 	if (ad.duration == *value)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	ad.duration = *value;
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Duration");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void ad_advertise_timeout(DBusConnection *conn, long int *value)
@@ -773,13 +805,15 @@ void ad_advertise_timeout(DBusConnection *conn, long int *value)
 	if (!value) {
 		if (ad.timeout)
 			bt_shell_printf("Timeout: %u sec\n", ad.timeout);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 	}
 
 	if (ad.timeout == *value)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	ad.timeout = *value;
 
 	g_dbus_emit_property_changed(conn, AD_PATH, AD_IFACE, "Timeout");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
diff --git a/client/gatt.c b/client/gatt.c
index b640b6eb9..91cfb019f 100644
--- a/client/gatt.c
+++ b/client/gatt.c
@@ -367,6 +367,7 @@ static void list_attributes(const char *path, GList *source)
 void gatt_list_attributes(const char *path)
 {
 	list_attributes(path, services);
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static GDBusProxy *select_attribute(const char *path)
@@ -488,14 +489,14 @@ static void read_reply(DBusMessage *message, void *user_data)
 	if (dbus_set_error_from_message(&error, message) == TRUE) {
 		bt_shell_printf("Failed to read: %s\n", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	dbus_message_iter_init(message, &iter);
 
 	if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
 		bt_shell_printf("Invalid response to read\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	dbus_message_iter_recurse(&iter, &array);
@@ -503,10 +504,12 @@ static void read_reply(DBusMessage *message, void *user_data)
 
 	if (len < 0) {
 		bt_shell_printf("Unable to parse value\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_hexdump(value, len);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void read_setup(DBusMessageIter *iter, void *user_data)
@@ -528,7 +531,7 @@ static void read_attribute(GDBusProxy *proxy)
 	if (g_dbus_proxy_method_call(proxy, "ReadValue", read_setup, read_reply,
 							NULL, NULL) == FALSE) {
 		bt_shell_printf("Failed to read\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Attempting to read %s\n", g_dbus_proxy_get_path(proxy));
@@ -547,6 +550,7 @@ void gatt_read_attribute(GDBusProxy *proxy)
 
 	bt_shell_printf("Unable to read attribute %s\n",
 						g_dbus_proxy_get_path(proxy));
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static void write_reply(DBusMessage *message, void *user_data)
@@ -558,8 +562,10 @@ static void write_reply(DBusMessage *message, void *user_data)
 	if (dbus_set_error_from_message(&error, message) == TRUE) {
 		bt_shell_printf("Failed to write: %s\n", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void write_setup(DBusMessageIter *iter, void *user_data)
@@ -598,13 +604,13 @@ static void write_attribute(GDBusProxy *proxy, char *arg)
 
 		if (i >= G_N_ELEMENTS(value)) {
 			bt_shell_printf("Too much data\n");
-			return;
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 
 		val = strtol(entry, &endptr, 0);
 		if (!endptr || *endptr != '\0' || val > UINT8_MAX) {
 			bt_shell_printf("Invalid value at index %d\n", i);
-			return;
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 
 		value[i] = val;
@@ -619,7 +625,7 @@ static void write_attribute(GDBusProxy *proxy, char *arg)
 						io_get_fd(write_io.io));
 		if (io_send(write_io.io, &iov, 1) < 0) {
 			bt_shell_printf("Failed to write: %s", strerror(errno));
-			return;
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 		return;
 	}
@@ -627,7 +633,7 @@ static void write_attribute(GDBusProxy *proxy, char *arg)
 	if (g_dbus_proxy_method_call(proxy, "WriteValue", write_setup,
 					write_reply, &iov, NULL) == FALSE) {
 		bt_shell_printf("Failed to write\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Attempting to write %s\n", g_dbus_proxy_get_path(proxy));
@@ -646,6 +652,8 @@ void gatt_write_attribute(GDBusProxy *proxy, const char *arg)
 
 	bt_shell_printf("Unable to write attribute %s\n",
 						g_dbus_proxy_get_path(proxy));
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static bool pipe_read(struct io *io, void *user_data)
@@ -729,7 +737,7 @@ static void acquire_write_reply(DBusMessage *message, void *user_data)
 		bt_shell_printf("Failed to acquire write: %s\n", error.name);
 		dbus_error_free(&error);
 		write_io.proxy = NULL;
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (write_io.io)
@@ -739,12 +747,13 @@ static void acquire_write_reply(DBusMessage *message, void *user_data)
 					DBUS_TYPE_UINT16, &write_io.mtu,
 					DBUS_TYPE_INVALID) == false)) {
 		bt_shell_printf("Invalid AcquireWrite response\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("AcquireWrite success: fd %d MTU %u\n", fd, write_io.mtu);
 
 	write_io.io = pipe_io_new(fd, NULL);
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void acquire_setup(DBusMessageIter *iter, void *user_data)
@@ -769,13 +778,13 @@ void gatt_acquire_write(GDBusProxy *proxy, const char *arg)
 	if (strcmp(iface, "org.bluez.GattCharacteristic1")) {
 		bt_shell_printf("Unable to acquire write: %s not a characteristic\n",
 						g_dbus_proxy_get_path(proxy));
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (g_dbus_proxy_method_call(proxy, "AcquireWrite", acquire_setup,
 				acquire_write_reply, NULL, NULL) == FALSE) {
 		bt_shell_printf("Failed to AcquireWrite\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	write_io.proxy = proxy;
@@ -785,10 +794,12 @@ void gatt_release_write(GDBusProxy *proxy, const char *arg)
 {
 	if (proxy != write_io.proxy || !write_io.io) {
 		bt_shell_printf("Write not acquired\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	write_io_destroy();
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void acquire_notify_reply(DBusMessage *message, void *user_data)
@@ -802,7 +813,7 @@ static void acquire_notify_reply(DBusMessage *message, void *user_data)
 		bt_shell_printf("Failed to acquire notify: %s\n", error.name);
 		dbus_error_free(&error);
 		write_io.proxy = NULL;
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (notify_io.io) {
@@ -816,12 +827,14 @@ static void acquire_notify_reply(DBusMessage *message, void *user_data)
 					DBUS_TYPE_UINT16, &notify_io.mtu,
 					DBUS_TYPE_INVALID) == false)) {
 		bt_shell_printf("Invalid AcquireNotify response\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("AcquireNotify success: fd %d MTU %u\n", fd, notify_io.mtu);
 
 	notify_io.io = pipe_io_new(fd, NULL);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void gatt_acquire_notify(GDBusProxy *proxy, const char *arg)
@@ -832,13 +845,13 @@ void gatt_acquire_notify(GDBusProxy *proxy, const char *arg)
 	if (strcmp(iface, "org.bluez.GattCharacteristic1")) {
 		bt_shell_printf("Unable to acquire notify: %s not a characteristic\n",
 						g_dbus_proxy_get_path(proxy));
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (g_dbus_proxy_method_call(proxy, "AcquireNotify", acquire_setup,
 				acquire_notify_reply, NULL, NULL) == FALSE) {
 		bt_shell_printf("Failed to AcquireNotify\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	notify_io.proxy = proxy;
@@ -848,10 +861,12 @@ void gatt_release_notify(GDBusProxy *proxy, const char *arg)
 {
 	if (proxy != notify_io.proxy || !notify_io.io) {
 		bt_shell_printf("Notify not acquired\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	notify_io_destroy();
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void notify_reply(DBusMessage *message, void *user_data)
@@ -865,10 +880,12 @@ static void notify_reply(DBusMessage *message, void *user_data)
 		bt_shell_printf("Failed to %s notify: %s\n",
 				enable ? "start" : "stop", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Notify %s\n", enable == TRUE ? "started" : "stopped");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void notify_attribute(GDBusProxy *proxy, bool enable)
@@ -883,8 +900,10 @@ static void notify_attribute(GDBusProxy *proxy, bool enable)
 	if (g_dbus_proxy_method_call(proxy, method, NULL, notify_reply,
 				GUINT_TO_POINTER(enable), NULL) == FALSE) {
 		bt_shell_printf("Failed to %s notify\n", enable ? "start" : "stop");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void gatt_notify_attribute(GDBusProxy *proxy, bool enable)
@@ -899,6 +918,8 @@ void gatt_notify_attribute(GDBusProxy *proxy, bool enable)
 
 	bt_shell_printf("Unable to notify attribute %s\n",
 						g_dbus_proxy_get_path(proxy));
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static void register_app_setup(DBusMessageIter *iter, void *user_data)
@@ -927,10 +948,12 @@ static void register_app_reply(DBusMessage *message, void *user_data)
 	if (dbus_set_error_from_message(&error, message) == TRUE) {
 		bt_shell_printf("Failed to register application: %s\n", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Application registered\n");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 void gatt_add_manager(GDBusProxy *proxy)
@@ -997,7 +1020,7 @@ void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy,
 	l = g_list_find_custom(managers, proxy, match_proxy);
 	if (!l) {
 		bt_shell_printf("Unable to find GattManager proxy\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	for (i = 0; i < argc; i++)
@@ -1009,7 +1032,7 @@ void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy,
 						NULL, properties, NULL,
 						NULL) == FALSE) {
 			bt_shell_printf("Failed to register application object\n");
-			return;
+			return bt_shell_noninteractive_quit(EXIT_FAILURE);
 		}
 	}
 
@@ -1019,7 +1042,7 @@ void gatt_register_app(DBusConnection *conn, GDBusProxy *proxy,
 						NULL) == FALSE) {
 		bt_shell_printf("Failed register application\n");
 		g_dbus_unregister_interface(conn, APP_PATH, PROFILE_INTERFACE);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -1033,18 +1056,20 @@ static void unregister_app_reply(DBusMessage *message, void *user_data)
 	if (dbus_set_error_from_message(&error, message) == TRUE) {
 		bt_shell_printf("Failed to unregister application: %s\n", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Application unregistered\n");
 
 	if (!uuids)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	g_list_free_full(uuids, g_free);
 	uuids = NULL;
 
 	g_dbus_unregister_interface(conn, APP_PATH, PROFILE_INTERFACE);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void unregister_app_setup(DBusMessageIter *iter, void *user_data)
@@ -1061,7 +1086,7 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
 	l = g_list_find_custom(managers, proxy, match_proxy);
 	if (!l) {
 		bt_shell_printf("Unable to find GattManager proxy\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (g_dbus_proxy_method_call(l->data, "UnregisterApplication",
@@ -1069,7 +1094,7 @@ void gatt_unregister_app(DBusConnection *conn, GDBusProxy *proxy)
 						unregister_app_reply, conn,
 						NULL) == FALSE) {
 		bt_shell_printf("Failed unregister profile\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -1190,7 +1215,7 @@ void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
 					service_free) == FALSE) {
 		bt_shell_printf("Failed to register service object\n");
 		service_free(service);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	print_service(service, COLORED_NEW);
@@ -1199,6 +1224,8 @@ void gatt_register_service(DBusConnection *conn, GDBusProxy *proxy,
 
 	bt_shell_prompt_input(service->path, "Primary (yes/no):", service_set_primary,
 			service);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static struct service *service_find(const char *pattern)
@@ -1228,7 +1255,7 @@ void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
 	service = service_find(argv[1]);
 	if (!service) {
 		bt_shell_printf("Failed to unregister service object\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	local_services = g_list_remove(local_services, service);
@@ -1237,6 +1264,8 @@ void gatt_unregister_service(DBusConnection *conn, GDBusProxy *proxy,
 
 	g_dbus_unregister_interface(service->conn, service->path,
 						SERVICE_INTERFACE);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static gboolean chrc_get_uuid(const GDBusPropertyTable *property,
@@ -1672,7 +1701,7 @@ void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy,
 
 	if (!local_services) {
 		bt_shell_printf("No service registered\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	service = g_list_last(local_services)->data;
@@ -1688,7 +1717,7 @@ void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy,
 					chrc, chrc_free) == FALSE) {
 		bt_shell_printf("Failed to register characteristic object\n");
 		chrc_free(chrc);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	service->chrcs = g_list_append(service->chrcs, chrc);
@@ -1696,6 +1725,8 @@ void gatt_register_chrc(DBusConnection *conn, GDBusProxy *proxy,
 	print_chrc(chrc, COLORED_NEW);
 
 	bt_shell_prompt_input(chrc->path, "Enter value:", chrc_set_value, chrc);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static struct chrc *chrc_find(const char *pattern)
@@ -1731,12 +1762,14 @@ void gatt_unregister_chrc(DBusConnection *conn, GDBusProxy *proxy,
 	chrc = chrc_find(argv[1]);
 	if (!chrc) {
 		bt_shell_printf("Failed to unregister characteristic object\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	chrc->service->chrcs = g_list_remove(chrc->service->chrcs, chrc);
 
 	chrc_unregister(chrc);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static DBusMessage *desc_read_value(DBusConnection *conn, DBusMessage *msg,
@@ -1859,14 +1892,14 @@ void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy,
 
 	if (!local_services) {
 		bt_shell_printf("No service registered\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	service = g_list_last(local_services)->data;
 
 	if (!service->chrcs) {
 		bt_shell_printf("No characteristic registered\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	desc = g_new0(struct desc, 1);
@@ -1880,7 +1913,7 @@ void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy,
 					desc, desc_free) == FALSE) {
 		bt_shell_printf("Failed to register descriptor object\n");
 		desc_free(desc);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	desc->chrc->descs = g_list_append(desc->chrc->descs, desc);
@@ -1888,6 +1921,8 @@ void gatt_register_desc(DBusConnection *conn, GDBusProxy *proxy,
 	print_desc(desc, COLORED_NEW);
 
 	bt_shell_prompt_input(desc->path, "Enter value:", desc_set_value, desc);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static struct desc *desc_find(const char *pattern)
@@ -1928,10 +1963,12 @@ void gatt_unregister_desc(DBusConnection *conn, GDBusProxy *proxy,
 	desc = desc_find(argv[1]);
 	if (!desc) {
 		bt_shell_printf("Failed to unregister descriptor object\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	desc->chrc->descs = g_list_remove(desc->chrc->descs, desc);
 
 	desc_unregister(desc);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
diff --git a/client/main.c b/client/main.c
index 962f3383b..85c1889fd 100644
--- a/client/main.c
+++ b/client/main.c
@@ -827,6 +827,8 @@ static void cmd_list(int argc, char *argv[])
 		struct adapter *adapter = list->data;
 		print_adapter(adapter->proxy, NULL);
 	}
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_show(int argc, char *argv[])
@@ -852,7 +854,7 @@ static void cmd_show(int argc, char *argv[])
 	}
 
 	if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	dbus_message_iter_get_basic(&iter, &address);
 
@@ -875,6 +877,8 @@ static void cmd_show(int argc, char *argv[])
 	print_uuids(proxy);
 	print_property(proxy, "Modalias");
 	print_property(proxy, "Discovering");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_select(int argc, char *argv[])
@@ -884,14 +888,16 @@ static void cmd_select(int argc, char *argv[])
 	adapter = find_ctrl_by_address(ctrl_list, argv[1]);
 	if (!adapter) {
 		bt_shell_printf("Controller %s not available\n", argv[1]);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (default_ctrl && default_ctrl->proxy == adapter->proxy)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	default_ctrl = adapter;
 	print_adapter(adapter->proxy, NULL);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_devices(int argc, char *argv[])
@@ -899,13 +905,15 @@ static void cmd_devices(int argc, char *argv[])
 	GList *ll;
 
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	for (ll = g_list_first(default_ctrl->devices);
 			ll; ll = g_list_next(ll)) {
 		GDBusProxy *proxy = ll->data;
 		print_device(proxy, NULL);
 	}
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_paired_devices(int argc, char *argv[])
@@ -913,7 +921,7 @@ static void cmd_paired_devices(int argc, char *argv[])
 	GList *ll;
 
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 
 	for (ll = g_list_first(default_ctrl->devices);
 			ll; ll = g_list_next(ll)) {
@@ -930,16 +938,21 @@ static void cmd_paired_devices(int argc, char *argv[])
 
 		print_device(proxy, NULL);
 	}
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void generic_callback(const DBusError *error, void *user_data)
 {
 	char *str = user_data;
 
-	if (dbus_error_is_set(error))
+	if (dbus_error_is_set(error)) {
 		bt_shell_printf("Failed to set %s: %s\n", str, error->name);
-	else
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
+	} else {
 		bt_shell_printf("Changing %s succeeded\n", str);
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+	}
 }
 
 static void cmd_system_alias(int argc, char *argv[])
@@ -1016,6 +1029,8 @@ static void cmd_pairable(int argc, char *argv[])
 		return;
 
 	g_free(str);
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static void cmd_discoverable(int argc, char *argv[])
@@ -1038,6 +1053,8 @@ static void cmd_discoverable(int argc, char *argv[])
 		return;
 
 	g_free(str);
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static void cmd_agent(int argc, char *argv[])
@@ -1047,7 +1064,7 @@ static void cmd_agent(int argc, char *argv[])
 
 	if (!parse_argument(argc, argv, agent_arguments, "capability",
 						&enable, &capability))
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	if (enable == TRUE) {
 		g_free(auto_register_agent);
@@ -1067,6 +1084,8 @@ static void cmd_agent(int argc, char *argv[])
 		else
 			bt_shell_printf("Agent registration disabled\n");
 	}
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_default_agent(int argc, char *argv[])
@@ -1085,10 +1104,11 @@ static void start_discovery_reply(DBusMessage *message, void *user_data)
 		bt_shell_printf("Failed to %s discovery: %s\n",
 				enable == TRUE ? "start" : "stop", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
-	bt_shell_printf("Discovery %s\n", enable == TRUE ? "started" : "stopped");
+	bt_shell_printf("Discovery %s\n", enable ? "started" : "stopped");
+	/* Leave the discovery running even on noninteractive mode */
 }
 
 static void append_variant(DBusMessageIter *iter, int type, void *val)
@@ -1235,12 +1255,14 @@ static void set_discovery_filter_reply(DBusMessage *message, void *user_data)
 	if (dbus_set_error_from_message(&error, message) == TRUE) {
 		bt_shell_printf("SetDiscoveryFilter failed: %s\n", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	filter.set = true;
 
 	bt_shell_printf("SetDiscoveryFilter success\n");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void set_discovery_filter(void)
@@ -1252,7 +1274,7 @@ static void set_discovery_filter(void)
 		set_discovery_filter_setup, set_discovery_filter_reply,
 		&filter, NULL) == FALSE) {
 		bt_shell_printf("Failed to set discovery filter\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	filter.set = true;
@@ -1280,7 +1302,7 @@ static void cmd_scan(int argc, char *argv[])
 				GUINT_TO_POINTER(enable), NULL) == FALSE) {
 		bt_shell_printf("Failed to %s discovery\n",
 					enable == TRUE ? "start" : "stop");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -1305,7 +1327,7 @@ static void cmd_scan_filter_uuids(int argc, char *argv[])
 	filter.uuids = g_strdupv(&argv[1]);
 	if (!filter.uuids) {
 		bt_shell_printf("Failed to parse input\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	filter.uuids_len = g_strv_length(filter.uuids);
@@ -1515,10 +1537,10 @@ static void cmd_info(int argc, char *argv[])
 
 	proxy = find_device(argc, argv);
 	if (!proxy)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	dbus_message_iter_get_basic(&iter, &address);
 
@@ -1548,6 +1570,8 @@ static void cmd_info(int argc, char *argv[])
 	print_property(proxy, "ServiceData");
 	print_property(proxy, "RSSI");
 	print_property(proxy, "TxPower");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void pair_reply(DBusMessage *message, void *user_data)
@@ -1559,10 +1583,12 @@ static void pair_reply(DBusMessage *message, void *user_data)
 	if (dbus_set_error_from_message(&error, message) == TRUE) {
 		bt_shell_printf("Failed to pair: %s\n", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Pairing successful\n");
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_pair(int argc, char *argv[])
@@ -1571,12 +1597,12 @@ static void cmd_pair(int argc, char *argv[])
 
 	proxy = find_device(argc, argv);
 	if (!proxy)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	if (g_dbus_proxy_method_call(proxy, "Pair", NULL, pair_reply,
 							NULL, NULL) == FALSE) {
 		bt_shell_printf("Failed to pair\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Attempting to pair with %s\n", argv[1]);
@@ -1590,7 +1616,7 @@ static void cmd_trust(int argc, char *argv[])
 
 	proxy = find_device(argc, argv);
 	if (!proxy)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	trusted = TRUE;
 
@@ -1602,6 +1628,8 @@ static void cmd_trust(int argc, char *argv[])
 		return;
 
 	g_free(str);
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static void cmd_untrust(int argc, char *argv[])
@@ -1612,7 +1640,7 @@ static void cmd_untrust(int argc, char *argv[])
 
 	proxy = find_device(argc, argv);
 	if (!proxy)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	trusted = FALSE;
 
@@ -1624,6 +1652,8 @@ static void cmd_untrust(int argc, char *argv[])
 		return;
 
 	g_free(str);
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static void cmd_block(int argc, char *argv[])
@@ -1634,7 +1664,7 @@ static void cmd_block(int argc, char *argv[])
 
 	proxy = find_device(argc, argv);
 	if (!proxy)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	blocked = TRUE;
 
@@ -1646,6 +1676,8 @@ static void cmd_block(int argc, char *argv[])
 		return;
 
 	g_free(str);
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static void cmd_unblock(int argc, char *argv[])
@@ -1656,7 +1688,7 @@ static void cmd_unblock(int argc, char *argv[])
 
 	proxy = find_device(argc, argv);
 	if (!proxy)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	blocked = FALSE;
 
@@ -1668,6 +1700,8 @@ static void cmd_unblock(int argc, char *argv[])
 		return;
 
 	g_free(str);
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static void remove_device_reply(DBusMessage *message, void *user_data)
@@ -1679,10 +1713,11 @@ static void remove_device_reply(DBusMessage *message, void *user_data)
 	if (dbus_set_error_from_message(&error, message) == TRUE) {
 		bt_shell_printf("Failed to remove device: %s\n", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Device has been removed\n");
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void remove_device_setup(DBusMessageIter *iter, void *user_data)
@@ -1707,6 +1742,7 @@ static void remove_device(GDBusProxy *proxy)
 						path, g_free) == FALSE) {
 		bt_shell_printf("Failed to remove device\n");
 		g_free(path);
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 }
 
@@ -1748,12 +1784,13 @@ static void connect_reply(DBusMessage *message, void *user_data)
 	if (dbus_set_error_from_message(&error, message) == TRUE) {
 		bt_shell_printf("Failed to connect: %s\n", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Connection successful\n");
 
 	set_default_device(proxy, NULL);
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_connect(int argc, char *argv[])
@@ -1766,13 +1803,13 @@ static void cmd_connect(int argc, char *argv[])
 	proxy = find_proxy_by_address(default_ctrl->devices, argv[1]);
 	if (!proxy) {
 		bt_shell_printf("Device %s not available\n", argv[1]);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
 							proxy, NULL) == FALSE) {
 		bt_shell_printf("Failed to connect\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Attempting to connect to %s\n", argv[1]);
@@ -1788,7 +1825,7 @@ static void disconn_reply(DBusMessage *message, void *user_data)
 	if (dbus_set_error_from_message(&error, message) == TRUE) {
 		bt_shell_printf("Failed to disconnect: %s\n", error.name);
 		dbus_error_free(&error);
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	bt_shell_printf("Successful disconnected\n");
@@ -1797,6 +1834,8 @@ static void disconn_reply(DBusMessage *message, void *user_data)
 		return;
 
 	set_default_device(NULL, NULL);
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_disconn(int argc, char *argv[])
@@ -1810,7 +1849,7 @@ static void cmd_disconn(int argc, char *argv[])
 	if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply,
 							proxy, NULL) == FALSE) {
 		bt_shell_printf("Failed to disconnect\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (argc < 2 || strlen(argv[1]) == 0) {
@@ -1831,9 +1870,11 @@ static void cmd_list_attributes(int argc, char *argv[])
 
 	proxy = find_device(argc, argv);
 	if (!proxy)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	gatt_list_attributes(g_dbus_proxy_get_path(proxy));
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_set_alias(int argc, char *argv[])
@@ -1853,6 +1894,8 @@ static void cmd_set_alias(int argc, char *argv[])
 		return;
 
 	g_free(name);
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static void cmd_select_attribute(int argc, char *argv[])
@@ -1865,8 +1908,12 @@ static void cmd_select_attribute(int argc, char *argv[])
 	}
 
 	proxy = gatt_select_attribute(default_attr, argv[1]);
-	if (proxy)
+	if (proxy) {
 		set_default_attribute(proxy);
+		return bt_shell_noninteractive_quit(EXIT_SUCCESS);
+	}
+
+	return bt_shell_noninteractive_quit(EXIT_FAILURE);
 }
 
 static struct GDBusProxy *find_attribute(int argc, char *argv[])
@@ -1897,10 +1944,10 @@ static void cmd_attribute_info(int argc, char *argv[])
 
 	proxy = find_attribute(argc, argv);
 	if (!proxy)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	if (g_dbus_proxy_get_property(proxy, "UUID", &iter) == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	dbus_message_iter_get_basic(&iter, &uuid);
 
@@ -1932,13 +1979,15 @@ static void cmd_attribute_info(int argc, char *argv[])
 		print_property(proxy, "Characteristic");
 		print_property(proxy, "Value");
 	}
+
+	return bt_shell_noninteractive_quit(EXIT_SUCCESS);
 }
 
 static void cmd_read(int argc, char *argv[])
 {
 	if (!default_attr) {
 		bt_shell_printf("No attribute selected\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	gatt_read_attribute(default_attr);
@@ -1948,7 +1997,7 @@ static void cmd_write(int argc, char *argv[])
 {
 	if (!default_attr) {
 		bt_shell_printf("No attribute selected\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	gatt_write_attribute(default_attr, argv[1]);
@@ -1958,7 +2007,7 @@ static void cmd_acquire_write(int argc, char *argv[])
 {
 	if (!default_attr) {
 		bt_shell_printf("No attribute selected\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	gatt_acquire_write(default_attr, argv[1]);
@@ -1968,7 +2017,7 @@ static void cmd_release_write(int argc, char *argv[])
 {
 	if (!default_attr) {
 		bt_shell_printf("No attribute selected\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	gatt_release_write(default_attr, argv[1]);
@@ -1978,7 +2027,7 @@ static void cmd_acquire_notify(int argc, char *argv[])
 {
 	if (!default_attr) {
 		bt_shell_printf("No attribute selected\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	gatt_acquire_notify(default_attr, argv[1]);
@@ -1988,7 +2037,7 @@ static void cmd_release_notify(int argc, char *argv[])
 {
 	if (!default_attr) {
 		bt_shell_printf("No attribute selected\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	gatt_release_notify(default_attr, argv[1]);
@@ -2003,7 +2052,7 @@ static void cmd_notify(int argc, char *argv[])
 
 	if (!default_attr) {
 		bt_shell_printf("No attribute selected\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	gatt_notify_attribute(default_attr, enable ? true : false);
@@ -2012,7 +2061,7 @@ static void cmd_notify(int argc, char *argv[])
 static void cmd_register_app(int argc, char *argv[])
 {
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	gatt_register_app(dbus_conn, default_ctrl->proxy, argc, argv);
 }
@@ -2020,7 +2069,7 @@ static void cmd_register_app(int argc, char *argv[])
 static void cmd_unregister_app(int argc, char *argv[])
 {
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	gatt_unregister_app(dbus_conn, default_ctrl->proxy);
 }
@@ -2028,7 +2077,7 @@ static void cmd_unregister_app(int argc, char *argv[])
 static void cmd_register_service(int argc, char *argv[])
 {
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	gatt_register_service(dbus_conn, default_ctrl->proxy, argc, argv);
 }
@@ -2036,7 +2085,7 @@ static void cmd_register_service(int argc, char *argv[])
 static void cmd_unregister_service(int argc, char *argv[])
 {
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	gatt_unregister_service(dbus_conn, default_ctrl->proxy, argc, argv);
 }
@@ -2044,7 +2093,7 @@ static void cmd_unregister_service(int argc, char *argv[])
 static void cmd_register_characteristic(int argc, char *argv[])
 {
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	gatt_register_chrc(dbus_conn, default_ctrl->proxy, argc, argv);
 }
@@ -2052,7 +2101,7 @@ static void cmd_register_characteristic(int argc, char *argv[])
 static void cmd_unregister_characteristic(int argc, char *argv[])
 {
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	gatt_unregister_chrc(dbus_conn, default_ctrl->proxy, argc, argv);
 }
@@ -2060,7 +2109,7 @@ static void cmd_unregister_characteristic(int argc, char *argv[])
 static void cmd_register_descriptor(int argc, char *argv[])
 {
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	gatt_register_desc(dbus_conn, default_ctrl->proxy, argc, argv);
 }
@@ -2068,7 +2117,7 @@ static void cmd_register_descriptor(int argc, char *argv[])
 static void cmd_unregister_descriptor(int argc, char *argv[])
 {
 	if (check_default_ctrl() == FALSE)
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 
 	gatt_unregister_desc(dbus_conn, default_ctrl->proxy, argc, argv);
 }
@@ -2184,7 +2233,7 @@ static void cmd_advertise(int argc, char *argv[])
 
 	if (!default_ctrl || !default_ctrl->ad_proxy) {
 		bt_shell_printf("LEAdvertisingManager not found\n");
-		return;
+		bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	if (enable == TRUE)
@@ -2271,7 +2320,7 @@ static void cmd_advertise_appearance(int argc, char *argv[])
 	value = strtol(argv[1], &endptr, 0);
 	if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
 		bt_shell_printf("Invalid argument\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	ad_advertise_local_appearance(dbus_conn, &value);
@@ -2290,7 +2339,7 @@ static void cmd_advertise_duration(int argc, char *argv[])
 	value = strtol(argv[1], &endptr, 0);
 	if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
 		bt_shell_printf("Invalid argument\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	ad_advertise_duration(dbus_conn, &value);
@@ -2309,7 +2358,7 @@ static void cmd_advertise_timeout(int argc, char *argv[])
 	value = strtol(argv[1], &endptr, 0);
 	if (!endptr || *endptr != '\0' || value > UINT16_MAX) {
 		bt_shell_printf("Invalid argument\n");
-		return;
+		return bt_shell_noninteractive_quit(EXIT_FAILURE);
 	}
 
 	ad_advertise_timeout(dbus_conn, &value);
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 12/14] shared/shell: Add bt_shell_usage
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (10 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 11/14] client: Call bt_shell_noninteractive_quit when done with command Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-26 15:53 ` [PATCH BlueZ 13/14] shared/shell: Fix parsing of mandatory arguments Luiz Augusto von Dentz
  2018-02-28 16:09 ` [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

bt_shell_usage can be used to print the usage of the current command
in execution.
---
 src/shared/shell.c | 14 ++++++++++++++
 src/shared/shell.h |  1 +
 2 files changed, 15 insertions(+)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index cd46532fe..c90d28a9f 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -76,6 +76,7 @@ static struct {
 	const struct bt_shell_menu *menu;
 	const struct bt_shell_menu *main;
 	struct queue *submenus;
+	const struct bt_shell_menu_entry *exec;
 
 	struct queue *envs;
 } data;
@@ -325,9 +326,13 @@ optional:
 	wordfree(&w);
 
 exec:
+	data.exec = entry;
+
 	if (entry->func)
 		entry->func(argc, argv);
 
+	data.exec = NULL;
+
 	return 0;
 
 fail:
@@ -451,6 +456,15 @@ void bt_shell_hexdump(const unsigned char *buf, size_t len)
 	util_hexdump(' ', buf, len, print_string, NULL);
 }
 
+void bt_shell_usage()
+{
+	if (!data.exec)
+		return;
+
+	bt_shell_printf("Usage: %s %s\n", data.exec->cmd,
+					data.exec->arg ? data.exec->arg : "");
+}
+
 void bt_shell_prompt_input(const char *label, const char *msg,
 			bt_shell_prompt_input_func func, void *user_data)
 {
diff --git a/src/shared/shell.h b/src/shared/shell.h
index 10747c955..33c31f35b 100644
--- a/src/shared/shell.h
+++ b/src/shared/shell.h
@@ -82,6 +82,7 @@ void bt_shell_set_prompt(const char *string);
 void bt_shell_printf(const char *fmt,
 				...) __attribute__((format(printf, 1, 2)));
 void bt_shell_hexdump(const unsigned char *buf, size_t len);
+void bt_shell_usage(void);
 
 void bt_shell_prompt_input(const char *label, const char *msg,
 			bt_shell_prompt_input_func func, void *user_data);
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* [PATCH BlueZ 13/14] shared/shell: Fix parsing of mandatory arguments
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (11 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 12/14] shared/shell: Add bt_shell_usage Luiz Augusto von Dentz
@ 2018-02-26 15:53 ` Luiz Augusto von Dentz
  2018-02-28 16:09 ` [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-26 15:53 UTC (permalink / raw)
  To: linux-bluetooth

From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

In certain cases the arguments may no start with the mandatory commands
such as when the command handler expects getopt arguments first.
---
 src/shared/shell.c | 17 ++++++++++++++---
 1 file changed, 14 insertions(+), 3 deletions(-)

diff --git a/src/shared/shell.c b/src/shared/shell.c
index c90d28a9f..9ae5af79e 100644
--- a/src/shared/shell.c
+++ b/src/shared/shell.c
@@ -291,11 +291,22 @@ static int cmd_exec(const struct bt_shell_menu_entry *entry,
 	}
 
 	len = man - entry->arg;
-	man = strndup(entry->arg, len + 1);
+	if (entry->arg[0] == '<')
+		man = strndup(entry->arg, len + 1);
+	else {
+		/* Find where mandatory arguments start */
+		opt = strrchr(entry->arg, '<');
+		/* Skip if mandatory arguments are not in the right format */
+		if (!opt || opt > man) {
+			opt = strdup(entry->arg);
+			goto optional;
+		}
+		man = strndup(opt, man - opt + 1);
+	}
 
 	if (parse_args(man, &w, "<>", flags) < 0) {
 		print_text(COLOR_HIGHLIGHT,
-				"Unable to parse mandatory command arguments");
+			"Unable to parse mandatory command arguments: %s", man );
 		return -EINVAL;
 	}
 
@@ -312,7 +323,7 @@ static int cmd_exec(const struct bt_shell_menu_entry *entry,
 optional:
 	if (parse_args(opt, &w, "[]", flags) < 0) {
 		print_text(COLOR_HIGHLIGHT,
-				"Unable to parse optional command arguments");
+			"Unable to parse optional command arguments: %s", opt);
 		return -EINVAL;
 	}
 
-- 
2.14.3


^ permalink raw reply related	[flat|nested] 15+ messages in thread

* Re: [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode
  2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
                   ` (12 preceding siblings ...)
  2018-02-26 15:53 ` [PATCH BlueZ 13/14] shared/shell: Fix parsing of mandatory arguments Luiz Augusto von Dentz
@ 2018-02-28 16:09 ` Luiz Augusto von Dentz
  13 siblings, 0 replies; 15+ messages in thread
From: Luiz Augusto von Dentz @ 2018-02-28 16:09 UTC (permalink / raw)
  To: linux-bluetooth

Hi,

On Mon, Feb 26, 2018 at 5:53 PM, Luiz Augusto von Dentz
<luiz.dentz@gmail.com> wrote:
> From: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
>
> This adds functionally to bt_shell to properly handle non-interactive
> mode making all command line tools handle commands given as argument:
>
>>./bluetoothctl power on
> [CHG] Controller B8:8A:60:D8:17:D7 Class: 0x002c010c
> Changing power on succeded
>
> While on non-interactive mode readline will not be used and only the
> command line arguments will be processed, in addition to that there
> is now bt_shell_noninteractive_quit which shall be used by the command
> handler to quit when it is done with the command execution.
>
> Luiz Augusto von Dentz (14):
>   shared/shell: Add bt_shell_{noninteractive_}quit
>   shared/shell: Fix not reseting optind
>   shared/shell: Fix timeout parameter
>   shared/shell: Do not quit immediatelly on noninteractive mode
>   shared/shell: Fix not handling sort options
>   shared/shell: Disable bt_shell_prompt_input in noninteractive mode
>   shared/shell: Disable readline while in noninteractive mode
>   sharead/mainloop-glib: Fix mainloop_exit*
>   shared/mainloop-glib: Fix calling g_main_loop_quit with NULL
>   shared/shell: Allow executing submenu commands
>   client: Call bt_shell_noninteractive_quit when done with command
>   shared/shell: Add bt_shell_usage
>   shared/shell: Fix parsing of mandatory arguments
>   tools/btmgmt: Port to use bt_shell
>
>  client/advertising.c       |   84 ++-
>  client/gatt.c              |  113 ++--
>  client/main.c              |  153 +++--
>  src/shared/mainloop-glib.c |    5 +
>  src/shared/shell.c         |  130 +++-
>  src/shared/shell.h         |    4 +
>  tools/btmgmt.c             | 1560 ++++++++++++++++----------------------------
>  7 files changed, 905 insertions(+), 1144 deletions(-)

Applied.

-- 
Luiz Augusto von Dentz

^ permalink raw reply	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2018-02-28 16:09 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-02-26 15:53 [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 01/14] shared/shell: Add bt_shell_{noninteractive_}quit Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 02/14] shared/shell: Fix not reseting optind Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 03/14] shared/shell: Fix timeout parameter Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 04/14] shared/shell: Do not quit immediatelly on noninteractive mode Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 05/14] shared/shell: Fix not handling sort options Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 06/14] shared/shell: Disable bt_shell_prompt_input in noninteractive mode Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 07/14] shared/shell: Disable readline while " Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 08/14] sharead/mainloop-glib: Fix mainloop_exit* Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 09/14] shared/mainloop-glib: Fix calling g_main_loop_quit with NULL Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 10/14] shared/shell: Allow executing submenu commands Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 11/14] client: Call bt_shell_noninteractive_quit when done with command Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 12/14] shared/shell: Add bt_shell_usage Luiz Augusto von Dentz
2018-02-26 15:53 ` [PATCH BlueZ 13/14] shared/shell: Fix parsing of mandatory arguments Luiz Augusto von Dentz
2018-02-28 16:09 ` [PATCH BlueZ 00/14] shared/shell: Add proper support for non-interactive mode Luiz Augusto von Dentz

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.