load-service.cc 42 KB

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