Ejemplo n.º 1
0
static int
get_phys(void)
{
	int padsz = 0;
	int res;
	int phyblk;
	struct mtop mb;
	char scbuf[MAXBLK];

	/*
	 * move to the file mark, and then back up one record and read it.
	 * this should tell us the physical record size the tape is using.
	 */
	if (lstrval == 1) {
		/*
		 * we know we are at file mark when we get back a 0 from
		 * read()
		 */
		while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0)
			padsz += res;
		if (res < 0) {
			syswarn(1, errno, "Unable to locate tape filemark.");
			return(-1);
		}
	}

	/*
	 * move backwards over the file mark so we are at the end of the
	 * last record.
	 */
	mb.mt_op = MTBSF;
	mb.mt_count = 1;
	if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
		syswarn(1, errno, "Unable to backspace over tape filemark.");
		return(-1);
	}

	/*
	 * move backwards so we are in front of the last record and read it to
	 * get physical tape blocksize.
	 */
	mb.mt_op = MTBSR;
	mb.mt_count = 1;
	if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
		syswarn(1, errno, "Unable to backspace over last tape block.");
		return(-1);
	}
	if ((phyblk = read(arfd, scbuf, sizeof(scbuf))) <= 0) {
		syswarn(1, errno, "Cannot determine archive tape blocksize.");
		return(-1);
	}

	/*
	 * read forward to the file mark, then back up in front of the filemark
	 * (this is a bit paranoid, but should be safe to do).
	 */
	while ((res = read(arfd, scbuf, sizeof(scbuf))) > 0)
		;
	if (res < 0) {
		syswarn(1, errno, "Unable to locate tape filemark.");
		return(-1);
	}
	mb.mt_op = MTBSF;
	mb.mt_count = 1;
	if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
		syswarn(1, errno, "Unable to backspace over tape filemark.");
		return(-1);
	}

	/*
	 * set lstrval so we know that the filemark has not been seen
	 */
	lstrval = 1;

	/*
	 * return if there was no padding
	 */
	if (padsz == 0)
		return(phyblk);

	/*
	 * make sure we can move backwards over the padding. (this should
	 * never fail).
	 */
	if (padsz % phyblk) {
		paxwarn(1, "Tape drive unable to backspace requested amount");
		return(-1);
	}

	/*
	 * move backwards over the padding so the head is where it was when
	 * we were first called (if required).
	 */
	mb.mt_op = MTBSR;
	mb.mt_count = padsz/phyblk;
	if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
		syswarn(1,errno,"Unable to backspace tape over %d pad blocks",
		    mb.mt_count);
		return(-1);
	}
	return(phyblk);
}
Ejemplo n.º 2
0
/*
 * Create a new client struct from a file descriptor and establish a GSS-API
 * context as a specified service with an incoming client and fills out the
 * client struct.  Returns a new client struct on success and NULL on failure,
 * logging an appropriate error message.
 */
struct client *
server_new_client(int fd, gss_cred_id_t creds)
{
    struct client *client;
    struct sockaddr_storage ss;
    socklen_t socklen;
    size_t length;
    char *buffer;
    gss_buffer_desc send_tok, recv_tok, name_buf;
    gss_name_t name = GSS_C_NO_NAME;
    gss_OID doid;
    OM_uint32 major = 0;
    OM_uint32 minor = 0;
    OM_uint32 acc_minor, time_rec;
    int flags, status;
    static const OM_uint32 req_gss_flags
        = (GSS_C_MUTUAL_FLAG | GSS_C_CONF_FLAG | GSS_C_INTEG_FLAG);

    /* Create and initialize a new client struct. */
    client = xcalloc(1, sizeof(struct client));
    client->fd = fd;
    client->context = GSS_C_NO_CONTEXT;

    /* Fill in hostname and IP address. */
    socklen = sizeof(ss);
    if (getpeername(fd, (struct sockaddr *) &ss, &socklen) != 0) {
        syswarn("cannot get peer address");
        goto fail;
    }
    length = INET6_ADDRSTRLEN;
    buffer = xmalloc(length);
    client->ipaddress = buffer;
    status = getnameinfo((struct sockaddr *) &ss, socklen, buffer, length,
                         NULL, 0, NI_NUMERICHOST);
    if (status != 0) {
        syswarn("cannot translate IP address of client: %s",
                gai_strerror(status));
        goto fail;
    }
    length = NI_MAXHOST;
    buffer = xmalloc(length);
    status = getnameinfo((struct sockaddr *) &ss, socklen, buffer, length,
                         NULL, 0, NI_NAMEREQD);
    if (status == 0)
        client->hostname = buffer;
    else
        free(buffer);

    /* Accept the initial (worthless) token. */
    status = token_recv(client->fd, &flags, &recv_tok, TOKEN_MAX_LENGTH,
                        TIMEOUT);
    if (status != TOKEN_OK) {
        warn_token("receiving initial token", status, major, minor);
        goto fail;
    }
    free(recv_tok.value);
    if (flags == (TOKEN_NOOP | TOKEN_CONTEXT_NEXT | TOKEN_PROTOCOL))
        client->protocol = 2;
    else if (flags == (TOKEN_NOOP | TOKEN_CONTEXT_NEXT))
        client->protocol = 1;
    else {
        warn("bad token flags %d in initial token", flags);
        goto fail;
    }

    /* Now, do the real work of negotiating the context. */
    do {
        status = token_recv(client->fd, &flags, &recv_tok, TOKEN_MAX_LENGTH,
                            TIMEOUT);
        if (status != TOKEN_OK) {
            warn_token("receiving context token", status, major, minor);
            goto fail;
        }
        if (flags == TOKEN_CONTEXT)
            client->protocol = 1;
        else if (flags != (TOKEN_CONTEXT | TOKEN_PROTOCOL)) {
            warn("bad token flags %d in context token", flags);
            free(recv_tok.value);
            goto fail;
        }
        debug("received context token (size=%lu)",
              (unsigned long) recv_tok.length);
        major = gss_accept_sec_context(&acc_minor, &client->context, creds,
                    &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &name, &doid,
                    &send_tok, &client->flags, &time_rec, NULL);
        free(recv_tok.value);

        /* Send back a token if we need to. */
        if (send_tok.length != 0) {
            debug("sending context token (size=%lu)",
                  (unsigned long) send_tok.length);
            flags = TOKEN_CONTEXT;
            if (client->protocol > 1)
                flags |= TOKEN_PROTOCOL;
            status = token_send(client->fd, flags, &send_tok, TIMEOUT);
            if (status != TOKEN_OK) {
                warn_token("sending context token", status, major, minor);
                gss_release_buffer(&minor, &send_tok);
                goto fail;
            }
            gss_release_buffer(&minor, &send_tok);
        }

        /* Bail out if we lose. */
        if (major != GSS_S_COMPLETE && major != GSS_S_CONTINUE_NEEDED) {
            warn_gssapi("while accepting context", major, acc_minor);
            goto fail;
        }
        if (major == GSS_S_CONTINUE_NEEDED)
            debug("continue needed while accepting context");
    } while (major == GSS_S_CONTINUE_NEEDED);

    /* Make sure that the appropriate context flags are set. */
    if (client->protocol > 1) {
        if ((client->flags & req_gss_flags) != req_gss_flags) {
            warn("client did not negotiate appropriate GSS-API flags");
            goto fail;
        }
    }

    /* Based on the protocol, set up the callbacks. */
    if (client->protocol == 1) {
        client->setup = server_v1_command_setup;
        client->finish = server_v1_send_output;
        client->error = server_v1_send_error;
    } else {
        client->setup = server_v2_command_setup;
        client->finish = server_v2_command_finish;
        client->error = server_v2_send_error;
    }

    /* Get the display version of the client name and store it. */
    major = gss_display_name(&minor, name, &name_buf, &doid);
    if (major != GSS_S_COMPLETE) {
        warn_gssapi("while displaying client name", major, minor);
        goto fail;
    }
    gss_release_name(&minor, &name);
    if (gss_oid_equal(doid, GSS_C_NT_ANONYMOUS))
        client->anonymous = true;
    client->user = xstrndup(name_buf.value, name_buf.length);
    client->expires = time(NULL) + time_rec;
    gss_release_buffer(&minor, &name_buf);
    return client;

fail:
    if (client->context != GSS_C_NO_CONTEXT)
        gss_delete_sec_context(&minor, &client->context, GSS_C_NO_BUFFER);
    if (name != GSS_C_NO_NAME)
        gss_release_name(&minor, &name);
    free(client->ipaddress);
    free(client->hostname);
    free(client);
    return NULL;
}
Ejemplo n.º 3
0
int
ar_open(const char *name)
{
	struct mtget mb;

	if (arfd != -1)
		(void)close(arfd);
	arfd = -1;
	can_unlnk = did_io = io_ok = invld_rec = 0;
	artyp = ISREG;
	flcnt = 0;

	/*
	 * open based on overall operation mode
	 */
	switch (act) {
	case LIST:
	case EXTRACT:
		if (name == NULL) {
			arfd = STDIN_FILENO;
			arcname = stdn;
		} else if ((arfd = open(name, EXT_MODE, DMOD)) < 0)
			syswarn(0, errno, "Failed open to read on %s", name);
		if (arfd != -1 && gzip_program != NULL)
			ar_start_gzip(arfd, gzip_program, 0);
		break;
	case ARCHIVE:
		if (name == NULL) {
			arfd = STDOUT_FILENO;
			arcname = stdo;
		} else if ((arfd = open(name, AR_MODE, DMOD)) < 0)
			syswarn(0, errno, "Failed open to write on %s", name);
		else
			can_unlnk = 1;
		if (arfd != -1 && gzip_program != NULL)
			ar_start_gzip(arfd, gzip_program, 1);
		break;
	case APPND:
		if (name == NULL) {
			arfd = STDOUT_FILENO;
			arcname = stdo;
		} else if ((arfd = open(name, APP_MODE, DMOD)) < 0)
			syswarn(0, errno, "Failed open to read/write on %s",
				name);
		break;
	case COPY:
		/*
		 * arfd not used in COPY mode
		 */
		arcname = none;
		lstrval = 1;
		return(0);
	}
	if (arfd < 0)
		return(-1);

	if (chdname != NULL)
		if (chdir(chdname) != 0) {
			syswarn(1, errno, "Failed chdir to %s", chdname);
			return(-1);
		}
	/*
	 * set up is based on device type
	 */
	if (fstat(arfd, &arsb) < 0) {
		syswarn(0, errno, "Failed stat on %s", arcname);
		(void)close(arfd);
		arfd = -1;
		can_unlnk = 0;
		return(-1);
	}
	if (S_ISDIR(arsb.st_mode)) {
		paxwarn(0, "Cannot write an archive on top of a directory %s",
		    arcname);
		(void)close(arfd);
		arfd = -1;
		can_unlnk = 0;
		return(-1);
	}

	if (S_ISCHR(arsb.st_mode))
		artyp = ioctl(arfd, MTIOCGET, &mb) ? ISCHR : ISTAPE;
	else if (S_ISBLK(arsb.st_mode))
		artyp = ISBLK;
	else if ((lseek(arfd, (off_t)0L, SEEK_CUR) == -1) && (errno == ESPIPE))
		artyp = ISPIPE;
	else
		artyp = ISREG;

	/*
	 * make sure we beyond any doubt that we only can unlink regular files
	 * we created
	 */
	if (artyp != ISREG)
		can_unlnk = 0;
	/*
	 * if we are writing, we are done
	 */
	if (act == ARCHIVE) {
		blksz = rdblksz = wrblksz;
		lstrval = 1;
		return(0);
	}

	/*
	 * set default blksz on read. APPNDs writes rdblksz on the last volume
	 * On all new archive volumes, we shift to wrblksz (if the user
	 * specified one, otherwise we will continue to use rdblksz). We
	 * must to set blocksize based on what kind of device the archive is
	 * stored.
	 */
	switch(artyp) {
	case ISTAPE:
		/*
		 * Tape drives come in at least two flavors. Those that support
		 * variable sized records and those that have fixed sized
		 * records. They must be treated differently. For tape drives
		 * that support variable sized records, we must make large
		 * reads to make sure we get the entire record, otherwise we
		 * will just get the first part of the record (up to size we
		 * asked). Tapes with fixed sized records may or may not return
		 * multiple records in a single read. We really do not care
		 * what the physical record size is UNLESS we are going to
		 * append. (We will need the physical block size to rewrite
		 * the trailer). Only when we are appending do we go to the
		 * effort to figure out the true PHYSICAL record size.
		 */
		blksz = rdblksz = MAXBLK;
		break;
	case ISPIPE:
	case ISBLK:
	case ISCHR:
		/*
		 * Blocksize is not a major issue with these devices (but must
		 * be kept a multiple of 512). If the user specified a write
		 * block size, we use that to read. Under append, we must
		 * always keep blksz == rdblksz. Otherwise we go ahead and use
		 * the device optimal blocksize as (and if) returned by stat
		 * and if it is within pax specs.
		 */
		if ((act == APPND) && wrblksz) {
			blksz = rdblksz = wrblksz;
			break;
		}

		if ((arsb.st_blksize > 0) && (arsb.st_blksize < MAXBLK) &&
		    ((arsb.st_blksize % BLKMULT) == 0))
			rdblksz = arsb.st_blksize;
		else
			rdblksz = DEVBLK;
		/*
		 * For performance go for large reads when we can without harm
		 */
		if ((act == APPND) || (artyp == ISCHR))
			blksz = rdblksz;
		else
			blksz = MAXBLK;
		break;
	case ISREG:
		/*
		 * if the user specified wrblksz works, use it. Under appends
		 * we must always keep blksz == rdblksz
		 */
		if ((act == APPND) && wrblksz && ((arsb.st_size%wrblksz)==0)){
			blksz = rdblksz = wrblksz;
			break;
		}
		/*
		 * See if we can find the blocking factor from the file size
		 */
		for (rdblksz = MAXBLK; rdblksz > 0; rdblksz -= BLKMULT)
			if ((arsb.st_size % rdblksz) == 0)
				break;
		/*
		 * When we cannot find a match, we may have a flawed archive.
		 */
		if (rdblksz <= 0)
			rdblksz = FILEBLK;
		/*
		 * for performance go for large reads when we can
		 */
		if (act == APPND)
			blksz = rdblksz;
		else
			blksz = MAXBLK;
		break;
	default:
		/*
		 * should never happen, worse case, slow...
		 */
		blksz = rdblksz = BLKMULT;
		break;
	}
	lstrval = 1;
	return(0);
}
Ejemplo n.º 4
0
static int
gen_init(void)
{
	struct rlimit reslimit;
	struct sigaction n_hand;
	struct sigaction o_hand;

	/*
	 * Really needed to handle large archives. We can run out of memory for
	 * internal tables really fast when we have a whole lot of files...
	 */
	if (getrlimit(RLIMIT_DATA , &reslimit) == 0){
		reslimit.rlim_cur = reslimit.rlim_max;
		(void)setrlimit(RLIMIT_DATA , &reslimit);
	}

	/*
	 * should file size limits be waived? if the os limits us, this is
	 * needed if we want to write a large archive
	 */
	if (getrlimit(RLIMIT_FSIZE , &reslimit) == 0){
		reslimit.rlim_cur = reslimit.rlim_max;
		(void)setrlimit(RLIMIT_FSIZE , &reslimit);
	}

	/*
	 * increase the size the stack can grow to
	 */
	if (getrlimit(RLIMIT_STACK , &reslimit) == 0){
		reslimit.rlim_cur = reslimit.rlim_max;
		(void)setrlimit(RLIMIT_STACK , &reslimit);
	}

	/*
	 * not really needed, but doesn't hurt
	 */
	if (getrlimit(RLIMIT_RSS , &reslimit) == 0){
		reslimit.rlim_cur = reslimit.rlim_max;
		(void)setrlimit(RLIMIT_RSS , &reslimit);
	}

	/*
	 * signal handling to reset stored directory times and modes. Since
	 * we deal with broken pipes via failed writes we ignore it. We also
	 * deal with any file size limit thorough failed writes. Cpu time
	 * limits are caught and a cleanup is forced.
	 */
	if ((sigemptyset(&s_mask) < 0) || (sigaddset(&s_mask, SIGTERM) < 0) ||
	    (sigaddset(&s_mask,SIGINT) < 0)||(sigaddset(&s_mask,SIGHUP) < 0) ||
	    (sigaddset(&s_mask,SIGPIPE) < 0)||(sigaddset(&s_mask,SIGQUIT)<0) ||
	    (sigaddset(&s_mask,SIGXCPU) < 0)||(sigaddset(&s_mask,SIGXFSZ)<0)) {
		paxwarn(1, "Unable to set up signal mask");
		return(-1);
	}
	memset(&n_hand, 0, sizeof n_hand);
	n_hand.sa_mask = s_mask;
	n_hand.sa_flags = 0;
	n_hand.sa_handler = sig_cleanup;

	if ((sigaction(SIGHUP, &n_hand, &o_hand) < 0) &&
	    (o_hand.sa_handler == SIG_IGN) &&
	    (sigaction(SIGHUP, &o_hand, &o_hand) < 0))
		goto out;

	if ((sigaction(SIGTERM, &n_hand, &o_hand) < 0) &&
	    (o_hand.sa_handler == SIG_IGN) &&
	    (sigaction(SIGTERM, &o_hand, &o_hand) < 0))
		goto out;

	if ((sigaction(SIGINT, &n_hand, &o_hand) < 0) &&
	    (o_hand.sa_handler == SIG_IGN) &&
	    (sigaction(SIGINT, &o_hand, &o_hand) < 0))
		goto out;

	if ((sigaction(SIGQUIT, &n_hand, &o_hand) < 0) &&
	    (o_hand.sa_handler == SIG_IGN) &&
	    (sigaction(SIGQUIT, &o_hand, &o_hand) < 0))
		goto out;

	if ((sigaction(SIGXCPU, &n_hand, &o_hand) < 0) &&
	    (o_hand.sa_handler == SIG_IGN) &&
	    (sigaction(SIGXCPU, &o_hand, &o_hand) < 0))
		goto out;

	n_hand.sa_handler = SIG_IGN;
	if ((sigaction(SIGPIPE, &n_hand, &o_hand) < 0) ||
	    (sigaction(SIGXFSZ, &n_hand, &o_hand) < 0))
		goto out;
	return(0);

    out:
	syswarn(1, errno, "Unable to set up signal handler");
	return(-1);
}
Ejemplo n.º 5
0
int
next_file(ARCHD *arcn)
{
    int cnt;
    time_t atime;
    time_t mtime;

    /*
     * ftree_sel() might have set the ftree_skip flag if the user has the
     * -n option and a file was selected from this file arg tree. (-n says
     * only one member is matched for each pattern) ftree_skip being 1
     * forces us to go to the next arg now.
     */
    if (ftree_skip) {
        /*
         * clear and go to next arg
         */
        ftree_skip = 0;
        if (ftree_arg() < 0)
            return(-1);
    }

    /*
     * loop until we get a valid file to process
     */
    for (;;) {
        if ((ftent = fts_read(ftsp)) == NULL) {
            if (errno)
                syswarn(1, errno, "next_file");
            /*
             * out of files in this tree, go to next arg, if none
             * we are done
             */
            if (ftree_arg() < 0)
                return(-1);
            continue;
        }

        /*
         * handle each type of fts_read() flag
         */
        switch (ftent->fts_info) {
        case FTS_D:
        case FTS_DEFAULT:
        case FTS_F:
        case FTS_SL:
        case FTS_SLNONE:
            /*
             * these are all ok
             */
            break;
        case FTS_DP:
            /*
             * already saw this directory. If the user wants file
             * access times reset, we use this to restore the
             * access time for this directory since this is the
             * last time we will see it in this file subtree
             * remember to force the time (this is -t on a read
             * directory, not a created directory).
             */
            if (!tflag || (get_atdir(ftent->fts_statp->st_dev,
                                     ftent->fts_statp->st_ino, &mtime, &atime) < 0))
                continue;
            set_ftime(ftent->fts_path, mtime, atime, 1);
            continue;
        case FTS_DC:
            /*
             * fts claims a file system cycle
             */
            paxwarn(1,"File system cycle found at %s",ftent->fts_path);
            continue;
        case FTS_DNR:
            syswarn(1, ftent->fts_errno,
                    "Unable to read directory %s", ftent->fts_path);
            continue;
        case FTS_ERR:
            syswarn(1, ftent->fts_errno,
                    "File system traversal error");
            continue;
        case FTS_NS:
        case FTS_NSOK:
            syswarn(1, ftent->fts_errno,
                    "Unable to access %s", ftent->fts_path);
            continue;
        }

        /*
         * ok got a file tree node to process. copy info into arcn
         * structure (initialize as required)
         */
        arcn->skip = 0;
        arcn->pad = 0;
        arcn->ln_nlen = 0;
        arcn->ln_name[0] = '\0';
        memcpy(&arcn->sb, ftent->fts_statp, sizeof(arcn->sb));

        /*
         * file type based set up and copy into the arcn struct
         * SIDE NOTE:
         * we try to reset the access time on all files and directories
         * we may read when the -t flag is specified. files are reset
         * when we close them after copying. we reset the directories
         * when we are done with their file tree (we also clean up at
         * end in case we cut short a file tree traversal). However
         * there is no way to reset access times on symlinks.
         */
        switch (S_IFMT & arcn->sb.st_mode) {
        case S_IFDIR:
            arcn->type = PAX_DIR;
            if (!tflag)
                break;
            add_atdir(ftent->fts_path, arcn->sb.st_dev,
                      arcn->sb.st_ino, arcn->sb.st_mtime,
                      arcn->sb.st_atime);
            break;
        case S_IFCHR:
            arcn->type = PAX_CHR;
            break;
        case S_IFBLK:
            arcn->type = PAX_BLK;
            break;
        case S_IFREG:
            /*
             * only regular files with have data to store on the
             * archive. all others will store a zero length skip.
             * the skip field is used by pax for actual data it has
             * to read (or skip over).
             */
            arcn->type = PAX_REG;
            arcn->skip = arcn->sb.st_size;
            break;
        case S_IFLNK:
            arcn->type = PAX_SLK;
            /*
             * have to read the symlink path from the file
             */
            if ((cnt = readlink(ftent->fts_path, arcn->ln_name,
                                PAXPATHLEN)) < 0) {
                syswarn(1, errno, "Unable to read symlink %s",
                        ftent->fts_path);
                continue;
            }
            /*
             * set link name length, watch out readlink does not
             * always NUL terminate the link path
             */
            arcn->ln_name[cnt] = '\0';
            arcn->ln_nlen = cnt;
            break;
        case S_IFSOCK:
            /*
             * under BSD storing a socket is senseless but we will
             * let the format specific write function make the
             * decision of what to do with it.
             */
            arcn->type = PAX_SCK;
            break;
        case S_IFIFO:
            arcn->type = PAX_FIF;
            break;
        }
        break;
    }

    /*
     * copy file name, set file name length
     */
    arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name));
    if (arcn->nlen >= sizeof(arcn->name))
        arcn->nlen = sizeof(arcn->name) - 1; /* XXX truncate? */
    arcn->org_name = ftent->fts_path;
    return(0);
}
Ejemplo n.º 6
0
static int
mk_link(char *to, struct stat *to_sb, char *from, int ign)
{
	struct stat sb;
	int oerrno;

	/*
	 * if from file exists, it has to be unlinked to make the link. If the
	 * file exists and -k is set, skip it quietly
	 */
	if (lstat(from, &sb) == 0) {
		if (kflag)
			return(0);

		/*
		 * make sure it is not the same file, protect the user
		 */
		if ((to_sb->st_dev==sb.st_dev)&&(to_sb->st_ino == sb.st_ino)) {
			paxwarn(1, "Unable to link file %s to itself", to);
			return(-1);;
		}

		/*
		 * try to get rid of the file, based on the type
		 */
		if (S_ISDIR(sb.st_mode)) {
			if (rmdir(from) < 0) {
				syswarn(1, errno, "Unable to remove %s", from);
				return(-1);
			}
		} else if (unlink(from) < 0) {
			if (!ign) {
				syswarn(1, errno, "Unable to remove %s", from);
				return(-1);
			}
			return(1);
		}
	}

	/*
	 * from file is gone (or did not exist), try to make the hard link.
	 * if it fails, check the path and try it again (if chk_path() says to
	 * try again)
	 */
	for (;;) {
		if (link(to, from) == 0)
			break;
		oerrno = errno;
		if (!nodirs && chk_path(from, to_sb->st_uid, to_sb->st_gid) == 0)
			continue;
		if (!ign) {
			syswarn(1, oerrno, "Could not link to %s from %s", to,
			    from);
			return(-1);
		}
		return(1);
	}

	/*
	 * all right the link was made
	 */
	return(0);
}
Ejemplo n.º 7
0
int
file_write(int fd, char *str, int cnt, int *rem, int *isempt, int sz,
	char *name)
{
	char *pt;
	char *end;
	int wcnt;
	char *st = str;

	/*
	 * while we have data to process
	 */
	while (cnt) {
		if (!*rem) {
			/*
			 * We are now at the start of file system block again
			 * (or what we think one is...). start looking for
			 * empty blocks again
			 */
			*isempt = 1;
			*rem = sz;
		}

		/*
		 * only examine up to the end of the current file block or
		 * remaining characters to write, whatever is smaller
		 */
		wcnt = MIN(cnt, *rem);
		cnt -= wcnt;
		*rem -= wcnt;
		if (*isempt) {
			/*
			 * have not written to this block yet, so we keep
			 * looking for zero's
			 */
			pt = st;
			end = st + wcnt;

			/*
			 * look for a zero filled buffer
			 */
			while ((pt < end) && (*pt == '\0'))
				++pt;

			if (pt == end) {
				/*
				 * skip, buf is empty so far
				 */
				if (fd > -1 &&
				    lseek(fd, (off_t)wcnt, SEEK_CUR) < 0) {
					syswarn(1,errno,"File seek on %s",
					    name);
					return(-1);
				}
				st = pt;
				continue;
			}
			/*
			 * drat, the buf is not zero filled
			 */
			*isempt = 0;
		}

		/*
		 * have non-zero data in this file system block, have to write
		 */
		if (fd == -1) {
			/* GNU hack */
			if (gnu_hack_string)
				err(1, "WARNING! Major Internal Error! GNU hack Failing!");
			gnu_hack_string = malloc(wcnt + 1);
			if (gnu_hack_string == NULL) {
				paxwarn(1, "Out of memory");
				return(-1);
			}
			memcpy(gnu_hack_string, st, wcnt);
			gnu_hack_string[wcnt] = '\0';
		} else if (write(fd, st, wcnt) != wcnt) {
			syswarn(1, errno, "Failed write to file %s", name);
			return(-1);
		}
		st += wcnt;
	}
	return(st - str);
}
Ejemplo n.º 8
0
int
chk_ftime(ARCHD *arcn)
{
	FTM *pt;
	int namelen;
	u_int indx;
	char ckname[PAXPATHLEN+1];

	/*
	 * no info, go ahead and add to archive
	 */
	if (ftab == NULL)
		return(0);

	/*
	 * hash the pathname and look up in table
	 */
	namelen = arcn->nlen;
	indx = st_hash(arcn->name, namelen, F_TAB_SZ);
	if ((pt = ftab[indx]) != NULL) {
		/*
		 * the hash chain is not empty, walk down looking for match
		 * only read up the path names if the lengths match, speeds
		 * up the search a lot
		 */
		while (pt != NULL) {
			if (pt->namelen == namelen) {
				/*
				 * potential match, have to read the name
				 * from the scratch file.
				 */
				if (lseek(ffd,pt->seek,SEEK_SET) != pt->seek) {
					syswarn(1, errno,
					    "Failed ftime table seek");
					return(-1);
				}
				if (read(ffd, ckname, namelen) != namelen) {
					syswarn(1, errno,
					    "Failed ftime table read");
					return(-1);
				}

				/*
				 * if the names match, we are done
				 */
				if (!strncmp(ckname, arcn->name, namelen))
					break;
			}

			/*
			 * try the next entry on the chain
			 */
			pt = pt->fow;
		}

		if (pt != NULL) {
			/*
			 * found the file, compare the times, save the newer
			 */
			if (arcn->sb.st_mtime > pt->mtime) {
				/*
				 * file is newer
				 */
				pt->mtime = arcn->sb.st_mtime;
				return(0);
			}
			/*
			 * file is older
			 */
			return(1);
		}
	}

	/*
	 * not in table, add it
	 */
	if ((pt = (FTM *)malloc(sizeof(FTM))) != NULL) {
		/*
		 * add the name at the end of the scratch file, saving the
		 * offset. add the file to the head of the hash chain
		 */
		if ((pt->seek = lseek(ffd, (off_t)0, SEEK_END)) >= 0) {
			if (write(ffd, arcn->name, namelen) == namelen) {
				pt->mtime = arcn->sb.st_mtime;
				pt->namelen = namelen;
				pt->fow = ftab[indx];
				ftab[indx] = pt;
				return(0);
			}
			syswarn(1, errno, "Failed write to file time table");
		} else
			syswarn(1, errno, "Failed seek on file time table");
	} else
		paxwarn(1, "File time table ran out of memory");

	if (pt != NULL)
		free(pt);
	return(-1);
}
Ejemplo n.º 9
0
int
rd_wrfile(ARCHD *arcn, int ofd, off_t *left)
{
    int cnt = 0;
    off_t size = arcn->sb.st_size;
    int res = 0;
    char *fnm = arcn->name;
    int isem = 1;
    int rem;
    int sz = MINFBSZ;
    struct stat sb;
    u_long crc = 0L;

    /*
     * pass the blocksize of the file being written to the write routine,
     * if the size is zero, use the default MINFBSZ
     */
    if (fstat(ofd, &sb) == 0) {
        if (sb.st_blksize > 0)
            sz = (int)sb.st_blksize;
    } else
        syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
    rem = sz;
    *left = 0L;

    /*
     * Copy the archive to the file the number of bytes specified. We have
     * to assume that we want to recover file holes as none of the archive
     * formats can record the location of file holes.
     */
    while (size > 0L) {
        cnt = bufend - bufpt;
        /*
         * if we get a read error, we do not want to skip, as we may
         * miss a header, so we do not set left, but if we get a write
         * error, we do want to skip over the unprocessed data.
         */
        if ((cnt <= 0) && ((cnt = buf_fill()) <= 0))
            break;
        cnt = MIN(cnt, size);
        if ((res = file_write(ofd,bufpt,cnt,&rem,&isem,sz,fnm)) <= 0) {
            *left = size;
            break;
        }

        if (docrc) {
            /*
             * update the actual crc value
             */
            cnt = res;
            while (--cnt >= 0)
                crc += *bufpt++ & 0xff;
        } else
            bufpt += res;
        size -= res;
    }

    /*
     * if the last block has a file hole (all zero), we must make sure this
     * gets updated in the file. We force the last block of zeros to be
     * written. just closing with the file offset moved forward may not put
     * a hole at the end of the file.
     */
    if (isem && (arcn->sb.st_size > 0L))
        file_flush(ofd, fnm, isem);

    /*
     * if we failed from archive read, we do not want to skip
     */
    if ((size > 0L) && (*left == 0L))
        return(-1);

    /*
     * some formats record a crc on file data. If so, then we compare the
     * calculated crc to the crc stored in the archive
     */
    if (docrc && (size == 0L) && (arcn->crc != crc))
        paxwarn(1,"Actual crc does not match expected crc %s",arcn->name);
    return(0);
}
Ejemplo n.º 10
0
int
next_file(ARCHD *arcn)
{
#ifndef SMALL
	static	char	curdir[PAXPATHLEN+2], curpath[PAXPATHLEN+2];
	static	int	curdirlen;

	struct stat	statbuf;
	FTSENT		Mftent;
#endif	/* SMALL */
	int		cnt;
	time_t		atime, mtime;
	char		*curlink;
#define MFTENT_DUMMY_DEV	UINT_MAX

	curlink = NULL;
#ifndef SMALL
	/*
	 * if parsing an mtree(8) specfile, build up `dummy' ftsent
	 * from specfile info, and jump below to complete setup of arcn.
	 */
	if (Mflag) {
		int	skipoptional;

 next_ftnode:
		skipoptional = 0;
		if (ftnode == NULL)		/* tree is empty */
			return (-1);

						/* get current name */
		if (snprintf(curpath, sizeof(curpath), "%s%s%s",
		    curdir, curdirlen ? "/" : "", ftnode->name)
		    >= sizeof(curpath)) {
			tty_warn(1, "line %lu: %s: %s", (u_long)ftnode->lineno,
			    curdir, strerror(ENAMETOOLONG));
			return (-1);
		}
		ftnode->flags |= F_VISIT;	/* mark node visited */

						/* construct dummy FTSENT */
		Mftent.fts_path = curpath;
		Mftent.fts_statp = &statbuf;
		Mftent.fts_pointer = ftnode;
		ftent = &Mftent;
						/* look for existing file */
		if (lstat(Mftent.fts_path, &statbuf) == -1) {
			if (ftnode->flags & F_OPT)
				skipoptional = 1;

						/* missing: fake up stat info */
			memset(&statbuf, 0, sizeof(statbuf));
			statbuf.st_dev = MFTENT_DUMMY_DEV;
			statbuf.st_ino = ftnode->lineno;
			statbuf.st_size = 0;
#define NODETEST(t, m)							\
			if (!(t)) {					\
				tty_warn(1, "line %lu: %s: %s not specified", \
				    (u_long)ftnode->lineno,		\
				    ftent->fts_path, m);		\
				return -1;				\
			}
			statbuf.st_mode = nodetoino(ftnode->type);
			NODETEST(ftnode->flags & F_TYPE, "type");
			NODETEST(ftnode->flags & F_MODE, "mode");
			if (!(ftnode->flags & F_TIME))
				statbuf.st_mtime = starttime;
			NODETEST(ftnode->flags & (F_GID | F_GNAME), "group");
			NODETEST(ftnode->flags & (F_UID | F_UNAME), "user");
			if (ftnode->type == F_BLOCK || ftnode->type == F_CHAR)
				NODETEST(ftnode->flags & F_DEV,
				    "device number");
			if (ftnode->type == F_LINK)
				NODETEST(ftnode->flags & F_SLINK, "symlink");
			/* don't require F_FLAGS or F_SIZE */
#undef NODETEST
		} else {
			if (ftnode->flags & F_TYPE && nodetoino(ftnode->type)
			    != (statbuf.st_mode & S_IFMT)) {
				tty_warn(1,
			    "line %lu: %s: type mismatch: specfile %s, tree %s",
				    (u_long)ftnode->lineno, ftent->fts_path,
				    inotype(nodetoino(ftnode->type)),
				    inotype(statbuf.st_mode));
				return -1;
			}
			if (ftnode->type == F_DIR && (ftnode->flags & F_OPT))
				skipoptional = 1;
		}
		/*
		 * override settings with those from specfile
		 */
		if (ftnode->flags & F_MODE) {
			statbuf.st_mode &= ~ALLPERMS; 
			statbuf.st_mode |= (ftnode->st_mode & ALLPERMS);
		}
		if (ftnode->flags & (F_GID | F_GNAME))
			statbuf.st_gid = ftnode->st_gid;
		if (ftnode->flags & (F_UID | F_UNAME))
			statbuf.st_uid = ftnode->st_uid;
#if HAVE_FILE_FLAGS
		if (ftnode->flags & F_FLAGS)
			statbuf.st_flags = ftnode->st_flags;
#endif
		if (ftnode->flags & F_TIME)
#if BSD4_4 && !HAVE_NBTOOL_CONFIG_H
			statbuf.st_mtimespec = ftnode->st_mtimespec;
#else
			statbuf.st_mtime = ftnode->st_mtimespec.tv_sec;
#endif
		if (ftnode->flags & F_DEV)
			statbuf.st_rdev = ftnode->st_rdev;
		if (ftnode->flags & F_SLINK)
			curlink = ftnode->slink;
				/* ignore F_SIZE */

		/*
		 * find next node
		 */
		if (ftnode->type == F_DIR && ftnode->child != NULL) {
					/* directory with unseen child */
			ftnode = ftnode->child;
			curdirlen = strlcpy(curdir, curpath, sizeof(curdir));
		} else do {
			if (ftnode->next != NULL) {
					/* next node at current level */
				ftnode = ftnode->next;
			} else {	/* move back to parent */
					/* reset time only on first cd.. */
				if (Mftent.fts_pointer == ftnode && tflag &&
				    (get_atdir(MFTENT_DUMMY_DEV, ftnode->lineno,
				    &mtime, &atime) == 0)) {
					set_ftime(ftent->fts_path,
					    mtime, atime, 1);
				}
				ftnode = ftnode->parent;
				if (ftnode->parent == ftnode)
					ftnode = NULL;
				else {
					curdirlen -= strlen(ftnode->name) + 1;
					curdir[curdirlen] = '\0';
				}
			}
		} while (ftnode != NULL && ftnode->flags & F_VISIT);
		if (skipoptional)	/* skip optional entries */
			goto next_ftnode;
		goto got_ftent;
	}
#endif	/* SMALL */

	/*
	 * ftree_sel() might have set the ftree_skip flag if the user has the
	 * -n option and a file was selected from this file arg tree. (-n says
	 * only one member is matched for each pattern) ftree_skip being 1
	 * forces us to go to the next arg now.
	 */
	if (ftree_skip) {
		/*
		 * clear and go to next arg
		 */
		ftree_skip = 0;
		if (ftree_arg() < 0)
			return -1;
	}

	if (ftsp == NULL)
		return -1;
	/*
	 * loop until we get a valid file to process
	 */
	for(;;) {
		if ((ftent = fts_read(ftsp)) == NULL) {
			/*
			 * out of files in this tree, go to next arg, if none
			 * we are done
			 */
			if (ftree_arg() < 0)
				return -1;
			continue;
		}

		/*
		 * handle each type of fts_read() flag
		 */
		switch(ftent->fts_info) {
		case FTS_D:
		case FTS_DEFAULT:
		case FTS_F:
		case FTS_SL:
		case FTS_SLNONE:
			/*
			 * these are all ok
			 */
			break;
		case FTS_DP:
			/*
			 * already saw this directory. If the user wants file
			 * access times reset, we use this to restore the
			 * access time for this directory since this is the
			 * last time we will see it in this file subtree
			 * remember to force the time (this is -t on a read
			 * directory, not a created directory).
			 */
			if (!tflag || (get_atdir(
#ifdef NET2_FTS
			    ftent->fts_statb.st_dev, ftent->fts_statb.st_ino,
#else
			    ftent->fts_statp->st_dev, ftent->fts_statp->st_ino,
#endif
			    &mtime, &atime) < 0))
				continue;
			set_ftime(ftent->fts_path, mtime, atime, 1);
			continue;
		case FTS_DC:
			/*
			 * fts claims a file system cycle
			 */
			tty_warn(1,"File system cycle found at %s",
			    ftent->fts_path);
			continue;
		case FTS_DNR:
			syswarn(1, FTS_ERRNO(ftent),
			    "Unable to read directory %s", ftent->fts_path);
			continue;
		case FTS_ERR:
			syswarn(1, FTS_ERRNO(ftent),
			    "File system traversal error");
			continue;
		case FTS_NS:
		case FTS_NSOK:
			syswarn(1, FTS_ERRNO(ftent),
			    "Unable to access %s", ftent->fts_path);
			continue;
		}

#ifndef SMALL
 got_ftent:
#endif	/* SMALL */
		/*
		 * ok got a file tree node to process. copy info into arcn
		 * structure (initialize as required)
		 */
		arcn->skip = 0;
		arcn->pad = 0;
		arcn->ln_nlen = 0;
		arcn->ln_name[0] = '\0';
#ifdef NET2_FTS
		arcn->sb = ftent->fts_statb;
#else
		arcn->sb = *(ftent->fts_statp);
#endif

		/*
		 * file type based set up and copy into the arcn struct
		 * SIDE NOTE:
		 * we try to reset the access time on all files and directories
		 * we may read when the -t flag is specified. files are reset
		 * when we close them after copying. we reset the directories
		 * when we are done with their file tree (we also clean up at
		 * end in case we cut short a file tree traversal). However
		 * there is no way to reset access times on symlinks.
		 */
		switch(S_IFMT & arcn->sb.st_mode) {
		case S_IFDIR:
			arcn->type = PAX_DIR;
			if (!tflag)
				break;
			add_atdir(ftent->fts_path, arcn->sb.st_dev,
			    arcn->sb.st_ino, arcn->sb.st_mtime,
			    arcn->sb.st_atime);
			break;
		case S_IFCHR:
			arcn->type = PAX_CHR;
			break;
		case S_IFBLK:
			arcn->type = PAX_BLK;
			break;
		case S_IFREG:
			/*
			 * only regular files with have data to store on the
			 * archive. all others will store a zero length skip.
			 * the skip field is used by pax for actual data it has
			 * to read (or skip over).
			 */
			arcn->type = PAX_REG;
			arcn->skip = arcn->sb.st_size;
			break;
		case S_IFLNK:
			arcn->type = PAX_SLK;
			if (curlink != NULL) {
				cnt = strlcpy(arcn->ln_name, curlink,
				    sizeof(arcn->ln_name));
			/*
			 * have to read the symlink path from the file
			 */
			} else if ((cnt =
			    readlink(ftent->fts_path, arcn->ln_name,
			    sizeof(arcn->ln_name) - 1)) < 0) {
				syswarn(1, errno, "Unable to read symlink %s",
				    ftent->fts_path);
				continue;
			}
			/*
			 * set link name length, watch out readlink does not
			 * allways null terminate the link path
			 */
			arcn->ln_name[cnt] = '\0';
			arcn->ln_nlen = cnt;
			break;
#ifdef S_IFSOCK
		case S_IFSOCK:
			/*
			 * under BSD storing a socket is senseless but we will
			 * let the format specific write function make the
			 * decision of what to do with it.
			 */
			arcn->type = PAX_SCK;
			break;
#endif
		case S_IFIFO:
			arcn->type = PAX_FIF;
			break;
		}
		break;
	}

	/*
	 * copy file name, set file name length
	 */
	arcn->nlen = strlcpy(arcn->name, ftent->fts_path, sizeof(arcn->name));
	arcn->org_name = arcn->fts_name;
	strlcpy(arcn->fts_name, ftent->fts_path, sizeof arcn->fts_name);
	if (strcmp(NM_CPIO, argv0) == 0) {
		/*
		 * cpio does *not* descend directories listed in the
		 * arguments, unlike pax/tar, so needs special handling
		 * here.  failure to do so results in massive amounts
		 * of duplicated files in the output. We kill fts after
		 * the first name is extracted, what a waste.
		 */
		ftcur->refcnt = 1;
		(void)ftree_arg();
	}
	return 0;
}
Ejemplo n.º 11
0
/*
 * A wrapper around fwrite that checks the return status and reports an error
 * if the write failed.  This is probably futile for stderr, since reporting
 * the error will probably also fail, but we can try.
 */
static void
fwrite_checked(const void *data, size_t size, size_t nmemb, FILE *stream)
{
    if (fwrite(data, size, nmemb, stream) != nmemb)
        syswarn("local write of command output failed");
}
Ejemplo n.º 12
0
Archivo: pax.c Proyecto: MirBSD/mircpio
int
main(int argc, char **argv)
{
	const char *tmpdir;
	size_t tdlen;

	/* may not be a constant, thus initialising early */
	listf = stderr;

	now = time(NULL);

	/*
	 * Keep a reference to cwd, so we can always come back home.
	 */
	cwdfd = binopen2(BO_CLEXEC, ".", O_RDONLY);
	if (cwdfd < 0) {
		syswarn(1, errno, "Cannot open current working directory.");
		return(exit_val);
	}

	/*
	 * Where should we put temporary files?
	 */
	if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
		tmpdir = _PATH_TMP;
	tdlen = strlen(tmpdir);
	while (tdlen > 0 && tmpdir[tdlen - 1] == '/')
		tdlen--;
	tempfile = malloc(tdlen + 1 + sizeof(_TFILE_BASE));
	if (tempfile == NULL) {
		paxwarn(1, "%s for %s", "Out of memory",
		    "temp file name");
		return (exit_val);
	}
	if (tdlen)
		memcpy(tempfile, tmpdir, tdlen);
	tempbase = tempfile + tdlen;
	*tempbase++ = '/';

#if HAVE_SETPGENT
	/*
	 * keep passwd and group files open for faster lookups.
	 */
	setpassent(1);
	setgroupent(1);
#endif

	/*
	 * parse options, determine operational mode, general init
	 */
	options(argc, argv);
	if ((gen_init() < 0) || (tty_init() < 0))
		return(exit_val);

#if HAVE_PLEDGE
	/*
	 * pmode needs to restore setugid bits when extracting or copying,
	 * so can't pledge at all then.
	 */
	if (pmode == 0 || (act != EXTRACT && act != COPY)) {
		if (pledge("stdio rpath wpath cpath fattr dpath getpw proc exec tape",
		    NULL) == -1)
			err(1, "pledge");

		/* Copy mode, or no gzip -- don't need to fork/exec. */
		if (compress_program == NULL || act == COPY) {
			if (pledge("stdio rpath wpath cpath fattr dpath getpw tape",
			    NULL) == -1)
				err(1, "pledge");
		}
	}
#endif

	/* make list fd independent and line-buffered */
	if ((listfd = dup(fileno(listf))) < 0 ||
	    !(listf = fdopen(listfd, "wb"))) {
		syswarn(1, errno, "Cannot open list file descriptor");
		return (exit_val);
	}
	if (fcntl(listfd, F_SETFD, FD_CLOEXEC) == -1)
		syswarn(0, errno, "%s on list file descriptor",
		    "Failed to set the close-on-exec flag");
	setlinebuf(listf);

	/*
	 * select a primary operation mode
	 */
	switch (act) {
	case EXTRACT:
		extract();
		break;
	case ARCHIVE:
		archive();
		break;
	case APPND:
		if (compress_program != NULL)
			errx(1, "cannot compress while appending");
		append();
		break;
	case COPY:
		copy();
		break;
	default:
		/* for ar_io.c etc. */
		act = LIST;
		/* FALLTHROUGH */
	case LIST:
		list();
		break;
	}
	return(exit_val);
}
Ejemplo n.º 13
0
/*
 * Take the amount of memory to allocate in bytes as a command-line argument
 * and call test_malloc with that amount of memory.
 */
int
main(int argc, char *argv[])
{
    size_t size, max;
    size_t limit = 0;
    int willfail = 0;
    unsigned char code;

    if (argc < 3)
        die("Usage error.  Type, size, and limit must be given.");
    errno = 0;
    size = strtol(argv[2], 0, 10);
    if (size == 0 && errno != 0)
        sysdie("Invalid size");
    errno = 0;
    limit = strtol(argv[3], 0, 10);
    if (limit == 0 && errno != 0)
        sysdie("Invalid limit");

    /* If the code is capitalized, install our customized error handler. */
    code = argv[1][0];
    if (isupper(code)) {
        xmalloc_error_handler = test_handler;
        code = tolower(code);
    }

    /*
     * Decide if the allocation should fail.  If it should, set willfail to 2,
     * so that if it unexpectedly succeeds, we exit with a status indicating
     * that the test should be skipped.
     */
    max = size;
    if (code == 's' || code == 'n' || code == 'a' || code == 'v') {
        max += size;
        if (limit > 0)
            limit += size;
    }
    if (limit > 0 && max > limit)
        willfail = 2;

    /*
     * If a memory limit was given and we can set memory limits, set it.
     * Otherwise, exit 2, signalling to the driver that the test should be
     * skipped.  We do this here rather than in the driver due to some
     * pathological problems with Linux (setting ulimit in the shell caused
     * the shell to die).
     */
    if (limit > 0) {
#if HAVE_SETRLIMIT && defined(RLIMIT_AS)
        struct rlimit rl;
        void *tmp;
        size_t test_size;

        rl.rlim_cur = limit;
        rl.rlim_max = limit;
        if (setrlimit(RLIMIT_AS, &rl) < 0) {
            syswarn("Can't set data limit to %lu", (unsigned long) limit);
            exit(2);
        }
        if (size < limit || code == 'r' || code == 'y') {
            test_size = (code == 'r' || code == 'y') ? 10 : size;
            if (test_size == 0)
                test_size = 1;
            tmp = malloc(test_size);
            if (tmp == NULL) {
                syswarn("Can't allocate initial memory of %lu (limit %lu)",
                        (unsigned long) test_size, (unsigned long) limit);
                exit(2);
            }
            free(tmp);
        }
#else
        warn("Data limits aren't supported.");
        exit(2);
#endif
    }

    switch (code) {
    case 'c': exit(test_calloc(size) ? willfail : 1);
    case 'm': exit(test_malloc(size) ? willfail : 1);
    case 'r': exit(test_realloc(size) ? willfail : 1);
    case 'y': exit(test_reallocarray(4, size / 4) ? willfail : 1);
    case 's': exit(test_strdup(size) ? willfail : 1);
    case 'n': exit(test_strndup(size) ? willfail : 1);
    case 'a': exit(test_asprintf(size) ? willfail : 1);
    case 'v': exit(test_vasprintf(size) ? willfail : 1);
    default:
        die("Unknown mode %c", argv[1][0]);
        break;
    }
    exit(1);
}
Ejemplo n.º 14
0
int
list(void)
{
	ARCHD *arcn;
	int res;
	time_t now;

	arcn = &archd;
	/*
	 * figure out archive type; pass any format specific options to the
	 * archive option processing routine; call the format init routine. We
	 * also save current time for ls_list() so we do not make a system
	 * call for each file we need to print. If verbose (vflag) start up
	 * the name and group caches.
	 */
	if ((get_arc() < 0) || ((*frmt->options)() < 0) ||
	    ((*frmt->st_rd)() < 0))
		return 1;

	now = time(NULL);

	/*
	 * step through the archive until the format says it is done
	 */
	while (next_head(arcn) == 0) {
		if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) {
			/*
			 * we need to read, to get the real filename
			 */
			off_t cnt;
			if (!(*frmt->rd_data)(arcn, -arcn->type, &cnt))
				(void)rd_skip(cnt + arcn->pad);
			continue;
		}

		/*
		 * check for pattern, and user specified options match.
		 * When all patterns are matched we are done.
		 */
		if ((res = pat_match(arcn)) < 0)
			break;

		if ((res == 0) && (sel_chk(arcn) == 0)) {
			/*
			 * pattern resulted in a selected file
			 */
			if (pat_sel(arcn) < 0)
				break;

			/*
			 * modify the name as requested by the user if name
			 * survives modification, do a listing of the file
			 */
			if ((res = mod_name(arcn, RENM)) < 0)
				break;
			if (res == 0) {
				if (arcn->name[0] == '/' && !check_Aflag()) {
					memmove(arcn->name, arcn->name + 1, 
					    strlen(arcn->name));
				}
				ls_list(arcn, now, stdout);
			}
			/*
			 * if there's an error writing to stdout then we must
			 * stop now -- we're probably writing to a pipe that
			 * has been closed by the reader.
			 */
			if (ferror(stdout)) {
				syswarn(1, errno, "Listing incomplete.");
				break;
			}
		}
		/*
		 * skip to next archive format header using values calculated
		 * by the format header read routine
		 */
		if (rd_skip(arcn->skip + arcn->pad) == 1)
			break;
	}

	/*
	 * all done, let format have a chance to cleanup, and make sure that
	 * the patterns supplied by the user were all matched
	 */
	(void)(*frmt->end_rd)();
	(void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
	ar_close();
	pat_chk();

	return 0;
}
Ejemplo n.º 15
0
static void
wr_archive(ARCHD *arcn, int is_app)
{
    int res;
    int hlk;
    int wr_one;
    off_t cnt;
    int (*wrf)();
    int fd = -1;
    time_t now;

    /*
     * if this format supports hard link storage, start up the database
     * that detects them.
     */
    if (((hlk = frmt->hlk) == 1) && (lnk_start() < 0))
        return;

    /*
     * start up the file traversal code and format specific write
     */
    if ((ftree_start() < 0) || ((*frmt->st_wr)() < 0))
        return;
    wrf = frmt->wr;

    /*
     * When we are doing interactive rename, we store the mapping of names
     * so we can fix up hard links files later in the archive.
     */
    if (iflag && (name_start() < 0))
        return;

    /*
     * if this is not append, and there are no files, we do not write a
     * trailer
     */
    wr_one = is_app;

    now = time(NULL);

    /*
     * while there are files to archive, process them one at at time
     */
    while (next_file(arcn) == 0) {
        /*
         * check if this file meets user specified options match.
         */
        if (sel_chk(arcn) != 0)
            continue;
        fd = -1;
        if (uflag) {
            /*
             * only archive if this file is newer than a file with
             * the same name that is already stored on the archive
             */
            if ((res = chk_ftime(arcn)) < 0)
                break;
            if (res > 0)
                continue;
        }

        /*
         * this file is considered selected now. see if this is a hard
         * link to a file already stored
         */
        ftree_sel(arcn);
        if (hlk && (chk_lnk(arcn) < 0))
            break;

        if ((arcn->type == PAX_REG) || (arcn->type == PAX_HRG) ||
                (arcn->type == PAX_CTG)) {
            /*
             * we will have to read this file. by opening it now we
             * can avoid writing a header to the archive for a file
             * we were later unable to read (we also purge it from
             * the link table).
             */
            if ((fd = open(arcn->org_name, O_RDONLY, 0)) < 0) {
                syswarn(1,errno, "Unable to open %s to read",
                        arcn->org_name);
                purg_lnk(arcn);
                continue;
            }
        }

        /*
         * Now modify the name as requested by the user
         */
        if ((res = mod_name(arcn)) < 0) {
            /*
             * name modification says to skip this file, close the
             * file and purge link table entry
             */
            rdfile_close(arcn, &fd);
            purg_lnk(arcn);
            break;
        }

        if ((res > 0) || (docrc && (set_crc(arcn, fd) < 0))) {
            /*
             * unable to obtain the crc we need, close the file,
             * purge link table entry
             */
            rdfile_close(arcn, &fd);
            purg_lnk(arcn);
            continue;
        }

        if (vflag) {
            if (vflag > 1)
                ls_list(arcn, now, listf);
            else {
                (void)safe_print(arcn->name, listf);
                vfpart = 1;
            }
        }
        ++flcnt;

        /*
         * looks safe to store the file, have the format specific
         * routine write routine store the file header on the archive
         */
        if ((res = (*wrf)(arcn)) < 0) {
            rdfile_close(arcn, &fd);
            break;
        }
        wr_one = 1;
        if (res > 0) {
            /*
             * format write says no file data needs to be stored
             * so we are done messing with this file
             */
            if (vflag && vfpart) {
                (void)putc('\n', listf);
                vfpart = 0;
            }
            rdfile_close(arcn, &fd);
            continue;
        }

        /*
         * Add file data to the archive, quit on write error. if we
         * cannot write the entire file contents to the archive we
         * must pad the archive to replace the missing file data
         * (otherwise during an extract the file header for the file
         * which FOLLOWS this one will not be where we expect it to
         * be).
         */
        res = (*frmt->wr_data)(arcn, fd, &cnt);
        rdfile_close(arcn, &fd);
        if (vflag && vfpart) {
            (void)putc('\n', listf);
            vfpart = 0;
        }
        if (res < 0)
            break;

        /*
         * pad as required, cnt is number of bytes not written
         */
        if (((cnt > 0) && (wr_skip(cnt) < 0)) ||
                ((arcn->pad > 0) && (wr_skip(arcn->pad) < 0)))
            break;
    }

    /*
     * tell format to write trailer; pad to block boundary; reset directory
     * mode/access times, and check if all patterns supplied by the user
     * were matched. block off signals to avoid chance for multiple entry
     * into the cleanup code
     */
    if (wr_one) {
        (*frmt->end_wr)();
        wr_fin();
    }
    (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
    ar_close();
    if (tflag)
        proc_dir();
    ftree_chk();
}
Ejemplo n.º 16
0
void
cp_file(ARCHD *arcn, int fd1, int fd2)
{
    int cnt;
    off_t cpcnt = 0L;
    int res = 0;
    char *fnm = arcn->name;
    int no_hole = 0;
    int isem = 1;
    int rem;
    int sz = MINFBSZ;
    struct stat sb;

    /*
     * check for holes in the source file. If none, we will use regular
     * write instead of file write.
     */
    if (((off_t)(arcn->sb.st_blocks * BLKMULT)) >= arcn->sb.st_size)
        ++no_hole;

    /*
     * pass the blocksize of the file being written to the write routine,
     * if the size is zero, use the default MINFBSZ
     */
    if (fstat(fd2, &sb) == 0) {
        if (sb.st_blksize > 0)
            sz = sb.st_blksize;
    } else
        syswarn(0,errno,"Unable to obtain block size for file %s",fnm);
    rem = sz;

    /*
     * read the source file and copy to destination file until EOF
     */
    for(;;) {
        if ((cnt = read(fd1, buf, blksz)) <= 0)
            break;
        if (no_hole)
            res = write(fd2, buf, cnt);
        else
            res = file_write(fd2, buf, cnt, &rem, &isem, sz, fnm);
        if (res != cnt)
            break;
        cpcnt += cnt;
    }

    /*
     * check to make sure the copy is valid.
     */
    if (res < 0)
        syswarn(1, errno, "Failed write during copy of %s to %s",
                arcn->org_name, arcn->name);
    else if (cpcnt != arcn->sb.st_size)
        paxwarn(1, "File %s changed size during copy to %s",
                arcn->org_name, arcn->name);
    else if (fstat(fd1, &sb) < 0)
        syswarn(1, errno, "Failed stat of %s", arcn->org_name);
    else if (arcn->sb.st_mtime != sb.st_mtime)
        paxwarn(1, "File %s was modified during copy to %s",
                arcn->org_name, arcn->name);

    /*
     * if the last block has a file hole (all zero), we must make sure this
     * gets updated in the file. We force the last block of zeros to be
     * written. just closing with the file offset moved forward may not put
     * a hole at the end of the file.
     */
    if (!no_hole && isem && (arcn->sb.st_size > 0L))
        file_flush(fd2, fnm, isem);
    return;
}
Ejemplo n.º 17
0
void
copy(void)
{
    ARCHD *arcn;
    int res;
    int fddest;
    char *dest_pt;
    int dlen;
    int drem;
    int fdsrc = -1;
    struct stat sb;
    ARCHD archd;
    char dirbuf[PAXPATHLEN+1];

    arcn = &archd;
    /*
     * set up the destination dir path and make sure it is a directory. We
     * make sure we have a trailing / on the destination
     */
    dlen = strlcpy(dirbuf, dirptr, sizeof(dirbuf));
    if (dlen >= sizeof(dirbuf) ||
            (dlen == sizeof(dirbuf) - 1 && dirbuf[dlen - 1] != '/')) {
        paxwarn(1, "directory name is too long %s", dirptr);
        return;
    }
    dest_pt = dirbuf + dlen;
    if (*(dest_pt-1) != '/') {
        *dest_pt++ = '/';
        *dest_pt = '\0';
        ++dlen;
    }
    drem = PAXPATHLEN - dlen;

    if (stat(dirptr, &sb) < 0) {
        syswarn(1, errno, "Cannot access destination directory %s",
                dirptr);
        return;
    }
    if (!S_ISDIR(sb.st_mode)) {
        paxwarn(1, "Destination is not a directory %s", dirptr);
        return;
    }

    /*
     * start up the hard link table; file traversal routines and the
     * modification time and access mode database
     */
    if ((lnk_start() < 0) || (ftree_start() < 0) || (dir_start() < 0))
        return;

    /*
     * When we are doing interactive rename, we store the mapping of names
     * so we can fix up hard links files later in the archive.
     */
    if (iflag && (name_start() < 0))
        return;

    /*
     * set up to cp file trees
     */
    cp_start();

    /*
     * while there are files to archive, process them
     */
    while (next_file(arcn) == 0) {
        fdsrc = -1;

        /*
         * check if this file meets user specified options
         */
        if (sel_chk(arcn) != 0)
            continue;

        /*
         * if there is already a file in the destination directory with
         * the same name and it is newer, skip the one stored on the
         * archive.
         * NOTE: this test is done BEFORE name modifications as
         * specified by pax. this can be confusing to the user who
         * might expect the test to be done on an existing file AFTER
         * the name mod. In honesty the pax spec is probably flawed in
         * this respect
         */
        if (uflag || Dflag) {
            /*
             * create the destination name
             */
            if (strlcpy(dest_pt, arcn->name + (*arcn->name == '/'),
                        drem + 1) > drem) {
                paxwarn(1, "Destination pathname too long %s",
                        arcn->name);
                continue;
            }

            /*
             * if existing file is same age or newer skip
             */
            res = lstat(dirbuf, &sb);
            *dest_pt = '\0';

            if (res == 0) {
                if (uflag && Dflag) {
                    if ((arcn->sb.st_mtime<=sb.st_mtime) &&
                            (arcn->sb.st_ctime<=sb.st_ctime))
                        continue;
                } else if (Dflag) {
                    if (arcn->sb.st_ctime <= sb.st_ctime)
                        continue;
                } else if (arcn->sb.st_mtime <= sb.st_mtime)
                    continue;
            }
        }

        /*
         * this file is considered selected. See if this is a hard link
         * to a previous file; modify the name as requested by the
         * user; set the final destination.
         */
        ftree_sel(arcn);
        if ((chk_lnk(arcn) < 0) || ((res = mod_name(arcn)) < 0))
            break;
        if ((res > 0) || (set_dest(arcn, dirbuf, dlen) < 0)) {
            /*
             * skip file, purge from link table
             */
            purg_lnk(arcn);
            continue;
        }

        /*
         * Non standard -Y and -Z flag. When the existing file is
         * same age or newer skip
         */
        if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) {
            if (Yflag && Zflag) {
                if ((arcn->sb.st_mtime <= sb.st_mtime) &&
                        (arcn->sb.st_ctime <= sb.st_ctime))
                    continue;
            } else if (Yflag) {
                if (arcn->sb.st_ctime <= sb.st_ctime)
                    continue;
            } else if (arcn->sb.st_mtime <= sb.st_mtime)
                continue;
        }

        if (vflag) {
            (void)safe_print(arcn->name, listf);
            vfpart = 1;
        }
        ++flcnt;

        /*
         * try to create a hard link to the src file if requested
         * but make sure we are not trying to overwrite ourselves.
         */
        if (lflag)
            res = cross_lnk(arcn);
        else
            res = chk_same(arcn);
        if (res <= 0) {
            if (vflag && vfpart) {
                (void)putc('\n', listf);
                vfpart = 0;
            }
            continue;
        }

        /*
         * have to create a new file
         */
        if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) {
            /*
             * create a link or special file
             */
            if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
                res = lnk_creat(arcn);
            else
                res = node_creat(arcn);
            if (res < 0)
                purg_lnk(arcn);
            if (vflag && vfpart) {
                (void)putc('\n', listf);
                vfpart = 0;
            }
            continue;
        }

        /*
         * have to copy a regular file to the destination directory.
         * first open source file and then create the destination file
         */
        if ((fdsrc = open(arcn->org_name, O_RDONLY, 0)) < 0) {
            syswarn(1, errno, "Unable to open %s to read",
                    arcn->org_name);
            purg_lnk(arcn);
            continue;
        }
        if ((fddest = file_creat(arcn)) < 0) {
            rdfile_close(arcn, &fdsrc);
            purg_lnk(arcn);
            continue;
        }

        /*
         * copy source file data to the destination file
         */
        cp_file(arcn, fdsrc, fddest);
        file_close(arcn, fddest);
        rdfile_close(arcn, &fdsrc);

        if (vflag && vfpart) {
            (void)putc('\n', listf);
            vfpart = 0;
        }
    }

    /*
     * restore directory modes and times as required; make sure all
     * patterns were selected block off signals to avoid chance for
     * multiple entry into the cleanup code.
     */
    (void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
    ar_close();
    proc_dir();
    ftree_chk();
}
Ejemplo n.º 18
0
int
ar_next(void)
{
	static char *arcbuf;
	char buf[PAXPATHLEN+2];
	sigset_t o_mask;

	/*
	 * WE MUST CLOSE THE DEVICE. A lot of devices must see last close, (so
	 * things like writing EOF etc will be done) (Watch out ar_close() can
	 * also be called via a signal handler, so we must prevent a race.
	 */
	if (sigprocmask(SIG_BLOCK, &s_mask, &o_mask) < 0)
		syswarn(0, errno, "Unable to set signal mask");
	ar_close();
	if (sigprocmask(SIG_SETMASK, &o_mask, NULL) < 0)
		syswarn(0, errno, "Unable to restore signal mask");

	if (done || !wr_trail || strcmp(NM_TAR, argv0) == 0)
		return(-1);

	tty_prnt("\nATTENTION! %s archive volume change required.\n", argv0);

	/*
	 * if i/o is on stdin or stdout, we cannot reopen it (we do not know
	 * the name), the user will be forced to type it in.
	 */
	if (strcmp(arcname, stdo) && strcmp(arcname, stdn) && (artyp != ISREG)
	    && (artyp != ISPIPE)) {
		if (artyp == ISTAPE) {
			tty_prnt("%s ready for archive tape volume: %d\n",
				arcname, arvol);
			tty_prnt("Load the NEXT TAPE on the tape drive");
		} else {
			tty_prnt("%s ready for archive volume: %d\n",
				arcname, arvol);
			tty_prnt("Load the NEXT STORAGE MEDIA (if required)");
		}

		if ((act == ARCHIVE) || (act == APPND))
			tty_prnt(" and make sure it is WRITE ENABLED.\n");
		else
			tty_prnt("\n");

		for(;;) {
			tty_prnt("Type \"y\" to continue, \".\" to quit %s,",
				argv0);
			tty_prnt(" or \"s\" to switch to new device.\nIf you");
			tty_prnt(" cannot change storage media, type \"s\"\n");
			tty_prnt("Is the device ready and online? > ");

			if ((tty_read(buf,sizeof(buf))<0) || !strcmp(buf,".")){
				done = 1;
				lstrval = -1;
				tty_prnt("Quitting %s!\n", argv0);
				vfpart = 0;
				return(-1);
			}

			if ((buf[0] == '\0') || (buf[1] != '\0')) {
				tty_prnt("%s unknown command, try again\n",buf);
				continue;
			}

			switch (buf[0]) {
			case 'y':
			case 'Y':
				/*
				 * we are to continue with the same device
				 */
				if (ar_open(arcname) >= 0)
					return(0);
				tty_prnt("Cannot re-open %s, try again\n",
					arcname);
				continue;
			case 's':
			case 'S':
				/*
				 * user wants to open a different device
				 */
				tty_prnt("Switching to a different archive\n");
				break;
			default:
				tty_prnt("%s unknown command, try again\n",buf);
				continue;
			}
			break;
		}
	} else
		tty_prnt("Ready for archive volume: %d\n", arvol);

	/*
	 * have to go to a different archive
	 */
	for (;;) {
		tty_prnt("Input archive name or \".\" to quit %s.\n", argv0);
		tty_prnt("Archive name > ");

		if ((tty_read(buf, sizeof(buf)) < 0) || !strcmp(buf, ".")) {
			done = 1;
			lstrval = -1;
			tty_prnt("Quitting %s!\n", argv0);
			vfpart = 0;
			return(-1);
		}
		if (buf[0] == '\0') {
			tty_prnt("Empty file name, try again\n");
			continue;
		}
		if (!strcmp(buf, "..")) {
			tty_prnt("Illegal file name: .. try again\n");
			continue;
		}
		if (strlen(buf) > PAXPATHLEN) {
			tty_prnt("File name too long, try again\n");
			continue;
		}

		/*
		 * try to open new archive
		 */
		if (ar_open(buf) >= 0) {
			free(arcbuf);
			if ((arcbuf = strdup(buf)) == NULL) {
				done = 1;
				lstrval = -1;
				paxwarn(0, "Cannot save archive name.");
				return(-1);
			}
			arcname = arcbuf;
			break;
		}
		tty_prnt("Cannot open %s, try again\n", buf);
		continue;
	}
	return(0);
}
Ejemplo n.º 19
0
int
node_creat(ARCHD *arcn)
{
	int res;
	int ign = 0;
	int oerrno;
	int pass = 0;
	mode_t file_mode;
	struct stat sb;
	char target[MAXPATHLEN];
	char *nm = arcn->name;
	int len;

	/*
	 * create node based on type, if that fails try to unlink the node and
	 * try again. finally check the path and try again. As noted in the
	 * file and link creation routines, this method seems to exhibit the
	 * best performance in general use workloads.
	 */
	file_mode = arcn->sb.st_mode & FILEBITS;

	for (;;) {
		switch(arcn->type) {
		case PAX_DIR:
			/*
			 * If -h (or -L) was given in tar-mode, follow the
			 * potential symlink chain before trying to create the
			 * directory.
			 */
			if (strcmp(NM_TAR, argv0) == 0 && Lflag) {
				while (lstat(nm, &sb) == 0 &&
				    S_ISLNK(sb.st_mode)) {
					len = readlink(nm, target,
					    sizeof target - 1);
					if (len == -1) {
						syswarn(0, errno,
						   "cannot follow symlink %s in chain for %s",
						    nm, arcn->name);
						res = -1;
						goto badlink;
					}
					target[len] = '\0';
					nm = target;
				}
			}
			res = mkdir(nm, file_mode);

badlink:
			if (ign)
				res = 0;
			break;
		case PAX_CHR:
			file_mode |= S_IFCHR;
			res = mknod(nm, file_mode, arcn->sb.st_rdev);
			break;
		case PAX_BLK:
			file_mode |= S_IFBLK;
			res = mknod(nm, file_mode, arcn->sb.st_rdev);
			break;
		case PAX_FIF:
			res = mkfifo(nm, file_mode);
			break;
		case PAX_SCK:
			/*
			 * Skip sockets, operation has no meaning under BSD
			 */
			paxwarn(0,
			    "%s skipped. Sockets cannot be copied or extracted",
			    nm);
			return(-1);
		case PAX_SLK:
			res = symlink(arcn->ln_name, nm);
			break;
		case PAX_CTG:
		case PAX_HLK:
		case PAX_HRG:
		case PAX_REG:
		default:
			/*
			 * we should never get here
			 */
			paxwarn(0, "%s has an unknown file type, skipping",
				nm);
			return(-1);
		}

		/*
		 * if we were able to create the node break out of the loop,
		 * otherwise try to unlink the node and try again. if that
		 * fails check the full path and try a final time.
		 */
		if (res == 0)
			break;

		/*
		 * we failed to make the node
		 */
		oerrno = errno;
		if ((ign = unlnk_exist(nm, arcn->type)) < 0)
			return(-1);

		if (++pass <= 1)
			continue;

		if (nodirs || chk_path(nm,arcn->sb.st_uid,arcn->sb.st_gid) < 0) {
			syswarn(1, oerrno, "Could not create: %s", nm);
			return(-1);
		}
	}

	/*
	 * we were able to create the node. set uid/gid, modes and times
	 */
	if (pids)
		res = ((arcn->type == PAX_SLK) ?
		    set_lids(nm, arcn->sb.st_uid, arcn->sb.st_gid) :
		    set_ids(nm, arcn->sb.st_uid, arcn->sb.st_gid));
	else
		res = 0;

	/*
	 * symlinks are done now.
	 */
	if (arcn->type == PAX_SLK)
		return(0);

	/*
	 * IMPORTANT SECURITY NOTE:
	 * if not preserving mode or we cannot set uid/gid, then PROHIBIT any
	 * set uid/gid bits
	 */
	if (!pmode || res)
		arcn->sb.st_mode &= ~(SETBITS);
	if (pmode)
		set_pmode(nm, arcn->sb.st_mode);

	if (arcn->type == PAX_DIR && strcmp(NM_CPIO, argv0) != 0) {
		/*
		 * Dirs must be processed again at end of extract to set times
		 * and modes to agree with those stored in the archive. However
		 * to allow extract to continue, we may have to also set owner
		 * rights. This allows nodes in the archive that are children
		 * of this directory to be extracted without failure. Both time
		 * and modes will be fixed after the entire archive is read and
		 * before pax exits.
		 */
		if (access(nm, R_OK | W_OK | X_OK) < 0) {
			if (lstat(nm, &sb) < 0) {
				syswarn(0, errno,"Could not access %s (stat)",
				    arcn->name);
				set_pmode(nm,file_mode | S_IRWXU);
			} else {
				/*
				 * We have to add rights to the dir, so we make
				 * sure to restore the mode. The mode must be
				 * restored AS CREATED and not as stored if
				 * pmode is not set.
				 */
				set_pmode(nm,
				    ((sb.st_mode & FILEBITS) | S_IRWXU));
				if (!pmode)
					arcn->sb.st_mode = sb.st_mode;
			}

			/*
			 * we have to force the mode to what was set here,
			 * since we changed it from the default as created.
			 */
			add_dir(nm, strlen(nm), &(arcn->sb), 1);
		} else if (pmode || patime || pmtime)
			add_dir(nm, strlen(nm), &(arcn->sb), 0);
	}

	if (patime || pmtime)
		set_ftime(nm, arcn->sb.st_mtime, arcn->sb.st_atime, 0);
	return(0);
}
Ejemplo n.º 20
0
int
ar_read(char *buf, int cnt)
{
	int res = 0;

	/*
	 * if last i/o was in error, no more reads until reset or new volume
	 */
	if (lstrval <= 0)
		return(lstrval);

	/*
	 * how we read must be based on device type
	 */
	switch (artyp) {
	case ISTAPE:
		if ((res = read(arfd, buf, cnt)) > 0) {
			/*
			 * CAUTION: tape systems may not always return the same
			 * sized records so we leave blksz == MAXBLK. The
			 * physical record size that a tape drive supports is
			 * very hard to determine in a uniform and portable
			 * manner.
			 */
			io_ok = 1;
			if (res != rdblksz) {
				/*
				 * Record size changed. If this is happens on
				 * any record after the first, we probably have
				 * a tape drive which has a fixed record size
				 * we are getting multiple records in a single
				 * read). Watch out for record blocking that
				 * violates pax spec (must be a multiple of
				 * BLKMULT).
				 */
				rdblksz = res;
				if (rdblksz % BLKMULT)
					invld_rec = 1;
			}
			return(res);
		}
		break;
	case ISREG:
	case ISBLK:
	case ISCHR:
	case ISPIPE:
	default:
		/*
		 * Files are so easy to deal with. These other things cannot
		 * be trusted at all. So when we are dealing with character
		 * devices and pipes we just take what they have ready for us
		 * and return. Trying to do anything else with them runs the
		 * risk of failure.
		 */
		if ((res = read(arfd, buf, cnt)) > 0) {
			io_ok = 1;
			return(res);
		}
		break;
	}

	/*
	 * We are in trouble at this point, something is broken...
	 */
	lstrval = res;
	if (res < 0)
		syswarn(1, errno, "Failed read on archive volume %d", arvol);
	else
		paxwarn(0, "End of archive volume %d reached", arvol);
	return(res);
}
Ejemplo n.º 21
0
int
main(int argc, char *argv[])
{
	const char *tmpdir;
	size_t tdlen;

	(void) setlocale(LC_ALL, "");
	listf = stderr;
	/*
	 * Keep a reference to cwd, so we can always come back home.
	 */
	cwdfd = open(".", O_RDONLY);
	if (cwdfd < 0) {
		syswarn(0, errno, "Can't open current working directory.");
		return(exit_val);
	}

	/*
	 * Where should we put temporary files?
	 */
	if ((tmpdir = getenv("TMPDIR")) == NULL || *tmpdir == '\0')
		tmpdir = _PATH_TMP;
	tdlen = strlen(tmpdir);
	while(tdlen > 0 && tmpdir[tdlen - 1] == '/')
		tdlen--;
	tempfile = malloc(tdlen + 1 + sizeof(_TFILE_BASE));
	if (tempfile == NULL) {
		paxwarn(1, "Cannot allocate memory for temp file name.");
		return(exit_val);
	}
	if (tdlen)
		memcpy(tempfile, tmpdir, tdlen);
	tempbase = tempfile + tdlen;
	*tempbase++ = '/';

	/*
	 * parse options, determine operational mode, general init
	 */
	options(argc, argv);
	if ((gen_init() < 0) || (tty_init() < 0))
		return(exit_val);

	/*
	 * select a primary operation mode
	 */
	switch(act) {
	case EXTRACT:
		extract();
		break;
	case ARCHIVE:
		archive();
		break;
	case APPND:
		if (gzip_program != NULL)
			err(1, "can not gzip while appending");
		append();
		break;
	case COPY:
		copy();
		break;
	default:
	case LIST:
		list();
		break;
	}
	return(exit_val);
}
Ejemplo n.º 22
0
int
ar_write(char *buf, int bsz)
{
	int res;
	off_t cpos;

	/*
	 * do not allow pax to create a "bad" archive. Once a write fails on
	 * an archive volume prevent further writes to it.
	 */
	if (lstrval <= 0)
		return(lstrval);

	if ((res = write(arfd, buf, bsz)) == bsz) {
		wr_trail = 1;
		io_ok = 1;
		return(bsz);
	}
	/*
	 * write broke, see what we can do with it. We try to send any partial
	 * writes that may violate pax spec to the next archive volume.
	 */
	if (res < 0)
		lstrval = res;
	else
		lstrval = 0;

	switch (artyp) {
	case ISREG:
		if ((res > 0) && (res % BLKMULT)) {
			/*
		 	 * try to fix up partial writes which are not BLKMULT
			 * in size by forcing the runt record to next archive
			 * volume
		 	 */
			if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0)
				break;
			cpos -= (off_t)res;
			if (ftruncate(arfd, cpos) < 0)
				break;
			res = lstrval = 0;
			break;
		}
		if (res >= 0)
			break;
		/*
		 * if file is out of space, handle it like a return of 0
		 */
		if ((errno == ENOSPC) || (errno == EFBIG) || (errno == EDQUOT))
			res = lstrval = 0;
		break;
	case ISTAPE:
	case ISCHR:
	case ISBLK:
		if (res >= 0)
			break;
		if (errno == EACCES) {
			paxwarn(0, "Write failed, archive is write protected.");
			res = lstrval = 0;
			return(0);
		}
		/*
		 * see if we reached the end of media, if so force a change to
		 * the next volume
		 */
		if ((errno == ENOSPC) || (errno == EIO) || (errno == ENXIO))
			res = lstrval = 0;
		break;
	case ISPIPE:
	default:
		/*
		 * we cannot fix errors to these devices
		 */
		break;
	}

	/*
	 * Better tell the user the bad news...
	 * if this is a block aligned archive format, we may have a bad archive
	 * if the format wants the header to start at a BLKMULT boundary. While
	 * we can deal with the mis-aligned data, it violates spec and other
	 * archive readers will likely fail. If the format is not block
	 * aligned, the user may be lucky (and the archive is ok).
	 */
	if (res >= 0) {
		if (res > 0)
			wr_trail = 1;
		io_ok = 1;
	}

	/*
	 * If we were trying to rewrite the trailer and it didn't work, we
	 * must quit right away.
	 */
	if (!wr_trail && (res <= 0)) {
		paxwarn(1,"Unable to append, trailer re-write failed. Quitting.");
		return(res);
	}

	if (res == 0)
		paxwarn(0, "End of archive volume %d reached", arvol);
	else if (res < 0)
		syswarn(1, errno, "Failed write to archive volume: %d", arvol);
	else if (!frmt->blkalgn || ((res % frmt->blkalgn) == 0))
		paxwarn(0,"WARNING: partial archive write. Archive MAY BE FLAWED");
	else
		paxwarn(1,"WARNING: partial archive write. Archive IS FLAWED");
	return(res);
}
Ejemplo n.º 23
0
static int
ftree_arg(void)
{

    /*
     * close off the current file tree
     */
    if (ftsp != NULL) {
        (void)fts_close(ftsp);
        ftsp = NULL;
    }

    /*
     * keep looping until we get a valid file tree to process. Stop when we
     * reach the end of the list (or get an eof on stdin)
     */
    for (;;) {
        if (fthead == NULL) {
            /*
             * the user didn't supply any args, get the file trees
             * to process from stdin;
             */
            if (getpathname(farray[0], PAXPATHLEN+1) == NULL)
                return(-1);
        } else {
            /*
             * the user supplied the file args as arguments to pax
             */
            if (ftcur == NULL)
                ftcur = fthead;
            else if ((ftcur = ftcur->fow) == NULL)
                return(-1);
            if (ftcur->chflg) {
                /* First fchdir() back... */
                if (fchdir(cwdfd) < 0) {
                    syswarn(1, errno,
                            "Can't fchdir to starting directory");
                    return(-1);
                }
                if (chdir(ftcur->fname) < 0) {
                    syswarn(1, errno, "Can't chdir to %s",
                            ftcur->fname);
                    return(-1);
                }
                continue;
            } else
                farray[0] = ftcur->fname;
        }

        /*
         * watch it, fts wants the file arg stored in a array of char
         * ptrs, with the last one a null. we use a two element array
         * and set farray[0] to point at the buffer with the file name
         * in it. We cannot pass all the file args to fts at one shot
         * as we need to keep a handle on which file arg generates what
         * files (the -n and -d flags need this). If the open is
         * successful, return a 0.
         */
        if ((ftsp = fts_open(farray, ftsopts, NULL)) != NULL)
            break;
    }
    return(0);
}
Ejemplo n.º 24
0
int
ar_rev(off_t sksz)
{
	off_t cpos;
	struct mtop mb;
	int phyblk;

	/*
	 * make sure we do not have try to reverse on a flawed archive
	 */
	if (lstrval < 0)
		return(lstrval);

	switch(artyp) {
	case ISPIPE:
		if (sksz <= 0)
			break;
		/*
		 * cannot go backwards on these critters
		 */
		paxwarn(1, "Reverse positioning on pipes is not supported.");
		lstrval = -1;
		return(-1);
	case ISREG:
	case ISBLK:
	case ISCHR:
	default:
		if (sksz <= 0)
			break;

		/*
		 * For things other than files, backwards movement has a very
		 * high probability of failure as we really do not know the
		 * true attributes of the device we are talking to (the device
		 * may not even have the ability to lseek() in any direction).
		 * First we figure out where we are in the archive.
		 */
		if ((cpos = lseek(arfd, (off_t)0L, SEEK_CUR)) < 0) {
			syswarn(1, errno,
			   "Unable to obtain current archive byte offset");
			lstrval = -1;
			return(-1);
		}

		/*
		 * we may try to go backwards past the start when the archive
		 * is only a single record. If this happens and we are on a
		 * multi volume archive, we need to go to the end of the
		 * previous volume and continue our movement backwards from
		 * there.
		 */
		if ((cpos -= sksz) < (off_t)0L) {
			if (arvol > 1) {
				/*
				 * this should never happen
				 */
				paxwarn(1,"Reverse position on previous volume.");
				lstrval = -1;
				return(-1);
			}
			cpos = (off_t)0L;
		}
		if (lseek(arfd, cpos, SEEK_SET) < 0) {
			syswarn(1, errno, "Unable to seek archive backwards");
			lstrval = -1;
			return(-1);
		}
		break;
	case ISTAPE:
		/*
	 	 * Calculate and move the proper number of PHYSICAL tape
		 * blocks. If the sksz is not an even multiple of the physical
		 * tape size, we cannot do the move (this should never happen).
		 * (We also cannot handler trailers spread over two vols).
		 * get_phys() also makes sure we are in front of the filemark.
	 	 */
		if ((phyblk = get_phys()) <= 0) {
			lstrval = -1;
			return(-1);
		}

		/*
		 * make sure future tape reads only go by physical tape block
		 * size (set rdblksz to the real size).
		 */
		rdblksz = phyblk;

		/*
		 * if no movement is required, just return (we must be after
		 * get_phys() so the physical blocksize is properly set)
		 */
		if (sksz <= 0)
			break;

		/*
		 * ok we have to move. Make sure the tape drive can do it.
		 */
		if (sksz % phyblk) {
			paxwarn(1,
			    "Tape drive unable to backspace requested amount");
			lstrval = -1;
			return(-1);
		}

		/*
		 * move backwards the requested number of bytes
		 */
		mb.mt_op = MTBSR;
		mb.mt_count = sksz/phyblk;
		if (ioctl(arfd, MTIOCTOP, &mb) < 0) {
			syswarn(1,errno, "Unable to backspace tape %d blocks.",
			    mb.mt_count);
			lstrval = -1;
			return(-1);
		}
		break;
	}
	lstrval = 1;
	return(0);
}
Ejemplo n.º 25
0
void
extract(void)
{
	ARCHD *arcn;
	int res;
	off_t cnt;
	ARCHD archd;
	struct stat sb;
	int fd;
	time_t now;

	arcn = &archd;
	/*
	 * figure out archive type; pass any format specific options to the
	 * archive option processing routine; call the format init routine;
	 * start up the directory modification time and access mode database
	 */
	if ((get_arc() < 0) || ((*frmt->options)() < 0) ||
	    ((*frmt->st_rd)() < 0) || (dir_start() < 0))
		return;

	/*
	 * When we are doing interactive rename, we store the mapping of names
	 * so we can fix up hard links files later in the archive.
	 */
	if (iflag && (name_start() < 0))
		return;

	now = time(NULL);

	/*
	 * step through each entry on the archive until the format read routine
	 * says it is done
	 */
	while (next_head(arcn) == 0) {
		if (arcn->type == PAX_GLL || arcn->type == PAX_GLF) {
			/*
			 * we need to read, to get the real filename
			 */
			if (!(*frmt->rd_data)(arcn, arcn->type == PAX_GLF
			    ? -1 : -2, &cnt))
				(void)rd_skip(cnt + arcn->pad);
			continue;
		}

		/*
		 * check for pattern, and user specified options match. When
		 * all the patterns are matched we are done
		 */
		if ((res = pat_match(arcn)) < 0)
			break;

		if ((res > 0) || (sel_chk(arcn) != 0)) {
			/*
			 * file is not selected. skip past any file data and
			 * padding and go back for the next archive member
			 */
			(void)rd_skip(arcn->skip + arcn->pad);
			continue;
		}

		/*
		 * with -u or -D only extract when the archive member is newer
		 * than the file with the same name in the file system (no
		 * test of being the same type is required).
		 * NOTE: this test is done BEFORE name modifications as
		 * specified by pax. this operation can be confusing to the
		 * user who might expect the test to be done on an existing
		 * file AFTER the name mod. In honesty the pax spec is probably
		 * flawed in this respect.
		 */
		if ((uflag || Dflag) && ((lstat(arcn->name, &sb) == 0))) {
			if (uflag && Dflag) {
				if ((arcn->sb.st_mtime <= sb.st_mtime) &&
				    (arcn->sb.st_ctime <= sb.st_ctime)) {
					(void)rd_skip(arcn->skip + arcn->pad);
					continue;
				}
			} else if (Dflag) {
				if (arcn->sb.st_ctime <= sb.st_ctime) {
					(void)rd_skip(arcn->skip + arcn->pad);
					continue;
				}
			} else if (arcn->sb.st_mtime <= sb.st_mtime) {
				(void)rd_skip(arcn->skip + arcn->pad);
				continue;
			}
		}

		/*
		 * this archive member is now been selected. modify the name.
		 */
		if ((pat_sel(arcn) < 0) || ((res = mod_name(arcn)) < 0))
			break;
		if (res > 0) {
			/*
			 * a bad name mod, skip and purge name from link table
			 */
			purg_lnk(arcn);
			(void)rd_skip(arcn->skip + arcn->pad);
			continue;
		}

		/*
		 * Non standard -Y and -Z flag. When the existing file is
		 * same age or newer skip
		 */
		if ((Yflag || Zflag) && ((lstat(arcn->name, &sb) == 0))) {
			if (Yflag && Zflag) {
				if ((arcn->sb.st_mtime <= sb.st_mtime) &&
				    (arcn->sb.st_ctime <= sb.st_ctime)) {
					(void)rd_skip(arcn->skip + arcn->pad);
					continue;
				}
			} else if (Yflag) {
				if (arcn->sb.st_ctime <= sb.st_ctime) {
					(void)rd_skip(arcn->skip + arcn->pad);
					continue;
				}
			} else if (arcn->sb.st_mtime <= sb.st_mtime) {
				(void)rd_skip(arcn->skip + arcn->pad);
				continue;
			}
		}

		if (vflag) {
			if (vflag > 1)
				ls_list(arcn, now, listf);
			else {
				(void)safe_print(arcn->name, listf);
				vfpart = 1;
			}
		}

		/*
		 * if required, chdir around.
		 */
		if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL))
			if (chdir(arcn->pat->chdname) != 0)
				syswarn(1, errno, "Cannot chdir to %s",
				    arcn->pat->chdname);

		/*
		 * all ok, extract this member based on type
		 */
		if ((arcn->type != PAX_REG) && (arcn->type != PAX_CTG)) {
			/*
			 * process archive members that are not regular files.
			 * throw out padding and any data that might follow the
			 * header (as determined by the format).
			 */
			if ((arcn->type == PAX_HLK) || (arcn->type == PAX_HRG))
				res = lnk_creat(arcn);
			else
				res = node_creat(arcn);

			(void)rd_skip(arcn->skip + arcn->pad);
			if (res < 0)
				purg_lnk(arcn);

			if (vflag && vfpart) {
				(void)putc('\n', listf);
				vfpart = 0;
			}
			goto popd;
		}
		/*
		 * we have a file with data here. If we can not create it, skip
		 * over the data and purge the name from hard link table
		 */
		if ((fd = file_creat(arcn)) < 0) {
			(void)rd_skip(arcn->skip + arcn->pad);
			purg_lnk(arcn);
			goto popd;
		}
		/*
		 * extract the file from the archive and skip over padding and
		 * any unprocessed data
		 */
		res = (*frmt->rd_data)(arcn, fd, &cnt);
		file_close(arcn, fd);
		if (vflag && vfpart) {
			(void)putc('\n', listf);
			vfpart = 0;
		}
		if (!res)
			(void)rd_skip(cnt + arcn->pad);

popd:
		/*
		 * if required, chdir around.
		 */
		if ((arcn->pat != NULL) && (arcn->pat->chdname != NULL))
			if (fchdir(cwdfd) != 0)
				syswarn(1, errno,
				    "Can't fchdir to starting directory");
	}

	/*
	 * all done, restore directory modes and times as required; make sure
	 * all patterns supplied by the user were matched; block off signals
	 * to avoid chance for multiple entry into the cleanup code.
	 */
	(void)(*frmt->end_rd)();
	(void)sigprocmask(SIG_BLOCK, &s_mask, NULL);
	ar_close();
	proc_dir();
	pat_chk();
}
Ejemplo n.º 26
0
Archivo: lbcd.c Proyecto: rra/lbcd
/*
 * Receive request packet and verify the integrity and format of the reply.
 * This routine is REQUIRED to sanitize the request packet.  All other program
 * routines can expect that the packet is safe to read once it is passed on.
 *
 * Returns a newly-allocated lbcd_request struct on success and NULL on
 * failure.
 */
static struct request *
request_recv(struct lbcd_config *config, socket_type fd)
{
    struct sockaddr_storage addr;
    struct sockaddr *sockaddr;
    socklen_t addrlen;
    ssize_t result;
    char raw[LBCD_MAXMESG];
    char source[INET6_ADDRSTRLEN] = "UNKNOWN";
    struct lbcd_request *packet;
    unsigned int protocol, id, operation, nservices, i;
    size_t expected;
    struct request *request;
    char *service;

    /* Receive the UDP packet from the wire. */
    addrlen = sizeof(addr);
    sockaddr = (struct sockaddr *) &addr;
    result = recvfrom(fd, raw, sizeof(raw), 0, sockaddr, &addrlen);
    if (result <= 0) {
        syswarn("cannot receive packet");
        return NULL;
    }

    /* Format the client address for logging. */
    if (!network_sockaddr_sprint(source, sizeof(source), sockaddr))
        syswarn("cannot convert client address to string");

    /* Ensure the packet is large enough to contain the header. */
    if ((size_t) result < sizeof(struct lbcd_header)) {
        warn("client %s: short packet received (length %lu)", source,
             (unsigned long) result);
        return NULL;
    }

    /* Extract the header fields. */
    packet = (struct lbcd_request *) raw;
    protocol  = ntohs(packet->h.version);
    id        = ntohs(packet->h.id);
    operation = ntohs(packet->h.op);
    nservices = ntohs(packet->h.status);

    /* Now, ensure the request packet is exactly the correct size. */
    expected = sizeof(struct lbcd_header);
    if (protocol == 3) {
        if (nservices > LBCD_MAX_SERVICES) {
            warn("client %s: too many services in request (%u)", source,
                 nservices);
            return NULL;
        }
        expected += nservices * sizeof(lbcd_name_type);
    }
    if ((size_t) result != expected) {
        warn("client %s: incorrect packet size (%lu != %lu)", source,
             (unsigned long) result, (unsigned long) expected);
        return NULL;
    }

    /* The packet appears valid.  Create the request struct. */
    request = xcalloc(1, sizeof(struct request));
    request->source    = xstrdup(source);
    request->addrlen   = addrlen;
    request->addr      = xmalloc(addrlen);
    memcpy(request->addr, &addr, addrlen);
    request->protocol  = protocol;
    request->id        = id;
    request->operation = operation;
    request->services  = vector_new();

    /* Check protocol number. */
    if (protocol != 2 && protocol != 3) {
        warn("client %s: protocol version %u unsupported", source, protocol);
        send_status(request, fd, LBCD_STATUS_VERSION);
        goto fail;
    }

    /*
     * Protocol version 3 takes a client-supplied list of services, with the
     * number of client-provided services given in the otherwise-unused status
     * field of the request header.
     */
    if (request->protocol == 3)
        for (i = 0; i < nservices; i++) {
            service = xstrndup(packet->names[i], sizeof(lbcd_name_type));
            if (!service_allowed(config, service)) {
                warn("client %s: service %s not allowed", source, service);
                send_status(request, fd, LBCD_STATUS_ERROR);
                free(service);
                goto fail;
            }
            vector_add(request->services, service);
            free(service);
        }
    return request;

fail:
    request_free(request);
    return NULL;
}