PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/util/light_process.cpp

https://github.com/zsj888/hiphop-php
C++ | 601 lines | 481 code | 82 blank | 38 comment | 108 complexity | 24071e7d251ecb0d810b8dbc3c173aef MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #include "light_process.h"
  17. #include "process.h"
  18. #include "util.h"
  19. #include <afdt.h>
  20. #include <string>
  21. #include <vector>
  22. #include <stdlib.h>
  23. #include <unistd.h>
  24. #include <sys/wait.h>
  25. #include <poll.h>
  26. #include <pwd.h>
  27. using namespace std;
  28. namespace HPHP {
  29. ///////////////////////////////////////////////////////////////////////////////
  30. // helper functions
  31. static const unsigned int BUFFER_SIZE = 4096;
  32. Mutex LightProcess::s_mutex;
  33. static void read_buf(FILE *fin, char *buf) {
  34. if (!fgets(buf, BUFFER_SIZE, fin)) {
  35. buf[0] = '\0';
  36. return;
  37. }
  38. // get rid of '\n'
  39. buf[strlen(buf) - 1] = '\0';
  40. }
  41. static bool send_fd(int afdt_fd, int fd) {
  42. afdt_error_t err;
  43. int ret = afdt_send_fd_msg(afdt_fd, 0, 0, fd, &err);
  44. return ret >= 0;
  45. }
  46. static int recv_fd(int afdt_fd) {
  47. int fd;
  48. afdt_error_t err;
  49. uint8_t afdt_buf[AFDT_MSGLEN];
  50. uint32_t afdt_len;
  51. if (afdt_recv_fd_msg(afdt_fd, afdt_buf, &afdt_len, &fd, &err) < 0) {
  52. return -1;
  53. }
  54. return fd;
  55. }
  56. static char **build_envp(const vector<string> &env) {
  57. char **envp = NULL;
  58. int size = env.size();
  59. if (size) {
  60. envp = (char **)malloc((size + 1) * sizeof(char *));
  61. int j = 0;
  62. for (unsigned int i = 0; i < env.size(); i++, j++) {
  63. *(envp + j) = (char *)env[i].c_str();
  64. }
  65. *(envp + j) = NULL;
  66. }
  67. return envp;
  68. }
  69. static void close_fds(const vector<int> &fds) {
  70. for (unsigned int i = 0; i < fds.size(); i++) {
  71. ::close(fds[i]);
  72. }
  73. }
  74. ///////////////////////////////////////////////////////////////////////////////
  75. // shadow process tasks
  76. static void do_popen(FILE *fin, FILE *fout, int afdt_fd) {
  77. char buf[BUFFER_SIZE];
  78. char cwd[BUFFER_SIZE];
  79. if (!fgets(buf, BUFFER_SIZE, fin)) buf[0] = '\0';
  80. bool read_only = (buf[0] == 'r');
  81. read_buf(fin, buf);
  82. string old_cwd = Process::GetCurrentDirectory();
  83. read_buf(fin, cwd);
  84. if (old_cwd != cwd) {
  85. chdir(cwd);
  86. }
  87. FILE *f = buf[0] ? ::popen(buf, read_only ? "r" : "w") : NULL;
  88. if (old_cwd != cwd) {
  89. chdir(old_cwd.c_str());
  90. }
  91. if (f == NULL) {
  92. // no need to send the errno back, as the main process will try ::popen
  93. fprintf(fout, "error\n");
  94. fflush(fout);
  95. } else {
  96. fprintf(fout, "success\n%lld\n", (int64)f);
  97. fflush(fout);
  98. int fd = fileno(f);
  99. send_fd(afdt_fd, fd);
  100. }
  101. }
  102. static void do_pclose(FILE *fin, FILE *fout) {
  103. char buf[BUFFER_SIZE];
  104. int64 fptr = 0;
  105. read_buf(fin, buf);
  106. sscanf(buf, "%lld", &fptr);
  107. FILE *f = (FILE *)fptr;
  108. int ret = ::pclose(f);
  109. fprintf(fout, "%d\n", ret);
  110. if (ret < 0) {
  111. fprintf(fout, "%d\n", errno);
  112. }
  113. fflush(fout);
  114. }
  115. static void do_proc_open(FILE *fin, FILE *fout, int afdt_fd) {
  116. char cmd[BUFFER_SIZE];
  117. read_buf(fin, cmd);
  118. if (strlen(cmd) == 0) {
  119. fprintf(fout, "error\n%d\n", ENOENT);
  120. fflush(fout);
  121. return;
  122. }
  123. char cwd[BUFFER_SIZE];
  124. read_buf(fin, cwd);
  125. char buf[BUFFER_SIZE];
  126. int env_size = 0;
  127. vector<string> env;
  128. read_buf(fin, buf);
  129. sscanf(buf, "%d", &env_size);
  130. for (int i = 0; i < env_size; i++) {
  131. read_buf(fin, buf);
  132. env.push_back(buf);
  133. }
  134. int pipe_size = 0;
  135. read_buf(fin, buf);
  136. sscanf(buf, "%d", &pipe_size);
  137. vector<int> pvals;
  138. for (int i = 0; i < pipe_size; i++) {
  139. int fd_value;
  140. read_buf(fin, buf);
  141. sscanf(buf, "%d", &fd_value);
  142. pvals.push_back(fd_value);
  143. }
  144. vector<int> pkeys;
  145. for (int i = 0; i < pipe_size; i++) {
  146. int fd = recv_fd(afdt_fd);
  147. if (fd < 0) {
  148. fprintf(fout, "error\n%d\n", errno);
  149. fflush(fout);
  150. close_fds(pkeys);
  151. return;
  152. }
  153. pkeys.push_back(fd);
  154. }
  155. // now ready to start the child process
  156. pid_t child = fork();
  157. if (child == 0) {
  158. for (int i = 0; i < pipe_size; i++) {
  159. dup2(pkeys[i], pvals[i]);
  160. }
  161. if (strlen(cwd) > 0) {
  162. if (chdir(cwd)) { // non-zero for error
  163. fprintf(fout, "error\n%d\n", errno);
  164. fflush(fout);
  165. close_fds(pkeys);
  166. return;
  167. }
  168. }
  169. if (!env.empty()) {
  170. char **envp = build_envp(env);
  171. execle("/bin/sh", "sh", "-c", cmd, NULL, envp);
  172. free(envp);
  173. } else {
  174. execl("/bin/sh", "sh", "-c", cmd, NULL);
  175. }
  176. _exit(127);
  177. } else if (child > 0) {
  178. // successfully created the child process
  179. fprintf(fout, "%lld\n", (int64)child);
  180. fflush(fout);
  181. } else {
  182. // failed creating the child process
  183. fprintf(fout, "error\n%d\n", errno);
  184. fflush(fout);
  185. }
  186. close_fds(pkeys);
  187. }
  188. static void do_waitpid(FILE *fin, FILE *fout) {
  189. char buf[BUFFER_SIZE];
  190. read_buf(fin, buf);
  191. int64 p = -1;
  192. int options = 0;
  193. sscanf(buf, "%lld %d", &p, &options);
  194. pid_t pid = (pid_t)p;
  195. int stat;
  196. pid_t ret = ::waitpid(pid, &stat, options);
  197. fprintf(fout, "%lld %d\n", (int64)ret, stat);
  198. if (ret < 0) {
  199. fprintf(fout, "%d\n", errno);
  200. }
  201. fflush(fout);
  202. }
  203. static void do_change_user(FILE *fin, FILE *fout) {
  204. char uname[BUFFER_SIZE];
  205. read_buf(fin, uname);
  206. if (strlen(uname) > 0) {
  207. struct passwd *pw = getpwnam(uname);
  208. if (pw && pw->pw_uid) {
  209. setuid(pw->pw_uid);
  210. }
  211. }
  212. }
  213. ///////////////////////////////////////////////////////////////////////////////
  214. // light-weight process
  215. static vector<LightProcess> g_procs;
  216. LightProcess::LightProcess()
  217. : m_shadowProcess(0), m_fin(NULL), m_fout(NULL), m_afdt_fd(-1) { }
  218. LightProcess::~LightProcess() {
  219. }
  220. void LightProcess::Initialize(const std::string &prefix, int count) {
  221. if (prefix.empty() || count <= 0) {
  222. return;
  223. }
  224. if (Available()) {
  225. // already initialized
  226. return;
  227. }
  228. g_procs.resize(count);
  229. for (int i = 0; i < count; i++) {
  230. if (!g_procs[i].initShadow(prefix, i)) {
  231. for (int j = 0; j < i; j++) {
  232. g_procs[j].closeShadow();
  233. }
  234. g_procs.clear();
  235. break;
  236. }
  237. }
  238. }
  239. bool LightProcess::initShadow(const std::string &prefix, int id) {
  240. Lock lock(m_procMutex);
  241. ostringstream os;
  242. os << prefix << "." << getpid() << "." << id;
  243. m_afdtFilename = os.str();
  244. // remove the possible leftover
  245. remove(m_afdtFilename.c_str());
  246. afdt_error_t err;
  247. int lfd = afdt_listen(m_afdtFilename.c_str(), &err);
  248. if (lfd < 0) {
  249. Logger::Warning("Unable to afdt_listen");
  250. return false;
  251. }
  252. CPipe p1, p2;
  253. if (!p1.open() || !p2.open()) {
  254. Logger::Warning("Unable to create pipe: %d %s", errno,
  255. Util::safe_strerror(errno).c_str());
  256. return false;
  257. }
  258. pid_t child = fork();
  259. if (child == 0) {
  260. // child
  261. pid_t sid = setsid();
  262. if (sid < 0) {
  263. Logger::Warning("Unable to setsid");
  264. exit(-1);
  265. }
  266. m_afdt_fd =
  267. afdt_connect(m_afdtFilename.c_str(), &err);
  268. if (m_afdt_fd < 0) {
  269. Logger::Warning("Unable to afdt_connect");
  270. exit(-1);
  271. }
  272. int fd1 = p1.detachOut();
  273. int fd2 = p2.detachIn();
  274. p1.close();
  275. p2.close();
  276. runShadow(fd1, fd2);
  277. } else if (child < 0) {
  278. // failed
  279. Logger::Warning("Unable to fork lightly: %d %s", errno,
  280. Util::safe_strerror(errno).c_str());
  281. return false;
  282. } else {
  283. // parent
  284. m_fin = fdopen(p2.detachOut(), "r");
  285. m_fout = fdopen(p1.detachIn(), "w");
  286. m_shadowProcess = child;
  287. sockaddr addr;
  288. socklen_t addrlen;
  289. m_afdt_fd = accept(lfd, &addr, &addrlen);
  290. if (m_afdt_fd < 0) {
  291. Logger::Warning("Unable to establish afdt connection");
  292. closeShadow();
  293. return false;
  294. }
  295. }
  296. return true;
  297. }
  298. void LightProcess::Close() {
  299. for (unsigned int i = 0; i < g_procs.size(); i++) {
  300. g_procs[i].closeShadow();
  301. }
  302. g_procs.clear();
  303. }
  304. void LightProcess::closeShadow() {
  305. Lock lock(m_procMutex);
  306. if (m_shadowProcess) {
  307. fprintf(m_fout, "exit\n");
  308. fflush(m_fout);
  309. fclose(m_fin);
  310. fclose(m_fout);
  311. // removes the "zombie" process, so not to interfere with later waits
  312. ::waitpid(m_shadowProcess, NULL, 0);
  313. }
  314. if (!m_afdtFilename.empty()) {
  315. remove(m_afdtFilename.c_str());
  316. }
  317. if (m_afdt_fd >= 0) {
  318. ::close(m_afdt_fd);
  319. m_afdt_fd = -1;
  320. }
  321. m_shadowProcess = 0;
  322. }
  323. bool LightProcess::Available() {
  324. return !g_procs.empty();
  325. }
  326. void LightProcess::runShadow(int fdin, int fdout) {
  327. FILE *fin = fdopen(fdin, "r");
  328. FILE *fout = fdopen(fdout, "w");
  329. char buf[BUFFER_SIZE];
  330. pollfd pfd[1];
  331. pfd[0].fd = fdin;
  332. pfd[0].events = POLLIN;
  333. while (true) {
  334. poll(pfd, 1, -1);
  335. if (pfd[0].revents & POLLHUP) {
  336. // no more command can come in
  337. break;
  338. }
  339. else if (pfd[0].revents & POLLIN) {
  340. if (!fgets(buf, BUFFER_SIZE, fin)) buf[0] = '\0';
  341. if (strncmp(buf, "exit", 4) == 0) {
  342. break;
  343. } else if (strncmp(buf, "popen", 5) == 0) {
  344. do_popen(fin, fout, m_afdt_fd);
  345. } else if (strncmp(buf, "pclose", 6) == 0) {
  346. do_pclose(fin, fout);
  347. } else if (strncmp(buf, "proc_open", 9) == 0) {
  348. do_proc_open(fin, fout, m_afdt_fd);
  349. } else if (strncmp(buf, "waitpid", 7) == 0) {
  350. do_waitpid(fin, fout);
  351. } else if (strncmp(buf, "change_user", 11) == 0) {
  352. do_change_user(fin, fout);
  353. }
  354. }
  355. }
  356. fclose(fin);
  357. fclose(fout);
  358. ::close(m_afdt_fd);
  359. remove(m_afdtFilename.c_str());
  360. exit(0);
  361. }
  362. int LightProcess::GetId() {
  363. return (int)pthread_self() % g_procs.size();
  364. }
  365. FILE *LightProcess::popen(const char *cmd, const char *type,
  366. const char *cwd /* = NULL */) {
  367. if (!Available()) {
  368. // fallback to normal popen
  369. Logger::Verbose("Light-weight fork not available; "
  370. "use the heavy one instead.");
  371. } else {
  372. FILE *f = LightPopenImpl(cmd, type, cwd);
  373. if (f) {
  374. return f;
  375. }
  376. Logger::Verbose("Light-weight fork failed; use the heavy one instead.");
  377. }
  378. return HeavyPopenImpl(cmd, type, cwd);
  379. }
  380. FILE *LightProcess::HeavyPopenImpl(const char *cmd, const char *type,
  381. const char *cwd) {
  382. if (cwd && *cwd) {
  383. string old_cwd = Process::GetCurrentDirectory();
  384. if (old_cwd != cwd) {
  385. Lock lock(s_mutex);
  386. chdir(cwd);
  387. FILE *f = ::popen(cmd, type);
  388. chdir(old_cwd.c_str());
  389. return f;
  390. }
  391. }
  392. return ::popen(cmd, type);
  393. }
  394. FILE *LightProcess::LightPopenImpl(const char *cmd, const char *type,
  395. const char *cwd) {
  396. int id = GetId();
  397. Lock lock(g_procs[id].m_procMutex);
  398. fprintf(g_procs[id].m_fout, "popen\n%s\n%s\n%s\n", type, cmd, cwd);
  399. fflush(g_procs[id].m_fout);
  400. char buf[BUFFER_SIZE];
  401. read_buf(g_procs[id].m_fin, buf);
  402. if (strncmp(buf, "error", 5) == 0) {
  403. return NULL;
  404. }
  405. int64 fptr = 0;
  406. read_buf(g_procs[id].m_fin, buf);
  407. sscanf(buf, "%lld", &fptr);
  408. if (!fptr) {
  409. return NULL;
  410. }
  411. int fd = recv_fd(g_procs[id].m_afdt_fd);
  412. if (fd < 0) {
  413. return NULL;
  414. }
  415. FILE *f = fdopen(fd, type);
  416. g_procs[id].m_popenMap[(int64)f] = fptr;
  417. return f;
  418. }
  419. int LightProcess::pclose(FILE *f) {
  420. if (!Available()) {
  421. return ::pclose(f);
  422. }
  423. int id = GetId();
  424. Lock lock(g_procs[id].m_procMutex);
  425. map<int64, int64>::iterator it = g_procs[id].m_popenMap.find((int64)f);
  426. if (it == g_procs[id].m_popenMap.end()) {
  427. // try to close it with normal pclose
  428. return ::pclose(f);
  429. }
  430. g_procs[id].m_popenMap.erase((int64)f);
  431. fclose(f);
  432. fprintf(g_procs[id].m_fout, "pclose\n%lld\n", it->second);
  433. fflush(g_procs[id].m_fout);
  434. char buf[BUFFER_SIZE];
  435. read_buf(g_procs[id].m_fin, buf);
  436. int ret = -1;
  437. sscanf(buf, "%d", &ret);
  438. if (ret < 0) {
  439. read_buf(g_procs[id].m_fin, buf);
  440. sscanf(buf, "%d", &errno);
  441. }
  442. return ret;
  443. }
  444. pid_t LightProcess::proc_open(const char *cmd, const vector<int> &created,
  445. const vector<int> &desired,
  446. const char *cwd, const vector<string> &env) {
  447. int id = GetId();
  448. Lock lock(g_procs[id].m_procMutex);
  449. assert(Available());
  450. assert(created.size() == desired.size());
  451. fprintf(g_procs[id].m_fout, "proc_open\n%s\n%s\n", cmd, cwd);
  452. fprintf(g_procs[id].m_fout, "%d\n", (int)env.size());
  453. for (unsigned int i = 0; i < env.size(); i++) {
  454. fprintf(g_procs[id].m_fout, "%s\n", env[i].c_str());
  455. }
  456. fprintf(g_procs[id].m_fout, "%d\n", (int)created.size());
  457. for (unsigned int i = 0; i < desired.size(); i++) {
  458. fprintf(g_procs[id].m_fout, "%d\n", desired[i]);
  459. }
  460. fflush(g_procs[id].m_fout);
  461. char buf[BUFFER_SIZE];
  462. for (unsigned int i = 0; i < created.size(); i++) {
  463. if (!send_fd(g_procs[id].m_afdt_fd, created[i])) break;
  464. }
  465. read_buf(g_procs[id].m_fin, buf);
  466. if (strncmp(buf, "error", 5) == 0) {
  467. read_buf(g_procs[id].m_fin, buf);
  468. sscanf(buf, "%d", &errno);
  469. return -1;
  470. }
  471. int64 pid = -1;
  472. sscanf(buf, "%lld", &pid);
  473. return (pid_t)pid;
  474. }
  475. pid_t LightProcess::waitpid(pid_t pid, int *stat_loc, int options) {
  476. if (!Available()) {
  477. // light process is not really there
  478. return ::waitpid(pid, stat_loc, options);
  479. }
  480. int id = GetId();
  481. Lock lock(g_procs[id].m_procMutex);
  482. fprintf(g_procs[id].m_fout, "waitpid\n%lld %d\n", (int64)pid, options);
  483. fflush(g_procs[id].m_fout);
  484. char buf[BUFFER_SIZE];
  485. read_buf(g_procs[id].m_fin, buf);
  486. if (!buf[0]) return -1;
  487. int64 ret;
  488. int stat;
  489. sscanf(buf, "%lld %d", &ret, &stat);
  490. *stat_loc = stat;
  491. if (ret < 0) {
  492. read_buf(g_procs[id].m_fin, buf);
  493. sscanf(buf, "%d", &errno);
  494. }
  495. return (pid_t)ret;
  496. }
  497. pid_t LightProcess::pcntl_waitpid(pid_t pid, int *stat_loc, int options) {
  498. if (!Available()) {
  499. return ::waitpid(pid, stat_loc, options);
  500. }
  501. int id = GetId();
  502. Lock lock(g_procs[id].m_procMutex);
  503. pid_t p = ::waitpid(pid, stat_loc, options);
  504. if (p == g_procs[id].m_shadowProcess) {
  505. // got the shadow process, wait again
  506. p = ::waitpid(pid, stat_loc, options);
  507. }
  508. return p;
  509. }
  510. void LightProcess::ChangeUser(const string &username) {
  511. if (username.empty()) return;
  512. for (unsigned i = 0; i < g_procs.size(); i++) {
  513. Lock lock(g_procs[i].m_procMutex);
  514. fprintf(g_procs[i].m_fout, "change_user\n%s\n", username.c_str());
  515. fflush(g_procs[i].m_fout);
  516. }
  517. }
  518. ///////////////////////////////////////////////////////////////////////////////
  519. }