aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org>2016-03-12 09:50:33 +0200
committerSergey Poznyakoff <gray@gnu.org>2016-03-12 09:50:33 +0200
commit3edbd2eb9288f1d2d675c422d5865b8be1f29c32 (patch)
treef022eda083b93ec5ca403a14ee081ba8f70a7d7c
downloadswu-3edbd2eb9288f1d2d675c422d5865b8be1f29c32.tar.gz
swu-3edbd2eb9288f1d2d675c422d5865b8be1f29c32.tar.bz2
Initial commit
-rw-r--r--Makefile4
-rw-r--r--swu.c337
2 files changed, 341 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0730f58
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,4 @@
+CFLAGS=-ggdb
+
+swu: swu.c
+ cc -oswu $(CFLAGS) $(CPPFLAGS) swu.c
diff --git a/swu.c b/swu.c
new file mode 100644
index 0000000..785b00c
--- /dev/null
+++ b/swu.c
@@ -0,0 +1,337 @@
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <glob.h>
+
+char *pattern = "/proc/*/status";
+int reverse;
+int human;
+int show_all;
+int show_total;
+int sizewidth = 8;
+int verbose;
+char *progname;
+
+void
+err(char const *fmt, ...)
+{
+ va_list ap;
+
+ fprintf(stderr, "%s: ", progname);
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fputc('\n', stderr);
+}
+
+struct swu {
+ char *name;
+ pid_t pid;
+ off_t size;
+};
+
+struct swu *usage;
+size_t nusage;
+
+#define ISWS(c) ((c)==' '||(c)=='\t')
+#define SKIPWS(p) do { while (*p && ISWS(*p)) ++p; } while(0)
+
+#define PFX_NAME "Name"
+#define PFX_PID "Pid"
+#define PFX_SWAP "VmSwap"
+
+#define SET_NAME 0x1
+#define SET_PID 0x2
+#define SET_SWAP 0x4
+#define SET_ALL (SET_NAME|SET_PID|SET_SWAP)
+
+static char dig[] = "0123456789";
+
+#define READNUM(fun, type) \
+type \
+fun(char const *s, char **end) \
+{ \
+ type x = 0; \
+ char *p; \
+ for (; *s; s++) { \
+ p = strchr(dig, *s); \
+ if (!p) \
+ break; \
+ x *= 10; \
+ x += p - dig; \
+ } \
+ *end = (char*) s; \
+ return x; \
+}
+
+READNUM(readpid, pid_t);
+READNUM(readsize, off_t);
+
+int
+width(off_t l)
+{
+ int i;
+
+ for (i = 0; l; i++)
+ l>>=1;
+ return i*100/332+1;
+}
+
+static int
+name_match(char const *name, char **argv)
+{
+ for (; *argv; argv++) {
+ if (strcmp(name, *argv) == 0)
+ return 1;
+ }
+ return 0;
+}
+
+void
+readstat(char const *name, char **argv)
+{
+ char buf[80];
+ FILE *fp;
+ struct swu *swp = usage + nusage;
+ int f = 0;
+
+ fp = fopen(name, "r");
+ if (!fp) {
+ if (errno != ENOENT)
+ err("can't open %s: %s", name, strerror(errno));
+ return;
+ }
+
+ free(swp->name);
+ swp->name = NULL;
+
+ while ((f & SET_ALL) != SET_ALL && fgets(buf, sizeof(buf), fp)) {
+ char *p = buf + strlen(buf);
+ if (p[-1] == '\n')
+ p[-1] = 0;
+ else {
+ if (verbose)
+ err("%s: line too long: %s", name, buf);
+ continue;
+ }
+ p = strchr(buf, ':');
+ if (!p) {
+ if (verbose)
+ err("%s: unrecognized line: %s", name, buf);
+ continue;
+ }
+ *p++ = 0;
+ SKIPWS(p);
+ if (strcmp(buf, PFX_NAME) == 0) {
+ if (argv[0] && !name_match(p, argv))
+ return;
+ swp->name = strdup(p);
+ if (!swp->name) {
+ err("out of memory");
+ exit(2);
+ }
+ f |= SET_NAME;
+ } else if (strcmp(buf, PFX_PID) == 0) {
+ swp->pid = readpid(p, &p);
+ if (*p)
+ return;
+ f |= SET_PID;
+ } else if (strcmp(buf, PFX_SWAP) == 0) {
+ swp->size = readsize(p, &p);
+ SKIPWS(p);
+ if (strcmp(p, "kB") == 0)
+ swp->size *= 1024;
+ else if (*p)
+ return;
+ if (swp->size == 0 && !show_all)
+ return;
+ f |= SET_SWAP;
+ }
+ }
+ fclose(fp);
+ if ((f & SET_ALL) == SET_ALL) {
+ size_t w = width(swp->size);
+ if (w > sizewidth)
+ sizewidth = w;
+ ++nusage;
+ }
+}
+
+static int
+cmp_name(struct swu const *a, struct swu const *b)
+{
+ return strcmp(a->name, b->name);
+}
+
+static int
+cmp_pid(struct swu const *a, struct swu const *b)
+{
+ if (a->pid < b->pid)
+ return -1;
+ else
+ return 1;
+}
+
+static int
+cmp_size(struct swu const *a, struct swu const *b)
+{
+ if (a->size < b->size)
+ return -1;
+ else if (a->size > b->size)
+ return 1;
+ return 0;
+}
+
+static int (*cmp)(struct swu const *, struct swu const *) = cmp_pid;
+
+static int
+compare(const void *a, const void *b)
+{
+ struct swu const *au = a, *bu = b;
+ return reverse ? cmp(bu, au) : cmp(au, bu);
+}
+
+static int
+globerrfunc(const char *epath, int eerrno)
+{
+ err("%s %s", progname, epath, strerror(eerrno));
+ return 1;
+}
+
+static void
+collect(char **argv)
+{
+ glob_t g;
+ size_t i;
+
+ switch (glob (pattern, GLOB_NOSORT, globerrfunc, &g)) {
+ case 0:
+ break;
+ case GLOB_NOSPACE:
+ err("out of memory");
+ exit(2);
+ case GLOB_NOMATCH:
+ err("no file matches %s", pattern);
+ exit(2);
+ default:
+ err("globbing error");
+ exit(2);
+ }
+
+ usage = calloc(g.gl_pathc, sizeof(*usage));
+ if (!usage) {
+ err("out of memory");
+ exit(2);
+ }
+
+ for (i = 0; i < g.gl_pathc; i++)
+ if (strncmp(g.gl_pathv[i], "/proc/self/", 11))
+ readstat(g.gl_pathv[i], argv);
+ globfree(&g);
+ qsort(usage, nusage, sizeof(usage[0]), compare);
+}
+
+void
+printsize(off_t size)
+{
+ static char *suf[] = { "", "K", "M", "G", NULL };
+ if (human) {
+ int i;
+ unsigned fract = 0;
+ for (i = 0; size > 1024 && suf[i+1]; i++) {
+ fract = size % 1024;
+ size /= 1024;
+ }
+ if (fract)
+ printf("% *jd.%01u%s",
+ sizewidth, (intmax_t) size, fract/100, suf[i]);
+ else if (i)
+ printf("% *jd%s",
+ sizewidth + 2, (intmax_t) size, suf[i]);
+ else
+ printf("% *jd", sizewidth + 3, (intmax_t) size);
+ } else {
+ printf("% *jd", sizewidth + 3, (intmax_t) size);
+ }
+}
+
+
+void
+output(void)
+{
+ size_t i;
+ off_t total = 0;
+
+ for (i = 0; i < nusage; i++) {
+ printf("% 8ju", (uintmax_t) usage[i].pid);
+ printsize(usage[i].size);
+ printf(" %s\n", usage[i].name);
+ if (show_total)
+ total += usage[i].size;
+ }
+ if (show_total) {
+ printf("%8s", "");
+ printsize(total);
+ printf(" %s\n", "total");
+ }
+}
+
+void
+help(void)
+{
+ //FIXME
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+
+ progname = strrchr(argv[0], '/');
+ if (progname)
+ ++progname;
+ else
+ progname = argv[0];
+ while ((c = getopt(argc, argv, "aHhnprstv")) != EOF) {
+ switch (c) {
+ case 'a':
+ show_all = 1;
+ break;
+ case 'H':
+ human = 1;
+ break;
+ case 'h':
+ help();
+ exit(0);
+ case 'n':
+ cmp = cmp_name;
+ break;
+ case 'p':
+ cmp = cmp_pid;
+ break;
+ case 'r':
+ reverse = 1;
+ break;
+ case 's':
+ cmp = cmp_size;
+ break;
+ case 't':
+ show_total = 1;
+ break;
+ case 'v':
+ verbose++;
+ break;
+ default:
+ exit(1);
+ }
+ }
+ if (argc > optind)
+ show_all = 1;
+ collect(argv + optind);
+ output();
+ exit(0);
+}

Return to:

Send suggestions and report system problems to the System administrator.