1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21 /*
22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
24 * Copyright 2022 Spencer Evans-Cole.
25 */
26
27 #include <stdio.h>
28 #include <stdio_ext.h>
29 #include <ctype.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <dirent.h>
35 #include <errno.h>
36 #include <sys/types.h>
37 #include <stropts.h>
38 #include <poll.h>
39 #include <procfs.h>
40 #include <sys/resource.h>
41
42 static int count_my_files();
43 static char *command;
44
45 /* slop to account for extra file descriptors opened by libraries we call */
46 #define SLOP 5
47
48 int
main(int argc,char ** argv)49 main(int argc, char **argv)
50 {
51 unsigned long remain = 0;
52 struct pollfd *pollfd;
53 struct pollfd *pfd;
54 struct rlimit rlim;
55 char *arg;
56 unsigned i;
57 int verbose = 0;
58 pid_t mypid = getpid();
59
60 if ((command = strrchr(argv[0], '/')) != NULL)
61 command++;
62 else
63 command = argv[0];
64
65 argc--;
66 argv++;
67
68 if (argc > 0 && strcmp(argv[0], "-v") == 0) {
69 verbose = 1;
70 argc--;
71 argv++;
72 }
73
74 if (argc <= 0) {
75 (void) fprintf(stderr, "usage:\t%s [-v] pid ...\n", command);
76 (void) fprintf(stderr, " (wait for processes to terminate)\n");
77 (void) fprintf(stderr,
78 " -v: verbose; report terminations to standard out\n");
79 return (2);
80 }
81
82 /* make sure we have enough file descriptors */
83 if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
84 int nfiles = count_my_files();
85
86 if (rlim.rlim_cur < argc + nfiles + SLOP) {
87 rlim.rlim_cur = argc + nfiles + SLOP;
88 if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
89 (void) fprintf(stderr,
90 "%s: insufficient file descriptors\n",
91 command);
92 return (2);
93 }
94 }
95 (void) enable_extended_FILE_stdio(-1, -1);
96 }
97
98 pollfd = (struct pollfd *)malloc(argc*sizeof (struct pollfd));
99 if (pollfd == NULL) {
100 perror("malloc");
101 return (2);
102 }
103
104 for (i = 0; i < argc; i++) {
105 char psinfofile[100];
106
107 arg = argv[i];
108 if (mypid == atol(arg)) {
109 if (verbose) {
110 (void) printf("%s: has the same"
111 " pid as this process\n", arg);
112 }
113 continue;
114 }
115 if (strchr(arg, '/') != NULL)
116 (void) strncpy(psinfofile, arg, sizeof (psinfofile));
117 else {
118 (void) strcpy(psinfofile, "/proc/");
119 (void) strncat(psinfofile, arg, sizeof (psinfofile)-6);
120 }
121 (void) strncat(psinfofile, "/psinfo",
122 sizeof (psinfofile) - strlen(psinfofile));
123
124 pfd = &pollfd[i];
125 if ((pfd->fd = open(psinfofile, O_RDONLY)) >= 0) {
126 remain++;
127 /*
128 * We set POLLPRI to detect system processes.
129 * We will get POLLNVAL below for a POLLPRI
130 * requested event on a system process.
131 */
132 pfd->events = POLLPRI;
133 pfd->revents = 0;
134 } else if (errno == ENOENT) {
135 (void) fprintf(stderr, "%s: no such process: %s\n",
136 command, arg);
137 } else {
138 perror(arg);
139 }
140 }
141
142 while (remain != 0) {
143 while (poll(pollfd, argc, INFTIM) < 0) {
144 if (errno != EAGAIN) {
145 perror("poll");
146 return (2);
147 }
148 (void) sleep(2);
149 }
150 for (i = 0; i < argc; i++) {
151 pfd = &pollfd[i];
152 if (pfd->fd < 0 || (pfd->revents & ~POLLPRI) == 0) {
153 /*
154 * We don't care if a non-system process
155 * stopped. Don't check for that again.
156 */
157 pfd->events = 0;
158 pfd->revents = 0;
159 continue;
160 }
161
162 if (verbose) {
163 arg = argv[i];
164 if (pfd->revents & POLLHUP) {
165 psinfo_t psinfo;
166
167 if (pread(pfd->fd, &psinfo,
168 sizeof (psinfo), (off_t)0)
169 == sizeof (psinfo)) {
170 (void) printf("%s: terminated,"
171 " wait status 0x%.4x\n",
172 arg, psinfo.pr_wstat);
173 } else {
174 (void) printf(
175 "%s: terminated\n", arg);
176 }
177 }
178 if (pfd->revents & POLLNVAL)
179 (void) printf("%s: system process\n",
180 arg);
181 if (pfd->revents & ~(POLLPRI|POLLHUP|POLLNVAL))
182 (void) printf("%s: unknown error\n",
183 arg);
184 }
185
186 (void) close(pfd->fd);
187 pfd->fd = -1;
188 remain--;
189 }
190 }
191
192 return (0);
193 }
194
195 /* ARGSUSED1 */
196 static int
do_count(void * nofilesp,int fd)197 do_count(void *nofilesp, int fd)
198 {
199 (*(int *)nofilesp)++;
200 return (0);
201 }
202
203 static int
count_my_files()204 count_my_files()
205 {
206 int nofiles = 0;
207
208 (void) fdwalk(do_count, &nofiles);
209 return (nofiles);
210 }
211