dinit-client.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458
  1. #include <cstdint>
  2. #include <cstring>
  3. #include <sys/types.h>
  4. #include <pwd.h>
  5. #include <mconfig.h>
  6. #include <cpbuffer.h>
  7. #include <control-cmds.h>
  8. #include <control-datatypes.h>
  9. #include <dinit-util.h>
  10. #include <service-constants.h>
  11. // Client library for Dinit clients
  12. using cpbuffer_t = cpbuffer<1024>;
  13. // read error on control socket
  14. class cp_read_exception
  15. {
  16. public:
  17. int errcode;
  18. cp_read_exception(int err) : errcode(err) { }
  19. };
  20. // write error on control socket
  21. class cp_write_exception
  22. {
  23. public:
  24. int errcode;
  25. cp_write_exception(int err) : errcode(err) { }
  26. };
  27. class dinit_protocol_error {};
  28. class cp_old_client_exception : public dinit_protocol_error {};
  29. class cp_old_server_exception : public dinit_protocol_error {};
  30. // Unrecognised service directory configuration
  31. class dinit_unknown_sd_conf : public dinit_protocol_error {};
  32. class general_error
  33. {
  34. int err; // related errno (or 0)
  35. const char *action; // may be nullptr if err != 0
  36. std::string arg; // may be empty, must be empty if action == nullptr
  37. public:
  38. general_error(int err) : err(err), action(nullptr), arg()
  39. {
  40. }
  41. general_error(int err, const char *action, std::string arg = {}) : err(err), action(action), arg(std::move(arg))
  42. {
  43. }
  44. int get_err() { return err; }
  45. const char *get_action() { return action; }
  46. std::string &get_arg() { return arg; }
  47. };
  48. // Specialise general_error for the case of connecting to the control socket
  49. class control_sock_conn_err : public general_error
  50. {
  51. public:
  52. control_sock_conn_err(int err, std::string sockpath) : general_error(err, "connecting to socket", std::move(sockpath))
  53. {
  54. }
  55. };
  56. // static_membuf: a buffer of a fixed size (N) with one additional value (of type T). Don't use this
  57. // directly, construct via membuf.
  58. template <int N> class static_membuf
  59. {
  60. public:
  61. static constexpr int size() { return N; }
  62. private:
  63. char buf[N];
  64. public:
  65. template <typename T>
  66. static_membuf(const T &val)
  67. {
  68. static_assert(sizeof(T) == N, "must initialise with object of correct size");
  69. memcpy(buf, &val, N);
  70. }
  71. template <int M, typename T>
  72. static_membuf(char (&prevbuf)[M], const T &val)
  73. {
  74. static_assert(M + sizeof(T) == N, "size is not correct");
  75. memcpy(buf, prevbuf, M);
  76. memcpy(buf + M, &val, sizeof(val));
  77. }
  78. const char *data() const { return buf; }
  79. template <typename U> static_membuf<N+sizeof(U)> append(const U &u)
  80. {
  81. return static_membuf<N+sizeof(U)>{buf, u};
  82. }
  83. void output(char *out)
  84. {
  85. memcpy(out, buf, size());
  86. }
  87. };
  88. // "membuf" class provides a compile-time allocated buffer that we can add items to one-by-one. This is
  89. // much safer than working with raw buffers and calculating offsets and sizes by hand (and with a decent
  90. // compiler the end result is just as efficient).
  91. //
  92. // To use:
  93. // auto m = membuf().append(value1).append(value2).append(value3);
  94. // Then:
  95. // m.size() - returns total size of the buffer (sizeof(value1)+...)
  96. // m.data() - returns a 'const char *' to the buffer contents
  97. class membuf
  98. {
  99. public:
  100. template <typename U> static_membuf<sizeof(U)> append(const U &u)
  101. {
  102. return static_membuf<sizeof(U)>(u);
  103. }
  104. };
  105. // Fill a circular buffer from a file descriptor, until it contains at least _rlength_ bytes.
  106. // Throws cp_read_exception if the requested number of bytes cannot be read, with:
  107. // errcode = 0 if end of stream (remote end closed)
  108. // errcode = errno if another error occurred
  109. // Note that EINTR is ignored (i.e. the read will be re-tried).
  110. inline void fill_buffer_to(cpbuffer_t &buf, int fd, int rlength)
  111. {
  112. do {
  113. int r = buf.fill_to(fd, rlength);
  114. if (r == -1) {
  115. if (errno != EINTR) {
  116. throw cp_read_exception(errno);
  117. }
  118. }
  119. else if (r == 0) {
  120. throw cp_read_exception(0);
  121. }
  122. else {
  123. return;
  124. }
  125. }
  126. while (true);
  127. }
  128. // Fill a circular buffer from a file descriptor, until it contains at least some more data
  129. // then it did. Throws cp_read_exception if no more bytes can be read, with:
  130. // errcode = 0 if end of stream (remote end closed)
  131. // errcode = errno if another error occurred
  132. // Note that EINTR is ignored (i.e. the read will be re-tried).
  133. inline void fill_some(cpbuffer_t &buf, int fd)
  134. {
  135. while(true) {
  136. int r = buf.fill(fd);
  137. if (r == 0) {
  138. throw cp_read_exception(0);
  139. }
  140. else if (r > 0) {
  141. return;
  142. }
  143. if (errno != EINTR) {
  144. throw cp_read_exception(errno);
  145. }
  146. // if EINTR, just try again
  147. }
  148. }
  149. // Wait for a reply packet, skipping over any information packets that are received in the meantime.
  150. // Note the reply packet may be partially read. Caller is responsible for reading full packet.
  151. inline void wait_for_reply(cpbuffer_t &rbuffer, int fd)
  152. {
  153. fill_buffer_to(rbuffer, fd, 1);
  154. while (rbuffer[0] >= 100) {
  155. // Information packet; discard.
  156. fill_buffer_to(rbuffer, fd, 2);
  157. int pktlen = (unsigned char) rbuffer[1];
  158. rbuffer.consume(1); // Consume one byte so we'll read one byte of the next packet
  159. fill_buffer_to(rbuffer, fd, pktlen);
  160. rbuffer.consume(pktlen - 1);
  161. }
  162. }
  163. // Wait for an info packet. If any other reply packet comes, throw a cp_read_exception.
  164. inline void wait_for_info(cpbuffer_t &rbuffer, int fd)
  165. {
  166. fill_buffer_to(rbuffer, fd, 2);
  167. if (rbuffer[0] < 100) {
  168. throw cp_read_exception(0);
  169. }
  170. int pktlen = (unsigned char) rbuffer[1];
  171. fill_buffer_to(rbuffer, fd, pktlen);
  172. }
  173. // Write *all* the requested buffer and re-try if necessary until
  174. // the buffer is written or an unrecoverable error occurs.
  175. // Note: count is int
  176. inline int write_all(int fd, const void *buf, int count)
  177. {
  178. const char *cbuf = static_cast<const char *>(buf);
  179. int w = 0;
  180. while (count > 0) {
  181. int r = write(fd, cbuf, count);
  182. if (r == -1) {
  183. if (errno == EINTR) continue;
  184. return (count > 0) ? count : r;
  185. }
  186. w += r;
  187. cbuf += r;
  188. count -= r;
  189. }
  190. return w;
  191. }
  192. // Write all the requested buffer, and throw an exception on failure.
  193. // Note: count is int
  194. inline void write_all_x(int fd, const void *buf, int count)
  195. {
  196. if (write_all(fd, buf, count) == -1) {
  197. throw cp_write_exception(errno);
  198. }
  199. }
  200. // Write all the requested buffer (eg membuf) and throw an exception on failure.
  201. template <typename Buf> inline void write_all_x(int fd, const Buf &b)
  202. {
  203. write_all_x(fd, b.data(), b.size());
  204. }
  205. // Check the protocol version is compatible with the client.
  206. // minversion - minimum protocol version that client can speak
  207. // version - maximum protocol version that client can speak
  208. // rbuffer, fd - communication buffer and socket
  209. // returns: the actual protocol version
  210. // throws an exception on protocol mismatch or error.
  211. inline uint16_t check_protocol_version(int minversion, int version, cpbuffer_t &rbuffer, int fd)
  212. {
  213. using namespace dinit_cptypes;
  214. constexpr int bufsize = 1;
  215. char buf[bufsize] = { (char)cp_cmd::QUERYVERSION };
  216. write_all_x(fd, buf, bufsize);
  217. wait_for_reply(rbuffer, fd);
  218. if (rbuffer[0] != (char)cp_rply::CPVERSION) {
  219. throw cp_read_exception{0};
  220. }
  221. // cp_rply::CVERSION, (2 byte) minimum compatible version, (2 byte) actual version
  222. constexpr int rbufsize = 1 + 2 * sizeof(uint16_t);
  223. fill_buffer_to(rbuffer, fd, rbufsize);
  224. uint16_t rminversion;
  225. uint16_t cpversion;
  226. rbuffer.extract(reinterpret_cast<char *>(&rminversion), 1, sizeof(uint16_t));
  227. rbuffer.extract(reinterpret_cast<char *>(&cpversion), 1 + sizeof(uint16_t), sizeof(uint16_t));
  228. rbuffer.consume(rbufsize);
  229. if (rminversion > version) {
  230. // We are too old
  231. throw cp_old_client_exception();
  232. }
  233. if (cpversion < minversion) {
  234. // Server is too old
  235. throw cp_old_server_exception();
  236. }
  237. return cpversion;
  238. }
  239. // Get the default socket path (i.e. the path to use if no path is explicitly specified).
  240. // 'control_socket_str' *may* be used for storage for the returned path.
  241. // 'user_dinit' should be true if getuid() == 0.
  242. inline const char *get_default_socket_path(std::string &control_socket_str, bool user_dinit)
  243. {
  244. const char *control_socket_path;
  245. const char *sockpath = getenv("DINIT_SOCKET_PATH");
  246. if (sockpath) {
  247. control_socket_str = sockpath;
  248. control_socket_path = control_socket_str.c_str();
  249. }
  250. else if (user_dinit) {
  251. const char * rundir = getenv("XDG_RUNTIME_DIR");
  252. const char * sockname = "dinitctl";
  253. if (rundir == nullptr) {
  254. sockname = ".dinitctl";
  255. rundir = getenv("HOME");
  256. if (rundir == nullptr) {
  257. struct passwd * pwuid_p = getpwuid(getuid());
  258. if (pwuid_p != nullptr) {
  259. rundir = pwuid_p->pw_dir;
  260. }
  261. }
  262. }
  263. if (rundir != nullptr) {
  264. control_socket_str = rundir;
  265. control_socket_str.push_back('/');
  266. control_socket_str += sockname;
  267. control_socket_path = control_socket_str.c_str();
  268. }
  269. else {
  270. return nullptr;
  271. }
  272. }
  273. else {
  274. control_socket_path = SYSCONTROLSOCKET; // default to system
  275. }
  276. return control_socket_path;
  277. }
  278. // Connect to the dinit daemon, return the connected socket fd.
  279. // Throws general_error on error.
  280. inline int connect_to_daemon(const char *control_socket_path)
  281. {
  282. int socknum = socket(AF_UNIX, SOCK_STREAM, 0);
  283. if (socknum == -1) {
  284. throw general_error(errno, "opening socket");
  285. }
  286. struct sockaddr_un * name;
  287. uint sockaddr_size = offsetof(struct sockaddr_un, sun_path) + strlen(control_socket_path) + 1;
  288. name = (struct sockaddr_un *) malloc(sockaddr_size);
  289. if (name == nullptr) {
  290. throw general_error(ENOMEM);
  291. }
  292. name->sun_family = AF_UNIX;
  293. strcpy(name->sun_path, control_socket_path);
  294. int connr = connect(socknum, (struct sockaddr *) name, sockaddr_size);
  295. free(name);
  296. if (connr == -1) {
  297. throw control_sock_conn_err(errno, control_socket_path);
  298. }
  299. return socknum;
  300. }
  301. // Get the file descriptor for the control socket connection as passed to use from parent process
  302. // (returns -1 if unsuccessful)
  303. inline int get_passed_cfd()
  304. {
  305. int socknum = -1;
  306. char * dinit_cs_fd_env = getenv("DINIT_CS_FD");
  307. if (dinit_cs_fd_env != nullptr) {
  308. char * endptr;
  309. long int cfdnum = strtol(dinit_cs_fd_env, &endptr, 10);
  310. if (endptr != dinit_cs_fd_env) {
  311. socknum = (int) cfdnum;
  312. // Set blocking mode (and validate file descriptor):
  313. errno = 0;
  314. int sock_flags = fcntl(socknum, F_GETFL, 0);
  315. if (sock_flags == -1 && errno != 0) {
  316. socknum = 0;
  317. }
  318. else {
  319. fcntl(socknum, F_SETFL, sock_flags & ~O_NONBLOCK);
  320. }
  321. }
  322. }
  323. return socknum;
  324. }
  325. // Extract/read a string of specified length from the buffer/socket. The string is consumed
  326. // from the buffer.
  327. inline std::string read_string(int socknum, cpbuffer_t &rbuffer, uint32_t length)
  328. {
  329. int rb_len = rbuffer.get_length();
  330. if (uint32_t(rb_len) >= length) {
  331. std::string r = rbuffer.extract_string(0, length);
  332. rbuffer.consume(length);
  333. return r;
  334. }
  335. std::string r = rbuffer.extract_string(0, rb_len);
  336. uint32_t rlen = length - rb_len;
  337. uint32_t clen;
  338. do {
  339. rbuffer.reset();
  340. fill_some(rbuffer, socknum);
  341. char *bptr = rbuffer.get_ptr(0);
  342. clen = rbuffer.get_length();
  343. clen = std::min(clen, rlen);
  344. r.append(bptr, clen);
  345. rlen -= clen;
  346. } while (rlen > 0);
  347. rbuffer.consume(clen);
  348. return r;
  349. }
  350. // Get the service description directories configured for the daemon as a vector of strings.
  351. // throws: dinit_unknown_sd_conf, dinit_protocol_error, cp_read_exception, cp_write_exception
  352. inline std::vector<std::string> get_service_description_dirs(int socknum, cpbuffer_t &rbuffer)
  353. {
  354. using namespace std;
  355. char buf[1] = { (char)cp_cmd::QUERY_LOAD_MECH };
  356. write_all_x(socknum, buf, 1);
  357. wait_for_reply(rbuffer, socknum);
  358. if (rbuffer[0] != (char)cp_rply::LOADER_MECH) {
  359. throw dinit_protocol_error();
  360. }
  361. // Packet type, load mechanism type, packet size:
  362. fill_buffer_to(rbuffer, socknum, 2 + sizeof(uint32_t));
  363. if (rbuffer[1] != SSET_TYPE_DIRLOAD) {
  364. throw dinit_unknown_sd_conf();
  365. }
  366. vector<string> paths;
  367. uint32_t pktsize;
  368. rbuffer.extract(&pktsize, 2, sizeof(uint32_t));
  369. fill_buffer_to(rbuffer, socknum, 2 + sizeof(uint32_t) * 3); // path entries, cwd length
  370. uint32_t path_entries; // number of service directories
  371. rbuffer.extract(&path_entries, 2 + sizeof(uint32_t), sizeof(uint32_t));
  372. uint32_t cwd_len;
  373. rbuffer.extract(&cwd_len, 2 + sizeof(uint32_t) * 2, sizeof(uint32_t));
  374. rbuffer.consume(2 + sizeof(uint32_t) * 3);
  375. pktsize -= 2 + sizeof(uint32_t) * 3;
  376. // Read current working directory of daemon:
  377. std::string dinit_cwd = read_string(socknum, rbuffer, cwd_len);
  378. // dinit daemon base directory against which service paths are resolved is in dinit_cwd
  379. for (uint32_t i = 0; i < path_entries; ++i) {
  380. uint32_t plen;
  381. fill_buffer_to(rbuffer, socknum, sizeof(uint32_t));
  382. rbuffer.extract(&plen, 0, sizeof(uint32_t));
  383. rbuffer.consume(sizeof(uint32_t));
  384. //paths.push_back(read_string(socknum, rbuffer, plen));
  385. string sd_rel_path = read_string(socknum, rbuffer, plen);
  386. paths.push_back(combine_paths(dinit_cwd, sd_rel_path.c_str()));
  387. }
  388. return paths;
  389. }