コード例 #1
0
static ya_result
journal_ix_reopen(journal *jh)
{
    journal_ix *jix = (journal_ix*)jh;
    ya_result ret = SUCCESS;
    journal_ix_writelock(jix);
    if(jix->fd < 0)
    {
        if(ISOK(ret = open_ex(jix->journal_name, O_RDWR)))
        {
            jix->fd = ret;
        }
        else
        {
            ret = ERRNO_ERROR;
            if(ret == MAKE_ERRNO_ERROR(ENOENT))
            {
                ret = ZDB_ERROR_ICMTL_NOTFOUND;
            }
        }        
    }
    journal_ix_writeunlock(jix);
    return ret;
}
コード例 #2
0
static ya_result
journal_ix_get_ixfr_stream_at_serial(journal *jh, u32 serial_from, input_stream *out_input_stream, dns_resource_record *last_soa_rr)
{
    journal_ix *jix = (journal_ix*)jh;
    ya_result return_value = SUCCESS;
    
    journal_ix_readlock(jix);
    
    /*
     * check that serial_from in in the journal range
     * set the file descriptor to the position
     * create a stream that'll stop at the current end of the stream
     */
    
    if(serial_lt(serial_from, jix->first_serial) || serial_ge(serial_from, jix->last_serial) || ((jix->first_serial == 0) && (jix->last_serial == 0)))
    {
        /* out of known range */
        
        journal_ix_readunlock(jix);
        
        if(serial_from == jix->last_serial)
        {
            return SUCCESS;
        }
        else
        {        
            return ZDB_JOURNAL_SERIAL_OUT_OF_KNOWN_RANGE;
        }
    }
    
    /*
     * On success, dup() returns a new file descriptor that has the following in common with the original:
     * 
     *  _ Same open file (or pipe)
     *  _ Same file pointer (both file descriptors share one file pointer) <= THIS is a problem
     *  _ Same access mode (read, write, or read/write)
     * 
     * So this is wrong:
     * 
     * cloned_fd = dup(jix->fd);
     */    
    
    int cloned_fd;
    
    while((cloned_fd = open_ex(jix->journal_name, O_RDONLY)) < 0)
    {
        int err = errno;

        if(err == EINTR)
        {
            continue;
        }

        return_value = MAKE_ERRNO_ERROR(err);

#ifdef DEBUG
        log_debug("journal: ix: unable to clone the file descriptor: %r", return_value);
#endif
        journal_ix_readunlock(jix);

        return return_value;
    }
    
    /* 
     * given that I use a clone of the fd and
     * given that only appends are done in the file and
     * given that the limit of the file has already been processed (should be at this point)
     * 
     * THEN
     * 
     * there is no point keeping the lock for reading (on unix systems)
     */
    
    struct stat journal_stat;
    
    s64 last_page_offset = jix->last_page_offset;
    
    if(fstat(cloned_fd, &journal_stat) < 0)
    {
        return_value = ERRNO_ERROR;
        
        log_err("journal: ix: unable to get journal file status", return_value);
        
        close_ex(cloned_fd);

        return return_value;
    }
    
    s64 file_size = journal_stat.st_size;
    
    
#if DEBUG_JOURNAL
    log_debug("journal: ix: the last page starts at position %lld", last_page_offset);
#endif

    journal_ix_readunlock(jix);
    jix = NULL;  
    
    input_stream fis;
    fd_input_stream_attach(&fis, cloned_fd);
    
    if(last_soa_rr != NULL)
    {
        /* seek and store the last SOA print*/
        
        last_soa_rr->tctr.qtype = 0; // clear type
        
        if(lseek(cloned_fd, last_page_offset, SEEK_SET) >= 0)
        {
            /* deleted SOA */
            if((return_value = dns_resource_record_read(last_soa_rr, &fis)) > 0 ) // Not FAIL nor EOF
            {
                if(last_soa_rr->tctr.qtype == TYPE_SOA)
                {
                    /* DEL records */
                    last_soa_rr->tctr.qtype = 0; // clear type
            
                    /* scan until added SOA found */
                    while((return_value = dns_resource_record_read(last_soa_rr, &fis)) > 0 ) // Not FAIL nor EOF
                    {
                        if(last_soa_rr->tctr.qtype == TYPE_SOA)
                        {
                            break;
                        }
                    }
                }
            }
            
            // if the SOA has not been found, it's an error (EOF has been reached is covered by this)
            
            
            if(ISOK(return_value))
            {
                if(last_soa_rr->tctr.qtype != TYPE_SOA)
                {
                    return_value = ZDB_JOURNAL_SOA_RECORD_EXPECTED;
                }
            }
        }
        else
        {
            return_value = ERRNO_ERROR;
        }
        
        if(FAIL(return_value))
        {
            input_stream_close(&fis);
            
            return return_value;
        }
    }
    
    /*
     * this format has no indexing so we scan for a page that STARTS with a DELETE of the SOA with serial = serial_from
     */
    
    if(lseek(cloned_fd, 0, SEEK_SET) != 0)  /* the resulting offset MUST be zero */
    {
        return_value = ERRNO_ERROR;
        
        if(ISOK(return_value))
        {
            return_value = ERROR;
        }
        
        input_stream_close(&fis);
            
        return return_value;
    }
    
    input_stream bis;
    dns_resource_record rr;
    dns_resource_record_init(&rr);
    buffer_input_stream_init(&fis, &bis, 512);
    
    s64 offset = 0;

    /* skip until the right serial is found */

    u32 soa_count = 0;

#ifdef DEBUG_JOURNAL
    u32 rr_count = 0;
#endif
    
    for(;;)
    {
        if( (return_value = dns_resource_record_read(&rr, &bis)) <= 0 ) // FAIL or nothing to 
        {
            return_value = ZDB_JOURNAL_ERROR_READING_JOURNAL; /* is the journal file broken ? */
            
            break;
        }

#ifdef DEBUG_JOURNAL
        rr_count++;
#endif
        
        u32 record_size = return_value;
        
        if(rr.tctr.qtype == TYPE_SOA)
        {
            // ((0+1)&1) != 0 => Y N Y N 
            
            if((++soa_count & 1) != 0) // 1 2 3 4
            {
                u8 *p = rr.rdata;

                if(FAIL(return_value = dnsname_len(p)))
                {
                    break;
                }

                p += return_value;

                if(FAIL(return_value = dnsname_len(p)))
                {
                    break;
                }

                p += return_value;

                u32 serial = ntohl(GET_U32_AT(*p));

                if(serial_ge(serial, serial_from))
                {
                    if(serial == serial_from)
                    {
                        /* setup the serial to be from 'offset' up to the current length of the stream */

                        return_value = SUCCESS;
                    }
                    else
                    {
                        /* the serial does not exist in the range */

                        return_value = ZDB_JOURNAL_SERIAL_OUT_OF_KNOWN_RANGE;
                    }

                    break;
                }
            }
        }
        
        offset += record_size;
    }
    
#if DEBUG_JOURNAL
    log_debug("journal: ix: serial %08x (%d) is at offset %lld. %d records parsed", serial_from, serial_from, offset, rr_count);
#endif
    
    dns_resource_record_clear(&rr);
    
    /* 
     * detach the file descriptor from the file stream in the buffer stream
     * I do it like this because the streams are not needed anymore but the
     * file descriptor still is (if no error occurred)
     */
    
    fd_input_stream_detach(buffer_input_stream_get_filtered(&bis));
    input_stream_close(&bis);

    if(ISOK(return_value))
    {
        // offset is the start of the page we are looking for
        if(lseek(cloned_fd, offset, SEEK_SET) >= 0)
        {
            fd_input_stream_attach(&fis, cloned_fd);
            limited_input_stream_init(&fis, out_input_stream, file_size - offset);
        }
        else
        {
            return_value = ERRNO_ERROR;
            
            close_ex(cloned_fd);
        }
    }
    else
    {
        close_ex(cloned_fd);
    }
        
    return return_value;
}
コード例 #3
0
static void*
scheduler_queue_zone_write_thread(void* data_)
{
    char fullname_tmp[MAX_PATH];

    zone_write_param *zwp = (zone_write_param*)data_;
    zdb_zone *zone = zwp->zone;
    u32 serial;

    log_info("zone write text: writing %{dnsname} zone file", zone->origin);
    
    if(ZDB_ZONE_INVALID(zone))
    {
        log_err("zone write text: zone %{dnsname} marked as invalid", zone->origin);
 
        scheduler_schedule_task(scheduler_queue_zone_write_callback, zwp);

        return NULL;
    }

    if(FAIL(zdb_zone_getserial(zone, &serial)))
    {
        log_err("zone write text: no SOA in %{dnsname}", zone->origin);

        scheduler_schedule_task(scheduler_queue_zone_write_callback, zwp);

        return NULL;
    }
    
    if(FAIL(snformat(fullname_tmp, sizeof (fullname_tmp), "%s.%d.tmp", zwp->file_path, serial)))
    {
        log_err("zone write text: path '%s.%d.tmp' is too big", zwp->file_path, serial);

        scheduler_schedule_task(scheduler_queue_zone_write_callback, zwp);

        /* WARNING: From this point forward, 'zone' cannot be used anymore */

        return NULL;
    }
    
    /**
     * @todo check there is not already a zone file writer working here ...
     * 
     */

    /*
     * delete the temp file if it exists already
     */
    
    if(unlink(fullname_tmp) < 0)
    {
        int err = errno;
        
        if(err != ENOENT)
        {
            log_err("zone write text: cannot cleanup '%s': %r", MAKE_ERRNO_ERROR(err));
            
            scheduler_schedule_task(scheduler_queue_zone_write_callback, zwp);

            /* WARNING: From this point forward, 'zone' cannot be used anymore */

            return NULL;
        }
    }
    
    log_info("zone write text: writing '%s'", fullname_tmp);
    
    zdb_zone_lock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER);
    zdb_zone_write_text_file(zone, fullname_tmp, FALSE);
    zdb_zone_unlock(zone, ZDB_ZONE_MUTEX_SIMPLEREADER);
      
    log_info("zone write text: renaming '%s' to '%s'", fullname_tmp, zwp->file_path);
    
    if(rename(fullname_tmp, zwp->file_path) < 0)
    {
        log_err("zone write text: unable to rename tmp zone file into '%s': %r", zwp->file_path, ERRNO_ERROR);
        
        scheduler_schedule_task(scheduler_queue_zone_write_callback, zwp);

        /** @note Calling this so the scheduler gets a SCHEDULER_TASK_FINISHED is mandatory. */

        return NULL;
    }
    
    log_info("zone write text: %{dnsname} zone file written", zone->origin);

    scheduler_schedule_task(scheduler_queue_zone_write_callback, zwp);

    /* WARNING: From this point forward, 'zwp' cannot be used anymore */

    return NULL;
}
コード例 #4
0
static ya_result
config_main_verify_and_update_directory(const char *base_path, char **dirp)
{
    char fullpath[PATH_MAX];
    char tempfile[PATH_MAX];
    
    if(dirp == NULL)
    {
        return UNEXPECTED_NULL_ARGUMENT_ERROR;
    }
    
    char *dir = *dirp;
    
    if(dir == NULL)
    {
        return UNEXPECTED_NULL_ARGUMENT_ERROR;
    }

    ya_result fullpath_len = snprintf(fullpath, sizeof(fullpath),"/%s/%s", base_path, dir);
    
    if(FAIL(fullpath_len))
    {
        return fullpath_len;
    }

    bool dirsep = TRUE;
    int j = 1;
    for(int i = 1; i <= fullpath_len; i++)
    {
        char c = fullpath[i];
        if(c == '/')
        {
            if(!dirsep)
            {
                fullpath[j++] = c;
            }
            dirsep = TRUE;
        }
        else
        {
            fullpath[j++] = fullpath[i];
            dirsep = FALSE;
        }
    }
    
    struct stat ds;

    if(stat(fullpath, &ds) < 0)
    {
        int err = errno;
        ttylog_err("error: '%s': %s", fullpath, strerror(err));

        return MAKE_ERRNO_ERROR(err);
    }

    if((ds.st_mode & S_IFMT) != S_IFDIR)
    {
        ttylog_err("error: '%s' is not a directory", dir);
        
        return INVALID_PATH;
    }
    
    snformat(tempfile, sizeof(tempfile), "%s/ydf.XXXXXX", fullpath);
    int tempfd;
    if((tempfd = mkstemp(tempfile)) < 0)
    {
        int return_code = ERRNO_ERROR;
        
        ttylog_err("error: '%s' is not writable: %r", fullpath, return_code);
        
        return return_code;
    }
    unlink(tempfile);
    close_ex(tempfd);
    
    free(dir);
    *dirp = strdup(fullpath);
    
    chroot_manage_path(dirp, fullpath, FALSE);
    
    return SUCCESS;
}
コード例 #5
0
ya_result
tcp_input_output_stream_connect_sockaddr(const struct sockaddr *sa, input_stream *istream_, output_stream *ostream_, struct sockaddr *bind_from, u8 to_sec)
{
    int fd;

    while((fd = socket(sa->sa_family, SOCK_STREAM, 0)) < 0)
    {
        int err = errno;
        
        if(err != EINTR)
        {
            return MAKE_ERRNO_ERROR(err);
        }
    }
    
    /*
     * Bind the socket if required.
     */

    if(bind_from != NULL)
    {
        while((bind(fd, bind_from, sizeof(socketaddress))) < 0)
        {
            int err = errno;

            if(err != EINTR)
            {
                close_ex(fd); /* could clear errno */

                return MAKE_ERRNO_ERROR(err);
            }
        }
    }

    int ssec, susec, rsec, rusec;

    tcp_get_sendtimeout(fd, &ssec, &susec);
    tcp_get_recvtimeout(fd, &rsec, &rusec);

    tcp_set_sendtimeout(fd, to_sec, 0);
    tcp_set_recvtimeout(fd, to_sec, 0);
    
    tcp_set_nodelay(fd, tcp_nodelay);
    tcp_set_cork(fd, tcp_cork);

#if HAS_SOCKADDR_SA_LEN
    while(connect(fd, sa, sa->sa_len) < 0)
#else
    while(connect(fd, sa, sizeof(socketaddress)) < 0)
#endif
    {
        int err = errno;
        
        if(err != EINTR)
        {
            close_ex(fd);
            
            // Linux quirk
            
            if(err == EINPROGRESS)
            {
                err = ETIMEDOUT;
            }
            
            return MAKE_ERRNO_ERROR(err);
        }
    }
    
    /* can only fail if fd < 0, which is never the case here */
    
    fd_input_stream_attach(istream_, fd);
    fd_output_stream_attach_noclose(ostream_, fd);

    tcp_set_sendtimeout(fd, ssec, susec);
    tcp_set_recvtimeout(fd, rsec, rusec);

    return fd;
}