logwrapper.c revision 4f6e8d7a00cbeda1e70cc15be9c4af1018bdad53
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 <string.h> 18#include <sys/types.h> 19#include <sys/wait.h> 20#include <stdio.h> 21#include <stdlib.h> 22#include <unistd.h> 23#include <errno.h> 24 25#include "cutils/log.h" 26 27void fatal(const char *msg) { 28 fprintf(stderr, msg); 29 LOG(LOG_ERROR, "logwrapper", msg); 30 exit(-1); 31} 32 33void usage() { 34 fatal( 35 "Usage: logwrapper BINARY [ARGS ...]\n" 36 "\n" 37 "Forks and executes BINARY ARGS, redirecting stdout and stderr to\n" 38 "the Android logging system. Tag is set to BINARY, priority is\n" 39 "always LOG_INFO.\n"); 40} 41 42void parent(const char *tag, int parent_read) { 43 int status; 44 char buffer[1024]; 45 46 int a = 0; // start index of unprocessed data 47 int b = 0; // end index of unprocessed data 48 int sz; 49 while ((sz = read(parent_read, &buffer[b], 1023 - b)) > 0) { 50 // Log one line at a time 51 for (b = a; b < sz; b++) { 52 if (buffer[b] == '\n') { 53 buffer[b] = '\0'; 54 LOG(LOG_INFO, tag, &buffer[a]); 55 a = b + 1; 56 } 57 } 58 59 if (a == 0 && b == 1023) { 60 // buffer is full, flush 61 buffer[b] = '\0'; 62 LOG(LOG_INFO, tag, &buffer[a]); 63 b = 0; 64 } else { 65 // Keep left-overs 66 b = sz - a; 67 memmove(buffer, &buffer[a], b); 68 a = 0; 69 } 70 } 71 // Flush remaining data 72 if (a != b) { 73 buffer[b] = '\0'; 74 LOG(LOG_INFO, tag, &buffer[a]); 75 } 76 wait(&status); // Wait for child 77} 78 79void child(int argc, char* argv[]) { 80 // create null terminated argv_child array 81 char* argv_child[argc + 1]; 82 memcpy(argv_child, argv, argc * sizeof(char *)); 83 argv_child[argc] = NULL; 84 85 if (execvp(argv_child[0], argv_child)) { 86 LOG(LOG_ERROR, "logwrapper", 87 "executing %s failed: %s\n", argv_child[0], strerror(errno)); 88 exit(-1); 89 } 90} 91 92int main(int argc, char* argv[]) { 93 pid_t pid; 94 95 int pipe_fds[2]; 96 int *parent_read = &pipe_fds[0]; 97 int *child_write = &pipe_fds[1]; 98 99 if (argc < 2) { 100 usage(); 101 } 102 103 if (pipe(pipe_fds) < 0) { 104 fatal("Cannot create pipe\n"); 105 } 106 107 pid = fork(); 108 if (pid < 0) { 109 fatal("Failed to fork\n"); 110 } else if (pid == 0) { 111 // redirect stdout and stderr 112 close(*parent_read); 113 dup2(*child_write, 1); 114 dup2(*child_write, 2); 115 close(*child_write); 116 117 child(argc - 1, &argv[1]); 118 119 } else { 120 close(*child_write); 121 122 parent(argv[1], *parent_read); 123 } 124 125 return 0; 126} 127