12 #include <sys/types.h>
17 #include "proc-service.h"
18 #include "dinit-log.h"
19 #include "dinit-util.h"
20 #include "dinit-utmp.h"
22 using string = std::string;
23 using string_iterator = std::string::iterator;
25 // Convert a signal name to the corresponding signal number
26 static int signal_name_to_number(std::string &signame)
28 if (signame == "HUP") return SIGHUP;
29 if (signame == "INT") return SIGINT;
30 if (signame == "QUIT") return SIGQUIT;
31 if (signame == "USR1") return SIGUSR1;
32 if (signame == "USR2") return SIGUSR2;
33 if (signame == "KILL") return SIGKILL;
37 static const char * uid_err_msg = "Specified user id contains invalid numeric characters "
38 "or is outside allowed range.";
40 // Parse a userid parameter which may be a numeric user ID or a username. If a name, the
41 // userid is looked up via the system user database (getpwnam() function). In this case,
42 // the associated group is stored in the location specified by the group_p parameter iff
43 // it is not null and iff it contains the value -1.
44 static uid_t parse_uid_param(const std::string ¶m, const std::string &service_name, gid_t *group_p)
46 // Could be a name or a numeric id. But we should assume numeric first, just in case
47 // a user manages to give themselves a username that parses as a number.
50 // POSIX does not specify whether uid_t is an signed or unsigned, but regardless
51 // is is probably safe to assume that valid values are positive. We'll also assert
52 // that the value range fits within "unsigned long long" since it seems unlikely
53 // that would ever not be the case.
54 static_assert((uintmax_t)std::numeric_limits<uid_t>::max()
55 <= (uintmax_t)std::numeric_limits<unsigned long long>::max(), "uid_t is too large");
56 unsigned long long v = std::stoull(param, &ind, 0);
57 if (v > static_cast<unsigned long long>(std::numeric_limits<uid_t>::max())
58 || ind != param.length()) {
59 throw service_description_exc(service_name, uid_err_msg);
63 catch (std::out_of_range &exc) {
64 throw service_description_exc(service_name, uid_err_msg);
66 catch (std::invalid_argument &exc) {
67 // Ok, so it doesn't look like a number: proceed...
71 struct passwd * pwent = getpwnam(param.c_str());
72 if (pwent == nullptr) {
73 // Maybe an error, maybe just no entry.
75 throw service_description_exc(service_name, "Specified user \"" + param
76 + "\" does not exist in system database.");
79 throw service_description_exc(service_name, std::string("Error accessing user database: ")
84 if (group_p && *group_p != (gid_t)-1) {
85 *group_p = pwent->pw_gid;
91 static const char * num_err_msg = "Specified value contains invalid numeric characters or is outside "
94 // Parse an unsigned numeric parameter value
95 static unsigned long long parse_unum_param(const std::string ¶m, const std::string &service_name,
96 unsigned long long max = std::numeric_limits<unsigned long long>::max())
100 unsigned long long v = std::stoull(param, &ind, 0);
101 if (v > max || ind != param.length()) {
102 throw service_description_exc(service_name, num_err_msg);
106 catch (std::out_of_range &exc) {
107 throw service_description_exc(service_name, num_err_msg);
109 catch (std::invalid_argument &exc) {
110 throw service_description_exc(service_name, num_err_msg);
114 static const char * gid_err_msg = "Specified group id contains invalid numeric characters or is "
115 "outside allowed range.";
117 static gid_t parse_gid_param(const std::string ¶m, const std::string &service_name)
119 // Could be a name or a numeric id. But we should assume numeric first, just in case
120 // a user manages to give themselves a username that parses as a number.
123 // POSIX does not specify whether uid_t is an signed or unsigned, but regardless
124 // is is probably safe to assume that valid values are positive. We'll also assume
125 // that the value range fits with "unsigned long long" since it seems unlikely
126 // that would ever not be the case.
127 static_assert((uintmax_t)std::numeric_limits<gid_t>::max()
128 <= (uintmax_t)std::numeric_limits<unsigned long long>::max(), "gid_t is too large");
129 unsigned long long v = std::stoull(param, &ind, 0);
130 if (v > static_cast<unsigned long long>(std::numeric_limits<gid_t>::max())
131 || ind != param.length()) {
132 throw service_description_exc(service_name, gid_err_msg);
136 catch (std::out_of_range &exc) {
137 throw service_description_exc(service_name, gid_err_msg);
139 catch (std::invalid_argument &exc) {
140 // Ok, so it doesn't look like a number: proceed...
144 struct group * grent = getgrnam(param.c_str());
145 if (grent == nullptr) {
146 // Maybe an error, maybe just no entry.
148 throw service_description_exc(service_name, "Specified group \"" + param
149 + "\" does not exist in system database.");
152 throw service_description_exc(service_name, std::string("Error accessing group database: ")
157 return grent->gr_gid;
160 // Parse a time, specified as a decimal number of seconds (with optional fractional component after decimal
161 // point or decimal comma).
162 static void parse_timespec(const std::string ¶mval, const std::string &servicename,
163 const char * paramname, timespec &ts)
165 decltype(ts.tv_sec) isec = 0;
166 decltype(ts.tv_nsec) insec = 0;
167 auto max_secs = std::numeric_limits<decltype(isec)>::max() / 10;
168 auto len = paramval.length();
170 for (i = 0; i < len; i++) {
171 char ch = paramval[i];
172 if (ch == '.' || ch == ',') {
176 if (ch < '0' || ch > '9') {
177 throw service_description_exc(servicename, std::string("Bad value for ") + paramname);
179 // check for overflow
180 if (isec >= max_secs) {
181 throw service_description_exc(servicename, std::string("Too-large value for ") + paramname);
186 decltype(insec) insec_m = 100000000; // 10^8
187 for ( ; i < len; i++) {
188 char ch = paramval[i];
189 if (ch < '0' || ch > '9') {
190 throw service_description_exc(servicename, std::string("Bad value for ") + paramname);
192 insec += (ch - '0') * insec_m;
199 // In a vector, find or create rlimits for a particular resource type.
200 static service_rlimits &find_rlimits(std::vector<service_rlimits> &all_rlimits, int resource_id)
202 for (service_rlimits &limits : all_rlimits) {
203 if (limits.resource_id == resource_id) {
208 all_rlimits.emplace_back(resource_id);
209 return all_rlimits.back();
212 // Parse resource limits setting (can specify both hard and soft limit).
213 static void parse_rlimit(const std::string &line, const std::string &service_name, const char *param_name,
214 service_rlimits &rlimit)
217 // 4:5 - soft:hard limits both set
218 // 4:- soft set, hard set to unlimited
219 // 4: soft set, hard limit unchanged
220 // 4 soft and hard limit set to same limit
223 throw service_description_exc(service_name, std::string("Bad value for ") + param_name);
226 const char *cline = line.c_str();
227 rlimit.hard_set = rlimit.soft_set = false;
230 const char * index = cline;
232 if (cline[0] != ':') {
233 rlimit.soft_set = true;
234 if (cline[0] == '-') {
235 rlimit.limits.rlim_cur = RLIM_INFINITY;
240 unsigned long long limit = std::strtoull(cline, &nindex, 0);
242 if (errno == ERANGE || limit > std::numeric_limits<rlim_t>::max()) throw std::out_of_range("");
243 if (index == cline) throw std::invalid_argument("");
244 rlimit.limits.rlim_cur = limit;
248 rlimit.hard_set = true;
249 rlimit.limits.rlim_max = rlimit.limits.rlim_cur;
254 throw service_description_exc(service_name, std::string("Bad value for ") + param_name);
259 if (*index == 0) return;
262 rlimit.limits.rlim_max = RLIM_INFINITY;
264 throw service_description_exc(service_name, std::string("Bad value for ") + param_name);
268 const char *hard_start = index;
270 unsigned long long limit = std::strtoull(cline, &nindex, 0);
272 if (errno == ERANGE || limit > std::numeric_limits<rlim_t>::max()) throw std::out_of_range("");
273 if (index == hard_start) throw std::invalid_argument("");
274 rlimit.limits.rlim_max = limit;
277 catch (std::invalid_argument &exc) {
278 throw service_description_exc(service_name, std::string("Bad value for ") + param_name);
280 catch (std::out_of_range &exc) {
281 throw service_description_exc(service_name, std::string("Too-large value for ") + param_name);
285 // Perform environment variable substitution on a command line, if specified.
286 // line - the string storing the command and arguments
287 // offsets - the [start,end) pair of offsets of the command and each argument within the string
289 static void do_env_subst(std::string &line, std::list<std::pair<unsigned,unsigned>> &offsets,
293 auto i = offsets.begin();
294 std::string r_line = line.substr(i->first, i->second - i->first); // copy command part
295 for (++i; i != offsets.end(); ++i) {
296 auto &offset_pair = *i;
297 if (line[offset_pair.first] == '$') {
298 // Do subsitution for this part:
299 auto env_name = line.substr(offset_pair.first + 1,
300 offset_pair.second - offset_pair.first - 1);
301 char *env_val = getenv(env_name.c_str());
302 if (env_val != nullptr) {
303 auto val_len = strlen(env_val);
305 offset_pair.first = r_line.length();
306 offset_pair.second = offset_pair.first + val_len;
310 // specified enironment variable not set: treat as an empty string
311 offset_pair.first = r_line.length();
312 offset_pair.second = offset_pair.first;
316 // No subsitution for this part:
318 auto new_offs = r_line.length();
319 auto len = offset_pair.second - offset_pair.first;
320 r_line += line.substr(offset_pair.first, len);
321 offset_pair.first = new_offs;
322 offset_pair.second = new_offs + len;
325 line = std::move(r_line);
329 // Process a dependency directory - filenames contained within correspond to service names which
330 // are loaded and added as a dependency of the given type. Expected use is with a directory
331 // containing symbolic links to other service descriptions, but this isn't required.
332 // Failure to read the directory contents, or to find a service listed within, is not considered
334 static void process_dep_dir(dirload_service_set &sset,
335 const char *servicename,
336 const string &service_filename,
337 std::list<prelim_dep> &deplist, const std::string &depdirpath,
338 dependency_type dep_type)
340 std::string depdir_fname = combine_paths(parent_path(service_filename), depdirpath.c_str());
342 DIR *depdir = opendir(depdir_fname.c_str());
343 if (depdir == nullptr) {
344 log(loglevel_t::WARN, "Could not open dependency directory '", depdir_fname,
345 "' for ", servicename, " service.");
350 dirent * dent = readdir(depdir);
351 while (dent != nullptr) {
352 char * name = dent->d_name;
353 if (name[0] != '.') {
355 service_record * sr = sset.load_service(name);
356 deplist.emplace_back(sr, dep_type);
358 catch (service_not_found &) {
359 log(loglevel_t::WARN, "Ignoring unresolved dependency '", name,
360 "' in dependency directory '", depdirpath,
361 "' for ", servicename, " service.");
364 dent = readdir(depdir);
368 log(loglevel_t::WARN, "Error reading dependency directory '", depdirpath,
369 "' for ", servicename, " service.");
375 // Check if one string starts with another
376 static bool starts_with(string s, const char *prefix)
378 const char * sp = s.c_str();
379 while (*sp != 0 && *prefix != 0) {
380 if (*sp != *prefix) return false;
386 // Find a service record, or load it from file. If the service has
387 // dependencies, load those also.
389 // Might throw a ServiceLoadExc exception if a dependency cycle is found or if another
390 // problem occurs (I/O error, service description not found etc). Throws std::bad_alloc
391 // if a memory allocation failure occurs.
393 service_record * dirload_service_set::load_service(const char * name)
405 using namespace dinit_load;
407 // First try and find an existing record...
408 service_record * rval = find_service(string(name));
410 if (rval->is_dummy()) {
411 throw service_cyclic_dependency(name);
416 ifstream service_file;
417 string service_filename;
419 // Couldn't find one. Have to load it.
420 for (auto &service_dir : service_dirs) {
421 service_filename = service_dir.get_dir();
422 if (*(service_filename.rbegin()) != '/') {
423 service_filename += '/';
425 service_filename += name;
427 service_file.open(service_filename.c_str(), ios::in);
428 if (service_file) break;
431 if (! service_file) {
432 throw service_not_found(string(name));
436 list<pair<unsigned,unsigned>> command_offsets;
438 list<pair<unsigned,unsigned>> stop_command_offsets;
443 bool do_sub_vars = false;
445 service_type_t service_type = service_type_t::PROCESS;
446 std::list<prelim_dep> depends;
448 service_flags_t onstart_flags;
449 int term_signal = -1; // additional termination signal
450 bool auto_restart = false;
451 bool smooth_recovery = false;
453 int socket_perms = 0666;
454 // Note: Posix allows that uid_t and gid_t may be unsigned types, but eg chown uses -1 as an
455 // invalid value, so it's safe to assume that we can do the same:
456 uid_t socket_uid = -1;
457 gid_t socket_gid = -1;
458 // Restart limit interval / count; default is 10 seconds, 3 restarts:
459 timespec restart_interval = { .tv_sec = 10, .tv_nsec = 0 };
460 int max_restarts = 3;
461 timespec restart_delay = { .tv_sec = 0, .tv_nsec = 200000000 };
462 timespec stop_timeout = { .tv_sec = 10, .tv_nsec = 0 };
463 timespec start_timeout = { .tv_sec = 60, .tv_nsec = 0 };
464 std::vector<service_rlimits> rlimits;
466 int readiness_fd = -1; // readiness fd in service process
467 std::string readiness_var; // environment var to hold readiness fd
469 uid_t run_as_uid = -1;
470 gid_t run_as_gid = -1;
472 string chain_to_name;
475 char inittab_id[sizeof(utmpx().ut_id)] = {0};
476 char inittab_line[sizeof(utmpx().ut_line)] = {0};
480 service_file.exceptions(ios::badbit | ios::failbit);
482 // Add a dummy service record now to prevent infinite recursion in case of cyclic dependency.
483 // We replace this with the real service later (or remove it if we find a configuration error).
484 rval = new service_record(this, string(name));
488 // getline can set failbit if it reaches end-of-file, we don't want an exception in that case:
489 service_file.exceptions(ios::badbit);
491 process_service_file(name, service_file,
492 [&](string &line, string &setting, string_iterator &i, string_iterator &end) -> void {
493 if (setting == "command") {
494 command = read_setting_value(i, end, &command_offsets);
496 else if (setting == "working-dir") {
497 working_dir = read_setting_value(i, end, nullptr);
499 else if (setting == "env-file") {
500 env_file = read_setting_value(i, end, nullptr);
502 else if (setting == "socket-listen") {
503 socket_path = read_setting_value(i, end, nullptr);
505 else if (setting == "socket-permissions") {
506 string sock_perm_str = read_setting_value(i, end, nullptr);
509 socket_perms = std::stoi(sock_perm_str, &ind, 8);
510 if (ind != sock_perm_str.length()) {
511 throw std::logic_error("");
514 catch (std::logic_error &exc) {
515 throw service_description_exc(name, "socket-permissions: Badly-formed or "
516 "out-of-range numeric value");
519 else if (setting == "socket-uid") {
520 string sock_uid_s = read_setting_value(i, end, nullptr);
521 socket_uid = parse_uid_param(sock_uid_s, name, &socket_gid);
523 else if (setting == "socket-gid") {
524 string sock_gid_s = read_setting_value(i, end, nullptr);
525 socket_gid = parse_gid_param(sock_gid_s, name);
527 else if (setting == "stop-command") {
528 stop_command = read_setting_value(i, end, &stop_command_offsets);
530 else if (setting == "pid-file") {
531 pid_file = read_setting_value(i, end);
533 else if (setting == "depends-on") {
534 string dependency_name = read_setting_value(i, end);
535 depends.emplace_back(load_service(dependency_name.c_str()), dependency_type::REGULAR);
537 else if (setting == "depends-ms") {
538 string dependency_name = read_setting_value(i, end);
539 depends.emplace_back(load_service(dependency_name.c_str()), dependency_type::MILESTONE);
541 else if (setting == "waits-for") {
542 string dependency_name = read_setting_value(i, end);
543 depends.emplace_back(load_service(dependency_name.c_str()), dependency_type::WAITS_FOR);
545 else if (setting == "waits-for.d") {
546 string waitsford = read_setting_value(i, end);
547 process_dep_dir(*this, name, service_filename, depends, waitsford,
548 dependency_type::WAITS_FOR);
550 else if (setting == "logfile") {
551 logfile = read_setting_value(i, end);
553 else if (setting == "restart") {
554 string restart = read_setting_value(i, end);
555 auto_restart = (restart == "yes" || restart == "true");
557 else if (setting == "smooth-recovery") {
558 string recovery = read_setting_value(i, end);
559 smooth_recovery = (recovery == "yes" || recovery == "true");
561 else if (setting == "type") {
562 string type_str = read_setting_value(i, end);
563 if (type_str == "scripted") {
564 service_type = service_type_t::SCRIPTED;
566 else if (type_str == "process") {
567 service_type = service_type_t::PROCESS;
569 else if (type_str == "bgprocess") {
570 service_type = service_type_t::BGPROCESS;
572 else if (type_str == "internal") {
573 service_type = service_type_t::INTERNAL;
576 throw service_description_exc(name, "Service type must be one of: \"scripted\","
577 " \"process\", \"bgprocess\" or \"internal\"");
580 else if (setting == "options") {
581 std::list<std::pair<unsigned,unsigned>> indices;
582 string onstart_cmds = read_setting_value(i, end, &indices);
583 for (auto indexpair : indices) {
584 string option_txt = onstart_cmds.substr(indexpair.first,
585 indexpair.second - indexpair.first);
586 if (option_txt == "starts-rwfs") {
587 onstart_flags.rw_ready = true;
589 else if (option_txt == "starts-log") {
590 onstart_flags.log_ready = true;
592 else if (option_txt == "no-sigterm") {
593 onstart_flags.no_sigterm = true;
595 else if (option_txt == "runs-on-console") {
596 onstart_flags.runs_on_console = true;
597 // A service that runs on the console necessarily starts on console:
598 onstart_flags.starts_on_console = true;
599 onstart_flags.shares_console = false;
601 else if (option_txt == "starts-on-console") {
602 onstart_flags.starts_on_console = true;
603 onstart_flags.shares_console = false;
605 else if (option_txt == "shares-console") {
606 onstart_flags.shares_console = true;
607 onstart_flags.runs_on_console = false;
608 onstart_flags.starts_on_console = false;
610 else if (option_txt == "pass-cs-fd") {
611 onstart_flags.pass_cs_fd = true;
613 else if (option_txt == "start-interruptible") {
614 onstart_flags.start_interruptible = true;
616 else if (option_txt == "skippable") {
617 onstart_flags.skippable = true;
619 else if (option_txt == "signal-process-only") {
620 onstart_flags.signal_process_only = true;
623 throw service_description_exc(name, "Unknown option: " + option_txt);
627 else if (setting == "load-options") {
628 std::list<std::pair<unsigned,unsigned>> indices;
629 string load_opts = read_setting_value(i, end, &indices);
630 for (auto indexpair : indices) {
631 string option_txt = load_opts.substr(indexpair.first,
632 indexpair.second - indexpair.first);
633 if (option_txt == "sub-vars") {
634 // substitute environment variables in command line
637 else if (option_txt == "no-sub-vars") {
641 throw service_description_exc(name, "Unknown load option: " + option_txt);
645 else if (setting == "term-signal" || setting == "termsignal") {
646 // Note: "termsignal" supported for legacy reasons.
647 string signame = read_setting_value(i, end, nullptr);
648 int signo = signal_name_to_number(signame);
650 throw service_description_exc(name, "Unknown/unsupported termination signal: "
657 else if (setting == "restart-limit-interval") {
658 string interval_str = read_setting_value(i, end, nullptr);
659 parse_timespec(interval_str, name, "restart-limit-interval", restart_interval);
661 else if (setting == "restart-delay") {
662 string rsdelay_str = read_setting_value(i, end, nullptr);
663 parse_timespec(rsdelay_str, name, "restart-delay", restart_delay);
665 else if (setting == "restart-limit-count") {
666 string limit_str = read_setting_value(i, end, nullptr);
667 max_restarts = parse_unum_param(limit_str, name, std::numeric_limits<int>::max());
669 else if (setting == "stop-timeout") {
670 string stoptimeout_str = read_setting_value(i, end, nullptr);
671 parse_timespec(stoptimeout_str, name, "stop-timeout", stop_timeout);
673 else if (setting == "start-timeout") {
674 string starttimeout_str = read_setting_value(i, end, nullptr);
675 parse_timespec(starttimeout_str, name, "start-timeout", start_timeout);
677 else if (setting == "run-as") {
678 string run_as_str = read_setting_value(i, end, nullptr);
679 run_as_uid = parse_uid_param(run_as_str, name, &run_as_gid);
681 else if (setting == "chain-to") {
682 chain_to_name = read_setting_value(i, end, nullptr);
684 else if (setting == "ready-notification") {
685 string notify_setting = read_setting_value(i, end, nullptr);
686 if (starts_with(notify_setting, "pipefd:")) {
687 readiness_fd = parse_unum_param(notify_setting.substr(7 /* len 'pipefd:' */),
688 name, std::numeric_limits<int>::max());
690 else if (starts_with(notify_setting, "pipevar:")) {
691 readiness_var = notify_setting.substr(8 /* len 'pipevar:' */);
692 if (readiness_var.empty()) {
693 throw service_description_exc(name, "Invalid pipevar variable name "
694 "in ready-notification");
698 throw service_description_exc(name, "Unknown ready-notification setting: "
702 else if (setting == "inittab-id") {
703 string inittab_setting = read_setting_value(i, end, nullptr);
705 if (inittab_setting.length() > sizeof(inittab_id)) {
706 throw service_description_exc(name, "inittab-id setting is too long");
708 strncpy(inittab_id, inittab_setting.c_str(), sizeof(inittab_id));
711 else if (setting == "inittab-line") {
712 string inittab_setting = read_setting_value(i, end, nullptr);
714 if (inittab_setting.length() > sizeof(inittab_line)) {
715 throw service_description_exc(name, "inittab-line setting is too long");
717 strncpy(inittab_line, inittab_setting.c_str(), sizeof(inittab_line));
720 else if (setting == "rlimit-nofile") {
721 string nofile_setting = read_setting_value(i, end, nullptr);
722 service_rlimits &nofile_limits = find_rlimits(rlimits, RLIMIT_NOFILE);
723 parse_rlimit(line, name, "rlimit-nofile", nofile_limits);
725 else if (setting == "rlimit-core") {
726 string nofile_setting = read_setting_value(i, end, nullptr);
727 service_rlimits &nofile_limits = find_rlimits(rlimits, RLIMIT_CORE);
728 parse_rlimit(line, name, "rlimit-core", nofile_limits);
730 else if (setting == "rlimit-data") {
731 string nofile_setting = read_setting_value(i, end, nullptr);
732 service_rlimits &nofile_limits = find_rlimits(rlimits, RLIMIT_DATA);
733 parse_rlimit(line, name, "rlimit-data", nofile_limits);
735 else if (setting == "rlimit-addrspace") {
736 #if defined(RLIMIT_AS)
737 string nofile_setting = read_setting_value(i, end, nullptr);
738 service_rlimits &nofile_limits = find_rlimits(rlimits, RLIMIT_AS);
739 parse_rlimit(line, name, "rlimit-addrspace", nofile_limits);
743 throw service_description_exc(name, "Unknown setting: " + setting);
747 service_file.close();
749 if (service_type == service_type_t::PROCESS || service_type == service_type_t::BGPROCESS
750 || service_type == service_type_t::SCRIPTED) {
751 if (command.length() == 0) {
752 throw service_description_exc(name, "Service command not specified");
756 // Now replace the dummy service record with a real record:
757 for (auto iter = records.begin(); iter != records.end(); iter++) {
759 // We've found the dummy record
761 if (service_type == service_type_t::PROCESS) {
762 do_env_subst(command, command_offsets, do_sub_vars);
763 auto rvalps = new process_service(this, string(name), std::move(command),
764 command_offsets, depends);
765 rvalps->set_working_dir(working_dir);
766 rvalps->set_env_file(env_file);
767 rvalps->set_rlimits(std::move(rlimits));
768 rvalps->set_restart_interval(restart_interval, max_restarts);
769 rvalps->set_restart_delay(restart_delay);
770 rvalps->set_stop_timeout(stop_timeout);
771 rvalps->set_start_timeout(start_timeout);
772 rvalps->set_extra_termination_signal(term_signal);
773 rvalps->set_run_as_uid_gid(run_as_uid, run_as_gid);
774 rvalps->set_notification_fd(readiness_fd);
775 rvalps->set_notification_var(std::move(readiness_var));
777 rvalps->set_utmp_id(inittab_id);
778 rvalps->set_utmp_line(inittab_line);
782 else if (service_type == service_type_t::BGPROCESS) {
783 do_env_subst(command, command_offsets, do_sub_vars);
784 auto rvalps = new bgproc_service(this, string(name), std::move(command),
785 command_offsets, depends);
786 rvalps->set_working_dir(working_dir);
787 rvalps->set_env_file(env_file);
788 rvalps->set_rlimits(std::move(rlimits));
789 rvalps->set_pid_file(std::move(pid_file));
790 rvalps->set_restart_interval(restart_interval, max_restarts);
791 rvalps->set_restart_delay(restart_delay);
792 rvalps->set_stop_timeout(stop_timeout);
793 rvalps->set_start_timeout(start_timeout);
794 rvalps->set_extra_termination_signal(term_signal);
795 rvalps->set_run_as_uid_gid(run_as_uid, run_as_gid);
796 onstart_flags.runs_on_console = false;
799 else if (service_type == service_type_t::SCRIPTED) {
800 do_env_subst(command, command_offsets, do_sub_vars);
801 auto rvalps = new scripted_service(this, string(name), std::move(command),
802 command_offsets, depends);
803 rvalps->set_stop_command(stop_command, stop_command_offsets);
804 rvalps->set_working_dir(working_dir);
805 rvalps->set_env_file(env_file);
806 rvalps->set_rlimits(std::move(rlimits));
807 rvalps->set_stop_timeout(stop_timeout);
808 rvalps->set_start_timeout(start_timeout);
809 rvalps->set_extra_termination_signal(term_signal);
810 rvalps->set_run_as_uid_gid(run_as_uid, run_as_gid);
814 rval = new service_record(this, string(name), service_type, depends);
816 rval->set_log_file(logfile);
817 rval->set_auto_restart(auto_restart);
818 rval->set_smooth_recovery(smooth_recovery);
819 rval->set_flags(onstart_flags);
820 rval->set_socket_details(std::move(socket_path), socket_perms, socket_uid, socket_gid);
821 rval->set_chain_to(std::move(chain_to_name));
829 catch (setting_exception &setting_exc)
831 // Must remove the dummy service record.
832 records.erase(std::find(records.begin(), records.end(), rval));
834 throw service_description_exc(name, std::move(setting_exc.get_info()));
837 // Must remove the dummy service record.
838 records.erase(std::find(records.begin(), records.end(), rval));