]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
compat: Use more portable setproctitle from nginx
authorRoy Marples <roy@marples.name>
Tue, 15 Oct 2019 10:59:58 +0000 (11:59 +0100)
committerRoy Marples <roy@marples.name>
Tue, 15 Oct 2019 10:59:58 +0000 (11:59 +0100)
Hopefully works on older Linux and Solaris.

compat/setproctitle.c
compat/setproctitle.h
src/dhcpcd.c

index f5ff0ac0a46f3b24096bcce0556fa91d0db58a76..9350e5eedb9ce7e2017ba87ef7df3084d6990179 100644 (file)
 /*
- * lxc: linux Container library
+ * Copyright (C) 2002-2019 Igor Sysoev
+ * Copyright (C) 2011-2019 Nginx, Inc.
+ * All rights reserved.
  *
- * (C) Copyright IBM Corp. 2007, 2008
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
  *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
-#ifndef _GNU_SOURCE
-#define _GNU_SOURCE 1
-#endif
-#include <sys/prctl.h>
-#include <sys/syscall.h>
-
-#include <fcntl.h>
 #include <stdarg.h>
 #include <stdlib.h>
-#include <stdio.h>
 #include <string.h>
-#include <unistd.h>
 
 #include "config.h"
 
-#define prctl_arg(x) ((unsigned long)x)
-
-/*
- * Sets the process title to the specified title. Note that this may fail if
- * the kernel doesn't support PR_SET_MM_MAP (kernels <3.18).
- */
-int setproctitle(const char *fmt, ...)
-{
-       char title[1024], *tp, *progname;
-       va_list args;
-       int fd, i;
-       char *buf_ptr, *tmp_proctitle;
-       char buf[BUFSIZ];
-       int ret = 0;
-       ssize_t bytes_read = 0;
-       size_t len;
-       static char *proctitle = NULL;
-
-#if 0
-       progname = getprogname();
+#ifdef __sun
+#define SETPROCTITLE_PAD       ' '
 #else
-       progname = "dhcpcd";
+#define        SETPROCTITLE_PAD        '\0'
 #endif
-       tp = title;
-       tp += snprintf(title, sizeof(title), "%s: ", progname);
 
-       va_start(args, fmt);
-       vsnprintf(tp, sizeof(title) - strlen(progname), fmt, args);
-       va_end(args);
+static int setproctitle_argc;
+static char *setproctitle_argv_last;
+static char **setproctitle_argv;
+static char *setproctitle_buf;
 
-       /*
-        * We don't really need to know all of this stuff, but unfortunately
-        * PR_SET_MM_MAP requires us to set it all at once, so we have to
-        * figure it out anyway.
-        */
-       unsigned long start_data, end_data, start_brk, start_code, end_code,
-           start_stack, arg_start, arg_end, env_start, env_end;
-       long brk_val;
-       struct prctl_mm_map prctl_map;
-
-       fd = open("/proc/self/stat", O_RDONLY);
-       if (fd == -1)
-               return -1;
-       bytes_read = read(fd, buf, sizeof(buf) - 1);
-       close(fd);
-       if (bytes_read == -1)
+int
+setproctitle_init(int argc, char **argv)
+{
+       size_t i, len;
+       char *p;
+
+       len = 0;
+       for (i = 0; environ[i] != NULL; i++)
+                len += strlen(environ[i]) + 1;
+       if ((setproctitle_buf = malloc(len)) == NULL)
                return -1;
 
-       buf[bytes_read] = '\0';
+       setproctitle_argc = argc;
+       setproctitle_argv = argv;
+       setproctitle_argv_last = setproctitle_argv[0];
+       for (i = 0; setproctitle_argv[i] != NULL; i++) {
+               if (setproctitle_argv_last == setproctitle_argv[i])
+                       setproctitle_argv_last = setproctitle_argv[i] +
+                           strlen(setproctitle_argv[i]) + 1;
+       }
 
-       /* Skip the first 25 fields, column 26-28 are start_code, end_code,
-        * and start_stack */
-       buf_ptr = strchr(buf, ' ');
-       for (i = 0; i < 24; i++) {
-               if (!buf_ptr)
-                       return -1;
-               buf_ptr = strchr(buf_ptr + 1, ' ');
+       p = setproctitle_buf;
+       for (i = 0; environ[i] != NULL; i++) {
+               if (setproctitle_argv_last != environ[i])
+                       continue;
+               len = strlen(environ[i]) + 1;
+               setproctitle_argv_last = environ[i] + len;
+               strlcpy(p, environ[i], len);
+               environ[i] = p;
+               p += len;
        }
-       if (!buf_ptr)
-               return -1;
 
-       i = sscanf(buf_ptr, "%lu %lu %lu", &start_code, &end_code, &start_stack);
-       if (i != 3)
-               return -1;
+       setproctitle_argv_last--;
+       return 0;
+}
 
-       /* Skip the next 19 fields, column 45-51 are start_data to arg_end */
-       for (i = 0; i < 19; i++) {
-               if (!buf_ptr)
-                       return -1;
-               buf_ptr = strchr(buf_ptr + 1, ' ');
-       }
+void
+setproctitle_free(void)
+{
 
-       if (!buf_ptr)
-               return -1;
+       free(setproctitle_buf);
+}
 
-       i = sscanf(buf_ptr, "%lu %lu %lu %*u %*u %lu %lu", &start_data,
-                  &end_data, &start_brk, &env_start, &env_end);
-       if (i != 5)
-               return -1;
+void
+setproctitle(const char *fmt, ...)
+{
+       const char *progname;
+       char *p;
+       int n;
+       va_list args;
+#if 0
+       progname = getprogname();
+#else
+       progname = "dhcpcd";
+#endif
 
-       /* Include the null byte here, because in the calculations below we
-        * want to have room for it. */
-       len = strlen(title) + 1;
+       setproctitle_argv[1] = NULL;
+#define        LAST_SIZE       (size_t)(setproctitle_argv_last - p)
 
-       tmp_proctitle = realloc(proctitle, len);
-       if (!tmp_proctitle)
-               return -1;
+       p = setproctitle_argv[0];
+       n = snprintf(p, LAST_SIZE, "%s: ", progname);
+       if (n == -1)
+               return;
+       p += n;
+
+       va_start(args, fmt);
+       n = vsnprintf(p, LAST_SIZE, fmt, args);
+       va_end(args);
+       if (n == -1)
+               return;
+       p += n;
+
+#ifdef __sun
+       size_t len;
+       int i;
+
+       len = 0;
+       for (i = 0; i < setproctitle_argc; i++)
+               len += strlen(setproctitle_argv[i]) + 1;
+
+       if (len > (size_t)(p - setproctitle_argv[0])) {
+               p += strlcpy(p, " (", LAST_SIZE);
+               for (i = 0; i < setproctitle_argc; i++) {
+                       p += strlcpy(p, setproctitle_argv[i], LAST_SIZE);
+                       p += strlcpy(p, " ", LAST_SIZE);
+               }
+       }
+#endif
 
-       proctitle = tmp_proctitle;
-
-       arg_start = (unsigned long)proctitle;
-       arg_end = arg_start + len;
-
-       brk_val = syscall(__NR_brk, 0);
-
-       prctl_map = (struct prctl_mm_map){
-           .start_code = start_code,
-           .end_code = end_code,
-           .start_stack = start_stack,
-           .start_data = start_data,
-           .end_data = end_data,
-           .start_brk = start_brk,
-           .brk = (unsigned long long)brk_val,
-           .arg_start = arg_start,
-           .arg_end = arg_end,
-           .env_start = env_start,
-           .env_end = env_end,
-           .auxv = NULL,
-           .auxv_size = 0,
-           .exe_fd = (unsigned int)-1,
-       };
-
-       ret = prctl(PR_SET_MM, prctl_arg(PR_SET_MM_MAP), prctl_arg(&prctl_map),
-                   prctl_arg(sizeof(prctl_map)), prctl_arg(0));
-       if (ret == 0)
-               (void)strlcpy((char *)arg_start, title, len);
-       return ret;
+       if (setproctitle_argv_last - p > 0)
+               memset(p, SETPROCTITLE_PAD, LAST_SIZE);
 }
index 2fe685f144bf35f658aafddb0ec68bd993ba9fc7..1824994780d7ae7f27238b3453698258a50f3ee2 100644 (file)
@@ -1,24 +1,28 @@
 /*
- * lxc: linux Container library
+ * Copyright (C) 2002-2019 Igor Sysoev
+ * Copyright (C) 2011-2019 Nginx, Inc.
+ * All rights reserved.
  *
- * (C) Copyright IBM Corp. 2007, 2008
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
  *
- * Authors:
- * Daniel Lezcano <daniel.lezcano at free.fr>
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2.1 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef SETPROCTITLE_H
@@ -32,5 +36,7 @@
 #endif
 #endif /* !__printflike */
 
-__printflike(1, 2) int setproctitle(const char *, ...);
+int setproctitle_init(int, char **);
+void setproctitle_free(void);
+__printflike(1, 2) void setproctitle(const char *, ...);
 #endif
index 193414ed67bbd6fb867bf14e3abd61c18b0633a9..85d9081f56298460e64e4b58dcdb68f9f32d5e24 100644 (file)
@@ -1549,6 +1549,47 @@ dhcpcd_handleargs(struct dhcpcd_ctx *ctx, struct fd_list *fd,
        return 0;
 }
 
+static int
+dhcpcd_saveargv(struct dhcpcd_ctx *ctx, int argc, char **argv)
+{
+#ifdef SETPROCTITLE_H
+       int i;
+
+       ctx->argv = reallocarray(ctx->argv, (size_t)argc + 1, sizeof(char *));
+       if (ctx->argv == NULL) {
+               logerr(__func__);
+               return -1;
+       }
+
+       ctx->argc = argc;
+       for (i = 0; i < argc; i++) {
+               if ((ctx->argv[i] = strdup(argv[i])) == NULL) {
+                       logerr(__func__);
+                       return -1;
+               }
+       }
+
+       ctx->argv[i] = NULL;
+#else
+       ctx->argv = argv;
+       ctx->argc = argc;
+#endif
+       return 0;
+
+}
+
+static void
+dhcpcd_freeargv(struct dhcpcd_ctx *ctx)
+{
+#ifdef SETPROCTITLE_H
+       int i;
+
+       for (i = 0; i < ctx->argc; i++)
+               free(ctx->argv[i]);
+       free(ctx->argv);
+#endif
+}
+
 int
 main(int argc, char **argv)
 {
@@ -1691,8 +1732,8 @@ main(int argc, char **argv)
        logsetopts(logopts);
        logopen(ctx.logfile);
 
-       ctx.argv = argv;
-       ctx.argc = argc;
+       if (dhcpcd_saveargv(&ctx, argc, argv) == -1)
+               goto exit_failure;
        ctx.ifc = argc - optind;
        ctx.ifv = argv + optind;
 
@@ -1702,7 +1743,7 @@ main(int argc, char **argv)
                        goto printpidfile;
                goto exit_failure;
        }
-       opt = add_options(&ctx, NULL, ifo, argc, argv);
+       opt = add_options(&ctx, NULL, ifo, ctx.argc, ctx.argv);
        if (opt != 1) {
                if (ctx.options & DHCPCD_PRINT_PIDFILE)
                        goto printpidfile;
@@ -1717,7 +1758,7 @@ main(int argc, char **argv)
                        ifo = read_config(&ctx, argv[optind], NULL, NULL);
                        if (ifo == NULL)
                                goto exit_failure;
-                       add_options(&ctx, NULL, ifo, argc, argv);
+                       add_options(&ctx, NULL, ifo, ctx.argc, ctx.argv);
                }
                if_printoptions();
 #ifdef INET
@@ -1840,7 +1881,7 @@ printpidfile:
                        logerr("%s: if_discover", __func__);
                        goto exit_failure;
                }
-               ifp = if_find(ctx.ifaces, argv[optind]);
+               ifp = if_find(ctx.ifaces, ctx.argv[optind]);
                if (ifp == NULL) {
                        ifp = calloc(1, sizeof(*ifp));
                        if (ifp == NULL) {
@@ -1848,7 +1889,7 @@ printpidfile:
                                goto exit_failure;
                        }
                        if (optind != argc)
-                               strlcpy(ctx.pidfile, argv[optind],
+                               strlcpy(ctx.pidfile, ctx.argv[optind],
                                    sizeof(ctx.pidfile));
                        ifp->ctx = &ctx;
                        TAILQ_INSERT_HEAD(ctx.ifaces, ifp, next);
@@ -1984,6 +2025,9 @@ printpidfile:
        logdebugx(PACKAGE "-" VERSION " starting");
        ctx.options |= DHCPCD_STARTED;
 
+#ifdef SETPROCTITLE_H
+       setproctitle_init(argc, argv);
+#endif
        setproctitle("%s%s%s",
            ctx.options & DHCPCD_MASTER ? "[master]" : argv[optind],
            ctx.options & DHCPCD_IPV4 ? " [ip4]" : "",
@@ -2044,7 +2088,7 @@ printpidfile:
 
        TAILQ_FOREACH(ifp, ctx.ifaces, next) {
                if (ifp->active)
-                       dhcpcd_initstate1(ifp, argc, argv, 0);
+                       dhcpcd_initstate1(ifp, ctx.argc, ctx.argv, 0);
        }
        if_learnaddrs(&ctx, ctx.ifaces, &ifaddrs);
 
@@ -2153,6 +2197,10 @@ exit1:
                loginfox(PACKAGE " exited");
        logclose();
        free(ctx.logfile);
+       dhcpcd_freeargv(&ctx);
+#ifdef SETPROCTITLE_H
+       setproctitle_free();
+#endif
 #ifdef USE_SIGNALS
        if (ctx.options & DHCPCD_FORKED)
                _exit(i); /* so atexit won't remove our pidfile */