logwrapper.c revision 1f28b775cfad4cf3d9112a4ad18603b34fb84fac
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> 251f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot#include <libgen.h> 26dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 27dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "private/android_filesystem_config.h" 28dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project#include "cutils/log.h" 29dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 30dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid fatal(const char *msg) { 31dd26bb3a00b95dc8448d2d35bcee52c8e1880096Nick Kralevich fprintf(stderr, "%s", msg); 3261fbcbe9761bbfdebb0b1f8147faf00cbb1c6e6aSteve Block ALOG(LOG_ERROR, "logwrapper", "%s", msg); 33dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project exit(-1); 34dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 35dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 36dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid usage() { 37dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project fatal( 381f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot "Usage: logwrapper [-d] BINARY [ARGS ...]\n" 39dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project "\n" 40dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project "Forks and executes BINARY ARGS, redirecting stdout and stderr to\n" 41dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project "the Android logging system. Tag is set to BINARY, priority is\n" 42dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project "always LOG_INFO.\n" 43dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project "\n" 441f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot "-d: Causes logwrapper to SIGSEGV when BINARY terminates\n" 45dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project " fault address is set to the status of wait()\n"); 46dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 47dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 48dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid parent(const char *tag, int seg_fault_on_exit, int parent_read) { 49dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int status; 50dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project char buffer[4096]; 51dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 52dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int a = 0; // start index of unprocessed data 53dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int b = 0; // end index of unprocessed data 54dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int sz; 551f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot 561f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot char *btag = basename(tag); 571f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot if (!btag) btag = (char*) tag; 581f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot 59dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project while ((sz = read(parent_read, &buffer[b], sizeof(buffer) - 1 - b)) > 0) { 60dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 61dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project sz += b; 62dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Log one line at a time 63dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project for (b = 0; b < sz; b++) { 64dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (buffer[b] == '\r') { 65dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project buffer[b] = '\0'; 66dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else if (buffer[b] == '\n') { 67dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project buffer[b] = '\0'; 681f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot ALOG(LOG_INFO, btag, "%s", &buffer[a]); 69dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project a = b + 1; 70dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 71dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 72dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 73dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (a == 0 && b == sizeof(buffer) - 1) { 74dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // buffer is full, flush 75dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project buffer[b] = '\0'; 761f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot ALOG(LOG_INFO, btag, "%s", &buffer[a]); 77dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project b = 0; 78dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else if (a != b) { 79dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Keep left-overs 80dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project b -= a; 81dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project memmove(buffer, &buffer[a], b); 82dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project a = 0; 83dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 84dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project a = 0; 85dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project b = 0; 86dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 87dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 88dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 89dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // Flush remaining data 90dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (a != b) { 91dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project buffer[b] = '\0'; 921f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot ALOG(LOG_INFO, btag, "%s", &buffer[a]); 93dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 94dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project status = 0xAAAA; 95dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (wait(&status) != -1) { // Wait for child 961f28b775cfad4cf3d9112a4ad18603b34fb84facTanguy Pruvot if (WIFEXITED(status) && WEXITSTATUS(status)) 9761fbcbe9761bbfdebb0b1f8147faf00cbb1c6e6aSteve Block ALOG(LOG_INFO, "logwrapper", "%s terminated by exit(%d)", tag, 98dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project WEXITSTATUS(status)); 99dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project else if (WIFSIGNALED(status)) 10061fbcbe9761bbfdebb0b1f8147faf00cbb1c6e6aSteve Block ALOG(LOG_INFO, "logwrapper", "%s terminated by signal %d", tag, 101dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project WTERMSIG(status)); 102dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project else if (WIFSTOPPED(status)) 10361fbcbe9761bbfdebb0b1f8147faf00cbb1c6e6aSteve Block ALOG(LOG_INFO, "logwrapper", "%s stopped by signal %d", tag, 104dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project WSTOPSIG(status)); 105dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else 10661fbcbe9761bbfdebb0b1f8147faf00cbb1c6e6aSteve Block ALOG(LOG_INFO, "logwrapper", "%s wait() failed: %s (%d)", tag, 107dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project strerror(errno), errno); 108dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (seg_fault_on_exit) 109dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project *(int *)status = 0; // causes SIGSEGV with fault_address = status 110dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 111dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 112dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectvoid child(int argc, char* argv[]) { 113dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // create null terminated argv_child array 114dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project char* argv_child[argc + 1]; 115dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project memcpy(argv_child, argv, argc * sizeof(char *)); 116dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project argv_child[argc] = NULL; 117dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 118dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (execvp(argv_child[0], argv_child)) { 11961fbcbe9761bbfdebb0b1f8147faf00cbb1c6e6aSteve Block ALOG(LOG_ERROR, "logwrapper", 120dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project "executing %s failed: %s\n", argv_child[0], strerror(errno)); 121dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project exit(-1); 122dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 123dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 124dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 125dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Projectint main(int argc, char* argv[]) { 126dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project pid_t pid; 127dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int seg_fault_on_exit = 0; 128dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 129dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int parent_ptty; 130dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project int child_ptty; 131dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project char *child_devname = NULL; 132dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 133dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (argc < 2) { 134dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project usage(); 135dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 136dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 137dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (strncmp(argv[1], "-d", 2) == 0) { 138dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project seg_fault_on_exit = 1; 139dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project argc--; 140dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project argv++; 141dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 142dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 143dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (argc < 2) { 144dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project usage(); 145dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 146dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 147dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project /* Use ptty instead of socketpair so that STDOUT is not buffered */ 148dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project parent_ptty = open("/dev/ptmx", O_RDWR); 149dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (parent_ptty < 0) { 150dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project fatal("Cannot create parent ptty\n"); 151dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 152dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 153dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (grantpt(parent_ptty) || unlockpt(parent_ptty) || 154dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project ((child_devname = (char*)ptsname(parent_ptty)) == 0)) { 155dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project fatal("Problem with /dev/ptmx\n"); 156dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 157dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 158dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project pid = fork(); 159dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (pid < 0) { 160dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project fatal("Failed to fork\n"); 161dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else if (pid == 0) { 162dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project child_ptty = open(child_devname, O_RDWR); 163dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project if (child_ptty < 0) { 164dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project fatal("Problem with child ptty\n"); 165dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 166dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 167dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // redirect stdout and stderr 168dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project close(parent_ptty); 169dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project dup2(child_ptty, 1); 170dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project dup2(child_ptty, 2); 171dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project close(child_ptty); 172dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 173dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project child(argc - 1, &argv[1]); 174dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 175dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } else { 176dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // switch user and group to "log" 177dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // this may fail if we are not root, 178dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project // but in that case switching user/group is unnecessary 179dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project setgid(AID_LOG); 180dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project setuid(AID_LOG); 181dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 182dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project parent(argv[1], seg_fault_on_exit, parent_ptty); 183dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project } 184dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project 185dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project return 0; 186dd7bc3319deb2b77c5d07a51b7d6cd7e11b5beb0The Android Open Source Project} 187