dinitctl.cc 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843
  1. #include <cstdio>
  2. #include <cstddef>
  3. #include <cstring>
  4. #include <string>
  5. #include <iostream>
  6. #include <fstream>
  7. #include <system_error>
  8. #include <memory>
  9. #include <algorithm>
  10. #include <sys/types.h>
  11. #include <sys/stat.h>
  12. #include <sys/wait.h>
  13. #include <sys/socket.h>
  14. #include <sys/un.h>
  15. #include <unistd.h>
  16. #include <signal.h>
  17. #include <pwd.h>
  18. #include "control-cmds.h"
  19. #include "service-constants.h"
  20. #include "cpbuffer.h"
  21. #include "dinit-client.h"
  22. #include "load-service.h"
  23. #include "dinit-util.h"
  24. #include "mconfig.h"
  25. // dinitctl: utility to control the Dinit daemon, including starting and stopping of services.
  26. // This utility communicates with the dinit daemon via a unix stream socket (as specified in
  27. // SYSCONTROLSOCKET, or $HOME/.dinitctl).
  28. static constexpr uint16_t min_cp_version = 1;
  29. static constexpr uint16_t max_cp_version = 1;
  30. enum class command_t;
  31. static int issue_load_service(int socknum, const char *service_name, bool find_only = false);
  32. static int check_load_reply(int socknum, cpbuffer_t &, handle_t *handle_p, service_state_t *state_p,
  33. bool write_error=true);
  34. static int start_stop_service(int socknum, cpbuffer_t &, const char *service_name, command_t command,
  35. bool do_pin, bool do_force, bool wait_for_service, bool ignore_unstarted, bool verbose);
  36. static int unpin_service(int socknum, cpbuffer_t &, const char *service_name, bool verbose);
  37. static int unload_service(int socknum, cpbuffer_t &, const char *service_name, bool verbose);
  38. static int reload_service(int socknum, cpbuffer_t &, const char *service_name, bool verbose);
  39. static int list_services(int socknum, cpbuffer_t &);
  40. static int service_status(int socknum, cpbuffer_t &rbuffer, const char *service_name, command_t command, bool verbose);
  41. static int shutdown_dinit(int soclknum, cpbuffer_t &, bool verbose);
  42. static int add_remove_dependency(int socknum, cpbuffer_t &rbuffer, bool add, const char *service_from,
  43. const char *service_to, dependency_type dep_type, bool verbose);
  44. static int enable_disable_service(int socknum, cpbuffer_t &rbuffer, const char *from, const char *to,
  45. bool enable, bool verbose);
  46. static int do_setenv(int socknum, cpbuffer_t &rbuffer, std::vector<const char *> &env_names);
  47. static int trigger_service(int socknum, cpbuffer_t &rbuffer, const char *service_name, bool trigger_value);
  48. static int cat_service_log(int socknum, cpbuffer_t &rbuffer, const char *service_name);
  49. static const char * describeState(bool stopped)
  50. {
  51. return stopped ? "stopped" : "started";
  52. }
  53. static const char * describeVerb(bool stop)
  54. {
  55. return stop ? "stop" : "start";
  56. }
  57. enum class command_t {
  58. NONE,
  59. START_SERVICE,
  60. WAKE_SERVICE,
  61. STOP_SERVICE,
  62. RESTART_SERVICE,
  63. RELEASE_SERVICE,
  64. UNPIN_SERVICE,
  65. UNLOAD_SERVICE,
  66. RELOAD_SERVICE,
  67. LIST_SERVICES,
  68. SERVICE_STATUS,
  69. SHUTDOWN,
  70. ADD_DEPENDENCY,
  71. RM_DEPENDENCY,
  72. ENABLE_SERVICE,
  73. DISABLE_SERVICE,
  74. SETENV,
  75. SET_TRIGGER,
  76. UNSET_TRIGGER,
  77. CAT_LOG,
  78. IS_ACTIVE,
  79. IS_FAILED,
  80. };
  81. class dinit_protocol_error
  82. {
  83. // no body
  84. };
  85. // Entry point.
  86. int dinitctl_main(int argc, char **argv)
  87. {
  88. using namespace std;
  89. bool show_help = argc < 2;
  90. const char *service_name = nullptr;
  91. const char *to_service_name = nullptr;
  92. dependency_type dep_type = dependency_type::AFTER; // avoid maybe-uninitialised warning
  93. bool dep_type_set = false;
  94. std::string control_socket_str;
  95. const char * control_socket_path = nullptr;
  96. bool verbose = true;
  97. bool user_dinit = (getuid() != 0); // communicate with user daemon
  98. bool wait_for_service = true;
  99. bool do_pin = false;
  100. bool do_force = false;
  101. bool ignore_unstarted = false;
  102. bool use_passed_cfd = false;
  103. command_t command = command_t::NONE;
  104. std::vector<const char *> cmd_args;
  105. for (int i = 1; i < argc; i++) {
  106. if (argv[i][0] == '-') {
  107. if (strcmp(argv[i], "--help") == 0) {
  108. show_help = true;
  109. break;
  110. }
  111. else if (strcmp(argv[i], "--version") == 0) {
  112. cout << "Dinit version " << DINIT_VERSION << ".\n";
  113. return 0;
  114. }
  115. else if (strcmp(argv[i], "--no-wait") == 0) {
  116. wait_for_service = false;
  117. }
  118. else if (strcmp(argv[i], "--ignore-unstarted") == 0) {
  119. ignore_unstarted = true;
  120. }
  121. else if (strcmp(argv[i], "--quiet") == 0) {
  122. verbose = false;
  123. }
  124. else if (strcmp(argv[i], "--system") == 0 || strcmp(argv[i], "-s") == 0) {
  125. user_dinit = false;
  126. }
  127. else if (strcmp(argv[i], "--user") == 0 || strcmp(argv[i], "-u") == 0) {
  128. user_dinit = true;
  129. }
  130. else if (strcmp(argv[i], "--pin") == 0) {
  131. do_pin = true;
  132. }
  133. else if (strcmp(argv[i], "--socket-path") == 0 || strcmp(argv[i], "-p") == 0) {
  134. ++i;
  135. if (i == argc) {
  136. cerr << "dinitctl: --socket-path/-p should be followed by socket path" << std::endl;
  137. return 1;
  138. }
  139. control_socket_str = argv[i];
  140. }
  141. else if (strcmp(argv[i], "--use-passed-cfd") == 0) {
  142. use_passed_cfd = true;
  143. }
  144. else if ((command == command_t::ENABLE_SERVICE || command == command_t::DISABLE_SERVICE)
  145. && strcmp(argv[i], "--from") == 0) {
  146. ++i;
  147. if (i == argc) {
  148. cerr << "dinitctl: --from should be followed by a service name" << std::endl;
  149. return 1;
  150. }
  151. service_name = argv[i];
  152. }
  153. else if ((command == command_t::STOP_SERVICE || command == command_t::RESTART_SERVICE)
  154. && (strcmp(argv[i], "--force") == 0 || strcmp(argv[i], "-f") == 0)) {
  155. do_force = true;
  156. }
  157. else {
  158. cerr << "dinitctl: unrecognized/invalid option: " << argv[i] << " (use --help for help)\n";
  159. return 1;
  160. }
  161. }
  162. else if (command == command_t::NONE) {
  163. if (strcmp(argv[i], "start") == 0) {
  164. command = command_t::START_SERVICE;
  165. }
  166. else if (strcmp(argv[i], "wake") == 0) {
  167. command = command_t::WAKE_SERVICE;
  168. }
  169. else if (strcmp(argv[i], "stop") == 0) {
  170. command = command_t::STOP_SERVICE;
  171. }
  172. else if (strcmp(argv[i], "restart") == 0) {
  173. command = command_t::RESTART_SERVICE;
  174. }
  175. else if (strcmp(argv[i], "release") == 0) {
  176. command = command_t::RELEASE_SERVICE;
  177. }
  178. else if (strcmp(argv[i], "unpin") == 0) {
  179. command = command_t::UNPIN_SERVICE;
  180. }
  181. else if (strcmp(argv[i], "unload") == 0) {
  182. command = command_t::UNLOAD_SERVICE;
  183. }
  184. else if (strcmp(argv[i], "reload") == 0) {
  185. command = command_t::RELOAD_SERVICE;
  186. }
  187. else if (strcmp(argv[i], "list") == 0) {
  188. command = command_t::LIST_SERVICES;
  189. }
  190. else if (strcmp(argv[i], "status") == 0) {
  191. command = command_t::SERVICE_STATUS;
  192. }
  193. else if (strcmp(argv[i], "is-active") == 0) {
  194. command = command_t::IS_ACTIVE;
  195. }
  196. else if (strcmp(argv[i], "is-failed") == 0) {
  197. command = command_t::IS_FAILED;
  198. }
  199. else if (strcmp(argv[i], "shutdown") == 0) {
  200. command = command_t::SHUTDOWN;
  201. }
  202. else if (strcmp(argv[i], "add-dep") == 0) {
  203. command = command_t::ADD_DEPENDENCY;
  204. }
  205. else if (strcmp(argv[i], "rm-dep") == 0) {
  206. command = command_t::RM_DEPENDENCY;
  207. }
  208. else if (strcmp(argv[i], "enable") == 0) {
  209. command = command_t::ENABLE_SERVICE;
  210. }
  211. else if (strcmp(argv[i], "disable") == 0) {
  212. command = command_t::DISABLE_SERVICE;
  213. }
  214. else if (strcmp(argv[i], "setenv") == 0) {
  215. command = command_t::SETENV;
  216. }
  217. else if (strcmp(argv[i], "trigger") == 0) {
  218. command = command_t::SET_TRIGGER;
  219. }
  220. else if (strcmp(argv[i], "untrigger") == 0) {
  221. command = command_t::UNSET_TRIGGER;
  222. }
  223. else if (strcmp(argv[i], "catlog") == 0) {
  224. command = command_t::CAT_LOG;
  225. }
  226. else {
  227. cerr << "dinitctl: unrecognized command: " << argv[i] << " (use --help for help)\n";
  228. return 1;
  229. }
  230. }
  231. else {
  232. // service name / other non-option
  233. if (command == command_t::ADD_DEPENDENCY || command == command_t::RM_DEPENDENCY) {
  234. if (! dep_type_set) {
  235. if (strcmp(argv[i], "regular") == 0) {
  236. dep_type = dependency_type::REGULAR;
  237. }
  238. else if (strcmp(argv[i], "milestone") == 0) {
  239. dep_type = dependency_type::MILESTONE;
  240. }
  241. else if (strcmp(argv[i], "waits-for") == 0) {
  242. dep_type = dependency_type::WAITS_FOR;
  243. }
  244. else {
  245. show_help = true;
  246. break;
  247. }
  248. dep_type_set = true;
  249. }
  250. else if (service_name == nullptr) {
  251. service_name = argv[i];
  252. }
  253. else if (to_service_name == nullptr) {
  254. to_service_name = argv[i];
  255. }
  256. else {
  257. show_help = true;
  258. break;
  259. }
  260. }
  261. else if (command == command_t::ENABLE_SERVICE || command == command_t::DISABLE_SERVICE) {
  262. if (to_service_name != nullptr) {
  263. show_help = true;
  264. break;
  265. }
  266. to_service_name = argv[i];
  267. }
  268. else {
  269. cmd_args.push_back(argv[i]);
  270. }
  271. }
  272. }
  273. // Additional argument checks for various commands:
  274. if (command == command_t::NONE) {
  275. show_help = true;
  276. }
  277. else if (command == command_t::ENABLE_SERVICE || command == command_t::DISABLE_SERVICE) {
  278. show_help |= (to_service_name == nullptr);
  279. }
  280. else if (command == command_t::SETENV) {
  281. // Handle SETENV specially, since it needs arguments but they are not service names
  282. if (cmd_args.empty()) {
  283. show_help = true;
  284. }
  285. }
  286. else {
  287. bool no_service_cmd = (command == command_t::LIST_SERVICES || command == command_t::SHUTDOWN);
  288. if (no_service_cmd) {
  289. if (!cmd_args.empty()) {
  290. show_help = true;
  291. }
  292. }
  293. else {
  294. if (command == command_t::ADD_DEPENDENCY || command == command_t::RM_DEPENDENCY) {
  295. if (! dep_type_set || service_name == nullptr || to_service_name == nullptr) {
  296. show_help = true;
  297. }
  298. }
  299. else if (cmd_args.empty()) {
  300. show_help = true;
  301. }
  302. else {
  303. // No command can currently accept more than one service argument:
  304. if (cmd_args.size() > 1) {
  305. show_help = true;
  306. }
  307. service_name = cmd_args.front();
  308. }
  309. }
  310. }
  311. if (show_help) {
  312. cout << "dinitctl: control Dinit services\n"
  313. "\n"
  314. "Usage:\n"
  315. " dinitctl [options] status <service-name>\n"
  316. " dinitctl [options] is-active <service-name>\n"
  317. " dinitctl [options] is-failed <service-name>\n"
  318. " dinitctl [options] start [options] <service-name>\n"
  319. " dinitctl [options] stop [options] <service-name>\n"
  320. " dinitctl [options] restart [options] <service-name>\n"
  321. " dinitctl [options] wake [options] <service-name>\n"
  322. " dinitctl [options] release [options] <service-name>\n"
  323. " dinitctl [options] unpin <service-name>\n"
  324. " dinitctl [options] unload <service-name>\n"
  325. " dinitctl [options] reload <service-name>\n"
  326. " dinitctl [options] list\n"
  327. " dinitctl [options] shutdown\n"
  328. " dinitctl [options] add-dep <type> <from-service> <to-service>\n"
  329. " dinitctl [options] rm-dep <type> <from-service> <to-service>\n"
  330. " dinitctl [options] enable [--from <from-service>] <to-service>\n"
  331. " dinitctl [options] disable [--from <from-service>] <to-service>\n"
  332. " dinitctl [options] trigger <service-name>\n"
  333. " dinitctl [options] untrigger <service-name>\n"
  334. " dinitctl [options] setenv [name[=value] ...]\n"
  335. " dinitctl [options] catlog <service-name>\n"
  336. "\n"
  337. "Note: An activated service continues running when its dependents stop.\n"
  338. "\n"
  339. "General options:\n"
  340. " --help : show this help\n"
  341. " -s, --system : control system daemon (default if run as root)\n"
  342. " -u, --user : control user daemon\n"
  343. " --quiet : suppress output (except errors)\n"
  344. " --socket-path <path>, -p <path>\n"
  345. " : specify socket for communication with daemon\n"
  346. " --use-passed-cfd : use the socket file descriptor identified by the DINIT_CS_FD\n"
  347. " environment variable to communicate with the dinit daemon.\n"
  348. "\n"
  349. "Command options:\n"
  350. " --no-wait : don't wait for service startup/shutdown to complete\n"
  351. " --pin : pin the service in the requested state\n"
  352. " --force : force stop even if dependents will be affected\n";
  353. return 1;
  354. }
  355. // Begin the real work: connect to dinit
  356. signal(SIGPIPE, SIG_IGN);
  357. int socknum = -1;
  358. if (use_passed_cfd) {
  359. socknum = get_passed_cfd();
  360. if (socknum == -1) {
  361. use_passed_cfd = false;
  362. }
  363. }
  364. if (!use_passed_cfd) {
  365. // Locate control socket
  366. if (!control_socket_str.empty()) {
  367. control_socket_path = control_socket_str.c_str();
  368. }
  369. else {
  370. control_socket_path = get_default_socket_path(control_socket_str, user_dinit);
  371. if (control_socket_path == nullptr) {
  372. cerr << "dinitctl: cannot locate user home directory (set XDG_RUNTIME_DIR, HOME, check /etc/passwd file, or "
  373. "specify socket path via -p)" << endl;
  374. return 1;
  375. }
  376. }
  377. }
  378. try {
  379. if (!use_passed_cfd) {
  380. socknum = connect_to_daemon(control_socket_path);
  381. }
  382. // Start by querying protocol version:
  383. cpbuffer_t rbuffer;
  384. uint16_t daemon_protocol_ver = check_protocol_version(min_cp_version, max_cp_version, rbuffer, socknum);
  385. if (command == command_t::UNPIN_SERVICE) {
  386. return unpin_service(socknum, rbuffer, service_name, verbose);
  387. }
  388. else if (command == command_t::UNLOAD_SERVICE) {
  389. return unload_service(socknum, rbuffer, service_name, verbose);
  390. }
  391. else if (command == command_t::RELOAD_SERVICE) {
  392. return reload_service(socknum, rbuffer, service_name, verbose);
  393. }
  394. else if (command == command_t::LIST_SERVICES) {
  395. return list_services(socknum, rbuffer);
  396. }
  397. else if (command == command_t::SERVICE_STATUS || command == command_t::IS_ACTIVE || command == command_t::IS_FAILED) {
  398. return service_status(socknum, rbuffer, service_name, command, verbose);
  399. }
  400. else if (command == command_t::SHUTDOWN) {
  401. return shutdown_dinit(socknum, rbuffer, verbose);
  402. }
  403. else if (command == command_t::ADD_DEPENDENCY || command == command_t::RM_DEPENDENCY) {
  404. return add_remove_dependency(socknum, rbuffer, command == command_t::ADD_DEPENDENCY,
  405. service_name, to_service_name, dep_type, verbose);
  406. }
  407. else if (command == command_t::ENABLE_SERVICE || command == command_t::DISABLE_SERVICE) {
  408. // If only one service specified, assume that we enable for 'boot' service:
  409. if (service_name == nullptr) {
  410. service_name = "boot";
  411. }
  412. return enable_disable_service(socknum, rbuffer, service_name, to_service_name,
  413. command == command_t::ENABLE_SERVICE, verbose);
  414. }
  415. else if (command == command_t::SETENV) {
  416. return do_setenv(socknum, rbuffer, cmd_args);
  417. }
  418. else if (command == command_t::SET_TRIGGER || command == command_t::UNSET_TRIGGER) {
  419. if (daemon_protocol_ver < 2) {
  420. throw cp_old_server_exception();
  421. }
  422. return trigger_service(socknum, rbuffer, service_name, (command == command_t::SET_TRIGGER));
  423. }
  424. else if (command == command_t::CAT_LOG) {
  425. if (daemon_protocol_ver < 2) {
  426. throw cp_old_server_exception();
  427. }
  428. return cat_service_log(socknum, rbuffer, service_name);
  429. }
  430. else {
  431. return start_stop_service(socknum, rbuffer, service_name, command, do_pin, do_force,
  432. wait_for_service, ignore_unstarted, verbose);
  433. }
  434. }
  435. catch (cp_old_client_exception &e) {
  436. std::cerr << "dinitctl: too old (server reports newer protocol version)" << std::endl;
  437. }
  438. catch (cp_old_server_exception &e) {
  439. std::cerr << "dinitctl: server too old or protocol error" << std::endl;
  440. }
  441. catch (cp_read_exception &e) {
  442. cerr << "dinitctl: control socket read failure or protocol error" << endl;
  443. }
  444. catch (cp_write_exception &e) {
  445. cerr << "dinitctl: control socket write error: " << std::strerror(e.errcode) << endl;
  446. }
  447. catch (dinit_protocol_error &e) {
  448. cerr << "dinitctl: protocol error" << endl;
  449. }
  450. catch (general_error &ge) {
  451. std::cerr << "dinit-client";
  452. if (ge.get_action() != nullptr) {
  453. std::cerr << ": " << ge.get_action();
  454. std::string &arg = ge.get_arg();
  455. if (!arg.empty()) {
  456. std::cerr << " " << arg;
  457. }
  458. }
  459. if (ge.get_err() != 0) {
  460. std::cerr << ": " << strerror(ge.get_err());
  461. }
  462. std::cerr << '\n';
  463. }
  464. return 1;
  465. }
  466. int main(int argc, char **argv)
  467. {
  468. try {
  469. return dinitctl_main(argc, argv);
  470. }
  471. catch (std::bad_alloc &e) {
  472. std::cerr << "dinitctl: out of memory\n";
  473. }
  474. return 1;
  475. }
  476. // Size of service status info (in various packets)
  477. constexpr static unsigned STATUS_BUFFER_SIZE = 6 + ((sizeof(pid_t) > sizeof(int)) ? sizeof(pid_t) : sizeof(int));
  478. // Extract/read a string of specified length from the buffer/socket. The string is consumed
  479. // from the buffer.
  480. static std::string read_string(int socknum, cpbuffer_t &rbuffer, uint32_t length)
  481. {
  482. int rb_len = rbuffer.get_length();
  483. if (uint32_t(rb_len) >= length) {
  484. std::string r = rbuffer.extract_string(0, length);
  485. rbuffer.consume(length);
  486. return r;
  487. }
  488. std::string r = rbuffer.extract_string(0, rb_len);
  489. uint32_t rlen = length - rb_len;
  490. uint32_t clen;
  491. do {
  492. rbuffer.reset();
  493. fill_some(rbuffer, socknum);
  494. char *bptr = rbuffer.get_ptr(0);
  495. clen = rbuffer.get_length();
  496. clen = std::min(clen, rlen);
  497. r.append(bptr, clen);
  498. rlen -= clen;
  499. } while (rlen > 0);
  500. rbuffer.consume(clen);
  501. return r;
  502. }
  503. // Load a service: issue load command, wait for reply. Return true on success, display error message
  504. // and return false on failure.
  505. // socknum - the socket fd to communicate via
  506. // rbuffer - the buffer for communication
  507. // name - the name of the service to load
  508. // handle - where to store the handle of the loaded service
  509. // state - where to store the state of the loaded service (may be null).
  510. // write_error - whether to write an error message if the service can't be loaded
  511. static bool load_service(int socknum, cpbuffer_t &rbuffer, const char *name, handle_t *handle,
  512. service_state_t *state, bool write_error=true)
  513. {
  514. // Load 'to' service:
  515. if (issue_load_service(socknum, name)) {
  516. return false;
  517. }
  518. wait_for_reply(rbuffer, socknum);
  519. if (check_load_reply(socknum, rbuffer, handle, state, write_error) != 0) {
  520. return false;
  521. }
  522. return true;
  523. }
  524. // Get the service name for a given handle, by querying the daemon.
  525. static std::string get_service_name(int socknum, cpbuffer_t &rbuffer, handle_t handle)
  526. {
  527. auto m = membuf()
  528. .append((char) DINIT_CP_QUERYSERVICENAME)
  529. .append((char) 0)
  530. .append(handle);
  531. write_all_x(socknum, m);
  532. wait_for_reply(rbuffer, socknum);
  533. if (rbuffer[0] != DINIT_RP_SERVICENAME) {
  534. throw cp_read_exception{0};
  535. }
  536. // 1 byte reserved
  537. // uint16_t size
  538. fill_buffer_to(rbuffer, socknum, 2 + sizeof(uint16_t));
  539. uint16_t namesize;
  540. rbuffer.extract(&namesize, 2, sizeof(uint16_t));
  541. rbuffer.consume(2 + sizeof(uint16_t));
  542. std::string name;
  543. do {
  544. if (rbuffer.get_length() == 0) {
  545. fill_some(rbuffer, socknum);
  546. }
  547. size_t to_extract = std::min(size_t(rbuffer.get_length()), namesize - name.length());
  548. size_t contiguous_len = rbuffer.get_contiguous_length(rbuffer.get_ptr(0));
  549. if (contiguous_len <= to_extract) {
  550. name.append(rbuffer.get_ptr(0), contiguous_len);
  551. rbuffer.consume(contiguous_len);
  552. name.append(rbuffer.get_ptr(0), to_extract - contiguous_len);
  553. rbuffer.consume(to_extract - contiguous_len);
  554. }
  555. else {
  556. name.append(rbuffer.get_ptr(0), to_extract);
  557. rbuffer.consume(to_extract);
  558. break;
  559. }
  560. } while (name.length() < namesize);
  561. return name;
  562. }
  563. static void print_termination_details(int exit_status)
  564. {
  565. using namespace std;
  566. if (WIFSIGNALED(exit_status)) {
  567. cout << "signalled - signal ";
  568. cout << WTERMSIG(exit_status);
  569. }
  570. else if (WIFEXITED(exit_status)) {
  571. cout << "exited - status ";
  572. cout << WEXITSTATUS(exit_status);
  573. }
  574. else {
  575. cout << "unknown reason";
  576. }
  577. }
  578. // Wait for a service to reached stopped (do_stop == true) or started (do_stop == false) state.
  579. // Returns 0 if the service started/stopped, 1 if start/stop was cancelled or failed.
  580. static int wait_service_state(int socknum, cpbuffer_t &rbuffer, handle_t handle,
  581. const std::string &service_name, bool do_stop, bool verbose)
  582. {
  583. using std::cout;
  584. using std::cerr;
  585. using std::endl;
  586. service_event_t completionEvent;
  587. service_event_t cancelledEvent;
  588. if (do_stop) {
  589. completionEvent = service_event_t::STOPPED;
  590. cancelledEvent = service_event_t::STOPCANCELLED;
  591. }
  592. else {
  593. completionEvent = service_event_t::STARTED;
  594. cancelledEvent = service_event_t::STARTCANCELLED;
  595. }
  596. // Wait until service started:
  597. int r = rbuffer.fill_to(socknum, 2);
  598. while (r > 0) {
  599. if (rbuffer[0] >= 100) {
  600. unsigned pktlen = (unsigned char) rbuffer[1];
  601. fill_buffer_to(rbuffer, socknum, pktlen);
  602. if (rbuffer[0] == DINIT_IP_SERVICEEVENT) {
  603. // earlier versions do not include status info, the size in that case is base_pkt_size:
  604. constexpr unsigned base_pkt_size = 2 + sizeof(handle_t) + 1;
  605. if (pktlen < base_pkt_size) {
  606. throw dinit_protocol_error();
  607. }
  608. handle_t ev_handle;
  609. rbuffer.extract((char *) &ev_handle, 2, sizeof(ev_handle));
  610. service_event_t event = static_cast<service_event_t>(rbuffer[2 + sizeof(ev_handle)]);
  611. if (ev_handle == handle) {
  612. if (event == completionEvent) {
  613. if (verbose) {
  614. cout << "Service '" << service_name << "' " << describeState(do_stop) << ".\n";
  615. }
  616. return 0;
  617. }
  618. else if (event == cancelledEvent) {
  619. if (verbose) {
  620. cout << "Service '" << service_name << "' " << describeVerb(do_stop) << " cancelled.\n";
  621. }
  622. return 1;
  623. }
  624. else if (!do_stop && event == service_event_t::FAILEDSTART) {
  625. if (verbose) {
  626. cout << "Service '" << service_name << "' failed to start.\n";
  627. if (pktlen >= base_pkt_size + STATUS_BUFFER_SIZE) {
  628. stopped_reason_t stop_reason =
  629. static_cast<stopped_reason_t>(rbuffer[base_pkt_size + 3]);
  630. int exit_status;
  631. rbuffer.extract((char *)&exit_status, base_pkt_size + 6, sizeof(exit_status));
  632. switch (stop_reason) {
  633. case stopped_reason_t::DEPFAILED:
  634. cout << "Reason: a dependency of the service failed to start. Check dinit log.\n";
  635. break;
  636. case stopped_reason_t::TIMEDOUT:
  637. cout << "Reason: start timed out.\n";
  638. break;
  639. case stopped_reason_t::EXECFAILED:
  640. cout << "Reason: execution of service process failed:\n";
  641. uint16_t launch_stage;
  642. rbuffer.extract((char *)&launch_stage, base_pkt_size + 4, sizeof(uint16_t));
  643. cout << " Stage: " << exec_stage_descriptions[launch_stage] << "\n";
  644. cout << " Error: " << strerror(exit_status) << "\n";
  645. break;
  646. case stopped_reason_t::FAILED:
  647. cout << "Reason: service process terminated before ready: ";
  648. print_termination_details(exit_status);
  649. cout << "\n";
  650. break;
  651. default:
  652. cout << "Reason unknown/unrecognised. Check dinit log.\n";
  653. }
  654. }
  655. }
  656. return 1;
  657. }
  658. }
  659. }
  660. rbuffer.consume(pktlen);
  661. r = rbuffer.fill_to(socknum, 2);
  662. }
  663. else {
  664. // Not an information packet?
  665. throw dinit_protocol_error();
  666. }
  667. }
  668. if (r == -1) {
  669. perror("dinitctl: read");
  670. }
  671. else {
  672. throw dinit_protocol_error();
  673. }
  674. return 1;
  675. }
  676. // Start/stop a service
  677. static int start_stop_service(int socknum, cpbuffer_t &rbuffer, const char *service_name,
  678. command_t command, bool do_pin, bool do_force, bool wait_for_service, bool ignore_unstarted,
  679. bool verbose)
  680. {
  681. using namespace std;
  682. bool do_stop = (command == command_t::STOP_SERVICE || command == command_t::RELEASE_SERVICE);
  683. service_state_t state;
  684. handle_t handle;
  685. if (command != command_t::RESTART_SERVICE && command != command_t::STOP_SERVICE
  686. && command != command_t::RELEASE_SERVICE) {
  687. ignore_unstarted = false;
  688. }
  689. if (!load_service(socknum, rbuffer, service_name, &handle, &state, !ignore_unstarted)) {
  690. return ignore_unstarted ? 0 : 1;
  691. }
  692. service_state_t wanted_state = do_stop ? service_state_t::STOPPED : service_state_t::STARTED;
  693. int pcommand = 0;
  694. switch (command) {
  695. case command_t::STOP_SERVICE:
  696. case command_t::RESTART_SERVICE: // stop, and then start
  697. pcommand = DINIT_CP_STOPSERVICE;
  698. break;
  699. case command_t::RELEASE_SERVICE:
  700. pcommand = DINIT_CP_RELEASESERVICE;
  701. break;
  702. case command_t::START_SERVICE:
  703. pcommand = DINIT_CP_STARTSERVICE;
  704. break;
  705. case command_t::WAKE_SERVICE:
  706. pcommand = DINIT_CP_WAKESERVICE;
  707. break;
  708. default: ;
  709. }
  710. // Need to issue STOPSERVICE/STARTSERVICE
  711. // We'll do this regardless of the current service state / target state, since issuing
  712. // start/stop also sets or clears the "explicitly started" flag on the service.
  713. {
  714. char flags = (do_pin ? 1 : 0) | ((pcommand == DINIT_CP_STOPSERVICE && !do_force) ? 2 : 0);
  715. if (command == command_t::RESTART_SERVICE) {
  716. flags |= 4;
  717. }
  718. auto m = membuf()
  719. .append((char) pcommand)
  720. .append(flags)
  721. .append(handle);
  722. write_all_x(socknum, m);
  723. wait_for_reply(rbuffer, socknum);
  724. auto reply_pkt_h = rbuffer[0];
  725. rbuffer.consume(1); // consume header
  726. if (reply_pkt_h == DINIT_RP_ALREADYSS) {
  727. bool already = (state == wanted_state);
  728. if (verbose) {
  729. cout << "Service " << (already ? "(already) " : "")
  730. << describeState(do_stop) << "." << endl;
  731. }
  732. return 0; // success!
  733. }
  734. if (reply_pkt_h == DINIT_RP_PINNEDSTARTED) {
  735. cerr << "dinitctl: cannot stop service '" << service_name << "' as it is pinned started\n";
  736. return 1;
  737. }
  738. if (reply_pkt_h == DINIT_RP_PINNEDSTOPPED) {
  739. cerr << "dinitctl: cannot start service '" << service_name << "' as it is pinned stopped\n";
  740. return 1;
  741. }
  742. if (reply_pkt_h == DINIT_RP_DEPENDENTS && pcommand == DINIT_CP_STOPSERVICE) {
  743. cerr << "dinitctl: cannot stop service '" << service_name << "' due to the following dependents:\n";
  744. if (command != command_t::RESTART_SERVICE) {
  745. cerr << "(only direct dependents are listed. Exercise caution before using '--force' !!)\n";
  746. }
  747. // size_t number, N * handle_t handles
  748. size_t number;
  749. rbuffer.fill_to(socknum, sizeof(number));
  750. rbuffer.extract(&number, 0, sizeof(number));
  751. rbuffer.consume(sizeof(number));
  752. std::vector<handle_t> handles;
  753. handles.reserve(number);
  754. for (size_t i = 0; i < number; i++) {
  755. handle_t handle;
  756. rbuffer.fill_to(socknum, sizeof(handle_t));
  757. rbuffer.extract(&handle, 0, sizeof(handle));
  758. handles.push_back(handle);
  759. rbuffer.consume(sizeof(handle));
  760. }
  761. // Print the directly affected dependents:
  762. cerr << " ";
  763. for (handle_t handle : handles) {
  764. cerr << " " << get_service_name(socknum, rbuffer, handle);
  765. }
  766. cerr << "\n";
  767. return 1;
  768. }
  769. if (reply_pkt_h == DINIT_RP_NAK && command == command_t::RESTART_SERVICE) {
  770. if (ignore_unstarted) {
  771. if (verbose) {
  772. cout << "Service '" << service_name << "' is not currently started.\n";
  773. }
  774. return 0;
  775. }
  776. cerr << "dinitctl: cannot restart service; service not started.\n";
  777. return 1;
  778. }
  779. if (reply_pkt_h == DINIT_RP_NAK && command == command_t::WAKE_SERVICE) {
  780. cerr << "dinitctl: service has no active dependents, cannot wake.\n";
  781. return 1;
  782. }
  783. if (reply_pkt_h == DINIT_RP_SHUTTINGDOWN) {
  784. cerr << "dinitctl: cannot start/restart/wake service, shutdown is in progress.\n";
  785. return 1;
  786. }
  787. if (reply_pkt_h != DINIT_RP_ACK && reply_pkt_h != DINIT_RP_ALREADYSS) {
  788. cerr << "dinitctl: protocol error." << endl;
  789. return 1;
  790. }
  791. }
  792. if (! wait_for_service) {
  793. if (verbose) {
  794. cout << "Issued " << describeVerb(do_stop) << " command successfully for service '"
  795. << service_name << "'." << endl;
  796. }
  797. return 0;
  798. }
  799. return wait_service_state(socknum, rbuffer, handle, service_name, do_stop, verbose);
  800. }
  801. // Issue a "load service" command (DINIT_CP_LOADSERVICE), without waiting for
  802. // a response. Returns 1 on failure (with error logged), 0 on success.
  803. static int issue_load_service(int socknum, const char *service_name, bool find_only)
  804. {
  805. // Build buffer;
  806. uint16_t sname_len = strlen(service_name);
  807. int bufsize = 3 + sname_len;
  808. std::unique_ptr<char[]> ubuf(new char[bufsize]);
  809. auto buf = ubuf.get();
  810. buf[0] = find_only ? DINIT_CP_FINDSERVICE : DINIT_CP_LOADSERVICE;
  811. memcpy(buf + 1, &sname_len, 2);
  812. memcpy(buf + 3, service_name, sname_len);
  813. write_all_x(socknum, buf, bufsize);
  814. return 0;
  815. }
  816. // Check that a "load service" reply was received, and that the requested service was found.
  817. // state_p may be null.
  818. static int check_load_reply(int socknum, cpbuffer_t &rbuffer, handle_t *handle_p, service_state_t *state_p, bool write_error)
  819. {
  820. using namespace std;
  821. if (rbuffer[0] == DINIT_RP_SERVICERECORD) {
  822. fill_buffer_to(rbuffer, socknum, 2 + sizeof(*handle_p));
  823. rbuffer.extract((char *) handle_p, 2, sizeof(*handle_p));
  824. if (state_p) *state_p = static_cast<service_state_t>(rbuffer[1]);
  825. //target_state = static_cast<service_state_t>(rbuffer[2 + sizeof(handle)]);
  826. rbuffer.consume(3 + sizeof(*handle_p));
  827. return 0;
  828. }
  829. else if (rbuffer[0] == DINIT_RP_NOSERVICE) {
  830. if (write_error) {
  831. cerr << "dinitctl: failed to find service description.\n";
  832. cerr << "dinitctl: check service description file exists / service name spelling.\n";
  833. }
  834. return 1;
  835. }
  836. else if (rbuffer[0] == DINIT_RP_SERVICE_DESC_ERR) {
  837. if (write_error) {
  838. cerr << "dinitctl: error in service description.\n";
  839. cerr << "dinitctl: try 'dinitcheck <service-name>' or check log for more information.\n";
  840. }
  841. return 1;
  842. }
  843. else if (rbuffer[0] == DINIT_RP_SERVICE_LOAD_ERR) {
  844. if (write_error) {
  845. cerr << "dinitctl: error loading service (or dependency of service).\n";
  846. cerr << "dinitctl: try 'dinitcheck <service-name>' or check log for more information.\n";
  847. }
  848. return 1;
  849. }
  850. else {
  851. throw dinit_protocol_error();
  852. }
  853. }
  854. static int unpin_service(int socknum, cpbuffer_t &rbuffer, const char *service_name, bool verbose)
  855. {
  856. using namespace std;
  857. handle_t handle;
  858. // Build buffer;
  859. if (! load_service(socknum, rbuffer, service_name, &handle, nullptr)) {
  860. return 1;
  861. }
  862. // Issue UNPIN command.
  863. {
  864. auto m = membuf()
  865. .append<char>(DINIT_CP_UNPINSERVICE)
  866. .append(handle);
  867. write_all_x(socknum, m);
  868. wait_for_reply(rbuffer, socknum);
  869. if (rbuffer[0] != DINIT_RP_ACK) {
  870. cerr << "dinitctl: protocol error." << endl;
  871. return 1;
  872. }
  873. rbuffer.consume(1);
  874. }
  875. if (verbose) {
  876. cout << "Service '" << service_name << "' unpinned." << endl;
  877. }
  878. return 0;
  879. }
  880. static int unload_service(int socknum, cpbuffer_t &rbuffer, const char *service_name, bool verbose)
  881. {
  882. using namespace std;
  883. if (issue_load_service(socknum, service_name, true) == 1) {
  884. return 1;
  885. }
  886. wait_for_reply(rbuffer, socknum);
  887. handle_t handle;
  888. if (rbuffer[0] == DINIT_RP_NOSERVICE) {
  889. cerr << "dinitctl: service not loaded." << endl;
  890. return 1;
  891. }
  892. if (check_load_reply(socknum, rbuffer, &handle, nullptr) != 0) {
  893. return 1;
  894. }
  895. // Issue UNLOAD command.
  896. {
  897. auto m = membuf()
  898. .append<char>(DINIT_CP_UNLOADSERVICE)
  899. .append(handle);
  900. write_all_x(socknum, m);
  901. wait_for_reply(rbuffer, socknum);
  902. if (rbuffer[0] == DINIT_RP_NAK) {
  903. cerr << "dinitctl: could not unload service; service not stopped, or is a dependency of "
  904. "other service." << endl;
  905. return 1;
  906. }
  907. if (rbuffer[0] != DINIT_RP_ACK) {
  908. cerr << "dinitctl: protocol error." << endl;
  909. return 1;
  910. }
  911. rbuffer.consume(1);
  912. }
  913. if (verbose) {
  914. cout << "Service '" << service_name << "' unloaded." << endl;
  915. }
  916. return 0;
  917. }
  918. static int reload_service(int socknum, cpbuffer_t &rbuffer, const char *service_name, bool verbose)
  919. {
  920. using namespace std;
  921. if (issue_load_service(socknum, service_name, true) == 1) {
  922. return 1;
  923. }
  924. wait_for_reply(rbuffer, socknum);
  925. handle_t handle;
  926. if (rbuffer[0] == DINIT_RP_NOSERVICE) {
  927. rbuffer.consume(1);
  928. // If the service isn't loaded yet at all, just do a basic load:
  929. if (issue_load_service(socknum, service_name, false) == 1) {
  930. return 1;
  931. }
  932. wait_for_reply(rbuffer, socknum);
  933. if (check_load_reply(socknum, rbuffer, &handle, nullptr) != 0) {
  934. return 1;
  935. }
  936. if (verbose) {
  937. cout << "Service '" << service_name << "' reloaded." << endl;
  938. }
  939. return 0;
  940. }
  941. if (check_load_reply(socknum, rbuffer, &handle, nullptr) != 0) {
  942. return 1;
  943. }
  944. // Issue RELOAD command.
  945. {
  946. auto m = membuf()
  947. .append<char>(DINIT_CP_RELOADSERVICE)
  948. .append(handle);
  949. write_all_x(socknum, m);
  950. wait_for_reply(rbuffer, socknum);
  951. if (rbuffer[0] == DINIT_RP_NAK) {
  952. cerr << "dinitctl: could not reload service; service in wrong state, incompatible change, "
  953. "or bad service description." << endl;
  954. return 1;
  955. }
  956. if (rbuffer[0] != DINIT_RP_ACK) {
  957. cerr << "dinitctl: protocol error." << endl;
  958. return 1;
  959. }
  960. rbuffer.consume(1);
  961. }
  962. if (verbose) {
  963. cout << "Service '" << service_name << "' reloaded." << endl;
  964. }
  965. return 0;
  966. }
  967. static int list_services(int socknum, cpbuffer_t &rbuffer)
  968. {
  969. using namespace std;
  970. char cmdbuf[] = { (char)DINIT_CP_LISTSERVICES };
  971. write_all_x(socknum, cmdbuf, 1);
  972. wait_for_reply(rbuffer, socknum);
  973. while (rbuffer[0] == DINIT_RP_SVCINFO) {
  974. int hdrsize = 8 + std::max(sizeof(int), sizeof(pid_t));
  975. fill_buffer_to(rbuffer, socknum, hdrsize);
  976. unsigned name_len = (unsigned char)rbuffer[1];
  977. service_state_t current = static_cast<service_state_t>(rbuffer[2]);
  978. service_state_t target = static_cast<service_state_t>(rbuffer[3]);
  979. int console_flags = rbuffer[4];
  980. bool has_console = (console_flags & 2) != 0;
  981. bool waiting_console = (console_flags & 1) != 0;
  982. bool was_skipped = (console_flags & 4) != 0;
  983. bool marked_active = (console_flags & 8) != 0;
  984. bool has_pid = (console_flags & 16) != 0;
  985. stopped_reason_t stop_reason = static_cast<stopped_reason_t>(rbuffer[5]);
  986. pid_t service_pid;
  987. int exit_status;
  988. if (has_pid) {
  989. rbuffer.extract((char *)&service_pid, 8, sizeof(service_pid));
  990. }
  991. else {
  992. rbuffer.extract((char *)&exit_status, 8, sizeof(exit_status));
  993. }
  994. fill_buffer_to(rbuffer, socknum, name_len + hdrsize);
  995. char *name_ptr = rbuffer.get_ptr(hdrsize);
  996. unsigned clength = std::min(rbuffer.get_contiguous_length(name_ptr), name_len);
  997. string name = string(name_ptr, clength);
  998. name.append(rbuffer.get_buf_base(), name_len - clength);
  999. cout << "[";
  1000. // [ ] if marked active; otherwise, { } if target state is STARTED
  1001. // + if started, 's' if skipped, space otherwise
  1002. char lbracket = target == service_state_t::STARTED ? '{' : ' ';
  1003. char rbracket = target == service_state_t::STARTED ? '}' : ' ';
  1004. cout << (marked_active ? '[' : lbracket);
  1005. if (current == service_state_t::STARTED) {
  1006. cout << (was_skipped ? 's' : '+');
  1007. }
  1008. else {
  1009. cout << ' ';
  1010. }
  1011. cout << (marked_active ? ']' : rbracket);
  1012. if (current == service_state_t::STARTING) {
  1013. cout << "<<";
  1014. }
  1015. else if (current == service_state_t::STOPPING) {
  1016. cout << ">>";
  1017. }
  1018. else {
  1019. cout << " ";
  1020. }
  1021. cout << (target == service_state_t::STOPPED ? '{' : ' ');
  1022. if (current == service_state_t::STOPPED) {
  1023. bool did_fail = false;
  1024. if (stop_reason == stopped_reason_t::TERMINATED) {
  1025. if (!WIFEXITED(exit_status) || WEXITSTATUS(exit_status) != 0) {
  1026. did_fail = true;
  1027. }
  1028. }
  1029. else did_fail = (stop_reason != stopped_reason_t::NORMAL);
  1030. cout << (did_fail ? 'X' : '-');
  1031. }
  1032. else {
  1033. cout << ' ';
  1034. }
  1035. cout << (target == service_state_t::STOPPED ? '}' : ' ');
  1036. cout << "] " << name;
  1037. if (current != service_state_t::STOPPED && has_pid) {
  1038. cout << " (pid: " << service_pid << ")";
  1039. }
  1040. if (current == service_state_t::STOPPED && stop_reason == stopped_reason_t::TERMINATED) {
  1041. if (WIFEXITED(exit_status)) {
  1042. cout << " (exit status: " << WEXITSTATUS(exit_status) << ")";
  1043. }
  1044. else if (WIFSIGNALED(exit_status)) {
  1045. cout << " (signal: " << WTERMSIG(exit_status) << ")";
  1046. }
  1047. }
  1048. if (has_console) {
  1049. cout << " (has console)";
  1050. }
  1051. else if (waiting_console) {
  1052. cout << " (waiting for console)";
  1053. }
  1054. cout << endl;
  1055. rbuffer.consume(hdrsize + name_len);
  1056. wait_for_reply(rbuffer, socknum);
  1057. }
  1058. if (rbuffer[0] != DINIT_RP_LISTDONE) {
  1059. cerr << "dinitctl: control socket protocol error" << endl;
  1060. return 1;
  1061. }
  1062. return 0;
  1063. }
  1064. static int service_status(int socknum, cpbuffer_t &rbuffer, const char *service_name, command_t command, bool verbose)
  1065. {
  1066. using namespace std;
  1067. bool is_status = command == command_t::SERVICE_STATUS;
  1068. if (issue_load_service(socknum, service_name, true) == 1) {
  1069. return 1;
  1070. }
  1071. wait_for_reply(rbuffer, socknum);
  1072. handle_t handle;
  1073. if (rbuffer[0] == DINIT_RP_NOSERVICE) {
  1074. if (is_status) {
  1075. cerr << "dinitctl: service not loaded." << endl;
  1076. }
  1077. return 1;
  1078. }
  1079. if (check_load_reply(socknum, rbuffer, &handle, nullptr, is_status) != 0) {
  1080. return 1;
  1081. }
  1082. // Issue STATUS request
  1083. {
  1084. auto m = membuf()
  1085. .append<char>(DINIT_CP_SERVICESTATUS)
  1086. .append(handle);
  1087. write_all_x(socknum, m);
  1088. wait_for_reply(rbuffer, socknum);
  1089. if (rbuffer[0] != DINIT_RP_SERVICESTATUS) {
  1090. cerr << "dinitctl: protocol error." << endl;
  1091. return 1;
  1092. }
  1093. rbuffer.consume(1);
  1094. fill_buffer_to(rbuffer, socknum, STATUS_BUFFER_SIZE + 1 /* reserved */);
  1095. rbuffer.consume(1);
  1096. service_state_t current = static_cast<service_state_t>(rbuffer[0]);
  1097. service_state_t target = static_cast<service_state_t>(rbuffer[1]);
  1098. int console_flags = rbuffer[2];
  1099. bool has_console = (console_flags & 2) != 0;
  1100. bool waiting_console = (console_flags & 1) != 0;
  1101. bool was_skipped = (console_flags & 4) != 0;
  1102. bool marked_active = (console_flags & 8) != 0;
  1103. bool has_pid = (console_flags & 16) != 0;
  1104. stopped_reason_t stop_reason = static_cast<stopped_reason_t>(rbuffer[3]);
  1105. pid_t service_pid = -1;
  1106. int exit_status = 0;
  1107. if (has_pid) {
  1108. rbuffer.extract((char *)&service_pid, 6, sizeof(service_pid));
  1109. }
  1110. else {
  1111. rbuffer.extract((char *)&exit_status, 6, sizeof(exit_status));
  1112. }
  1113. switch (command) {
  1114. case command_t::IS_ACTIVE:
  1115. case command_t::IS_FAILED:
  1116. if (verbose) {
  1117. switch (current) {
  1118. case service_state_t::STOPPED:
  1119. cout << "STOPPED" << endl;
  1120. break;
  1121. case service_state_t::STARTING:
  1122. cout << "STARTING" << endl;
  1123. break;
  1124. case service_state_t::STARTED:
  1125. cout << "STARTED" << endl;
  1126. break;
  1127. case service_state_t::STOPPING:
  1128. cout << "STOPPING" << endl;
  1129. }
  1130. }
  1131. /* return 0 (success) for started */
  1132. if (command == command_t::IS_ACTIVE) {
  1133. return current != service_state_t::STARTED;
  1134. }
  1135. /* return 0 (success) for specific stopped reasons */
  1136. if (current == service_state_t::STOPPED) {
  1137. switch (stop_reason) {
  1138. case stopped_reason_t::DEPFAILED:
  1139. case stopped_reason_t::FAILED:
  1140. case stopped_reason_t::EXECFAILED:
  1141. case stopped_reason_t::TIMEDOUT:
  1142. return 0;
  1143. default:
  1144. break;
  1145. }
  1146. }
  1147. return 1;
  1148. default:
  1149. /* status */
  1150. break;
  1151. }
  1152. cout << "Service: " << service_name << "\n"
  1153. " State: ";
  1154. switch (current) {
  1155. case service_state_t::STOPPED:
  1156. cout << "STOPPED";
  1157. switch (stop_reason) {
  1158. case stopped_reason_t::DEPRESTART:
  1159. cout << " (dependency restarted)";
  1160. break;
  1161. case stopped_reason_t::DEPFAILED:
  1162. cout << " (dependency failed/terminated)";
  1163. break;
  1164. case stopped_reason_t::FAILED:
  1165. cout << " (failed to start";
  1166. if (exit_status != 0) {
  1167. cout << "; ";
  1168. print_termination_details(exit_status);
  1169. }
  1170. cout << ")";
  1171. break;
  1172. case stopped_reason_t::EXECFAILED:
  1173. uint16_t launch_stage;
  1174. rbuffer.extract((char *)&launch_stage, 4, 2);
  1175. cout << " (could not be launched)\n";
  1176. cout << " Stage: " << exec_stage_descriptions[launch_stage] << "\n";
  1177. cout << " Error: " << strerror(exit_status);
  1178. break;
  1179. case stopped_reason_t::TERMINATED:
  1180. cout << " (terminated";
  1181. if (exit_status != 0) {
  1182. cout << "; ";
  1183. print_termination_details(exit_status);
  1184. }
  1185. cout << ")";
  1186. break;
  1187. case stopped_reason_t::TIMEDOUT:
  1188. cout << " (start timed out)";
  1189. break;
  1190. case stopped_reason_t::NORMAL:
  1191. break;
  1192. }
  1193. break;
  1194. case service_state_t::STARTING:
  1195. cout << "STARTING";
  1196. if (target == service_state_t::STOPPED) {
  1197. cout << " (target state: STOPPED)";
  1198. }
  1199. break;
  1200. case service_state_t::STARTED:
  1201. cout << "STARTED";
  1202. if (was_skipped) {
  1203. cout << " (startup skipped)";
  1204. }
  1205. break;
  1206. case service_state_t::STOPPING:
  1207. cout << "STOPPING";
  1208. if (target == service_state_t::STARTED) {
  1209. cout << " (target state: STARTED)";
  1210. }
  1211. if (exit_status != 0) {
  1212. cout << "(terminated ;";
  1213. print_termination_details(exit_status);
  1214. cout << ")";
  1215. }
  1216. }
  1217. if (has_console) {
  1218. cout << " (holding console)";
  1219. }
  1220. if (waiting_console) {
  1221. cout << " (waiting for console)";
  1222. }
  1223. cout << "\n";
  1224. if (target == service_state_t::STARTED) {
  1225. cout << " Activation: ";
  1226. if (marked_active) {
  1227. cout << "explicitly started\n";
  1228. }
  1229. else {
  1230. cout << "start due to dependent(s)\n";
  1231. }
  1232. }
  1233. if (service_pid != -1) {
  1234. cout << " Process ID: " << service_pid << "\n";
  1235. }
  1236. }
  1237. return 0;
  1238. }
  1239. static int add_remove_dependency(int socknum, cpbuffer_t &rbuffer, bool add,
  1240. const char *service_from, const char *service_to, dependency_type dep_type, bool verbose)
  1241. {
  1242. using namespace std;
  1243. handle_t from_handle;
  1244. handle_t to_handle;
  1245. if (! load_service(socknum, rbuffer, service_from, &from_handle, nullptr)
  1246. || ! load_service(socknum, rbuffer, service_to, &to_handle, nullptr)) {
  1247. return 1;
  1248. }
  1249. if (from_handle == to_handle) {
  1250. cerr << "dinitctl: can not add/remove a dependency from a service to itself" << endl;
  1251. return 1;
  1252. }
  1253. auto m = membuf()
  1254. .append<char>(add ? (char)DINIT_CP_ADD_DEP : (char)DINIT_CP_REM_DEP)
  1255. .append(static_cast<char>(dep_type))
  1256. .append(from_handle)
  1257. .append(to_handle);
  1258. write_all_x(socknum, m);
  1259. wait_for_reply(rbuffer, socknum);
  1260. // check reply
  1261. if (rbuffer[0] == DINIT_RP_NAK) {
  1262. if (add) {
  1263. cerr << "dinitctl: could not add dependency: circular dependency or wrong state" << endl;
  1264. }
  1265. else {
  1266. cerr << "dinitctl: no such dependency to remove" << endl;
  1267. }
  1268. return 1;
  1269. }
  1270. if (rbuffer[0] != DINIT_RP_ACK) {
  1271. cerr << "dinitctl: control socket protocol error" << endl;
  1272. return 1;
  1273. }
  1274. if (verbose) {
  1275. std::cout << "Service '" << service_from << "': dependency '" << service_to << "' " << (add ? "added" : "removed") << endl;
  1276. }
  1277. return 0;
  1278. }
  1279. static int shutdown_dinit(int socknum, cpbuffer_t &rbuffer, bool verbose)
  1280. {
  1281. // TODO support no-wait option.
  1282. using namespace std;
  1283. auto m = membuf()
  1284. .append<char>(DINIT_CP_SHUTDOWN)
  1285. .append(static_cast<char>(shutdown_type_t::HALT));
  1286. write_all_x(socknum, m);
  1287. wait_for_reply(rbuffer, socknum);
  1288. if (rbuffer[0] != DINIT_RP_ACK) {
  1289. cerr << "dinitctl: control socket protocol error" << endl;
  1290. return 1;
  1291. }
  1292. if (verbose) {
  1293. std::cout << "Shutting down dinit..." << std::endl;
  1294. }
  1295. // Now wait for rollback complete, by waiting for the connection to close:
  1296. try {
  1297. while (true) {
  1298. wait_for_info(rbuffer, socknum);
  1299. rbuffer.consume(rbuffer[1]);
  1300. }
  1301. }
  1302. catch (cp_read_exception &exc) {
  1303. // Assume that the connection closed.
  1304. }
  1305. if (verbose) {
  1306. std::cout << "Connection closed." << std::endl;
  1307. }
  1308. return 0;
  1309. }
  1310. // exception for cancelling a service operation
  1311. class service_op_cancel { };
  1312. static int enable_disable_service(int socknum, cpbuffer_t &rbuffer, const char *from, const char *to,
  1313. bool enable, bool verbose)
  1314. {
  1315. using namespace std;
  1316. service_state_t from_state = service_state_t::STARTED;
  1317. handle_t from_handle;
  1318. handle_t to_handle;
  1319. if (!load_service(socknum, rbuffer, from, &from_handle, &from_state)
  1320. || !load_service(socknum, rbuffer, to, &to_handle, nullptr)) {
  1321. return 1;
  1322. }
  1323. // Get service load path
  1324. char buf[1] = { DINIT_CP_QUERY_LOAD_MECH };
  1325. write_all_x(socknum, buf, 1);
  1326. wait_for_reply(rbuffer, socknum);
  1327. if (rbuffer[0] != DINIT_RP_LOADER_MECH) {
  1328. cerr << "dinitctl: control socket protocol error" << endl;
  1329. return 1;
  1330. }
  1331. // Packet type, load mechanism type, packet size:
  1332. fill_buffer_to(rbuffer, socknum, 2 + sizeof(uint32_t));
  1333. if (rbuffer[1] != SSET_TYPE_DIRLOAD) {
  1334. cerr << "dinitctl: unknown configuration, unable to load service descriptions" << endl;
  1335. return 1;
  1336. }
  1337. vector<string> paths;
  1338. uint32_t pktsize;
  1339. rbuffer.extract(&pktsize, 2, sizeof(uint32_t));
  1340. fill_buffer_to(rbuffer, socknum, 2 + sizeof(uint32_t) * 3); // path entries, cwd length
  1341. uint32_t path_entries; // number of service directories
  1342. rbuffer.extract(&path_entries, 2 + sizeof(uint32_t), sizeof(uint32_t));
  1343. uint32_t cwd_len;
  1344. rbuffer.extract(&cwd_len, 2 + sizeof(uint32_t) * 2, sizeof(uint32_t));
  1345. rbuffer.consume(2 + sizeof(uint32_t) * 3);
  1346. pktsize -= 2 + sizeof(uint32_t) * 3;
  1347. // Read current working directory of daemon:
  1348. std::string dinit_cwd = read_string(socknum, rbuffer, cwd_len);
  1349. // dinit daemon base directory against which service paths are resolved is in dinit_cwd
  1350. for (uint32_t i = 0; i < path_entries; ++i) {
  1351. uint32_t plen;
  1352. fill_buffer_to(rbuffer, socknum, sizeof(uint32_t));
  1353. rbuffer.extract(&plen, 0, sizeof(uint32_t));
  1354. rbuffer.consume(sizeof(uint32_t));
  1355. paths.push_back(read_string(socknum, rbuffer, plen));
  1356. }
  1357. // all service directories are now in the 'paths' vector
  1358. // Load/read service description for 'from' service:
  1359. ifstream service_file;
  1360. string service_file_path;
  1361. for (std::string path : paths) {
  1362. string test_path = combine_paths(combine_paths(dinit_cwd, path.c_str()), from);
  1363. service_file.open(test_path.c_str(), ios::in);
  1364. if (service_file) {
  1365. service_file_path = test_path;
  1366. break;
  1367. }
  1368. }
  1369. if (! service_file) {
  1370. cerr << "dinitctl: could not locate service file for service '" << from << "'" << endl;
  1371. return 1;
  1372. }
  1373. // We now need to read the service file, identify the waits-for.d directory (bail out if more than one),
  1374. // make sure the service is not listed as a dependency individually.
  1375. string waits_for_d;
  1376. try {
  1377. process_service_file(from, service_file, [&](string &line, unsigned line_num, string &setting,
  1378. dinit_load::string_iterator i, dinit_load::string_iterator end) -> void {
  1379. if (setting == "waits-for" || setting == "depends-on" || setting == "depends-ms") {
  1380. string dname = dinit_load::read_setting_value(line_num, i, end);
  1381. if (dname == to) {
  1382. // There is already a dependency
  1383. cerr << "dinitctl: there is a fixed dependency to service '" << to
  1384. << "' in the service description of '" << from << "'." << endl;
  1385. throw service_op_cancel();
  1386. }
  1387. }
  1388. else if (setting == "waits-for.d") {
  1389. string dname = dinit_load::read_setting_value(line_num, i, end);
  1390. if (! waits_for_d.empty()) {
  1391. cerr << "dinitctl: service '" << from << "' has multiple waits-for.d directories "
  1392. << "specified in service description" << endl;
  1393. throw service_op_cancel();
  1394. }
  1395. waits_for_d = std::move(dname);
  1396. }
  1397. });
  1398. }
  1399. catch (const service_op_cancel &cexc) {
  1400. return 1;
  1401. }
  1402. // If the from service has no waits-for.d specified, we can't continue
  1403. if (waits_for_d.empty()) {
  1404. cerr << "dinitctl: service '" << from << "' has no waits-for.d directory specified" << endl;
  1405. return 1;
  1406. }
  1407. // The waits-for.d path is relative to the service file path, combine:
  1408. string waits_for_d_full = combine_paths(parent_path(service_file_path), waits_for_d.c_str());
  1409. // check if dependency already exists
  1410. string dep_link_path = combine_paths(waits_for_d_full, to);
  1411. struct stat stat_buf;
  1412. if (lstat(dep_link_path.c_str(), &stat_buf) == -1) {
  1413. if (errno != ENOENT) {
  1414. cerr << "dinitctl: checking for existing dependency link: " << dep_link_path << ": "
  1415. << strerror(errno) << endl;
  1416. return 1;
  1417. }
  1418. }
  1419. else {
  1420. // dependency already exists
  1421. if (enable) {
  1422. cerr << "dinitctl: service already enabled." << endl;
  1423. return 1;
  1424. }
  1425. }
  1426. // warn if 'from' service is not started
  1427. if (enable && from_state != service_state_t::STARTED) {
  1428. cerr << "dinitctl: warning: enabling dependency for non-started service" << endl;
  1429. }
  1430. // add/remove dependency
  1431. constexpr int enable_pktsize = 2 + sizeof(handle_t) * 2;
  1432. char cmdbuf[enable_pktsize] = { char(enable ? DINIT_CP_ENABLESERVICE : DINIT_CP_REM_DEP),
  1433. char(dependency_type::WAITS_FOR)};
  1434. memcpy(cmdbuf + 2, &from_handle, sizeof(from_handle));
  1435. memcpy(cmdbuf + 2 + sizeof(from_handle), &to_handle, sizeof(to_handle));
  1436. write_all_x(socknum, cmdbuf, enable_pktsize);
  1437. wait_for_reply(rbuffer, socknum);
  1438. // check reply
  1439. if (rbuffer[0] == DINIT_RP_NAK) {
  1440. if (enable) {
  1441. cerr << "dinitctl: could not enable service: possible circular dependency" << endl;
  1442. }
  1443. else {
  1444. cerr << "dinitctl: service not currently enabled" << endl;
  1445. }
  1446. return 1;
  1447. }
  1448. if (rbuffer[0] != DINIT_RP_ACK) {
  1449. cerr << "dinitctl: control socket protocol error" << endl;
  1450. return 1;
  1451. }
  1452. rbuffer.consume(1);
  1453. // create link
  1454. if (enable) {
  1455. if (symlink((string("../") + to).c_str(), dep_link_path.c_str()) == -1) {
  1456. cerr << "dinitctl: could not create symlink at " << dep_link_path << ": " << strerror(errno)
  1457. << "\n" "dinitctl: note: service was enabled for now; persistent enable failed."
  1458. << endl;
  1459. return 1;
  1460. }
  1461. }
  1462. else {
  1463. if (unlink(dep_link_path.c_str()) == -1) {
  1464. cerr << "dinitctl: could not unlink dependency entry " << dep_link_path << ": "
  1465. << strerror(errno) << "\n"
  1466. "dinitctl: note: service was disabled for now; persistent disable failed." << endl;
  1467. return 1;
  1468. }
  1469. }
  1470. // Check status of the service now
  1471. auto m = membuf()
  1472. .append<char>(DINIT_CP_SERVICESTATUS)
  1473. .append(to_handle);
  1474. write_all_x(socknum, m);
  1475. wait_for_reply(rbuffer, socknum);
  1476. if (rbuffer[0] != DINIT_RP_SERVICESTATUS) {
  1477. cerr << "dinitctl: protocol error." << endl;
  1478. return 1;
  1479. }
  1480. rbuffer.consume(1);
  1481. int statussize = 6 + std::max(sizeof(pid_t), sizeof(int));;
  1482. fill_buffer_to(rbuffer, socknum, statussize + 1 /* reserved */);
  1483. rbuffer.consume(1);
  1484. service_state_t current = static_cast<service_state_t>(rbuffer[0]);
  1485. service_state_t target = static_cast<service_state_t>(rbuffer[1]);
  1486. rbuffer.consume(statussize);
  1487. if (verbose) {
  1488. cout << "Service '" << to << "' has been " << (enable ? "enabled" : "disabled") << "." << endl;
  1489. }
  1490. if (enable) {
  1491. if (current != service_state_t::STARTED) {
  1492. wait_service_state(socknum, rbuffer, to_handle, to, false /* start */, verbose);
  1493. }
  1494. }
  1495. else {
  1496. if (target != service_state_t::STOPPED) {
  1497. std::cerr << "dinitctl: note: disabled service may have other dependents\n";
  1498. }
  1499. }
  1500. return 0;
  1501. }
  1502. static int do_setenv(int socknum, cpbuffer_t &rbuffer, std::vector<const char *> &env_names)
  1503. {
  1504. using namespace std;
  1505. string buf;
  1506. for (const char *envp : env_names) {
  1507. buf.clear();
  1508. buf.reserve(6);
  1509. // protocol message and size space
  1510. buf.push_back(DINIT_CP_SETENV);
  1511. buf.append(2, 0);
  1512. const unsigned hdr_len = 3;
  1513. // either full var or name
  1514. auto elen = strlen(envp);
  1515. buf.append(envp, elen);
  1516. // if '=' not found, get value from environment
  1517. if (!memchr(envp, '=', elen)) {
  1518. buf.push_back('=');
  1519. auto *envv = getenv(envp);
  1520. if (envv) {
  1521. buf.append(envv);
  1522. }
  1523. }
  1524. uint16_t bufs = buf.size() - hdr_len;
  1525. // sanitize length early on
  1526. if (buf.size() > cpbuffer_t::get_size()) {
  1527. auto eq = buf.find('=', hdr_len);
  1528. auto name = buf.substr(hdr_len, eq - hdr_len);
  1529. cerr << "dinitctl: environment variable '" << name << "' too long." << endl;
  1530. return 1;
  1531. }
  1532. // set size in protocol message
  1533. memcpy(&buf[1], &bufs, 2);
  1534. // send
  1535. write_all_x(socknum, buf.data(), buf.size());
  1536. wait_for_reply(rbuffer, socknum);
  1537. if (rbuffer[0] == DINIT_RP_BADREQ) {
  1538. cerr << "dinitctl: failed to export environment." << endl;
  1539. return 1;
  1540. } else if (rbuffer[0] != DINIT_RP_ACK) {
  1541. throw dinit_protocol_error();
  1542. }
  1543. rbuffer.consume(1);
  1544. }
  1545. return 0;
  1546. }
  1547. static int trigger_service(int socknum, cpbuffer_t &rbuffer, const char *service_name, bool trigger_value)
  1548. {
  1549. using namespace std;
  1550. handle_t handle;
  1551. if (!load_service(socknum, rbuffer, service_name, &handle, nullptr, true)) {
  1552. return 1;
  1553. }
  1554. // Issue SET_TRIGGER command.
  1555. {
  1556. auto m = membuf()
  1557. .append<char>(DINIT_CP_SETTRIGGER)
  1558. .append(handle)
  1559. .append<char>(trigger_value);
  1560. write_all_x(socknum, m);
  1561. wait_for_reply(rbuffer, socknum);
  1562. if (rbuffer[0] == DINIT_RP_NAK) {
  1563. cerr << "dinitctl: cannot trigger a service that is not of 'triggered' type.\n";
  1564. return 1;
  1565. }
  1566. if (rbuffer[0] != DINIT_RP_ACK) {
  1567. cerr << "dinitctl: protocol error.\n";
  1568. return 1;
  1569. }
  1570. rbuffer.consume(1);
  1571. }
  1572. return 0;
  1573. }
  1574. static int cat_service_log(int socknum, cpbuffer_t &rbuffer, const char *service_name)
  1575. {
  1576. using namespace std;
  1577. handle_t handle;
  1578. if (!load_service(socknum, rbuffer, service_name, &handle, nullptr, true)) {
  1579. return 1;
  1580. }
  1581. // Issue CATLOG
  1582. auto m = membuf()
  1583. .append<char>(DINIT_CP_CATLOG)
  1584. .append<char>(0)
  1585. .append(handle);
  1586. write_all_x(socknum, m);
  1587. wait_for_reply(rbuffer, socknum);
  1588. if (rbuffer[0] == DINIT_RP_NAK) {
  1589. cerr << "dinitctl: cannot cat log for service not configured to buffer output.\n";
  1590. return 1;
  1591. }
  1592. if (rbuffer[0] != DINIT_RP_SERVICE_LOG) {
  1593. cerr << "dinitctl: protocol error.\n";
  1594. return 1;
  1595. }
  1596. fill_buffer_to(rbuffer, socknum, 1 + sizeof(unsigned));
  1597. unsigned bufsize;
  1598. rbuffer.extract(&bufsize, 1, sizeof(unsigned));
  1599. rbuffer.consume(1 + sizeof(unsigned));
  1600. // output the log
  1601. if (bufsize > 0) {
  1602. cout << flush;
  1603. bool trailing_nl = false;
  1604. char output_buf[rbuffer.get_size()];
  1605. while (bufsize > 0) {
  1606. unsigned l = rbuffer.get_length();
  1607. if (l == 0) {
  1608. fill_buffer_to(rbuffer, socknum, 1);
  1609. }
  1610. l = std::min(rbuffer.get_length(), bufsize);
  1611. rbuffer.extract(output_buf, 0, l);
  1612. write(STDOUT_FILENO, output_buf, l);
  1613. rbuffer.consume(l);
  1614. bufsize -= l;
  1615. trailing_nl = (output_buf[l - 1] == '\n');
  1616. }
  1617. if (!trailing_nl) {
  1618. cout << "\n(last line is truncated or incomplete)\n";
  1619. }
  1620. }
  1621. return 0;
  1622. }