android_system_core/logwrapper/logwrapper.c
Tom Cherry 013289364e logwrapper: open child_ptty in child process and remove ignore_int_quit
Opening child_ptty before fork() means that the parent process will
use child_ptty as the controlling terminal if it doesn't already have
one.  This is a problem, because when the parent_ptty closes, SIGHUP
will be sent to the parent process, since its controlling terminal has
closed.

It's better to have the child process start its own session and then
open child_ptty as its controlling terminal.  In this case, the child
process will get SIGHUP if the parent process exits, but the parent
process avoids the original issue.

There is a concern that the child_ptty will never be opened and
POLLHUP will never be generated, but there is a work-around in place
with a timeout to handle that extremely rare situation.

Secondly, remove the ignore_int_quit logic.  It is described to
totally ignore these signals, similar to `nohup` which should be
preferred.  However, it regressed shortly after being introduced in
2013 and serves essentially no purpose currently.

Thirdly, add a forward_signals option that does what we should have
done the whole time with signals: it forwards SIGHUP, SIGQUIT, and
SIGINT to the child process and let that process handle them.  This
only needs to be enabled in the `logwrapper` case itself.  Other
processes should not need to change any signals.  This fixes case 3)
below.

Lastly, add O_CLOEXEC where appropriate.

Test: launch process as `adb shell logwrapper yes`
      1) The both processes exit when given SIGINT
      2) The process prints when abbreviated is not enabled
      3) The process does print when abbreviated is enabled;
         this was previously broken
Test: launch process as `adb shell` then `logwrapper yes`
      4) The both processes exit when given SIGINT
      5) The process prints if abbreviated is enabled or not.
      6) Ctrl-c then Ctrl-c again rapidly and observe that the
         logwrapper process is terminated by the second Ctrl-c.
Test: simulate a failure in child() before opening child_tty and
      observe logwrapper and the child exiting appropriately.

Change-Id: Ia76cd17e16535500170d8f5e2183b3bbbf843df7
2019-09-25 12:59:52 -07:00

96 lines
2.7 KiB
C

/*
* Copyright (C) 2008 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>
#include <cutils/klog.h>
#include <log/log.h>
#include <logwrap/logwrap.h>
void fatal(const char *msg) {
fprintf(stderr, "%s", msg);
ALOG(LOG_ERROR, "logwrapper", "%s", msg);
exit(-1);
}
void usage() {
fatal(
"Usage: logwrapper [-a] [-d] [-k] BINARY [ARGS ...]\n"
"\n"
"Forks and executes BINARY ARGS, redirecting stdout and stderr to\n"
"the Android logging system. Tag is set to BINARY, priority is\n"
"always LOG_INFO.\n"
"\n"
"-a: Causes logwrapper to do abbreviated logging.\n"
" This logs up to the first 4K and last 4K of the command\n"
" being run, and logs the output when the command exits\n"
"-d: Causes logwrapper to SIGSEGV when BINARY terminates\n"
" fault address is set to the status of wait()\n"
"-k: Causes logwrapper to log to the kernel log instead of\n"
" the Android system log\n");
}
int main(int argc, char* argv[]) {
int seg_fault_on_exit = 0;
int log_target = LOG_ALOG;
bool abbreviated = false;
int ch;
int status = 0xAAAA;
int rc;
while ((ch = getopt(argc, argv, "adk")) != -1) {
switch (ch) {
case 'a':
abbreviated = true;
break;
case 'd':
seg_fault_on_exit = 1;
break;
case 'k':
log_target = LOG_KLOG;
klog_set_level(6);
break;
case '?':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < 1) {
usage();
}
rc = android_fork_execvp_ext2(argc, &argv[0], &status, true, log_target, abbreviated, NULL);
if (!rc) {
if (WIFEXITED(status))
rc = WEXITSTATUS(status);
else
rc = -ECHILD;
}
if (seg_fault_on_exit) {
uintptr_t fault_address = (uintptr_t) status;
*(int *) fault_address = 0; // causes SIGSEGV with fault_address = status
}
return rc;
}