Mercurial > hg-stable
annotate contrib/chg/util.c @ 28084:3fc45956c978
chg: initialize sigaction fields more reliably
It seems calling memset() and sigemptyset() is common pattern to initialize
sigaction. And strictly speaking, sigset_t must be initialized by sigemptyset()
or sigfillset(). I saw git and uwsgi do that way, so let's follow them.
author | Yuya Nishihara <yuya@tcha.org> |
---|---|
date | Fri, 29 Jan 2016 22:42:22 +0900 |
parents | 726f8d6cc324 |
children | c6705c6303dd |
rev | line source |
---|---|
28060 | 1 /* |
2 * Utility functions | |
3 * | |
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org> | |
5 * | |
6 * This software may be used and distributed according to the terms of the | |
7 * GNU General Public License version 2 or any later version. | |
8 */ | |
9 | |
10 #include <signal.h> | |
11 #include <stdarg.h> | |
12 #include <stdio.h> | |
13 #include <stdlib.h> | |
28084
3fc45956c978
chg: initialize sigaction fields more reliably
Yuya Nishihara <yuya@tcha.org>
parents:
28060
diff
changeset
|
14 #include <string.h> |
28060 | 15 #include <sys/types.h> |
16 #include <sys/wait.h> | |
17 #include <unistd.h> | |
18 | |
19 #include "util.h" | |
20 | |
21 void abortmsg(const char *fmt, ...) | |
22 { | |
23 va_list args; | |
24 va_start(args, fmt); | |
25 fputs("\033[1;31mchg: abort: ", stderr); | |
26 vfprintf(stderr, fmt, args); | |
27 fputs("\033[m\n", stderr); | |
28 va_end(args); | |
29 | |
30 exit(255); | |
31 } | |
32 | |
33 static int debugmsgenabled = 0; | |
34 | |
35 void enabledebugmsg(void) | |
36 { | |
37 debugmsgenabled = 1; | |
38 } | |
39 | |
40 void debugmsg(const char *fmt, ...) | |
41 { | |
42 if (!debugmsgenabled) | |
43 return; | |
44 | |
45 va_list args; | |
46 va_start(args, fmt); | |
47 fputs("\033[1;30mchg: debug: ", stderr); | |
48 vfprintf(stderr, fmt, args); | |
49 fputs("\033[m\n", stderr); | |
50 va_end(args); | |
51 } | |
52 | |
53 /* | |
54 * Execute a shell command in mostly the same manner as system(), with the | |
55 * give environment variables, after chdir to the given cwd. Returns a status | |
56 * code compatible with the Python subprocess module. | |
57 */ | |
58 int runshellcmd(const char *cmd, const char *envp[], const char *cwd) | |
59 { | |
60 enum { F_SIGINT = 1, F_SIGQUIT = 2, F_SIGMASK = 4, F_WAITPID = 8 }; | |
61 unsigned int doneflags = 0; | |
62 int status = 0; | |
63 struct sigaction newsa, oldsaint, oldsaquit; | |
64 sigset_t oldmask; | |
65 | |
66 /* block or mask signals just as system() does */ | |
28084
3fc45956c978
chg: initialize sigaction fields more reliably
Yuya Nishihara <yuya@tcha.org>
parents:
28060
diff
changeset
|
67 memset(&newsa, 0, sizeof(newsa)); |
28060 | 68 newsa.sa_handler = SIG_IGN; |
69 newsa.sa_flags = 0; | |
70 if (sigemptyset(&newsa.sa_mask) < 0) | |
71 goto done; | |
72 if (sigaction(SIGINT, &newsa, &oldsaint) < 0) | |
73 goto done; | |
74 doneflags |= F_SIGINT; | |
75 if (sigaction(SIGQUIT, &newsa, &oldsaquit) < 0) | |
76 goto done; | |
77 doneflags |= F_SIGQUIT; | |
78 | |
79 if (sigaddset(&newsa.sa_mask, SIGCHLD) < 0) | |
80 goto done; | |
81 if (sigprocmask(SIG_BLOCK, &newsa.sa_mask, &oldmask) < 0) | |
82 goto done; | |
83 doneflags |= F_SIGMASK; | |
84 | |
85 pid_t pid = fork(); | |
86 if (pid < 0) | |
87 goto done; | |
88 if (pid == 0) { | |
89 sigaction(SIGINT, &oldsaint, NULL); | |
90 sigaction(SIGQUIT, &oldsaquit, NULL); | |
91 sigprocmask(SIG_SETMASK, &oldmask, NULL); | |
92 if (cwd && chdir(cwd) < 0) | |
93 _exit(127); | |
94 const char *argv[] = {"sh", "-c", cmd, NULL}; | |
95 if (envp) { | |
96 execve("/bin/sh", (char **)argv, (char **)envp); | |
97 } else { | |
98 execv("/bin/sh", (char **)argv); | |
99 } | |
100 _exit(127); | |
101 } else { | |
102 if (waitpid(pid, &status, 0) < 0) | |
103 goto done; | |
104 doneflags |= F_WAITPID; | |
105 } | |
106 | |
107 done: | |
108 if (doneflags & F_SIGINT) | |
109 sigaction(SIGINT, &oldsaint, NULL); | |
110 if (doneflags & F_SIGQUIT) | |
111 sigaction(SIGQUIT, &oldsaquit, NULL); | |
112 if (doneflags & F_SIGMASK) | |
113 sigprocmask(SIG_SETMASK, &oldmask, NULL); | |
114 | |
115 /* no way to report other errors, use 127 (= shell termination) */ | |
116 if (!(doneflags & F_WAITPID)) | |
117 return 127; | |
118 if (WIFEXITED(status)) | |
119 return WEXITSTATUS(status); | |
120 if (WIFSIGNALED(status)) | |
121 return -WTERMSIG(status); | |
122 return 127; | |
123 } |