Mercurial > hg
annotate contrib/chg/util.c @ 28854:ddef14468952
chg: add fchdirx as a utility function
As part of the series to support long socket paths, we need to use fchdir and
check its result in several places. Make it a utility function.
author | Jun Wu <quark@fb.com> |
---|---|
date | Sun, 10 Apr 2016 03:14:32 +0100 |
parents | 57a78a64de44 |
children | f5764e177bbe |
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 | |
28788
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
10 #include <errno.h> |
28060 | 11 #include <signal.h> |
12 #include <stdarg.h> | |
13 #include <stdio.h> | |
14 #include <stdlib.h> | |
28084
3fc45956c978
chg: initialize sigaction fields more reliably
Yuya Nishihara <yuya@tcha.org>
parents:
28060
diff
changeset
|
15 #include <string.h> |
28060 | 16 #include <sys/types.h> |
17 #include <sys/wait.h> | |
18 #include <unistd.h> | |
19 | |
20 #include "util.h" | |
21 | |
28787
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
22 static int colorenabled = 0; |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
23 |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
24 static inline void fsetcolor(FILE *fp, const char *code) |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
25 { |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
26 if (!colorenabled) |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
27 return; |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
28 fprintf(fp, "\033[%sm", code); |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
29 } |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
30 |
28788
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
31 static void vabortmsgerrno(int no, const char *fmt, va_list args) |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
32 { |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
33 fsetcolor(stderr, "1;31"); |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
34 fputs("chg: abort: ", stderr); |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
35 vfprintf(stderr, fmt, args); |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
36 if (no != 0) |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
37 fprintf(stderr, " (errno = %d, %s)", no, strerror(no)); |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
38 fsetcolor(stderr, ""); |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
39 fputc('\n', stderr); |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
40 exit(255); |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
41 } |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
42 |
28060 | 43 void abortmsg(const char *fmt, ...) |
44 { | |
45 va_list args; | |
46 va_start(args, fmt); | |
28788
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
47 vabortmsgerrno(0, fmt, args); |
28060 | 48 va_end(args); |
28788
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
49 } |
28060 | 50 |
28788
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
51 void abortmsgerrno(const char *fmt, ...) |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
52 { |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
53 int no = errno; |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
54 va_list args; |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
55 va_start(args, fmt); |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
56 vabortmsgerrno(no, fmt, args); |
57a78a64de44
chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents:
28787
diff
changeset
|
57 va_end(args); |
28060 | 58 } |
59 | |
60 static int debugmsgenabled = 0; | |
61 | |
28787
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
62 void enablecolor(void) |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
63 { |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
64 colorenabled = 1; |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
65 } |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
66 |
28060 | 67 void enabledebugmsg(void) |
68 { | |
69 debugmsgenabled = 1; | |
70 } | |
71 | |
72 void debugmsg(const char *fmt, ...) | |
73 { | |
74 if (!debugmsgenabled) | |
75 return; | |
76 | |
77 va_list args; | |
78 va_start(args, fmt); | |
28787
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
79 fsetcolor(stderr, "1;30"); |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
80 fputs("chg: debug: ", stderr); |
28060 | 81 vfprintf(stderr, fmt, args); |
28787
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
82 fsetcolor(stderr, ""); |
ea86cdcd9b50
chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents:
28165
diff
changeset
|
83 fputc('\n', stderr); |
28060 | 84 va_end(args); |
85 } | |
86 | |
28854
ddef14468952
chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents:
28788
diff
changeset
|
87 void fchdirx(int dirfd) |
ddef14468952
chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents:
28788
diff
changeset
|
88 { |
ddef14468952
chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents:
28788
diff
changeset
|
89 int r = fchdir(dirfd); |
ddef14468952
chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents:
28788
diff
changeset
|
90 if (r == -1) |
ddef14468952
chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents:
28788
diff
changeset
|
91 abortmsgerrno("failed to fchdir"); |
ddef14468952
chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents:
28788
diff
changeset
|
92 } |
ddef14468952
chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents:
28788
diff
changeset
|
93 |
28165
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
94 void *mallocx(size_t size) |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
95 { |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
96 void *result = malloc(size); |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
97 if (!result) |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
98 abortmsg("failed to malloc"); |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
99 return result; |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
100 } |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
101 |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
102 void *reallocx(void *ptr, size_t size) |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
103 { |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
104 void *result = realloc(ptr, size); |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
105 if (!result) |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
106 abortmsg("failed to realloc"); |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
107 return result; |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
108 } |
c6705c6303dd
chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents:
28084
diff
changeset
|
109 |
28060 | 110 /* |
111 * Execute a shell command in mostly the same manner as system(), with the | |
112 * give environment variables, after chdir to the given cwd. Returns a status | |
113 * code compatible with the Python subprocess module. | |
114 */ | |
115 int runshellcmd(const char *cmd, const char *envp[], const char *cwd) | |
116 { | |
117 enum { F_SIGINT = 1, F_SIGQUIT = 2, F_SIGMASK = 4, F_WAITPID = 8 }; | |
118 unsigned int doneflags = 0; | |
119 int status = 0; | |
120 struct sigaction newsa, oldsaint, oldsaquit; | |
121 sigset_t oldmask; | |
122 | |
123 /* 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
|
124 memset(&newsa, 0, sizeof(newsa)); |
28060 | 125 newsa.sa_handler = SIG_IGN; |
126 newsa.sa_flags = 0; | |
127 if (sigemptyset(&newsa.sa_mask) < 0) | |
128 goto done; | |
129 if (sigaction(SIGINT, &newsa, &oldsaint) < 0) | |
130 goto done; | |
131 doneflags |= F_SIGINT; | |
132 if (sigaction(SIGQUIT, &newsa, &oldsaquit) < 0) | |
133 goto done; | |
134 doneflags |= F_SIGQUIT; | |
135 | |
136 if (sigaddset(&newsa.sa_mask, SIGCHLD) < 0) | |
137 goto done; | |
138 if (sigprocmask(SIG_BLOCK, &newsa.sa_mask, &oldmask) < 0) | |
139 goto done; | |
140 doneflags |= F_SIGMASK; | |
141 | |
142 pid_t pid = fork(); | |
143 if (pid < 0) | |
144 goto done; | |
145 if (pid == 0) { | |
146 sigaction(SIGINT, &oldsaint, NULL); | |
147 sigaction(SIGQUIT, &oldsaquit, NULL); | |
148 sigprocmask(SIG_SETMASK, &oldmask, NULL); | |
149 if (cwd && chdir(cwd) < 0) | |
150 _exit(127); | |
151 const char *argv[] = {"sh", "-c", cmd, NULL}; | |
152 if (envp) { | |
153 execve("/bin/sh", (char **)argv, (char **)envp); | |
154 } else { | |
155 execv("/bin/sh", (char **)argv); | |
156 } | |
157 _exit(127); | |
158 } else { | |
159 if (waitpid(pid, &status, 0) < 0) | |
160 goto done; | |
161 doneflags |= F_WAITPID; | |
162 } | |
163 | |
164 done: | |
165 if (doneflags & F_SIGINT) | |
166 sigaction(SIGINT, &oldsaint, NULL); | |
167 if (doneflags & F_SIGQUIT) | |
168 sigaction(SIGQUIT, &oldsaquit, NULL); | |
169 if (doneflags & F_SIGMASK) | |
170 sigprocmask(SIG_SETMASK, &oldmask, NULL); | |
171 | |
172 /* no way to report other errors, use 127 (= shell termination) */ | |
173 if (!(doneflags & F_WAITPID)) | |
174 return 127; | |
175 if (WIFEXITED(status)) | |
176 return WEXITSTATUS(status); | |
177 if (WIFSIGNALED(status)) | |
178 return -WTERMSIG(status); | |
179 return 127; | |
180 } |