logwrapper.c revision dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0
1dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project/*
2dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
3dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
4dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * you may not use this file except in compliance with the License.
6dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * You may obtain a copy of the License at
7dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
8dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *
10dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * See the License for the specific language governing permissions and
14dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project * limitations under the License.
15dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project */
16dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
17dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <string.h>
18dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/types.h>
19dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <sys/wait.h>
20dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdio.h>
21dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <stdlib.h>
22dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <unistd.h>
23dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <errno.h>
24dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include <fcntl.h>
25dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "private/android_filesystem_config.h"
27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "cutils/log.h"
28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid fatal(const char *msg) {
30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fprintf(stderr, msg);
31dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    LOG(LOG_ERROR, "logwrapper", msg);
32dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    exit(-1);
33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid usage() {
36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    fatal(
37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        "Usage: logwrapper [-x] BINARY [ARGS ...]\n"
38dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        "\n"
39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        "Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        "the Android logging system. Tag is set to BINARY, priority is\n"
41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        "always LOG_INFO.\n"
42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        "\n"
43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        "-x: Causes logwrapper to SIGSEGV when BINARY terminates\n"
44dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        "    fault address is set to the status of wait()\n");
45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid parent(const char *tag, int seg_fault_on_exit, int parent_read) {
48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int status;
49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char buffer[4096];
50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int a = 0;  // start index of unprocessed data
52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int b = 0;  // end index of unprocessed data
53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int sz;
54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) {
55dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
56dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        sz += b;
57dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // Log one line at a time
58dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        for (b = 0; b < sz; b++) {
59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            if (buffer[b] == '\r') {
60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                buffer[b] = '\0';
61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            } else if (buffer[b] == '\n') {
62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                buffer[b] = '\0';
63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                LOG(LOG_INFO, tag, &buffer[a]);
64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                a = b + 1;
65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            }
66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
68dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (a == 0 && b == sizeof(buffer) - 1) {
69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            // buffer is full, flush
70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            buffer[b] = '\0';
71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG(LOG_INFO, tag, &buffer[a]);
72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            b = 0;
73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else if (a != b) {
74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            // Keep left-overs
75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            b -= a;
76dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            memmove(buffer, &buffer[a], b);
77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            a = 0;
78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        } else {
79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            a = 0;
80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            b = 0;
81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // Flush remaining data
85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (a != b) {
86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        buffer[b] = '\0';
87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG(LOG_INFO, tag, &buffer[a]);
88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    status = 0xAAAA;
90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (wait(&status) != -1) {  // Wait for child
91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (WIFEXITED(status))
92dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag,
93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    WEXITSTATUS(status));
94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        else if (WIFSIGNALED(status))
95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag,
96dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    WTERMSIG(status));
97dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        else if (WIFSTOPPED(status))
98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            LOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag,
99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                    WSTOPSIG(status));
100dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else
101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag,
102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project                strerror(errno), errno);
103dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (seg_fault_on_exit)
104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        *(int *)status = 0;  // causes SIGSEGV with fault_address = status
105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
106dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid child(int argc, char* argv[]) {
108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    // create null terminated argv_child array
109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char* argv_child[argc + 1];
110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    memcpy(argv_child, argv, argc * sizeof(char *));
111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    argv_child[argc] = NULL;
112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (execvp(argv_child[0], argv_child)) {
114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        LOG(LOG_ERROR, "logwrapper",
115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            "executing %s failed: %s\n", argv_child[0], strerror(errno));
116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        exit(-1);
117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
119dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint main(int argc, char* argv[]) {
121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid_t pid;
122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int seg_fault_on_exit = 0;
123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int parent_ptty;
125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    int child_ptty;
126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    char *child_devname = NULL;
127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (argc < 2) {
129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        usage();
130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (strncmp(argv[1], "-d", 2) == 0) {
133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        seg_fault_on_exit = 1;
134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        argc--;
135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        argv++;
136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (argc < 2) {
139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        usage();
140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    /* Use ptty instead of socketpair so that STDOUT is not buffered */
143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    parent_ptty = open("/dev/ptmx", O_RDWR);
144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (parent_ptty < 0) {
145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fatal("Cannot create parent ptty\n");
146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (grantpt(parent_ptty) || unlockpt(parent_ptty) ||
149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            ((child_devname = (char*)ptsname(parent_ptty)) == 0)) {
150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fatal("Problem with /dev/ptmx\n");
151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    pid = fork();
154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    if (pid < 0) {
155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        fatal("Failed to fork\n");
156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else if (pid == 0) {
157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        child_ptty = open(child_devname, O_RDWR);
158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        if (child_ptty < 0) {
159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project            fatal("Problem with child ptty\n");
160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        }
161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // redirect stdout and stderr
163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        close(parent_ptty);
164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        dup2(child_ptty, 1);
165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        dup2(child_ptty, 2);
166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        close(child_ptty);
167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        child(argc - 1, &argv[1]);
169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    } else {
171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // switch user and group to "log"
172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // this may fail if we are not root,
173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        // but in that case switching user/group is unnecessary
174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        setgid(AID_LOG);
175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        setuid(AID_LOG);
176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project        parent(argv[1], seg_fault_on_exit, parent_ptty);
178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    }
179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project
180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project    return 0;
181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project}
182