1#!/bin/sh
2#
3# The ‘multicd’ package was initially written by Heiko Schlittermann
4# <heiko@lotte.sax.de> based on builtin access methods written by Ian
5# Jackson <ijackson@chiark.greenend.org.uk>.  The final packaging as well as
6# cleanups were made by Martin Schulze <joey@infodrom.north.de> who also
7# put this package together for the slink release (Debian GNU/Linux
8# 2.1).
9
10# Copyright © 1995-1998 Ian Jackson <ijackson@chiark.greenend.org.uk>
11# Copyright © 1998 Heiko Schlittermann <hs@schlittermann.de>
12#
13# This is free software; you can redistribute it and/or modify
14# it under the terms of the GNU General Public License as published by
15# the Free Software Foundation; either version 2 of the License, or
16# (at your option) any later version.
17#
18# This program is distributed in the hope that it will be useful,
19# but WITHOUT ANY WARRANTY; without even the implied warranty of
20# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21# GNU General Public License for more details.
22#
23# You should have received a copy of the GNU General Public License
24# along with this program.  If not, see <https://www.gnu.org/licenses/>.
25
26set -e
27vardir="$1"
28method=$2
29option=$3
30
31test -d "$vardir/methods/$method" || mkdir "$vardir/methods/$method"
32cd "$vardir/methods/$method"
33tp=/tmp/ddm$$
34
35iarch=`dpkg --print-architecture`
36dist=stable
37
38xit=1
39trap '
40	rm -f $tp.?
41	if [ -n "$umount" ]
42	then
43		umount "$umount" >/dev/null 2>&1
44	fi
45	exit $xit
46' 0
47
48if ls -d "$tp.?" >/dev/null 2>&1
49then
50	rm $tp.?
51fi
52
53#debug() { echo "DEBUG: $@"; }
54debug() { true; }
55ismulti() { debug $1 $2; test -e "$1/.disk/info" || test -e "$1$2/.disk/info"; }
56
57# 1/ mountpoint
58# 2/ hierarchy
59getdisklabel () {
60    debug "$1" "$2"
61    if [ -f $1/.disk/info ]
62    then
63	echo -n `head -1 "$1/.disk/info"`
64    else
65        if [ -f $1$2/.disk/info ]
66	then
67	    echo -n `head -1 "$1$2/.disk/info"`
68	else
69            echo -n 'Non-Debian disc'
70	fi
71    fi
72}
73
74yesno () {
75	while true
76	do
77		echo -n "$2 [$1]  "
78		read response
79		if [ -z "$response" ]
80		then
81			response="$1"
82		fi
83		case "$response" in
84		[Nn]*)	yesno=no ; return ;;
85		[Yy]*)	yesno=yes ; return ;;
86		esac
87	done
88}
89
90getblockdev () {
91	mountpoint="$vardir/methods/mnt"
92	if [ -z "$defaultdevice" ]
93	then
94		defaultdevice="$newdefaultdevice"
95	elif [ "$defaultdevice" != "$newdefaultdevice" ]
96	then
97		echo \
98	"Last time you specified installation from $defaultdevice."
99	fi
100	promptstring="$1"
101	while [ -z "$blockdevice" ]
102	do
103		echo -n "$promptstring [$defaultdevice]:  "
104		read response
105		if [ -z "$response" ]
106		then
107			response="$defaultdevice"
108		fi
109		if [ ! -b "$response" ]
110		then
111			echo "$response is not a block device - will try as loopback.";
112			loop=",loop"
113		fi
114		tryblockdevice="$response"
115		if [ $option = multi_cd ]
116		then
117			fstype=iso9660
118		elif [ $option = harddisk2 ]
119		then
120			blockbase="`echo \"$tryblockdevice\" | sed -e 's/[0-9]\{1,\}$//'`"
121			set +e
122			printf 'p\nq\n' | fdisk "$blockbase" 2>/dev/null >$tp.f
123			set -e
124			proposeddevice="$tryblockdevice" perl -ne '
125next unless /^ *Device +Boot +Begin +Start +End +Blocks +Id +System *$/i .. !/\S/;
126next unless s:^/\S+::p && ${^MATCH} eq $ENV{proposeddevice};
127next unless s/^ +(\* +)?\d+ +\d+ +\d+ +\d+\+? +//;
128next unless m/^([0-9a-f]{1,2}) /i;
129%types= ( "1","msdos", "4","msdos", "6","msdos", "7","hpfs", "80","minix",
130          "81","minix", "83","ext2" );
131print $types{$1}; exit(0);	' <$tp.f >$tp.m
132			defaultfstype="`cat $tp.m`"
133			if [ -n "$defaultfstype" ]
134			then
135				cat <<END
136The partition table for $blockbase claims that $tryblockdevice
137contains filesystem type $defaultfstype.
138END
139				if ! grep "	$defaultfstype$" /proc/filesystems >/dev/null
140				then
141					echo \
142	"Your kernel does not appear to support that filesystem type."
143					defaultfstype=""
144				fi
145			fi
146			echo -n "Supported filesystems: "
147			sed -e 's/^.*	/ /' /proc/filesystems | tr '\n' ' '
148			echo -n "
149Enter filesystem type (for $tryblockdevice) [$defaultfstype]:  "
150			read fstype
151			if [ -z "$fstype" ]
152			then
153				fstype="$defaultfstype"
154			fi
155		fi
156		umount="$mountpoint"
157		if mount -rt "$fstype" -o nosuid,nodev$loop "$tryblockdevice" "$mountpoint"
158		then
159			echo
160			blockdevice="$tryblockdevice"
161		else
162			umount=""
163			echo \
164	"Unable to mount $tryblockdevice on $mountpoint, type $fstype."
165		fi
166	done
167}
168
169outputparam () {
170	echo "$2" | sed -e "s/'/'\\\\''/; s/^/$1='/; s/$/'/" >&3
171}
172
173## MAIN
174intrkey="`stty -a | sed -n 's/.*intr = \([^;]*\);.*/\1/p'`"
175echo "
176If you make a mistake, use the interrupt key ($intrkey) to abort.
177"
178
179# State variables, “best first”
180#  {main,ctb,nf,lcl}_{packages,binary}
181#   Empty before we've found them or if they're not available,
182#   set to the relevant bit under mountpoint otherwise.
183#  hierbase
184#   A directory containing a Debian FTP site mirror tree.
185#  mountpoint
186#   The mountpoint for the filesystem containing the stuff
187#   empty or unset if we don't know yet, or if we haven't mounted anything;
188#   may also be empty if ‘directory’ was set.
189#  blockdevice
190#   The actual block device to mount.
191#  fstype
192#   The filesystem type to use.
193#  defaultdevice
194#   The default block device to mount.
195
196p_usedevel=no
197if [ -f shvar.$option ]
198then
199	. ./shvar.$option
200	defaultdevice="$p_blockdev"
201	defaultnfsserver="$p_nfsserver"
202	defaultnfsrempath="$p_nfsrempath"
203	usedevel="$p_usedevel"
204fi
205
206if [ $option = multi_cd ]
207then
208	mount >$tp.m
209	sed -n 's/ ([^)]*)$//; s/^[^ ]* on //; s/ type iso9660$//p' <$tp.m >$tp.l
210	ncdroms=`wc -l <$tp.l`
211	if [ $ncdroms -gt 1 ]
212	then
213		response=""
214		while [ -z "$response" ]
215		do
216			echo \
217	'Several CD-ROMs (or other ISO9660 filesystems) are mounted:'
218			egrep 'type iso9660 \([^)]*\)$' <$tp.m | nl
219			echo -n \
220	"Is it any of these ?  Type a number, or 'n' for none.  "
221			read response
222			response="`echo \"$response\" | sed -e 's/[ 	]*$//'`"
223			if expr "$response" : '[0-9][0-9]*$' >/dev/null && \
224			   [ $response -ge 1 -a $response -le $ncdroms ]
225			then
226				mountpoint="`sed -n $response'p' <$tp.l`"
227				echo
228			elif expr "$response" : '[Nn]' >/dev/null
229			then
230				mountpoint=""
231			else
232				response=""
233			fi
234		done
235	elif [ $ncdroms = 1 ]
236	then
237		mountpoint="`cat $tp.l`"
238		perl -ne 'print if s/ type iso9660 \([^)]*\)$// && s/ on .*$//;' \
239			<$tp.m >$tp.d
240		blockdevice="`cat $tp.d`"
241		yesno yes \
242	"I see a CD-ROM: $blockdevice, mounted on $mountpoint.  Is it the right one ?"
243		if [ $yesno = no ]
244		then
245			echo 'Unmounting it ...'
246			umount="$mountpoint"
247			while true
248			do
249				echo -n \
250	'Please insert the right disc, and hit return:  '
251				read response
252				if mount -rt iso9660 -o nosuid,nodev \
253					"$blockdevice" "$mountpoint"
254				then
255					echo
256					break
257				fi
258			done
259		fi
260	fi
261	if [ -z "$mountpoint" ]
262	then
263		if [ -b /dev/cdrom ]
264		then
265			echo \
266	'I see that /dev/cdrom exists and is a block device.'
267			newdefaultdevice=/dev/cdrom
268		fi
269		getblockdev 'Insert the CD-ROM and enter the block device name'
270	fi
271fi
272
273if [ $option = multi_nfs ]
274then
275	mountpoint="$vardir/methods/mnt"
276	while [ -z "$nfsserver" ]
277	do
278		echo -n \
279"What is the name of the NFS server ? [$defaultnfsserver]  "
280		read response
281		if [ -z "$response" -a -n "$defaultnfsserver" ]
282		then
283			response="$defaultnfsserver"
284		fi
285		if [ -z "$response" ]; then continue; fi
286		if [ -x "`which rpcinfo`" ]
287		then
288			if rpcinfo -u "$response" mountd >/dev/null
289			then
290				nfsserver="$response"
291			else
292				echo "$response appears not to be an NFS server."
293			fi
294		elif [ -x "`which ping`" ]
295		then
296			if ping -q -c 1 "$response" | grep -q ', 1 packets received'
297			then
298				nfsserver="$response"
299			else
300				echo "$response appears to be down or nonexistent."
301			fi
302		else
303			echo \
304"(I can't check that now because there is no rpcinfo or ping.)"
305			nfsserver="$response"
306		fi
307	done
308	while [ -z "$nfsrempath" ]
309	do
310		echo -n "
311What is the pathname on the NFS server of the filesystem with
312the Debian files ? [$defaultnfsrempath]  "
313		read response
314		if [ -z "$response" -a -n "$defaultnfsrempath" ]
315		then
316			response="$defaultnfsrempath"
317		else
318			response="`echo \"$response\" | sed -e 's:/$::; s:^/*:/:'`"
319		fi
320		umount="$mountpoint"
321		if mount -rt nfs -o nosuid,nodev "$nfsserver:$response" "$mountpoint"
322		then
323			echo
324			nfsrempath="$response"
325		else
326			umount=""
327			echo \
328"Unable to mount NFS filesystem $nfsserver:$response."
329		fi
330	done
331	nfs="$nfsserver:$nfsrempath"
332fi
333
334if [ $option = harddisk2 ]
335then
336	set +e
337	printf 'p\nq\n' | fdisk /dev/hda 2>/dev/null >$tp.f
338	if [ $? != 0 ]
339	then
340		printf 'p\nq\n' | fdisk /dev/sda 2>/dev/null >$tp.f
341	fi
342	set -e
343	perl -ne '
344next unless /^ *Device +Boot +Begin +Start +End +Blocks +Id +System *$/i .. !/\S/;
345next unless / [146] +DOS \d+-bit \S+$/;
346next unless m:^/\S+:p;
347print ${^MATCH};		' <$tp.f >$tp.d
348	newdefaultdevice="`cat $tp.d`"
349	echo "
350I need to know which disk partition contains the distribution files;
351disk partitions are specified by the block device name in Linux."
352	if [ -n "$newdefaultdevice" ]
353	then
354		echo \
355"By the way, $newdefaultdevice looks like a DOS partition."
356	fi
357	getblockdev "Enter the partition's block device name"
358fi
359
360if [ -n "$mountpoint" ]
361then
362	# We must have $mountpoint
363	if [ $option = multi_cd ]
364	then
365		echo \
366'All directory names should be entered relative to the root of the CD-ROM.
367'
368	elif [ $option = multi_nfs ]
369	then
370		echo \
371"All directory names should be entered relative to the root of the NFS
372filesystem, ie relative to $nfsrempath on the server.
373"
374	else
375		echo \
376"All directory names should be entered relative to the root of the
377$fstype filesystem on $blockdevice.
378"
379	fi
380fi
381
382# now try to get the users idea where the debian
383# hierarchy start below the mointpoint
384
385debug "mountpoint: $mountpoint"
386while true
387do
388	if ismulti "${mountpoint}" "${hierbase}"; then
389		multi=yes
390	fi
391
392	if [ $option = multi_cd ]
393	then
394		echo \
395"I would like to know where on the CD-ROM the top level of the Debian
396distribution is - this will usually contain the 'dists' directory.
397
398If the CD-ROM is badly organized and doesn't have a straightforward copy of
399the distribution you may answer 'none' and we'll go through the parts
400I need individually."
401	else
402		echo \
403"In order to make it easy for me to find the relevant files I'd ideally
404like to install from a straightforward copy of the Debian distribution.
405To use this I'll need to know where the top level of that copy of the
406distribution is - this directory usually contains the Packages-Master file.
407
408If you do not have a straightforward copy of the distribution available
409just answer 'none' and we'll go through the parts I need individually."
410	fi
411
412	defhierbase=none
413	if [ -n "$p_hierbase" ]; then
414		if [ -d "$mountpoint/$p_hierbase/dists/$dist/main/binary-$iarch" \
415			-o -n "$multi" ]; then
416			echo "Last time you said '$p_hierbase', and that looks plausible."
417			defhierbase="$p_hierbase"
418		else
419			echo "
420Last time you said '$p_hierbase', but that doesn't look plausible,
421since '$p_hierbase/dists/$dist/main/binary-$iarch' doesn't seem to exist.
422And I can't get the impression that you're using a multi-CD  set."
423		fi
424	fi
425
426	# at this point defhierbase is set if it looks plausible
427	# if ‘none’ was entered, we assume a CD with a debian/ directory
428
429	if [ none = "$defhierbase" -a -d "$mountpoint/debian/dists/$dist/main/binary-$iarch" ]
430	then
431		echo "'/debian' exists and looks plausible, so that's the default."
432		defhierbase=/debian
433	fi
434
435	echo -n "Distribution top level ? [$defhierbase]  "
436	read response
437	if [ -z "$response" ]; then response="$defhierbase"; fi
438	if [ none = "$response" ]; then
439		hierbase=""
440		break
441	elif ismulti "$mountpoint" "$response" && [ -z "$multi" ]; then
442		multi=yes
443	fi
444
445	if ! [ -d "$mountpoint/$response/dists/$dist/main/binary-$iarch" \
446			-o -n "$multi" ]; then
447		echo \
448"Neither $response/dists/$dist/main/binary-$iarch does not exist,
449nor are you using a multi-CD set"
450		break
451	fi
452
453	hierbase="`echo \"$response\" | sed -e 's:/$::; s:^/*:/:; s:/\+:/:g;'`"
454	debug "hierbase: [$hierbase]"
455
456	if [ -n "$multi" ]; then
457		disklabel=`getdisklabel "$mountpoint" "/$response"`
458		echo "Ok, this is disc"
459		echo "    $disklabel"
460		#echo "Updating multi CD contents file cache ..."
461		#multi_contentsfile="${mountpoint}/${response}/.disk/contents.gz"
462		#zcat "$multi_contentsfile" > disk-contents.$option
463	fi
464
465	break;
466done
467
468distribution=$dist
469if [ -n "$hierbase" ]
470then
471	if [ -d "$mountpoint/$hierbase/dists/unstable/binary-$iarch" ]
472	then
473		echo \
474'
475Both a stable released distribution and a work-in-progress
476development tree are available for installation.  Would you like to
477use the unreleased development tree (this is only recommended for
478experts who like to live dangerously and want to help with testing) ?'
479		yesno "$p_usedevel" 'Use unreleased development distribution ?'
480		usedevel="$yesno"
481		if [ "$usedevel" = yes ]
482		then
483			distribution=development
484		fi
485	else
486		usedevel=no
487	fi
488	echo
489fi
490
491case "$hierbase" in
492/* )	;;
493'' )	;;
494* )	hierbase="/$hierbase" ;;
495esac
496
497check_binary () {
498	# args: area-in-messages directory
499	debug "check_binary($@)"
500
501	if [ ! -d "${mountpoint}$2" -a -z "$multi" ]
502	then
503		echo "'$2' does not exist."
504		return
505	fi
506
507# In this special case it is ok for a sub-distribution to not contain any
508# .deb files.  Each CD should contain all Packages.cd files but doesn't
509# need to contain the .deb files.
510#
511#  	if ! { find -L "$mountpoint$2" -name '*.deb' -print \
512#  		| head -1 | grep . ; } >/dev/null 2>&1 && [ -z "$multi" ];
513#  	then
514#  		echo "'$2' does not contain any *.deb packages."
515#  		return
516#  	fi
517
518	this_binary="$2"
519	echo -n "Using '$this_binary' as $1 binary directory"
520
521	if [ -n "$multi" ]; then
522		this_disk=`getdisklabel ${mountpoint} "/$hierbase"`
523		echo " from disc"
524		echo "    '$this_disk'"
525	else
526		echo ""
527	fi
528}
529
530find_area () {
531	# args: area-in-messages area-in-vars subdirectory-in-hier
532	#       last-time-binary last-time-packages
533	debug "find_area($@)"
534	this_binary=''
535	this_packages=''
536	this_disk=''
537	if [ -n "$hierbase" ]
538	then
539		check_binary $1 `echo "$hierbase/dists/$3/$1/binary-$iarch" | sed 's:/\+:/:g'`
540		debug "THIS_BINARY $this_binary"
541	fi
542	if [ $option = multi_cd -a $2 = nf -a -z "$this_binary" ]
543	then
544		echo "
545Note: most CD-ROM distributions of Debian do not include programs
546available in the 'non-free' directory of the distribution site.
547This is because these programs have copyrights that prevent
548distribution for profit on a CD-ROM - ie they are not free software.
549If you wish to install these programs you'll have to get them from an
550alternative source."
551	fi
552	while [ -z "$this_binary" ]
553	do
554		defaultbinary="$4"
555		echo "
556Which directory contains the *.deb packages from the $1 distribution
557area (this directory is named '$3/binary' on the distribution site) ?
558Say 'none' if this area is not available."
559		if [ $2 != main -a -z "$defaultbinary" ]
560		then
561			defaultbinary=none
562		fi
563		echo -n \
564"Enter _$1_ binary directory. [$4]
565 ?  "
566		read response
567		if [ -z "$response" -a -n "$defaultbinary" ]
568		then
569			response="$defaultbinary"
570		fi
571		if [ none = "$response" ]
572		then
573			break
574		fi
575		case "$response" in
576		'' | none)	continue		;;
577		esac
578		check_binary $1 "`echo \"$response\" | sed -e 's:/$::; s:^/*:/:'`"
579	done
580	if [ -n "$this_binary" ]
581	then
582		if [ "$multi" = "yes" ]; then
583			for f in Packages.cd.gz packages.cd.gz Packages.cd packages.cd
584			do
585				if [ -f "$mountpoint/$this_binary/$f" ]
586				then
587					this_packages="$this_binary/$f"
588					echo "Using '$this_packages' for $1."
589					break
590				fi
591			done
592		else
593			if [ -f "${mountpoint}${hierbase}/.disk/packages/$1/Packages.gz" ]; then
594				this_packages=`echo "${hierbase}/.disk/packages/$1/Packages.gz"|sed 's:/\+:/:g'`
595				echo "Using '${this_packages}' for $1."
596			fi
597		fi
598		while [ -z "$this_packages" ]
599		do
600			echo -n "
601I can't find the $1 'Packages.cd' file.  The information in the
602'Packages.cd' file is important for package selection during new
603installations, and is very useful for upgrades.
604
605If you overlooked it when downloading you should do get it now and
606return to this installation procedure when you have done so: you will
607find one Packages.cd file and one Packages.cd.gz file -- either will do --
608in the 'binary' subdirectory of each area on the FTP sites and
609CD-ROMs.  Alternatively (and this will be rather slow) I can scan the
610packages in the distribution area - say 'scan' if you want me to do so.
611
612You need a separate Packages.cd file from each of the distribution areas
613you wish to install.
614
615Where is the _$1_ 'Packages.cd' file (if none is available, say 'none')
616[$5]
617 ?  "
618			read response
619			if [ -z "$response" -a -n "$5" ]
620			then
621				response="$5"
622			fi
623			case "$response" in
624			'')		break				;;
625			none)		break				;;
626			scan)		this_packages=scan		;;
627			/*)		this_packages="$response"	;;
628			*)		this_packages="/$response"	;;
629			esac
630		done
631	fi
632	eval $2'_binary="$this_binary"'
633	eval $2'_packages="$this_packages"'
634	eval $2'_disk="$this_disk"'
635}
636
637find_area main main "$distribution" "$p_main_binary" "$p_main_packages"
638find_area contrib ctb "$distribution" "$p_ctb_binary" "$p_ctb_packages"
639find_area non-free nf "$distribution" "$p_nf_binary" "$p_nf_packages"
640find_area local lcl local "$p_lcl_binary" "$p_lcl_packages"
641
642echo -n '
643Hit RETURN to continue.  '
644read response
645
646exec 3>shvar.$option.new
647
648outputparam p_blockdev "$blockdevice"
649outputparam p_fstype "$fstype"
650outputparam p_mountpoint "$mountpoint"
651outputparam p_nfsserver "$nfsserver"
652outputparam p_nfsrempath "$nfsrempath"
653outputparam p_nfs "$nfs"
654outputparam p_hierbase "$hierbase"
655outputparam p_usedevel "$usedevel"
656outputparam p_main_packages "$main_packages"
657outputparam p_main_binary "$main_binary"
658outputparam p_main_disk "$main_disk"
659outputparam p_ctb_packages "$ctb_packages"
660outputparam p_ctb_binary "$ctb_binary"
661outputparam p_ctb_disk "$ctb_disk"
662outputparam p_nf_packages "$nf_packages"
663outputparam p_nf_binary "$nf_binary"
664outputparam p_nf_disk "$nf_disk"
665outputparam p_lcl_packages "$lcl_packages"
666outputparam p_lcl_binary "$lcl_binary"
667outputparam p_multi "$multi"
668outputparam p_multi_contentsfile "$multi_contentsfile"
669
670mv shvar.$option.new shvar.$option
671
672xit=0
673