diff mbox series

[libgpiod,v3,1/2] tools: remove dependency on glibc program_invocation_[short_]name

Message ID 20230228001307.249811-2-benl@squareup.com
State Superseded
Headers show
Series tools: fix compile issues when GNU extensions are not present | expand

Commit Message

Benjamin Li Feb. 28, 2023, 12:13 a.m. UTC
Platforms like Bionic libc don't have program_invocation_[short_]name,
which is a GNU extension. It does have getprogname(), a BSD extension,
but rather than supporting multiple extensions let's just introduce
our own local helpers.

We derive the short name ourselves rather than calling basename(),
as the POSIX version takes char *, not const char *, and is thus
not guaranteed to avoid modifying its input. (The GNU version does
take const char * but we are avoiding extensions here.)

Signed-off-by: Benjamin Li <benl@squareup.com>
---
 tools/gpiodetect.c   |  5 +++--
 tools/gpioget.c      |  5 +++--
 tools/gpioinfo.c     |  5 +++--
 tools/gpiomon.c      |  5 +++--
 tools/gpionotify.c   |  5 +++--
 tools/gpioset.c      |  5 +++--
 tools/tools-common.c | 34 ++++++++++++++++++++++++++--------
 tools/tools-common.h |  4 +++-
 8 files changed, 47 insertions(+), 21 deletions(-)

Comments

Bartosz Golaszewski March 6, 2023, 1:52 p.m. UTC | #1
On Tue, Feb 28, 2023 at 1:13 AM Benjamin Li <benl@squareup.com> wrote:
>
> Platforms like Bionic libc don't have program_invocation_[short_]name,
> which is a GNU extension. It does have getprogname(), a BSD extension,
> but rather than supporting multiple extensions let's just introduce
> our own local helpers.
>
> We derive the short name ourselves rather than calling basename(),
> as the POSIX version takes char *, not const char *, and is thus
> not guaranteed to avoid modifying its input. (The GNU version does
> take const char * but we are avoiding extensions here.)
>
> Signed-off-by: Benjamin Li <benl@squareup.com>
> ---
>  tools/gpiodetect.c   |  5 +++--
>  tools/gpioget.c      |  5 +++--
>  tools/gpioinfo.c     |  5 +++--
>  tools/gpiomon.c      |  5 +++--
>  tools/gpionotify.c   |  5 +++--
>  tools/gpioset.c      |  5 +++--
>  tools/tools-common.c | 34 ++++++++++++++++++++++++++--------
>  tools/tools-common.h |  4 +++-
>  8 files changed, 47 insertions(+), 21 deletions(-)
>
> diff --git a/tools/gpiodetect.c b/tools/gpiodetect.c
> index f0211da..eb8d273 100644
> --- a/tools/gpiodetect.c
> +++ b/tools/gpiodetect.c
> @@ -12,7 +12,7 @@
>
>  static void print_help(void)
>  {
> -       printf("Usage: %s [OPTIONS] [chip]...\n", get_progname());
> +       printf("Usage: %s [OPTIONS] [chip]...\n", get_prog_short_name());
>         printf("\n");
>         printf("List GPIO chips, print their labels and number of GPIO lines.\n");
>         printf("\n");
> @@ -51,7 +51,7 @@ static int parse_config(int argc, char **argv)
>                         print_version();
>                         exit(EXIT_SUCCESS);
>                 case '?':
> -                       die("try %s --help", get_progname());
> +                       die("try %s --help", get_prog_short_name());

This changes the semantics though - previously it would have returned
the long name. I think it's better for the help output to return the
full path. It's also consistent with what most command-line program
seem to do.

Same elsewhere.

Bart

>                 default:
>                         abort();
>                 }
> @@ -89,6 +89,7 @@ int main(int argc, char **argv)
>         int num_chips, i, ret = EXIT_SUCCESS;
>         char **paths, *path;
>
> +       set_prog_name(argv[0]);
>         i = parse_config(argc, argv);
>         argc -= i;
>         argv += i;
> diff --git a/tools/gpioget.c b/tools/gpioget.c
> index 08c17e6..c8238cf 100644
> --- a/tools/gpioget.c
> +++ b/tools/gpioget.c
> @@ -26,7 +26,7 @@ struct config {
>
>  static void print_help(void)
>  {
> -       printf("Usage: %s [OPTIONS] <line>...\n", get_progname());
> +       printf("Usage: %s [OPTIONS] <line>...\n", get_prog_short_name());
>         printf("\n");
>         printf("Read values of GPIO lines.\n");
>         printf("\n");
> @@ -120,7 +120,7 @@ static int parse_config(int argc, char **argv, struct config *cfg)
>                         print_version();
>                         exit(EXIT_SUCCESS);
>                 case '?':
> -                       die("try %s --help", get_progname());
> +                       die("try %s --help", get_prog_short_name());
>                 case 0:
>                         break;
>                 default:
> @@ -146,6 +146,7 @@ int main(int argc, char **argv)
>         struct config cfg;
>         const char *fmt;
>
> +       set_prog_name(argv[0]);
>         i = parse_config(argc, argv, &cfg);
>         argc -= i;
>         argv += i;
> diff --git a/tools/gpioinfo.c b/tools/gpioinfo.c
> index 1ec7f63..ce2df63 100644
> --- a/tools/gpioinfo.c
> +++ b/tools/gpioinfo.c
> @@ -20,7 +20,7 @@ struct config {
>
>  static void print_help(void)
>  {
> -       printf("Usage: %s [OPTIONS] [line]...\n", get_progname());
> +       printf("Usage: %s [OPTIONS] [line]...\n", get_prog_short_name());
>         printf("\n");
>         printf("Print information about GPIO lines.\n");
>         printf("\n");
> @@ -83,7 +83,7 @@ static int parse_config(int argc, char **argv, struct config *cfg)
>                         print_version();
>                         exit(EXIT_SUCCESS);
>                 case '?':
> -                       die("try %s --help", get_progname());
> +                       die("try %s --help", get_prog_short_name());
>                 case 0:
>                         break;
>                 default:
> @@ -228,6 +228,7 @@ int main(int argc, char **argv)
>         struct config cfg;
>         char **paths;
>
> +       set_prog_name(argv[0]);
>         i = parse_config(argc, argv, &cfg);
>         argc -= i;
>         argv += i;
> diff --git a/tools/gpiomon.c b/tools/gpiomon.c
> index 93ff463..893b966 100644
> --- a/tools/gpiomon.c
> +++ b/tools/gpiomon.c
> @@ -34,7 +34,7 @@ struct config {
>
>  static void print_help(void)
>  {
> -       printf("Usage: %s [OPTIONS] <line>...\n", get_progname());
> +       printf("Usage: %s [OPTIONS] <line>...\n", get_prog_short_name());
>         printf("\n");
>         printf("Wait for events on GPIO lines and print them to standard output.\n");
>         printf("\n");
> @@ -195,7 +195,7 @@ static int parse_config(int argc, char **argv, struct config *cfg)
>                         print_version();
>                         exit(EXIT_SUCCESS);
>                 case '?':
> -                       die("try %s --help", get_progname());
> +                       die("try %s --help", get_prog_short_name());
>                 case 0:
>                         break;
>                 default:
> @@ -360,6 +360,7 @@ int main(int argc, char **argv)
>         struct config cfg;
>         int ret, i, j;
>
> +       set_prog_name(argv[0]);
>         i = parse_config(argc, argv, &cfg);
>         argc -= i;
>         argv += i;
> diff --git a/tools/gpionotify.c b/tools/gpionotify.c
> index a0976f7..e19d88c 100644
> --- a/tools/gpionotify.c
> +++ b/tools/gpionotify.c
> @@ -27,7 +27,7 @@ struct config {
>
>  static void print_help(void)
>  {
> -       printf("Usage: %s [OPTIONS] <line>...\n", get_progname());
> +       printf("Usage: %s [OPTIONS] <line>...\n", get_prog_short_name());
>         printf("\n");
>         printf("Wait for changes to info on GPIO lines and print them to standard output.\n");
>         printf("\n");
> @@ -144,7 +144,7 @@ static int parse_config(int argc, char **argv, struct config *cfg)
>                         print_version();
>                         exit(EXIT_SUCCESS);
>                 case '?':
> -                       die("try %s --help", get_progname());
> +                       die("try %s --help", get_prog_short_name());
>                 case 0:
>                         break;
>                 default:
> @@ -370,6 +370,7 @@ int main(int argc, char **argv)
>         struct pollfd *pollfds;
>         struct config cfg;
>
> +       set_prog_name(argv[0]);
>         i = parse_config(argc, argv, &cfg);
>         argc -= optind;
>         argv += optind;
> diff --git a/tools/gpioset.c b/tools/gpioset.c
> index a7084a3..cc9106c 100644
> --- a/tools/gpioset.c
> +++ b/tools/gpioset.c
> @@ -36,7 +36,7 @@ struct config {
>
>  static void print_help(void)
>  {
> -       printf("Usage: %s [OPTIONS] <line=value>...\n", get_progname());
> +       printf("Usage: %s [OPTIONS] <line=value>...\n", get_prog_short_name());
>         printf("\n");
>         printf("Set values of GPIO lines.\n");
>         printf("\n");
> @@ -212,7 +212,7 @@ static int parse_config(int argc, char **argv, struct config *cfg)
>                         print_version();
>                         exit(EXIT_SUCCESS);
>                 case '?':
> -                       die("try %s --help", get_progname());
> +                       die("try %s --help", get_prog_short_name());
>                 case 0:
>                         break;
>                 default:
> @@ -876,6 +876,7 @@ int main(int argc, char **argv)
>         struct config cfg;
>         char **lines;
>
> +       set_prog_name(argv[0]);
>         i = parse_config(argc, argv, &cfg);
>         argc -= i;
>         argv += i;
> diff --git a/tools/tools-common.c b/tools/tools-common.c
> index a0080fc..e5f6fc1 100644
> --- a/tools/tools-common.c
> +++ b/tools/tools-common.c
> @@ -19,9 +19,28 @@
>
>  #include "tools-common.h"
>
> -const char *get_progname(void)
> +static const char *prog_name = NULL;
> +static const char *prog_short_name = NULL;
> +
> +void set_prog_name(const char *name)
> +{
> +       prog_name = name;
> +       prog_short_name = name;
> +       while (*name) {
> +               if (*name++ == '/') {
> +                       prog_short_name = name;
> +               }
> +       }
> +}
> +
> +const char *get_prog_name(void)
> +{
> +       return prog_name;
> +}
> +
> +const char *get_prog_short_name(void)
>  {
> -       return program_invocation_name;
> +       return prog_short_name;
>  }
>
>  void print_error(const char *fmt, ...)
> @@ -29,7 +48,7 @@ void print_error(const char *fmt, ...)
>         va_list va;
>
>         va_start(va, fmt);
> -       fprintf(stderr, "%s: ", program_invocation_name);
> +       fprintf(stderr, "%s: ", get_prog_name());
>         vfprintf(stderr, fmt, va);
>         fprintf(stderr, "\n");
>         va_end(va);
> @@ -40,7 +59,7 @@ void print_perror(const char *fmt, ...)
>         va_list va;
>
>         va_start(va, fmt);
> -       fprintf(stderr, "%s: ", program_invocation_name);
> +       fprintf(stderr, "%s: ", get_prog_name());
>         vfprintf(stderr, fmt, va);
>         fprintf(stderr, ": %s\n", strerror(errno));
>         va_end(va);
> @@ -51,7 +70,7 @@ void die(const char *fmt, ...)
>         va_list va;
>
>         va_start(va, fmt);
> -       fprintf(stderr, "%s: ", program_invocation_name);
> +       fprintf(stderr, "%s: ", get_prog_name());
>         vfprintf(stderr, fmt, va);
>         fprintf(stderr, "\n");
>         va_end(va);
> @@ -64,7 +83,7 @@ void die_perror(const char *fmt, ...)
>         va_list va;
>
>         va_start(va, fmt);
> -       fprintf(stderr, "%s: ", program_invocation_name);
> +       fprintf(stderr, "%s: ", get_prog_name());
>         vfprintf(stderr, fmt, va);
>         fprintf(stderr, ": %s\n", strerror(errno));
>         va_end(va);
> @@ -74,8 +93,7 @@ void die_perror(const char *fmt, ...)
>
>  void print_version(void)
>  {
> -       printf("%s (libgpiod) v%s\n",
> -              program_invocation_short_name, gpiod_api_version());
> +       printf("%s (libgpiod) v%s\n", get_prog_short_name(), gpiod_api_version());
>         printf("Copyright (C) 2017-2023 Bartosz Golaszewski\n");
>         printf("License: GPL-2.0-or-later\n");
>         printf("This is free software: you are free to change and redistribute it.\n");
> diff --git a/tools/tools-common.h b/tools/tools-common.h
> index 434e5ba..c82317a 100644
> --- a/tools/tools-common.h
> +++ b/tools/tools-common.h
> @@ -78,7 +78,9 @@ struct line_resolver {
>         struct resolved_line lines[];
>  };
>
> -const char *get_progname(void);
> +void set_prog_name(const char *name);
> +const char *get_prog_name(void);
> +const char *get_prog_short_name(void);
>  void print_error(const char *fmt, ...) PRINTF(1, 2);
>  void print_perror(const char *fmt, ...) PRINTF(1, 2);
>  void die(const char *fmt, ...) NORETURN PRINTF(1, 2);
> --
> 2.25.1
>
diff mbox series

Patch

diff --git a/tools/gpiodetect.c b/tools/gpiodetect.c
index f0211da..eb8d273 100644
--- a/tools/gpiodetect.c
+++ b/tools/gpiodetect.c
@@ -12,7 +12,7 @@ 
 
 static void print_help(void)
 {
-	printf("Usage: %s [OPTIONS] [chip]...\n", get_progname());
+	printf("Usage: %s [OPTIONS] [chip]...\n", get_prog_short_name());
 	printf("\n");
 	printf("List GPIO chips, print their labels and number of GPIO lines.\n");
 	printf("\n");
@@ -51,7 +51,7 @@  static int parse_config(int argc, char **argv)
 			print_version();
 			exit(EXIT_SUCCESS);
 		case '?':
-			die("try %s --help", get_progname());
+			die("try %s --help", get_prog_short_name());
 		default:
 			abort();
 		}
@@ -89,6 +89,7 @@  int main(int argc, char **argv)
 	int num_chips, i, ret = EXIT_SUCCESS;
 	char **paths, *path;
 
+	set_prog_name(argv[0]);
 	i = parse_config(argc, argv);
 	argc -= i;
 	argv += i;
diff --git a/tools/gpioget.c b/tools/gpioget.c
index 08c17e6..c8238cf 100644
--- a/tools/gpioget.c
+++ b/tools/gpioget.c
@@ -26,7 +26,7 @@  struct config {
 
 static void print_help(void)
 {
-	printf("Usage: %s [OPTIONS] <line>...\n", get_progname());
+	printf("Usage: %s [OPTIONS] <line>...\n", get_prog_short_name());
 	printf("\n");
 	printf("Read values of GPIO lines.\n");
 	printf("\n");
@@ -120,7 +120,7 @@  static int parse_config(int argc, char **argv, struct config *cfg)
 			print_version();
 			exit(EXIT_SUCCESS);
 		case '?':
-			die("try %s --help", get_progname());
+			die("try %s --help", get_prog_short_name());
 		case 0:
 			break;
 		default:
@@ -146,6 +146,7 @@  int main(int argc, char **argv)
 	struct config cfg;
 	const char *fmt;
 
+	set_prog_name(argv[0]);
 	i = parse_config(argc, argv, &cfg);
 	argc -= i;
 	argv += i;
diff --git a/tools/gpioinfo.c b/tools/gpioinfo.c
index 1ec7f63..ce2df63 100644
--- a/tools/gpioinfo.c
+++ b/tools/gpioinfo.c
@@ -20,7 +20,7 @@  struct config {
 
 static void print_help(void)
 {
-	printf("Usage: %s [OPTIONS] [line]...\n", get_progname());
+	printf("Usage: %s [OPTIONS] [line]...\n", get_prog_short_name());
 	printf("\n");
 	printf("Print information about GPIO lines.\n");
 	printf("\n");
@@ -83,7 +83,7 @@  static int parse_config(int argc, char **argv, struct config *cfg)
 			print_version();
 			exit(EXIT_SUCCESS);
 		case '?':
-			die("try %s --help", get_progname());
+			die("try %s --help", get_prog_short_name());
 		case 0:
 			break;
 		default:
@@ -228,6 +228,7 @@  int main(int argc, char **argv)
 	struct config cfg;
 	char **paths;
 
+	set_prog_name(argv[0]);
 	i = parse_config(argc, argv, &cfg);
 	argc -= i;
 	argv += i;
diff --git a/tools/gpiomon.c b/tools/gpiomon.c
index 93ff463..893b966 100644
--- a/tools/gpiomon.c
+++ b/tools/gpiomon.c
@@ -34,7 +34,7 @@  struct config {
 
 static void print_help(void)
 {
-	printf("Usage: %s [OPTIONS] <line>...\n", get_progname());
+	printf("Usage: %s [OPTIONS] <line>...\n", get_prog_short_name());
 	printf("\n");
 	printf("Wait for events on GPIO lines and print them to standard output.\n");
 	printf("\n");
@@ -195,7 +195,7 @@  static int parse_config(int argc, char **argv, struct config *cfg)
 			print_version();
 			exit(EXIT_SUCCESS);
 		case '?':
-			die("try %s --help", get_progname());
+			die("try %s --help", get_prog_short_name());
 		case 0:
 			break;
 		default:
@@ -360,6 +360,7 @@  int main(int argc, char **argv)
 	struct config cfg;
 	int ret, i, j;
 
+	set_prog_name(argv[0]);
 	i = parse_config(argc, argv, &cfg);
 	argc -= i;
 	argv += i;
diff --git a/tools/gpionotify.c b/tools/gpionotify.c
index a0976f7..e19d88c 100644
--- a/tools/gpionotify.c
+++ b/tools/gpionotify.c
@@ -27,7 +27,7 @@  struct config {
 
 static void print_help(void)
 {
-	printf("Usage: %s [OPTIONS] <line>...\n", get_progname());
+	printf("Usage: %s [OPTIONS] <line>...\n", get_prog_short_name());
 	printf("\n");
 	printf("Wait for changes to info on GPIO lines and print them to standard output.\n");
 	printf("\n");
@@ -144,7 +144,7 @@  static int parse_config(int argc, char **argv, struct config *cfg)
 			print_version();
 			exit(EXIT_SUCCESS);
 		case '?':
-			die("try %s --help", get_progname());
+			die("try %s --help", get_prog_short_name());
 		case 0:
 			break;
 		default:
@@ -370,6 +370,7 @@  int main(int argc, char **argv)
 	struct pollfd *pollfds;
 	struct config cfg;
 
+	set_prog_name(argv[0]);
 	i = parse_config(argc, argv, &cfg);
 	argc -= optind;
 	argv += optind;
diff --git a/tools/gpioset.c b/tools/gpioset.c
index a7084a3..cc9106c 100644
--- a/tools/gpioset.c
+++ b/tools/gpioset.c
@@ -36,7 +36,7 @@  struct config {
 
 static void print_help(void)
 {
-	printf("Usage: %s [OPTIONS] <line=value>...\n", get_progname());
+	printf("Usage: %s [OPTIONS] <line=value>...\n", get_prog_short_name());
 	printf("\n");
 	printf("Set values of GPIO lines.\n");
 	printf("\n");
@@ -212,7 +212,7 @@  static int parse_config(int argc, char **argv, struct config *cfg)
 			print_version();
 			exit(EXIT_SUCCESS);
 		case '?':
-			die("try %s --help", get_progname());
+			die("try %s --help", get_prog_short_name());
 		case 0:
 			break;
 		default:
@@ -876,6 +876,7 @@  int main(int argc, char **argv)
 	struct config cfg;
 	char **lines;
 
+	set_prog_name(argv[0]);
 	i = parse_config(argc, argv, &cfg);
 	argc -= i;
 	argv += i;
diff --git a/tools/tools-common.c b/tools/tools-common.c
index a0080fc..e5f6fc1 100644
--- a/tools/tools-common.c
+++ b/tools/tools-common.c
@@ -19,9 +19,28 @@ 
 
 #include "tools-common.h"
 
-const char *get_progname(void)
+static const char *prog_name = NULL;
+static const char *prog_short_name = NULL;
+
+void set_prog_name(const char *name)
+{
+	prog_name = name;
+	prog_short_name = name;
+	while (*name) {
+		if (*name++ == '/') {
+			prog_short_name = name;
+		}
+	}
+}
+
+const char *get_prog_name(void)
+{
+	return prog_name;
+}
+
+const char *get_prog_short_name(void)
 {
-	return program_invocation_name;
+	return prog_short_name;
 }
 
 void print_error(const char *fmt, ...)
@@ -29,7 +48,7 @@  void print_error(const char *fmt, ...)
 	va_list va;
 
 	va_start(va, fmt);
-	fprintf(stderr, "%s: ", program_invocation_name);
+	fprintf(stderr, "%s: ", get_prog_name());
 	vfprintf(stderr, fmt, va);
 	fprintf(stderr, "\n");
 	va_end(va);
@@ -40,7 +59,7 @@  void print_perror(const char *fmt, ...)
 	va_list va;
 
 	va_start(va, fmt);
-	fprintf(stderr, "%s: ", program_invocation_name);
+	fprintf(stderr, "%s: ", get_prog_name());
 	vfprintf(stderr, fmt, va);
 	fprintf(stderr, ": %s\n", strerror(errno));
 	va_end(va);
@@ -51,7 +70,7 @@  void die(const char *fmt, ...)
 	va_list va;
 
 	va_start(va, fmt);
-	fprintf(stderr, "%s: ", program_invocation_name);
+	fprintf(stderr, "%s: ", get_prog_name());
 	vfprintf(stderr, fmt, va);
 	fprintf(stderr, "\n");
 	va_end(va);
@@ -64,7 +83,7 @@  void die_perror(const char *fmt, ...)
 	va_list va;
 
 	va_start(va, fmt);
-	fprintf(stderr, "%s: ", program_invocation_name);
+	fprintf(stderr, "%s: ", get_prog_name());
 	vfprintf(stderr, fmt, va);
 	fprintf(stderr, ": %s\n", strerror(errno));
 	va_end(va);
@@ -74,8 +93,7 @@  void die_perror(const char *fmt, ...)
 
 void print_version(void)
 {
-	printf("%s (libgpiod) v%s\n",
-	       program_invocation_short_name, gpiod_api_version());
+	printf("%s (libgpiod) v%s\n", get_prog_short_name(), gpiod_api_version());
 	printf("Copyright (C) 2017-2023 Bartosz Golaszewski\n");
 	printf("License: GPL-2.0-or-later\n");
 	printf("This is free software: you are free to change and redistribute it.\n");
diff --git a/tools/tools-common.h b/tools/tools-common.h
index 434e5ba..c82317a 100644
--- a/tools/tools-common.h
+++ b/tools/tools-common.h
@@ -78,7 +78,9 @@  struct line_resolver {
 	struct resolved_line lines[];
 };
 
-const char *get_progname(void);
+void set_prog_name(const char *name);
+const char *get_prog_name(void);
+const char *get_prog_short_name(void);
 void print_error(const char *fmt, ...) PRINTF(1, 2);
 void print_perror(const char *fmt, ...) PRINTF(1, 2);
 void die(const char *fmt, ...) NORETURN PRINTF(1, 2);