1*9c5db199SXin Li#!/usr/bin/python3 2*9c5db199SXin Li 3*9c5db199SXin Lifrom __future__ import absolute_import 4*9c5db199SXin Lifrom __future__ import division 5*9c5db199SXin Lifrom __future__ import print_function 6*9c5db199SXin Liimport common 7*9c5db199SXin Liimport sys, os, signal, time, subprocess, fcntl 8*9c5db199SXin Li 9*9c5db199SXin Li 10*9c5db199SXin Lidef _print_to_file_and_flush(msg, file): 11*9c5db199SXin Li """Print to the provided file, and flush after printing.""" 12*9c5db199SXin Li print(msg, file=file) 13*9c5db199SXin Li file.flush() 14*9c5db199SXin Li 15*9c5db199SXin Lilogdir = sys.argv[1] 16*9c5db199SXin Listdout_start = int(sys.argv[2]) # number of bytes we can skip on stdout 17*9c5db199SXin Listderr_start = int(sys.argv[3]) # nubmer of bytes we can skip on stderr 18*9c5db199SXin Li# TODO (crosbug.com/38224)- sbasi: Remove extra logging. 19*9c5db199SXin Listderr = open(os.path.join(logdir, 'stderr'), 'a', buffering=2) 20*9c5db199SXin Li 21*9c5db199SXin Li_print_to_file_and_flush('Entered autotestd_monitor.', file=stderr) 22*9c5db199SXin Li 23*9c5db199SXin Li# if any of our tail processes die, the monitor should die too 24*9c5db199SXin Lidef kill_self(signum, frame): 25*9c5db199SXin Li os.kill(os.getpid(), signal.SIGTERM) 26*9c5db199SXin Lisignal.signal(signal.SIGCHLD, kill_self) 27*9c5db199SXin Li 28*9c5db199SXin Lidevnull = open(os.devnull, 'w') 29*9c5db199SXin Li 30*9c5db199SXin Li# launch some tail processes to pump the std* streams 31*9c5db199SXin Lidef launch_tail(filename, outstream, start): 32*9c5db199SXin Li path = os.path.join(logdir, filename) 33*9c5db199SXin Li argv = ['tail', '--retry', '--follow=name', '--bytes=+%d' % start, path] 34*9c5db199SXin Li # stdout=sys.stdout fails on pre-2.5 python (bug in subprocess module) 35*9c5db199SXin Li if outstream != subprocess.PIPE and outstream.fileno() == 1: 36*9c5db199SXin Li return subprocess.Popen(argv, stderr=devnull) 37*9c5db199SXin Li else: 38*9c5db199SXin Li return subprocess.Popen(argv, stdout=outstream, stderr=devnull) 39*9c5db199SXin Listdout_pump = launch_tail('stdout', sys.stdout, stdout_start) 40*9c5db199SXin Listderr_pump = launch_tail('stderr', sys.stderr, stderr_start) 41*9c5db199SXin Li 42*9c5db199SXin Li_print_to_file_and_flush('Finished launching tail subprocesses.', file=stderr) 43*9c5db199SXin Li# wait for logdir/started to exist to be sure autotestd is started 44*9c5db199SXin Listart_time = time.time() 45*9c5db199SXin Listarted_file_path = os.path.join(logdir, 'started') 46*9c5db199SXin Liwhile not os.path.exists(started_file_path): 47*9c5db199SXin Li time.sleep(1) 48*9c5db199SXin Li if time.time() - start_time >= 30: 49*9c5db199SXin Li raise Exception("autotestd failed to start in %s" % logdir) 50*9c5db199SXin Li 51*9c5db199SXin Li_print_to_file_and_flush('Finished waiting on autotestd to start.', 52*9c5db199SXin Li file=stderr) 53*9c5db199SXin Li 54*9c5db199SXin Li# watch the exit code file for an exit 55*9c5db199SXin Liexit_code_file = open(os.path.join(logdir, 'exit_code')) 56*9c5db199SXin Lifcntl.flock(exit_code_file, fcntl.LOCK_EX) 57*9c5db199SXin Li_print_to_file_and_flush('Got lock of exit_code_file.', file=stderr) 58*9c5db199SXin Li 59*9c5db199SXin Litry: 60*9c5db199SXin Li exit_code = exit_code_file.read() 61*9c5db199SXin Li if len(exit_code) != 4: 62*9c5db199SXin Li exit_code = -signal.SIGKILL # autotestd was nuked 63*9c5db199SXin Li else: 64*9c5db199SXin Li exit_code = int(exit_code) 65*9c5db199SXin Lifinally: 66*9c5db199SXin Li fcntl.flock(exit_code_file, fcntl.LOCK_UN) 67*9c5db199SXin Li exit_code_file.close() 68*9c5db199SXin Li _print_to_file_and_flush('Released lock of exit_code_file and closed it.', 69*9c5db199SXin Li file=stderr) 70*9c5db199SXin Li 71*9c5db199SXin Li# Give tail a tiny bit of time to finish. 72*9c5db199SXin Litime.sleep(0.01) 73*9c5db199SXin Li 74*9c5db199SXin Li_print_to_file_and_flush('Killing child processes.', file=stderr) 75*9c5db199SXin Li 76*9c5db199SXin Li# clear the SIGCHLD handler so that killing the tails doesn't kill us 77*9c5db199SXin Lisignal.signal(signal.SIGCHLD, signal.SIG_DFL) 78*9c5db199SXin Lios.kill(stdout_pump.pid, signal.SIGTERM) 79*9c5db199SXin Lios.kill(stderr_pump.pid, signal.SIGTERM) 80*9c5db199SXin Li 81*9c5db199SXin Listderr.close() 82*9c5db199SXin Li# exit (with the same code as autotestd) 83*9c5db199SXin Lisys.exit(exit_code) 84