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