#!/usr/pkg/bin/perl -w
# CD-R(W) restore utility
# Copyright (C) 2001 John-Paul Gignac
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# $Id: cdcat.in,v 1.5 2002/02/28 12:34:22 bubuchka Exp $

$mntpt = "/tmp/cdcatdir";
$| = 1;

sub esc_shell {
	$_ = shift;
	s/([^-.\/_a-zA-Z0-9])/\\$1/g;
	return $_;
}

sub usage {
	print STDERR
	"cdcat concatenates several parts of a tar archive from multiple CD-Rs\n".
	"and writes the output to STDOUT.  It is useful as an interactive\n".
	"front-end for multi-disk CD restores.\n".
	"\n".
	"Usage: $0 [OPTION]...\n".
	"Options:\n".
	" -d, --device=PATH   Specify the CD-ROM device (default: /dev/cdrom)\n".
	" -h, --help          Show this help message\n".
	" -p, --prefix=NAME   Specify the filename prefix (default: '')\n".
	" -t, --test          Get files from the current directory instead of the CD\n".
	" -V, --version       Show version info\n";
	exit 1;
}

# Option defaults
$device = "/dev/cdrom";
$prefix = "";
$test = 0;

# Parse the options
while( scalar @ARGV) {
	$_ = shift;
	if( substr( $_, 0, 1) ne '-') {
		unshift( @ARGV, $_);
		last;
	}

	$i = index( $_, '=');
	if( $i > 0) {
		unshift( @ARGV, substr( $_, $i+1));
		$_ = substr( $_, 0, $i);
	}

	if( $_ eq '--') {
		last;
	} elsif( $_ eq '-d' || $_ eq '--device') {
		$device = shift;
	} elsif( $_ eq '-p' || $_ eq '--prefix') {
		$prefix = shift;
	} elsif( $_ eq '-t' || $_ eq '--test') {
		$test = 1;
	} elsif( $_ eq '-V' || $_ eq '--version') {
		print "cdcat-" . '1.0' . "\n";
		exit 0;
	} else {
		usage();
	}
}
usage() if( scalar @ARGV != 0);

$curdisk = 1;

if( $test) {
	$mntpt = ".";
} else {
	# Create the mount point
	die "Directory $mntpt already exists.  Delete it first.\n" if( -e $mntpt);
	mkdir ($mntpt, 0750) || die "Can't create mount point $mntpt.\n";
}

sub eject {
	return if( $test);
	# Eject the drive if possible.
	$cmd = "/usr/bin/eject ".esc_shell($device);
	`$cmd`;  # It's okay if this fails
}

sub mount {
	return if( $test);
	if( system("/sbin/mount -t cd9660 ".esc_shell($device)." $mntpt") != 0)
	{
		die "Can't mount $device: $!\n";
	}
}

sub umount {
	`/sbin/umount $mntpt` unless( $test);
}

$single_disk = 0;
while(1) {
	print STDERR "\07Insert disk $curdisk, then press Enter.\n";
	print STDERR "Type 'q' to quit now if there are no more disks.\n";
	chomp( $ans = <STDIN>);
	last if( $ans eq 'q');

	# Mount the disk
	mount();

	# Figure out the filename
	if( $curdisk == 1) {
		# For the first disk, we have to establish the correct
		# filename prefix from the provided pattern.

		@accept = ();
		@matches = glob $mntpt."/".esc_shell($prefix)."*";
		foreach $match (@matches) {
			if( $match =~ /\.([0-9]+)$/) {
				push @accept, $match if( int( $1) == 1);
			} else {
				push @accept, $match;
			}
		}
		if( scalar @accept == 0) {
			umount();
			die "File pattern not found on CD: $prefix*\n";
		}
		if( scalar @accept > 1) {
			print STDERR "Multiple possible backup files found:\n";
			while(1) {
				for( $i=0; $i < scalar @accept; $i++) {
					print STDERR (($i+1).". ".
						substr($accept[$i],1+length($mntpt))."\n");
				}
				print STDERR "Please enter the number, or 'q' to quit: ";
				chomp( $ans = <STDIN>);
				if( $ans eq 'q') {
					umount();
					print STDERR "Terminated at user request\n";
					exit 2;
				}
				if( $ans =~ /^[1-9][0-9]*$/) {
					$ans = int( $ans);
					last if( $ans <= scalar @accept);
				}
			}
			$filename = $accept[$ans - 1];
		} else {
			$filename = $accept[0];
		}
		if( $filename =~ /^(.*)\.1$/) {
			$prefix = substr($1,1+length($mntpt));
		} else {
			$single_disk = 1;
		}
	} else {
		$filename = "$mntpt/$prefix.$curdisk";
	}

	$uqname = substr($filename,1+length($mntpt));

	if( !-f $filename) {
		umount();
		print STDERR "$uqname not found on CD.\n";
		eject();
		next;
	}

	if( system( "/bin/cat ".esc_shell($filename)) != 0) {
		umount();
		die "Problem reading $uqname from CD.\n";
	}

	# Unmount the disk
	umount();

	last if( $single_disk);

	$curdisk ++;
	eject();
}

rmdir( $mntpt) unless( $test);
