Filewatcher File Search
FTP Search
  
Directory (beta)
  
Content Search (beta)
   
pkg://amanda-2.4.5-2.src.rpm:1570510/amanda-2.4.5.tar.gz  info  downloads

amanda-2.4.5/0000777000200500003130000000000010231512125006464 5amanda-2.4.5/tape-src/0000777000200500003130000000000010231512126010203 5amanda-2.4.5/tape-src/output-tape.h0000644000200500003130000000435407631740465012610 /*
 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
 * Copyright (c) 1991-1998 University of Maryland at College Park
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of U.M. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  U.M. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: James da Silva, Systems Design and Analysis Group
 *			   Computer Science Department
 *			   University of Maryland at College Park
 */

/*
 * $Id: output-tape.h,v 1.1.2.2.2.2 2003/03/06 21:44:21 martinea Exp $
 *
 * tapeio.c virtual tape interface for normal tape drives.
 */

#ifndef OUTPUT_TAPE_H
#define OUTPUT_TAPE_H

#ifdef NO_AMANDA
#include "output-rait.h"
#else
#include "amanda.h"
#endif

extern int tape_tape_access P((char *, int));
extern int tape_tape_open ();
extern int tape_tape_stat P((char *, struct stat *));
extern int tape_tapefd_close P((int));
extern int tape_tapefd_fsf P((int, int));
extern ssize_t tape_tapefd_read P((int, void *, size_t));
extern int tape_tapefd_rewind P((int));
extern void tape_tapefd_resetofs P((int));
extern int tape_tapefd_unload P((int));
extern int tape_tapefd_status P((int, struct am_mt_status *));
extern int tape_tapefd_weof P((int, int));
extern ssize_t tape_tapefd_write P((int, const void *, size_t));
extern int tape_tapefd_can_fork P((int));

#endif /* OUTPUT_TAPE_H */
amanda-2.4.5/tape-src/output-null.h0000644000200500003130000000426007631740464012624 /*
 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
 * Copyright (c) 1991-1998 University of Maryland at College Park
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of U.M. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  U.M. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: James da Silva, Systems Design and Analysis Group
 *			   Computer Science Department
 *			   University of Maryland at College Park
 */

/*
 * $Id: output-null.h,v 1.1.2.2.2.2 2003/03/06 21:44:20 martinea Exp $
 *
 * tapeio.c virtual tape interface for a null device.
 */

#ifndef OUTPUT_NULL_H
#define OUTPUT_NULL_H

#include "amanda.h"

extern int null_tape_access P((char *, int));
extern int null_tape_open ();
extern int null_tape_stat P((char *, struct stat *));
extern int null_tapefd_close P((int));
extern int null_tapefd_fsf P((int, int));
extern ssize_t null_tapefd_read P((int, void *, size_t));
extern int null_tapefd_rewind P((int));
extern void null_tapefd_resetofs P((int));
extern int null_tapefd_unload P((int));
extern int null_tapefd_status P((int, struct am_mt_status *));
extern int null_tapefd_weof P((int, int));
extern ssize_t null_tapefd_write P((int, const void *, size_t));
extern int null_tapefd_can_fork P((int));

#endif /* OUTPUT_NULL_H */
amanda-2.4.5/tape-src/output-file.h0000644000200500003130000000426007631740464012571 /*
 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
 * Copyright (c) 1991-1998 University of Maryland at College Park
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of U.M. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  U.M. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: James da Silva, Systems Design and Analysis Group
 *			   Computer Science Department
 *			   University of Maryland at College Park
 */

/*
 * $Id: output-file.h,v 1.1.2.2.2.2 2003/03/06 21:44:20 martinea Exp $
 *
 * tapeio.c virtual tape interface for a file device.
 */

#ifndef OUTPUT_FILE_H
#define OUTPUT_FILE_H

#include "amanda.h"

extern int file_tape_access P((char *, int));
extern int file_tape_open ();
extern int file_tape_stat P((char *, struct stat *));
extern int file_tapefd_close P((int));
extern int file_tapefd_fsf P((int, int));
extern ssize_t file_tapefd_read P((int, void *, size_t));
extern int file_tapefd_rewind P((int));
extern void file_tapefd_resetofs P((int));
extern int file_tapefd_unload P((int));
extern int file_tapefd_status P((int, struct am_mt_status *));
extern int file_tapefd_weof P((int, int));
extern ssize_t file_tapefd_write P((int, const void *, size_t));
extern int file_tapefd_can_fork P((int));

#endif /* OUTPUT_FILE_H */
amanda-2.4.5/tape-src/Makefile.am0000644000200500003130000000364407573720625012206 # Makefile for Amanda tape library.

INCLUDES =		-I$(top_srcdir)/common-src

lib_LTLIBRARIES = 	libamtape.la
LIB_EXTENSION = la

sbin_PROGRAMS=          ammt amdd amtapetype

libamtape_la_SOURCES = 	output-file.c \
			output-null.c \
			output-rait.c \
			output-tape.c \
			tapeio.c

libamtape_la_LDFLAGS =  -release $(VERSION)

###
# Because libamanda includes routines (e.g. regex) provided by some system
# libraries, and because of the way libtool sets up the command line, we
# need to list libamanda twice here, first to override the system library
# routines, and second to pick up any references in the other libraries.
###

LDADD =	../common-src/libamanda.$(LIB_EXTENSION) \
	libamtape.$(LIB_EXTENSION) \
	../common-src/libamanda.$(LIB_EXTENSION)

# used for testing only

TEST_PROGS =		amtapeio

EXTRA_PROGRAMS = 	$(TEST_PROGS)

CLEANFILES = *.test.c

amtapetype_SOURCES = tapetype.c

noinst_HEADERS = 	\
			output-file.h \
			output-null.h \
			output-rait.h \
			output-tape.h \
			tapeio.h

install-exec-hook:
	@list="$(sbin_PROGRAMS) $(sbin_SCRIPTS)"; \
	for p in $$list; do \
		pa=$(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \
		echo chown $(BINARY_OWNER) $$pa; \
		chown $(BINARY_OWNER) $$pa; \
		echo chgrp $(SETUID_GROUP) $$pa; \
		chgrp $(SETUID_GROUP) $$pa; \
	done
	@list="$(libexec_PROGRAMS) $(libexec_SCRIPTS)"; \
	for p in $$list; do \
		pa=$(DESTDIR)$(libexecdir)/`echo $$p|sed '$(transform)'`; \
		echo chown $(BINARY_OWNER) $$pa; \
		chown $(BINARY_OWNER) $$pa; \
		echo chgrp $(SETUID_GROUP) $$pa; \
		chgrp $(SETUID_GROUP) $$pa; \
	done

amtapeio_SOURCES = amtapeio.test.c
amtapeio_LDADD =	../common-src/libamanda.$(LIB_EXTENSION) \
			libamtape.$(LIB_EXTENSION) \
			../common-src/libamanda.$(LIB_EXTENSION)

amtapeio.test.c: $(srcdir)/tapeio.c
	echo '#define TEST' >$@
	echo '#include "$<"' >>$@

%.test.c: $(srcdir)/%.c
	echo '#define TEST' >$@
	echo '#include "$<"' >>$@

tapetype:
	@echo "Use amtapetype instead"
amanda-2.4.5/tape-src/output-file.c0000644000200500003130000006765107665465001012577 /*
 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
 * Copyright (c) 1991-1998 University of Maryland at College Park
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of U.M. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  U.M. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: James da Silva, Systems Design and Analysis Group
 *			   Computer Science Department
 *			   University of Maryland at College Park
 */

/*
 * $Id: output-file.c,v 1.1.2.4.2.4 2003/05/29 20:13:53 martinea Exp $
 *
 * tapeio.c virtual tape interface for a file device.
 *
 * The following was based on testing with real tapes on Solaris 2.6.
 * It is possible other OS drivers behave somewhat different in end
 * cases, usually involving errors.
 */

#include "amanda.h"

#include "token.h"
#include "tapeio.h"
#include "output-file.h"
#include "fileheader.h"

#ifndef SEEK_SET
#define SEEK_SET 0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR 1
#endif
#ifndef SEEK_END
#define SEEK_END 2
#endif

#define	MAX_TOKENS		10

#define	DATA_INDICATOR		"."
#define	RECORD_INDICATOR	"-"

static
struct volume_info {
    char *basename;			/* filename from open */
    struct file_info *fi;		/* file info array */
    int fi_limit;			/* length of file info array */
    int flags;				/* open flags */
    int mask;				/* open mask */
    int file_count;			/* number of files */
    int file_current;			/* current file position */
    int record_current;			/* current record position */
    int fd;				/* data file descriptor */
    int is_online;			/* true if "tape" is "online" */
    int at_bof;				/* true if at begining of file */
    int at_eof;				/* true if at end of file */
    int at_eom;				/* true if at end of medium */
    int last_operation_write;		/* true if last op was a write */
    long amount_written;		/* KBytes written since open/rewind */
} *volume_info = NULL;

struct file_info {
    char *name;				/* file name (tapefd_getinfo_...) */
    struct record_info *ri;		/* record info array */
    int ri_count;			/* number of record info entries */
    int ri_limit;			/* length of record info array */
    int ri_altered;			/* true if record info altered */
};

struct record_info {
    int record_size;			/* record size */
    int start_record;			/* first record in range */ 
    int end_record;			/* last record in range */ 
};

static int open_count = 0;

/*
 * "Open" the tape by scanning the "data" directory.  "Tape files"
 * have five leading digits indicating the position (counting from zero)
 * followed by a '.' and optional other information (e.g. host/disk/level
 * image name).
 *
 * We allow for the following situations:
 *
 *   + If we see the same "file" (position number) more than once, the
 *     last one seen wins.  This should not normally happen.
 *
 *   + We allow gaps in the positions.  This should not normally happen.
 *
 * Anything in the directory that does not match a "tape file" name
 * pattern is ignored.
 *
 * If the data directory does not exist, the "tape" is considered offline.
 * It is allowed to "appear" later.
 */

static int
check_online(fd)
    int fd;
{
    char *token[MAX_TOKENS];
    DIR *tapedir;
    struct dirent *entry;
    struct file_info *fi;
    char *line;
    int f;
    int pos;
    int rc = 0;

    /*
     * If we are already online, there is nothing else to do.
     */
    if (volume_info[fd].is_online) {
	goto common_exit;
    }

    if ((tapedir = opendir(volume_info[fd].basename)) == NULL) {
	/*
	 * We have already opened the info file which is in the same
	 * directory as the data directory, so ENOENT has to mean the data
	 * directory is not there, which we treat as being "offline".
	 * We're already offline at this point (see the above test)
	 * and this is not an error, so just return success (no error).
	 */

	rc = (errno != ENOENT);
	fprintf(stderr,"ERROR: %s: %s\n", volume_info[fd].basename, strerror(errno));
	goto common_exit;
    }
    while ((entry = readdir(tapedir)) != NULL) {
	if (is_dot_or_dotdot(entry->d_name)) {
	    continue;
	}
	if (isdigit((int)entry->d_name[0])
	    && isdigit((int)entry->d_name[1])
	    && isdigit((int)entry->d_name[2])
	    && isdigit((int)entry->d_name[3])
	    && isdigit((int)entry->d_name[4])
	    && entry->d_name[5] == '.') {

	    /*
	     * This is a "tape file".
	     */
	    pos = atoi(entry->d_name);
	    amtable_alloc((void **)&volume_info[fd].fi,
			  &volume_info[fd].fi_limit,
			  sizeof(*volume_info[fd].fi),
			  pos + 1,
			  10,
			  NULL);
	    fi = &volume_info[fd].fi[pos];
	    if (fi->name != NULL) {
		/*
		 * Two files with the same position???
		 */
		amfree(fi->name);
		fi->ri_count = 0;
	    }
	    fi->name = stralloc(&entry->d_name[6]);
	    if (pos + 1 > volume_info[fd].file_count) {
		volume_info[fd].file_count = pos + 1;
	    }
	}
    }
    closedir(tapedir);

    /*
     * Parse the info file.  We know we are at beginning of file because
     * the only thing that can happen to it prior to here is it being
     * opened.
     */
    for (; (line = areads(fd)) != NULL; free(line)) {
	f = split(line, token, sizeof(token) / sizeof(token[0]), " ");
	if (f == 2 && strcmp(token[1], "position") == 0) {
	    volume_info[fd].file_current = atoi(token[2]);
	    volume_info[fd].record_current = 0;
	}
    }

    /*
     * Set EOM and make sure we are not pre-BOI.
     */
    if (volume_info[fd].file_current >= volume_info[fd].file_count) {
	volume_info[fd].at_eom = 1;
    }
    if (volume_info[fd].file_current < 0) {
	volume_info[fd].file_current = 0;
	volume_info[fd].record_current = 0;
    }

    volume_info[fd].is_online = 1;

common_exit:

    return rc;
}

/*
 * Open the tape file if not already.  If we are beyond the file count
 * (end of tape) or the file is missing and we are only reading, set
 * up to read /dev/null which will look like EOF.  If we are writing,
 * create the file.
 */

static int
file_open(fd)
    int fd;
{
    struct file_info *fi;
    char *datafilename = NULL;
    char *recordfilename = NULL;
    char *f = NULL;
    int pos;
    char *host;
    char *disk;
    int level;
    char number[NUM_STR_SIZE];
    int flags;
    int rfd;
    int n;
    char *line = NULL;
    struct record_info *ri;
    int start_record;
    int end_record;
    int record_size;

    if (volume_info[fd].fd < 0) {
	flags = volume_info[fd].flags;
	pos = volume_info[fd].file_current;
	amtable_alloc((void **)&volume_info[fd].fi,
		      &volume_info[fd].fi_limit,
		      sizeof(*volume_info[fd].fi),
		      pos + 1,
		      10,
		      NULL);
	fi = &volume_info[fd].fi[pos];

	/*
	 * See if we are creating a new file.
	 */
	if (pos >= volume_info[fd].file_count) {
	    volume_info[fd].file_count = pos + 1;
	}

	/*
	 * Generate the file name to open.
	 */
	if (fi->name == NULL) {
	    if ((volume_info[fd].flags & 3) != O_RDONLY) {

		/*
		 * This is a new file, so make sure we create/truncate
		 * it.	Generate the name based on the host/disk/level
		 * information from the caller, if available, else
		 * a constant.
		 */
		flags |= (O_CREAT | O_TRUNC);
		host = tapefd_getinfo_host(fd);
		disk = tapefd_getinfo_disk(fd);
		level = tapefd_getinfo_level(fd);
		ap_snprintf(number, sizeof(number), "%d", level);
		if (host != NULL) {
		    f = stralloc(host);
		}
		if (disk != NULL) {
		    disk = sanitise_filename(disk);
		    if (f == NULL) {
			f = stralloc(disk);
		    } else {
			f = newvstralloc(f, f, ".", disk, NULL);
		    }
		    amfree(disk);
		}
		if (level >= 0) {
		    if (f == NULL) {
			f = stralloc(number);
		    } else {
			f = newvstralloc(f, f, ".", number, NULL);
		    }
		}
		if (f == NULL) {
		    f = stralloc("unknown");
		}
		amfree(fi->name);
		fi->name = stralloc(f);
		fi->ri_count = 0;
		amfree(f);
	    } else {

		/*
		 * This is a missing file, so set up to read nothing.
		 */
		datafilename = stralloc("/dev/null");
		recordfilename = stralloc("/dev/null");
	    }
	}
	if (datafilename == NULL) {
	    ap_snprintf(number, sizeof(number), "%05d", pos);
	    datafilename = vstralloc(volume_info[fd].basename,
				     number,
				     DATA_INDICATOR,
				     volume_info[fd].fi[pos].name,
				     NULL);
	    recordfilename = vstralloc(volume_info[fd].basename,
				       number,
				       RECORD_INDICATOR,
				       volume_info[fd].fi[pos].name,
				       NULL);
	}

	/*
	 * Do the data file open.
	 */
	volume_info[fd].fd = open(datafilename, flags, volume_info[fd].mask);
	amfree(datafilename);

	/*
	 * Load the record information.
	 */
	if (volume_info[fd].fd >= 0
	    && fi->ri_count == 0
	    && (rfd = open(recordfilename, O_RDONLY)) >= 0) {
	    for (; (line = areads(rfd)) != NULL; free(line)) {
		n = sscanf(line,
			   "%d %d %d",
			   &start_record,
			   &end_record,
			   &record_size);
		if (n == 3) {
		    amtable_alloc((void **)&fi->ri,
				  &fi->ri_limit,
				  sizeof(*fi->ri),
				  fi->ri_count + 1,
				  10,
				  NULL);
		    ri = &fi->ri[fi->ri_count];
		    ri->start_record = start_record;
		    ri->end_record = end_record;
		    ri->record_size = record_size;
		    fi->ri_count++;
		}
	    }
	    aclose(rfd);
	}
	amfree(recordfilename);
    }
    return volume_info[fd].fd;
}

/*
 * Close the current data file, if open.  Dump the record information
 * if it has been altered.
 */

static void
file_close(fd)
    int fd;
{
    struct file_info *fi;
    int pos;
    char number[NUM_STR_SIZE];
    char *filename = NULL;
    int r;
    FILE *f;

    aclose(volume_info[fd].fd);
    pos = volume_info[fd].file_current;
    amtable_alloc((void **)&volume_info[fd].fi,
		  &volume_info[fd].fi_limit,
		  sizeof(*volume_info[fd].fi),
		  pos + 1,
		  10,
		  NULL);
    fi = &volume_info[fd].fi[pos];
    if (fi->ri_altered) {
	ap_snprintf(number, sizeof(number), "%05d", pos);
	filename = vstralloc(volume_info[fd].basename,
			     number,
			     RECORD_INDICATOR,
			     fi->name,
			     NULL);
	if ((f = fopen(filename, "w")) == NULL) {
	    goto common_exit;
	}
	for (r = 0; r < fi->ri_count; r++) {
	    fprintf(f,
		    "%d %d %d\n",
		    fi->ri[r].start_record,
		    fi->ri[r].end_record,
		    fi->ri[r].record_size);
	}
	afclose(f);
	fi->ri_altered = 0;
    }

common_exit:

    amfree(filename);
}

/*
 * Release any files beyond a given position current position and reset
 * file_count to file_current to indicate EOM.
 */

static void
file_release(fd)
    int fd;
{
    int position;
    char *filename;
    int pos;
    char number[NUM_STR_SIZE];

    /*
     * If the current file is open, release everything beyond it.
     * If it is not open, release everything from current.
     */
    if (volume_info[fd].fd >= 0) {
	position = volume_info[fd].file_current + 1;
    } else {
	position = volume_info[fd].file_current;
    }
    for (pos = position; pos < volume_info[fd].file_count; pos++) {
	amtable_alloc((void **)&volume_info[fd].fi,
		      &volume_info[fd].fi_limit,
		      sizeof(*volume_info[fd].fi),
		      pos + 1,
		      10,
		      NULL);
	if (volume_info[fd].fi[pos].name != NULL) {
	    ap_snprintf(number, sizeof(number), "%05d", pos);
	    filename = vstralloc(volume_info[fd].basename,
				 number,
				 DATA_INDICATOR,
				 volume_info[fd].fi[pos].name,
				 NULL);
	    unlink(filename);
	    amfree(filename);
	    filename = vstralloc(volume_info[fd].basename,
				 number,
				 RECORD_INDICATOR,
				 volume_info[fd].fi[pos].name,
				 NULL);
	    unlink(filename);
	    amfree(filename);
	    amfree(volume_info[fd].fi[pos].name);
	    volume_info[fd].fi[pos].ri_count = 0;
	}
    }
    volume_info[fd].file_count = position;
}

/*
 * Get the size of a particular record.  We assume the record information is
 * sorted, does not overlap and does not have gaps.
 */

static int
get_record_size(fi, record)
    struct file_info *fi;
    int record;
{
    int r;
    struct record_info *ri;

    for(r = 0; r < fi->ri_count; r++) {
	ri = &fi->ri[r];
	if (record <= ri->end_record) {
	    return ri->record_size;
	}
    }

    /*
     * For historical reasons, the default record size is 32 KBytes.
     * This allows us to read files written by Amanda with that block
     * size before the record information was being kept.
     */
    return 32 * 1024;
}

/*
 * Update the record information.  We assume the record information is
 * sorted, does not overlap and does not have gaps.
 */

static void
put_record_size(fi, record, size)
    struct file_info *fi;
    int record;
    int size;
{
    int r;
    struct record_info *ri;

    fi->ri_altered = 1;
    if (record == 0) {
	fi->ri_count = 0;			/* start over */
    }
    for(r = 0; r < fi->ri_count; r++) {
	ri = &fi->ri[r];
	if (record - 1 <= ri->end_record) {
	    /*
	     * If this record is the same size as the rest of the records
	     * in this entry, or it would replace the entire entry,
	     * reset the end record number and size, then zap the chain
	     * beyond this point.
	     */
	    if (record == ri->start_record || ri->record_size == size) {
		ri->end_record = record;
		ri->record_size = size;
		fi->ri_count = r + 1;
		return;
	    }
	    /*
	     * This record needs a new entry right after the current one.
	     */
	    ri->end_record = record - 1;
	    fi->ri_count = r + 1;
	    break;
	}
    }
    /*
     * Add a new entry.
     */
    amtable_alloc((void **)&fi->ri,
		  &fi->ri_limit,
		  sizeof(*fi->ri),
		  fi->ri_count + 1,
		  10,
		  NULL);
    ri = &fi->ri[fi->ri_count];
    ri->start_record = record;
    ri->end_record = record;
    ri->record_size = size;
    fi->ri_count++;
}

/*
 * The normal interface routines ...
 */

int
file_tape_open(filename, flags, mask)
    char *filename;
    int flags;
    int mask;
{
    int fd = -1;
    int save_errno;
    char *info_file = NULL;

    /*
     * Use only O_RDONLY and O_RDWR.
     */
    if ((flags & 3) != O_RDONLY) {
	flags &= ~3;
	flags |= O_RDWR;
    }

    /*
     * If the caller did not set O_CREAT (and thus, pass a mask
     * parameter), we may still end up creating data files and need a
     * "reasonable" value.  Pick a "tight" value on the "better safe
     * than sorry" theory.
     */
    if ((flags & O_CREAT) == 0) {
	mask = 0600;
    }

    /*
     * Open/create the info file for this "tape".
     */
    info_file = stralloc2(filename, "/info");
    if ((fd = open(info_file, O_RDWR|O_CREAT, 0600)) < 0) {
	goto common_exit;
    }

    /*
     * Create the internal info structure for this "tape".
     */
    amtable_alloc((void **)&volume_info,
		  &open_count,
		  sizeof(*volume_info),
		  fd + 1,
		  10,
		  NULL);
    volume_info[fd].flags = flags;
    volume_info[fd].mask = mask;
    volume_info[fd].file_count = 0;
    volume_info[fd].file_current = 0;
    volume_info[fd].record_current = 0;
    volume_info[fd].fd = -1;
    volume_info[fd].is_online = 0;		/* true when .../data found */
    volume_info[fd].at_bof = 1;			/* by definition */
    volume_info[fd].at_eof = 0;			/* do not know yet */
    volume_info[fd].at_eom = 0;			/* may get reset below */
    volume_info[fd].last_operation_write = 0;
    volume_info[fd].amount_written = 0;

    /*
     * Save the base directory name and see if we are "online".
     */
    volume_info[fd].basename = stralloc2(filename, "/data/");
    if (check_online(fd)) {
	save_errno = errno;
	aclose(fd);
	fd = -1;
	amfree(volume_info[fd].basename);
	errno = save_errno;
	goto common_exit;
    }

common_exit:

    amfree(info_file);

    /*
     * Return the info file descriptor as the unique descriptor for
     * this open.
     */
    return fd;
}

ssize_t
file_tapefd_read(fd, buffer, count)
    int fd;
    void *buffer;
    size_t count;
{
    int result;
    int file_fd;
    int pos;
    int record_size;
    int read_size;

    /*
     * Make sure we are online.
     */
    if ((result = check_online(fd)) != 0) {
	return result;
    }
    if (! volume_info[fd].is_online) {
	errno = EIO;
	return -1;
    }

    /*
     * Do not allow any more reads after we find EOF.
     */
    if (volume_info[fd].at_eof) {
	errno = EIO;
	return -1;
    }

    /*
     * If we are at EOM, set EOF and return a zero length result.
     */
    if (volume_info[fd].at_eom) {
	volume_info[fd].at_eof = 1;
	return 0;
    }

    /*
     * Open the file, if needed.
     */
    if ((file_fd = file_open(fd)) < 0) {
	return file_fd;
    }

    /*
     * Make sure we do not read too much.
     */
    pos = volume_info[fd].file_current;
    record_size = get_record_size(&volume_info[fd].fi[pos],
				  volume_info[fd].record_current);
    if (record_size <= count) {
	read_size = record_size;
    } else {
	read_size = count;
    }

    /*
     * Read the data.  If we ask for less than the record size, skip to
     * the next record boundary.
     */
    result = read(file_fd, buffer, read_size);
    if (result > 0) {
	volume_info[fd].at_bof = 0;
	if (result < record_size) {
	    (void)lseek(file_fd, record_size - result, SEEK_CUR);
	}
	volume_info[fd].record_current++;
    } else if (result == 0) {
	volume_info[fd].at_eof = 1;
    }
    return result;
}

ssize_t
file_tapefd_write(fd, buffer, count)
    int fd;
    const void *buffer;
    size_t count;
{
    int file_fd;
    int write_count = count;
    long length;
    long kbytes_left;
    int result;
    int pos;

    /*
     * Make sure we are online.
     */
    if ((result = check_online(fd)) != 0) {
	return result;
    }
    if (! volume_info[fd].is_online) {
	errno = EIO;
	return -1;
    }

    /*
     * Check for write access first.
     */
    if ((volume_info[fd].flags & 3) == O_RDONLY) {
	errno = EBADF;
	return -1;
    }

    /*
     * Special case: allow negative buffer size.
     */
    if (write_count <= 0) {
	return 0;				/* special case */
    }

    /*
     * If we are at EOM, it takes precedence over EOF.
     */
    if (volume_info[fd].at_eom) {
	volume_info[fd].at_eof = 0;
    }

#if 0 /*JJ*/
    /*
     * Writes are only allowed at BOF and EOM.
     */
    if (! (volume_info[fd].at_bof || volume_info[fd].at_eom)) {
	errno = EIO;
	return -1;
    }
#endif /*JJ*/

    /*
     * Writes are only allowed if we are not at EOF.
     */
    if (volume_info[fd].at_eof) {
	errno = EIO;
	return -1;
    }

    /*
     * Open the file, if needed.
     */
    if((file_fd = volume_info[fd].fd) < 0) {
	file_release(fd);
	if ((file_fd = file_open(fd)) < 0) {
	    return file_fd;
	}
    }

    /*
     * Truncate the write if requested and return a simulated ENOSPC.
     */
    if ((length = tapefd_getinfo_length(fd)) > 0) {
	kbytes_left = length - volume_info[fd].amount_written;
	if (write_count / 1024 > kbytes_left) {
	    write_count = kbytes_left * 1024;
	}
    }
    volume_info[fd].amount_written += (write_count + 1023) / 1024;
    if (write_count <= 0) {
	volume_info[fd].at_bof = 0;
	volume_info[fd].at_eom = 1;
	errno = ENOSPC;
	return -1;
    }

    /*
     * Do the write and truncate the file, if needed.  Checking for
     * last_operation_write is an optimization so we only truncate
     * once.
     */
    if (! volume_info[fd].last_operation_write) {
	(void)ftruncate(file_fd, lseek(file_fd, 0, SEEK_CUR));
	volume_info[fd].at_bof = 0;
	volume_info[fd].at_eom = 1;
    }
    result = write(file_fd, buffer, write_count);
    if (result >= 0) {
	volume_info[fd].last_operation_write = 1;
	pos = volume_info[fd].file_current;
	put_record_size(&volume_info[fd].fi[pos],
			volume_info[fd].record_current,
			result);
	volume_info[fd].record_current++;
    }

    return result;
}

int
file_tapefd_close(fd)
    int fd;
{
    int pos;
    int save_errno;
    char *line;
    int len;
    char number[NUM_STR_SIZE];
    int result;

    /*
     * If our last operation was a write, write a tapemark.
     */
    if (volume_info[fd].last_operation_write) {
	if ((result = file_tapefd_weof(fd, 1)) != 0) {
	    return result;
	}
    }

    /*
     * If we are not at BOF, fsf to the next file unless we
     * are already at end of tape.
     */
    if (! volume_info[fd].at_bof && ! volume_info[fd].at_eom) {
	if ((result = file_tapefd_fsf(fd, 1)) != 0) {
	    return result;
	}
    }

    /*
     * Close the file if it is still open.
     */
    file_close(fd);

    /*
     * Release the info structure areas.
     */
    for (pos = 0; pos < volume_info[fd].fi_limit; pos++) {
	amfree(volume_info[fd].fi[pos].name);
	amtable_free((void **)&volume_info[fd].fi[pos].ri,
		     &volume_info[fd].fi[pos].ri_limit);
	volume_info[fd].fi[pos].ri_count = 0;
    }
    amtable_free((void **)&volume_info[fd].fi, &volume_info[fd].fi_limit);
    volume_info[fd].file_count = 0;
    amfree(volume_info[fd].basename);

    /*
     * Update the status file if we were online.
     */
    if (volume_info[fd].is_online) {
	if (lseek(fd, 0, SEEK_SET) != 0) {
	    save_errno = errno;
	    aclose(fd);
	    errno = save_errno;
	    return -1;
	}
	if (ftruncate(fd, 0) != 0) {
	    save_errno = errno;
	    aclose(fd);
	    errno = save_errno;
	    return -1;
	}
	ap_snprintf(number, sizeof(number),
		    "%d", volume_info[fd].file_current);
	line = vstralloc("position ", number, "\n", NULL);
	len = strlen(line);
	result = write(fd, line, len);
	amfree(line);
	if (result != len) {
	    if (result >= 0) {
		errno = ENOSPC;
	    }
	    save_errno = errno;
	    aclose(fd);
	    errno = save_errno;
	    return -1;
	}
    }

    areads_relbuf(fd);
    return close(fd);
}

void
file_tapefd_resetofs(fd)
    int fd;
{
}

int
file_tapefd_status(fd, stat)
    int fd;
    struct am_mt_status *stat;
{
    int result;

    /*
     * See if we are online.
     */
    if ((result = check_online(fd)) != 0) {
	return result;
    }
    memset((void *)stat, 0, sizeof(*stat));
    stat->online_valid = 1;
    stat->online = volume_info[fd].is_online;
    return 0;
}

int
file_tape_stat(filename, buf)
     char *filename;
     struct stat *buf;
{
     return stat(filename, buf);
}

int
file_tape_access(filename, mode)
     char *filename;
     int mode;
{
     return access(filename, mode);
}

int
file_tapefd_rewind(fd)
    int fd;
{
    int result = 0;

    /*
     * Make sure we are online.
     */
    if ((result = check_online(fd)) != 0) {
	return result;
    }
    if (! volume_info[fd].is_online) {
	errno = EIO;
	return -1;
    }

    /*
     * If our last operation was a write, write a tapemark.
     */
    if (volume_info[fd].last_operation_write) {
	if ((result = file_tapefd_weof(fd, 1)) != 0) {
	    return result;
	}
    }

    /*
     * Close the file if it is still open.
     */
    file_close(fd);

    /*
     * Adjust the position and reset the flags.
     */
    volume_info[fd].file_current = 0;
    volume_info[fd].record_current = 0;

    volume_info[fd].at_bof = 1;
    volume_info[fd].at_eof = 0;
    volume_info[fd].at_eom
      = (volume_info[fd].file_current >= volume_info[fd].file_count);
    volume_info[fd].last_operation_write = 0;
    volume_info[fd].amount_written = 0;

    return result;
}

int
file_tapefd_unload(fd)
    int fd;
{
    int result;

    /*
     * Make sure we are online.
     */
    if ((result = check_online(fd)) != 0) {
	return result;
    }
    if (! volume_info[fd].is_online) {
	errno = EIO;
	return -1;
    }

    file_tapefd_rewind(fd);
    return 0;
}

int
file_tapefd_fsf(fd, count)
    int fd, count;
{
    int result = 0;

    /*
     * Make sure we are online.
     */
    if ((result = check_online(fd)) != 0) {
	return result;
    }
    if (! volume_info[fd].is_online) {
	errno = EIO;
	return -1;
    }

    /*
     * If our last operation was a write and we are going to move
     * backward, write a tapemark.
     */
    if (volume_info[fd].last_operation_write && count < 0) {
	if ((result = file_tapefd_weof(fd, 1)) != 0) {
	    errno = EIO;
	    return -1;
	}
    }

    /*
     * Close the file if it is still open.
     */
    file_close(fd);

    /*
     * If we are at EOM and moving backward, adjust the count to go
     * one more file.
     */
    if (volume_info[fd].at_eom && count < 0) {
	count--;
    }

    /*
     * Adjust the position and return an error if we go beyond either
     * end of the tape.
     */
    volume_info[fd].file_current += count;
    if (volume_info[fd].file_current > volume_info[fd].file_count) {
        volume_info[fd].file_current = volume_info[fd].file_count;
	errno = EIO;
	result = -1;
    } else if (volume_info[fd].file_current < 0) {
        volume_info[fd].file_current = 0;
	errno = EIO;
	result = -1;
    }
    volume_info[fd].record_current = 0;

    /*
     * Set BOF to true so we can write.  Set to EOF to false if the
     * fsf succeeded or if it failed but we were moving backward (and
     * thus we are at beginning of tape), otherwise set it to true so
     * a subsequent read will fail.  Set EOM to whatever is right.
     * Reset amount_written if we ended up back at BOM.
     */
    volume_info[fd].at_bof = 1;
    if (result == 0 || count < 0) {
	volume_info[fd].at_eof = 0;
    } else {
	volume_info[fd].at_eof = 1;
    }
    volume_info[fd].at_eom
      = (volume_info[fd].file_current >= volume_info[fd].file_count);
    volume_info[fd].last_operation_write = 0;
    if (volume_info[fd].file_current == 0) {
	volume_info[fd].amount_written = 0;
    }

    return result;
}

int
file_tapefd_weof(fd, count)
    int fd, count;
{
    int file_fd;
    int result = 0;
    char *save_host;
    char *save_disk;
    int save_level;
    int save_errno;

    /*
     * Make sure we are online.
     */
    if ((result = check_online(fd)) != 0) {
	return result;
    }
    if (! volume_info[fd].is_online) {
	errno = EIO;
	return -1;
    }

    /*
     * Check for write access first.
     */
    if ((volume_info[fd].flags & 3) == O_RDONLY) {
	errno = EACCES;
	return -1;
    }

    /*
     * Special case: allow a zero count.
     */
    if (count == 0) {
	return 0;				/* special case */
    }

    /*
     * Disallow negative count.
     */
    if (count < 0) {
	errno = EINVAL;
	return -1;
    }

    /*
     * Close out the current file if open.
     */
    if ((file_fd = volume_info[fd].fd) >= 0) {
	(void)ftruncate(file_fd, lseek(file_fd, 0, SEEK_CUR));
	file_close(fd);
	volume_info[fd].file_current++;
	volume_info[fd].record_current = 0;
	volume_info[fd].at_bof = 1;
	volume_info[fd].at_eof = 0;
	volume_info[fd].at_eom = 1;
	volume_info[fd].last_operation_write = 0;
	count--;
    }

    /*
     * Release any data files from current through the end.
     */
    file_release(fd);

    /*
     * Save any labelling information in case we clobber it.
     */
    if ((save_host = tapefd_getinfo_host(fd)) != NULL) {
	save_host = stralloc(save_host);
    }
    if ((save_disk = tapefd_getinfo_disk(fd)) != NULL) {
	save_disk = stralloc(save_disk);
    }
    save_level = tapefd_getinfo_level(fd);

    /*
     * Add more tapemarks.
     */
    while (--count >= 0) {
	if (file_open(fd) < 0) {
	    break;
	}
	file_close(fd);
	volume_info[fd].file_current++;
	volume_info[fd].file_count = volume_info[fd].file_current;
	volume_info[fd].record_current = 0;
	volume_info[fd].at_bof = 1;
	volume_info[fd].at_eof = 0;
	volume_info[fd].at_eom = 1;
	volume_info[fd].last_operation_write = 0;

	/*
	 * Only the first "file" terminated by an EOF gets the naming
	 * information from the caller.
	 */
	tapefd_setinfo_host(fd, NULL);
	tapefd_setinfo_disk(fd, NULL);
	tapefd_setinfo_level(fd, -1);
    }

    /*
     * Restore the labelling information.
     */
    save_errno = errno;
    tapefd_setinfo_host(fd, save_host);
    amfree(save_host);
    tapefd_setinfo_disk(fd, save_disk);
    amfree(save_disk);
    tapefd_setinfo_level(fd, save_level);
    errno = save_errno;

    return result;
}

int
file_tapefd_can_fork(fd)
    int fd;
{
    return 0;
}
amanda-2.4.5/tape-src/Makefile.in0000644000200500003130000005523110231511677012204 # Makefile.in generated by automake 1.8.4 from Makefile.am.
# @configure_input@

# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
# 2003, 2004  Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.

# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.

@SET_MAKE@

# Makefile for Amanda tape library.



SOURCES = $(libamtape_la_SOURCES) amdd.c ammt.c $(amtapeio_SOURCES) $(amtapetype_SOURCES)

srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_HEADER = $(INSTALL_DATA)
transform = $(program_transform_name)
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_triplet = @host@
sbin_PROGRAMS = ammt$(EXEEXT) amdd$(EXEEXT) amtapetype$(EXEEXT)
EXTRA_PROGRAMS = $(am__EXEEXT_1)
subdir = tape-src
DIST_COMMON = $(noinst_HEADERS) $(srcdir)/Makefile.am \
	$(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
	$(top_srcdir)/configure.in
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
	$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/config/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config/config.h
CONFIG_CLEAN_FILES =
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)"
libLTLIBRARIES_INSTALL = $(INSTALL)
LTLIBRARIES = $(lib_LTLIBRARIES)
libamtape_la_LIBADD =
am_libamtape_la_OBJECTS = output-file.lo output-null.lo output-rait.lo \
	output-tape.lo tapeio.lo
libamtape_la_OBJECTS = $(am_libamtape_la_OBJECTS)
am__EXEEXT_1 = amtapeio$(EXEEXT)
sbinPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
PROGRAMS = $(sbin_PROGRAMS)
amdd_SOURCES = amdd.c
amdd_OBJECTS = amdd.$(OBJEXT)
amdd_LDADD = $(LDADD)
amdd_DEPENDENCIES = ../common-src/libamanda.$(LIB_EXTENSION) \
	libamtape.$(LIB_EXTENSION) \
	../common-src/libamanda.$(LIB_EXTENSION)
ammt_SOURCES = ammt.c
ammt_OBJECTS = ammt.$(OBJEXT)
ammt_LDADD = $(LDADD)
ammt_DEPENDENCIES = ../common-src/libamanda.$(LIB_EXTENSION) \
	libamtape.$(LIB_EXTENSION) \
	../common-src/libamanda.$(LIB_EXTENSION)
am_amtapeio_OBJECTS = amtapeio.test.$(OBJEXT)
amtapeio_OBJECTS = $(am_amtapeio_OBJECTS)
amtapeio_DEPENDENCIES = ../common-src/libamanda.$(LIB_EXTENSION) \
	libamtape.$(LIB_EXTENSION) \
	../common-src/libamanda.$(LIB_EXTENSION)
am_amtapetype_OBJECTS = tapetype.$(OBJEXT)
amtapetype_OBJECTS = $(am_amtapetype_OBJECTS)
amtapetype_LDADD = $(LDADD)
amtapetype_DEPENDENCIES = ../common-src/libamanda.$(LIB_EXTENSION) \
	libamtape.$(LIB_EXTENSION) \
	../common-src/libamanda.$(LIB_EXTENSION)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)/config
depcomp = $(SHELL) $(top_srcdir)/config/depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/amdd.Po ./$(DEPDIR)/ammt.Po \
@AMDEP_TRUE@	./$(DEPDIR)/amtapeio.test.Po \
@AMDEP_TRUE@	./$(DEPDIR)/output-file.Plo \
@AMDEP_TRUE@	./$(DEPDIR)/output-null.Plo \
@AMDEP_TRUE@	./$(DEPDIR)/output-rait.Plo \
@AMDEP_TRUE@	./$(DEPDIR)/output-tape.Plo ./$(DEPDIR)/tapeio.Plo \
@AMDEP_TRUE@	./$(DEPDIR)/tapetype.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) \
	$(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
	$(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
	$(AM_LDFLAGS) $(LDFLAGS) -o $@
SOURCES = $(libamtape_la_SOURCES) amdd.c ammt.c $(amtapeio_SOURCES) \
	$(amtapetype_SOURCES)
DIST_SOURCES = $(libamtape_la_SOURCES) amdd.c ammt.c \
	$(amtapeio_SOURCES) $(amtapetype_SOURCES)
HEADERS = $(noinst_HEADERS)
ETAGS = etags
CTAGS = ctags
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
ACLOCAL = @ACLOCAL@
ALLOCA = @ALLOCA@
AMANDA_DBGDIR = @AMANDA_DBGDIR@
AMANDA_DEBUG_DAYS = @AMANDA_DEBUG_DAYS@
AMANDA_TMPDIR = @AMANDA_TMPDIR@
AMDEP_FALSE = @AMDEP_FALSE@
AMDEP_TRUE = @AMDEP_TRUE@
AMPLOT_CAT_COMPRESS = @AMPLOT_CAT_COMPRESS@
AMPLOT_CAT_GZIP = @AMPLOT_CAT_GZIP@
AMPLOT_CAT_PACK = @AMPLOT_CAT_PACK@
AMPLOT_COMPRESS = @AMPLOT_COMPRESS@
AMTAR = @AMTAR@
AR = @AR@
AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
AWK_VAR_ASSIGNMENT_OPT = @AWK_VAR_ASSIGNMENT_OPT@
BINARY_OWNER = @BINARY_OWNER@
CAT = @CAT@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
CHIO = @CHIO@
CHS = @CHS@
CLIENT_LOGIN = @CLIENT_LOGIN@
CLIENT_SCRIPTS_OPT = @CLIENT_SCRIPTS_OPT@
COMPRESS = @COMPRESS@
CONFIGURE_COMMAND = @CONFIGURE_COMMAND@
CONFIG_DIR = @CONFIG_DIR@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
DB_EXT = @DB_EXT@
DD = @DD@
DEFAULT_CHANGER_DEVICE = @DEFAULT_CHANGER_DEVICE@
DEFAULT_CONFIG = @DEFAULT_CONFIG@
DEFAULT_RAW_TAPE_DEVICE = @DEFAULT_RAW_TAPE_DEVICE@
DEFAULT_SERVER = @DEFAULT_SERVER@
DEFAULT_TAPE_DEVICE = @DEFAULT_TAPE_DEVICE@
DEFAULT_TAPE_SERVER = @DEFAULT_TAPE_SERVER@
DEFS = @DEFS@
DEPDIR = @DEPDIR@
DUMP = @DUMP@
ECHO = @ECHO@
ECHO_C = @ECHO_C@
ECHO_N = @ECHO_N@
ECHO_T = @ECHO_T@
EGREP = @EGREP@
EXEEXT = @EXEEXT@
F77 = @F77@
FFLAGS = @FFLAGS@
GETCONF = @GETCONF@
GNUPLOT = @GNUPLOT@
GNUTAR = @GNUTAR@
GNUTAR_LISTED_INCREMENTAL_DIRX = @GNUTAR_LISTED_INCREMENTAL_DIRX@
GREP = @GREP@
GZIP = @GZIP@
INSTALL_DATA = @INSTALL_DATA@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LDFLAGS = @LDFLAGS@
LEX = @LEX@
LEXLIB = @LEXLIB@
LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
LIBOBJS = @LIBOBJS@
LIBS = @LIBS@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
LN_S = @LN_S@
LTALLOCA = @LTALLOCA@
LTLIBOBJS = @LTLIBOBJS@
MAILER = @MAILER@
MAKEINFO = @MAKEINFO@
MAXTAPEBLOCKSIZE = @MAXTAPEBLOCKSIZE@
MCUTIL = @MCUTIL@
MT = @MT@
MTX = @MTX@
MT_FILE_FLAG = @MT_FILE_FLAG@
OBJEXT = @OBJEXT@
PACKAGE = @PACKAGE@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_TARNAME = @PACKAGE_TARNAME@
PACKAGE_VERSION = @PACKAGE_VERSION@
PATH_SEPARATOR = @PATH_SEPARATOR@
PCAT = @PCAT@
PERL = @PERL@
PRINT = @PRINT@
RANLIB = @RANLIB@
READLINE_LIBS = @READLINE_LIBS@
RESTORE = @RESTORE@
SAMBA_CLIENT = @SAMBA_CLIENT@
SERVICE_SUFFIX = @SERVICE_SUFFIX@
SETUID_GROUP = @SETUID_GROUP@
SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SNAPSHOT_STAMP = @SNAPSHOT_STAMP@
STRIP = @STRIP@
USE_VERSION_SUFFIXES = @USE_VERSION_SUFFIXES@
VDUMP = @VDUMP@
VERSION = @VERSION@
VERSION_COMMENT = @VERSION_COMMENT@
VERSION_MAJOR = @VERSION_MAJOR@
VERSION_MINOR = @VERSION_MINOR@
VERSION_PATCH = @VERSION_PATCH@
VERSION_SUFFIX = @VERSION_SUFFIX@
VRESTORE = @VRESTORE@
VXDUMP = @VXDUMP@
VXRESTORE = @VXRESTORE@
WANT_AMPLOT_FALSE = @WANT_AMPLOT_FALSE@
WANT_AMPLOT_TRUE = @WANT_AMPLOT_TRUE@
WANT_CHG_SCSI_FALSE = @WANT_CHG_SCSI_FALSE@
WANT_CHG_SCSI_TRUE = @WANT_CHG_SCSI_TRUE@
WANT_CHIO_SCSI_FALSE = @WANT_CHIO_SCSI_FALSE@
WANT_CHIO_SCSI_TRUE = @WANT_CHIO_SCSI_TRUE@
WANT_CLIENT_FALSE = @WANT_CLIENT_FALSE@
WANT_CLIENT_TRUE = @WANT_CLIENT_TRUE@
WANT_RECOVER_FALSE = @WANT_RECOVER_FALSE@
WANT_RECOVER_TRUE = @WANT_RECOVER_TRUE@
WANT_RESTORE_FALSE = @WANT_RESTORE_FALSE@
WANT_RESTORE_TRUE = @WANT_RESTORE_TRUE@
WANT_RUNTIME_PSEUDO_RELOC_FALSE = @WANT_RUNTIME_PSEUDO_RELOC_FALSE@
WANT_RUNTIME_PSEUDO_RELOC_TRUE = @WANT_RUNTIME_PSEUDO_RELOC_TRUE@
WANT_SAMBA_FALSE = @WANT_SAMBA_FALSE@
WANT_SAMBA_TRUE = @WANT_SAMBA_TRUE@
WANT_SERVER_FALSE = @WANT_SERVER_FALSE@
WANT_SERVER_TRUE = @WANT_SERVER_TRUE@
WANT_SETUID_CLIENT_FALSE = @WANT_SETUID_CLIENT_FALSE@
WANT_SETUID_CLIENT_TRUE = @WANT_SETUID_CLIENT_TRUE@
WANT_TAPE_FALSE = @WANT_TAPE_FALSE@
WANT_TAPE_TRUE = @WANT_TAPE_TRUE@
XFSDUMP = @XFSDUMP@
XFSRESTORE = @XFSRESTORE@
YACC = @YACC@
ac_c = @ac_c@
ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_CXX = @ac_ct_CXX@
ac_ct_F77 = @ac_ct_F77@
ac_ct_RANLIB = @ac_ct_RANLIB@
ac_ct_STRIP = @ac_ct_STRIP@
ac_n = @ac_n@
am__fastdepCC_FALSE = @am__fastdepCC_FALSE@
am__fastdepCC_TRUE = @am__fastdepCC_TRUE@
am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@
am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@
am__include = @am__include@
am__leading_dot = @am__leading_dot@
am__quote = @am__quote@
bindir = @bindir@
build = @build@
build_alias = @build_alias@
build_cpu = @build_cpu@
build_os = @build_os@
build_vendor = @build_vendor@
datadir = @datadir@
exec_prefix = @exec_prefix@
host = @host@
host_alias = @host_alias@
host_cpu = @host_cpu@
host_os = @host_os@
host_vendor = @host_vendor@
includedir = @includedir@
infodir = @infodir@
install_sh = @install_sh@
libdir = @libdir@
libexecdir = @libexecdir@
localstatedir = @localstatedir@
mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
prefix = @prefix@
program_transform_name = @program_transform_name@
sbindir = @sbindir@
sharedstatedir = @sharedstatedir@
sysconfdir = @sysconfdir@
target = @target@
target_alias = @target_alias@
target_cpu = @target_cpu@
target_os = @target_os@
target_vendor = @target_vendor@
INCLUDES = -I$(top_srcdir)/common-src
lib_LTLIBRARIES = libamtape.la
LIB_EXTENSION = la
libamtape_la_SOURCES = output-file.c \
			output-null.c \
			output-rait.c \
			output-tape.c \
			tapeio.c

libamtape_la_LDFLAGS = -release $(VERSION)

###
# Because libamanda includes routines (e.g. regex) provided by some system
# libraries, and because of the way libtool sets up the command line, we
# need to list libamanda twice here, first to override the system library
# routines, and second to pick up any references in the other libraries.
###
LDADD = ../common-src/libamanda.$(LIB_EXTENSION) \
	libamtape.$(LIB_EXTENSION) \
	../common-src/libamanda.$(LIB_EXTENSION)


# used for testing only
TEST_PROGS = amtapeio
CLEANFILES = *.test.c
amtapetype_SOURCES = tapetype.c
noinst_HEADERS = \
			output-file.h \
			output-null.h \
			output-rait.h \
			output-tape.h \
			tapeio.h

amtapeio_SOURCES = amtapeio.test.c
amtapeio_LDADD = ../common-src/libamanda.$(LIB_EXTENSION) \
			libamtape.$(LIB_EXTENSION) \
			../common-src/libamanda.$(LIB_EXTENSION)

all: all-am

.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am  $(am__configure_deps)
	@for dep in $?; do \
	  case '$(am__configure_deps)' in \
	    *$$dep*) \
	      cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh \
		&& exit 0; \
	      exit 1;; \
	  esac; \
	done; \
	echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu  tape-src/Makefile'; \
	cd $(top_srcdir) && \
	  $(AUTOMAKE) --gnu  tape-src/Makefile
.PRECIOUS: Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
	@case '$?' in \
	  *config.status*) \
	    cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
	  *) \
	    echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
	    cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
	esac;

$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh

$(top_srcdir)/configure:  $(am__configure_deps)
	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
	cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
install-libLTLIBRARIES: $(lib_LTLIBRARIES)
	@$(NORMAL_INSTALL)
	test -z "$(libdir)" || $(mkdir_p) "$(DESTDIR)$(libdir)"
	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
	  if test -f $$p; then \
	    f="`echo $$p | sed -e 's|^.*/||'`"; \
	    echo " $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) '$$p' '$(DESTDIR)$(libdir)/$$f'"; \
	    $(LIBTOOL) --mode=install $(libLTLIBRARIES_INSTALL) $(INSTALL_STRIP_FLAG) "$$p" "$(DESTDIR)$(libdir)/$$f"; \
	  else :; fi; \
	done

uninstall-libLTLIBRARIES:
	@$(NORMAL_UNINSTALL)
	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
	    p="`echo $$p | sed -e 's|^.*/||'`"; \
	  echo " $(LIBTOOL) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$p'"; \
	  $(LIBTOOL) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$p"; \
	done

clean-libLTLIBRARIES:
	-test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
	@list='$(lib_LTLIBRARIES)'; for p in $$list; do \
	  dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
	  test "$$dir" = "$$p" && dir=.; \
	  echo "rm -f \"$${dir}/so_locations\""; \
	  rm -f "$${dir}/so_locations"; \
	done
libamtape.la: $(libamtape_la_OBJECTS) $(libamtape_la_DEPENDENCIES) 
	$(LINK) -rpath $(libdir) $(libamtape_la_LDFLAGS) $(libamtape_la_OBJECTS) $(libamtape_la_LIBADD) $(LIBS)
install-sbinPROGRAMS: $(sbin_PROGRAMS)
	@$(NORMAL_INSTALL)
	test -z "$(sbindir)" || $(mkdir_p) "$(DESTDIR)$(sbindir)"
	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
	  p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
	  if test -f $$p \
	     || test -f $$p1 \
	  ; then \
	    f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
	   echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) '$$p' '$(DESTDIR)$(sbindir)/$$f'"; \
	   $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(sbinPROGRAMS_INSTALL) "$$p" "$(DESTDIR)$(sbindir)/$$f" || exit 1; \
	  else :; fi; \
	done

uninstall-sbinPROGRAMS:
	@$(NORMAL_UNINSTALL)
	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
	  f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
	  echo " rm -f '$(DESTDIR)$(sbindir)/$$f'"; \
	  rm -f "$(DESTDIR)$(sbindir)/$$f"; \
	done

clean-sbinPROGRAMS:
	@list='$(sbin_PROGRAMS)'; for p in $$list; do \
	  f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
	  echo " rm -f $$p $$f"; \
	  rm -f $$p $$f ; \
	done
amdd$(EXEEXT): $(amdd_OBJECTS) $(amdd_DEPENDENCIES) 
	@rm -f amdd$(EXEEXT)
	$(LINK) $(amdd_LDFLAGS) $(amdd_OBJECTS) $(amdd_LDADD) $(LIBS)
ammt$(EXEEXT): $(ammt_OBJECTS) $(ammt_DEPENDENCIES) 
	@rm -f ammt$(EXEEXT)
	$(LINK) $(ammt_LDFLAGS) $(ammt_OBJECTS) $(ammt_LDADD) $(LIBS)
amtapeio$(EXEEXT): $(amtapeio_OBJECTS) $(amtapeio_DEPENDENCIES) 
	@rm -f amtapeio$(EXEEXT)
	$(LINK) $(amtapeio_LDFLAGS) $(amtapeio_OBJECTS) $(amtapeio_LDADD) $(LIBS)
amtapetype$(EXEEXT): $(amtapetype_OBJECTS) $(amtapetype_DEPENDENCIES) 
	@rm -f amtapetype$(EXEEXT)
	$(LINK) $(amtapetype_LDFLAGS) $(amtapetype_OBJECTS) $(amtapetype_LDADD) $(LIBS)

mostlyclean-compile:
	-rm -f *.$(OBJEXT)

distclean-compile:
	-rm -f *.tab.c

@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amdd.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ammt.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/amtapeio.test.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output-file.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output-null.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output-rait.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/output-tape.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapeio.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tapetype.Po@am__quote@

.c.o:
@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(COMPILE) -c $<

.c.obj:
@am__fastdepCC_TRUE@	if $(COMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \
@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(COMPILE) -c `$(CYGPATH_W) '$<'`

.c.lo:
@am__fastdepCC_TRUE@	if $(LTCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \
@am__fastdepCC_TRUE@	then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Plo"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi
@AMDEP_TRUE@@am__fastdepCC_FALSE@	source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
@AMDEP_TRUE@@am__fastdepCC_FALSE@	$(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
@am__fastdepCC_FALSE@	$(LTCOMPILE) -c -o $@ $<

mostlyclean-libtool:
	-rm -f *.lo

clean-libtool:
	-rm -rf .libs _libs

distclean-libtool:
	-rm -f libtool
uninstall-info-am:

ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
	list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
	unique=`for i in $$list; do \
	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
	  done | \
	  $(AWK) '    { files[$$0] = 1; } \
	       END { for (i in files) print i; }'`; \
	mkid -fID $$unique
tags: TAGS

TAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
		$(TAGS_FILES) $(LISP)
	tags=; \
	here=`pwd`; \
	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
	unique=`for i in $$list; do \
	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
	  done | \
	  $(AWK) '    { files[$$0] = 1; } \
	       END { for (i in files) print i; }'`; \
	if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \
	  test -z "$$unique" && unique=$$empty_fix; \
	  $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
	    $$tags $$unique; \
	fi
ctags: CTAGS
CTAGS:  $(HEADERS) $(SOURCES)  $(TAGS_DEPENDENCIES) \
		$(TAGS_FILES) $(LISP)
	tags=; \
	here=`pwd`; \
	list='$(SOURCES) $(HEADERS)  $(LISP) $(TAGS_FILES)'; \
	unique=`for i in $$list; do \
	    if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
	  done | \
	  $(AWK) '    { files[$$0] = 1; } \
	       END { for (i in files) print i; }'`; \
	test -z "$(CTAGS_ARGS)$$tags$$unique" \
	  || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
	     $$tags $$unique

GTAGS:
	here=`$(am__cd) $(top_builddir) && pwd` \
	  && cd $(top_srcdir) \
	  && gtags -i $(GTAGS_ARGS) $$here

distclean-tags:
	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags

distdir: $(DISTFILES)
	@srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; \
	topsrcdirstrip=`echo "$(top_srcdir)" | sed 's|.|.|g'`; \
	list='$(DISTFILES)'; for file in $$list; do \
	  case $$file in \
	    $(srcdir)/*) file=`echo "$$file" | sed "s|^$$srcdirstrip/||"`;; \
	    $(top_srcdir)/*) file=`echo "$$file" | sed "s|^$$topsrcdirstrip/|$(top_builddir)/|"`;; \
	  esac; \
	  if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
	  dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
	  if test "$$dir" != "$$file" && test "$$dir" != "."; then \
	    dir="/$$dir"; \
	    $(mkdir_p) "$(distdir)$$dir"; \
	  else \
	    dir=''; \
	  fi; \
	  if test -d $$d/$$file; then \
	    if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
	      cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
	    fi; \
	    cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
	  else \
	    test -f $(distdir)/$$file \
	    || cp -p $$d/$$file $(distdir)/$$file \
	    || exit 1; \
	  fi; \
	done
check-am: all-am
check: check-am
all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(HEADERS)
installdirs:
	for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sbindir)"; do \
	  test -z "$$dir" || $(mkdir_p) "$$dir"; \
	done
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am

install-am: all-am
	@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am

installcheck: installcheck-am
install-strip:
	$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
	  install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
	  `test -z '$(STRIP)' || \
	    echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:

clean-generic:
	-test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)

distclean-generic:
	-rm -f $(CONFIG_CLEAN_FILES)

maintainer-clean-generic:
	@echo "This command is intended for maintainers to use"
	@echo "it deletes files that may require special tools to rebuild."
clean: clean-am

clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
	clean-sbinPROGRAMS mostlyclean-am

distclean: distclean-am
	-rm -rf ./$(DEPDIR)
	-rm -f Makefile
distclean-am: clean-am distclean-compile distclean-generic \
	distclean-libtool distclean-tags

dvi: dvi-am

dvi-am:

html: html-am

info: info-am

info-am:

install-data-am:

install-exec-am: install-libLTLIBRARIES install-sbinPROGRAMS
	@$(NORMAL_INSTALL)
	$(MAKE) $(AM_MAKEFLAGS) install-exec-hook

install-info: install-info-am

install-man:

installcheck-am:

maintainer-clean: maintainer-clean-am
	-rm -rf ./$(DEPDIR)
	-rm -f Makefile
maintainer-clean-am: distclean-am maintainer-clean-generic

mostlyclean: mostlyclean-am

mostlyclean-am: mostlyclean-compile mostlyclean-generic \
	mostlyclean-libtool

pdf: pdf-am

pdf-am:

ps: ps-am

ps-am:

uninstall-am: uninstall-info-am uninstall-libLTLIBRARIES \
	uninstall-sbinPROGRAMS

.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \
	clean-libLTLIBRARIES clean-libtool clean-sbinPROGRAMS ctags \
	distclean distclean-compile distclean-generic \
	distclean-libtool distclean-tags distdir dvi dvi-am html \
	html-am info info-am install install-am install-data \
	install-data-am install-exec install-exec-am install-info \
	install-info-am install-libLTLIBRARIES install-man \
	install-sbinPROGRAMS install-strip installcheck \
	installcheck-am installdirs maintainer-clean \
	maintainer-clean-generic mostlyclean mostlyclean-compile \
	mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
	tags uninstall uninstall-am uninstall-info-am \
	uninstall-libLTLIBRARIES uninstall-sbinPROGRAMS


install-exec-hook:
	@list="$(sbin_PROGRAMS) $(sbin_SCRIPTS)"; \
	for p in $$list; do \
		pa=$(DESTDIR)$(sbindir)/`echo $$p|sed '$(transform)'`; \
		echo chown $(BINARY_OWNER) $$pa; \
		chown $(BINARY_OWNER) $$pa; \
		echo chgrp $(SETUID_GROUP) $$pa; \
		chgrp $(SETUID_GROUP) $$pa; \
	done
	@list="$(libexec_PROGRAMS) $(libexec_SCRIPTS)"; \
	for p in $$list; do \
		pa=$(DESTDIR)$(libexecdir)/`echo $$p|sed '$(transform)'`; \
		echo chown $(BINARY_OWNER) $$pa; \
		chown $(BINARY_OWNER) $$pa; \
		echo chgrp $(SETUID_GROUP) $$pa; \
		chgrp $(SETUID_GROUP) $$pa; \
	done

amtapeio.test.c: $(srcdir)/tapeio.c
	echo '#define TEST' >$@
	echo '#include "$<"' >>$@

%.test.c: $(srcdir)/%.c
	echo '#define TEST' >$@
	echo '#include "$<"' >>$@

tapetype:
	@echo "Use amtapetype instead"
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
amanda-2.4.5/tape-src/output-rait.h0000644000200500003130000000675107631740465012621 #ifndef RAIT_H

#define RAIT_H

typedef struct {
    int nopen;
    int nfds;
    int fd_count;
    int *fds;
    int *readres;
    int xorbuflen;
    char *xorbuf;
} RAIT;

#ifdef NO_AMANDA

#define stralloc strdup
#define P(x)	x			/* for function prototypes */

/*
 * Tape drive status structure.  This abstracts the things we are
 * interested in from the free-for-all of what the various drivers
 * supply.
 */

struct am_mt_status {
    char online_valid;			/* is the online flag valid? */
    char bot_valid;			/* is the BOT flag valid? */
    char eot_valid;			/* is the EOT flag valid? */
    char protected_valid;		/* is the protected flag valid? */
    char flags_valid;			/* is the flags field valid? */
    char fileno_valid;			/* is the fileno field valid? */
    char blkno_valid;			/* is the blkno field valid? */
    char device_status_valid;		/* is the device status field valid? */
    char error_status_valid;		/* is the device status field valid? */

    char online;			/* true if device is online/ready */
    char bot;				/* true if tape is at the beginning */
    char eot;				/* true if tape is at end of medium */
    char protected;			/* true if tape is write protected */
    long flags;				/* device flags, whatever that is */
    long fileno;			/* tape file number */
    long blkno;				/* block within file */
    int device_status_size;		/* size of orig device status field */
    unsigned long device_status;	/* "device status", whatever that is */
    int error_status_size;		/* size of orig error status field */
    unsigned long error_status;		/* "error status", whatever that is */
};
#endif

extern int rait_open ();
extern int rait_access P((char *, int));
extern int rait_stat P((char *, struct stat *));
extern int rait_close P((int ));
extern int rait_lseek P((int , long, int));
extern ssize_t rait_write P((int , const void *, size_t));
extern ssize_t rait_read P((int , void *, size_t));
extern int rait_ioctl P((int , int, void *));
extern int rait_copy P((char *f1, char *f2, int buflen));

extern char *rait_init_namelist P((char * dev,
				   char **dev_left,
				   char **dev_right,
				   char **dev_next));
extern int rait_next_name P((char * dev_left,
       			     char * dev_right,
       			     char **dev_next,
       			     char * dev_real));

extern int  rait_tape_open ();
extern int  rait_tapefd_fsf P((int rait_tapefd, int count));
extern int  rait_tapefd_rewind P((int rait_tapefd));
extern void rait_tapefd_resetofs P((int rait_tapefd));
extern int  rait_tapefd_unload P((int rait_tapefd));
extern int  rait_tapefd_status P((int rait_tapefd, struct am_mt_status *stat));
extern int  rait_tapefd_weof P((int rait_tapefd, int count));
extern int  rait_tapefd_can_fork P((int));

#ifdef RAIT_REDIRECT

/* handle ugly Solaris stat mess */

#ifdef _FILE_OFFSET_BITS
#include <sys/stat.h>
#undef stat
#undef open
#if _FILE_OFFSET_BITS == 64
struct	stat {
	dev_t	st_dev;
	long	st_pad1[3];	/* reserved for network id */
	ino_t	st_ino;
	mode_t	st_mode;
	nlink_t st_nlink;
	uid_t 	st_uid;
	gid_t 	st_gid;
	dev_t	st_rdev;
	long	st_pad2[2];
	off_t	st_size;
	timestruc_t st_atim;
	timestruc_t st_mtim;
	timestruc_t st_ctim;
	long	st_blksize;
	blkcnt_t st_blocks;
	char	st_fstype[_ST_FSTYPSZ];
	long	st_pad4[8];	/* expansion area */
};
#endif

#endif

#define access(p,f)	rait_access(p,f)
#define stat(a,b)	rait_stat(a,b)
#define open		rait_open
#define	close(a)	rait_close(a)
#define read(f,b,l)	rait_read(f,b,l)
#define write(f,b,l)	rait_write(f,b,l)
#define	ioctl(f,n,x)	rait_ioctl(f,n,x)
#endif

#endif
amanda-2.4.5/tape-src/output-rait.c0000644000200500003130000007066010043223626012576 #ifdef NO_AMANDA
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <sys/ioctl.h>
#else
#include "amanda.h"
#include "tapeio.h"
#endif

#include "output-rait.h"
#include "output-tape.h"

#ifdef NO_AMANDA
#define	amfree(x)	do {						\
	int save_errno = errno;						\
	free(x);							\
	(x) = 0;							\
	errno = save_errno;						\
} while(0)
#define	tape_open	open
#define tapefd_read	read
#define tapefd_write	write
#define tapefd_close	close
#define tape_access	access
#define tape_stat	stat
#define tapefd_fsf	tape_tapefd_fsf
#define tapefd_rewind	tape_tapefd_rewind
#define tapefd_status	tape_tapefd_status
#define tapefd_unload	tape_tapefd_unload
#define tapefd_weof	tape_tapefd_weof

int tapeio_init_devname (char * dev,
			 char **dev_left,
			 char **dev_right,
			 char **dev_next);
char *tapeio_next_devname (char * dev_left,
			   char * dev_right,
			   char **dev_next);
#endif

/*
** RAIT -- redundant array of (inexpensive?) tapes
**
** Author: Marc Mengel <mengel@fnal.gov>
**
** This package provides for striping input/output across
** multiple tape drives.
**
		 Table of Contents

  rait.c..................................................1
	MAX_RAITS.........................................2
        rait_table........................................2
	rait_open(char *dev, int flags, int mode).........2
	rait_close(int fd)................................3
	rait_lseek(int fd, long pos, int whence)..........4
	rait_write(int fd, const char *buf, int len) .....5
	rait_read(int fd, char *buf, int len).............6
	rait_ioctl(int fd, int op, void *p)...............8
	rait_access(devname, R_OK|W_OK)...................8
	rait_stat(devname, struct statbuf*)...............8
	rait_copy(char *f1, char *f2).....................9
	ifndef NO_AMANDA
	    rait_tapefd_fsf(rait_tapefd, count)..........10
	    rait_tapefd_rewind(rait_tapefd)..............10
	    rait_tapefd_resetofs(rait_tapefd)............10
	    rait_tapefd_unload(rait_tapefd)..............10
	    rait_tapefd_status(rait_tapefd, stat)........10
	    rait_tapefd_weof(rait_tapefd, count).........10

	

   rait.h.................................................1
        typedef RAIT......................................1
        ifdef RAIT_REDIRECT...............................1
             open.........................................1
	     close........................................1
             ioctl........................................1
	     read.........................................1
             write........................................1
*/

/**/

/*
** rait_open takes a string like:
** "/dev/rmt/tps0d{3,5,7,19}nrnsv"
** and opens
** "/dev/rmt/tps0d3nrnsv"
** "/dev/rmt/tps0d5nrnsv"
** "/dev/rmt/tps0d7nrnsv"
** "/dev/rmt/tps0d19nrnsv"
** as a RAIT.
**
** If it has no curly brace, we treat it as a plain device,
** and do a normal open, and do normal operations on it.
*/

#ifdef RAIT_DEBUG
#define rait_debug(p) do {						\
  int save_errno = errno;						\
									\
  if (0!=getenv("RAIT_DEBUG")) {					\
    fprintf p;								\
  }									\
  errno = save_errno;							\
} while (0)
#else
#define rait_debug(p)
#endif

static RAIT *rait_table = 0;		/* table to keep track of RAITS */
static int rait_table_count;

#ifdef NO_AMANDA
/*
 * amtable_alloc -- (re)allocate enough space for some number of elements.
 *
 * input:	table -- pointer to pointer to table
 *		current -- pointer to current number of elements
 *		elsize -- size of a table element
 *		count -- desired number of elements
 *		bump -- round up factor
 * output:	table -- possibly adjusted to point to new table area
 *		current -- possibly adjusted to new number of elements
 */

static int
amtable_alloc(void **table,
	      int *current,
	      size_t elsize,
	      int count,
	      int bump,
	      void *dummy) {
    void *table_new;
    int table_count_new;

    if (count >= *current) {
	table_count_new = ((count + bump) / bump) * bump;
	table_new = malloc(table_count_new * elsize);
	if (0 == table_new) {
	    errno = ENOMEM;
	    return -1;
	}
	if (0 != *table) {
	    memcpy(table_new, *table, *current * elsize);
	    amfree(*table);
	}
	*table = table_new;
	memset(((char *)*table) + *current * elsize,
	       0,
	       (table_count_new - *current) * elsize);
	*current = table_count_new;
    }
    return 0;
}

/*
 * amtable_free -- release a table.
 *
 * input:	table -- pointer to pointer to table
 *		current -- pointer to current number of elements
 * output:	table -- possibly adjusted to point to new table area
 *		current -- possibly adjusted to new number of elements
 */

void
amtable_free(table, current)
    void **table;
    int *current;
{
    amfree(*table);
    *current = 0;
}
#endif

#define rait_table_alloc(fd)	amtable_alloc((void **)&rait_table,	\
					      &rait_table_count,	\
					      sizeof(*rait_table),	\
					      (fd),			\
					      10,			\
					      NULL)

int
rait_open(char *dev, int flags, int mask) {
    int fd;			/* the file descriptor number to return */
    RAIT *res;			/* resulting RAIT structure */
    char *dev_left;		/* string before { */
    char *dev_right;		/* string after } */
    char *dev_next;		/* string inside {} */
    char *dev_real;		/* parsed device name */
    int rait_flag;		/* true if RAIT syntax in dev */
    int save_errno;
    int r;

    rait_debug((stderr,"rait_open( %s, %d, %d )\n", dev, flags, mask));

    rait_flag = (0 != strchr(dev, '{'));

    if (rait_flag) {

	/*
	** we have to return a valid file descriptor, so use
	** a dummy one to /dev/null
	*/
	fd = open("/dev/null",flags,mask);
    } else {

	/*
	** call the normal tape_open function if we are not
	** going to do RAIT
	*/
	fd = tape_open(dev,flags,mask);
    }
    if(-1 == fd) {
	rait_debug((stderr, "rait_open:returning %d: %s\n",
			    fd,
			    strerror(errno)));
	return fd;
    }

    if(0 != rait_table_alloc(fd + 1)) {
	save_errno = errno;
	(void)tapefd_close(fd);
	errno = save_errno;
	rait_debug((stderr, "rait_open:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    res = &rait_table[fd];

    memset(res, 0, sizeof(*res));
    res->nopen = 1;

    res->fd_count = 0;
    if (rait_flag) {

	/* copy and parse the dev string so we can scribble on it */
	dev = stralloc(dev);
	if (0 == dev) {
	    rait_debug((stderr, "rait_open:returning %d: %s\n",
			        -1,
			        "out of stralloc memory"));
	    return -1;
        }
        if (0 != tapeio_init_devname(dev, &dev_left, &dev_right, &dev_next)) {
	    rait_debug((stderr, "rait_open:returning %d: %s\n",
			        -1,
			        strerror(errno)));
	    return -1;
        }

	while (0 != (dev_real = tapeio_next_devname(dev_left, dev_right, &dev_next))) {
	    r = amtable_alloc((void **)&res->fds,
			    &res->fd_count,
			    sizeof(*res->fds),
			    res->nfds + 1,
			    10,
			    NULL);
	    if (0 != r) {
		(void)rait_close(fd);
		fd = -1;
		amfree(dev_real);
		break;
	    }
	    res->fds[ res->nfds ] = tape_open(dev_real,flags,mask);
	    rait_debug((stderr,"rait_open:opening %s yields %d\n",
			dev_real, res->fds[res->nfds] ));
	    if ( res->fds[res->nfds] < 0 ) {
		save_errno = errno;
		(void)rait_close(fd);
		amfree(dev_real);
		errno = save_errno;
		fd = -1;
		break;
	    }
	    tapefd_set_master_fd(res->fds[res->nfds], fd);
	    amfree(dev_real);
	    res->nfds++;
	}

	/* clean up our copied string */
	amfree(dev);

    } else {

	/*
	** set things up to treat this as a normal tape if we ever
	** come in here again
	*/

	res->nfds = 0;
	r = amtable_alloc((void **)&res->fds,
			  &res->fd_count,
			  sizeof(*res->fds),
			  res->nfds + 1,
			  1,
			  NULL);
	if (0 != r) {
	    (void)tapefd_close(fd);
	    memset(res, 0, sizeof(*res));
	    errno = ENOMEM;
	    fd = -1;
	} else {
	    res->fds[res->nfds] = fd;
	    res->nfds++;
	}
    }

    if (fd >= 0 && res->nfds > 0) {
	res->readres = (int *) malloc(res->nfds * sizeof(*res->readres));
	if (0 == res->readres) {
	    (void)rait_close(fd);
	    errno = ENOMEM;
	    fd = -1;
	} else {
	    memset(res->readres, 0, res->nfds * sizeof(*res->readres));
	}
    }

    rait_debug((stderr, "rait_open:returning %d%s%s\n",
			fd,
			(fd < 0) ? ": " : "",
			(fd < 0) ? strerror(errno) : ""));

    return fd;
}

#ifdef NO_AMANDA
int
tapeio_init_devname(char * dev,
		    char **dev_left,
		    char **dev_right,
		    char **dev_next) {
    /*
    ** find the first { and then the first } that follows it
    */
    if ( 0 == (*dev_next = strchr(dev, '{'))
	 || 0 == (*dev_right = strchr(*dev_next + 1, '}')) ) {
	/* we dont have a {} pair */
	amfree(dev);
	errno = EINVAL;
	return -1;
    }

    *dev_left = dev;				/* before the { */
    **dev_next = 0;				/* zap the { */
    (*dev_next)++;
    (*dev_right)++;				/* after the } */
    return 0;
}

char *
tapeio_next_devname(char * dev_left,
	            char * dev_right,
	            char **dev_next) {
    char *dev_real = 0;
    char *next;
    int len;

    next = *dev_next;
    if (0 != (*dev_next = strchr(next, ','))
	|| 0 != (*dev_next = strchr(next, '}'))){
    
	**dev_next = 0;				/* zap the terminator */
	(*dev_next)++;

	/* 
	** we have one string picked out, build it into the buffer
	*/
	len = strlen(dev_left) + strlen(next) + strlen(dev_right) + 1;
	if ( 0 != (dev_real = malloc(len)) ) {
	    strcpy(dev_real, dev_left);		/* safe */
	    strcat(dev_real, next);		/* safe */
	    strcat(dev_real, dev_right);	/* safe */
	}
    }
    return dev_real;
}
#endif

/*
** close everything we opened and free our memory.
*/
int 
rait_close(int fd) {
    int i;			/* index into RAIT drives */
    int j;			/* individual tapefd_close result */
    int res;			/* result from close */
    RAIT *pr;			/* RAIT entry from table */
    int save_errno = errno;
    int kid;

    rait_debug((stderr,"rait_close( %d )\n", fd));

    if (fd < 0 || fd >= rait_table_count) {
	errno = EBADF;
	rait_debug((stderr, "rait_close:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    pr = &rait_table[fd];
    if (0 == pr->nopen) {
	errno = EBADF;
	rait_debug((stderr, "rait_close:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    if (0 == pr->readres && 0 < pr->nfds) {
	pr->readres = (int *) malloc(pr->nfds * sizeof(*pr->readres));
	if (0 == pr->readres) {
	    errno = ENOMEM;
	    rait_debug((stderr, "rait_close:returning %d: %s\n",
			        -1,
			        strerror(errno)));
	    return -1;
	}
	memset(pr->readres, 0, pr->nfds * sizeof(*pr->readres));
    }

    res = 0;
    /* 
    ** this looks strange, but we start kids who are going to close the
    ** drives in parallel just after the parent has closed their copy of
    ** the descriptor. ('cause closing tape devices usually causes slow
    ** activities like filemark writes, etc.)
    */
    for( i = 0; i < pr->nfds; i++ ) {
	if(tapefd_can_fork(pr->fds[i])) {
	    if ((kid = fork()) == 0) {
		/* we are the child process */
		sleep(0);
		j = tapefd_close(pr->fds[i]);
		exit(j);
            } else {
		/* remember who the child is or that an error happened */
	  	pr->readres[i] = kid;
            }
	}
	else {
	    j = tapefd_close(pr->fds[i]);
	    if ( j != 0 )
		res = j;
	    pr->readres[i] = -1;
	}
    }

    for( i = 0; i < pr->nfds; i++ ) {
	j = tapefd_close(pr->fds[i]);
	if ( j != 0 )
           res = j;
    }

    for( i = 0; i < pr->nfds; i++ ) {
        int stat;
	if(pr->readres[i] != -1) {
	    waitpid( pr->readres[i], &stat, 0);
	    if( WEXITSTATUS(stat) != 0 ) {
		res = WEXITSTATUS(stat);
		if( res == 255 ) 
		    res = -1;
	    }
        }
    }
    if (pr->nfds > 1) {
	(void)close(fd);	/* close the dummy /dev/null descriptor */
    }
    if (0 != pr->fds) {
	amtable_free((void **)&pr->fds, &pr->fd_count);
    }
    if (0 != pr->readres) {
	amfree(pr->readres);
    }
    if (0 != pr->xorbuf) {
	amfree(pr->xorbuf);
    }
    pr->nopen = 0;
    errno = save_errno;
    rait_debug((stderr, "rait_close:returning %d%s%s\n",
			res,
			(res < 0) ? ": " : "",
			(res < 0) ? strerror(errno) : ""));
    return res;
}

/**/

/*
** seek out to the nth byte on the RAIT set.
** this is assumed to be evenly divided across all the stripes
*/
int 
rait_lseek(int fd, long pos, int whence) {
    int i;			/* drive number in RAIT */
    long res, 			/* result of lseeks */
	 total;			/* total of results */
    RAIT *pr;			/* RAIT slot in table */

    rait_debug((stderr, "rait_lseek(%d,%ld,%d)\n",fd,pos,whence));

    if (fd < 0 || fd >= rait_table_count) {
	errno = EBADF;
	rait_debug((stderr, "rait_lseek:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    pr = &rait_table[fd];
    if (0 == pr->nopen) {
	errno = EBADF;
	rait_debug((stderr, "rait_lseek:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    if (pr->nfds > 1 && (pos % (pr->nfds-1)) != 0) {
	errno = EDOM;
	total = -1;
    } else {
	total = 0;
	pos = pos / pr->nfds;
	for( i = 0; i < pr->nfds; i++ ) {
	    if (0 >= (res = lseek(pr->fds[i], pos, whence))) {
		total = res;
		break;
	    }
	    total += res;
	}
    }
    rait_debug((stderr, "rait_lseek:returning %ld%s%s\n",
			total,
			(total < 0) ? ": " : "",
			(total < 0) ? strerror(errno) : ""));
    return total;
}

/**/

/*
** if we only have one stream, just do a write, 
** otherwise compute an xor sum, and do several
** writes...
*/
ssize_t 
rait_write(int fd, const void *bufptr, size_t len) {
    const char *buf = bufptr;
    int i = 0, j;	/* drive number, byte offset */
    RAIT *pr;		/* RAIT structure for this RAIT */
    int res, total = 0;
    int data_fds;	/* number of data stream file descriptors */

    rait_debug((stderr, "rait_write(%d,%lx,%d)\n",fd,(unsigned long)buf,len));

    if (fd < 0 || fd >= rait_table_count) {
	errno = EBADF;
	rait_debug((stderr, "rait_write:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    pr = &rait_table[fd];
    if (0 == pr->nopen) {
	errno = EBADF;
	rait_debug((stderr, "rait_write:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    /* need to be able to slice it up evenly... */
    if (pr->nfds > 1) {
	data_fds = pr->nfds - 1;
	if (0 != len % data_fds) {
	    errno = EDOM;
	    rait_debug((stderr, "rait_write:returning %d: %s\n",
			        -1,
			        strerror(errno)));
	    return -1;
	}
	/* each slice gets an even portion */
	len = len / data_fds;

	/* make sure we have enough buffer space */
	if (len > pr->xorbuflen) {
	    if (0 != pr->xorbuf) {
		amfree(pr->xorbuf);
	    }
	    pr->xorbuf = malloc(len);
	    if (0 == pr->xorbuf) {
		errno = ENOMEM;
	        rait_debug((stderr, "rait_write:returning %d: %s\n",
			            -1,
			            strerror(errno)));
		return -1;
	    }
	    pr->xorbuflen = len;
	}

	/* compute the sum */
	memcpy(pr->xorbuf, buf, len);
	for( i = 1; i < data_fds; i++ ) {
	    for( j = 0; j < len; j++ ) {
		pr->xorbuf[j] ^= buf[len * i + j];
	    }
	}
    } else {
	data_fds = pr->nfds;
    }

    /* write the chunks in the main buffer */
    if (total >= 0) {
	for( i = 0; i < data_fds; i++ ) {
	    res = tapefd_write(pr->fds[i], buf + len*i , len);
	    rait_debug((stderr, "rait_write: write(%d,%lx,%d) returns %d%s%s\n",
		        pr->fds[i],
			(unsigned long)(buf + len*i),
			len,
			res,
			(res < 0) ? ": " : "",
			(res < 0) ? strerror(errno) : ""));
	    if (res < 0) {
		total = res;
		break;
	    }
	    total += res;
	}
    }
    if (total >= 0 && pr->nfds > 1) {
        /* write the sum, don't include it in the total bytes written */
	res = tapefd_write(pr->fds[i], pr->xorbuf, len);
	rait_debug((stderr, "rait_write: write(%d,%lx,%d) returns %d%s%s\n",
		    pr->fds[i],
		    (unsigned long)pr->xorbuf,
		    len,
		    res,
		    (res < 0) ? ": " : "",
		    (res < 0) ? strerror(errno) : ""));
	if (res < 0) {
	    total = res;
	}
    }

    rait_debug((stderr, "rait_write:returning %d%s%s\n",
			total,
			(total < 0) ? ": " : "",
			(total < 0) ? strerror(errno) : ""));

    return total;
}

/**/

/*
** once again, if there is one data stream do a read, otherwise
** do all n reads, and if any of the first n - 1 fail, compute
** the missing block from the other three, then return the data.
** there's some silliness here for reading tape with bigger buffers
** than we wrote with, (thus the extra bcopys down below).  On disk if
** you read with a bigger buffer size than you wrote with, you just 
** garble the data...
*/
ssize_t 
rait_read(int fd, void *bufptr, size_t len) {
    char *buf = bufptr;
    int nerrors, 
        neofs, 
        total, 
        errorblock;
    int i,j;
    RAIT *pr;
    int data_fds;
    int save_errno = errno;
    int maxreadres = 0;
    int sum_mismatch = 0;

    rait_debug((stderr, "rait_read(%d,%lx,%d)\n",fd,(unsigned long)buf,len));

    if (fd < 0 || fd >= rait_table_count) {
	errno = EBADF;
	rait_debug((stderr, "rait_read:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    pr = &rait_table[fd];
    if (0 == pr->nopen) {
	errno = EBADF;
	rait_debug((stderr, "rait_read:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    nerrors = 0;
    neofs = 0;
    total = 0;
    errorblock = -1;
    /* once again , we slice it evenly... */
    if (pr->nfds > 1) {
	data_fds = pr->nfds - 1;
	if (0 != len % data_fds) {
	    errno = EDOM;
	    rait_debug((stderr, "rait_read:returning %d: %s\n",
			        -1,
			        strerror(errno)));
	    return -1;
	}
	len = len / data_fds;
    } else {
	data_fds = 1;
    }

    /* try all the reads, save the result codes */
    /* count the eof/errors */
    for( i = 0; i < data_fds; i++ ) {
	pr->readres[i] = tapefd_read(pr->fds[i], buf + len*i , len);
	rait_debug((stderr, "rait_read: read on fd %d returns %d%s%s\n",
		    pr->fds[i],
		    pr->readres[i],
		    (pr->readres[i] < 0) ? ": " : "",
		    (pr->readres[i] < 0) ? strerror(errno) : ""));
	if ( pr->readres[i] <= 0 ) {
	    if ( pr->readres[i] == 0 ) {
		neofs++;
	    } else {
	        if (0 == nerrors) {
		    save_errno = errno;
	        }
	        nerrors++;
	    }
	    errorblock = i;
	} else if (pr->readres[i] > maxreadres) {
	    maxreadres = pr->readres[i];
	}
    }
    if (pr->nfds > 1) {
	/* make sure we have enough buffer space */
	if (len > pr->xorbuflen) {
	    if (0 != pr->xorbuf) {
		amfree(pr->xorbuf);
	    }
	    pr->xorbuf = malloc(len);
	    if (0 == pr->xorbuf) {
		errno = ENOMEM;
	        rait_debug((stderr, "rait_write:returning %d: %s\n",
			            -1,
			            strerror(errno)));
		return -1;
	    }
	    pr->xorbuflen = len;
	}
	pr->readres[i] = tapefd_read(pr->fds[i], pr->xorbuf , len);
	rait_debug((stderr, "rait_read: read on fd %d returns %d%s%s\n",
		    pr->fds[i],
		    pr->readres[i],
		    (pr->readres[i] < 0) ? ": " : "",
		    (pr->readres[i] < 0) ? strerror(errno) : ""));
    }

    /*
     * Make sure all the reads were the same length
     */
    for (j = 0; j < pr->nfds; j++) {
	if (pr->readres[j] != maxreadres) {
	    nerrors++;
	    errorblock = j;
	}
    }

    /*
     * If no errors, check that the xor sum matches
     */
    if ( nerrors == 0 && pr->nfds > 1  ) {
       for(i = 0; i < maxreadres; i++ ) {
	   int sum = 0;
	   for(j = 0; j < pr->nfds - 1; j++) {
	       sum ^= (buf + len * j)[i];
           }
	   if (sum != pr->xorbuf[i]) {
	      sum_mismatch = 1;
	   }
       }
    }

    /* 
    ** now decide what "really" happened --
    ** all n getting eof is a "real" eof
    ** just one getting an error/eof is recoverable if we are doing RAIT
    ** anything else fails
    */

    if (neofs == pr->nfds) {
	rait_debug((stderr, "rait_read:returning 0\n"));
	return 0;
    }

    if (sum_mismatch) {
	errno = EDOM;
	rait_debug((stderr, "rait_read:returning %d: %s\n",
			    -1,
			    "XOR block mismatch"));
	return -1;
    }

    if (nerrors > 1 || (pr->nfds <= 1 && nerrors > 0)) {
	errno = save_errno;
	rait_debug((stderr, "rait_read:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    /*
    ** so now if we failed on a data block, we need to do a recovery
    ** if we failed on the xor block -- who cares?
    */
    if (nerrors == 1 && pr->nfds > 1 && errorblock != pr->nfds-1) {

	rait_debug((stderr, "rait_read: fixing data from fd %d\n",
			    pr->fds[errorblock]));

	/* the reads were all *supposed* to be the same size, so... */
	pr->readres[errorblock] = maxreadres;

	/* fill it in first with the xor sum */
	memcpy(buf + len * errorblock, pr->xorbuf, len);

	/* xor back out the other blocks */
	for( i = 0; i < data_fds; i++ ) {
	    if( i != errorblock ) {
		for( j = 0; j < len ; j++ ) {
		    buf[j + len * errorblock] ^= buf[j + len * i];
		}
	    }
	}
	/* there, now the block is back as if it never failed... */
    }

    /* pack together partial reads... */
    total = pr->readres[0];
    for( i = 1; i < data_fds; i++ ) {
	if (total != len * i) {
	    memmove(buf + total, buf + len*i, pr->readres[i]);
        }
	total += pr->readres[i];
    }

    rait_debug((stderr, "rait_read:returning %d%s%s\n",
			total,
			(total < 0) ? ": " : "",
			(total < 0) ? strerror(errno) : ""));

    return total;
}

/**/

int rait_ioctl(int fd, int op, void *p) {
    int i, res = 0;
    RAIT *pr;
    int errors = 0;

    rait_debug((stderr, "rait_ioctl(%d,%d)\n",fd,op));

    if (fd < 0 || fd >= rait_table_count) {
	errno = EBADF;
	rait_debug((stderr, "rait_ioctl:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    pr = &rait_table[fd];
    if (0 == pr->nopen) {
	errno = EBADF;
	rait_debug((stderr, "rait_ioctl:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    for( i = 0; i < pr->nfds ; i++ ) {
	res = ioctl(pr->fds[i], op, p);
	if ( res != 0 ) { 
	    errors++;
	    if (errors > 1) {
		break;
	    }
	    res = 0;
	}
    }

    rait_debug((stderr, "rait_ioctl: returning %d%s%s\n",
			res,
			(res < 0) ? ": " : "",
			(res < 0) ? strerror(errno) : ""));

    return res;
}

/*
** access() all the devices, returning if any fail
*/
int rait_access(char *devname, int flags) {
    int res = 0;
    char *dev_left;		/* string before { */
    char *dev_right;		/* string after } */
    char *dev_next;		/* string inside {} */
    char *dev_real;		/* parsed device name */

    /* copy and parse the dev string so we can scribble on it */
    devname = stralloc(devname);
    if (0 == devname) {
	rait_debug((stderr, "rait_access:returning %d: %s\n",
			    -1,
			    "out of stralloc memory"));
	return -1;
    }
    if ( 0 != tapeio_init_devname(devname, &dev_left, &dev_right, &dev_next)) {
	rait_debug((stderr, "rait_access:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    while( 0 != (dev_real = tapeio_next_devname(dev_left, dev_right, &dev_next))) {
	res = tape_access(dev_real, flags);
	rait_debug((stderr,"rait_access:access( %s, %d ) yields %d\n",
		dev_real, flags, res ));
	amfree(dev_real);
	if (res < 0) { 
	    break;
        }
    }
    amfree(devname);

    rait_debug((stderr, "rait_access: returning %d%s%s\n",
			res,
			(res < 0) ? ": " : "",
			(res < 0) ? strerror(errno) : ""));

    return res;
}

/*
** stat all the devices, returning the last one unless one fails
*/
int rait_stat(char *devname, struct stat *buf) {
    int res = 0;
    char *dev_left;		/* string before { */
    char *dev_right;		/* string after } */
    char *dev_next;		/* string inside {} */
    char *dev_real;		/* parsed device name */

    /* copy and parse the dev string so we can scribble on it */
    devname = stralloc(devname);
    if (0 == devname) {
	rait_debug((stderr, "rait_access:returning %d: %s\n",
			    -1,
			    "out of stralloc memory"));
	return -1;
    }
    if ( 0 != tapeio_init_devname(devname, &dev_left, &dev_right, &dev_next)) {
	rait_debug((stderr, "rait_access:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    while( 0 != (dev_real = tapeio_next_devname(dev_left, dev_right, &dev_next))) {
	res = tape_stat(dev_real, buf);
	rait_debug((stderr,"rait_stat:stat( %s ) yields %d (%s)\n",
		dev_real, res, (res != 0) ? strerror(errno) : "no error" ));
	amfree(dev_real);
	if (res != 0) { 
	    break;
        }
    }
    amfree(devname);

    rait_debug((stderr, "rait_access: returning %d%s%s\n",
			res,
			(res < 0) ? ": " : "",
			(res < 0) ? strerror(errno) : ""));

    return res;
}

/**/

int rait_copy(char *f1, char *f2, int buflen) {
    int t1, t2;
    int len, wres;
    char *buf;
    int save_errno;

    t1 = rait_open(f1,O_RDONLY,0644);
    if (t1 < 0) {
	return t1;
    }
    t2 = rait_open(f2,O_CREAT|O_RDWR,0644);
    if (t2 < 0) {
	save_errno = errno;
	(void)rait_close(t1);
	errno = save_errno;
	return -1;
    }
    buf = malloc(buflen);
    if (0 == buf) {
	(void)rait_close(t1);
	(void)rait_close(t2);
	errno = ENOMEM;
	return -1;
    }
    do {
	len = rait_read(t1,buf,buflen);
	if (len > 0 ) {
	    wres = rait_write(t2, buf, len);
	    if (wres < 0) {
		len = -1;
		break;
	    }
	}
    } while( len > 0 );
    save_errno = errno;
    amfree(buf);
    (void)rait_close(t1);
    (void)rait_close(t2);
    errno = save_errno;
    return (len < 0) ? -1 : 0;
}

/**/

/*
** Amanda Tape API routines:
*/

static int rait_tapefd_ioctl(int (*func0)(int),
			     int (*func1)(int, int),
			     int fd,
			     int count) {
    int i, j, res = 0;
    RAIT *pr;
    int errors = 0;
    int kid;
    int stat;

    rait_debug((stderr, "rait_tapefd_ioctl(%d,%d)\n",fd,count));

    if (fd < 0 || fd >= rait_table_count) {
	errno = EBADF;
	rait_debug((stderr, "rait_tapefd_ioctl:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    pr = &rait_table[fd];
    if (0 == pr->nopen) {
	errno = EBADF;
	rait_debug((stderr, "rait_tapefd_ioctl:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    if (0 == pr->readres && 0 < pr->nfds) {
	pr->readres = (int *) malloc(pr->nfds * sizeof(*pr->readres));
	if (0 == pr->readres) {
	    errno = ENOMEM;
	    rait_debug((stderr, "rait_tapefd_ioctl:returning %d: %s\n",
			        -1,
			        strerror(errno)));
	    return -1;
	}
	memset(pr->readres, 0, pr->nfds * sizeof(*pr->readres));
    }

    for( i = 0; i < pr->nfds ; i++ ) {
	if(tapefd_can_fork(pr->fds[i])) {
            if ((kid = fork()) < 1) {
		rait_debug((stderr, "in kid, fork returned %d\n", kid));
		/* if we are the kid, or fork failed do the action */
		if (0 != func0) {
		    res = (*func0)(pr->fds[i]);
		} else {
		    res = (*func1)(pr->fds[i], count);
		}
		rait_debug((stderr, "in kid, func ( %d ) returned %d errno %d\n", pr->fds[i], res, errno));
		if (kid == 0)
		    exit(res);
            } else {
		rait_debug((stderr, "in parent, fork returned %d\n", kid));
		pr->readres[i] = kid;
            }
	}
	else {
	    if(0 != func0) {
		j = (*func0)(pr->fds[i]);
	    } else {
		j = (*func1)(pr->fds[i], count);
	    }
	    if( j != 0) {
		errors++;
	    }
	    pr->readres[i] = -1;
	}
    }
    for( i = 0; i < pr->nfds ; i++ ) {
	if(tapefd_can_fork(pr->fds[i])) {
            rait_debug((stderr, "in parent, waiting for %d\n", pr->readres[i]));
	    waitpid( pr->readres[i], &stat, 0);
	    if( WEXITSTATUS(stat) != 0 ) {
		res = WEXITSTATUS(stat);
		if( res == 255 ) 
		    res = -1;
            }
            rait_debug((stderr, "in parent, return code was %d\n", res));
	    if ( res != 0 ) { 
		errors++;
		res = 0;
	    }
	}
    }
    if (errors > 0) {
	res = -1;
    }

    rait_debug((stderr, "rait_tapefd_ioctl: returning %d%s%s\n",
			res,
			(res < 0) ? ": " : "",
			(res < 0) ? strerror(errno) : ""));

    return res;
}

int rait_tapefd_fsf(int fd, int count) {
    return rait_tapefd_ioctl(0, tapefd_fsf, fd, count);
}

int rait_tapefd_rewind(int fd) {
    return rait_tapefd_ioctl(tapefd_rewind, 0, fd, -1);
}

int rait_tapefd_unload(int fd) {
    return rait_tapefd_ioctl(tapefd_unload, 0, fd, -1);
}

int rait_tapefd_weof(int fd, int count) {
    return rait_tapefd_ioctl(0, tapefd_weof, fd, count);
}

int rait_tape_open(char *name, int flags, int mask) {
    return rait_open(name, flags, mask);
}

int rait_tapefd_status(int fd, struct am_mt_status *stat) {
    int i;
    RAIT *pr;
    int res = 0;
    int errors = 0;

    rait_debug((stderr, "rait_tapefd_status(%d)\n",fd));

    if (fd < 0 || fd >= rait_table_count) {
	errno = EBADF;
	rait_debug((stderr, "rait_tapefd_status:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    pr = &rait_table[fd];
    if (0 == pr->nopen) {
	errno = EBADF;
	rait_debug((stderr, "rait_tapefd_status:returning %d: %s\n",
			    -1,
			    strerror(errno)));
	return -1;
    }

    for( i = 0; i < pr->nfds ; i++ ) {
	res = tapefd_status(pr->fds[i], stat);
	if(res != 0) {
	    errors++;
	}
    }
    if (errors > 0) {
	res = -1;
    }
    return res;
}

void rait_tapefd_resetofs(int fd) {
    rait_lseek(fd,  0L, SEEK_SET);
}

int 
rait_tapefd_can_fork(fd)
    int fd;
{
    return 0;
}

amanda-2.4.5/tape-src/output-null.c0000644000200500003130000000740307631740464012621 /*
 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
 * Copyright (c) 1991-1998 University of Maryland at College Park
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of U.M. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  U.M. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: James da Silva, Systems Design and Analysis Group
 *			   Computer Science Department
 *			   University of Maryland at College Park
 */

/*
 * $Id: output-null.c,v 1.1.2.3.2.3 2003/03/06 21:44:20 martinea Exp $
 *
 * tapeio.c virtual tape interface for a null device.
 */

#include "amanda.h"

#include "tapeio.h"
#include "output-null.h"
#include "fileheader.h"
#ifndef R_OK
#define R_OK 4
#define W_OK 2
#endif

static long *amount_written = NULL;
static int open_count = 0;

int
null_tape_open(filename, flags, mask)
    char *filename;
    int flags;
    int mask;
{
    int fd;

    if ((flags & 3) != O_RDONLY) {
	flags &= ~3;
	flags |= O_RDWR;
    }
    if ((fd = open("/dev/null", flags, mask)) >= 0) {
	tapefd_setinfo_fake_label(fd, 1);
	amtable_alloc((void **)&amount_written,
		      &open_count,
		      sizeof(*amount_written),
		      fd + 1,
		      10,
		      NULL);
	amount_written[fd] = 0;
    }
    return fd;
}

ssize_t
null_tapefd_read(fd, buffer, count)
    int fd;
    void *buffer;
    size_t count;
{
    return read(fd, buffer, count);
}

ssize_t
null_tapefd_write(fd, buffer, count)
    int fd;
    const void *buffer;
    size_t count;
{
    int write_count = count;
    long length;
    long kbytes_left;
    int r;

    if (write_count <= 0) {
	return 0;				/* special case */
    }

    if ((length = tapefd_getinfo_length(fd)) > 0) {
	kbytes_left = length - amount_written[fd];
	if (write_count / 1024 > kbytes_left) {
	    write_count = kbytes_left * 1024;
	}
    }
    amount_written[fd] += (write_count + 1023) / 1024;
    if (write_count <= 0) {
	errno = ENOSPC;
	r = -1;
    } else {
	r = write(fd, buffer, write_count);
    }
    return r;
}

int
null_tapefd_close(fd)
    int fd;
{
    return close(fd);
}

void
null_tapefd_resetofs(fd)
    int fd;
{
}

int
null_tapefd_status(fd, stat)
    int fd;
    struct am_mt_status *stat;
{
    memset((void *)stat, 0, sizeof(*stat));
    stat->online_valid = 1;
    stat->online = 1;
    return 0;
}

int
null_tape_stat(filename, buf)
     char *filename;
     struct stat *buf;
{
     return stat("/dev/null", buf);
}

int
null_tape_access(filename, mode)
     char *filename;
     int mode;
{
     return access("/dev/null", mode);
}

int
null_tapefd_rewind(fd)
    int fd;
{
    amount_written[fd] = 0;
    return 0;
}

int
null_tapefd_unload(fd)
    int fd;
{
    amount_written[fd] = 0;
    return 0;
}

int
null_tapefd_fsf(fd, count)
    int fd, count;
{
    return 0;
}

int
null_tapefd_weof(fd, count)
    int fd, count;
{
    return 0;
}

int 
null_tapefd_can_fork(fd)
    int fd;
{
    return 0;
}

amanda-2.4.5/tape-src/tapeio.h0000644000200500003130000001244307632203511011563 /*
 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
 * Copyright (c) 1991-1998 University of Maryland at College Park
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of U.M. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  U.M. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: James da Silva, Systems Design and Analysis Group
 *			   Computer Science Department
 *			   University of Maryland at College Park
 */
/*
 * $Id: tapeio.h,v 1.9.2.2.4.3.2.3 2003/03/07 20:55:37 martinea Exp $
 *
 * interface for tapeio.c
 */
#ifndef TAPEIO_H
#define TAPEIO_H

#include "amanda.h"

/*
 * Tape drive status structure.  This abstracts the things we are
 * interested in from the free-for-all of what the various drivers
 * supply.
 */

struct am_mt_status {
    char online_valid;			/* is the online flag valid? */
    char bot_valid;			/* is the BOT flag valid? */
    char eot_valid;			/* is the EOT flag valid? */
    char protected_valid;		/* is the protected flag valid? */
    char flags_valid;			/* is the flags field valid? */
    char fileno_valid;			/* is the fileno field valid? */
    char blkno_valid;			/* is the blkno field valid? */
    char device_status_valid;		/* is the device status field valid? */
    char error_status_valid;		/* is the device status field valid? */

    char online;			/* true if device is online/ready */
    char bot;				/* true if tape is at the beginning */
    char eot;				/* true if tape is at end of medium */
    char protected;			/* true if tape is write protected */
    long flags;				/* device flags, whatever that is */
    long fileno;			/* tape file number */
    long blkno;				/* block within file */
    int device_status_size;		/* size of orig device status field */
    unsigned long device_status;	/* "device status", whatever that is */
    int error_status_size;		/* size of orig error status field */
    unsigned long error_status;		/* "error status", whatever that is */
};

#define	FAKE_LABEL	"[fake-label]"

int tape_open ();

int tapefd_rewind P((int tapefd));
int tapefd_unload P((int tapefd));
int tapefd_fsf P((int tapefd, int count));
int tapefd_weof P((int tapefd, int count));

int tapefd_status P((int tapefd, struct am_mt_status *));

void tapefd_resetofs P((int tapefd));

ssize_t tapefd_read P((int tapefd, void *buffer, size_t count));
ssize_t tapefd_write P((int tapefd, const void *buffer, size_t count));

char *tapefd_rdlabel P((int tapefd, char **datestamp, char **label));
char *tapefd_wrlabel P((int tapefd,
			char  *datestamp,
			char  *label,
			unsigned int s));
char *tapefd_wrendmark P((int tapefd, char *datestamp, unsigned int s));

int tapefd_eof P((int tapefd));		/* just used in tapeio-test */
int tapefd_close P((int tapefd));
int tapefd_can_fork P((int tapefd));

char *tape_unload P((char *dev));
char *tape_rewind P((char *dev));
char *tape_fsf P((char *dev, int count));
char *tape_rdlabel P((char *dev, char **datestamp, char **label));
char *tape_wrlabel P((char *dev,
		      char  *datestamp,
		      char  *label,
		      unsigned int size));
char *tape_wrendmark P((char *dev,
			char *datestamp,
			unsigned int size));
char *tape_writable P((char *dev));

int tape_access P((char *dev, int mode));
int tape_stat P((char *filename, struct stat *buf));

char *tapefd_getinfo_label P((int fd));
void tapefd_setinfo_label P((int fd, char *v));
char *tapefd_getinfo_host P((int fd));
void tapefd_setinfo_host P((int fd, char *v));
char *tapefd_getinfo_disk P((int fd));
void tapefd_setinfo_disk P((int fd, char *v));
int tapefd_getinfo_level P((int fd));
void tapefd_setinfo_level P((int fd, int v));
char *tapefd_getinfo_datestamp P((int fd));
void tapefd_setinfo_datestamp P((int fd, char *v));
long tapefd_getinfo_length P((int fd));
void tapefd_setinfo_length P((int fd, long v));
char *tapefd_getinfo_tapetype P((int fd));
void tapefd_setinfo_tapetype P((int fd, char *v));
int tapefd_getinfo_fake_label P((int fd));
void tapefd_setinfo_fake_label P((int fd, int v));
int tapefd_getinfo_ioctl_fork P((int fd));
void tapefd_setinfo_ioctl_fork P((int fd, int v));
void tapefd_set_master_fd P((int tapefd, int master_fd));

#ifdef HAVE_LINUX_ZFTAPE_H
int is_zftape P((const char *filename));
#endif

int tapeio_init_devname P((char * dev,
			   char **dev_left,
			   char **dev_right,
			   char **dev_next));
char *tapeio_next_devname P((char * dev_left,
			     char * dev_right,
			     char **dev_next));

#endif /* ! TAPEIO_H */
amanda-2.4.5/tape-src/tapetype.c0000644000200500003130000003656510144440673012147 /*
 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
 * Copyright (c) 1991-1998 University of Maryland at College Park
 * All Rights Reserved.
 *
 * Permission to use, copy, modify, distribute, and sell this software and its
 * documentation for any purpose is hereby granted without fee, provided that
 * the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of U.M. not be used in advertising or
 * publicity pertaining to distribution of the software without specific,
 * written prior permission.  U.M. makes no representations about the
 * suitability of this software for any purpose.  It is provided "as is"
 * without express or implied warranty.
 *
 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 *
 * Author: James da Silva, Systems Design and Analysis Group
 *			   Computer Science Department
 *			   University of Maryland at College Park
 */
/*
 * $Id: tapetype.c,v 1.3.2.3.4.3.2.9.2.2 2004/11/10 16:28:43 martinea Exp $
 *
 * tests a tape in a given tape unit and prints a tapetype entry for
 * it.  */
#include "amanda.h"

#include "tapeio.h"

#define NBLOCKS 32			/* number of random blocks */

extern int optind;

static char *sProgName;
static char *tapedev;
static int fd;

static int blockkb = 32;
static int blocksize;

static char *randombytes = (char *) NULL;

#if USE_RAND
/* If the C library does not define random(), try to use rand() by
   defining USE_RAND, but then make sure you are not using hardware
   compression, because the low-order bits of rand() may not be that
   random... :-( */
#define random() rand()
#define srandom(seed) srand(seed)
#endif

static void allocrandombytes() {
  int i, j, page_size;
  char *p;

  if (randombytes == (char *)NULL) {
#if defined(HAVE_GETPAGESIZE)
    page_size = getpagesize();
#else
    page_size = 1024;
#endif
    j = (NBLOCKS * blocksize) + page_size;	/* buffer space plus one page */
    j = am_round(j, page_size);			/* even number of pages */
    p = alloc(j);
    i = (p - (char *)0) & (page_size - 1);	/* page boundary offset */
    if(i != 0) {
      randombytes = p + page_size - i;		/* round up to page boundary */
    } else {
      randombytes = p;				/* alloc already on boundary */
    }
  }
}

static void initnotrandombytes() {
  int i, j;
  char *p;

  allocrandombytes();
  j =NBLOCKS * blocksize;
  p = randombytes;
  for(i=0; i < j; ++i) {
    *p++ = (char) (i % 256);
  }
}

static void initrandombytes() {
  int i, j;
  char *p;

  allocrandombytes();
  j = NBLOCKS * blocksize;
  p = randombytes;
  for(i=0; i < j; ++i) {
    *p++ = (char)random();
  }
}

static char *getrandombytes() {
  static int counter = 0;

  return randombytes + ((counter++ % NBLOCKS) * blocksize);
}

static int short_write;

int writeblock(fd)
     int fd;
{
  size_t w;

  if ((w = tapefd_write(fd, getrandombytes(), blocksize)) == blocksize) {
    return 1;
  }
  if (w >= 0) {
    short_write = 1;
  } else {
    short_write = 0;
  }
  return 0;
}


/* returns number of blocks actually written */
size_t writeblocks(int fd, size_t nblks)
{
  size_t blks = 0;

  while (blks < nblks) {
    if (! writeblock(fd)) {
      return 0;
    }
    blks++;
  }

  return blks;
}


void usage()
{
  fputs("usage: ", stderr);
  fputs(sProgName, stderr);
  fputs(" [-h]", stderr);
  fputs(" [-c]", stderr);
  fputs(" [-o]", stderr);
  fputs(" [-b blocksize]", stderr);
  fputs(" [-e estsize]", stderr);
  fputs(" [-f tapedev]", stderr);
  fputs(" [-t typename]", stderr);
  fputc('\n', stderr);
}

void help()
{
  usage();
  fputs("\
  -h			display this message\n\
  -c			run hardware compression detection test only\n\
  -o			overwrite amanda tape\n\
  -b blocksize		record block size (default: 32k)\n\
  -e estsize		estimated tape size (default: 1g == 1024m)\n\
  -f tapedev		tape device name (default: $TAPE)\n\
  -t typename		tapetype name (default: unknown-tapetype)\n\
\n\
Note: disable hardware compression when running this program.\n\
", stderr);
}


int do_tty;

void show_progress(blocks, files)
  size_t *blocks, *files;
{
  fprintf(stderr, "wrote %ld %dKb block%s in %ld file%s",
	  (long)*blocks, blockkb, (*blocks == 1) ? "" : "s",
	  (long)*files, (*files == 1) ? "" : "s");
}


void do_pass(size, blocks, files, seconds)
  size_t size, *blocks, *files;
  time_t *seconds;
{
  size_t blks;
  time_t start, end;
  int save_errno;

  if (tapefd_rewind(fd) == -1) {
    fprintf(stderr, "%s: could not rewind %s: %s\n",
	    sProgName, tapedev, strerror(errno));
    exit(1);
  }

  time(&start);

  while(1) {

    if ((blks = writeblocks(fd, size)) <= 0 || tapefd_weof(fd, 1) != 0)
      break;
    *blocks += blks;
    (*files)++;
    if(do_tty) {
      putc('\r', stderr);
      show_progress(blocks, files);
    }
  }
  save_errno = errno;

  time(&end);

  if (*blocks == 0) {
    fprintf(stderr, "%s: could not write any data in this pass: %s\n",
	    sProgName, short_write ? "short write" : strerror(save_errno));
    exit(1);
  }

  if(end <= start) {
    /*
     * Just in case time warped backward or the device is really, really
     * fast (e.g. /dev/null testing).
     */
    *seconds = 1;
  } else {
    *seconds = end - start;
  }
  if(do_tty) {
    putc('\r', stderr);
  }
  show_progress(blocks, files);
  fprintf(stderr, " in %ld second%s (%s)\n",
	  (long)*seconds, ((long)*seconds == 1) ? "" : "s",
	  short_write ? "short write" : strerror(save_errno));
}


void do_pass0(size, seconds, dorewind)
  size_t size;
  time_t *seconds;
  int dorewind;
{
  size_t blks;
  time_t start, end;
  int save_errno;

  if (dorewind  &&  tapefd_rewind(fd) == -1) {
    fprintf(stderr, "%s: could not rewind %s: %s\n",
	    sProgName, tapedev, strerror(errno));
    exit(1);
  }

  time(&start);

  blks = writeblocks(fd, size);
  tapefd_weof(fd, 1);

  save_errno = errno;

  time(&end);

  if (blks <= 0) {
    fprintf(stderr, "%s: could not write any data in this pass: %s\n",
	    sProgName, short_write ? "short write" : strerror(save_errno));
    exit(1);
  }

  if(end <= start) {
    /*
     * Just in case time warped backward or the device is really, really
     * fast (e.g. /dev/null testing).
     */
    *seconds = 1;
  } else {
    *seconds = end - start;
  }
}


int main(argc, argv)
     int argc;
     char *argv[];
{
  size_t pass1blocks = 0;
  size_t pass2blocks = 0;
  time_t pass1time;
  time_t pass2time;
  time_t timediff;
  size_t pass1files = 0;
  size_t pass2files = 0;
  size_t estsize;
  size_t pass0size;
  size_t pass1size;
  size_t pass2size;
  size_t blockdiff;
  size_t filediff;
  long filemark;
  long speed;
  size_t size;
  char *sizeunits;
  int ch;
  char *suffix;
  char *typename;
  time_t now;
  int hwcompr = 0;
  int comprtstonly = 0;
  int overwrite_label = 0;
  int is_labeled = 0;
  char *result;
  char *datestamp = NULL;
  char *label = NULL;


  if ((sProgName = strrchr(*argv, '/')) == NULL) {
    sProgName = *argv;
  } else {
    sProgName++;
  }

  estsize = 1024 * 1024;			/* assume 1 GByte for now */
  tapedev = getenv("TAPE");
  typename = "unknown-tapetype";

  while ((ch = getopt(argc, argv, "b:e:f:t:hco")) != EOF) {
    switch (ch) {
    case 'b':
      blockkb = strtol(optarg, &suffix, 0);
      if (*suffix == '\0' || *suffix == 'k' || *suffix == 'K') {
      } else if (*suffix == 'm' || *suffix == 'M') {
	blockkb *= 1024;
      } else if (*suffix == 'g' || *suffix == 'G') {
	blockkb *= 1024 * 1024;
      } else {
	fprintf(stderr, "%s: unknown size suffix \'%c\'\n", sProgName, *suffix);
	return 1;
      }
      break;
    case 'e':
      estsize = strtol(optarg, &suffix, 0);
      if (*suffix == '\0' || *suffix == 'k' || *suffix == 'K') {
      } else if (*suffix == 'm' || *suffix == 'M') {
	estsize *= 1024;
      } else if (*suffix == 'g' || *suffix == 'G') {
	estsize *= 1024 * 1024;
      } else {
	fprintf(stderr, "%s: unknown size suffix \'%c\'\n", sProgName, *suffix);
	return 1;
      }
      break;
    case 'f':
      tapedev = stralloc(optarg);
      break;
    case 't':
      typename = stralloc(optarg);
      break;
    case 'c':
      comprtstonly = 1;
      break;
    case 'h':
      help();
      return 1;
      break;
    case 'o':
      overwrite_label=1;
      break;
    default:
      fprintf(stderr, "%s: unknown option \'%c\'\n", sProgName, ch);
      /* fall through to ... */
    case '?':
      usage();
      return 1;
      break;
    }
  }
  blocksize = blockkb * 1024;

  if (tapedev == NULL || optind < argc) {
    usage();
    return 1;
  }

/* verifier tape */


  fd = tape_open(tapedev, O_RDONLY);
  if (fd == -1) {
    fprintf(stderr, "%s: could not open %s: %s\n",
	    sProgName, tapedev, strerror(errno));
    return 1;
  }

  if((result = tapefd_rdlabel(fd, &datestamp, &label)) == NULL) {
    is_labeled = 1;
  }
  else if (strcmp(result,"not an amanda tape") == 0) {
    is_labeled = 2;
  }

  if(tapefd_rewind(fd) == -1) {
    fprintf(stderr, "%s: could not rewind %s: %s\n",
	    sProgName, tapedev, strerror(errno));
    tapefd_close(fd);
    return 1;
  }

  tapefd_close(fd);

  if(is_labeled == 1 && overwrite_label == 0) {
    fprintf(stderr, "%s: The tape is an amanda tape, use -o to overwrite the tape\n",
	    sProgName);
    return 1;
  }
  else if(is_labeled == 2 && overwrite_label == 0) {
    fprintf(stderr, "%s: The tape is already used, use -o to overwrite the tape\n",
	    sProgName);
    return 1;
  }

  fd = tape_open(tapedev, O_RDWR);
  if (fd == -1) {
    fprintf(stderr, "%s: could not open %s: %s\n",
	    sProgName, tapedev, strerror(errno));
    return 1;
  }

  do_tty = isatty(fileno(stderr));

  /*
   * Estimate pass: write twice a small file, once with compressable
   * data and once with uncompressable data.
   * The theory is that if the drive is in hardware compression mode
   * we notice a significant difference in writing speed between the two
   * (at least if we can provide data as fast the tape streams).
   */

  initnotrandombytes();

  fprintf(stderr, "Estimate phase 1...");
  pass0size = 8 * 1024 / blockkb;
  pass1time = 0;
  pass2time = 0;
  /*
   * To get accurate results, we should write enough data
   * so that rewind/start/stop time is small compared to
   * the total time; let's take 10%.
   * The timer has a 1 sec granularity, so the test
   * should take at least 10 seconds to measure a
   * difference with 10% accuracy; let's take 25 seconds.
   */ 
  while (pass1time < 25 || ((100*(pass2time-pass1time)/pass2time) >= 10) ) {
    if (pass1time != 0) {
      int i = pass1time;
      do {
	  pass0size *= 2;
	  i *= 2;
      } while (i < 25);
    }
    /*
     * first a dummy pass to rewind, stop, start and
     * get drive streaming, then do the real timing
     */
    do_pass0(pass0size, &pass2time, 1);
    do_pass0(pass0size, &pass1time, 0);
    if (pass0size >= 10 * 1024 * 1024) {
      fprintf(stderr,
	"\rTape device is