⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 amandad.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 3 页
字号:
    state_machine(as, A_RECVREP, NULL);}/* * Called when a repfd has timed out */static voidtimeout_repfd(    void *	cookie){    struct active_service *as = cookie;    assert(as != NULL);    assert(as->ev_reptimeout != NULL);    state_machine(as, A_TIMEOUT, NULL);}/* * Called when a handle has received data */static voidprotocol_recv(    void *		cookie,    pkt_t *		pkt,    security_status_t	status){    struct active_service *as = cookie;    assert(as != NULL);    switch (status) {    case S_OK:	dbprintf(_("received %s pkt:\n<<<<<\n%s>>>>>\n"),	    pkt_type2str(pkt->type), pkt->body);	state_machine(as, A_RECVPKT, pkt);	break;    case S_TIMEOUT:	dbprintf(_("timeout\n"));	state_machine(as, A_TIMEOUT, NULL);	break;    case S_ERROR:	dbprintf(_("receive error: %s\n"),	    security_geterror(as->security_handle));	break;    }}/* * This is a generic relay function that just reads data from one of * the process's pipes and passes it up the equivalent security_stream_t */static voidprocess_readnetfd(    void *	cookie){    pkt_t nak;    struct datafd_handle *dh = cookie;    struct active_service *as = dh->as;    ssize_t n;    nak.body = NULL;    do {	n = read(dh->fd_read, as->databuf, SIZEOF(as->databuf));    } while ((n < 0) && ((errno == EINTR) || (errno == EAGAIN)));    /*     * Process has died.     */    if (n < 0) {	pkt_init(&nak, P_NAK, _("A ERROR data descriptor %d broken: %s\n"),	    dh->fd_read, strerror(errno));	goto sendnak;    }    /*     * Process has closed the pipe.  Just remove this event handler.     * If all pipes are closed, shut down this service.     */    if (n == 0) {	event_release(dh->ev_read);	dh->ev_read = NULL;	if(dh->ev_write == NULL) {	    security_stream_close(dh->netfd);	    dh->netfd = NULL;	}	for (dh = &as->data[0]; dh < &as->data[DATA_FD_COUNT]; dh++) {	    if (dh->netfd != NULL)		return;	}	service_delete(as);	return;    }    if (security_stream_write(dh->netfd, as->databuf, (size_t)n) < 0) {	/* stream has croaked */	pkt_init(&nak, P_NAK, _("ERROR write error on stream %d: %s\n"),	    security_stream_id(dh->netfd),	    security_stream_geterror(dh->netfd));	goto sendnak;    }    return;sendnak:    do_sendpkt(as->security_handle, &nak);    service_delete(as);    amfree(nak.body);}/* * This is a generic relay function that just read data from one of * the security_stream_t and passes it up the equivalent process's pipes */static voidprocess_writenetfd(    void *	cookie,    void *	buf,    ssize_t	size){    struct datafd_handle *dh;    assert(cookie != NULL);    dh = cookie;    if (dh->fd_write <= 0) {	dbprintf(_("process_writenetfd: dh->fd_write <= 0\n"));    } else if (size > 0) {	fullwrite(dh->fd_write, buf, (size_t)size);	security_stream_read(dh->netfd, process_writenetfd, dh);    }    else {	aclose(dh->fd_write);    }}/* * Convert a local stream handle (DATA_FD...) into something that * can be sent to the amanda server. * * Returns a number that should be sent to the server in the REP packet. */static intallocstream(    struct active_service *	as,    int				handle){    struct datafd_handle *dh;    /* if the handle is -1, then we don't bother */    if (handle < 0)	return (-1);    /* make sure the handle's kosher */    if (handle < DATA_FD_OFFSET || handle >= DATA_FD_OFFSET + DATA_FD_COUNT)	return (-1);    /* get a pointer into our handle array */    dh = &as->data[handle - DATA_FD_OFFSET];    /* make sure we're not already using the net handle */    if (dh->netfd != NULL)	return (-1);    /* allocate a stream from the security layer and return */    dh->netfd = security_stream_server(as->security_handle);    if (dh->netfd == NULL) {	dbprintf(_("couldn't open stream to server: %s\n"),	    security_geterror(as->security_handle));	return (-1);    }    /*     * convert the stream into a numeric id that can be sent to the     * remote end.     */    return (security_stream_id(dh->netfd));}/* * Create a new service instance */static struct active_service *service_new(    security_handle_t *	security_handle,    const char *	cmd,    const char *	arguments){    int i;    int data_read[DATA_FD_COUNT + 1][2];    int data_write[DATA_FD_COUNT + 1][2];    struct active_service *as;    pid_t pid;    int newfd;    assert(security_handle != NULL);    assert(cmd != NULL);    assert(arguments != NULL);    /* a plethora of pipes */    for (i = 0; i < DATA_FD_COUNT + 1; i++) {	if (pipe(data_read[i]) < 0) {	    error(_("pipe: %s\n"), strerror(errno));	    /*NOTREACHED*/	}	if (pipe(data_write[i]) < 0) {	    error(_("pipe: %s\n"), strerror(errno));	    /*NOTREACHED*/	}    }    switch(pid = fork()) {    case -1:	error(_("could not fork service %s: %s\n"), cmd, strerror(errno));	/*NOTREACHED*/    default:	/*	 * The parent.  Close the far ends of our pipes and return.	 */	as = alloc(SIZEOF(*as));	as->cmd = stralloc(cmd);	as->arguments = stralloc(arguments);	as->security_handle = security_handle;	as->state = NULL;	as->pid = pid;	as->send_partial_reply = 0;	if(strcmp(cmd+(strlen(cmd)-8), "sendsize") == 0) {	    g_option_t *g_options;	    char *option_str, *p;	    option_str = stralloc(as->arguments+8);	    p = strchr(option_str,'\n');	    if(p) *p = '\0';	    g_options = parse_g_options(option_str, 1);	    if(am_has_feature(g_options->features, fe_partial_estimate)) {		as->send_partial_reply = 1;	    }	    free_g_options(g_options);	    amfree(option_str);	}	/* write to the request pipe */	aclose(data_read[0][0]);	as->reqfd = data_read[0][1];	/*	 * read from the reply pipe	 */	as->repfd = data_write[0][0];	aclose(data_write[0][1]);	as->ev_repfd = NULL;	as->repbuf = NULL;	as->repbufsize = 0;	as->bufsize = 0;	as->repretry = 0;	as->rep_pkt.body = NULL;	/*	 * read from the rest of the general-use pipes	 * (netfds are opened as the client requests them)	 */	for (i = 0; i < DATA_FD_COUNT; i++) {	    aclose(data_read[i + 1][1]);	    aclose(data_write[i + 1][0]);	    as->data[i].fd_read = data_read[i + 1][0];	    as->data[i].fd_write = data_write[i + 1][1];	    as->data[i].ev_read = NULL;	    as->data[i].ev_write = NULL;	    as->data[i].netfd = NULL;	    as->data[i].as = as;	}	/* add it to the service queue */	/* increment the active service count */	TAILQ_INSERT_TAIL(&serviceq.tailq, as, tq);	serviceq.qlength++;	return (as);    case 0:	/*	 * The child.  Put our pipes in their advertised locations	 * and start up.	 */	/*	 * The data stream is stdin in the new process	 */        if (dup2(data_read[0][0], 0) < 0) {	    error(_("dup %d to %d failed: %s\n"), data_read[0][0], 0,		strerror(errno));	    /*NOTREACHED*/	}	aclose(data_read[0][0]);	aclose(data_read[0][1]);	/*	 * The reply stream is stdout	 */        if (dup2(data_write[0][1], 1) < 0) {	    error(_("dup %d to %d failed: %s\n"), data_write[0][1], 1,		strerror(errno));	}        aclose(data_write[0][0]);        aclose(data_write[0][1]);	for (i = 0; i < DATA_FD_COUNT; i++) {	    aclose(data_read[i + 1][0]);	    aclose(data_write[i + 1][1]);	}	/*	 *  Make sure they are not open in the range DATA_FD_OFFSET to	 *      DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1	 */	for (i = 0; i < DATA_FD_COUNT; i++) {	    while(data_read[i + 1][1] >= DATA_FD_OFFSET &&		  data_read[i + 1][1] <= DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1) {		newfd = dup(data_read[i + 1][1]);		if(newfd == -1)		    error(_("Can't dup out off DATA_FD range"));		data_read[i + 1][1] = newfd;	    }	    while(data_write[i + 1][0] >= DATA_FD_OFFSET &&		  data_write[i + 1][0] <= DATA_FD_OFFSET + DATA_FD_COUNT*2 - 1) {		newfd = dup(data_write[i + 1][0]);		if(newfd == -1)		    error(_("Can't dup out off DATA_FD range"));		data_write[i + 1][0] = newfd;	    }	}	for (i = 0; i < DATA_FD_COUNT*2; i++)	    close(DATA_FD_OFFSET + i);	/*	 * The rest start at the offset defined in amandad.h, and continue	 * through the internal defined.	 */	for (i = 0; i < DATA_FD_COUNT; i++) {	    if (dup2(data_read[i + 1][1], i*2 + DATA_FD_OFFSET) < 0) {		error(_("dup %d to %d failed: %s\n"), data_read[i + 1][1],		    i + DATA_FD_OFFSET, strerror(errno));	    }	    aclose(data_read[i + 1][1]);	    if (dup2(data_write[i + 1][0], i*2 + 1 + DATA_FD_OFFSET) < 0) {		error(_("dup %d to %d failed: %s\n"), data_write[i + 1][0],		    i + DATA_FD_OFFSET, strerror(errno));	    }	    aclose(data_write[i + 1][0]);	}	/* close all unneeded fd */	close(STDERR_FILENO);	debug_dup_stderr_to_debug();	safe_fd(DATA_FD_OFFSET, DATA_FD_COUNT*2);	execle(cmd, cmd, "amandad", auth, (char *)NULL, safe_env());	error(_("could not exec service %s: %s\n"), cmd, strerror(errno));	/*NOTREACHED*/    }    return NULL;}/* * Unallocate a service instance */static voidservice_delete(    struct active_service *	as){    int i;    struct datafd_handle *dh;    amandad_debug(1, _("closing service: %s\n"),		      (as->cmd)?as->cmd:_("??UNKONWN??"));    assert(as != NULL);    assert(as->cmd != NULL);    amfree(as->cmd);    assert(as->arguments != NULL);    amfree(as->arguments);    if (as->reqfd != -1)	aclose(as->reqfd);    if (as->repfd != -1)	aclose(as->repfd);    if (as->ev_repfd != NULL)	event_release(as->ev_repfd);    if (as->ev_reptimeout != NULL)	event_release(as->ev_reptimeout);    for (i = 0; i < DATA_FD_COUNT; i++) {	dh = &as->data[i];	aclose(dh->fd_read);	aclose(dh->fd_write);	if (dh->netfd != NULL)	    security_stream_close(dh->netfd);	if (dh->ev_read != NULL)	    event_release(dh->ev_read);	if (dh->ev_write != NULL)	    event_release(dh->ev_write);    }    if (as->security_handle != NULL)	security_close(as->security_handle);    assert(as->pid > 0);    kill(as->pid, SIGTERM);    waitpid(as->pid, NULL, WNOHANG);    TAILQ_REMOVE(&serviceq.tailq, as, tq);    assert(serviceq.qlength > 0);    serviceq.qlength--;    amfree(as->cmd);    amfree(as->arguments);    amfree(as->repbuf);    amfree(as->rep_pkt.body);    amfree(as);    if(exit_on_qlength == 0 && serviceq.qlength == 0) {	dbclose();	exit(0);    }}/* * Like 'fullwrite', but does the work in a child process so pipelines * do not hang. */static intwritebuf(    struct active_service *	as,    const void *		bufp,    size_t			size){    pid_t pid;    ssize_t    writesize;    switch (pid=fork()) {    case -1:	break;    default:	waitpid(pid, NULL, WNOHANG);	return 0;			/* this is the parent */    case 0: 				/* this is the child */	close(as->repfd);	writesize = fullwrite(as->reqfd, bufp, size);	exit(writesize != (ssize_t)size);	/* NOTREACHED */    }    return -1;}static ssize_tdo_sendpkt(    security_handle_t *	handle,    pkt_t *		pkt){    dbprintf(_("sending %s pkt:\n<<<<<\n%s>>>>>\n"),	pkt_type2str(pkt->type), pkt->body);    if (handle)	return security_sendpkt(handle, pkt);    else	return 1;}/* * Convert a state into a string */static const char *state2str(    state_t	state){    static const struct {	state_t state;	const char str[13];    } states[] = {#define	X(state)	{ state, stringize(state) }	X(s_sendack),	X(s_repwait),	X(s_processrep),	X(s_sendrep),	X(s_ackwait),#undef X    };    int i;    for (i = 0; i < (int)(sizeof(states) / sizeof(states[0])); i++)	if (state == states[i].state)	    return (states[i].str);    return (_("INVALID STATE"));}/* * Convert an action into a string */static const char *action2str(    action_t	action){    static const struct {	action_t action;	const char str[12];    } actions[] = {#define	X(action)	{ action, stringize(action) }	X(A_START),	X(A_RECVPKT),	X(A_RECVREP),	X(A_PENDING),	X(A_FINISH),	X(A_CONTINUE),	X(A_SENDNAK),	X(A_TIMEOUT),#undef X    };    int i;    for (i = 0; i < (int)(sizeof(actions) / sizeof(actions[0])); i++)	if (action == actions[i].action)	    return (actions[i].str);    return (_("UNKNOWN ACTION"));}static char *amandad_get_security_conf(    char *      string,    void *      arg){    (void)arg;      /* Quiet unused parameter warning */    if (!string || !*string)	return(NULL);    if (strcmp(string, "kencrypt")==0) {	if (amandad_kencrypt == KENCRYPT_YES)	    return ("yes");	else	    return (NULL);    }    return(NULL);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -