]> git.itanic.dy.fi Git - scan-pagemap/blob - main.c
main: Assume non-option arguments to be pids or process names
[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                 printf("%s ", argv[optind]);
121                 int pid = pidstr_is_ok(argv[optind]);
122
123                 if (pid) {
124                         opts->parse_mask |= PARSE_PID;
125                         add_pid_to_pidlist(pid, &opts->pidlist);
126                 } else {
127                         get_all_pids_by_name(opts, argv[optind]);
128                         opts->parse_mask |= PARSE_PID;
129                 }
130                 optind++;
131         }
132 }
133
134 int main(int argc, char *argv[])
135 {
136         struct pageframe pf;
137         struct process process_list;
138         struct parse_opts opts;
139
140         if (geteuid()) {
141                 printf("WARNING: Running without root priviledges. "
142                         "Results may be inaccurate\n");
143         }
144
145         init_parse_opts(&opts);
146
147         read_args(argc, argv, &opts);
148
149         if (argc < 2) {
150                 printf("A pid or process name "
151                         "needs to be given as an argument\n");
152                 print_help_and_die(argv[0]);
153         }
154
155         clear_pageframe(&pf);
156
157         memset(&process_list, 0, sizeof(process_list));
158         INIT_LIST_HEAD(&process_list.list);
159
160         if (scan_all_pids(&pf, &process_list, &opts))
161                 return 1;
162
163         update_kpageflags(&pf);
164
165         if (opts.parse_mask & PARSE_DUMP)
166                 dump_process_maps(&pf, &process_list, &opts);
167         else
168                 print_pid_stats(&pf, &process_list, &opts);
169
170         print_page_stats(&pf);
171
172         return 0;
173 }