blob: 41473a8a01daf33c3a8a0f0bab77e1277dbea24c [file] [log] [blame]
Peter Qiu5dd242d2014-10-14 12:23:21 -07001// 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
15using std::vector;
16
17namespace {
18
19namespace switches {
20
21// Don't daemon()ize; run in foreground.
22const char kForeground[] = "foreground";
23// Flag that causes apmanager to show the help message and exit.
24const char kHelp[] = "help";
25
26// The help message shown if help flag is passed to the program.
27const 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
35namespace {
36
37const char kLoggerCommand[] = "/usr/bin/logger";
38const 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.
44void 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
85void 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
93void 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
104int 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}