| Peter Qiu | 5dd242d | 2014-10-14 12:23:21 -0700 | [diff] [blame^] | 1 | // Copyright 2014 The Chromium OS Authors. All rights reserved. | 
 | 2 | // Use of this source code is governed by a BSD-style license that can be | 
 | 3 | // found in the LICENSE file. | 
 | 4 |  | 
 | 5 | #include <vector> | 
 | 6 |  | 
 | 7 | #include <base/bind.h> | 
 | 8 | #include <base/command_line.h> | 
 | 9 | #include <base/logging.h> | 
 | 10 | #include <chromeos/minijail/minijail.h> | 
 | 11 | #include <chromeos/syslog_logging.h> | 
 | 12 |  | 
 | 13 | #include "apmanager/daemon.h" | 
 | 14 |  | 
 | 15 | using std::vector; | 
 | 16 |  | 
 | 17 | namespace { | 
 | 18 |  | 
 | 19 | namespace switches { | 
 | 20 |  | 
 | 21 | // Don't daemon()ize; run in foreground. | 
 | 22 | const char kForeground[] = "foreground"; | 
 | 23 | // Flag that causes apmanager to show the help message and exit. | 
 | 24 | const char kHelp[] = "help"; | 
 | 25 |  | 
 | 26 | // The help message shown if help flag is passed to the program. | 
 | 27 | const char kHelpMessage[] = "\n" | 
 | 28 |     "Available Switches: \n" | 
 | 29 |     "  --foreground\n" | 
 | 30 |     "    Don\'t daemon()ize; run in foreground.\n"; | 
 | 31 | }  // namespace switches | 
 | 32 |  | 
 | 33 | }  // namespace | 
 | 34 |  | 
 | 35 | namespace { | 
 | 36 |  | 
 | 37 | const char kLoggerCommand[] = "/usr/bin/logger"; | 
 | 38 | const char kLoggerUser[] = "syslog"; | 
 | 39 |  | 
 | 40 | }  // namespace | 
 | 41 |  | 
 | 42 | // Always logs to the syslog and logs to stderr if | 
 | 43 | // we are running in the foreground. | 
 | 44 | void SetupLogging(chromeos::Minijail* minijail, | 
 | 45 |                   bool foreground, | 
 | 46 |                   const char* daemon_name) { | 
 | 47 |   int log_flags = 0; | 
 | 48 |   log_flags |= chromeos::kLogToSyslog; | 
 | 49 |   log_flags |= chromeos::kLogHeader; | 
 | 50 |   if (foreground) { | 
 | 51 |     log_flags |= chromeos::kLogToStderr; | 
 | 52 |   } | 
 | 53 |   chromeos::InitLog(log_flags); | 
 | 54 |  | 
 | 55 |   if (!foreground) { | 
 | 56 |     vector<char*> logger_command_line; | 
 | 57 |     int logger_stdin_fd; | 
 | 58 |     logger_command_line.push_back(const_cast<char*>(kLoggerCommand)); | 
 | 59 |     logger_command_line.push_back(const_cast<char*>("--priority")); | 
 | 60 |     logger_command_line.push_back(const_cast<char*>("daemon.err")); | 
 | 61 |     logger_command_line.push_back(const_cast<char*>("--tag")); | 
 | 62 |     logger_command_line.push_back(const_cast<char*>(daemon_name)); | 
 | 63 |     logger_command_line.push_back(nullptr); | 
 | 64 |  | 
 | 65 |     struct minijail* jail = minijail->New(); | 
 | 66 |     minijail->DropRoot(jail, kLoggerUser, kLoggerUser); | 
 | 67 |  | 
 | 68 |     if (!minijail->RunPipeAndDestroy(jail, logger_command_line, | 
 | 69 |                                      nullptr, &logger_stdin_fd)) { | 
 | 70 |       LOG(ERROR) << "Unable to spawn logger. " | 
 | 71 |                  << "Writes to stderr will be discarded."; | 
 | 72 |       return; | 
 | 73 |     } | 
 | 74 |  | 
 | 75 |     // Note that we don't set O_CLOEXEC here. This means that stderr | 
 | 76 |     // from any child processes will, by default, be logged to syslog. | 
 | 77 |     if (dup2(logger_stdin_fd, fileno(stderr)) != fileno(stderr)) { | 
 | 78 |       LOG(ERROR) << "Failed to redirect stderr to syslog: " | 
 | 79 |                  << strerror(errno); | 
 | 80 |     } | 
 | 81 |     close(logger_stdin_fd); | 
 | 82 |   } | 
 | 83 | } | 
 | 84 |  | 
 | 85 | void DropPrivileges(chromeos::Minijail* minijail) { | 
 | 86 |   struct minijail* jail = minijail->New(); | 
 | 87 |   minijail->DropRoot(jail, apmanager::Daemon::kAPManagerUserName, | 
 | 88 |                      apmanager::Daemon::kAPManagerGroupName); | 
 | 89 |   minijail_enter(jail); | 
 | 90 |   minijail->Destroy(jail); | 
 | 91 | } | 
 | 92 |  | 
 | 93 | void OnStartup(const char* daemon_name, CommandLine* cl) { | 
 | 94 |   chromeos::Minijail* minijail = chromeos::Minijail::GetInstance(); | 
 | 95 |   SetupLogging(minijail, cl->HasSwitch(switches::kForeground), daemon_name); | 
 | 96 |  | 
 | 97 |   LOG(INFO) << __func__ << ": Dropping privileges"; | 
 | 98 |  | 
 | 99 |   // Now that the daemon has all the resources it needs to run, we can drop | 
 | 100 |   // privileges further. | 
 | 101 |   DropPrivileges(minijail); | 
 | 102 | } | 
 | 103 |  | 
 | 104 | int main(int argc, char* argv[]) { | 
 | 105 |   CommandLine::Init(argc, argv); | 
 | 106 |   CommandLine* cl = CommandLine::ForCurrentProcess(); | 
 | 107 |  | 
 | 108 |   if (cl->HasSwitch(switches::kHelp)) { | 
 | 109 |     LOG(INFO) << switches::kHelpMessage; | 
 | 110 |     return 0; | 
 | 111 |   } | 
 | 112 |  | 
 | 113 |   const int nochdir = 0, noclose = 0; | 
 | 114 |   if (!cl->HasSwitch(switches::kForeground)) | 
 | 115 |     PLOG_IF(FATAL, daemon(nochdir, noclose) == -1) << "Failed to daemonize"; | 
 | 116 |  | 
 | 117 |   apmanager::Daemon daemon(base::Bind(&OnStartup, argv[0], cl)); | 
 | 118 |  | 
 | 119 |   daemon.Run(); | 
 | 120 |  | 
 | 121 |   return 0; | 
 | 122 | } |