##// END OF EJS Templates
chg: add fchdirx as a utility function...
Jun Wu -
r28854:ddef1446 default
parent child Browse files
Show More
@@ -1,173 +1,180
1 1 /*
2 2 * Utility functions
3 3 *
4 4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 5 *
6 6 * This software may be used and distributed according to the terms of the
7 7 * GNU General Public License version 2 or any later version.
8 8 */
9 9
10 10 #include <errno.h>
11 11 #include <signal.h>
12 12 #include <stdarg.h>
13 13 #include <stdio.h>
14 14 #include <stdlib.h>
15 15 #include <string.h>
16 16 #include <sys/types.h>
17 17 #include <sys/wait.h>
18 18 #include <unistd.h>
19 19
20 20 #include "util.h"
21 21
22 22 static int colorenabled = 0;
23 23
24 24 static inline void fsetcolor(FILE *fp, const char *code)
25 25 {
26 26 if (!colorenabled)
27 27 return;
28 28 fprintf(fp, "\033[%sm", code);
29 29 }
30 30
31 31 static void vabortmsgerrno(int no, const char *fmt, va_list args)
32 32 {
33 33 fsetcolor(stderr, "1;31");
34 34 fputs("chg: abort: ", stderr);
35 35 vfprintf(stderr, fmt, args);
36 36 if (no != 0)
37 37 fprintf(stderr, " (errno = %d, %s)", no, strerror(no));
38 38 fsetcolor(stderr, "");
39 39 fputc('\n', stderr);
40 40 exit(255);
41 41 }
42 42
43 43 void abortmsg(const char *fmt, ...)
44 44 {
45 45 va_list args;
46 46 va_start(args, fmt);
47 47 vabortmsgerrno(0, fmt, args);
48 48 va_end(args);
49 49 }
50 50
51 51 void abortmsgerrno(const char *fmt, ...)
52 52 {
53 53 int no = errno;
54 54 va_list args;
55 55 va_start(args, fmt);
56 56 vabortmsgerrno(no, fmt, args);
57 57 va_end(args);
58 58 }
59 59
60 60 static int debugmsgenabled = 0;
61 61
62 62 void enablecolor(void)
63 63 {
64 64 colorenabled = 1;
65 65 }
66 66
67 67 void enabledebugmsg(void)
68 68 {
69 69 debugmsgenabled = 1;
70 70 }
71 71
72 72 void debugmsg(const char *fmt, ...)
73 73 {
74 74 if (!debugmsgenabled)
75 75 return;
76 76
77 77 va_list args;
78 78 va_start(args, fmt);
79 79 fsetcolor(stderr, "1;30");
80 80 fputs("chg: debug: ", stderr);
81 81 vfprintf(stderr, fmt, args);
82 82 fsetcolor(stderr, "");
83 83 fputc('\n', stderr);
84 84 va_end(args);
85 85 }
86 86
87 void fchdirx(int dirfd)
88 {
89 int r = fchdir(dirfd);
90 if (r == -1)
91 abortmsgerrno("failed to fchdir");
92 }
93
87 94 void *mallocx(size_t size)
88 95 {
89 96 void *result = malloc(size);
90 97 if (!result)
91 98 abortmsg("failed to malloc");
92 99 return result;
93 100 }
94 101
95 102 void *reallocx(void *ptr, size_t size)
96 103 {
97 104 void *result = realloc(ptr, size);
98 105 if (!result)
99 106 abortmsg("failed to realloc");
100 107 return result;
101 108 }
102 109
103 110 /*
104 111 * Execute a shell command in mostly the same manner as system(), with the
105 112 * give environment variables, after chdir to the given cwd. Returns a status
106 113 * code compatible with the Python subprocess module.
107 114 */
108 115 int runshellcmd(const char *cmd, const char *envp[], const char *cwd)
109 116 {
110 117 enum { F_SIGINT = 1, F_SIGQUIT = 2, F_SIGMASK = 4, F_WAITPID = 8 };
111 118 unsigned int doneflags = 0;
112 119 int status = 0;
113 120 struct sigaction newsa, oldsaint, oldsaquit;
114 121 sigset_t oldmask;
115 122
116 123 /* block or mask signals just as system() does */
117 124 memset(&newsa, 0, sizeof(newsa));
118 125 newsa.sa_handler = SIG_IGN;
119 126 newsa.sa_flags = 0;
120 127 if (sigemptyset(&newsa.sa_mask) < 0)
121 128 goto done;
122 129 if (sigaction(SIGINT, &newsa, &oldsaint) < 0)
123 130 goto done;
124 131 doneflags |= F_SIGINT;
125 132 if (sigaction(SIGQUIT, &newsa, &oldsaquit) < 0)
126 133 goto done;
127 134 doneflags |= F_SIGQUIT;
128 135
129 136 if (sigaddset(&newsa.sa_mask, SIGCHLD) < 0)
130 137 goto done;
131 138 if (sigprocmask(SIG_BLOCK, &newsa.sa_mask, &oldmask) < 0)
132 139 goto done;
133 140 doneflags |= F_SIGMASK;
134 141
135 142 pid_t pid = fork();
136 143 if (pid < 0)
137 144 goto done;
138 145 if (pid == 0) {
139 146 sigaction(SIGINT, &oldsaint, NULL);
140 147 sigaction(SIGQUIT, &oldsaquit, NULL);
141 148 sigprocmask(SIG_SETMASK, &oldmask, NULL);
142 149 if (cwd && chdir(cwd) < 0)
143 150 _exit(127);
144 151 const char *argv[] = {"sh", "-c", cmd, NULL};
145 152 if (envp) {
146 153 execve("/bin/sh", (char **)argv, (char **)envp);
147 154 } else {
148 155 execv("/bin/sh", (char **)argv);
149 156 }
150 157 _exit(127);
151 158 } else {
152 159 if (waitpid(pid, &status, 0) < 0)
153 160 goto done;
154 161 doneflags |= F_WAITPID;
155 162 }
156 163
157 164 done:
158 165 if (doneflags & F_SIGINT)
159 166 sigaction(SIGINT, &oldsaint, NULL);
160 167 if (doneflags & F_SIGQUIT)
161 168 sigaction(SIGQUIT, &oldsaquit, NULL);
162 169 if (doneflags & F_SIGMASK)
163 170 sigprocmask(SIG_SETMASK, &oldmask, NULL);
164 171
165 172 /* no way to report other errors, use 127 (= shell termination) */
166 173 if (!(doneflags & F_WAITPID))
167 174 return 127;
168 175 if (WIFEXITED(status))
169 176 return WEXITSTATUS(status);
170 177 if (WIFSIGNALED(status))
171 178 return -WTERMSIG(status);
172 179 return 127;
173 180 }
@@ -1,31 +1,32
1 1 /*
2 2 * Utility functions
3 3 *
4 4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
5 5 *
6 6 * This software may be used and distributed according to the terms of the
7 7 * GNU General Public License version 2 or any later version.
8 8 */
9 9
10 10 #ifndef UTIL_H_
11 11 #define UTIL_H_
12 12
13 13 #ifdef __GNUC__
14 14 #define PRINTF_FORMAT_ __attribute__((format(printf, 1, 2)))
15 15 #else
16 16 #define PRINTF_FORMAT_
17 17 #endif
18 18
19 19 void abortmsg(const char *fmt, ...) PRINTF_FORMAT_;
20 20 void abortmsgerrno(const char *fmt, ...) PRINTF_FORMAT_;
21 21
22 22 void enablecolor(void);
23 23 void enabledebugmsg(void);
24 24 void debugmsg(const char *fmt, ...) PRINTF_FORMAT_;
25 25
26 void fchdirx(int dirfd);
26 27 void *mallocx(size_t size);
27 28 void *reallocx(void *ptr, size_t size);
28 29
29 30 int runshellcmd(const char *cmd, const char *envp[], const char *cwd);
30 31
31 32 #endif /* UTIL_H_ */
General Comments 0
You need to be logged in to leave comments. Login now