blob: 4e4d039f757c1149178e23f30c376e03bb9786b4 [file] [log] [blame]
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +01001/*
2 * Wrapper to make haproxy systemd-compliant.
3 *
4 * Copyright 2013 Marc-Antoine Perennou <Marc-Antoine@Perennou.com>
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 */
12
13#include <errno.h>
14#include <signal.h>
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010015#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <unistd.h>
19#include <sys/wait.h>
20
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +030021#define REEXEC_FLAG "HAPROXY_SYSTEMD_REEXEC"
Apollon Oikonomopoulos6b6f3a02014-04-17 16:39:29 +030022#define SD_DEBUG "<7>"
23#define SD_NOTICE "<5>"
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +030024
Conrad Hoffmann62c85652014-07-28 23:52:20 +020025static volatile sig_atomic_t caught_signal;
26
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010027static char *pid_file = "/run/haproxy.pid";
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +030028static int wrapper_argc;
29static char **wrapper_argv;
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010030
Willy Tarreauafbfc272014-09-19 15:42:30 +020031/* returns the path to the haproxy binary into <buffer>, whose size indicated
32 * in <buffer_size> must be at least 1 byte long.
33 */
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010034static void locate_haproxy(char *buffer, size_t buffer_size)
35{
Willy Tarreaue5eddaf2014-04-14 15:34:34 +020036 char *end = NULL;
Willy Tarreauafbfc272014-09-19 15:42:30 +020037 int len;
Willy Tarreaue5eddaf2014-04-14 15:34:34 +020038
Willy Tarreauafbfc272014-09-19 15:42:30 +020039 len = readlink("/proc/self/exe", buffer, buffer_size - 1);
40 if (len == -1)
41 goto fail;
Willy Tarreaue5eddaf2014-04-14 15:34:34 +020042
Willy Tarreauafbfc272014-09-19 15:42:30 +020043 buffer[len] = 0;
44 end = strrchr(buffer, '/');
45 if (end == NULL)
46 goto fail;
47
48 if (strcmp(end + strlen(end) - 16, "-systemd-wrapper") == 0) {
49 end[strlen(end) - 16] = '\0';
Willy Tarreaue5eddaf2014-04-14 15:34:34 +020050 return;
51 }
Willy Tarreauafbfc272014-09-19 15:42:30 +020052
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010053 end[1] = '\0';
Willy Tarreaue5eddaf2014-04-14 15:34:34 +020054 strncpy(end + 1, "haproxy", buffer + buffer_size - (end + 1));
55 buffer[buffer_size - 1] = '\0';
Willy Tarreauafbfc272014-09-19 15:42:30 +020056 return;
57 fail:
58 strncpy(buffer, "/usr/sbin/haproxy", buffer_size);
59 buffer[buffer_size - 1] = '\0';
60 return;
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010061}
62
Marc-Antoine Perennou47f922d2013-04-02 13:53:21 +020063static void spawn_haproxy(char **pid_strv, int nb_pid)
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010064{
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010065 char haproxy_bin[512];
66 pid_t pid;
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +030067 int main_argc;
68 char **main_argv;
69
70 main_argc = wrapper_argc - 1;
71 main_argv = wrapper_argv + 1;
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010072
Willy Tarreau575e2992014-09-24 12:59:25 +020073 pid = fork();
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010074 if (!pid) {
75 /* 3 for "haproxy -Ds -sf" */
76 char **argv = calloc(4 + main_argc + nb_pid + 1, sizeof(char *));
77 int i;
78 int argno = 0;
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010079 locate_haproxy(haproxy_bin, 512);
80 argv[argno++] = haproxy_bin;
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010081 for (i = 0; i < main_argc; ++i)
82 argv[argno++] = main_argv[i];
83 argv[argno++] = "-Ds";
84 if (nb_pid > 0) {
85 argv[argno++] = "-sf";
86 for (i = 0; i < nb_pid; ++i)
87 argv[argno++] = pid_strv[i];
88 }
89 argv[argno] = NULL;
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +010090
Apollon Oikonomopoulos6b6f3a02014-04-17 16:39:29 +030091 fprintf(stderr, SD_DEBUG "haproxy-systemd-wrapper: executing ");
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +010092 for (i = 0; argv[i]; ++i)
Apollon Oikonomopoulos6b6f3a02014-04-17 16:39:29 +030093 fprintf(stderr, "%s ", argv[i]);
94 fprintf(stderr, "\n");
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +010095
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010096 execv(argv[0], argv);
97 exit(0);
98 }
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010099}
100
101static int read_pids(char ***pid_strv)
102{
103 FILE *f = fopen(pid_file, "r");
104 int read = 0, allocated = 8;
105 char pid_str[10];
106
107 if (!f)
108 return 0;
109
110 *pid_strv = malloc(allocated * sizeof(char *));
111 while (1 == fscanf(f, "%s\n", pid_str)) {
112 if (read == allocated) {
113 allocated *= 2;
114 *pid_strv = realloc(*pid_strv, allocated * sizeof(char *));
115 }
116 (*pid_strv)[read++] = strdup(pid_str);
117 }
118
119 fclose(f);
120
121 return read;
122}
123
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200124static void signal_handler(int signum)
125{
Willy Tarreaua24f95d2016-02-27 08:26:14 +0100126 if (caught_signal != SIGINT && caught_signal != SIGTERM)
127 caught_signal = signum;
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200128}
129
Willy Tarreau60278b92016-02-27 08:18:04 +0100130/* handles SIGUSR2 and SIGHUP only */
131static void do_restart(int sig)
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100132{
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300133 setenv(REEXEC_FLAG, "1", 1);
Willy Tarreau60278b92016-02-27 08:18:04 +0100134 fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: re-executing on %s.\n",
135 sig == SIGUSR2 ? "SIGUSR2" : "SIGHUP");
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100136
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300137 execv(wrapper_argv[0], wrapper_argv);
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100138}
139
Willy Tarreau60278b92016-02-27 08:18:04 +0100140/* handles SIGTERM and SIGINT only */
141static void do_shutdown(int sig)
Kristoffer Grönlund66fd1d82013-11-22 11:09:39 +0100142{
143 int i, pid;
144 char **pid_strv = NULL;
145 int nb_pid = read_pids(&pid_strv);
146 for (i = 0; i < nb_pid; ++i) {
147 pid = atoi(pid_strv[i]);
148 if (pid > 0) {
Willy Tarreau60278b92016-02-27 08:18:04 +0100149 fprintf(stderr, SD_DEBUG "haproxy-systemd-wrapper: %s -> %d.\n",
150 sig == SIGTERM ? "SIGTERM" : "SIGINT", pid);
Willy Tarreau081753c2016-02-27 08:20:17 +0100151 kill(pid, sig);
Kristoffer Grönlund66fd1d82013-11-22 11:09:39 +0100152 free(pid_strv[i]);
153 }
154 }
155 free(pid_strv);
156}
157
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100158static void init(int argc, char **argv)
159{
160 while (argc > 1) {
Conrad Hoffmann715e9b82014-07-28 23:22:43 +0200161 if ((*argv)[0] == '-' && (*argv)[1] == 'p') {
162 pid_file = *(argv + 1);
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100163 }
164 --argc; ++argv;
165 }
166}
167
168int main(int argc, char **argv)
169{
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +0100170 int status;
171
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300172 wrapper_argc = argc;
173 wrapper_argv = argv;
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100174
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300175 --argc; ++argv;
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100176 init(argc, argv);
177
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200178 struct sigaction sa;
179 memset(&sa, 0, sizeof(struct sigaction));
180 sa.sa_handler = &signal_handler;
181 sigaction(SIGUSR2, &sa, NULL);
Matt Robenolt6bb7bf72014-09-11 05:19:30 +0000182 sigaction(SIGHUP, &sa, NULL);
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200183 sigaction(SIGINT, &sa, NULL);
Matt Robenolt6bb7bf72014-09-11 05:19:30 +0000184 sigaction(SIGTERM, &sa, NULL);
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100185
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300186 if (getenv(REEXEC_FLAG) != NULL) {
187 /* We are being re-executed: restart HAProxy gracefully */
188 int i;
189 char **pid_strv = NULL;
190 int nb_pid = read_pids(&pid_strv);
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300191
192 unsetenv(REEXEC_FLAG);
193 spawn_haproxy(pid_strv, nb_pid);
194
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300195 for (i = 0; i < nb_pid; ++i)
196 free(pid_strv[i]);
197 free(pid_strv);
198 }
199 else {
200 /* Start a fresh copy of HAProxy */
201 spawn_haproxy(NULL, 0);
202 }
203
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +0100204 status = -1;
Willy Tarreau1e7893c2016-02-27 07:58:50 +0100205 while (caught_signal || wait(&status) != -1 || errno == EINTR) {
Willy Tarreau60278b92016-02-27 08:18:04 +0100206 int sig = caught_signal;
207
Matt Robenolt6bb7bf72014-09-11 05:19:30 +0000208 if (caught_signal == SIGUSR2 || caught_signal == SIGHUP) {
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200209 caught_signal = 0;
Willy Tarreau60278b92016-02-27 08:18:04 +0100210 do_restart(sig);
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200211 }
Matt Robenolt6bb7bf72014-09-11 05:19:30 +0000212 else if (caught_signal == SIGINT || caught_signal == SIGTERM) {
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200213 caught_signal = 0;
Willy Tarreau60278b92016-02-27 08:18:04 +0100214 do_shutdown(sig);
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200215 }
216 }
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100217
Apollon Oikonomopoulos6b6f3a02014-04-17 16:39:29 +0300218 fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: exit, haproxy RC=%d\n",
219 status);
Apollon Oikonomopoulose8ea5982014-04-17 16:39:30 +0300220 return status;
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100221}