Пример #1
0
static void
fillSpecialObject(ObjectPtr object, void (*fn) (FILE *, char *), void *closure)
{
	int rc;
	int filedes[2];
	pid_t pid;
	sigset_t ss, old_mask;

	if (object->flags & OBJECT_INPROGRESS)
		return;

	rc = pipe(filedes);
	if (rc < 0) {
		do_log_error(L_ERROR, errno, "Couldn't create pipe");
		abortObject(object, 503,
			    internAtomError(errno, "Couldn't create pipe"));
		return;
	}

	fflush(stdout);
	fflush(stderr);
	flushLog();

	interestingSignals(&ss);
	do {
		rc = sigprocmask(SIG_BLOCK, &ss, &old_mask);
	} while (rc < 0 && errno == EINTR);
	if (rc < 0) {
		do_log_error(L_ERROR, errno, "Sigprocmask failed");
		abortObject(object, 503,
			    internAtomError(errno, "Sigprocmask failed"));
		close(filedes[0]);
		close(filedes[1]);
		return;
	}

	pid = fork();
	if (pid < 0) {
		do_log_error(L_ERROR, errno, "Couldn't fork");
		abortObject(object, 503,
			    internAtomError(errno, "Couldn't fork"));
		close(filedes[0]);
		close(filedes[1]);
		do {
			rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
		} while (rc < 0 && errno == EINTR);
		if (rc < 0) {
			do_log_error(L_ERROR, errno,
				     "Couldn't restore signal mask");
			s_serverExit();
		}
		return;
	}

	if (pid > 0) {
		SpecialRequestPtr request;
		close(filedes[1]);
		do {
			rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
		} while (rc < 0 && errno == EINTR);
		if (rc < 0) {
			do_log_error(L_ERROR, errno,
				     "Couldn't restore signal mask");
			s_serverExit();
			return;
		}

		request = malloc(sizeof(SpecialRequestRec));
		if (request == NULL) {
			kill(pid, SIGTERM);
			close(filedes[0]);
			abortObject(object, 503,
				    internAtom("Couldn't allocate request\n"));
			notifyObject(object);
			
		} else {
			request->buf = get_chunk();
			if (request->buf == NULL) {
				kill(pid, SIGTERM);
				close(filedes[0]);
				free(request);
				abortObject(object, 503,
					    internAtom
					    ("Couldn't allocate request\n"));
				notifyObject(object);
			}
		}
		object->flags |= OBJECT_INPROGRESS;
		retainObject(object);
		request->object = object;
		request->fd = filedes[0];
		request->pid = pid;
		request->offset = 0;
		do_stream(IO_READ, filedes[0], 0, request->buf, CHUNK_SIZE,
			  specialRequestHandler, request);
	} else {
		
		close(filedes[0]);
		uninitEvents();
		do {
			rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
		} while (rc < 0 && errno == EINTR);
		if (rc < 0)
			exit(1);

		if (filedes[1] != 1)
			dup2(filedes[1], 1);

		(*fn) (stdout, closure);
		exit(0);
	}
}
Пример #2
0
int
runRedirector(pid_t *pid_return, int *read_fd_return, int *write_fd_return)
{
    int rc, rc2, status;
    pid_t pid;
    int filedes1[2], filedes2[2];
    sigset_t ss, old_mask;

    assert(redirector);

    if(redirector_buffer == NULL) {
        redirector_buffer = malloc(REDIRECTOR_BUFFER_SIZE);
        if(redirector_buffer == NULL)
            return -errno;
    }

    rc = pipe(filedes1);
    if(rc < 0) {
        rc = -errno;
        goto fail1;
    }


    rc = pipe(filedes2);
    if(rc < 0) {
        rc = -errno;
        goto fail2;
    }

    fflush(stdout);
    fflush(stderr);
    flushLog();

    interestingSignals(&ss);
    do {
        rc = sigprocmask(SIG_BLOCK, &ss, &old_mask);
    } while (rc < 0 && errno == EINTR);
    if(rc < 0) {
        rc = -errno;
        goto fail3;
    }

    pid = fork();
    if(pid < 0) {
        rc = -errno;
        goto fail4;
    }

    if(pid > 0) {
        do {
            rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
        } while(rc < 0 && errno == EINTR);

        if(rc < 0) {
            rc = -errno;
            goto fail4;
        }

        rc = setNonblocking(filedes1[1], 1);
        if(rc >= 0)
            rc = setNonblocking(filedes2[0], 1);
        if(rc < 0) {
            rc = -errno;
            goto fail4;
        }

        /* This is completely unnecesary -- if the redirector cannot be
           started, redirectorStreamHandler1 will get EPIPE straight away --,
           but it improves error messages somewhat. */
        rc = waitpid(pid, &status, WNOHANG);
        if(rc > 0) {
            logExitStatus(status);
            rc = -EREDIRECTOR;
            goto fail4;
        } else if(rc < 0) {
            rc = -errno;
            goto fail4;
        }

        *read_fd_return = filedes2[0];
        *write_fd_return = filedes1[1];

        *pid_return = pid;
        /* This comes at the end so that the fail* labels can work */
        close(filedes1[0]);
        close(filedes2[1]);
    } else {
        close(filedes1[1]);
        close(filedes2[0]);
        uninitEvents();
        do {
            rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
        } while (rc < 0 && errno == EINTR);
        if(rc < 0)
            exit(142);

        if(filedes1[0] != 0)
            dup2(filedes1[0], 0);
        if(filedes2[1] != 1)
            dup2(filedes2[1], 1);

        execlp(redirector->string, redirector->string, NULL);
        exit(142);
        /* NOTREACHED */
    }
    return 1;

 fail4:
    do {
        rc2 = sigprocmask(SIG_SETMASK, &old_mask, NULL);
    } while(rc2 < 0 && errno == EINTR);
 fail3:
    close(filedes2[0]);
    close(filedes2[1]);
 fail2:
    close(filedes1[0]);
    close(filedes1[1]);
 fail1:
    free(redirector_buffer);
    redirector_buffer = NULL;
    return rc;
}
Пример #3
0
static void
fillSpecialObject(ObjectPtr object, void (*fn)(FILE*, char*), void* closure)
{
    int rc;
    int filedes[2];
    pid_t pid;
    sigset_t ss, old_mask;

    if(object->flags & OBJECT_INPROGRESS)
        return;

    rc = pipe(filedes);
    if(rc < 0) {
        do_log_error(L_ERROR, errno, "Couldn't create pipe");
        abortObject(object, 503,
                    internAtomError(errno, "Couldn't create pipe"));
        return;
    }

    fflush(stdout);
    fflush(stderr);
    flushLog();

    /* Block signals that we handle specially until the child can
       disable the handlers. */
    interestingSignals(&ss);
    /* I'm a little confused.  POSIX doesn't allow EINTR here, but I
       think that both Linux and SVR4 do. */
    do {
        rc = sigprocmask(SIG_BLOCK, &ss, &old_mask);
    } while (rc < 0 && errno == EINTR);
    if(rc < 0) {
        do_log_error(L_ERROR, errno, "Sigprocmask failed");
        abortObject(object, 503, internAtomError(errno, "Sigprocmask failed"));
        close(filedes[0]);
        close(filedes[1]);
        return;
    }

    pid = fork();
    if(pid < 0) {
        do_log_error(L_ERROR, errno, "Couldn't fork");
        abortObject(object, 503, internAtomError(errno, "Couldn't fork"));
        close(filedes[0]);
        close(filedes[1]);
        do {
            rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
        } while (rc < 0 && errno == EINTR);
        if(rc < 0) {
            do_log_error(L_ERROR, errno, "Couldn't restore signal mask");
            polipoExit();
        }
        return;
    }

    if(pid > 0) {
        SpecialRequestPtr request;
        close(filedes[1]);
        do {
            rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
        } while (rc < 0 && errno == EINTR);
        if(rc < 0) {
            do_log_error(L_ERROR, errno, "Couldn't restore signal mask");
            polipoExit();
            return;
        }

        request = malloc(sizeof(SpecialRequestRec));
        if(request == NULL) {
            kill(pid, SIGTERM);
            close(filedes[0]);
            abortObject(object, 503,
                        internAtom("Couldn't allocate request\n"));
            notifyObject(object);
            return;
        } else {
            request->buf = get_chunk();
            if(request->buf == NULL) {
                kill(pid, SIGTERM);
                close(filedes[0]);
                free(request);
                abortObject(object, 503,
                            internAtom("Couldn't allocate request\n"));
                notifyObject(object);
                return;
            }
        }
        object->flags |= OBJECT_INPROGRESS;
        retainObject(object);
        request->object = object;
        request->fd = filedes[0];
        request->pid = pid;
        request->offset = 0;
        /* Under any sensible scheduler, the child will run before the
           parent.  So no need for IO_NOTNOW. */
        do_stream(IO_READ, filedes[0], 0, request->buf, CHUNK_SIZE,
                  specialRequestHandler, request);
    } else {
        /* child */
        close(filedes[0]);
        uninitEvents();
        do {
            rc = sigprocmask(SIG_SETMASK, &old_mask, NULL);
        } while (rc < 0 && errno == EINTR);
        if(rc < 0)
            exit(1);

        if(filedes[1] != 1)
            dup2(filedes[1], 1);

        (*fn)(stdout, closure);
        exit(0);
    }
}