blob: d907d3f96c16ecbd1177938b1a1ebb7735a10e33 [file] [log] [blame]
James Kuszmaul3224b8e2022-01-07 19:00:39 -08001#include "aos/starter/subprocess.h"
2
3#include <grp.h>
4#include <pwd.h>
5#include <sys/prctl.h>
6#include <sys/types.h>
7#include <sys/wait.h>
8
9#include "glog/logging.h"
10
11namespace aos::starter {
12
Austin Schuhbbeb37e2022-08-17 16:19:27 -070013// RAII class to become root and restore back to the original user and group
14// afterwards.
15class Sudo {
16 public:
17 Sudo() {
18 // Save what we were.
19 PCHECK(getresuid(&ruid_, &euid_, &suid_) == 0);
20 PCHECK(getresgid(&rgid_, &egid_, &sgid_) == 0);
21
22 // Become root.
23 PCHECK(setresuid(/* ruid */ 0 /* root */, /* euid */ 0, /* suid */ 0) == 0)
24 << ": Failed to become root";
25 PCHECK(setresgid(/* ruid */ 0 /* root */, /* euid */ 0, /* suid */ 0) == 0)
26 << ": Failed to become root";
27 }
28
29 ~Sudo() {
30 // And recover.
31 PCHECK(setresgid(rgid_, egid_, sgid_) == 0);
32 PCHECK(setresuid(ruid_, euid_, suid_) == 0);
33 }
34
35 uid_t ruid_, euid_, suid_;
36 gid_t rgid_, egid_, sgid_;
37};
38
39MemoryCGroup::MemoryCGroup(std::string_view name)
40 : cgroup_(absl::StrCat("/sys/fs/cgroup/memory/aos_", name)) {
41 Sudo sudo;
42 int ret = mkdir(cgroup_.c_str(), 0755);
43
44 if (ret != 0) {
45 if (errno == EEXIST) {
Austin Schuh4d8a46e2022-10-07 19:20:20 -070046 PCHECK(rmdir(cgroup_.c_str()) == 0)
Austin Schuhbbeb37e2022-08-17 16:19:27 -070047 << ": Failed to remove previous cgroup " << cgroup_;
48 ret = mkdir(cgroup_.c_str(), 0755);
49 }
50 }
51
52 if (ret != 0) {
53 PLOG(FATAL) << ": Failed to create cgroup aos_" << cgroup_
54 << ", do you have permission?";
55 }
56}
57
58void MemoryCGroup::AddTid(pid_t pid) {
59 if (pid == 0) {
60 pid = getpid();
61 }
62 Sudo sudo;
63 util::WriteStringToFileOrDie(absl::StrCat(cgroup_, "/tasks").c_str(),
64 std::to_string(pid));
65}
66
67void MemoryCGroup::SetLimit(std::string_view limit_name, uint64_t limit_value) {
68 Sudo sudo;
69 util::WriteStringToFileOrDie(absl::StrCat(cgroup_, "/", limit_name).c_str(),
70 std::to_string(limit_value));
71}
72
73MemoryCGroup::~MemoryCGroup() {
74 Sudo sudo;
75 PCHECK(rmdir(absl::StrCat(cgroup_).c_str()) == 0);
76}
77
James Kuszmaul3224b8e2022-01-07 19:00:39 -080078SignalListener::SignalListener(aos::ShmEventLoop *loop,
79 std::function<void(signalfd_siginfo)> callback)
80 : SignalListener(loop, callback,
81 {SIGHUP, SIGINT, SIGQUIT, SIGABRT, SIGFPE, SIGSEGV,
82 SIGPIPE, SIGTERM, SIGBUS, SIGXCPU, SIGCHLD}) {}
83
84SignalListener::SignalListener(aos::ShmEventLoop *loop,
85 std::function<void(signalfd_siginfo)> callback,
86 std::initializer_list<unsigned int> signals)
87 : loop_(loop), callback_(std::move(callback)), signalfd_(signals) {
88 loop->epoll()->OnReadable(signalfd_.fd(), [this] {
89 signalfd_siginfo info = signalfd_.Read();
90
91 if (info.ssi_signo == 0) {
92 LOG(WARNING) << "Could not read " << sizeof(signalfd_siginfo) << " bytes";
93 return;
94 }
95
96 callback_(info);
97 });
98}
99
100SignalListener::~SignalListener() { loop_->epoll()->DeleteFd(signalfd_.fd()); }
101
James Kuszmauld42edb42022-01-07 18:00:16 -0800102Application::Application(std::string_view name,
103 std::string_view executable_name,
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800104 aos::EventLoop *event_loop,
105 std::function<void()> on_change)
James Kuszmauld42edb42022-01-07 18:00:16 -0800106 : name_(name),
107 path_(executable_name),
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800108 event_loop_(event_loop),
109 start_timer_(event_loop_->AddTimer([this] {
110 status_ = aos::starter::State::RUNNING;
111 LOG(INFO) << "Started '" << name_ << "' pid: " << pid_;
112 })),
113 restart_timer_(event_loop_->AddTimer([this] { DoStart(); })),
114 stop_timer_(event_loop_->AddTimer([this] {
115 if (kill(pid_, SIGKILL) == 0) {
116 LOG(WARNING) << "Failed to stop, sending SIGKILL to '" << name_
117 << "' pid: " << pid_;
118 }
119 })),
James Kuszmauld42edb42022-01-07 18:00:16 -0800120 pipe_timer_(event_loop_->AddTimer([this]() { FetchOutputs(); })),
121 child_status_handler_(
122 event_loop_->AddTimer([this]() { MaybeHandleSignal(); })),
123 on_change_(on_change) {
124 event_loop_->OnRun([this]() {
125 // Every second poll to check if the child is dead. This is used as a
126 // default for the case where the user is not directly catching SIGCHLD and
127 // calling MaybeHandleSignal for us.
Philipp Schradera6712522023-07-05 20:25:11 -0700128 child_status_handler_->Schedule(event_loop_->monotonic_now(),
129 std::chrono::seconds(1));
James Kuszmauld42edb42022-01-07 18:00:16 -0800130 });
131}
132
133Application::Application(const aos::Application *application,
134 aos::EventLoop *event_loop,
135 std::function<void()> on_change)
136 : Application(application->name()->string_view(),
137 application->has_executable_name()
138 ? application->executable_name()->string_view()
139 : application->name()->string_view(),
140 event_loop, on_change) {
141 user_name_ = application->has_user() ? application->user()->str() : "";
142 user_ = application->has_user() ? FindUid(user_name_.c_str()) : std::nullopt;
143 group_ = application->has_user() ? FindPrimaryGidForUser(user_name_.c_str())
144 : std::nullopt;
145 autostart_ = application->autostart();
146 autorestart_ = application->autorestart();
147 if (application->has_args()) {
148 set_args(*application->args());
149 }
Austin Schuhbbeb37e2022-08-17 16:19:27 -0700150
151 if (application->has_memory_limit() && application->memory_limit() > 0) {
152 SetMemoryLimit(application->memory_limit());
153 }
James Kuszmauld42edb42022-01-07 18:00:16 -0800154}
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800155
156void Application::DoStart() {
157 if (status_ != aos::starter::State::WAITING) {
158 return;
159 }
160
161 start_timer_->Disable();
162 restart_timer_->Disable();
163
James Kuszmauld42edb42022-01-07 18:00:16 -0800164 status_pipes_ = util::ScopedPipe::MakePipe();
165
166 if (capture_stdout_) {
167 stdout_pipes_ = util::ScopedPipe::MakePipe();
168 stdout_.clear();
169 }
170 if (capture_stderr_) {
171 stderr_pipes_ = util::ScopedPipe::MakePipe();
172 stderr_.clear();
173 }
174
Philipp Schradera6712522023-07-05 20:25:11 -0700175 pipe_timer_->Schedule(event_loop_->monotonic_now(),
176 std::chrono::milliseconds(100));
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800177
178 const pid_t pid = fork();
179
180 if (pid != 0) {
181 if (pid == -1) {
182 PLOG(WARNING) << "Failed to fork '" << name_ << "'";
183 stop_reason_ = aos::starter::LastStopReason::FORK_ERR;
184 status_ = aos::starter::State::STOPPED;
185 } else {
186 pid_ = pid;
187 id_ = next_id_++;
188 start_time_ = event_loop_->monotonic_now();
189 status_ = aos::starter::State::STARTING;
190 LOG(INFO) << "Starting '" << name_ << "' pid " << pid_;
191
Philipp Schradera6712522023-07-05 20:25:11 -0700192 // Set up timer which moves application to RUNNING state if it is still
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800193 // alive in 1 second.
Philipp Schradera6712522023-07-05 20:25:11 -0700194 start_timer_->Schedule(event_loop_->monotonic_now() +
195 std::chrono::seconds(1));
James Kuszmauld42edb42022-01-07 18:00:16 -0800196 // Since we are the parent process, clear our write-side of all the pipes.
197 status_pipes_.write.reset();
198 stdout_pipes_.write.reset();
199 stderr_pipes_.write.reset();
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800200 }
201 on_change_();
202 return;
203 }
204
Austin Schuhbbeb37e2022-08-17 16:19:27 -0700205 if (memory_cgroup_) {
206 memory_cgroup_->AddTid();
207 }
208
James Kuszmauld42edb42022-01-07 18:00:16 -0800209 // Since we are the child process, clear our read-side of all the pipes.
210 status_pipes_.read.reset();
211 stdout_pipes_.read.reset();
212 stderr_pipes_.read.reset();
213
214 // The status pipe will not be needed if the execve succeeds.
215 status_pipes_.write->SetCloexec();
216
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800217 // Clear out signal mask of parent so forked process receives all signals
218 // normally.
219 sigset_t empty_mask;
220 sigemptyset(&empty_mask);
221 sigprocmask(SIG_SETMASK, &empty_mask, nullptr);
222
223 // Cleanup children if starter dies in a way that is not handled gracefully.
224 if (prctl(PR_SET_PDEATHSIG, SIGKILL) == -1) {
James Kuszmauld42edb42022-01-07 18:00:16 -0800225 status_pipes_.write->Write(
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800226 static_cast<uint32_t>(aos::starter::LastStopReason::SET_PRCTL_ERR));
227 PLOG(FATAL) << "Could not set PR_SET_PDEATHSIG to SIGKILL";
228 }
229
230 if (group_) {
231 CHECK(!user_name_.empty());
232 // The manpage for setgroups says we just need CAP_SETGID, but empirically
233 // we also need the effective UID to be 0 to make it work. user_ must also
234 // be set so we change this effective UID back later.
235 CHECK(user_);
236 if (seteuid(0) == -1) {
James Kuszmauld42edb42022-01-07 18:00:16 -0800237 status_pipes_.write->Write(
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800238 static_cast<uint32_t>(aos::starter::LastStopReason::SET_GRP_ERR));
239 PLOG(FATAL) << "Could not seteuid(0) for " << name_
240 << " in preparation for setting groups";
241 }
242 if (initgroups(user_name_.c_str(), *group_) == -1) {
James Kuszmauld42edb42022-01-07 18:00:16 -0800243 status_pipes_.write->Write(
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800244 static_cast<uint32_t>(aos::starter::LastStopReason::SET_GRP_ERR));
245 PLOG(FATAL) << "Could not initialize normal groups for " << name_
246 << " as " << user_name_ << " with " << *group_;
247 }
248 if (setgid(*group_) == -1) {
James Kuszmauld42edb42022-01-07 18:00:16 -0800249 status_pipes_.write->Write(
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800250 static_cast<uint32_t>(aos::starter::LastStopReason::SET_GRP_ERR));
251 PLOG(FATAL) << "Could not set group for " << name_ << " to " << *group_;
252 }
253 }
254
255 if (user_) {
256 if (setuid(*user_) == -1) {
James Kuszmauld42edb42022-01-07 18:00:16 -0800257 status_pipes_.write->Write(
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800258 static_cast<uint32_t>(aos::starter::LastStopReason::SET_USR_ERR));
259 PLOG(FATAL) << "Could not set user for " << name_ << " to " << *user_;
260 }
261 }
262
James Kuszmauld42edb42022-01-07 18:00:16 -0800263 if (capture_stdout_) {
264 PCHECK(STDOUT_FILENO == dup2(stdout_pipes_.write->fd(), STDOUT_FILENO));
265 stdout_pipes_.write.reset();
266 }
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800267
James Kuszmauld42edb42022-01-07 18:00:16 -0800268 if (capture_stderr_) {
269 PCHECK(STDERR_FILENO == dup2(stderr_pipes_.write->fd(), STDERR_FILENO));
270 stderr_pipes_.write.reset();
271 }
272
Sanjay Narayanan01a228f2022-04-26 14:19:30 -0700273 if (run_as_sudo_) {
Sarah Newman6d1e53b2022-08-09 14:38:08 -0700274 // For sudo we must supply the actual path
275 args_.insert(args_.begin(), path_);
Sanjay Narayanan01a228f2022-04-26 14:19:30 -0700276 args_.insert(args_.begin(), kSudo);
Sarah Newman6d1e53b2022-08-09 14:38:08 -0700277 } else {
278 // argv[0] should be the program name
279 args_.insert(args_.begin(), name_);
Sanjay Narayanan01a228f2022-04-26 14:19:30 -0700280 }
James Kuszmauld42edb42022-01-07 18:00:16 -0800281
282 std::vector<char *> cargs = CArgs();
Philipp Schrader790cb542023-07-05 21:06:52 -0700283 const char *path = run_as_sudo_ ? kSudo : path_.c_str();
Sanjay Narayanan01a228f2022-04-26 14:19:30 -0700284 execvp(path, cargs.data());
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800285
286 // If we got here, something went wrong
James Kuszmauld42edb42022-01-07 18:00:16 -0800287 status_pipes_.write->Write(
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800288 static_cast<uint32_t>(aos::starter::LastStopReason::EXECV_ERR));
James Kuszmaul6f10b382022-03-11 22:31:38 -0800289 PLOG(WARNING) << "Could not execute " << name_ << " (" << path_ << ')';
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800290
291 _exit(EXIT_FAILURE);
292}
293
James Kuszmauld42edb42022-01-07 18:00:16 -0800294void Application::FetchOutputs() {
295 if (capture_stdout_) {
296 stdout_pipes_.read->Read(&stdout_);
297 }
298 if (capture_stderr_) {
299 stderr_pipes_.read->Read(&stderr_);
300 }
301}
302
303const std::string &Application::GetStdout() {
304 CHECK(capture_stdout_);
305 FetchOutputs();
306 return stdout_;
307}
308
309const std::string &Application::GetStderr() {
310 CHECK(capture_stderr_);
311 FetchOutputs();
312 return stderr_;
313}
314
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800315void Application::DoStop(bool restart) {
316 // If stop or restart received, the old state of these is no longer applicable
317 // so cancel both.
318 restart_timer_->Disable();
319 start_timer_->Disable();
320
James Kuszmauld42edb42022-01-07 18:00:16 -0800321 FetchOutputs();
322
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800323 switch (status_) {
324 case aos::starter::State::STARTING:
325 case aos::starter::State::RUNNING: {
326 LOG(INFO) << "Stopping '" << name_ << "' pid: " << pid_ << " with signal "
327 << SIGINT;
328 status_ = aos::starter::State::STOPPING;
329
330 kill(pid_, SIGINT);
331
332 // Watchdog timer to SIGKILL application if it is still running 1 second
333 // after SIGINT
Philipp Schradera6712522023-07-05 20:25:11 -0700334 stop_timer_->Schedule(event_loop_->monotonic_now() +
335 std::chrono::seconds(1));
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800336 queue_restart_ = restart;
337 on_change_();
338 break;
339 }
340 case aos::starter::State::WAITING: {
341 // If waiting to restart, and receives restart, skip the waiting period
342 // and restart immediately. If stop received, all we have to do is move
343 // to the STOPPED state.
344 if (restart) {
345 DoStart();
346 } else {
347 status_ = aos::starter::State::STOPPED;
348 on_change_();
349 }
350 break;
351 }
352 case aos::starter::State::STOPPING: {
353 // If the application is already stopping, then we just need to update the
354 // restart flag to the most recent status.
355 queue_restart_ = restart;
356 break;
357 }
358 case aos::starter::State::STOPPED: {
359 // Restart immediately if the application is already stopped
360 if (restart) {
361 status_ = aos::starter::State::WAITING;
362 DoStart();
363 }
364 break;
365 }
366 }
367}
368
369void Application::QueueStart() {
370 status_ = aos::starter::State::WAITING;
371
372 LOG(INFO) << "Restarting " << name_ << " in 3 seconds";
Philipp Schradera6712522023-07-05 20:25:11 -0700373 restart_timer_->Schedule(event_loop_->monotonic_now() +
374 std::chrono::seconds(3));
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800375 start_timer_->Disable();
376 stop_timer_->Disable();
377 on_change_();
378}
379
James Kuszmauld42edb42022-01-07 18:00:16 -0800380std::vector<char *> Application::CArgs() {
381 std::vector<char *> cargs;
382 std::transform(args_.begin(), args_.end(), std::back_inserter(cargs),
383 [](std::string &str) { return str.data(); });
384 cargs.push_back(nullptr);
385 return cargs;
386}
387
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800388void Application::set_args(
389 const flatbuffers::Vector<flatbuffers::Offset<flatbuffers::String>> &v) {
390 args_.clear();
391 std::transform(v.begin(), v.end(), std::back_inserter(args_),
James Kuszmauld42edb42022-01-07 18:00:16 -0800392 [](const flatbuffers::String *str) { return str->str(); });
393}
394
395void Application::set_args(std::vector<std::string> args) {
396 args_ = std::move(args);
397}
398
399void Application::set_capture_stdout(bool capture) {
400 capture_stdout_ = capture;
401}
402
403void Application::set_capture_stderr(bool capture) {
404 capture_stderr_ = capture;
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800405}
406
407std::optional<uid_t> Application::FindUid(const char *name) {
408 // TODO(austin): Use the reentrant version. This should be safe.
409 struct passwd *user_data = getpwnam(name);
410 if (user_data != nullptr) {
411 return user_data->pw_uid;
412 } else {
413 LOG(FATAL) << "Could not find user " << name;
414 return std::nullopt;
415 }
416}
417
418std::optional<gid_t> Application::FindPrimaryGidForUser(const char *name) {
419 // TODO(austin): Use the reentrant version. This should be safe.
420 struct passwd *user_data = getpwnam(name);
421 if (user_data != nullptr) {
422 return user_data->pw_gid;
423 } else {
424 LOG(FATAL) << "Could not find user " << name;
425 return std::nullopt;
426 }
427}
428
429flatbuffers::Offset<aos::starter::ApplicationStatus>
James Kuszmaul6295a642022-03-22 15:23:59 -0700430Application::PopulateStatus(flatbuffers::FlatBufferBuilder *builder,
431 util::Top *top) {
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800432 CHECK_NOTNULL(builder);
433 auto name_fbs = builder->CreateString(name_);
434
James Kuszmaul6295a642022-03-22 15:23:59 -0700435 const bool valid_pid = pid_ > 0 && status_ != aos::starter::State::STOPPED;
436 const flatbuffers::Offset<util::ProcessInfo> process_info =
437 valid_pid ? top->InfoForProcess(builder, pid_)
438 : flatbuffers::Offset<util::ProcessInfo>();
439
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800440 aos::starter::ApplicationStatus::Builder status_builder(*builder);
441 status_builder.add_name(name_fbs);
442 status_builder.add_state(status_);
James Kuszmauld42edb42022-01-07 18:00:16 -0800443 if (exit_code_.has_value()) {
444 status_builder.add_last_exit_code(exit_code_.value());
445 }
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800446 status_builder.add_last_stop_reason(stop_reason_);
447 if (pid_ != -1) {
448 status_builder.add_pid(pid_);
449 status_builder.add_id(id_);
450 }
James Kuszmaul6295a642022-03-22 15:23:59 -0700451 // Note that even if process_info is null, calling add_process_info is fine.
452 status_builder.add_process_info(process_info);
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800453 status_builder.add_last_start_time(start_time_.time_since_epoch().count());
454 return status_builder.Finish();
455}
456
457void Application::Terminate() {
458 stop_reason_ = aos::starter::LastStopReason::TERMINATE;
459 DoStop(false);
460 terminating_ = true;
461}
462
463void Application::HandleCommand(aos::starter::Command cmd) {
464 switch (cmd) {
465 case aos::starter::Command::START: {
466 switch (status_) {
467 case aos::starter::State::WAITING: {
468 restart_timer_->Disable();
469 DoStart();
470 break;
471 }
472 case aos::starter::State::STARTING: {
473 break;
474 }
475 case aos::starter::State::RUNNING: {
476 break;
477 }
478 case aos::starter::State::STOPPING: {
479 queue_restart_ = true;
480 break;
481 }
482 case aos::starter::State::STOPPED: {
483 status_ = aos::starter::State::WAITING;
484 DoStart();
485 break;
486 }
487 }
488 break;
489 }
490 case aos::starter::Command::STOP: {
491 stop_reason_ = aos::starter::LastStopReason::STOP_REQUESTED;
492 DoStop(false);
493 break;
494 }
495 case aos::starter::Command::RESTART: {
496 stop_reason_ = aos::starter::LastStopReason::RESTART_REQUESTED;
497 DoStop(true);
498 break;
499 }
500 }
501}
502
503bool Application::MaybeHandleSignal() {
504 int status;
505
Sarah Newman21c59202022-06-16 12:36:33 -0700506 if (status_ == aos::starter::State::WAITING ||
507 status_ == aos::starter::State::STOPPED) {
508 // We can't possibly have received a signal meant for this process.
509 return false;
510 }
511
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800512 // Check if the status of this process has changed
Sarah Newman21c59202022-06-16 12:36:33 -0700513 // The PID won't be -1 if this application has ever been run successfully
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800514 if (pid_ == -1 || waitpid(pid_, &status, WNOHANG) != pid_) {
515 return false;
516 }
517
518 // Check that the event was the process exiting
519 if (!WIFEXITED(status) && !WIFSIGNALED(status)) {
520 return false;
521 }
522
James Kuszmauld42edb42022-01-07 18:00:16 -0800523 start_timer_->Disable();
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800524 exit_time_ = event_loop_->monotonic_now();
525 exit_code_ = WIFEXITED(status) ? WEXITSTATUS(status) : WTERMSIG(status);
526
James Kuszmauld42edb42022-01-07 18:00:16 -0800527 if (auto read_result = status_pipes_.read->Read()) {
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800528 stop_reason_ = static_cast<aos::starter::LastStopReason>(*read_result);
529 }
530
531 switch (status_) {
532 case aos::starter::State::STARTING: {
James Kuszmauld42edb42022-01-07 18:00:16 -0800533 if (exit_code_.value() == 0) {
534 LOG(INFO) << "Application '" << name_ << "' pid " << pid_
535 << " exited with status " << exit_code_.value();
536 } else {
537 LOG(WARNING) << "Failed to start '" << name_ << "' on pid " << pid_
538 << " : Exited with status " << exit_code_.value();
539 }
James Kuszmaul6f10b382022-03-11 22:31:38 -0800540 if (autorestart()) {
541 QueueStart();
542 } else {
543 status_ = aos::starter::State::STOPPED;
544 on_change_();
545 }
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800546 break;
547 }
548 case aos::starter::State::RUNNING: {
James Kuszmauld42edb42022-01-07 18:00:16 -0800549 if (exit_code_.value() == 0) {
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800550 LOG(INFO) << "Application '" << name_ << "' pid " << pid_
James Kuszmauld42edb42022-01-07 18:00:16 -0800551 << " exited with status " << exit_code_.value();
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800552 } else {
553 LOG(WARNING) << "Application '" << name_ << "' pid " << pid_
James Kuszmauld42edb42022-01-07 18:00:16 -0800554 << " exited unexpectedly with status "
555 << exit_code_.value();
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800556 }
James Kuszmaul6f10b382022-03-11 22:31:38 -0800557 if (autorestart()) {
558 QueueStart();
559 } else {
560 status_ = aos::starter::State::STOPPED;
561 on_change_();
562 }
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800563 break;
564 }
565 case aos::starter::State::STOPPING: {
566 LOG(INFO) << "Successfully stopped '" << name_ << "' pid: " << pid_
James Kuszmauld42edb42022-01-07 18:00:16 -0800567 << " with status " << exit_code_.value();
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800568 status_ = aos::starter::State::STOPPED;
569
570 // Disable force stop timer since the process already died
571 stop_timer_->Disable();
572
573 on_change_();
574 if (terminating_) {
575 return true;
576 }
577
578 if (queue_restart_) {
579 queue_restart_ = false;
580 status_ = aos::starter::State::WAITING;
581 DoStart();
582 }
583 break;
584 }
585 case aos::starter::State::WAITING:
586 case aos::starter::State::STOPPED: {
Sarah Newman21c59202022-06-16 12:36:33 -0700587 __builtin_unreachable();
James Kuszmaul3224b8e2022-01-07 19:00:39 -0800588 break;
589 }
590 }
591
592 return false;
593}
594
595} // namespace aos::starter