]> git.itanic.dy.fi Git - scan-pagemap/blob - main.c
10f1a9eb5c21e1ad4b5ee690b400a52ceffd1ce9
[scan-pagemap] / main.c
1 /*
2  * Copyright (C) 2010 Timo Kokkonen <kaapeli@itanic.dy.fi>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16  */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include <getopt.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25
26 #include "parse.h"
27 #include "analyze.h"
28 #include "pidlib.h"
29
30 void print_help_and_die(char *name)
31 {
32         printf("Usage: %s options\n"
33                 "-p, --pid=PID          scan maps belonging to a given pid\n"
34                 "-P, --process=PROCESS  scan maps belonging to processes with "
35                 "given name\n"
36                 "-m, --map=mapname      scan maps with given mapping name\n"
37                 "-d, --dump             dump process maps\n"
38                 "-s, --shared-mappings  dump only shared mappings\n"
39                 "-h, --help             show this help\n",
40                 name);
41
42         exit(0);
43 }
44
45 #define OPT_WITH_THREADS        0x101
46
47 static void get_all_pids_by_name(struct parse_opts *opts, char *name)
48 {
49         struct pidlist *pidlist;
50         DIR *dir = NULL;
51         int pid;
52
53         while ((pid = get_next_pid_by_name(&dir, name))) {
54                 pidlist = alloc_pidlist();
55                 if (pidlist == NULL)
56                         return;
57                 pidlist->pid = pid;
58                 list_add_tail(&pidlist->list, &opts->pidlist);
59         }
60 }
61
62 static int add_pid_to_pidlist(int pidi, struct list_head *pidlist)
63 {
64         struct pidlist *pid = alloc_pidlist();
65
66         if (pid == NULL) {
67                 perror("malloc");
68                 return -1;
69         }
70         pid->pid = pidi;
71
72         list_add_tail(&pid->list, pidlist);
73
74         return 0;
75 }
76
77 void read_args(int argc, char *argv[], struct parse_opts *opts)
78 {
79         int option_index = 0, c;
80         static struct option long_options[] = {
81                 { .val = 'p', .name = "pid", .has_arg = 1, },
82                 { .val = 'P', .name = "process", .has_arg = 1, },
83                 { .val = 'm', .name = "map", .has_arg = 1, },
84                 { .val = OPT_WITH_THREADS, .name = "with-threads" },
85                 { .val = 'd', .name = "dump", },
86                 { .val = 's', .name = "shared-mappings", },
87                 { .val = 'h', .name = "help", },
88         };
89         char short_options[] = "p:P:m:sdh";
90         opts->parse_mask = 0;
91
92         while (1) {
93                 c = getopt_long(argc, argv, short_options, long_options,
94                                 &option_index);
95
96                 if (c == -1)
97                         break;
98
99                 switch (c) {
100                 case 'p':
101                 {
102                         int pid = pidstr_is_ok(optarg);
103                         if (!pid) {
104                                 fprintf(stderr, "Invalid pid number %s\n",
105                                         optarg);
106                                 break;
107                         }
108
109                         opts->parse_mask |= PARSE_PID;
110                         add_pid_to_pidlist(pid, &opts->pidlist);
111                         break;
112                 }
113                 case 'P':
114                         get_all_pids_by_name(opts, optarg);
115                         opts->parse_mask |= PARSE_PID;
116                         break;
117                 case 'm':
118                         opts->parse_mask |= PARSE_MAP_NAME;
119                         opts->name = optarg;
120                         break;
121                 case OPT_WITH_THREADS:
122                         opts->with_threads = 1;
123                         break;
124                 case 's':
125                         opts->parse_mask |= PARSE_SHARED_MAPPING;
126                         /* implies --dump */
127                 case 'd':
128                         opts->parse_mask |= PARSE_DUMP;
129                         break;
130                 case 'h':
131                         print_help_and_die(argv[0]);
132                         break;
133                 }
134         }
135
136         while (optind < argc) {
137                 int pid = pidstr_is_ok(argv[optind]);
138
139                 if (pid) {
140                         opts->parse_mask |= PARSE_PID;
141                         add_pid_to_pidlist(pid, &opts->pidlist);
142                 } else {
143                         get_all_pids_by_name(opts, argv[optind]);
144                         opts->parse_mask |= PARSE_PID;
145                 }
146                 optind++;
147         }
148 }
149
150 int main(int argc, char *argv[])
151 {
152         struct pageframe pf;
153         struct process process_list;
154         struct parse_opts opts;
155
156         if (geteuid()) {
157                 printf("WARNING: Running without root priviledges. "
158                         "Results may be inaccurate\n");
159         }
160
161         init_parse_opts(&opts);
162
163         read_args(argc, argv, &opts);
164
165         if (argc < 2) {
166                 opts.parse_mask = PARSE_MAP_NAME;
167                 opts.name = "";
168         }
169
170         clear_pageframe(&pf);
171
172         memset(&process_list, 0, sizeof(process_list));
173         INIT_LIST_HEAD(&process_list.list);
174
175         if (scan_all_pids(&pf, &process_list, &opts))
176                 return 1;
177
178         update_kpageflags(&pf);
179
180         if (opts.parse_mask & PARSE_DUMP)
181                 dump_process_maps(&pf, &process_list, &opts);
182         else
183                 print_pid_stats(&pf, &process_list, &opts);
184
185         print_page_stats(&pf);
186
187         return 0;
188 }