1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20#include <time.h>
21#include <unistd.h>
22#include <sys/stat.h>
23#include <dirent.h>
24#include <limits.h>
25#include <fcntl.h>
26#include <signal.h>
27#include <sys/time.h>
28#include <sys/wait.h>
29
30#include <cutils/properties.h>
31#include <sys/system_properties.h>
32
33#include "dumpstate.h"
34
35
36/* prints the contents of a file */
37int dump_file(const char* path) {
38    char    buffer[32768];
39    int fd, amount_read;
40    int ret = 0;
41
42    fd = open(path, O_RDONLY);
43    if (fd < 0)
44        return fd;
45
46    do {
47        ret = read(fd, buffer, sizeof(buffer));
48        if (ret > 0)
49            ret = write(STDOUT_FILENO, buffer, ret);
50    } while (ret > 0);
51
52    buffer[0] = '\n';
53    write(STDOUT_FILENO, buffer, 1);
54
55    close(fd);
56    return ret;
57}
58
59/* prints the contents of all files in a directory */
60void dump_files(const char* path) {
61    DIR* dir;
62    struct dirent* entry;
63    char buffer[PATH_MAX];
64
65    dir = opendir(path);
66    if (!dir) {
67        fprintf(stderr, "could not open directory %s\n", path);
68        return;
69    }
70
71    while ((entry = readdir(dir))) {
72        if (entry->d_type == DT_REG) {
73            snprintf(buffer, sizeof(buffer), "%s/%s", path, entry->d_name);
74            dump_file(path);
75            printf("\n");
76        }
77    }
78
79    closedir(dir);
80}
81
82/* prints the name and value of a system property */
83int print_property(const char* name) {
84    char    value[PROP_VALUE_MAX];
85
86    __system_property_get(name, value);
87    printf("%s=%s\n", name, value);
88    return 0;
89}
90
91static pid_t alarm_pid = 0;
92static int timed_out = 0;
93static void sig_alarm(int sig)
94{
95    if (alarm_pid) {
96        kill(alarm_pid, SIGKILL);
97        timed_out = 1;
98        alarm_pid = 0;
99    }
100}
101
102/* forks a command and waits for it to finish */
103int run_command(struct Command* cmd, int timeout) {
104    struct sigaction sa;
105    pid_t pid;
106    int status;
107
108    pid = fork();
109    /* handle error case */
110    if (pid < 0)
111        return pid;
112
113    /* handle child case */
114    if (pid == 0) {
115        int ret = execv(cmd->path, cmd->args);
116        if (ret)
117            fprintf(stderr, "execv %s returned %d\n", cmd->path, ret);
118        exit(ret);
119    }
120
121    /* handle parent case */
122    timed_out = 0;
123    if (timeout) {
124        memset(&sa, 0, sizeof(sa));
125        sa.sa_flags = SA_RESETHAND;
126        sa.sa_handler = sig_alarm;
127        sigaction(SIGALRM, &sa, NULL);
128
129        /* set an alarm so we don't hang forever */
130        alarm_pid = pid;
131        alarm(timeout);
132    }
133
134    waitpid(pid, &status, 0);
135
136    if (timed_out)
137        printf("ERROR: command %s timed out\n", cmd->path);
138
139    return status;
140}
141
142/* reads the current time into tm */
143void get_time(struct tm *tm) {
144    time_t t;
145
146    tzset();
147    time(&t);
148    localtime_r(&t, tm);
149}
150
151/* prints the date in tm */
152void print_date(const char* prompt, struct tm *tm) {
153    char strbuf[260];
154
155    strftime(strbuf, sizeof(strbuf),
156             "%a %b %e %H:%M:%S %Z %Y",
157             tm);
158    printf("%s%s\n", prompt, strbuf);
159}
160
161
162static void print_prop(const char *key, const char *name,
163                     void *user __attribute__((unused)))
164{
165    printf("[%s]: [%s]\n", key, name);
166}
167
168/* prints all the system properties */
169void print_properties() {
170    property_list(print_prop, NULL);
171}
172
173/* creates directories as needed for the given path */
174void create_directories(char *path)
175{
176    char *chp = path;
177
178    /* skip initial slash */
179    if (chp[0] == '/')
180        chp++;
181
182    while (chp && chp[0]) {
183        chp = strchr(chp, '/');
184        if (chp) {
185            *chp = 0;
186            mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
187            *chp = '/';
188            chp++;
189        }
190    }
191}
192
193/* runs the vibrator using the given pattern */
194void vibrate_pattern(int fd, int* pattern)
195{
196    struct timespec tm;
197    char    buffer[10];
198
199    while (*pattern) {
200        /* read vibrate on time */
201        int on_time = *pattern++;
202        snprintf(buffer, sizeof(buffer), "%d", on_time);
203        write(fd, buffer, strlen(buffer));
204
205        /* read vibrate off time */
206        int delay = *pattern++;
207        if (delay) {
208            delay += on_time;
209
210            tm.tv_sec = delay / 1000;
211            tm.tv_nsec = (delay % 1000) * 1000000;
212            nanosleep(&tm, NULL);
213        } else
214            break;
215    }
216}
217
218/* prevents the OOM killer from killing us */
219void protect_from_oom_killer()
220{
221    int fd;
222
223    fd = open("/proc/self/oom_adj", O_WRONLY);
224    if (fd >= 0) {
225        // -17 should make us immune to OOM
226        const char* text = "-17";
227        write(fd, text, strlen(text));
228        close(fd);
229    }
230}
231