annotate contrib/chg/util.c @ 39772:ae531f5e583c

testing: add interface unit tests for file storage Our strategy for supporting alternate storage backends is to define interfaces for everything then "code to the interface." We already have interfaces for various primitives, including file and manifest storage. What we don't have is generic unit tests for those interfaces. Up to this point we've been relying on high-level integration tests (mainly in the form of existing .t tests) to test alternate storage backends. And my experience with developing the "simple store" test extension is that such testing is very tedious: it takes several minutes to run all tests and when you find a failure, it is often non-trivial to debug. This commit starts to change that. This commit introduces the mercurial.testing.storage module. It contains testing code for storage. Currently, it defines some unittest.TestCase classes for testing the file storage interfaces. It also defines some factory functions that allow a caller to easily spawn a custom TestCase "bound" to a specific file storage backend implementation. A new .py test has been added. It simply defines a callable to produce filelog and transaction instances on demand and then "registers" the various test classes so the filelog class can be tested with the storage interface unit tests. As part of writing the tests, I identified a couple of apparent bugs in revlog.py and filelog.py! These are tracked with inline TODO comments. Writing the tests makes it more obvious where the storage interface is lacking. For example, we raise either IndexError or error.LookupError for missing revisions depending on whether we use an integer revision or a node. Also, we raise error.RevlogError in various places when we should be raising a storage-agnostic error type. The storage interfaces are currently far from perfect and there is much work to be done to improve them. But at least with this commit we finally have the start of unit tests that can be used to "qualify" the behavior of a storage backend. And when implementing and debugging new storage backends, we now have an obvious place to define new tests and have obvious places to insert breakpoints to facilitate debugging. This should be invaluable when implementing new storage backends. I added the mercurial.testing package because these interface conformance tests are generic and need to be usable by all storage backends. Having the code live in tests/ would make it difficult for storage backends implemented in extensions to test their interface conformance. First, it would require obtaining a copy of Mercurial's storage test code in order to test. Second, it would make testing against multiple Mercurial versions difficult, as you would need to import N copies of the storage testing code in order to achieve test coverage. By making the test code part of the Mercurial distribution itself, extensions can `import mercurial.testing.*` to access and run the test code. The test will run against whatever Mercurial version is active. FWIW I've always wanted to move parts of run-tests.py into the mercurial.* package to make the testing story simpler (e.g. imagine an `hg debugruntests` command that could invoke the test harness). While I have no plans to do that in the near future, establishing the mercurial.testing package does provide a natural home for that code should someone do this in the future. Differential Revision: https://phab.mercurial-scm.org/D4650
author Gregory Szorc <gregory.szorc@gmail.com>
date Tue, 18 Sep 2018 16:52:11 -0700
parents 9724f54923ec
children 763b45bc4483
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
1 /*
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
2 * Utility functions
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
3 *
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
4 * Copyright (c) 2011 Yuya Nishihara <yuya@tcha.org>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
5 *
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
6 * This software may be used and distributed according to the terms of the
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
7 * GNU General Public License version 2 or any later version.
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
8 */
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
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
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
12 #include <signal.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
13 #include <stdarg.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
14 #include <stdio.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
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>
34309
b94db1780365 chg: show timestamp with debug messages
Jun Wu <quark@fb.com>
parents: 28855
diff changeset
17 #include <sys/time.h>
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
18 #include <sys/types.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
19 #include <sys/wait.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
20 #include <unistd.h>
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
21
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
22 #include "util.h"
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
23
28787
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
24 static int colorenabled = 0;
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 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
27 {
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
28 if (!colorenabled)
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
29 return;
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
30 fprintf(fp, "\033[%sm", code);
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
31 }
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
32
28788
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
33 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
34 {
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
35 fsetcolor(stderr, "1;31");
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
36 fputs("chg: abort: ", stderr);
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
37 vfprintf(stderr, fmt, args);
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
38 if (no != 0)
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
39 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
40 fsetcolor(stderr, "");
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
41 fputc('\n', stderr);
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
42 exit(255);
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
43 }
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
44
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
45 void abortmsg(const char *fmt, ...)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
46 {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
47 va_list args;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
48 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
49 vabortmsgerrno(0, fmt, args);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
50 va_end(args);
28788
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
51 }
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
52
28788
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
53 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
54 {
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
55 int no = errno;
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
56 va_list args;
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
57 va_start(args, fmt);
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
58 vabortmsgerrno(no, fmt, args);
57a78a64de44 chg: add util function abortmsgerrno to print error with errno
Jun Wu <quark@fb.com>
parents: 28787
diff changeset
59 va_end(args);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
60 }
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
61
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
62 static int debugmsgenabled = 0;
34309
b94db1780365 chg: show timestamp with debug messages
Jun Wu <quark@fb.com>
parents: 28855
diff changeset
63 static double debugstart = 0;
b94db1780365 chg: show timestamp with debug messages
Jun Wu <quark@fb.com>
parents: 28855
diff changeset
64
35959
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34309
diff changeset
65 static double now()
9724f54923ec chg: enable clang-format on all .c and .h files
Augie Fackler <augie@google.com>
parents: 34309
diff changeset
66 {
34309
b94db1780365 chg: show timestamp with debug messages
Jun Wu <quark@fb.com>
parents: 28855
diff changeset
67 struct timeval t;
b94db1780365 chg: show timestamp with debug messages
Jun Wu <quark@fb.com>
parents: 28855
diff changeset
68 gettimeofday(&t, NULL);
b94db1780365 chg: show timestamp with debug messages
Jun Wu <quark@fb.com>
parents: 28855
diff changeset
69 return t.tv_usec / 1e6 + t.tv_sec;
b94db1780365 chg: show timestamp with debug messages
Jun Wu <quark@fb.com>
parents: 28855
diff changeset
70 }
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
71
28787
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
72 void enablecolor(void)
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
73 {
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
74 colorenabled = 1;
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
75 }
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
76
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
77 void enabledebugmsg(void)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
78 {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
79 debugmsgenabled = 1;
34309
b94db1780365 chg: show timestamp with debug messages
Jun Wu <quark@fb.com>
parents: 28855
diff changeset
80 debugstart = now();
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
81 }
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
82
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
83 void debugmsg(const char *fmt, ...)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
84 {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
85 if (!debugmsgenabled)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
86 return;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
87
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
88 va_list args;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
89 va_start(args, fmt);
28787
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
90 fsetcolor(stderr, "1;30");
34309
b94db1780365 chg: show timestamp with debug messages
Jun Wu <quark@fb.com>
parents: 28855
diff changeset
91 fprintf(stderr, "chg: debug: %4.6f ", now() - debugstart);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
92 vfprintf(stderr, fmt, args);
28787
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
93 fsetcolor(stderr, "");
ea86cdcd9b50 chg: use color in debug/error messages conditionally
Jun Wu <quark@fb.com>
parents: 28165
diff changeset
94 fputc('\n', stderr);
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
95 va_end(args);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
96 }
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
97
28854
ddef14468952 chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents: 28788
diff changeset
98 void fchdirx(int dirfd)
ddef14468952 chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents: 28788
diff changeset
99 {
ddef14468952 chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents: 28788
diff changeset
100 int r = fchdir(dirfd);
ddef14468952 chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents: 28788
diff changeset
101 if (r == -1)
ddef14468952 chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents: 28788
diff changeset
102 abortmsgerrno("failed to fchdir");
ddef14468952 chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents: 28788
diff changeset
103 }
ddef14468952 chg: add fchdirx as a utility function
Jun Wu <quark@fb.com>
parents: 28788
diff changeset
104
28855
f5764e177bbe chg: extract the logic of setting FD_CLOEXEC to a utility function
Jun Wu <quark@fb.com>
parents: 28854
diff changeset
105 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
106 {
f5764e177bbe chg: extract the logic of setting FD_CLOEXEC to a utility function
Jun Wu <quark@fb.com>
parents: 28854
diff changeset
107 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
108 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
109 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
110 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
111 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
112 }
f5764e177bbe chg: extract the logic of setting FD_CLOEXEC to a utility function
Jun Wu <quark@fb.com>
parents: 28854
diff changeset
113
28165
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
114 void *mallocx(size_t size)
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
115 {
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
116 void *result = malloc(size);
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
117 if (!result)
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
118 abortmsg("failed to malloc");
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
119 return result;
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
120 }
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
121
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
122 void *reallocx(void *ptr, size_t size)
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
123 {
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
124 void *result = realloc(ptr, size);
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
125 if (!result)
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
126 abortmsg("failed to realloc");
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
127 return result;
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
128 }
c6705c6303dd chg: add utility functions mallocx, reallocx
Jun Wu <quark@fb.com>
parents: 28084
diff changeset
129
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
130 /*
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
131 * Execute a shell command in mostly the same manner as system(), with the
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
132 * give environment variables, after chdir to the given cwd. Returns a status
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
133 * code compatible with the Python subprocess module.
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
134 */
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
135 int runshellcmd(const char *cmd, const char *envp[], const char *cwd)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
136 {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
137 enum { F_SIGINT = 1, F_SIGQUIT = 2, F_SIGMASK = 4, F_WAITPID = 8 };
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
138 unsigned int doneflags = 0;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
139 int status = 0;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
140 struct sigaction newsa, oldsaint, oldsaquit;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
141 sigset_t oldmask;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
142
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
143 /* 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
144 memset(&newsa, 0, sizeof(newsa));
28060
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
145 newsa.sa_handler = SIG_IGN;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
146 newsa.sa_flags = 0;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
147 if (sigemptyset(&newsa.sa_mask) < 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
148 goto done;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
149 if (sigaction(SIGINT, &newsa, &oldsaint) < 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
150 goto done;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
151 doneflags |= F_SIGINT;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
152 if (sigaction(SIGQUIT, &newsa, &oldsaquit) < 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
153 goto done;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
154 doneflags |= F_SIGQUIT;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
155
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
156 if (sigaddset(&newsa.sa_mask, SIGCHLD) < 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
157 goto done;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
158 if (sigprocmask(SIG_BLOCK, &newsa.sa_mask, &oldmask) < 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
159 goto done;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
160 doneflags |= F_SIGMASK;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
161
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
162 pid_t pid = fork();
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
163 if (pid < 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
164 goto done;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
165 if (pid == 0) {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
166 sigaction(SIGINT, &oldsaint, NULL);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
167 sigaction(SIGQUIT, &oldsaquit, NULL);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
168 sigprocmask(SIG_SETMASK, &oldmask, NULL);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
169 if (cwd && chdir(cwd) < 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
170 _exit(127);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
171 const char *argv[] = {"sh", "-c", cmd, NULL};
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
172 if (envp) {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
173 execve("/bin/sh", (char **)argv, (char **)envp);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
174 } else {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
175 execv("/bin/sh", (char **)argv);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
176 }
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
177 _exit(127);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
178 } else {
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
179 if (waitpid(pid, &status, 0) < 0)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
180 goto done;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
181 doneflags |= F_WAITPID;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
182 }
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
183
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
184 done:
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
185 if (doneflags & F_SIGINT)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
186 sigaction(SIGINT, &oldsaint, NULL);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
187 if (doneflags & F_SIGQUIT)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
188 sigaction(SIGQUIT, &oldsaquit, NULL);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
189 if (doneflags & F_SIGMASK)
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
190 sigprocmask(SIG_SETMASK, &oldmask, NULL);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
191
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
192 /* no way to report other errors, use 127 (= shell termination) */
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
193 if (!(doneflags & F_WAITPID))
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
194 return 127;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
195 if (WIFEXITED(status))
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
196 return WEXITSTATUS(status);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
197 if (WIFSIGNALED(status))
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
198 return -WTERMSIG(status);
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
199 return 127;
726f8d6cc324 chg: import frontend sources
Yuya Nishihara <yuya@tcha.org>
parents:
diff changeset
200 }