HardenedBSD src tree
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
4.9 KiB

  1. /*-
  2. * Copyright (c) 2004-2009, Jilles Tjoelker
  3. * All rights reserved.
  4. *
  5. * Redistribution and use in source and binary forms, with
  6. * or without modification, are permitted provided that the
  7. * following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above
  10. * copyright notice, this list of conditions and the
  11. * following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the
  13. * above copyright notice, this list of conditions and
  14. * the following disclaimer in the documentation and/or
  15. * other materials provided with the distribution.
  16. *
  17. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
  18. * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
  19. * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  21. * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  22. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY
  23. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  24. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  25. * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  26. * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  27. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  28. * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  29. * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
  30. * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  31. * OF SUCH DAMAGE.
  32. */
  33. #include <sys/cdefs.h>
  34. __FBSDID("$FreeBSD$");
  35. #include <sys/types.h>
  36. #include <sys/event.h>
  37. #include <sys/time.h>
  38. #include <sys/wait.h>
  39. #include <err.h>
  40. #include <errno.h>
  41. #include <fcntl.h>
  42. #include <signal.h>
  43. #include <stdio.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. #include <sysexits.h>
  47. #include <unistd.h>
  48. static void
  49. usage(void)
  50. {
  51. errx(EX_USAGE, "usage: pwait [-t timeout] [-ov] pid ...");
  52. }
  53. /*
  54. * pwait - wait for processes to terminate
  55. */
  56. int
  57. main(int argc, char *argv[])
  58. {
  59. struct itimerval itv;
  60. struct kevent *e;
  61. int oflag, tflag, verbose;
  62. int i, kq, n, nleft, opt, status;
  63. long pid;
  64. char *end, *s;
  65. double timeout;
  66. oflag = 0;
  67. tflag = 0;
  68. verbose = 0;
  69. memset(&itv, 0, sizeof(itv));
  70. while ((opt = getopt(argc, argv, "ot:v")) != -1) {
  71. switch (opt) {
  72. case 'o':
  73. oflag = 1;
  74. break;
  75. case 't':
  76. tflag = 1;
  77. errno = 0;
  78. timeout = strtod(optarg, &end);
  79. if (end == optarg || errno == ERANGE || timeout < 0) {
  80. errx(EX_DATAERR, "timeout value");
  81. }
  82. switch(*end) {
  83. case 0:
  84. case 's':
  85. break;
  86. case 'h':
  87. timeout *= 60;
  88. /* FALLTHROUGH */
  89. case 'm':
  90. timeout *= 60;
  91. break;
  92. default:
  93. errx(EX_DATAERR, "timeout unit");
  94. }
  95. if (timeout > 100000000L) {
  96. errx(EX_DATAERR, "timeout value");
  97. }
  98. itv.it_value.tv_sec = (time_t)timeout;
  99. timeout -= (time_t)timeout;
  100. itv.it_value.tv_usec =
  101. (suseconds_t)(timeout * 1000000UL);
  102. break;
  103. case 'v':
  104. verbose = 1;
  105. break;
  106. default:
  107. usage();
  108. /* NOTREACHED */
  109. }
  110. }
  111. argc -= optind;
  112. argv += optind;
  113. if (argc == 0) {
  114. usage();
  115. }
  116. kq = kqueue();
  117. if (kq == -1) {
  118. err(EX_OSERR, "kqueue");
  119. }
  120. e = malloc((argc + tflag) * sizeof(struct kevent));
  121. if (e == NULL) {
  122. err(EX_OSERR, "malloc");
  123. }
  124. nleft = 0;
  125. for (n = 0; n < argc; n++) {
  126. s = argv[n];
  127. /* Undocumented Solaris compat */
  128. if (!strncmp(s, "/proc/", 6)) {
  129. s += 6;
  130. }
  131. errno = 0;
  132. pid = strtol(s, &end, 10);
  133. if (pid < 0 || *end != '\0' || errno != 0) {
  134. warnx("%s: bad process id", s);
  135. continue;
  136. }
  137. for (i = 0; i < nleft; i++) {
  138. if (e[i].ident == (uintptr_t)pid) {
  139. break;
  140. }
  141. }
  142. if (i < nleft) {
  143. /* Duplicate. */
  144. continue;
  145. }
  146. EV_SET(e + nleft, pid, EVFILT_PROC, EV_ADD, NOTE_EXIT, 0, NULL);
  147. if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) {
  148. warn("%ld", pid);
  149. if (oflag) {
  150. exit(EX_OK);
  151. }
  152. } else {
  153. nleft++;
  154. }
  155. }
  156. if (nleft > 0 && tflag) {
  157. /*
  158. * Explicitly detect SIGALRM so that an exit status of 124
  159. * can be returned rather than 142.
  160. */
  161. EV_SET(e + nleft, SIGALRM, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
  162. if (kevent(kq, e + nleft, 1, NULL, 0, NULL) == -1) {
  163. err(EX_OSERR, "kevent");
  164. }
  165. /* Ignore SIGALRM to not interrupt kevent(2). */
  166. signal(SIGALRM, SIG_IGN);
  167. if (setitimer(ITIMER_REAL, &itv, NULL) == -1) {
  168. err(EX_OSERR, "setitimer");
  169. }
  170. }
  171. while (nleft > 0) {
  172. n = kevent(kq, NULL, 0, e, nleft + tflag, NULL);
  173. if (n == -1) {
  174. err(EX_OSERR, "kevent");
  175. }
  176. for (i = 0; i < n; i++) {
  177. if (e[i].filter == EVFILT_SIGNAL) {
  178. if (verbose) {
  179. printf("timeout\n");
  180. }
  181. exit(124);
  182. }
  183. if (verbose) {
  184. status = e[i].data;
  185. if (WIFEXITED(status)) {
  186. printf("%ld: exited with status %d.\n",
  187. (long)e[i].ident,
  188. WEXITSTATUS(status));
  189. } else if (WIFSIGNALED(status)) {
  190. printf("%ld: killed by signal %d.\n",
  191. (long)e[i].ident,
  192. WTERMSIG(status));
  193. } else {
  194. printf("%ld: terminated.\n",
  195. (long)e[i].ident);
  196. }
  197. }
  198. if (oflag) {
  199. exit(EX_OK);
  200. }
  201. --nleft;
  202. }
  203. }
  204. exit(EX_OK);
  205. }