utils.c revision efd13938013099e58f4dcbf818f508c585547817
19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <dirent.h>
1852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <errno.h>
1952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <fcntl.h>
2052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <limits.h>
2152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <poll.h>
2252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <signal.h>
2352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <stdarg.h>
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdio.h>
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <stdlib.h>
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <string.h>
2752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <sys/inotify.h>
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/stat.h>
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/time.h>
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <sys/wait.h>
3152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <time.h>
3252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <unistd.h>
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include <cutils/properties.h>
3552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor#include <cutils/sockets.h>
36efd13938013099e58f4dcbf818f508c585547817Dan Egnor#include <private/android_filesystem_config.h>
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project#include "dumpstate.h"
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* prints the contents of a file */
4252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorint dump_file(const char *title, const char* path) {
4352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    char buffer[32768];
4452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    int fd = open(path, O_RDONLY);
4552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (fd < 0) {
4652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        int err = errno;
47ea11654e684cb91252487f697c72e76da507f7beDan Egnor        if (title) printf("------ %s (%s) ------\n", title, path);
4852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        printf("*** %s: %s\n", path, strerror(err));
4952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (title) printf("\n");
5052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        return -1;
5152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
53ea11654e684cb91252487f697c72e76da507f7beDan Egnor    if (title) printf("------ %s (%s", title, path);
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (title) {
5652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        struct stat st;
5752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (memcmp(path, "/proc/", 6) && memcmp(path, "/sys/", 5) && !fstat(fd, &st)) {
5852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            char stamp[80];
5952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            time_t mtime = st.st_mtime;
6052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
6152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            printf(": %s", stamp);
6252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        }
63ea11654e684cb91252487f697c72e76da507f7beDan Egnor        printf(") ------\n");
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    int newline = 0;
6752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    for (;;) {
6852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        int ret = read(fd, buffer, sizeof(buffer));
6952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (ret > 0) {
7052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            newline = (buffer[ret - 1] == '\n');
7152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            ret = fwrite(buffer, ret, 1, stdout);
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (ret <= 0) break;
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    close(fd);
7752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (!newline) printf("\n");
7852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (title) printf("\n");
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    return 0;
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/* forks a command and waits for it to finish */
8352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorint run_command(const char *title, int timeout_seconds, const char *command, ...) {
8452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    fflush(stdout);
8552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    clock_t start = clock();
8652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    pid_t pid = fork();
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* handle error case */
8952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (pid < 0) {
9052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        printf("*** fork: %s\n", strerror(errno));
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return pid;
9252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* handle child case */
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (pid == 0) {
9652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        const char *args[1024] = {command};
9752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        size_t arg;
9852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
9952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        va_list ap;
10052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        va_start(ap, command);
101ea11654e684cb91252487f697c72e76da507f7beDan Egnor        if (title) printf("------ %s (%s", title, command);
10252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
10352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            args[arg] = va_arg(ap, const char *);
10452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            if (args[arg] == NULL) break;
10552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            if (title) printf(" %s", args[arg]);
10652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        }
107ea11654e684cb91252487f697c72e76da507f7beDan Egnor        if (title) printf(") ------\n");
10852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fflush(stdout);
10952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
11052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        execvp(command, (char**) args);
11152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        printf("*** exec(%s): %s\n", command, strerror(errno));
11252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        _exit(-1);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* handle parent case */
11652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    for (;;) {
11752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        int status;
11852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        pid_t p = waitpid(pid, &status, WNOHANG);
11952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        float elapsed = (float) (clock() - start) / CLOCKS_PER_SEC;
12052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (p == pid) {
12152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            if (WIFSIGNALED(status)) {
12252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor                printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
12352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            } else if (WEXITSTATUS(status) > 0) {
12452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor                printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
12552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            }
12652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            if (title) printf("[%s: %.1fs elapsed]\n\n", command, elapsed);
12752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            return status;
12852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        }
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (timeout_seconds && elapsed > timeout_seconds) {
13152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            printf("*** %s: Timed out after %.1fs (killing pid %d)\n", command, elapsed, pid);
13252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            kill(pid, SIGTERM);
13352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            return -1;
13452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        }
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
13652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        usleep(100000);  // poll every 0.1 sec
13752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
13852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor}
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorsize_t num_props = 0;
14152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorstatic char* props[2000];
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
14352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorstatic void print_prop(const char *key, const char *name, void *user) {
14452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    (void) user;
14552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (num_props < sizeof(props) / sizeof(props[0])) {
14652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        char buf[PROPERTY_KEY_MAX + PROPERTY_VALUE_MAX + 10];
14752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        snprintf(buf, sizeof(buf), "[%s]: [%s]\n", key, name);
14852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        props[num_props++] = strdup(buf);
14952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorstatic int compare_prop(const void *a, const void *b) {
15352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    return strcmp(*(char * const *) a, *(char * const *) b);
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
15652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor/* prints all the system properties */
15752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorvoid print_properties() {
15852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    size_t i;
15952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    num_props = 0;
16052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    property_list(print_prop, NULL);
16152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    qsort(&props, num_props, sizeof(props[0]), compare_prop);
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
163ea11654e684cb91252487f697c72e76da507f7beDan Egnor    printf("------ SYSTEM PROPERTIES ------\n");
16452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    for (i = 0; i < num_props; ++i) {
16552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fputs(props[i], stdout);
16652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        free(props[i]);
16752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
16852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    printf("\n");
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
17152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor/* redirect output to a service control socket */
17252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorvoid redirect_to_socket(FILE *redirect, const char *service) {
17352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    int s = android_get_control_socket(service);
17452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (s < 0) {
17552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno));
17652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        exit(1);
17752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
17852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (listen(s, 4) < 0) {
17952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fprintf(stderr, "listen(control socket): %s\n", strerror(errno));
18052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        exit(1);
18152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
18352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    struct sockaddr addr;
18452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    socklen_t alen = sizeof(addr);
18552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    int fd = accept(s, &addr, &alen);
18652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (fd < 0) {
18752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fprintf(stderr, "accept(control socket): %s\n", strerror(errno));
18852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        exit(1);
18952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    fflush(redirect);
19252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    dup2(fd, fileno(redirect));
19352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    close(fd);
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor/* redirect output to a file, optionally gzipping; returns gzip pid (or -1) */
19752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorpid_t redirect_to_file(FILE *redirect, char *path, int gzip_level) {
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    char *chp = path;
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /* skip initial slash */
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    if (chp[0] == '/')
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        chp++;
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
20452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    /* create leading directories, if necessary */
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    while (chp && chp[0]) {
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        chp = strchr(chp, '/');
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (chp) {
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            *chp = 0;
20952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            mkdir(path, 0775);  /* drwxrwxr-x */
21052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            *chp++ = '/';
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
21452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
21552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (fd < 0) {
21652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fprintf(stderr, "%s: %s\n", path, strerror(errno));
21752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        exit(1);
21852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
21952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
22052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    pid_t gzip_pid = -1;
22152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (gzip_level > 0) {
22252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        int fds[2];
22352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (pipe(fds)) {
22452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            fprintf(stderr, "pipe: %s\n", strerror(errno));
22552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            exit(1);
22652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        }
22752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
22852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fflush(redirect);
22952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fflush(stdout);
23052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
23152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        gzip_pid = fork();
23252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (gzip_pid < 0) {
23352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            fprintf(stderr, "fork: %s\n", strerror(errno));
23452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            exit(1);
23552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        }
23652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
23752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (gzip_pid == 0) {
23852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            dup2(fds[0], STDIN_FILENO);
23952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            dup2(fd, STDOUT_FILENO);
24052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
24152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            close(fd);
24252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            close(fds[0]);
24352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            close(fds[1]);
24452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
24552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            char level[10];
24652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            snprintf(level, sizeof(level), "-%d", gzip_level);
24752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            execlp("gzip", "gzip", level, NULL);
24852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            fprintf(stderr, "exec(gzip): %s\n", strerror(errno));
24952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            _exit(-1);
25052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        }
25152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
25252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        close(fd);
25352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        close(fds[0]);
25452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fd = fds[1];
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
25652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
25752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    dup2(fd, fileno(redirect));
25852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    close(fd);
25952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    return gzip_pid;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
26252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor/* dump Dalvik stack traces, return the trace file location (NULL if none) */
26352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnorconst char *dump_vm_traces() {
26452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    char traces_path[PROPERTY_VALUE_MAX] = "";
26552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    property_get("dalvik.vm.stack-trace-file", traces_path, "");
26652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (!traces_path[0]) return NULL;
26752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
26852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    /* move the old traces.txt (if any) out of the way temporarily */
26952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    char anr_traces_path[PATH_MAX];
27052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    strlcpy(anr_traces_path, traces_path, sizeof(anr_traces_path));
27152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    strlcat(anr_traces_path, ".anr", sizeof(anr_traces_path));
2726a70d7d1e28bd0b98d03e7ecab3fd08ea5973e34Dan Egnor    if (rename(traces_path, anr_traces_path) && errno != ENOENT) {
2736a70d7d1e28bd0b98d03e7ecab3fd08ea5973e34Dan Egnor        fprintf(stderr, "rename(%s, %s): %s\n", traces_path, anr_traces_path, strerror(errno));
2746a70d7d1e28bd0b98d03e7ecab3fd08ea5973e34Dan Egnor        return NULL;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
2756a70d7d1e28bd0b98d03e7ecab3fd08ea5973e34Dan Egnor    }
27652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
277efd13938013099e58f4dcbf818f508c585547817Dan Egnor    /* make the directory if necessary */
278efd13938013099e58f4dcbf818f508c585547817Dan Egnor    char anr_traces_dir[PATH_MAX];
279efd13938013099e58f4dcbf818f508c585547817Dan Egnor    strlcpy(anr_traces_dir, traces_path, sizeof(anr_traces_dir));
280efd13938013099e58f4dcbf818f508c585547817Dan Egnor    char *slash = strrchr(anr_traces_dir, '/');
281efd13938013099e58f4dcbf818f508c585547817Dan Egnor    if (slash != NULL) {
282efd13938013099e58f4dcbf818f508c585547817Dan Egnor        *slash = '\0';
283efd13938013099e58f4dcbf818f508c585547817Dan Egnor        if (!mkdir(anr_traces_dir, 0775)) {
284efd13938013099e58f4dcbf818f508c585547817Dan Egnor            chown(anr_traces_dir, AID_SYSTEM, AID_SYSTEM);
285efd13938013099e58f4dcbf818f508c585547817Dan Egnor        } else if (errno != EEXIST) {
286efd13938013099e58f4dcbf818f508c585547817Dan Egnor            fprintf(stderr, "mkdir(%s): %s\n", anr_traces_dir, strerror(errno));
287efd13938013099e58f4dcbf818f508c585547817Dan Egnor            return NULL;
288efd13938013099e58f4dcbf818f508c585547817Dan Egnor        }
289efd13938013099e58f4dcbf818f508c585547817Dan Egnor    }
290efd13938013099e58f4dcbf818f508c585547817Dan Egnor
29152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    /* create a new, empty traces.txt file to receive stack dumps */
29252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC, 0666);  /* -rw-rw-rw- */
29352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (fd < 0) {
29452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fprintf(stderr, "%s: %s\n", traces_path, strerror(errno));
29552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        return NULL;
29652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
29752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    close(fd);
29852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
29952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    /* walk /proc and kill -QUIT all Dalvik processes */
30052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    DIR *proc = opendir("/proc");
30152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (proc == NULL) {
30252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fprintf(stderr, "/proc: %s\n", strerror(errno));
30352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        return NULL;
30452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
30552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
30652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    /* use inotify to find when processes are done dumping */
30752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    int ifd = inotify_init();
30852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (ifd < 0) {
30952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fprintf(stderr, "inotify_init: %s\n", strerror(errno));
31052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        return NULL;
31152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
31252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
31352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    int wfd = inotify_add_watch(ifd, traces_path, IN_CLOSE_WRITE);
31452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (wfd < 0) {
31552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fprintf(stderr, "inotify_add_watch(%s): %s\n", traces_path, strerror(errno));
31652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        return NULL;
31752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
31952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    struct dirent *d;
320efd13938013099e58f4dcbf818f508c585547817Dan Egnor    int dalvik_found = 0;
32152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    while ((d = readdir(proc))) {
32252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        int pid = atoi(d->d_name);
32352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (pid <= 0) continue;
32452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
32552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        /* identify Dalvik: /proc/(pid)/exe = /system/bin/app_process */
32652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        char path[PATH_MAX], data[PATH_MAX];
32752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        snprintf(path, sizeof(path), "/proc/%d/exe", pid);
32852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        size_t len = readlink(path, data, sizeof(data) - 1);
32952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (len <= 0 || memcmp(data, "/system/bin/app_process", 23)) continue;
33052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
33152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        /* skip zygote -- it won't dump its stack anyway */
33252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
33352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        int fd = open(path, O_RDONLY);
33452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        len = read(fd, data, sizeof(data) - 1);
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        close(fd);
33652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (len <= 0 || !memcmp(data, "zygote", 6)) continue;
33752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
338efd13938013099e58f4dcbf818f508c585547817Dan Egnor        ++dalvik_found;
33952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (kill(pid, SIGQUIT)) {
34052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
34152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            continue;
34252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        }
34352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
34452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        /* wait for the writable-close notification from inotify */
34552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        struct pollfd pfd = { ifd, POLLIN, 0 };
34652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        int ret = poll(&pfd, 1, 200);  /* 200 msec timeout */
34752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        if (ret < 0) {
34852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            fprintf(stderr, "poll: %s\n", strerror(errno));
34952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        } else if (ret == 0) {
35052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            fprintf(stderr, "warning: timed out dumping pid %d\n", pid);
35152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        } else {
35252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            struct inotify_event ie;
35352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor            read(ifd, &ie, sizeof(ie));
35452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        }
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
35652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
35752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    close(ifd);
358efd13938013099e58f4dcbf818f508c585547817Dan Egnor    if (dalvik_found == 0) {
359efd13938013099e58f4dcbf818f508c585547817Dan Egnor        fprintf(stderr, "Warning: no Dalvik processes found to dump stacks\n");
360efd13938013099e58f4dcbf818f508c585547817Dan Egnor    }
36152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
36252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    static char dump_traces_path[PATH_MAX];
36352952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    strlcpy(dump_traces_path, traces_path, sizeof(dump_traces_path));
36452952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    strlcat(dump_traces_path, ".bugreport", sizeof(dump_traces_path));
36552952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    if (rename(traces_path, dump_traces_path)) {
36652952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        fprintf(stderr, "rename(%s, %s): %s\n", traces_path, dump_traces_path, strerror(errno));
36752952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor        return NULL;
36852952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    }
36952952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor
37052952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    /* replace the saved [ANR] traces.txt file */
37152952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    rename(anr_traces_path, traces_path);
37252952b1bcab28f655775efbad8f2e2b41d06a34bDan Egnor    return dump_traces_path;
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
374