load-service.cc 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847
  1. #include <algorithm>
  2. #include <string>
  3. #include <fstream>
  4. #include <locale>
  5. #include <limits>
  6. #include <list>
  7. #include <utility>
  8. #include <iterator>
  9. #include <cstring>
  10. #include <cstdlib>
  11. #include <sys/stat.h>
  12. #include <sys/types.h>
  13. #include <pwd.h>
  14. #include <grp.h>
  15. #include <dirent.h>
  16. #include "proc-service.h"
  17. #include "dinit-log.h"
  18. #include "dinit-util.h"
  19. #include "dinit-utmp.h"
  20. using string = std::string;
  21. using string_iterator = std::string::iterator;
  22. // Perform environment variable substitution on a command line, if specified.
  23. // line - the string storing the command and arguments
  24. // offsets - the [start,end) pair of offsets of the command and each argument within the string
  25. //
  26. static void do_env_subst(const char *setting_name, ha_string &line,
  27. std::list<std::pair<unsigned,unsigned>> &offsets,
  28. environment::env_map const &envmap)
  29. {
  30. using namespace dinit_load;
  31. std::string line_s = std::string(line.c_str(), line.length());
  32. value_var_subst(setting_name, line_s, offsets, resolve_env_var, envmap);
  33. line = line_s;
  34. }
  35. // Process a dependency directory - filenames contained within correspond to service names which
  36. // are loaded and added as a dependency of the given type. Expected use is with a directory
  37. // containing symbolic links to other service descriptions, but this isn't required.
  38. // Failure to read the directory contents, or to find a service listed within, is not considered
  39. // a fatal error.
  40. static void process_dep_dir(dirload_service_set &sset,
  41. const char *servicename,
  42. const string &service_filename,
  43. std::list<prelim_dep> &deplist, const std::string &depdirpath,
  44. dependency_type dep_type,
  45. const service_record *avoid_circular)
  46. {
  47. std::string depdir_fname = combine_paths(parent_path(service_filename), depdirpath.c_str());
  48. DIR *depdir = opendir(depdir_fname.c_str());
  49. if (depdir == nullptr) {
  50. log(loglevel_t::WARN, "Could not open dependency directory '", depdir_fname,
  51. "' for ", servicename, " service.");
  52. return;
  53. }
  54. errno = 0;
  55. dirent * dent = readdir(depdir);
  56. while (dent != nullptr) {
  57. char * name = dent->d_name;
  58. if (name[0] != '.') {
  59. try {
  60. service_record * sr = sset.load_service(name);
  61. deplist.emplace_back(sr, dep_type);
  62. }
  63. catch (service_not_found &) {
  64. log(loglevel_t::WARN, "Ignoring unresolved dependency '", name,
  65. "' in dependency directory '", depdirpath,
  66. "' for ", servicename, " service.");
  67. }
  68. }
  69. errno = 0; // errno may have changed in the meantime
  70. dent = readdir(depdir);
  71. }
  72. if (errno != 0) {
  73. log(loglevel_t::WARN, "Error reading dependency directory '", depdirpath,
  74. "' for ", servicename, " service.");
  75. }
  76. closedir(depdir);
  77. }
  78. service_record * dirload_service_set::load_service(const char * name, const service_record *avoid_circular)
  79. {
  80. return load_reload_service(name, nullptr, avoid_circular);
  81. }
  82. service_record * dirload_service_set::reload_service(service_record * service)
  83. {
  84. return load_reload_service(service->get_name().c_str(), service, service);
  85. }
  86. using service_dep_list = decltype(std::declval<dinit_load::service_settings_wrapper<prelim_dep>>().depends);
  87. // Check for dependency cycles for the specified service (orig) with the given set of dependencies. Report
  88. // any cycles as occurring in _report_svc_name_.
  89. static void check_cycle(service_dep_list &deps, service_record *orig, const std::string &report_svc_name)
  90. {
  91. linked_uo_set<service_record *> pending;
  92. for (auto &new_dep : deps) {
  93. if (new_dep.to == orig) {
  94. throw service_cyclic_dependency(report_svc_name);
  95. }
  96. pending.add_back(new_dep.to);
  97. }
  98. for (auto i = pending.begin(); i != pending.end(); ++i) {
  99. auto &dep_list = (*i)->get_dependencies();
  100. for (auto &dep : dep_list) {
  101. if (dep.get_to() == orig) {
  102. throw service_cyclic_dependency(report_svc_name);
  103. }
  104. pending.add_back(dep.get_to());
  105. }
  106. }
  107. }
  108. // Check for dependency cycles in "before" dependencies, _orig_ is where cycles will be identified.
  109. static void check_cycle(service_dep_list &deps, service_record *orig)
  110. {
  111. check_cycle(deps, orig, orig->get_name());
  112. }
  113. // Update the dependencies of the specified service atomically.
  114. // May fail with bad_alloc, service_cyclic_dependency.
  115. static void update_depenencies(service_record *service,
  116. dinit_load::service_settings_wrapper<prelim_dep> &settings,
  117. std::list<service_dep> &before_deps)
  118. {
  119. check_cycle(settings.depends, service);
  120. std::list<service_dep> &deps = service->get_dependencies();
  121. auto first_preexisting = deps.begin();
  122. auto &depts = service->get_dependents();
  123. auto first_pre_dept = depts.begin();
  124. try {
  125. // Insert all new dependents (from "before" relationships) before the first pre-existing dependent
  126. for (auto new_dept_i = before_deps.begin(); new_dept_i != before_deps.end(); ) {
  127. auto &new_dept = *new_dept_i;
  128. depts.insert(depts.begin(), &new_dept);
  129. // splice the dependency into the dependent:
  130. auto next_dept_i = std::next(new_dept_i);
  131. auto &from_deps = new_dept.get_from()->get_dependencies();
  132. from_deps.splice(from_deps.begin(), before_deps, new_dept_i);
  133. new_dept_i = next_dept_i;
  134. }
  135. // Insert all the new dependencies before the first pre-existing dependency
  136. for (auto i = settings.depends.begin(); i != settings.depends.end(); ) {
  137. auto &new_dep = *i;
  138. service->add_dep(new_dep.to, new_dep.dep_type, first_preexisting);
  139. i = settings.depends.erase(i);
  140. }
  141. }
  142. catch (...) {
  143. // remove "before" dependencies from dependents
  144. for (auto i = depts.begin(); i != first_pre_dept; ) {
  145. auto next_i = std::next(i);
  146. (*i)->get_from()->rm_dep(**i);
  147. i = next_i;
  148. }
  149. // remove the inserted dependencies
  150. for (auto i = deps.begin(); i != first_preexisting; ) {
  151. i = service->rm_dep(i);
  152. }
  153. // re-throw the exception
  154. throw;
  155. }
  156. // Now remove all pre-existing dependencies, except for "before" dependencies (which come from the
  157. // linked service and so must be retained)
  158. for( ; first_preexisting != deps.end(); ) {
  159. if (first_preexisting->dep_type != dependency_type::BEFORE) {
  160. first_preexisting = service->rm_dep(first_preexisting);
  161. }
  162. else {
  163. ++first_preexisting;
  164. }
  165. }
  166. // Also remove pre-existing "before" dependents (because they come from this service)
  167. for( ; first_pre_dept != depts.end(); ) {
  168. auto next_pre_dept = std::next(first_pre_dept);
  169. if ((*first_pre_dept)->dep_type == dependency_type::BEFORE) {
  170. (*first_pre_dept)->get_from()->rm_dep(**first_pre_dept);
  171. }
  172. first_pre_dept = next_pre_dept;
  173. }
  174. }
  175. // Update the command, and dependencies, of the specified service atomically.
  176. // May fail with bad_alloc, service_cyclic_dependency.
  177. static void update_command_and_dependencies(base_process_service *service,
  178. dinit_load::service_settings_wrapper<prelim_dep> &settings,
  179. std::list<service_dep> &before_deps)
  180. {
  181. // Get the current command parts
  182. ha_string orig_cmd; std::vector<const char *> orig_arg_parts;
  183. service->get_command(orig_cmd, orig_arg_parts);
  184. // Separate the new command parts and set
  185. std::vector<const char *> cmd_arg_parts = separate_args(settings.command, settings.command_offsets);
  186. service->set_command(std::move(settings.command), std::move(cmd_arg_parts));
  187. try {
  188. update_depenencies(service, settings, before_deps);
  189. }
  190. catch (...) {
  191. // restore original command
  192. service->set_command(std::move(orig_cmd), std::move(orig_arg_parts));
  193. // re-throw the exception
  194. throw;
  195. }
  196. }
  197. service_record * dirload_service_set::load_reload_service(const char *name, service_record *reload_svc,
  198. const service_record *avoid_circular)
  199. {
  200. // Load a new service, or reload an already-loaded service.
  201. // For reload, we have the following problems:
  202. // - ideally want to allow changing service type, at least for stopped services. That implies creating
  203. // a new (replacement) service_record object, at least in cases where the type does change.
  204. // - dependencies may change (including addition of new dependencies which aren't yet loaded). We need
  205. // to prevent cyclic dependencies forming.
  206. // - We want atomicity. If any new settings are not valid/alterable, or if a cyclic dependency is
  207. // created, nothing should change.
  208. // - We need to either transfer handles referring to the old service (so that they refer to the new
  209. // service), or make them invalid. Or, we alter the original service without creating a new one
  210. // (which we can only do if the type doesn't change).
  211. // Approach:
  212. // - determine whether we need a new service record or can alter the existing one
  213. // (loading a new service always creates a new record; reload only creates a new record if the service
  214. // type changes, and otherwise just changes the existing record in-place).
  215. // - if loading a new service, a dummy record is created to enable easy cyclic dependency detection.
  216. // (In other cases cycles must be checked by walking the service graph).
  217. // The dummy is replaced with the real service once loading is complete (or is removed if it fails).
  218. // - process settings from the service file (into a service_settings_wrapper).
  219. // - check that the new settings are valid (for reload, if the service is running, check if the settings
  220. // can be altered).
  221. // - create the new record and install the new settings in it (or the existing record if not creating a
  222. // new record). If doing a reload, check for cycles at this point (there is no dummy record in this
  223. // case, so the quick cycle detection is not active).
  224. // - (if doing a reload, with a new record) move the dependents on the original record to the new record.
  225. //
  226. // "Before" dependencies require special handling, as a "before = " specified in a service actually creates
  227. // a dependency in the specified service on this service. Hence they always require explicit cycle checks
  228. // (the quick cycle detection method using a dummy service cannot be used). For reloads this is done early,
  229. // for new services it is done late (after the dummy has been removed).
  230. //
  231. // This is all an intricate dance. If failure occurs at any stage, we must restore the previous state.
  232. // Limitations:
  233. // - caller must check there are no handles (or only a single requesting handle) to the service before
  234. // calling
  235. // - cannot change the type of a non-stopped service
  236. using std::string;
  237. using std::ifstream;
  238. using std::ios;
  239. using std::ios_base;
  240. using std::locale;
  241. using std::isspace;
  242. using std::list;
  243. using std::pair;
  244. using namespace dinit_load;
  245. if (reload_svc == nullptr) {
  246. // First try and find an existing record...
  247. service_record *existing = find_service(string(name), true);
  248. if (existing != nullptr) {
  249. if (existing == avoid_circular || existing->check_is_loading()) {
  250. throw service_cyclic_dependency(name);
  251. }
  252. if (existing->get_type() != service_type_t::PLACEHOLDER) {
  253. return existing;
  254. }
  255. // If we found a placeholder, we proceed as for a reload:
  256. reload_svc = existing;
  257. }
  258. }
  259. service_record *rval = nullptr;
  260. service_record *dummy = nullptr;
  261. ifstream service_file;
  262. string service_filename;
  263. int fail_load_errno = 0;
  264. std::string fail_load_path;
  265. // Couldn't find one. Have to load it.
  266. for (auto &service_dir : service_dirs) {
  267. service_filename = service_dir.get_dir();
  268. if (*(service_filename.rbegin()) != '/') {
  269. service_filename += '/';
  270. }
  271. service_filename += name;
  272. service_file.open(service_filename.c_str(), ios::in);
  273. if (service_file) break;
  274. if (errno != ENOENT && fail_load_errno == 0) {
  275. fail_load_errno = errno;
  276. fail_load_path = std::move(service_filename);
  277. }
  278. }
  279. if (!service_file) {
  280. if (fail_load_errno == 0) {
  281. throw service_not_found(string(name));
  282. }
  283. else {
  284. throw service_load_error(name, std::move(fail_load_path), fail_load_errno);
  285. }
  286. }
  287. service_settings_wrapper<prelim_dep> settings;
  288. string line;
  289. // getline can set failbit if it reaches end-of-file, we don't want an exception in that case. There's
  290. // no good way to handle an I/O error however, so we'll have exceptions thrown on badbit:
  291. service_file.exceptions(ios::badbit);
  292. bool create_new_record = true;
  293. // any "before" "dependencies" that were loaded
  294. std::list<service_dep> before_deps;
  295. auto exception_cleanup = [&]() {
  296. // Must remove the dummy service record.
  297. if (dummy != nullptr) {
  298. remove_service(dummy);
  299. delete dummy;
  300. }
  301. if (create_new_record && rval != nullptr) {
  302. rval->prepare_for_unload();
  303. delete rval;
  304. }
  305. for (service_dep &before_dep : before_deps) {
  306. service_record *before_svc = before_dep.get_from();
  307. if (before_svc->get_type() == service_type_t::PLACEHOLDER) {
  308. if (before_svc->is_unrefd()) {
  309. remove_service(before_svc);
  310. delete before_svc;
  311. }
  312. }
  313. }
  314. // Remove any "after" placeholders that were created while loading but not successfully added as
  315. // dependencies on the new service (rval). (This requires that settings.depends has been cleared
  316. // of any dependencies that were successfully added).
  317. for (prelim_dep &dep : settings.depends) {
  318. if (dep.dep_type == dependency_type::AFTER && dep.to->is_unrefd()) {
  319. remove_service(dep.to);
  320. }
  321. }
  322. };
  323. if (reload_svc == nullptr) {
  324. // Add a placeholder record now to prevent infinite recursion in case of cyclic dependency.
  325. // We replace this with the real service later (or remove it if we find a configuration error).
  326. try {
  327. dummy = new service_record(this, string(name), service_record::LOADING_TAG);
  328. add_service(dummy);
  329. }
  330. catch (...) {
  331. delete dummy; // (no effect if dummy is null)
  332. dummy = nullptr;
  333. throw;
  334. }
  335. }
  336. try {
  337. process_service_file(name, service_file,
  338. [&](string &line, unsigned line_num, string &setting,
  339. string_iterator &i, string_iterator &end) -> void {
  340. auto process_dep_dir_n = [&](std::list<prelim_dep> &deplist, const std::string &waitsford,
  341. dependency_type dep_type) -> void {
  342. process_dep_dir(*this, name, service_filename, deplist, waitsford, dep_type, reload_svc);
  343. };
  344. auto load_service_n = [&](const string &dep_name) -> service_record * {
  345. try {
  346. return load_service(dep_name.c_str(), reload_svc);
  347. }
  348. catch (service_description_exc &sle) {
  349. log_service_load_failure(sle);
  350. throw service_load_exc(name, "could not load dependency.");
  351. }
  352. catch (service_load_exc &sle) {
  353. log(loglevel_t::ERROR, "Could not load service ", sle.service_name, ": ",
  354. sle.exc_description);
  355. throw service_load_exc(name, "could not load dependency.");
  356. }
  357. };
  358. process_service_line(settings, name, line, line_num, setting, i, end, load_service_n,
  359. process_dep_dir_n);
  360. });
  361. service_file.close();
  362. auto report_err = [&](const char *msg){
  363. throw service_load_exc(name, msg);
  364. };
  365. environment srv_env;
  366. /* fill user vars before reading env file */
  367. if (settings.export_passwd_vars) {
  368. fill_environment_userinfo(settings.run_as_uid, name, srv_env);
  369. }
  370. /* set service name in environment if desired */
  371. if (settings.export_service_name) {
  372. std::string envname = "DINIT_SERVICE=";
  373. envname += name;
  374. srv_env.set_var(std::move(envname));
  375. }
  376. // this mapping is temporary, for load substitutions
  377. // the reason for this is that the environment actually *may* change
  378. // after load, e.g. through dinitctl setenv (either from the outside
  379. // or from within services) and we want this to refresh for each
  380. // process invocation
  381. environment::env_map srv_envmap;
  382. if (!settings.env_file.empty()) {
  383. try {
  384. read_env_file(settings.env_file.data(), false, srv_env);
  385. } catch (const std::system_error &se) {
  386. throw service_load_exc(name, std::string("could not load environment file: ") + se.what());
  387. }
  388. }
  389. srv_envmap = srv_env.build(main_env);
  390. settings.finalise(report_err, srv_envmap);
  391. auto service_type = settings.service_type;
  392. if (reload_svc != nullptr) {
  393. // Make sure settings are able to be changed/are compatible
  394. service_record *service = reload_svc;
  395. if (service->get_state() != service_state_t::STOPPED) {
  396. // Can not change type of a running service.
  397. if (service_type != service->get_type()) {
  398. throw service_load_exc(name, "cannot change type of non-stopped service.");
  399. }
  400. // Can not alter a starting/stopping service, at least for now.
  401. if (service->get_state() != service_state_t::STARTED) {
  402. throw service_load_exc(name,
  403. "cannot alter settings for service which is currently starting/stopping.");
  404. }
  405. // Check validity of dependencies (if started, regular deps must be started)
  406. for (auto &new_dep : settings.depends) {
  407. if (new_dep.dep_type == dependency_type::REGULAR) {
  408. if (new_dep.to->get_state() != service_state_t::STARTED) {
  409. throw service_load_exc(name,
  410. std::string("cannot add non-started dependency '")
  411. + new_dep.to->get_name() + "'.");
  412. }
  413. }
  414. }
  415. // Cannot change certain flags
  416. auto current_flags = service->get_flags();
  417. if (current_flags.starts_on_console != settings.onstart_flags.starts_on_console
  418. || current_flags.shares_console != settings.onstart_flags.shares_console) {
  419. throw service_load_exc(name, "cannot change starts_on_console/"
  420. "shares_console flags for a running service.");
  421. }
  422. // Cannot change pid file
  423. if (service->get_type() == service_type_t::BGPROCESS) {
  424. auto *bgp_service = static_cast<bgproc_service *>(service);
  425. if (bgp_service->get_pid_file() != settings.pid_file) {
  426. throw service_load_exc(name, "cannot change pid_file for running service.");
  427. }
  428. }
  429. // Cannot change inittab_id/inittab_line
  430. #if USE_UTMPX
  431. if (service->get_type() == service_type_t::PROCESS) {
  432. auto *proc_service = static_cast<process_service *>(service);
  433. auto *svc_utmp_id = proc_service->get_utmp_id();
  434. auto *svc_utmp_ln = proc_service->get_utmp_line();
  435. if (strncmp(svc_utmp_id, settings.inittab_id, proc_service->get_utmp_id_size()) != 0
  436. || strncmp(svc_utmp_ln, settings.inittab_line,
  437. proc_service->get_utmp_line_size()) != 0) {
  438. throw service_load_exc(name, "cannot change inittab-id or inittab-line "
  439. "settings for running service.");
  440. }
  441. }
  442. #endif
  443. // Cannot change log type
  444. if (value(service->get_type()).is_in(service_type_t::PROCESS, service_type_t::BGPROCESS,
  445. service_type_t::SCRIPTED)) {
  446. base_process_service *bps = static_cast<base_process_service *>(service);
  447. if (bps->get_log_mode() != settings.log_type) {
  448. throw service_load_exc(name, "cannot change log-type for running service.");
  449. }
  450. }
  451. // Already started; we must replace settings on existing service record
  452. create_new_record = false;
  453. }
  454. else if (service_type == service->get_type()) {
  455. // No need to create a new record if the type hasn't changed
  456. create_new_record = false;
  457. }
  458. }
  459. // Note, we need to be very careful to handle exceptions properly and roll back any changes that
  460. // we've made before the exception occurred.
  461. // If we have "after" constraints, load them now and treat them as regular dependencies. We need
  462. // to do this now, after the other dependents are loaded, because we might create a placeholder
  463. // instead (and we don't want to create a placeholder, have it added to the list of dependencies,
  464. // then load the same service as a real dependency shortly afterwards, which would replace the
  465. // placeholder but leave a dangling pointer to it in the list).
  466. for (const std::string &after_ent : settings.after_svcs) {
  467. service_record *after_svc;
  468. if (after_ent == name) throw service_cyclic_dependency(name);
  469. after_svc = find_service(after_ent.c_str(), true);
  470. if (after_svc != nullptr) {
  471. if (after_svc->check_is_loading()) {
  472. throw service_cyclic_dependency(name);
  473. }
  474. }
  475. if (after_svc == nullptr) {
  476. after_svc = new service_record(this, after_ent);
  477. try {
  478. add_service(after_svc);
  479. }
  480. catch (...) {
  481. delete after_svc;
  482. throw;
  483. }
  484. }
  485. try {
  486. settings.depends.emplace_back(after_svc, dependency_type::AFTER);
  487. }
  488. catch (...) {
  489. if (after_svc->is_unrefd()) {
  490. remove_service(after_svc);
  491. delete after_svc;
  492. throw;
  493. }
  494. }
  495. }
  496. // if we have "before" constraints, check them now.
  497. for (const std::string &before_ent : settings.before_svcs) {
  498. service_record *before_svc;
  499. if (before_ent == name)
  500. throw service_cyclic_dependency(name);
  501. before_svc = find_service(before_ent.c_str(), true);
  502. if (before_svc != nullptr) {
  503. check_cycle(settings.depends, before_svc, name);
  504. }
  505. else {
  506. bool before_svc_added = false;
  507. try {
  508. before_svc = new service_record(this, before_ent);
  509. add_service(before_svc);
  510. before_svc_added = true;
  511. }
  512. catch (...) {
  513. if (before_svc_added) remove_service(before_svc);
  514. delete before_svc;
  515. throw;
  516. }
  517. before_deps.emplace_back(before_svc, reload_svc, dependency_type::BEFORE);
  518. // (note, we may need to adjust the to-service if we create a new service record object)
  519. }
  520. }
  521. if (service_type == service_type_t::PROCESS) {
  522. do_env_subst("command", settings.command, settings.command_offsets, srv_envmap);
  523. do_env_subst("stop-command", settings.stop_command, settings.stop_command_offsets, srv_envmap);
  524. std::vector<const char *> stop_arg_parts = separate_args(settings.stop_command, settings.stop_command_offsets);
  525. process_service *rvalps;
  526. if (create_new_record) {
  527. rvalps = new process_service(this, string(name), std::move(settings.command),
  528. settings.command_offsets, settings.depends);
  529. settings.depends.clear();
  530. if (reload_svc != nullptr) {
  531. check_cycle(settings.depends, reload_svc);
  532. }
  533. }
  534. else {
  535. rvalps = static_cast<process_service *>(reload_svc);
  536. update_command_and_dependencies(rvalps, settings, before_deps);
  537. }
  538. rval = rvalps;
  539. // All of the following should be noexcept or must perform rollback on exception
  540. rvalps->set_stop_command(std::move(settings.stop_command), std::move(stop_arg_parts));
  541. rvalps->set_working_dir(std::move(settings.working_dir));
  542. rvalps->set_env_file(std::move(settings.env_file));
  543. #if SUPPORT_CGROUPS
  544. rvalps->set_cgroup(std::move(settings.run_in_cgroup));
  545. #endif
  546. rvalps->set_rlimits(std::move(settings.rlimits));
  547. rvalps->set_restart_interval(settings.restart_interval, settings.max_restarts);
  548. rvalps->set_restart_delay(settings.restart_delay);
  549. rvalps->set_stop_timeout(settings.stop_timeout);
  550. rvalps->set_start_timeout(settings.start_timeout);
  551. rvalps->set_extra_termination_signal(settings.term_signal);
  552. rvalps->set_run_as_uid_gid(settings.run_as_uid, settings.run_as_gid);
  553. rvalps->set_notification_fd(settings.readiness_fd);
  554. rvalps->set_notification_var(std::move(settings.readiness_var));
  555. rvalps->set_log_file(std::move(settings.logfile));
  556. rvalps->set_log_buf_max(settings.max_log_buffer_sz);
  557. rvalps->set_log_mode(settings.log_type);
  558. #if USE_UTMPX
  559. rvalps->set_utmp_id(settings.inittab_id);
  560. rvalps->set_utmp_line(settings.inittab_line);
  561. #endif
  562. }
  563. else if (service_type == service_type_t::BGPROCESS) {
  564. do_env_subst("command", settings.command, settings.command_offsets, srv_envmap);
  565. do_env_subst("stop-command", settings.stop_command, settings.stop_command_offsets, srv_envmap);
  566. std::vector<const char *> stop_arg_parts = separate_args(settings.stop_command, settings.stop_command_offsets);
  567. bgproc_service *rvalps;
  568. if (create_new_record) {
  569. rvalps = new bgproc_service(this, string(name), std::move(settings.command),
  570. settings.command_offsets, settings.depends);
  571. settings.depends.clear();
  572. if (reload_svc != nullptr) {
  573. check_cycle(settings.depends, reload_svc);
  574. }
  575. }
  576. else {
  577. rvalps = static_cast<bgproc_service *>(reload_svc);
  578. update_command_and_dependencies(rvalps, settings, before_deps);
  579. }
  580. rval = rvalps;
  581. // All of the following should be noexcept or must perform rollback on exception
  582. rvalps->set_stop_command(std::move(settings.stop_command), std::move(stop_arg_parts));
  583. rvalps->set_working_dir(std::move(settings.working_dir));
  584. rvalps->set_env_file(std::move(settings.env_file));
  585. #if SUPPORT_CGROUPS
  586. rvalps->set_cgroup(std::move(settings.run_in_cgroup));
  587. #endif
  588. rvalps->set_rlimits(std::move(settings.rlimits));
  589. rvalps->set_pid_file(std::move(settings.pid_file));
  590. rvalps->set_restart_interval(settings.restart_interval, settings.max_restarts);
  591. rvalps->set_restart_delay(settings.restart_delay);
  592. rvalps->set_stop_timeout(settings.stop_timeout);
  593. rvalps->set_start_timeout(settings.start_timeout);
  594. rvalps->set_extra_termination_signal(settings.term_signal);
  595. rvalps->set_run_as_uid_gid(settings.run_as_uid, settings.run_as_gid);
  596. rvalps->set_log_file(std::move(settings.logfile));
  597. rvalps->set_log_buf_max(settings.max_log_buffer_sz);
  598. rvalps->set_log_mode(settings.log_type);
  599. settings.onstart_flags.runs_on_console = false;
  600. }
  601. else if (service_type == service_type_t::SCRIPTED) {
  602. do_env_subst("command", settings.command, settings.command_offsets, srv_envmap);
  603. do_env_subst("stop-command", settings.stop_command, settings.stop_command_offsets, srv_envmap);
  604. std::vector<const char *> stop_arg_parts = separate_args(settings.stop_command, settings.stop_command_offsets);
  605. scripted_service *rvalps;
  606. if (create_new_record) {
  607. rvalps = new scripted_service(this, string(name), std::move(settings.command),
  608. settings.command_offsets, settings.depends);
  609. settings.depends.clear();
  610. if (reload_svc != nullptr) {
  611. check_cycle(settings.depends, reload_svc);
  612. }
  613. }
  614. else {
  615. rvalps = static_cast<scripted_service *>(reload_svc);
  616. update_command_and_dependencies(rvalps, settings, before_deps);
  617. }
  618. rval = rvalps;
  619. // All of the following should be noexcept or must perform rollback on exception
  620. rvalps->set_stop_command(std::move(settings.stop_command), std::move(stop_arg_parts));
  621. rvalps->set_working_dir(std::move(settings.working_dir));
  622. rvalps->set_env_file(std::move(settings.env_file));
  623. #if SUPPORT_CGROUPS
  624. rvalps->set_cgroup(std::move(settings.run_in_cgroup));
  625. #endif
  626. rvalps->set_rlimits(std::move(settings.rlimits));
  627. rvalps->set_stop_timeout(settings.stop_timeout);
  628. rvalps->set_start_timeout(settings.start_timeout);
  629. rvalps->set_extra_termination_signal(settings.term_signal);
  630. rvalps->set_run_as_uid_gid(settings.run_as_uid, settings.run_as_gid);
  631. rvalps->set_log_file(std::move(settings.logfile));
  632. rvalps->set_log_buf_max(settings.max_log_buffer_sz);
  633. rvalps->set_log_mode(settings.log_type);
  634. }
  635. else {
  636. if (create_new_record) {
  637. if (service_type == service_type_t::INTERNAL) {
  638. rval = new service_record(this, string(name), service_type, settings.depends);
  639. }
  640. else {
  641. /* TRIGGERED */
  642. rval = new triggered_service(this, string(name), service_type, settings.depends);
  643. }
  644. settings.depends.clear();
  645. if (reload_svc != nullptr) {
  646. check_cycle(settings.depends, reload_svc);
  647. }
  648. }
  649. else {
  650. rval = reload_svc;
  651. update_depenencies(rval, settings, before_deps);
  652. }
  653. }
  654. rval->set_auto_restart(settings.auto_restart);
  655. rval->set_smooth_recovery(settings.smooth_recovery);
  656. rval->set_flags(settings.onstart_flags);
  657. rval->set_socket_details(std::move(settings.socket_path), settings.socket_perms,
  658. settings.socket_uid, settings.socket_gid);
  659. rval->set_chain_to(std::move(settings.chain_to_name));
  660. rval->set_environment(std::move(srv_env));
  661. if (create_new_record) {
  662. // switch dependencies on old record so that they refer to the new record
  663. // first link in all the (new) "before" dependents (one way at this stage):
  664. auto &dept_list = rval->get_dependents();
  665. unsigned added_dependents = 0;
  666. try {
  667. for (auto &dept : before_deps) {
  668. dept_list.push_back(&dept);
  669. ++added_dependents;
  670. }
  671. }
  672. catch (...) {
  673. // Undo, since the invalid state will cause issues when the new service is disposed of
  674. while (added_dependents > 0) {
  675. dept_list.pop_back();
  676. --added_dependents;
  677. }
  678. throw;
  679. }
  680. // --- Point of no return: mustn't fail from here ---
  681. // Splice in the new "before" dependencies
  682. auto i = before_deps.begin();
  683. decltype(i) j;
  684. while (i != before_deps.end()) {
  685. j = std::next(i);
  686. i->set_to(rval);
  687. auto &from_deps = i->get_from()->get_dependencies();
  688. from_deps.splice(from_deps.end(), before_deps, i);
  689. i = j;
  690. }
  691. if (reload_svc != nullptr) {
  692. // Complete dependency/dependent transfers.
  693. // Remove all "before" dependents from the original service (these were created by the
  694. // original service itself)
  695. auto &reload_depts = reload_svc->get_dependents();
  696. for (auto i = reload_depts.begin(); i != reload_depts.end(); ) {
  697. auto next_i = std::next(i);
  698. if ((*i)->dep_type == dependency_type::BEFORE) {
  699. service_record *before_svc = (*i)->get_from();
  700. before_svc->rm_dep(**i);
  701. if (before_svc->get_type() == service_type_t::PLACEHOLDER && before_svc->is_unrefd()) {
  702. remove_service(before_svc);
  703. delete before_svc;
  704. }
  705. }
  706. i = next_i;
  707. }
  708. // Transfer dependents from the original service record to the new record;
  709. // set links in all dependents on the original to point to the new service:
  710. auto first_new_before = dept_list.begin();
  711. dept_list.splice(first_new_before, reload_depts);
  712. for (auto &dept : dept_list) {
  713. dept->set_to(rval);
  714. }
  715. // Transfer all "before" dependencies (which are actually created by other services) to the
  716. // new service
  717. auto &dep_list_prev = reload_svc->get_dependencies();
  718. auto &dep_list = rval->get_dependencies();
  719. for (auto i = dep_list_prev.begin(); i != dep_list_prev.end(); ++i) {
  720. if (i->dep_type == dependency_type::BEFORE) {
  721. i->set_from(rval);
  722. dep_list.splice(dep_list.end(), dep_list_prev, i++);
  723. continue;
  724. }
  725. }
  726. // Remove dependent-link for all dependencies from the original:
  727. reload_svc->prepare_for_unload();
  728. }
  729. // Finally, replace the old service with the new one:
  730. service_record *old_service = (reload_svc != nullptr) ? reload_svc : dummy;
  731. auto iter = std::find(records.begin(), records.end(), old_service);
  732. *iter = rval;
  733. delete old_service;
  734. }
  735. return rval;
  736. }
  737. catch (service_description_exc &setting_exc)
  738. {
  739. exception_cleanup();
  740. if (setting_exc.service_name.empty()) {
  741. setting_exc.service_name = name;
  742. }
  743. throw;
  744. }
  745. catch (std::system_error &sys_err)
  746. {
  747. exception_cleanup();
  748. throw service_load_exc(name, sys_err.what());
  749. }
  750. catch (...) // (should only be std::bad_alloc or service_load_exc)
  751. {
  752. exception_cleanup();
  753. throw;
  754. }
  755. }