blob: 90a94ce47fdb41557bb2a70c7e2287937ed2b1f0 [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
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010031static void locate_haproxy(char *buffer, size_t buffer_size)
32{
Willy Tarreaue5eddaf2014-04-14 15:34:34 +020033 char *end = NULL;
34
Lukas Tribus439cfde2013-12-10 08:32:56 +010035 if (readlink("/proc/self/exe", buffer, buffer_size) > 0)
36 end = strrchr(buffer, '/');
Willy Tarreaue5eddaf2014-04-14 15:34:34 +020037
38 if (end == NULL) {
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010039 strncpy(buffer, "/usr/sbin/haproxy", buffer_size);
Willy Tarreaue5eddaf2014-04-14 15:34:34 +020040 return;
41 }
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010042 end[1] = '\0';
Willy Tarreaue5eddaf2014-04-14 15:34:34 +020043 strncpy(end + 1, "haproxy", buffer + buffer_size - (end + 1));
44 buffer[buffer_size - 1] = '\0';
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010045}
46
Marc-Antoine Perennou47f922d2013-04-02 13:53:21 +020047static void spawn_haproxy(char **pid_strv, int nb_pid)
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010048{
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010049 char haproxy_bin[512];
50 pid_t pid;
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +030051 int main_argc;
52 char **main_argv;
53
54 main_argc = wrapper_argc - 1;
55 main_argv = wrapper_argv + 1;
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010056
57 pid = fork();
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010058 if (!pid) {
59 /* 3 for "haproxy -Ds -sf" */
60 char **argv = calloc(4 + main_argc + nb_pid + 1, sizeof(char *));
61 int i;
62 int argno = 0;
Kristoffer Grönlund1b6e75f2013-11-22 11:06:34 +010063 locate_haproxy(haproxy_bin, 512);
64 argv[argno++] = haproxy_bin;
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010065 for (i = 0; i < main_argc; ++i)
66 argv[argno++] = main_argv[i];
67 argv[argno++] = "-Ds";
68 if (nb_pid > 0) {
69 argv[argno++] = "-sf";
70 for (i = 0; i < nb_pid; ++i)
71 argv[argno++] = pid_strv[i];
72 }
73 argv[argno] = NULL;
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +010074
Apollon Oikonomopoulos6b6f3a02014-04-17 16:39:29 +030075 fprintf(stderr, SD_DEBUG "haproxy-systemd-wrapper: executing ");
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +010076 for (i = 0; argv[i]; ++i)
Apollon Oikonomopoulos6b6f3a02014-04-17 16:39:29 +030077 fprintf(stderr, "%s ", argv[i]);
78 fprintf(stderr, "\n");
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +010079
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010080 execv(argv[0], argv);
81 exit(0);
82 }
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +010083}
84
85static int read_pids(char ***pid_strv)
86{
87 FILE *f = fopen(pid_file, "r");
88 int read = 0, allocated = 8;
89 char pid_str[10];
90
91 if (!f)
92 return 0;
93
94 *pid_strv = malloc(allocated * sizeof(char *));
95 while (1 == fscanf(f, "%s\n", pid_str)) {
96 if (read == allocated) {
97 allocated *= 2;
98 *pid_strv = realloc(*pid_strv, allocated * sizeof(char *));
99 }
100 (*pid_strv)[read++] = strdup(pid_str);
101 }
102
103 fclose(f);
104
105 return read;
106}
107
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200108static void signal_handler(int signum)
109{
110 caught_signal = signum;
111}
112
113static void do_restart(void)
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100114{
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300115 setenv(REEXEC_FLAG, "1", 1);
Apollon Oikonomopoulos6b6f3a02014-04-17 16:39:29 +0300116 fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: re-executing\n");
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100117
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300118 execv(wrapper_argv[0], wrapper_argv);
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100119}
120
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200121static void do_shutdown(void)
Kristoffer Grönlund66fd1d82013-11-22 11:09:39 +0100122{
123 int i, pid;
124 char **pid_strv = NULL;
125 int nb_pid = read_pids(&pid_strv);
126 for (i = 0; i < nb_pid; ++i) {
127 pid = atoi(pid_strv[i]);
128 if (pid > 0) {
Apollon Oikonomopoulos6b6f3a02014-04-17 16:39:29 +0300129 fprintf(stderr, SD_DEBUG "haproxy-systemd-wrapper: SIGINT -> %d\n", pid);
Kristoffer Grönlund66fd1d82013-11-22 11:09:39 +0100130 kill(pid, SIGINT);
131 free(pid_strv[i]);
132 }
133 }
134 free(pid_strv);
135}
136
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100137static void init(int argc, char **argv)
138{
139 while (argc > 1) {
Conrad Hoffmann715e9b82014-07-28 23:22:43 +0200140 if ((*argv)[0] == '-' && (*argv)[1] == 'p') {
141 pid_file = *(argv + 1);
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100142 }
143 --argc; ++argv;
144 }
145}
146
147int main(int argc, char **argv)
148{
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +0100149 int status;
150
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300151 wrapper_argc = argc;
152 wrapper_argv = argv;
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100153
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300154 --argc; ++argv;
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100155 init(argc, argv);
156
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200157 struct sigaction sa;
158 memset(&sa, 0, sizeof(struct sigaction));
159 sa.sa_handler = &signal_handler;
160 sigaction(SIGUSR2, &sa, NULL);
161 sigaction(SIGINT, &sa, NULL);
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100162
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300163 if (getenv(REEXEC_FLAG) != NULL) {
164 /* We are being re-executed: restart HAProxy gracefully */
165 int i;
166 char **pid_strv = NULL;
167 int nb_pid = read_pids(&pid_strv);
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300168
169 unsetenv(REEXEC_FLAG);
170 spawn_haproxy(pid_strv, nb_pid);
171
Apollon Oikonomopoulosb3fce6e2014-04-17 16:39:28 +0300172 for (i = 0; i < nb_pid; ++i)
173 free(pid_strv[i]);
174 free(pid_strv);
175 }
176 else {
177 /* Start a fresh copy of HAProxy */
178 spawn_haproxy(NULL, 0);
179 }
180
Kristoffer Grönlundf65194a2013-11-22 11:11:54 +0100181 status = -1;
Conrad Hoffmann62c85652014-07-28 23:52:20 +0200182 while (-1 != wait(&status) || errno == EINTR) {
183 if (caught_signal == SIGUSR2) {
184 caught_signal = 0;
185 do_restart();
186 }
187 else if (caught_signal == SIGINT) {
188 caught_signal = 0;
189 do_shutdown();
190 }
191 }
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100192
Apollon Oikonomopoulos6b6f3a02014-04-17 16:39:29 +0300193 fprintf(stderr, SD_NOTICE "haproxy-systemd-wrapper: exit, haproxy RC=%d\n",
194 status);
Apollon Oikonomopoulose8ea5982014-04-17 16:39:30 +0300195 return status;
Marc-Antoine Perennoued9803e2013-02-12 10:53:53 +0100196}