URI: 
       ps.c - ubase - suckless linux base utils
  HTML git clone git://git.suckless.org/ubase
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       ps.c (3852B)
       ---
            1 /* See LICENSE file for copyright and license details. */
            2 #include <sys/ioctl.h>
            3 #include <sys/sysinfo.h>
            4 
            5 #include <errno.h>
            6 #include <libgen.h>
            7 #include <limits.h>
            8 #include <pwd.h>
            9 #include <stdio.h>
           10 #include <stdlib.h>
           11 #include <string.h>
           12 #include <time.h>
           13 #include <unistd.h>
           14 
           15 #include "proc.h"
           16 #include "util.h"
           17 
           18 static void psout(struct procstat *ps);
           19 static void psr(const char *file);
           20 
           21 enum {
           22         PS_aflag = 1 << 0,
           23         PS_Aflag = 1 << 1,
           24         PS_dflag = 1 << 2,
           25         PS_fflag = 1 << 3
           26 };
           27 
           28 static int flags;
           29 
           30 static void
           31 psout(struct procstat *ps)
           32 {
           33         struct procstatus pstatus;
           34         char cmdline[BUFSIZ], *cmd;
           35         char buf[BUFSIZ];
           36         char ttystr[TTY_NAME_MAX], *myttystr;
           37         int tty_maj, tty_min;
           38         uid_t myeuid;
           39         unsigned sutime;
           40         time_t start;
           41         char stimestr[sizeof("%H:%M")];
           42         struct sysinfo info;
           43         struct passwd *pw;
           44         struct winsize w;
           45 
           46         /* Ignore session leaders */
           47         if (flags & PS_dflag)
           48                 if (ps->pid == ps->sid)
           49                         return;
           50 
           51         devtotty(ps->tty_nr, &tty_maj, &tty_min);
           52         ttytostr(tty_maj, tty_min, ttystr, sizeof(ttystr));
           53 
           54         /* Only print processes that are associated with
           55          * a terminal and they are not session leaders */
           56         if (flags & PS_aflag)
           57                 if (ps->pid == ps->sid || ttystr[0] == '?')
           58                         return;
           59 
           60         if (parsestatus(ps->pid, &pstatus) < 0)
           61                 return;
           62 
           63         /* This is the default case, only print processes that have
           64          * the same controlling terminal as the invoker and the same
           65          * euid as the current user */
           66         if (!(flags & (PS_aflag | PS_Aflag | PS_dflag))) {
           67                 myttystr = ttyname(0);
           68                 if (myttystr) {
           69                         if (strcmp(myttystr + strlen("/dev/"), ttystr))
           70                                 return;
           71                 } else {
           72                         /* The invoker has no controlling terminal - just
           73                          * go ahead and print the processes anyway */
           74                         ttystr[0] = '?';
           75                         ttystr[1] = '\0';
           76                 }
           77                 myeuid = geteuid();
           78                 if (myeuid != pstatus.euid)
           79                         return;
           80         }
           81 
           82         sutime = (ps->stime + ps->utime) / sysconf(_SC_CLK_TCK);
           83 
           84         ioctl(1, TIOCGWINSZ, &w);
           85         if (!(flags & PS_fflag)) {
           86                 snprintf(buf, sizeof(buf), "%5d %-6s   %02u:%02u:%02u %s", ps->pid, ttystr,
           87                          sutime / 3600, (sutime % 3600) / 60, sutime % 60,
           88                          ps->comm);
           89                 if (w.ws_col)
           90                         printf("%.*s\n", w.ws_col, buf);
           91                 else
           92                         printf("%s\n", buf);
           93         } else {
           94                 errno = 0;
           95                 pw = getpwuid(pstatus.uid);
           96                 if (!pw)
           97                         eprintf("getpwuid %d:", pstatus.uid);
           98 
           99                 if (sysinfo(&info) < 0)
          100                         eprintf("sysinfo:");
          101 
          102                 start = time(NULL) - info.uptime;
          103                 start += (ps->starttime / sysconf(_SC_CLK_TCK));
          104                 strftime(stimestr, sizeof(stimestr),
          105                          "%H:%M", localtime(&start));
          106 
          107                 /* For kthreads/zombies /proc/<pid>/cmdline will be
          108                  * empty so use ps->comm in that case */
          109                 if (parsecmdline(ps->pid, cmdline, sizeof(cmdline)) < 0)
          110                         cmd = ps->comm;
          111                 else
          112                         cmd = cmdline;
          113 
          114                 snprintf(buf, sizeof(buf), "%-8s %5d %5d  ? %5s %-5s    %02u:%02u:%02u %s%s%s",
          115                          pw->pw_name, ps->pid,
          116                          ps->ppid, stimestr, ttystr,
          117                          sutime / 3600, (sutime % 3600) / 60, sutime % 60,
          118                          (cmd == ps->comm) ? "[" : "", cmd,
          119                          (cmd == ps->comm) ? "]" : "");
          120                 if (w.ws_col)
          121                         printf("%.*s\n", w.ws_col, buf);
          122                 else
          123                         printf("%s\n", buf);
          124         }
          125 }
          126 
          127 static void
          128 psr(const char *file)
          129 {
          130         char path[PATH_MAX], *p;
          131         struct procstat ps;
          132         pid_t pid;
          133 
          134         if (strlcpy(path, file, sizeof(path)) >= sizeof(path))
          135                 eprintf("path too long\n");
          136         p = basename(path);
          137         if (pidfile(p) == 0)
          138                 return;
          139         pid = estrtol(p, 10);
          140         if (parsestat(pid, &ps) < 0)
          141                 return;
          142         psout(&ps);
          143 }
          144 
          145 static void
          146 usage(void)
          147 {
          148         eprintf("usage: %s [-aAdef]\n", argv0);
          149 }
          150 
          151 int
          152 main(int argc, char *argv[])
          153 {
          154         ARGBEGIN {
          155         case 'a':
          156                 flags |= PS_aflag;
          157                 break;
          158         case 'A':
          159                 flags |= PS_Aflag;
          160                 break;
          161         case 'd':
          162                 flags |= PS_dflag;
          163                 break;
          164         case 'e':
          165                 flags |= PS_Aflag;
          166                 break;
          167         case 'f':
          168                 flags |= PS_fflag;
          169                 break;
          170         default:
          171                 usage();
          172         } ARGEND;
          173 
          174         if (!(flags & PS_fflag))
          175                 printf("  PID TTY          TIME CMD\n");
          176         else
          177                 printf("UID        PID  PPID  C STIME TTY          TIME CMD\n");
          178         recurse("/proc", psr);
          179         return 0;
          180 }