in hadoop-yarn-project/hadoop-yarn/hadoop-yarn-server/hadoop-yarn-server-nodemanager/src/main/native/container-executor/impl/container-executor.c [1533:1752]
int exec_container(const char *command_file) {
int exit_code = -1;
struct configuration command_config = {0, NULL};
char **args = NULL;
char **env = NULL;
char *workdir = NULL;
char *docker_binary = get_docker_binary(&CFG);
char *binary = NULL;
int fdm, fds, rc;
char input[4000];
int docker = 0;
char *user = NULL;
int ret = read_config(command_file, &command_config);
if (ret != 0) {
free_configuration(&command_config);
free(docker_binary);
return INVALID_DOCKER_COMMAND_FILE;
}
char *value = get_configuration_value("docker-command", DOCKER_COMMAND_FILE_SECTION, &command_config);
if (value != NULL && strcasecmp(value, "exec") == 0) {
args = construct_docker_command(command_file);
binary = strdup(docker_binary);
docker = 1;
} else {
value = get_configuration_value("command", COMMAND_FILE_SECTION, &command_config);
if (value != NULL && strcasecmp(value, "exec") == 0) {
args = get_configuration_values_delimiter("launch-command",
COMMAND_FILE_SECTION, &command_config, ",");
if (args == NULL) {
goto cleanup;
}
binary = strdup(args[0]);
workdir = get_configuration_value("workdir", COMMAND_FILE_SECTION, &command_config);
if (workdir == NULL) {
goto cleanup;
}
env = (char **) alloc_and_clear_memory(3, sizeof(char *));
env[0] = make_string("PWD=%s", workdir);
env[1] = make_string("TERM=%s", "xterm-256color");
env[2] = NULL;
user = get_configuration_value("user", COMMAND_FILE_SECTION, &command_config);
if (user == NULL) {
goto cleanup;
}
} else {
goto cleanup;
}
}
fdm = posix_openpt(O_RDWR);
if (fdm < 0) {
fprintf(stderr, "Error %d on posix_openpt()\n", errno);
exit_code = DOCKER_EXEC_FAILED;
goto cleanup;
}
rc = grantpt(fdm);
if (rc != 0) {
fprintf(stderr, "Error %d on grantpt()\n", errno);
exit_code = DOCKER_EXEC_FAILED;
goto cleanup;
}
rc = unlockpt(fdm);
if (rc != 0) {
fprintf(stderr, "Error %d on unlockpt()\n", errno);
exit_code = DOCKER_EXEC_FAILED;
goto cleanup;
}
// Open the slave PTY
fds = open(ptsname(fdm), O_RDWR);
// Creation of a child process
if (fork()) {
fd_set fd_in;
// Parent
// Close the slave side of the PTY
close(fds);
while (1) {
// Wait for data from standard input and master side of PTY
FD_ZERO(&fd_in);
FD_SET(0, &fd_in);
FD_SET(fdm, &fd_in);
rc = select(fdm + 1, &fd_in, NULL, NULL, NULL);
switch(rc) {
case -1 : fprintf(stderr, "Error %d on select()\n", errno);
exit(1);
default :
{
// If data on standard input
if (FD_ISSET(0, &fd_in)) {
rc = read(0, input, sizeof(input));
if (rc > 0) {
// Send data on the master side of PTY
ssize_t written = write(fdm, input, rc);
if (written == -1) {
fprintf(stderr, "Error %d writing to container.\n", errno);
exit(DOCKER_EXEC_FAILED);
}
} else {
if (rc < 0) {
fprintf(stderr, "Error %d on read standard input\n", errno);
exit(DOCKER_EXEC_FAILED);
}
}
}
// If data on master side of PTY
if (FD_ISSET(fdm, &fd_in)) {
rc = read(fdm, input, sizeof(input));
if (rc > 0) {
// Send data on standard output
ssize_t written = write(1, input, rc);
if (written == -1) {
fprintf(stderr, "Error %d writing to terminal.\n", errno);
exit(DOCKER_EXEC_FAILED);
}
} else {
if (rc < 0) {
if (errno == EIO) {
fprintf(stderr, "Remote Connection Closed.\n");
exit(0);
} else {
fprintf(stderr, "Error %d on read master PTY\n", errno);
exit(DOCKER_EXEC_FAILED);
}
}
}
}
}
} // End switch
} // End while
} else {
struct termios slave_orig_term_settings; // Saved terminal settings
struct termios new_term_settings; // Current terminal settings
// Child
// Close the master side of the PTY
close(fdm);
// Save the default parameters of the slave side of the PTY
rc = tcgetattr(fds, &slave_orig_term_settings);
// Set raw mode on the slave side of the PTY
new_term_settings = slave_orig_term_settings;
cfmakeraw (&new_term_settings);
if (!docker) {
new_term_settings.c_lflag |= ECHO;
}
tcsetattr (fds, TCSANOW, &new_term_settings);
// The slave side of the PTY becomes the standard input and outputs of the child process
close(STDIN_FILENO); // Close standard input (current terminal)
close(STDOUT_FILENO); // Close standard output (current terminal)
close(STDERR_FILENO); // Close standard error (current terminal)
if (dup(fds) == -1) {
// PTY becomes standard input (0)
_exit(DOCKER_EXEC_FAILED);
}
if (dup(fds) == -1) {
// PTY becomes standard output (1)
_exit(DOCKER_EXEC_FAILED);
}
if (dup(fds) == -1) {
// PTY becomes standard error (2)
_exit(DOCKER_EXEC_FAILED);
}
// Now the original file descriptor is useless
close(fds);
// Make the current process a new session leader
if (docker) {
setsid();
} else {
exit_code = set_user(user);
if (exit_code != 0) {
_exit(exit_code);
}
}
// As the child is a session leader, set the controlling terminal to be the slave side of the PTY
// (Mandatory for programs like the shell to make them manage correctly their outputs)
ioctl(0, TIOCSCTTY, 1);
if (docker) {
ret = execvp(binary, args);
fprintf(ERRORFILE, "exec failed - %s\n", strerror(errno));
_exit(DOCKER_EXEC_FAILED);
} else {
if (change_user(user_detail->pw_uid, user_detail->pw_gid) != 0) {
_exit(DOCKER_EXEC_FAILED);
}
ret = chdir(workdir);
if (ret != 0) {
fprintf(ERRORFILE, "chdir failed - %s", strerror(errno));
_exit(DOCKER_EXEC_FAILED);
}
execve(binary, args, env);
fprintf(ERRORFILE, "exec failed - %s\n", strerror(errno));
_exit(DOCKER_EXEC_FAILED);
}
}
cleanup:
free(docker_binary);
free(binary);
free(user);
free(workdir);
free_values(args);
free_values(env);
free_configuration(&command_config);
return exit_code; // we reach this point only if an error occurs
}