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