[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH v2 7/8] Use posix_spawn to run external scripts
From: |
Ladislav Michl |
Subject: |
[PATCH v2 7/8] Use posix_spawn to run external scripts |
Date: |
Tue, 4 Dec 2018 22:27:46 +0100 |
User-agent: |
Mutt/1.10.1 (2018-07-13) |
posix_spawn specification dates back to last century and its
implementation is mature enough in all systems we do support.
Thus use it instead of current fork and exec in hope it will
save us some resources.
---
CHANGES:
-v2: Drop unneeded changes, split patch
common/Makefile.am | 7 ++-
common/device.c | 59 +--------------------
common/posixscript.c | 108 ++++++++++++++++++++++++++++++++++++++
configure.ac | 2 +
include/gnokii-internal.h | 9 ++++
5 files changed, 127 insertions(+), 58 deletions(-)
create mode 100644 common/posixscript.c
diff --git a/common/Makefile.am b/common/Makefile.am
index 5e6be928..21dee3fd 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -6,6 +6,10 @@ else
DATA_DIR = data
endif
+if HAVE_POSIX_SPAWN
+DEVICE_SCRIPT = posixscript.c
+endif
+
lib_LTLIBRARIES = libgnokii.la
SUBDIRS = phones \
@@ -51,7 +55,8 @@ libgnokii_la_SOURCES = \
snprintf.c \
localcharset.c \
map.c \
- gsm-auth.c
+ gsm-auth.c \
+ $(DEVICE_SCRIPT)
libgnokii_la_LIBADD = \
$(top_builddir)/common/phones/libPHONES.la \
diff --git a/common/device.c b/common/device.c
index 7b6a901c..a74b9f95 100644
--- a/common/device.c
+++ b/common/device.c
@@ -27,66 +27,11 @@
#include "devices/tcp.h"
#include "devices/tekram.h"
-#include <errno.h>
-#include <sys/wait.h>
-
GNOKII_API int device_getfd(struct gn_statemachine *state)
{
return state->device.fd;
}
-/* Script handling: */
-static void device_script_cfgfunc(const char *section, const char *key, const
char *value)
-{
- setenv(key, value, 1); /* errors ignored */
-}
-
-int device_script(int fd, const char *section, struct gn_statemachine *state)
-{
- pid_t pid;
- const char *scriptname;
- int status;
-
- if (!strcmp(section, "connect_script"))
- scriptname = state->config.connect_script;
- else
- scriptname = state->config.disconnect_script;
- if (scriptname[0] == '\0')
- return 0;
-
- errno = 0;
- switch ((pid = fork())) {
- case -1:
- fprintf(stderr, _("device_script(\"%s\"): fork() failure:
%s!\n"), scriptname, strerror(errno));
- return -1;
-
- case 0: /* child */
- cfg_foreach(section, device_script_cfgfunc);
- errno = 0;
- if (dup2(fd, 0) != 0 || dup2(fd, 1) != 1 || close(fd)) {
- fprintf(stderr, _("device_script(\"%s\"): file
descriptor preparation failure: %s\n"), scriptname, strerror(errno));
- _exit(-1);
- }
- /* FIXME: close all open descriptors - how to track them?
- */
- execl("/bin/sh", "sh", "-c", scriptname, NULL);
- fprintf(stderr, _("device_script(\"%s\"): script execution
failure: %s\n"), scriptname, strerror(errno));
- _exit(-1);
- /* NOTREACHED */
-
- default:
- if (pid == waitpid(pid, &status, 0 /* options */) &&
WIFEXITED(status) && !WEXITSTATUS(status))
- return 0;
- fprintf(stderr, _("device_script(\"%s\"): child script
execution failure: %s, exit code=%d\n"), scriptname,
- (WIFEXITED(status) ? _("normal exit") : _("abnormal
exit")),
- (WIFEXITED(status) ? WEXITSTATUS(status) : -1));
- errno = EIO;
- return -1;
-
- }
- /* NOTREACHED */
-}
-
int device_open(const char *file, int with_odd_parity, int with_async,
int with_hw_handshake, gn_connection_type device_type,
struct gn_statemachine *state)
@@ -131,7 +76,7 @@ int device_open(const char *file, int with_odd_parity, int
with_async,
/*
* handle config file connect_script:
*/
- if (device_script(state->device.fd, "connect_script", state) == -1) {
+ if (device_script(state->device.fd, 1, state)) {
dprintf("gnokii open device: connect_script failure\n");
device_close(state);
return 0;
@@ -147,7 +92,7 @@ void device_close(struct gn_statemachine *state)
/*
* handle config file disconnect_script:
*/
- if (device_script(state->device.fd, "disconnect_script", state) == -1)
+ if (device_script(state->device.fd, 0, state))
dprintf("gnokii device close: disconnect_script failure\n");
switch (state->device.type) {
diff --git a/common/posixscript.c b/common/posixscript.c
new file mode 100644
index 00000000..272eab42
--- /dev/null
+++ b/common/posixscript.c
@@ -0,0 +1,108 @@
+/*
+
+ G N O K I I
+
+ A Linux/Unix toolset and driver for the mobile phones.
+
+ This file is part of gnokii.
+
+ Copyright (C) 2018 Ladislav Michl
+
+*/
+
+#include "config.h"
+#include "compat.h"
+#include "cfgreader.h"
+#include "misc.h"
+#include "gnokii.h"
+#include "gnokii-internal.h"
+
+#include <errno.h>
+#include <spawn.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define cfg_foreach_entry(section, header, entry) \
+ for (h = gn_cfg_info; header != NULL; header = header->next) \
+ if (strcmp(section, h->section) == 0) \
+ for (entry = h->entries; entry != NULL; entry =
entry->next)
+
+int device_script(int fd, int connect, struct gn_statemachine *state)
+{
+ const char *scriptname, *section;
+ char **envp, *env;
+ struct gn_cfg_entry *e;
+ struct gn_cfg_header *h;
+ posix_spawn_file_actions_t fa;
+ pid_t pid;
+ int cnt, ret, status;
+ size_t len;
+
+ if (connect) {
+ scriptname = state->config.connect_script;
+ section = "connect_script";
+ } else {
+ scriptname = state->config.disconnect_script;
+ section = "disconnect_script";
+ }
+ if (scriptname[0] == '\0')
+ return 0;
+
+ cnt = 0; len = 0; ret = -1;
+ h = gn_cfg_info;
+ cfg_foreach_entry(section, h, e) {
+ len += strlen(e->key);
+ len += strlen(e->value);
+ len += 1 + 1 + sizeof(char *);
+ cnt++;
+ }
+
+ env = malloc(len + sizeof(char *));
+ if (!env) {
+ fprintf(stderr, _("device_script(\"%s\"): out of memory\n"),
scriptname);
+ goto out;
+ }
+
+ envp = &env;
+ env += sizeof(char *) * (cnt + 1);
+ h = gn_cfg_info;
+ cfg_foreach_entry(section, h, e) {
+ *envp++ = &env;
+ env += snprintf(env, "%s=%s", e->key, e->value);
+ env++;
+ }
+ envp = NULL;
+
+ if (posix_spawn_file_actions_init(&fa)) {
+ fprintf(stderr, _("device_script(\"%s\"): file descriptor
preparation failure: %s\n"),
+ scriptname, strerror(errno));
+ goto out_free;
+ }
+ if (posix_spawn_file_actions_adddup2(&fa, fd, STDIN_FILENO) ||
+ posix_spawn_file_actions_adddup2(&fa, fd, STDOUT_FILENO) ||
+ posix_spawn_file_actions_addclose(&fa, fd)) {
+ fprintf(stderr, _("device_script(\"%s\"): file descriptor
preparation failure: %s\n"),
+ scriptname, strerror(errno));
+ goto out_destroy;
+ }
+ if (posix_spawn(&pid, scriptname, &fa, NULL, NULL, envp)) {
+ fprintf(stderr, _("device_script(\"%s\"): script execution
failure: %s\n"),
+ scriptname, strerror(errno));
+ goto out_destroy;
+ }
+
+ if (pid != waitpid(pid, &status, 0) && WIFEXITED(status) &&
!WEXITSTATUS(status)) {
+ fprintf(stderr, _("device_script(\"%s\"): child script
execution failure: %s, exit code=%d\n"), scriptname,
+ (WIFEXITED(status) ? _("normal exit") : _("abnormal
exit")),
+ (WIFEXITED(status) ? WEXITSTATUS(status) : -1));
+ } else {
+ ret = 0;
+ }
+
+out_destroy:
+ posix_spawn_file_actions_destroy(&fa);
+out_free:
+ free(env);
+out:
+ return ret;
+}
diff --git a/configure.ac b/configure.ac
index b427c393..49c21fd5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -927,6 +927,8 @@ AC_CHECK_FUNCS(mktime timegm gettimeofday select poll
wcrtomb)
AC_CHECK_FUNCS(strchr strdup strndup strstr strtol strtok strsep)
AC_CHECK_FUNCS(asprintf vasprintf snprintf vsnprintf getpass setenv)
AC_CHECK_FUNCS(getaddrinfo)
+AC_CHECK_FUNCS(posix_spawn)
+AM_CONDITIONAL([HAVE_POSIX_SPAWN], [test "x$ac_cv_func_posix_spawn" = xyes])
AC_CACHE_CHECK(for ISO C99 compliant snprintf,ac_cv_func_snprintf_c99,
[AC_TRY_RUN([
#include <stdio.h>
diff --git a/include/gnokii-internal.h b/include/gnokii-internal.h
index c4f6d625..e02e44ea 100644
--- a/include/gnokii-internal.h
+++ b/include/gnokii-internal.h
@@ -179,4 +179,13 @@ int strip_slashes(char *dest, const char *src, int maxlen,
int len);
/* authentication for at driver */
gn_error do_auth(gn_auth_type auth_type, struct gn_statemachine *state);
+#ifdef HAVE_POSIX_SPAWN
+int device_script(int fd, int connect, struct gn_statemachine *state);
+#else
+static int device_script(int fd, int connect, struct gn_statemachine *state)
+{
+ return 0;
+}
+#endif
+
#endif /* _gnokii_internal_h */
--
2.20.0.rc2
- [PATCH v2 1/8] Use the native autoconf support for cross-compilation, (continued)
[PATCH v2 4/8] Test for number of mkdir() arguments, Ladislav Michl, 2018/12/04
[PATCH 8/8] Remove cfg_foreach, Ladislav Michl, 2018/12/04
[PATCH v2 6/8] Refactor devices build, Ladislav Michl, 2018/12/04
[PATCH v2 7/8] Use posix_spawn to run external scripts,
Ladislav Michl <=
[PATCH 5/8] Fix compat.c compilation with mingw32, Ladislav Michl, 2018/12/04