• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 <brillo/daemons/daemon.h>
6 
7 #include <signal.h>
8 #include <sysexits.h>
9 #include <time.h>
10 
11 #include <base/bind.h>
12 #include <base/files/file_util.h>
13 #include <base/logging.h>
14 #include <base/run_loop.h>
15 
16 namespace brillo {
17 
Daemon()18 Daemon::Daemon() : exit_code_{EX_OK}, exiting_(false) {
19   message_loop_.SetAsCurrent();
20 }
21 
~Daemon()22 Daemon::~Daemon() {
23 }
24 
Run()25 int Daemon::Run() {
26   int exit_code = OnInit();
27   if (exit_code != EX_OK)
28     return exit_code;
29 
30   message_loop_.PostTask(
31       base::BindOnce(&Daemon::OnEventLoopStartedTask, base::Unretained(this)));
32   message_loop_.Run();
33 
34   OnShutdown(&exit_code_);
35 
36   // base::RunLoop::QuitClosure() causes the message loop to quit
37   // immediately, even if pending tasks are still queued.
38   // Run a secondary loop to make sure all those are processed.
39   // This becomes important when working with D-Bus since dbus::Bus does
40   // a bunch of clean-up tasks asynchronously when shutting down.
41   while (message_loop_.RunOnce(false /* may_block */)) {}
42 
43   return exit_code_;
44 }
45 
Quit()46 void Daemon::Quit() { QuitWithExitCode(EX_OK); }
47 
QuitWithExitCode(int exit_code)48 void Daemon::QuitWithExitCode(int exit_code) {
49   exit_code_ = exit_code;
50   message_loop_.PostTask(FROM_HERE, QuitClosure());
51 }
52 
RegisterHandler(int signal,const AsynchronousSignalHandlerInterface::SignalHandler & callback)53 void Daemon::RegisterHandler(
54     int signal,
55     const AsynchronousSignalHandlerInterface::SignalHandler& callback) {
56   async_signal_handler_.RegisterHandler(signal, callback);
57 }
58 
UnregisterHandler(int signal)59 void Daemon::UnregisterHandler(int signal) {
60   async_signal_handler_.UnregisterHandler(signal);
61 }
62 
OnInit()63 int Daemon::OnInit() {
64   async_signal_handler_.Init();
65   for (int signal : {SIGTERM, SIGINT}) {
66     async_signal_handler_.RegisterHandler(
67         signal, base::Bind(&Daemon::Shutdown, base::Unretained(this)));
68   }
69   async_signal_handler_.RegisterHandler(
70       SIGHUP, base::Bind(&Daemon::Restart, base::Unretained(this)));
71   return EX_OK;
72 }
73 
OnEventLoopStarted()74 int Daemon::OnEventLoopStarted() {
75   // Do nothing.
76   return EX_OK;
77 }
78 
OnShutdown(int *)79 void Daemon::OnShutdown(int* /* exit_code */) {
80   // Do nothing.
81 }
82 
OnRestart()83 bool Daemon::OnRestart() {
84   // Not handled.
85   return false;  // Returning false will shut down the daemon instead.
86 }
87 
Shutdown(const signalfd_siginfo &)88 bool Daemon::Shutdown(const signalfd_siginfo& /* info */) {
89   // Only respond to the first call.
90   if (!exiting_) {
91     exiting_ = true;
92     Quit();
93   }
94   // Always return false, to avoid unregistering the signal handler. We might
95   // receive multiple successive signals, and we don't want to take the default
96   // response (termination) while we're still tearing down.
97   return false;
98 }
99 
Restart(const signalfd_siginfo &)100 bool Daemon::Restart(const signalfd_siginfo& /* info */) {
101   if (!exiting_ && !OnRestart()) {
102     // Only Quit() once.
103     exiting_ = true;
104     Quit();
105   }
106   // Always return false, to avoid unregistering the signal handler. We might
107   // receive multiple successive signals, and we don't want to take the default
108   // response (termination) while we're still tearing down.
109   return false;
110 }
111 
OnEventLoopStartedTask()112 void Daemon::OnEventLoopStartedTask() {
113   int exit_code = OnEventLoopStarted();
114   if (exit_code != EX_OK)
115     QuitWithExitCode(exit_code);
116 }
117 
UpdateLogSymlinks(const base::FilePath & latest_log_symlink,const base::FilePath & previous_log_symlink,const base::FilePath & log_file)118 void UpdateLogSymlinks(const base::FilePath& latest_log_symlink,
119                        const base::FilePath& previous_log_symlink,
120                        const base::FilePath& log_file) {
121   base::DeleteFile(previous_log_symlink, false);
122   base::Move(latest_log_symlink, previous_log_symlink);
123   if (!base::CreateSymbolicLink(log_file.BaseName(), latest_log_symlink)) {
124     PLOG(ERROR) << "Unable to create symbolic link from "
125                 << latest_log_symlink.value() << " to " << log_file.value();
126   }
127 }
128 
GetTimeAsLogString(const base::Time & time)129 std::string GetTimeAsLogString(const base::Time& time) {
130   time_t utime = time.ToTimeT();
131   struct tm tm;
132   CHECK_EQ(localtime_r(&utime, &tm), &tm);
133   char str[16];
134   CHECK_EQ(strftime(str, sizeof(str), "%Y%m%d-%H%M%S", &tm), 15UL);
135   return std::string(str);
136 }
137 
138 }  // namespace brillo
139