| /* | 
 |  * pmap implementation for busybox | 
 |  * | 
 |  * Copyright (C) 2010 Nokia Corporation. All rights reserved. | 
 |  * Written by Alexander Shishkin <virtuoso@slind.org> | 
 |  * | 
 |  * Licensed under GPLv2 or later, see the LICENSE file in this source tree | 
 |  * for details. | 
 |  */ | 
 |  | 
 | //config:config PMAP | 
 | //config:       bool "pmap" | 
 | //config:       default y | 
 | //config:       help | 
 | //config:         Display processes' memory mappings. | 
 |  | 
 | //applet:IF_PMAP(APPLET(pmap, BB_DIR_USR_BIN, BB_SUID_DROP)) | 
 | //kbuild:lib-$(CONFIG_PMAP) += pmap.o | 
 |  | 
 | //usage:#define pmap_trivial_usage | 
 | //usage:       "[-xq] PID" | 
 | //usage:#define pmap_full_usage "\n\n" | 
 | //usage:       "Display detailed process memory usage" | 
 | //usage:     "\n" | 
 | //usage:     "\n	-x	Show details" | 
 | //usage:     "\n	-q	Quiet" | 
 |  | 
 | #include "libbb.h" | 
 |  | 
 | #if ULONG_MAX == 0xffffffff | 
 | # define TABS "\t" | 
 | # define AFMT "8" | 
 | # define DASHES "" | 
 | #else | 
 | # define TABS "\t\t" | 
 | # define AFMT "16" | 
 | # define DASHES "--------" | 
 | #endif | 
 |  | 
 | enum { | 
 | 	OPT_x = 1 << 0, | 
 | 	OPT_q = 1 << 1, | 
 | }; | 
 |  | 
 | static void print_smaprec(struct smaprec *currec, void *data) | 
 | { | 
 | 	unsigned opt = (uintptr_t)data; | 
 |  | 
 | 	printf("%0" AFMT "lx ", currec->smap_start); | 
 |  | 
 | 	if (opt & OPT_x) | 
 | 		printf("%7lu %7lu %7lu %7lu ", | 
 | 			currec->smap_size, | 
 | 			currec->smap_pss, | 
 | 			currec->private_dirty, | 
 | 			currec->smap_swap); | 
 | 	else | 
 | 		printf("%7luK", currec->smap_size); | 
 |  | 
 | 	printf(" %.4s  %s\n", currec->smap_mode, currec->smap_name); | 
 | } | 
 |  | 
 | static int procps_get_maps(pid_t pid, unsigned opt) | 
 | { | 
 | 	struct smaprec total; | 
 | 	int ret; | 
 | 	char buf[256]; | 
 |  | 
 | 	read_cmdline(buf, sizeof(buf), pid, "no such process"); | 
 | 	printf("%u: %s\n", (int)pid, buf); | 
 |  | 
 | 	if (!(opt & OPT_q) && (opt & OPT_x)) | 
 | 		puts("Address" TABS "  Kbytes     PSS   Dirty    Swap  Mode  Mapping"); | 
 |  | 
 | 	memset(&total, 0, sizeof(total)); | 
 |  | 
 | 	ret = procps_read_smaps(pid, &total, print_smaprec, (void*)(uintptr_t)opt); | 
 | 	if (ret) | 
 | 		return ret; | 
 |  | 
 | 	if (!(opt & OPT_q)) { | 
 | 		if (opt & OPT_x) | 
 | 			printf("--------" DASHES "  ------  ------  ------  ------\n" | 
 | 				"total" TABS " %7lu %7lu %7lu %7lu\n", | 
 | 				total.smap_size, total.smap_pss, total.private_dirty, total.smap_swap); | 
 | 		else | 
 | 			printf("mapped: %luK\n", total.smap_size); | 
 | 	} | 
 |  | 
 | 	return 0; | 
 | } | 
 |  | 
 | int pmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 
 | int pmap_main(int argc UNUSED_PARAM, char **argv) | 
 | { | 
 | 	unsigned opts; | 
 | 	int ret; | 
 |  | 
 | 	opts = getopt32(argv, "xq"); | 
 | 	argv += optind; | 
 |  | 
 | 	ret = 0; | 
 | 	while (*argv) { | 
 | 		pid_t pid = xatoi_positive(*argv++); | 
 | 		/* GNU pmap returns 42 if any of the pids failed */ | 
 | 		if (procps_get_maps(pid, opts) != 0) | 
 | 			ret = 42; | 
 | 	} | 
 |  | 
 | 	return ret; | 
 | } |