]> git.itanic.dy.fi Git - scan-pagemap/blob - main.c
838f801288077191e9b108df828bdeb735627e1d
[scan-pagemap] / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <getopt.h>
6 #include <unistd.h>
7 #include <sys/types.h>
8
9 #include "parse.h"
10 #include "analyze.h"
11 #include "pidlib.h"
12
13 void print_help_and_die(char *name)
14 {
15         printf("Usage: %s options\n"
16                 "-p, --pid=PID          scan maps belonging to a given pid\n"
17                 "-P, --process=PROCESS  scan maps belonging to processes with "
18                 "given name\n"
19                 "-m, --map=mapname      scan maps with given mapping name\n"
20                 "-d, --dump             dump process maps\n"
21                 "-s, --shared-mappings  dump only shared mappings\n"
22                 "-h, --help             show this help\n",
23                 name);
24
25         exit(0);
26 }
27
28 #define OPT_WITH_THREADS        0x101
29
30 static void get_all_pids_by_name(struct parse_opts *opts, char *name)
31 {
32         struct pidlist *pidlist;
33         DIR *dir = NULL;
34         int pid;
35
36         while ((pid = get_next_pid_by_name(&dir, name))) {
37                 pidlist = alloc_pidlist();
38                 if (pidlist == NULL)
39                         return;
40                 pidlist->pid = pid;
41                 list_add_tail(&pidlist->list, &opts->pidlist);
42         }
43 }
44
45 static int add_pid_to_pidlist(int pidi, struct list_head *pidlist)
46 {
47         struct pidlist *pid = alloc_pidlist();
48
49         if (pid == NULL) {
50                 perror("malloc");
51                 return -1;
52         }
53         pid->pid = pidi;
54
55         list_add_tail(&pid->list, pidlist);
56
57         return 0;
58 }
59
60 void read_args(int argc, char *argv[], struct parse_opts *opts)
61 {
62         int option_index = 0, c;
63         static struct option long_options[] = {
64                 { .val = 'p', .name = "pid", .has_arg = 1, },
65                 { .val = 'P', .name = "process", .has_arg = 1, },
66                 { .val = 'm', .name = "map", .has_arg = 1, },
67                 { .val = OPT_WITH_THREADS, .name = "with-threads" },
68                 { .val = 'd', .name = "dump", },
69                 { .val = 's', .name = "shared-mappings", },
70                 { .val = 'h', .name = "help", },
71         };
72         char short_options[] = "p:P:m:sdh";
73         opts->parse_mask = 0;
74
75         while (1) {
76                 c = getopt_long(argc, argv, short_options, long_options,
77                                 &option_index);
78
79                 if (c == -1)
80                         break;
81
82                 switch (c) {
83                 case 'p':
84                 {
85                         int pid = pidstr_is_ok(optarg);
86                         if (!pid) {
87                                 fprintf(stderr, "Invalid pid number %s\n",
88                                         optarg);
89                                 break;
90                         }
91
92                         opts->parse_mask |= PARSE_PID;
93                         add_pid_to_pidlist(pid, &opts->pidlist);
94                         break;
95                 }
96                 case 'P':
97                         get_all_pids_by_name(opts, optarg);
98                         opts->parse_mask |= PARSE_PID;
99                         break;
100                 case 'm':
101                         opts->parse_mask |= PARSE_MAP_NAME;
102                         opts->name = optarg;
103                         break;
104                 case OPT_WITH_THREADS:
105                         opts->with_threads = 1;
106                         break;
107                 case 's':
108                         opts->parse_mask |= PARSE_SHARED_MAPPING;
109                         /* implies --dump */
110                 case 'd':
111                         opts->parse_mask |= PARSE_DUMP;
112                         break;
113                 case 'h':
114                         print_help_and_die(argv[0]);
115                         break;
116                 }
117         }
118
119         while (optind < argc) {
120                 int pid = pidstr_is_ok(argv[optind]);
121
122                 if (pid) {
123                         opts->parse_mask |= PARSE_PID;
124                         add_pid_to_pidlist(pid, &opts->pidlist);
125                 } else {
126                         get_all_pids_by_name(opts, argv[optind]);
127                         opts->parse_mask |= PARSE_PID;
128                 }
129                 optind++;
130         }
131 }
132
133 int main(int argc, char *argv[])
134 {
135         struct pageframe pf;
136         struct process process_list;
137         struct parse_opts opts;
138
139         if (geteuid()) {
140                 printf("WARNING: Running without root priviledges. "
141                         "Results may be inaccurate\n");
142         }
143
144         init_parse_opts(&opts);
145
146         read_args(argc, argv, &opts);
147
148         if (argc < 2) {
149                 printf("A pid or process name "
150                         "needs to be given as an argument\n");
151                 print_help_and_die(argv[0]);
152         }
153
154         clear_pageframe(&pf);
155
156         memset(&process_list, 0, sizeof(process_list));
157         INIT_LIST_HEAD(&process_list.list);
158
159         if (scan_all_pids(&pf, &process_list, &opts))
160                 return 1;
161
162         update_kpageflags(&pf);
163
164         if (opts.parse_mask & PARSE_DUMP)
165                 dump_process_maps(&pf, &process_list, &opts);
166         else
167                 print_pid_stats(&pf, &process_list, &opts);
168
169         print_page_stats(&pf);
170
171         return 0;
172 }