Esempio n. 1
0
FILE *LightProcess::LightPopenImpl(const char *cmd, const char *type,
                                   const char *cwd) {
  int id = GetId();
  Lock lock(g_procs[id].m_procMutex);

  auto fout = g_procs[id].m_afdt_fd;
  lwp_write(fout, "popen");
  lwp_write(fout, type);
  lwp_write(fout, cmd);
  lwp_write(fout, cwd ? cwd : "");

  std::string buf;
  auto fin = g_procs[id].m_afdt_fd;
  lwp_read(fin, buf);
  if (buf == "error") {
    return nullptr;
  }

  int64_t fptr = 0;
  lwp_read_int64(fin, fptr);
  if (!fptr) {
    Logger::Error("Light process failed to return the file pointer.");
    return nullptr;
  }

  int fd = recv_fd(fin);
  if (fd < 0) {
    Logger::Error("Light process failed to send the file descriptor.");
    return nullptr;
  }
  FILE *f = fdopen(fd, type);
  g_procs[id].m_popenMap[(int64_t)f] = fptr;

  return f;
}
Esempio n. 2
0
void LightProcess::ChangeUser(const std::string &username) {
  if (username.empty()) return;
  for (int i = 0; i < g_procsCount; i++) {
    Lock lock(g_procs[i].m_procMutex);
    auto fout = g_procs[i].m_afdt_fd;
    lwp_write(fout, "change_user");
    lwp_write(fout, username);
  }
}
Esempio n. 3
0
pid_t do_proc_open_helper(int afdt_fd) {
  std::string cmd, cwd;
  std::vector<std::string> env;
  std::vector<int> pvals;
  lwp_read(afdt_fd, cmd, cwd, env, pvals);

  std::vector<int> pkeys;
  for (int i = 0; i < pvals.size(); i++) {
    int fd = recv_fd(afdt_fd);
    if (fd < 0) {
      lwp_write(afdt_fd, "error", (int32_t)EPROTO);
      close_fds(pkeys);
      return -1;
    }
    pkeys.push_back(fd);
  }

  // indicate error if an empty command was received
  if (cmd.length() == 0) {
    lwp_write(afdt_fd, "error", (int32_t)ENOENT);
    return -1;
  }

  // now ready to start the child process
  pid_t child = fork();
  if (child == 0) {
    mprotect_1g_pages(PROT_READ);
    Process::OOMScoreAdj(1000);
    for (int i = 0; i < pvals.size(); i++) {
      dup2(pkeys[i], pvals[i]);
    }
    if (!cwd.empty() && chdir(cwd.c_str())) {
      // non-zero for error
      // chdir failed, the working directory remains unchanged
    }
    if (!env.empty()) {
      char **envp = build_envp(env);
      execle("/bin/sh", "sh", "-c", cmd.c_str(), nullptr, envp);
      free(envp);
    } else {
      execl("/bin/sh", "sh", "-c", cmd.c_str(), nullptr);
    }
    _Exit(HPHP_EXIT_FAILURE);
  }

  if (child > 0) {
    // successfully created the child process
    lwp_write(afdt_fd, "success", child);
  } else {
    // failed creating the child process
    lwp_write(afdt_fd, "error", errno);
  }

  close_fds(pkeys);
  return child;
}
Esempio n. 4
0
pid_t LightProcess::proc_open(const char *cmd, const std::vector<int> &created,
                              const std::vector<int> &desired,
                              const char *cwd,
                              const std::vector<std::string> &env) {
  int id = GetId();
  Lock lock(g_procs[id].m_procMutex);
  always_assert(Available());
  always_assert(created.size() == desired.size());

  auto fout = g_procs[id].m_afdt_fd;
  lwp_write(fout, "proc_open");
  lwp_write(fout, cmd);
  lwp_write(fout, cwd ? cwd : "");
  lwp_write_int32(fout, (int)env.size());
  for (unsigned int i = 0; i < env.size(); i++) {
    lwp_write(fout, env[i]);
  }

  lwp_write_int32(fout, (int)created.size());
  for (unsigned int i = 0; i < desired.size(); i++) {
    lwp_write_int32(fout, desired[i]);
  }

  bool error_send = false;
  int save_errno = 0;
  for (unsigned int i = 0; i < created.size(); i++) {
    if (!send_fd(g_procs[id].m_afdt_fd, created[i])) {
      error_send = true;
      save_errno = errno;
      break;
    }
  }

  std::string buf;
  auto fin = g_procs[id].m_afdt_fd;
  lwp_read(fin, buf);
  if (buf == "error") {
    lwp_read_int32(fin, errno);
    if (error_send) {
      // On this error, the receiver side returns dummy errno,
      // use the sender side errno here.
      errno = save_errno;
    }
    return -1;
  }
  always_assert_flog(buf == "success",
                     "Unexpected message from light process: `{}'", buf);
  int64_t pid = -1;
  lwp_read_int64(fin, pid);
  always_assert(pid);
  return (pid_t)pid;
}
Esempio n. 5
0
pid_t LightProcess::waitpid(pid_t pid, int *stat_loc, int options,
                            int timeout) {
  if (!Available()) {
    // light process is not really there
    return ::waitpid(pid, stat_loc, options);
  }

  int id = GetId();
  Lock lock(g_procs[id].m_procMutex);

  auto fout = g_procs[id].m_afdt_fd;
  lwp_write(fout, "waitpid");
  lwp_write_int64(fout, (int64_t)pid);
  lwp_write_int32(fout, options);
  lwp_write_int32(fout, timeout);

  int64_t ret;
  int stat;
  auto fin = g_procs[id].m_afdt_fd;
  lwp_read_int64(fin, ret);
  lwp_read_int32(fin, stat);

  *stat_loc = stat;
  if (ret < 0) {
    lwp_read_int32(fin, errno);
  }
  return (pid_t)ret;
}
Esempio n. 6
0
int LightProcess::pclose(FILE *f) {
  if (!Available()) {
    return ::pclose(f);
  }

  int id = GetId();
  Lock lock(g_procs[id].m_procMutex);

  std::map<int64_t, int64_t>::iterator it = g_procs[id].m_popenMap.find((int64_t)f);
  if (it == g_procs[id].m_popenMap.end()) {
    // try to close it with normal pclose
    return ::pclose(f);
  }

  int64_t f2 = it->second;
  g_procs[id].m_popenMap.erase((int64_t)f);
  fclose(f);

  lwp_write(g_procs[id].m_afdt_fd, "pclose");
  lwp_write_int64(g_procs[id].m_afdt_fd, f2);

  int ret = -1;
  lwp_read_int32(g_procs[id].m_afdt_fd, ret);
  if (ret < 0) {
    lwp_read_int32(g_procs[id].m_afdt_fd, errno);
  }
  return ret;
}
Esempio n. 7
0
static void do_popen(int afdt_fd) {
  std::string buf;
  std::string cwd;

  lwp_read(afdt_fd, buf);
  bool read_only = (buf[0] == 'r');

  lwp_read(afdt_fd, buf);

  std::string old_cwd;
  lwp_read(afdt_fd, cwd);

  if (!cwd.empty()) {
    old_cwd = Process::GetCurrentDirectory();
    if (old_cwd != cwd) {
      if (chdir(cwd.c_str())) {
        // Ignore chdir failures, because the compiled version might not
        // have the directory any more.
        Logger::Warning("Light Process failed chdir to %s.", cwd.c_str());
      }
    }
  }

  FILE *f = buf[0] ? ::popen(buf.c_str(), read_only ? "r" : "w") : nullptr;

  if (!old_cwd.empty() && chdir(old_cwd.c_str())) {
    // only here if we can't change the cwd back
  }

  if (f == nullptr) {
    Logger::Error("Light process failed popen: %d (%s).", errno,
                  folly::errnoStr(errno).c_str());
    lwp_write(afdt_fd, "error");
  } else {
    lwp_write(afdt_fd, "success");
    lwp_write_int64(afdt_fd, (int64_t)f);
    int fd = fileno(f);
    send_fd(afdt_fd, fd);
  }
}
Esempio n. 8
0
void LightProcess::closeShadow() {
  Lock lock(m_procMutex);
  if (m_shadowProcess) {
    lwp_write(m_afdt_fd, "exit");
    // removes the "zombie" process, so not to interfere with later waits
    ::waitpid(m_shadowProcess, nullptr, 0);
  }
  if (m_afdt_fd >= 0) {
    ::close(m_afdt_fd);
    m_afdt_fd = -1;
  }
  m_shadowProcess = 0;
}
Esempio n. 9
0
pid_t do_popen_helper(int afdt_fd) {
  std::string mode, buf, cwd;

  lwp_read(afdt_fd, mode, buf, cwd);

  std::string old_cwd;

  if (!cwd.empty()) {
    old_cwd = Process::GetCurrentDirectory();
    if (old_cwd != cwd) {
      if (chdir(cwd.c_str())) {
        // Ignore chdir failures, because the compiled version might not
        // have the directory any more.
        Logger::Warning("Light Process failed chdir to %s.", cwd.c_str());
      }
    }
  }

  pid_t pid;

  auto fd = buf.empty() ? -1 :
    popen_impl(buf.c_str(), mode.c_str(), &pid);

  if (!old_cwd.empty() && chdir(old_cwd.c_str())) {
    // only here if we can't change the cwd back
  }

  if (fd < 0) {
    Logger::Error("Light process failed popen: %d (%s).", errno,
                  folly::errnoStr(errno).c_str());
    lwp_write(afdt_fd, "error");
  } else {
    lwp_write(afdt_fd, "success", pid);
    send_fd(afdt_fd, fd);
    // the fd is now owned by the main process, close our copy
    close(fd);
  }
  return pid;
}
Esempio n. 10
0
void do_waitpid(int afdt_fd) {
  pid_t pid = -1;
  int options = 0;
  int timeout = 0;
  lwp_read(afdt_fd, pid, options, timeout);

  int stat;
  if (timeout > 0) {
    waited = pid;
    signal(SIGALRM, kill_handler);
    alarm(timeout);
  }

  rusage ru;
  int64_t time_us = 0;
  const auto ret = ::wait4(pid, &stat, options, &ru);
  alarm(0); // cancel the previous alarm if not triggered yet
  waited = 0;
  int64_t events[] = { 0, 0, 0 };
  if (ret > 0 && s_trackProcessTimes) {
    time_us = ru2microseconds(ru);
    auto it = s_pidToHCWMap.find(ret);
    if (it == s_pidToHCWMap.end()) {
      throw Exception("pid not in map: %s",
                      folly::errnoStr(errno).c_str());
    }

    auto hcw = std::move(it->second);
    s_pidToHCWMap.erase(it);
    hcw->events = events;
    hcw->barrier.wait();
    pthread_join(hcw->thr, nullptr);
  }

  lwp_write(afdt_fd, ret, errno, stat,
            time_us, events[0], events[1], events[2]);
}
Esempio n. 11
0
/*
 * This procedure writes a list of type 'listt' according to the
 * rds interface protocol. It uses the already opened and initialized
 * protocol module (see file protocol.[c,h]).
 * param listt	- the type of the list, see rdimpl.h
 * param Po	- print option, if 1 the list will be also printed on stdout.
 * return 0, or -1 on error and store the error message in
 *		the global buffer 'errmsg'.
 */
int
list_write(int listt, int Po)
{
	char		idstr[P_MAXVAL];
	list_t 		*list;
	id_info_t	*id = NULL, *nextid;

	if (listt == L_LWP) {
		return (lwp_write(&lwps));
	} else if (listt == L_SYSTEM) {
		if (wr_lhead(listt, 1) != 0) {
			format_err(
				"RDS protocol error: cannot write list header");
			return (-1);
		}
		(void) snprintf(idstr, sizeof (idstr), "%s", sys_info.name);
		if (wr_element(listt, (char *)(&sys_info), idstr) != 0) {
			format_err(
				"RDS protocol error: cannot write list header");
			return (-1);
		}

	} else {
		switch (listt) {
		case L_PRC_SI : list =  &processes;
				break;
		case L_AC_USR :
		case L_USR_SI : list =  &users;
				break;
		case L_AC_PRJ :
		case L_PRJ_SI : list =  &projects;
				break;
		}
		id = list->l_head;

		if (wr_lhead(listt, list->l_count) != 0) {
			format_err(
				"RDS protocol error: cannot write list header");
			return (-1);
		}
		while (id != NULL) {
			switch (listt) {
			case L_PRC_SI :
				(void) sprintf(idstr, "%d", id->id_pid);
				break;
			case L_AC_USR :
			case L_USR_SI :
				(void) sprintf(idstr, "%d", id->id_uid);
				break;
			case L_AC_PRJ :
			case L_PRJ_SI :
				(void) snprintf(idstr, sizeof (idstr), "%s",
				    id->id_name);
				break;
			}
			if (wr_element(listt, (char *)id, idstr) != 0) {
					format_err(
				"RDS protocol error: cannot write list header");
			}
			if (Po == 1)
				prtelement(stderr, id);
			nextid = id->id_next;
			id = nextid;
		}
	}
	return (0);
}
Esempio n. 12
0
static void do_proc_open(int afdt_fd) {
  std::string cmd;
  lwp_read(afdt_fd, cmd);

  std::string cwd;
  lwp_read(afdt_fd, cwd);

  std::string buf;
  int env_size = 0;
  std::vector<std::string> env;
  lwp_read_int32(afdt_fd, env_size);
  for (int i = 0; i < env_size; i++) {
    lwp_read(afdt_fd, buf);
    env.push_back(buf);
  }

  int pipe_size = 0;
  lwp_read_int32(afdt_fd, pipe_size);
  std::vector<int> pvals;
  for (int i = 0; i < pipe_size; i++) {
    int fd_value;
    lwp_read_int32(afdt_fd, fd_value);
    pvals.push_back(fd_value);
  }

  std::vector<int> pkeys;
  for (int i = 0; i < pipe_size; i++) {
    int fd = recv_fd(afdt_fd);
    if (fd < 0) {
      lwp_write(afdt_fd, "error");
      lwp_write_int32(afdt_fd, EPROTO);
      close_fds(pkeys);
      return;
    }
    pkeys.push_back(fd);
  }

  // indicate error if an empty command was received
  if (cmd.length() == 0) {
    lwp_write(afdt_fd, "error");
    lwp_write_int32(afdt_fd, ENOENT);
    return;
  }

  // now ready to start the child process
  pid_t child = fork();
  if (child == 0) {
    for (int i = 0; i < pipe_size; i++) {
      dup2(pkeys[i], pvals[i]);
    }
    if (!cwd.empty() && chdir(cwd.c_str())) {
      // non-zero for error
      // chdir failed, the working directory remains unchanged
    }
    if (!env.empty()) {
      char **envp = build_envp(env);
      execle("/bin/sh", "sh", "-c", cmd.c_str(), nullptr, envp);
      free(envp);
    } else {
      execl("/bin/sh", "sh", "-c", cmd.c_str(), nullptr);
    }
    _Exit(HPHP_EXIT_FAILURE);
  } else if (child > 0) {
    // successfully created the child process
    lwp_write(afdt_fd, "success");
    lwp_write_int64(afdt_fd, (int64_t)child);
  } else {
    // failed creating the child process
    lwp_write(afdt_fd, "error");
    lwp_write_int32(afdt_fd, errno);
  }

  close_fds(pkeys);
}