Fix potentially undefined behavior
[platform/core/system/crash-worker.git] / src / dump_systemstate / dump_systemstate.c
1 /*
2  * dump_systemstate
3  *
4  * Copyright (c) 2012 - 2013 Samsung Electronics Co., Ltd.
5  *
6  * Licensed under the Apache License, Version 2.0 (the License);
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 /**
20  * @file    dump_systemstate.c
21  * @brief   dump system states.
22  */
23
24 #include <stdbool.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #include <time.h>
31 #include <limits.h>
32 #include <getopt.h>
33 #include <sys/stat.h>
34 #include <sys/vfs.h>
35
36 #include "shared/util.h"
37 #include "shared/log.h"
38
39 #define FILE_PERM (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)
40 static struct dump_item {
41         const char *title;
42         const char *path;
43 } dump_item[] = {
44         {"==== Binary version "            , "/etc/info.ini"},
45         {"==== Tizen version "             , "/etc/tizen-release"},
46         {"==== Kernel version "            , "/proc/version"},
47         {"==== Boot arguments "            , "/proc/cmdline"},
48         {"==== CPU & system architecture " , "/proc/cpuinfo"},
49         {"==== System uptime "             , "/proc/uptime"},
50         {"==== System statistics "         , "/proc/stat"},
51         {"==== System memory usage "       , "/proc/meminfo"},
52         {"==== Device major numbers "      , "/proc/devices"},
53         {"==== System disk I/O satistics " , "/proc/diskstats"},
54 };
55
56 static void usage()
57 {
58         fprintf(stderr, "usage: dump_systemstate [-k] [-d] [-f file]\n"
59                         "  -f: write to file (instead of stdout)\n"
60                         "  -k: dump kernel messages (only root)\n"
61                         "  -d: dump dlog messages\n"
62                         "  -j: dump journal log messages\n"
63            );
64 }
65
66 /* get disk used percentage */
67 static int get_disk_used_percent(const char *path)
68 {
69         struct statfs lstatfs;
70         int percent;
71
72         if (!path)
73                 return -1;
74
75         if (statfs(path, &lstatfs) < 0)
76                 return -1;
77         percent = (((lstatfs.f_blocks - lstatfs.f_bfree) * 1000) / (lstatfs.f_blocks)) + 9;
78         percent = percent/10;
79         return percent;
80 }
81
82 int main(int argc, char *argv[])
83 {
84         int c, ret, i, is_root, dpercent;
85         const char *arg_file = NULL;
86         int out_fd = -1;
87         bool arg_dlog = false;
88         bool arg_dmesg = false;
89         bool arg_journal = false;
90         char timestr[80];
91         time_t cur_time;
92         struct tm gm_tm;
93         struct tm loc_tm;
94
95         while ((c = getopt(argc, argv, "hf:kdj")) != -1) {
96                 switch (c) {
97                 case 'd':
98                         arg_dlog = true;
99                         break;
100                 case 'k':
101                         arg_dmesg = true;
102                         break;
103                 case 'j':
104                         arg_journal = true;
105                         break;
106                 case 'f':
107                         arg_file = optarg;
108                         break;
109                 case '?':
110                 case 'h':
111                         printf("\n");
112                         usage();
113                         ret = 0;
114                         goto exit;
115                 }
116         }
117         ret = 0;
118         cur_time = time(NULL);
119         gmtime_r(&cur_time, &gm_tm);
120         localtime_r(&cur_time, &loc_tm);
121         is_root = !(geteuid());
122
123         /* open output file */
124         if (arg_file == NULL) {
125                 out_fd = STDOUT_FILENO;
126         } else {
127                 out_fd = open(arg_file, O_WRONLY | O_TRUNC | O_CREAT, FILE_PERM);
128                 if (out_fd < 0) {
129                         perror("couldn't open output file");
130                         ret = out_fd;
131                         goto exit;
132                 }
133         }
134         /* print timestamp */
135         strftime(timestr, sizeof(timestr),
136                                         "%Y-%m-%d %H:%M:%S%z", &loc_tm);
137         fprintf_fd(out_fd, "dump_systemstate: %s\n", timestr);
138
139         for (i = 0; i < ARRAY_SIZE(dump_item); i++) {
140                 fsync(out_fd);
141                 fprintf_fd(out_fd, "\n%s(%s)\n",
142                                                 dump_item[i].title, dump_item[i].path);
143                 ret = dump_file_write_fd((char *)dump_item[i].path, out_fd);
144                 if (ret < 0)
145                         goto exit_close;
146         }
147         fprintf_fd(out_fd, "\n");
148
149         fprintf_fd(out_fd, "\n==== System disk space usage (/bin/df -h)\n");
150         ret = run_command_write_fd("/bin/df -h", out_fd);
151         if (ret < 0)
152                 goto exit_close;
153
154         dpercent = get_disk_used_percent("/opt");
155         if (90 < dpercent) {
156                 fprintf_fd(out_fd, "\n==== System disk space usage detail - %d\% (/bin/du -ah /opt)\n", dpercent);
157                 ret = run_command_write_fd("/usr/bin/du -ah /opt --exclude=/opt/usr", out_fd);
158                 if (ret < 0)
159                         goto exit_close;
160         }
161         fprintf_fd(out_fd, "\n==== System timezone (ls -al /opt/etc/localtime)\n");
162         ret = run_command_write_fd("ls -al /opt/etc/localtime", out_fd);
163         if (ret < 0)
164                 goto exit_close;
165
166         fprintf_fd(out_fd, "\n==== System summary (/usr/bin/top -bcH -n 1)\n");
167         ret = run_command_write_fd("COLUMNS=200 /usr/bin/top -bcH -n 1", out_fd);
168         if (ret < 0)
169                 goto exit_close;
170
171         fprintf_fd(out_fd, "\n==== Current processes (/bin/ps auxfw)\n");
172         ret = run_command_write_fd("/bin/ps auxfw", out_fd);
173         if (ret < 0)
174                 goto exit_close;
175
176         fprintf_fd(out_fd, "\n==== System memory statistics (/usr/bin/memps -v)\n");
177         ret = run_command_write_fd("/usr/bin/memps -v", out_fd);
178         if (ret < 0)
179                 goto exit_close;
180
181         if (is_root) {
182                 fprintf_fd(out_fd, "\n==== System configuration (/usr/bin/vconftool get memory, db, file)\n");
183                 ret = run_command_write_fd("/usr/bin/vconftool get memory/ -r", out_fd);
184                 if (ret < 0)
185                         goto exit_close;
186
187                 ret = run_command_write_fd("/usr/bin/vconftool get db/ -r", out_fd);
188                 if (ret < 0)
189                         goto exit_close;
190
191                 ret = run_command_write_fd("/usr/bin/vconftool get file/ -r", out_fd);
192                 if (ret < 0)
193                         goto exit_close;
194         }
195
196         if (arg_dmesg && is_root) {
197                 fprintf_fd(out_fd, "\n==== Kernel messages (TZ=UTC /bin/dmesg -T)\n");
198                 ret = run_command_write_fd("TZ=UTC /bin/dmesg -T", out_fd);
199                 if (ret < 0)
200                         goto exit_close;
201         }
202
203         if (arg_dlog) {
204                 fprintf_fd(out_fd, "\n==== Log messages\n");
205                 ret = run_command_write_fd("/usr/bin/dlogutil -d -v threadtime -u 16384", out_fd);
206                 if (ret < 0)
207                         goto exit_close;
208         }
209
210         if (arg_journal) {
211                 fprintf_fd(out_fd, "\n==== Journal messages\n");
212                 ret = run_command_write_fd("/usr/bin/journalctl -b -n 1024", out_fd);
213                 if (ret < 0)
214                         goto exit_close;
215         }
216
217 exit_close:
218         if (arg_file)
219                 close(out_fd);
220 exit:
221         return ret;
222 }