Esempio n. 1
0
int start_child()
{
    pid_t mypid = getpid();
    setpgid(mypid, mypid);

    pid_t child;
    child = fork();

    switch (child) {
        case 0:
            close(pipe_fd[1]);
            dup2(pipe_fd[0],0);
            if (proc_stat.argc > 0) {
                return execvp(proc_stat.path, proc_stat.argv);
            } else {
                char *b = NULL;
                b = malloc((sizeof("exec ") - 1) + strlen(proc_stat.path) + 1);
                strcpy(b, "exec ");
                strcat(b, proc_stat.path);
                return execl("/bin/sh", "sh", "-c", b, (char *) NULL);
            }

        case -1:
            fprintf(stderr, "launch: fork failed: %s\n", strerror(errno));
            return -1;

        default:
            close(pipe_fd[0]);
            proc_stat.pid = child;
            int a=1;
            mylog("start child pid=%d",child);
            if(wait_for_service()){
                proc_stat.running = RUNNING;
                wait_for_stop();
                clean_child();
            }else{
                clean_child();
            }
    }
}
Esempio n. 2
0
int sendafile(int code) {

    char    receive_buffer[MAXMESSLEN] ;
    char    receive_buffer_sup[MAXMESSLEN] ;
    char    send_buffer[MAXMESSLEN] ;
    int        savederrno ;

    char    readbuffer[READBUFLEN] ;
    char    buffercomp[READBUFLEN] ;
    struct    mess_compress *msg_compress ;
#ifdef WITH_GZIP
    uLong    buflen ;
    uLong    bufcomplen ;
#endif
    my64_t    filelen64 ;
    my64_t    toprint64 ;
    
#ifdef STANDART_FILE_CALL
    off_t         nbperchild ;
    off_t         nbtosend ;
    off_t         nbread ;
    off_t         nbsent ;
    off_t         numberread ;
    off_t         startpoint ;
    off_t        realnbtosend ;
    off_t        filelen ;
    struct stat statbuf ;
#else
    off64_t     nbperchild ;
    off64_t     nbtosend ;
    off64_t     nbread ;
    off64_t     nbsent ;
    off64_t     numberread ;
    off64_t     startpoint ;
    off64_t        realnbtosend ;
    off64_t        filelen ;
    struct stat64 statbuf ;
#endif

    int        lentosend ;

    char    readfilename[MAXLENFILE] ;
    
    int        retcode ;
    int        fd ;
    int        i ;
    int        sendsock ;
    char    logmessage[256] ;
    int        compressiontype ;
    
    struct message *msg ;
    struct mess_store *msg_store ;
    struct mess_retr_ok *msg_retr_ok ;
    
    int        nfds ;
    fd_set    selectmask ; /* Select mask */
    struct timeval    wait_timer;
    
    
    /*
    ** Initilize the pid array
    */
     for ( i=0 ; i< MAXPORT ; i++) {
        pid_child[i] = 0 ;
    }
    childendinerror = 0 ; /* No child so no error */

    strcpy(currentfilename,"") ;
    if ( (retcode = readmessage(msgsock,receive_buffer,STORMESSLEN,recvcontrolto) ) < 0 ) {
        syslog(BBFTPD_ERR,"Error receiving file char") ;
        return retcode ;
    }
    msg_store = (struct mess_store *) receive_buffer ;
    strcpy(readfilename,msg_store->filename) ;
#ifndef WORDS_BIGENDIAN
    msg_store->nbport = ntohl(msg_store->nbport) ;
    for (i = 0 ; i< MAXPORT ; i++ ) {
        msg_store->port[i] = ntohl(msg_store->port[i]) ;
    }
#endif
    if ( code == MSG_RETR ) {
        compressiontype = NOCOMPRESSION ;
        syslog(BBFTPD_DEBUG,"Retreiving file %s with %d children",readfilename,msg_store->nbport) ;
    } else {
        compressiontype = COMPRESSION ;
        syslog(BBFTPD_DEBUG,"Retreiving file %s with %d children in compressed mode",readfilename,msg_store->nbport) ;
    }
    /*
    ** WARNING ----------
    **
    ** Do not use the receive buffer in father before having forked
    ** because all data related to the ports are in it
    **
    ** WARNING ----------
    */
    /*
    ** First stat the file in order to know if it is a directory
    */
#ifdef STANDART_FILE_CALL
    if ( stat(readfilename,&statbuf) < 0 ) {
#else
    if ( stat64(readfilename,&statbuf) < 0 ) {
#endif
        /*
        ** We tell the client not to retry in the following case (even in waiting
        ** WAITRETRYTIME the problem will not be solved) :
        **        EACCES        : Search permission denied
        **        ELOOP        : To many symbolic links on path
        **        ENAMETOOLONG: Path argument too long
        **        ENOENT        : The file does not exists
        **        ENOTDIR        : A component in path is not a directory
        */
        savederrno = errno ;
        sprintf(logmessage,"Error stating file %s : %s ",readfilename,strerror(savederrno)) ;
        syslog(BBFTPD_ERR,"Error stating file %s : %s ",readfilename,strerror(savederrno)) ;
        if ( savederrno == EACCES ||
            savederrno == ELOOP ||
            savederrno == ENAMETOOLONG ||
            savederrno == ENOENT ||
            savederrno == ENOTDIR ) {
            reply(MSG_BAD_NO_RETRY,logmessage) ;
            return 0 ;
        } else {
            reply(MSG_BAD,logmessage) ;
            return 0 ;
        }
    } else {
        /*
        ** The file exists so check if it is a directory
        */
        if ( (statbuf.st_mode & S_IFDIR) == S_IFDIR) {
            syslog(BBFTPD_ERR,"file %s is a directory",readfilename) ;
            sprintf(logmessage,"File %s is a directory",readfilename) ;
            reply(MSG_BAD_NO_RETRY,logmessage) ;
            return 0 ;
        }
    }                
    /*
    ** Getting filesize in order to send it to the client
    */
#ifdef STANDART_FILE_CALL
    if ( (fd = open(readfilename,O_RDONLY)) < 0 ) {
#else
    if ( (fd = open64(readfilename,O_RDONLY)) < 0 ) {
#endif
        /*
        ** An error on openning the local file is considered
        ** as fatal. Maybe this need to be improved depending
        ** on errno
        */
        savederrno = errno ;
        syslog(BBFTPD_ERR,"Error opening local file %s : %s",readfilename,strerror(errno)) ;
        sprintf(logmessage,"Error opening local file %s : %s ",readfilename,strerror(errno)) ;
        /*
        ** We tell the client not to retry in the following case (even in waiting
        ** WAITRETRYTIME the problem will not be solved) :
        **        EACCES        : Search permission denied
        **        ELOOP        : To many symbolic links on path
        **        ENOENT        : No such file or directory
        **        ENAMETOOLONG: Path argument too long
        **        ENOTDIR        : A component in path is not a directory
        */
        if ( savederrno == EACCES ||
                savederrno == ELOOP ||
                savederrno == ENOENT ||
                savederrno == ENAMETOOLONG ||
                savederrno == ENOTDIR ) {
            reply(MSG_BAD_NO_RETRY,logmessage) ;
        } else {
            reply(MSG_BAD,logmessage) ;
        }
        return 0 ;
    }
#ifdef STANDART_FILE_CALL
    if ( (filelen = lseek(fd,0,SEEK_END) ) < 0 ) {
#else
    if ( (filelen = lseek64(fd,0,SEEK_END) ) < 0 ) {
#endif
        /*
        ** An error on seekin the local file is considered
        ** as fatal. lseek error  in this case is completly
        ** abnormal
        */
        close(fd) ;
        syslog(BBFTPD_ERR,"Error seeking local file %s : %s",readfilename,strerror(errno)) ;
        sprintf(logmessage,"Error seeking local file %s : %s ",readfilename,strerror(errno)) ;
        reply(MSG_BAD,logmessage) ;
        return 0 ;
    }
    filelen64 = filelen ;
    /*
    ** Close the file as the only interresting thing was the length
    */
    close(fd) ;
    /*
    ** We are going to send the file length 
    */
    msg = (struct message *) send_buffer ;
    msg->code = MSG_RETR_OK ;
#ifndef WORDS_BIGENDIAN
    msg->msglen = ntohl(RETROKMESSLEN) ;
#else
    msg->msglen = RETROKMESSLEN ;
#endif
    if ( writemessage(msgsock,send_buffer,MINMESSLEN,recvcontrolto) < 0 ) {
        /*
        ** Something wrong in sending message
        ** tell calling to close the connection
        */
        syslog(BBFTPD_ERR,"Error sending RETROK part 1") ;
        return -1 ;
    }
    msg_retr_ok = (struct mess_retr_ok *) send_buffer ;
#ifndef WORDS_BIGENDIAN
    msg_retr_ok->filesize = ntohll(filelen64) ;
#else
    msg_retr_ok->filesize = filelen64 ;
#endif
    if ( writemessage(msgsock,send_buffer,RETROKMESSLEN,recvcontrolto) < 0 ) {
        /*
        ** Something wrong in sending message
        ** tell calling to close the connection
        */
        syslog(BBFTPD_ERR,"Error sending RETROK part 2") ;
        return -1 ;
    }
    /*
    ** Wait for the START message
    */
    if ( readmessage(msgsock,receive_buffer_sup,MINMESSLEN,RETRSTARTTO) < 0 ) {
        /*
        ** Something wrong in receiving message
        ** tell calling to close the connection
        */
        syslog(BBFTPD_ERR,"Error receiving RETRSTART") ;
        return -1 ;
    }
    msg = (struct message *) receive_buffer_sup ;
    if ( msg->code == MSG_ABR) {
        /*
        ** In this case the client will not close the connection
        ** so do the same
        */
        syslog(BBFTPD_ERR,"Receive ABORT message") ;
        return 0 ;
    } else if ( msg->code == MSG_CREATE_ZERO ) {
        syslog(BBFTPD_INFO,"Send zero length file") ;
        return 0 ;
    } else if ( msg->code != MSG_RETR_START ) {
        syslog(BBFTPD_ERR,"Receive Unknown message code while waiting RETRSTART %d",msg->code) ;
        return -1 ;
    }
    /*
    ** So we receive the start message ...
    */
    /*
    ** Now start all our children
    */
    nbperchild = filelen/msg_store->nbport ;
    for (i = 1 ; i <= msg_store->nbport ; i++) {
        if ( i == msg_store->nbport) {
            startpoint = (i-1)*nbperchild;
            nbtosend = filelen-(nbperchild*(msg_store->nbport-1)) ;
        } else {
            startpoint = (i-1)*nbperchild;
            nbtosend = nbperchild ;
        }
        /*
        ** Now create the socket to send
        */
        sendsock = 0 ;
        while (sendsock == 0 ) {
            sendsock = createreceivesock(msg_store->port[i-1],i,logmessage) ;
        }
        if ( sendsock < 0 ) {
            /*
            ** We set childendinerror to 1 in order to prevent the father
            ** to send a BAD message which can desynchronize the client and the
            ** server (We need only one error message)
            ** Bug discovered by amlutz on 2000/03/11
            */
            if ( childendinerror == 0 ) {
                childendinerror = 1 ;
                reply(MSG_BAD,logmessage) ;
            }
            clean_child() ;
            return 0 ;
        }
        /*
        ** Set flagsighup to zero in order to be able in child
        ** not to wait STARTCHILDTO if signal was sent before 
        ** entering select. (Seen on Linux with one child)
        */
        flagsighup = 0 ;
        /*
        ** At this stage we are ready to receive packets
        ** So we are going to fork
        */
        if ( (retcode = fork()) == 0 ) {
            /*
            ** We are in child
            */
            /*
            ** Pause until father send a SIGHUP in order to prevent
            ** child to die before father has started all children
            */
            if ( flagsighup == 0) {
                nfds = sysconf(_SC_OPEN_MAX) ;
                wait_timer.tv_sec  = STARTCHILDTO ;
                wait_timer.tv_usec = 0 ;
                select(nfds,0,0,0,&wait_timer) ;
            }
            syslog(BBFTPD_DEBUG,"Child Starting") ;
            /*
            ** Close all unnecessary stuff
            */
            close(msgsock) ;
            /*
            ** And open the file 
            */
#ifdef STANDART_FILE_CALL
            if ( (fd = open(readfilename,O_RDONLY)) < 0 ) {
#else
            if ( (fd = open64(readfilename,O_RDONLY)) < 0 ) {
#endif
                /*
                ** An error on openning the local file is considered
                ** as fatal. Maybe this need to be improved depending
                ** on errno
                */
                i = errno ;
                syslog(BBFTPD_ERR,"Error opening local file %s : %s",readfilename,strerror(errno)) ;
                close(sendsock) ;
                exit(i) ;
            }
#ifdef STANDART_FILE_CALL
            if ( lseek(fd,startpoint,SEEK_SET) < 0 ) {
#else
            if ( lseek64(fd,startpoint,SEEK_SET) < 0 ) {
#endif
                i = errno ;
                close(fd) ;
                syslog(BBFTPD_ERR,"Error seeking file : %s",strerror(errno)) ;
                close(sendsock) ;
                exit(i)  ;
            }
            /*
            ** Start the sending loop
            */
            nbread = 0 ;
            while ( nbread < nbtosend ) {
                if ( (numberread = read ( fd, readbuffer, (sizeof(readbuffer) <= nbtosend - nbread) ? sizeof(readbuffer) : nbtosend-nbread) ) > 0 ) {
                    nbread = nbread+numberread ;
#ifdef WITH_GZIP
                    if ( compressiontype == COMPRESSION ) {
                        /*
                        ** In case of compression we are going to use
                        ** a temporary buffer
                        */
                        bufcomplen = READBUFLEN ;
                        buflen = numberread ;
                        msg_compress = ( struct mess_compress *) send_buffer;
                        retcode = compress((Bytef *)buffercomp,&bufcomplen,(Bytef *)readbuffer,buflen) ;
                        if ( retcode != 0 ) {
                            /*
                            ** Compress error, in this cas we are sending the
                            ** date uncompressed
                            */
                            msg_compress->code = DATA_NOCOMPRESS ;
                            lentosend = numberread ;
#ifndef WORDS_BIGENDIAN
                            msg_compress->datalen = ntohl(lentosend) ;
#else
                            msg_compress->datalen = lentosend ;
#endif
                            realnbtosend = numberread ;
                        } else {
                            msg_compress->code = DATA_COMPRESS ;
                            lentosend = bufcomplen ;
#ifndef WORDS_BIGENDIAN
                            msg_compress->datalen = ntohl(lentosend) ;
#else
                            msg_compress->datalen = lentosend ;
#endif
                            realnbtosend =  bufcomplen ;
                            memcpy(readbuffer,buffercomp,READBUFLEN) ;
                        }
                        /*
                        ** Send the header
                        */
                        if ( writemessage(sendsock,send_buffer,COMPMESSLEN,datato) < 0 ) {
                            i = ETIMEDOUT ;
                            syslog(BBFTPD_ERR,"Error sending header data") ;
                            close(sendsock) ;
                            exit(i) ;
                        }
                    } else {
                        realnbtosend = numberread ;
                    }
#else
                    realnbtosend = numberread ;
#endif
                    /*
                    ** Send the data
                    */
                    nbsent = 0 ;
                    while ( nbsent < realnbtosend ) {
                        lentosend = realnbtosend-nbsent ;
                        nfds = sysconf(_SC_OPEN_MAX) ;
                        FD_ZERO(&selectmask) ;
                        FD_SET(sendsock,&selectmask) ;
                        wait_timer.tv_sec  = datato  ;
                        wait_timer.tv_usec = 0 ;
                        if ( (retcode = select(nfds,0,&selectmask,0,&wait_timer) ) == -1 ) {
                            /*
                            ** Select error
                            */
                            i = errno ;
                            syslog(BBFTPD_ERR,"Error select while sending : %s",strerror(errno)) ;
                            close(fd) ;
                            close(sendsock) ;
                            exit(i) ;
                        } else if ( retcode == 0 ) {
                            syslog(BBFTPD_ERR,"Time out while sending") ;
                            close(fd) ;
                            i=ETIMEDOUT ;
                            close(sendsock) ;
                            exit(i) ;
                        } else {
                            retcode = send(sendsock,&readbuffer[nbsent],lentosend,0) ;
                            if ( retcode < 0 ) {
                                i = errno ;
                                syslog(BBFTPD_ERR,"Error while sending %s",strerror(i)) ;
                                close(sendsock) ;
                                exit(i) ;
                            } else if ( retcode == 0 ) {
                                i = ECONNRESET ;
                                syslog(BBFTPD_ERR,"Connexion breaks") ;
                                close(fd) ;
                                close(sendsock) ;
                                exit(i) ;
                            } else {
                                nbsent = nbsent+retcode ;
                            }
                        }
                    }
                } else {
                    i = errno ;
                    syslog(BBFTPD_ERR,"Child Error reading : %s",strerror(errno)) ;
                    close(sendsock) ;
                    exit(i) ;
                }
            }
            /*
            ** All data has been sent so wait for the acknoledge
            */
            if ( readmessage(sendsock,receive_buffer,MINMESSLEN,ackto) < 0 ) {
                syslog(BBFTPD_ERR,"Error waiting ACK") ;
                close(sendsock) ;
                exit(ETIMEDOUT) ;
            }
            msg = (struct message *) receive_buffer ;
            if ( msg->code != MSG_ACK) {
                syslog(BBFTPD_ERR,"Error unknown messge while waiting ACK %d",msg->code) ;
                close(sendsock) ;
                exit(1) ;
            }
            toprint64 = nbtosend ;
            syslog(BBFTPD_DEBUG,"Child send %" LONG_LONG_FORMAT " bytes ; end correct ",toprint64) ;
            close(sendsock) ;
            exit(0) ;
        } else {
            /*
            ** We are in father
            */
            if ( retcode == -1 ) {
                /*
                ** Fork failed ...
                */
                syslog(BBFTPD_ERR,"fork failed : %s",strerror(errno)) ;
                sprintf(logmessage,"fork failed : %s ",strerror(errno)) ;
                if ( childendinerror == 0 ) {
                    childendinerror = 1 ;
                    reply(MSG_BAD,logmessage) ;
                }
                clean_child() ;
                return 0 ;
            } else {
                syslog(BBFTPD_DEBUG,"Started child pid %d",retcode) ;
                pid_child[i-1] = retcode ;
                close(sendsock) ;
            }
        }
    }
    /*
    ** Set the state before starting children because if the file was
    ** small the child has ended before state was setup to correct value
    */
    state = S_SENDING ;
    /*
    ** Start all children
    */
    for (i = 0 ; i<MAXPORT ; i++) {
        if (pid_child[i] != 0) {
            kill(pid_child[i],SIGHUP) ;
        }
    }
    return 0 ;
}