Exemple #1
0
struct sio_hdl *
fdpass_sio_open(int num, unsigned int mode)
{
	int fd;

	if (!fdpass_send(fdpass_peer, FDPASS_OPEN_SND, num, mode, -1))
		return NULL;
	if (!fdpass_waitret(fdpass_peer, &fd))
		return NULL;
	if (fd < 0)
		return NULL;
	return sio_sun_fdopen(fd, mode, 1);
}
Exemple #2
0
struct mio_hdl *
fdpass_mio_open(int num, unsigned int mode)
{
	int fd;

	if (!fdpass_send(fdpass_peer, FDPASS_OPEN_MIDI, num, mode, -1))
		return NULL;
	if (!fdpass_waitret(fdpass_peer, &fd))
		return NULL;
	if (fd < 0)
		return NULL;
	return mio_rmidi_fdopen(fd, mode, 1);
}
Exemple #3
0
void
fdpass_in_helper(void *arg)
{
	int cmd, num, mode, fd;
	struct fdpass *f = arg;
	struct dev *d;
	struct port *p;

	if (!fdpass_recv(f, &cmd, &num, &mode, &fd))
		return;
	switch (cmd) {
	case FDPASS_OPEN_SND:
		d = dev_bynum(num);
		if (d == NULL || !(mode & (SIO_PLAY | SIO_REC))) {
			if (log_level >= 1) {
				fdpass_log(f);
				log_puts(": bad audio device or mode\n");
			}
			fdpass_close(f);
			return;
		}
		fd = sio_sun_getfd(d->path, mode, 1);
		break;
	case FDPASS_OPEN_MIDI:
		p = port_bynum(num);
		if (p == NULL || !(mode & (MIO_IN | MIO_OUT))) {
			if (log_level >= 1) {
				fdpass_log(f);
				log_puts(": bad midi port or mode\n");
			}
			fdpass_close(f);
			return;
		}
		fd = mio_rmidi_getfd(p->path, mode, 1);
		break;
	default:
		fdpass_close(f);
		return;
	}
	fdpass_send(f, FDPASS_RETURN, 0, 0, fd);
}
// we launch the job via a wrapper. the full chain of exec() calls looks
// like:
//
// (condor_starter)->(condor_glexec_run)->(glexec)->(condor_glexec_wrapper)->(job)
//
// glexec_wrapper serves two purposes:
//   - it allows us to pass environment variables to the job, which glexec
//     (as of 08/2008) does not support
//   - it allows us to distinguish between failures in the job and failures
//     in condor_glexec_run or glexec or condor_glexec_wrapper
//
// this function:
//   - sends the job's environment over to the wrapper's stdin (which is a
//     UNIX domain socket we set up to communicate with the wrapper)
//   - sends the job's stdin FD to the wrapper
//   - waits for an error message from the wrapper; if EOF is read first, the
//     job was successfully exec()'d
//
int
GLExecPrivSepHelper::feed_wrapper(int pid,
                                  int sock_fds[2],
                                  Env& env,
                                  int dc_job_opts,
                                  int job_std_fds[3],
								  int &glexec_err_fd,
								  MyString *error_msg,
								  int *glexec_rc)
{
	// we can now close the end of the socket that we handed down
	// to the wrapper; the other end we'll use to send stuff over
	//
	close(sock_fds[1]);

	// if pid is 0, Create_Process failed; just close the socket
	// and return
	//
	if (pid == FALSE) {
		close(sock_fds[0]);
		return pid;
	}

	unsigned int hello = 0;
	ssize_t bytes = full_read(sock_fds[0], &hello, sizeof(int));
	if (bytes != sizeof(int)) {
		dprintf(D_ALWAYS,
		        "GLEXEC: error reading hello from glexec_job_wrapper\n");
		close(sock_fds[0]);

		if( bytes <= 0 ) {
				// Since we failed to read the expected hello bytes
				// from the wrapper, this likely indicates that glexec
				// failed to execute the wrapper.  Attempt to read an
				// error message from glexec.
			MyString glexec_stderr;
			FILE *fp = fdopen(glexec_err_fd,"r");
			if( fp ) {
				while( glexec_stderr.readLine(fp,true) );
				fclose(fp);
				glexec_err_fd = -1; // fd is closed now
			}

				// Collect the exit status from glexec.  Since we
				// created this process via
				// DaemonCore::Create_Process() we could/should wait
				// for DaemonCore to reap the process.  However, given
				// the way this function is used in the starter, that
				// happens too late.
			int glexec_status = 0;
			if (waitpid(pid,&glexec_status,0)==pid) {
				if (WIFEXITED(glexec_status)) {
					int status = WEXITSTATUS(glexec_status);
					ASSERT( glexec_rc );
					*glexec_rc = status;
					dprintf(D_ALWAYS,
							"GLEXEC: glexec call exited with status %d\n",
							status);
					if( error_msg ) {
						error_msg->formatstr_cat(
							" glexec call exited with status %d",
							status);
					}
				}
				else if (WIFSIGNALED(glexec_status)) {
					int sig = WTERMSIG(glexec_status);
					dprintf(D_ALWAYS,
							"GLEXEC: glexec call exited via signal %d\n",
							sig);
					if( error_msg ) {
						error_msg->formatstr_cat(
							" glexec call exited via signal %d",
							sig);
					}
				}
			}

			if( !glexec_stderr.IsEmpty() ) {
				glexec_stderr.trim();
				StringList lines(glexec_stderr.Value(),"\n");
				lines.rewind();
				char const *line;

				if( error_msg ) {
					*error_msg += " and with error output (";
				}
				int line_count=0;
				while( (line=lines.next()) ) {
						// strip out the annoying line about pthread_mutex_init
					if( strstr(line,"It appears that the value of pthread_mutex_init") ) {
						continue;
					}
					line_count++;

					if( !glexec_stderr.IsEmpty() ) {
						glexec_stderr += "; ";
					}
					dprintf(D_ALWAYS,
							"GLEXEC: error output: %s\n",line);

					if( error_msg ) {
						if( line_count>1 ) {
							*error_msg += "; ";
						}
						*error_msg += line;
					}
				}
				if( error_msg ) {
					*error_msg += ")";
				}
			}

		}
		errno = 0; // avoid higher-level code thinking there was a syscall error
		return FALSE;
	}
	if( hello != 0xdeadbeef ) {
		dprintf(D_ALWAYS,
				"GLEXEC: did not receive expected hello from wrapper: %x\n",
				hello);
		close(sock_fds[0]);
		return FALSE;
	}

	// now send over the environment
	//
	Env env_to_send;
	if (HAS_DCJOBOPT_ENV_INHERIT(dc_job_opts)) {
		env_to_send.MergeFrom(environ);
	}
	env_to_send.MergeFrom(env);
	MyString env_str;
	MyString merge_err;
	if (!env_to_send.getDelimitedStringV2Raw(&env_str, &merge_err)) {
		dprintf(D_ALWAYS,
		        "GLEXEC: Env::getDelimitedStringV2Raw error: %s\n",
		        merge_err.Value());
		close(sock_fds[0]);
		return FALSE;
	}
	const char* env_buf = env_str.Value();
	int env_len = env_str.Length() + 1;
	errno = 0;
	if (full_write(sock_fds[0], &env_len, sizeof(env_len)) != sizeof(env_len)) {
		dprintf(D_ALWAYS,
		        "GLEXEC: error sending env size to wrapper: %s\n",
		        strerror(errno));
		close(sock_fds[0]);
		return FALSE;
	}
	errno = 0;
	if (full_write(sock_fds[0], env_buf, env_len) != env_len) {
		dprintf(D_ALWAYS,
		        "GLEXEC: error sending env to wrapper: %s\n",
		        strerror(errno));
		close(sock_fds[0]);
		return FALSE;
	}

	// now send over the FDs that the Starter should use for stdin/out/err
	//
	int i;
	for(i=0;i<3;i++) {
		int std_fd = job_std_fds[i];
		if (std_fd != -1) {
			int pipe_fd;
			if (daemonCore->Get_Pipe_FD(std_fd, &pipe_fd) == TRUE) {
				std_fd = pipe_fd;
			}
			if (fdpass_send(sock_fds[0], std_fd) == -1) {
				dprintf(D_ALWAYS, "GLEXEC: fdpass_send failed\n");
				close(sock_fds[0]);
				return FALSE;
			}
		}
	}

		// Now we do a little dance to replace the socketpair that we
		// have been using to communicate with the wrapper with a new
		// one.  Why?  Because, as of glexec 0.8, when glexec is
		// configured with linger=on, some persistent process
		// (glexec?, procd?) is keeping a handle to the wrapper's end
		// of the socket open, so the starter hangs waiting for the
		// socket to close when the job is executed.

	int old_sock_fd = sock_fds[0];
	if (socketpair(PF_UNIX, SOCK_STREAM, 0, sock_fds) == -1)
	{
		dprintf(D_ALWAYS,
		        "GLEXEC: socketpair error: %s\n",
		        strerror(errno));
		close(old_sock_fd);
		return FALSE;
	}
	if (fdpass_send(old_sock_fd, sock_fds[1]) == -1) {
		dprintf(D_ALWAYS, "GLEXEC: fdpass_send failed on new sock fd\n");
		close(old_sock_fd);
		close(sock_fds[0]);
		close(sock_fds[1]);
		return FALSE;
	}
		// close our handle to the wrapper's end of the socket
	close(sock_fds[1]);
		// close our old socket
	close(old_sock_fd);

	// now read any error messages produced by the wrapper
	//
	char err[256];
	bytes = full_read(sock_fds[0], err, sizeof(err) - 1);
	if (bytes == -1) {
		dprintf(D_ALWAYS,
		        "GLEXEC: error reading message from wrapper: %s\n",
		        strerror(errno));
		close(sock_fds[0]);
		return FALSE;
	}
	if (bytes > 0) {
		err[bytes] = '\0';
		dprintf(D_ALWAYS, "GLEXEC: error from wrapper: %s\n", err);
		if( error_msg ) {
			error_msg->formatstr_cat("glexec_job_wrapper error: %s", err);
		}
			// prevent higher-level code from thinking this was a syscall error
		errno = 0;
		return FALSE;
	}

	// if we're here, it all worked
	//
	close(sock_fds[0]);
	return pid;
}
Exemple #5
0
bool
glexec_starter_handle_env(pid_t pid)
{
    // we can now close the end of the socket that we handed down
    // to the wrapper; the other end we'll use to send stuff over
    //
    close(s_saved_sock_fds[1]);
    int sock_fd = s_saved_sock_fds[0];

    // if pid is 0, Create_Process failed; just close the socket
    // and return
    //
    if (pid == 0) {
        close(sock_fd);
        return false;
    }

    // before sending the environment, scrub some stuff that was
    // only for glexec
    //
    s_saved_env.SetEnv("GLEXEC_MODE", "");
    s_saved_env.SetEnv("GLEXEC_CLIENT_CERT", "");
    s_saved_env.SetEnv("GLEXEC_SOURCE_PROXY", "");
    s_saved_env.SetEnv("GLEXEC_TARGET_PROXY", "");

    // now send over the environment; what we send over is our own
    // environment with the stuff we added in prepareForGlexec
    // added in
    //
    Env env_to_send;
    env_to_send.MergeFrom(environ);
    env_to_send.MergeFrom(s_saved_env);
    MyString env_str;
    MyString merge_err;
    if (!env_to_send.getDelimitedStringV2Raw(&env_str, &merge_err)) {
        dprintf(D_ALWAYS,
                "GLEXEC: Env::getDelimitedStringV2Raw error: %s\n",
                merge_err.Value());
        close(sock_fd);
        return false;
    }
    const char* env_buf = env_str.Value();
    int env_len = env_str.Length() + 1;
    errno = 0;
    if (write(sock_fd, &env_len, sizeof(env_len)) != sizeof(env_len)) {
        dprintf(D_ALWAYS,
                "GLEXEC: error sending env size to wrapper: %s\n",
                strerror(errno));
        close(sock_fd);
        return false;
    }
    errno = 0;
    if (write(sock_fd, env_buf, env_len) != env_len) {
        dprintf(D_ALWAYS,
                "GLEXEC: error sending env to wrapper: %s\n",
                strerror(errno));
        close(sock_fd);
        return false;
    }

    // now send over the FD that the Starter should use for stdin, if any
    // (we send a flag whether there is an FD to send first)
    //
    int flag = (s_saved_starter_stdin != -1) ? 1 : 0;
    if (write(sock_fd, &flag, sizeof(flag)) != sizeof(flag)) {
        dprintf(D_ALWAYS,
                "GLEXEC: error sending flag to wrapper: %s\n",
                strerror(errno));
        close(sock_fd);
        return false;
    }
    if (flag) {
        int fd;
        int rv = daemonCore->Get_Pipe_FD(s_saved_starter_stdin,
                                         &fd);
        if (rv == FALSE) {
            fd = s_saved_starter_stdin;
        }
        if (fdpass_send(sock_fd, fd) == -1) {
            dprintf(D_ALWAYS, "GLEXEC: fdpass_send failed\n");
            close(sock_fd);
            return false;
        }
    }

    // now read any error messages produced by the wrapper
    //
    char err[256];
    ssize_t bytes = read(sock_fd, err, sizeof(err) - 1);
    if (bytes == -1) {
        dprintf(D_ALWAYS,
                "GLEXEC: error reading message from wrapper: %s\n",
                strerror(errno));
        close(sock_fd);
        return false;
    }
    if (bytes > 0) {
        err[bytes] = '\0';
        dprintf(D_ALWAYS, "GLEXEC: error from wrapper: %s\n", err);
        return false;
    }

    // if we're here, it all worked
    //
    close(sock_fd);
    return true;
}