morpheus-base

morpheus base system
git clone git://git.2f30.org/morpheus-base
Log | Files | Refs

ps.c (3915B)


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