1e1c2450385374aa951b88a954a8b2c92cedc4b1
2 * after: wait for an unrelated process to terminate, returning
3 * its exit code if possible.
7 * Possible future extensions:
9 * - alternatives to ptrace on systems supporting different
10 * process-debugging mechanisms
12 * - possibly an approach based on invoking ps?
13 * * with a longish interval, to prevent system overload
14 * * and we have to deal with the profusion of ps options. I
15 * suspect going by SUS/POSIX is the best thing here: set
16 * POSIXLY_CORRECT and expect ps to support the options
18 * * need to try to avoid race condition if the process ends
19 * and another one of the same name starts up. Printing the
20 * start time seems like the sensible thing, except that SUS
21 * doesn't give a standard option to do that; we can only
22 * print elapsed time since the process began, which means
23 * we have to be alert for off-by-1s errors if we wait 30s
24 * and the time only changes by 29 for some irritating
35 #include <sys/types.h>
45 * ptrace-based waiting method, which gets the process's exit
49 #include <sys/ptrace.h>
51 int after_ptrace(int pid
)
53 if (ptrace(PTRACE_ATTACH
, pid
, NULL
, 0) < 0) {
55 * If we can't attach to the process, that's not a fatal
56 * error; it just means we fall back to the next available
59 errlen
+= sprintf(errbuf
+errlen
,
60 "%s: ptrace(PTRACE_ATTACH, %d): %.256s\n",
61 pname
, pid
, strerror(errno
));
66 * Having successfully attached to the process, however, any
67 * subsequent error is fatal.
72 wpid
= waitpid(pid
, &wstatus
, 0);
76 } else if (WIFEXITED(wstatus
)) {
77 return WEXITSTATUS(wstatus
);
79 if (ptrace(PTRACE_CONT
, pid
, NULL
, 0) < 0) {
80 perror("ptrace(PTRACE_CONT)");
92 * /proc-based waiting method.
95 int after_proc(int pid
)
99 sprintf(buf
, "/proc/%d", pid
);
101 if (chdir(buf
) < 0) {
105 errlen
+= sprintf(errbuf
+errlen
,
106 "%s: chdir(\"%.32s\"): %.256s\n",
107 pname
, buf
, strerror(errno
));
113 } while (getcwd(buf
, sizeof(buf
)));
124 const char usagemsg
[] =
131 "where: -x return an error if the process's exit code is unavailable\n"
132 " -z return 0 instead of the process's exit code\n"
134 " also: after --version report version number\n"
135 " after --help display this help text\n"
136 " after --licence display the (MIT) licence text\n"
140 fputs(usagemsg
, stdout
);
143 const char licencemsg
[] =
144 "after is copyright 2008 Simon Tatham.\n"
146 "Permission is hereby granted, free of charge, to any person\n"
147 "obtaining a copy of this software and associated documentation files\n"
148 "(the \"Software\"), to deal in the Software without restriction,\n"
149 "including without limitation the rights to use, copy, modify, merge,\n"
150 "publish, distribute, sublicense, and/or sell copies of the Software,\n"
151 "and to permit persons to whom the Software is furnished to do so,\n"
152 "subject to the following conditions:\n"
154 "The above copyright notice and this permission notice shall be\n"
155 "included in all copies or substantial portions of the Software.\n"
157 "THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
158 "EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
159 "MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n"
160 "NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n"
161 "BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n"
162 "ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n"
163 "CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
168 fputs(licencemsg
, stdout
);
172 #define SVN_REV "$Revision: 6566 $"
173 char rev
[sizeof(SVN_REV
)];
176 strcpy(rev
, SVN_REV
);
178 for (p
= rev
; *p
&& *p
!= ':'; p
++);
181 while (*p
&& isspace((unsigned char)*p
)) p
++;
182 for (q
= p
; *q
&& !isspace((unsigned char)*q
) && *q
!= '$'; q
++);
184 printf("after revision %s", p
);
186 printf("after: unknown version");
191 int main(int argc
, char **argv
)
194 enum { UNWANTED
, OPTIONAL
, MANDATORY
} exitcode
= OPTIONAL
;
199 /* parse the command line arguments */
204 if (!strcmp(p
, "-x")) {
205 exitcode
= MANDATORY
;
206 } else if (!strcmp(p
, "-z")) {
210 if (!strcmp(p
, "--help")) {
213 } else if (!strcmp(p
, "--version")) {
216 } else if (!strcmp(p
, "--licence") || !strcmp(p
, "--license")) {
219 } else if (*p
=='-') {
220 fprintf(stderr
, "%s: unrecognised option `%s'\n", pname
, p
);
224 fprintf(stderr
, "%s: parameter `%s' unexpected\n", pname
, p
);
238 ret
= after_ptrace(pid
);
240 return (exitcode
== UNWANTED ?
0 : ret
);
243 if (exitcode
== MANDATORY
) {
245 * If we reach here, the user has demanded the process's
246 * return code, and we haven't been able to get it. Print
247 * the error messages we accrued while trying, and abandon
250 fputs(errbuf
, stderr
);
255 ret
= after_proc(pid
);
261 * If we reach here, we have run out of all our options. Print
262 * all our error messages, and return total failure.
264 fputs(errbuf
, stderr
);