2 * Copyright (C) 2012-2020 all contributors <cmogstored-public@yhbt.net>
3 * License: GPL-3.0+ <https://www.gnu.org/licenses/gpl-3.0.txt>
5 #include "cmogstored.h"
6 #include "compat_memstream.h"
13 #define FD_PFX "CMOGSTORED_FD="
15 MOG_NOINLINE
static void free_list(char **head
)
26 /* only needed to make valgrind happy */
27 __attribute__((destructor
)) static void upgrade_atexit(void)
29 free_list(start
.argv
);
30 free_list(start
.envp
);
33 void mog_upgrade_prepare(int argc
, char *argv
[], char *envp
[])
36 size_t env_count
= 2; /* extra for NULL-termination and CMOGSTORED_FD */
40 start
.argv
= xmalloc(sizeof(char *) * (argc
+ 1));
41 for (i
= 0; i
< argc
; i
++)
42 start
.argv
[i
] = xstrdup(argv
[i
]);
43 start
.argv
[argc
] = NULL
;
45 /* allocate slots for envp */
46 for (e
= envp
; *e
; e
++)
48 start
.envp
= xmalloc(sizeof(char *) * env_count
);
52 *e
++ = xstrdup(FD_PFX
); /* placeholder */
53 for (; *envp
; envp
++) {
54 if (strncmp(*envp
, FD_PFX
, strlen(FD_PFX
)))
55 *e
++ = xstrdup(*envp
);
60 /* writes one comma-delimited fd to fp */
61 static bool emit_fd(FILE *fp
, struct mog_fd
*mfd
)
65 /* no error, just the FD isn't used */
70 r
= fprintf(fp
, "%d,", mfd
->fd
);
75 syslog(LOG_ERR
, "fprintf() failed: %m");
79 static bool svc_emit_fd_i(void *svcptr
, void *_fp
)
82 struct mog_svc
*svc
= svcptr
;
84 return (emit_fd(fp
, svc
->mgmt_mfd
)
85 && emit_fd(fp
, svc
->http_mfd
)
86 && emit_fd(fp
, svc
->httpget_mfd
));
89 /* returns the PID of the newly spawned child */
90 pid_t
mog_upgrade_spawn(void)
99 if (!mog_pidfile_upgrade_prepare())
102 fp
= open_memstream(&dst
, &bytes
);
104 syslog(LOG_ERR
, "open_memstream failed for upgrade: %m");
108 execfile
= find_in_path(start
.argv
[0]);
110 rc
= fputs(FD_PFX
, fp
);
111 if (rc
< 0 || rc
== EOF
) {
114 PRESERVE_ERRNO( (void)fclose(fp
) );
115 syslog(LOG_ERR
, "fputs returned %d on memstream: %m", rc
);
119 mog_svc_each(svc_emit_fd_i
, fp
);
121 if ((my_memstream_close(fp
, &dst
, &bytes
) != 0) && (errno
!= EINTR
)) {
122 syslog(LOG_ERR
, "fclose on memstream failed for upgrade: %m");
126 assert(dst
[bytes
- 1] == ',' && "not comma-terminated no listeners?");
127 dst
[bytes
- 1] = '\0'; /* kill the last comma */
130 pid
= mog_fork_for_exec();
132 mog_svc_upgrade_prepare();
133 execve(execfile
, start
.argv
, start
.envp
);
135 } else if (pid
> 0) {
136 mog_process_register(pid
, MOG_PROC_UPGRADE
);
137 syslog(LOG_INFO
, "upgrade spawned PID:%d", pid
);
139 syslog(LOG_ERR
, "fork failed for upgrade: %m");
143 /* find_in_path does not malloc if output == input */
144 if (execfile
!= start
.argv
[0])