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  */
  25 
  26 #include <stdio.h>
  27 #include <stdio_ext.h>
  28 #include <ctype.h>
  29 #include <stdlib.h>
  30 #include <unistd.h>
  31 #include <fcntl.h>
  32 #include <string.h>
  33 #include <dirent.h>
  34 #include <errno.h>
  35 #include <sys/types.h>
  36 #include <stropts.h>
  37 #include <poll.h>
  38 #include <procfs.h>
  39 #include <sys/resource.h>
  40 #include <limits.h>
  41 #include "ptools_common.h"
  42 
  43 static int count_my_files();
  44 static char *command;
  45 
  46 /* slop to account for extra file descriptors opened by libraries we call */
  47 #define SLOP    5
  48 
  49 int
  50 main(int argc, char **argv)
  51 {
  52         char buf[PATH_MAX];
  53         unsigned long remain = 0;
  54         struct pollfd *pollfd;
  55         struct pollfd *pfd;
  56         struct rlimit rlim;
  57         char *arg;
  58         unsigned i;
  59         int verbose = 0;
  60 
  61         if ((command = strrchr(argv[0], '/')) != NULL)
  62                 command++;
  63         else
  64                 command = argv[0];
  65 
  66         argc--;
  67         argv++;
  68 
  69         if (argc > 0 && strcmp(argv[0], "-v") == 0) {
  70                 verbose = 1;
  71                 argc--;
  72                 argv++;
  73         }
  74 
  75         if (argc <= 0) {
  76                 (void) fprintf(stderr, "usage:\t%s [-v] pid ...\n", command);
  77                 (void) fprintf(stderr, "  (wait for processes to terminate)\n");
  78                 (void) fprintf(stderr,
  79                     "  -v: verbose; report terminations to standard out\n");
  80                 return (2);
  81         }
  82 
  83         (void) proc_snprintf(buf, sizeof (buf), "/proc/");
  84 
  85         /* make sure we have enough file descriptors */
  86         if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) {
  87                 int nfiles = count_my_files();
  88 
  89                 if (rlim.rlim_cur < argc + nfiles + SLOP) {
  90                         rlim.rlim_cur = argc + nfiles + SLOP;
  91                         if (setrlimit(RLIMIT_NOFILE, &rlim) != 0) {
  92                                 (void) fprintf(stderr,
  93                                     "%s: insufficient file descriptors\n",
  94                                     command);
  95                                 return (2);
  96                         }
  97                 }
  98                 (void) enable_extended_FILE_stdio(-1, -1);
  99         }
 100 
 101         pollfd = (struct pollfd *)malloc(argc*sizeof (struct pollfd));
 102         if (pollfd == NULL) {
 103                 perror("malloc");
 104                 return (2);
 105         }
 106 
 107         for (i = 0; i < argc; i++) {
 108                 char psinfofile[100];
 109 
 110                 arg = argv[i];
 111                 if (strchr(arg, '/') != NULL)
 112                         (void) strncpy(psinfofile, arg, sizeof (psinfofile));
 113                 else {
 114                         (void) strcpy(psinfofile, buf);
 115                         (void) strncat(psinfofile, arg, sizeof (psinfofile)-6);
 116                 }
 117                 (void) strncat(psinfofile, "/psinfo",
 118                     sizeof (psinfofile)-strlen(psinfofile));
 119 
 120                 pfd = &pollfd[i];
 121                 if ((pfd->fd = open(psinfofile, O_RDONLY)) >= 0) {
 122                         remain++;
 123                         /*
 124                          * We set POLLPRI to detect system processes.
 125                          * We will get POLLNVAL below for a POLLPRI
 126                          * requested event on a system process.
 127                          */
 128                         pfd->events = POLLPRI;
 129                         pfd->revents = 0;
 130                 } else if (errno == ENOENT) {
 131                         (void) fprintf(stderr, "%s: no such process: %s\n",
 132                             command, arg);
 133                 } else {
 134                         perror(arg);
 135                 }
 136         }
 137 
 138         while (remain != 0) {
 139                 while (poll(pollfd, argc, INFTIM) < 0) {
 140                         if (errno != EAGAIN) {
 141                                 perror("poll");
 142                                 return (2);
 143                         }
 144                         (void) sleep(2);
 145                 }
 146                 for (i = 0; i < argc; i++) {
 147                         pfd = &pollfd[i];
 148                         if (pfd->fd < 0 || (pfd->revents & ~POLLPRI) == 0) {
 149                                 /*
 150                                  * We don't care if a non-system process
 151                                  * stopped.  Don't check for that again.
 152                                  */
 153                                 pfd->events = 0;
 154                                 pfd->revents = 0;
 155                                 continue;
 156                         }
 157 
 158                         if (verbose) {
 159                                 arg = argv[i];
 160                                 if (pfd->revents & POLLHUP) {
 161                                         psinfo_t psinfo;
 162 
 163                                         if (pread(pfd->fd, &psinfo,
 164                                             sizeof (psinfo), (off_t)0)
 165                                             == sizeof (psinfo)) {
 166                                                 (void) printf("%s: terminated, "
 167                                                     "wait status 0x%.4x\n",
 168                                                     arg, psinfo.pr_wstat);
 169                                         } else {
 170                                                 (void) printf(
 171                                                     "%s: terminated\n", arg);
 172                                         }
 173                                 }
 174                                 if (pfd->revents & POLLNVAL)
 175                                         (void) printf("%s: system process\n",
 176                                             arg);
 177                                 if (pfd->revents & ~(POLLPRI|POLLHUP|POLLNVAL))
 178                                         (void) printf("%s: unknown error\n",
 179                                             arg);
 180                         }
 181 
 182                         (void) close(pfd->fd);
 183                         pfd->fd = -1;
 184                         remain--;
 185                 }
 186         }
 187 
 188         return (0);
 189 }
 190 
 191 /* ARGSUSED1 */
 192 static int
 193 do_count(void *nofilesp, int fd)
 194 {
 195         (*(int *)nofilesp)++;
 196         return (0);
 197 }
 198 
 199 static int
 200 count_my_files()
 201 {
 202         int nofiles = 0;
 203 
 204         (void) fdwalk(do_count, &nofiles);
 205         return (nofiles);
 206 }