From 66c32905a8e5a3e70909fe6dbcfedb4498e10f03 Mon Sep 17 00:00:00 2001 From: Thorsten Glaser Date: Sat, 20 Nov 2010 19:19:21 +0000 Subject: new GRUB2 installation script, derived from MirBSD bootblocks Signed-off-by: Thorsten Glaser --- scripts/install.sh | 408 +++++++++++++++++++++++++++++++++++++++-------------- tools/adk/Makefile | 5 +- tools/adk/pt.c | 243 ------------------------------- 3 files changed, 303 insertions(+), 353 deletions(-) delete mode 100644 tools/adk/pt.c diff --git a/scripts/install.sh b/scripts/install.sh index e1a80d787..2665c30c5 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1,132 +1,328 @@ #!/usr/bin/env bash -# This file is part of the OpenADK project. OpenADK is copyrighted -# material, please see the LICENCE file in the top-level directory. +#- +# Copyright © 2010 +# Waldemar Brodkorb +# Thorsten Glaser +# +# Provided that these terms and disclaimer and all copyright notices +# are retained or reproduced in an accompanying document, permission +# is granted to deal in this work without restriction, including un‐ +# limited rights to use, publicly perform, distribute, sell, modify, +# merge, give away, or sublicence. +# +# This work is provided “AS IS” and WITHOUT WARRANTY of any kind, to +# the utmost extent permitted by applicable law, neither express nor +# implied; without malicious intent or gross negligence. In no event +# may a licensor, author or contributor be held liable for indirect, +# direct, other damage, loss, or other issues arising in any way out +# of dealing in the work, even if advised of the possibility of such +# damage or existence of a defect, except proven that it results out +# of said person’s immediate fault when using the work as intended. +# +# Alternatively, this work may be distributed under the terms of the +# General Public License, any version, as published by the Free Soft- +# ware Foundation. +#- +# Prepare a USB stick or CF/SD/MMC card or hard disc for installation +# of OpenADK: +# • install a Master Boot Record containing a MirBSD PBR loading GRUB +# • write GRUB2 core.img just past the MBR +# • create a root partition with ext2fs and extract the OpenADK image +# just built there +# • create a cfgfs partition TOPDIR=$(pwd) +me=$0 -if [ $(id -u) -ne 0 ];then - printf "Installation is only possible as root\n" - exit 1 +case :$PATH: in +(*:$TOPDIR/bin/tools:*) ;; +(*) export PATH=$PATH:$TOPDIR/bin/tools ;; +esac + +test -n "$KSH_VERSION" || if ! which mksh >/dev/null 2>&1; then + make package=mksh fetch || exit 1 + df=$(cd package/mksh; TOPDIR="$TOPDIR" gmake show=DISTFILES) + mkdir -p build_mksh + gzip -dc dl/"$df" | (cd build_mksh; cpio -mid) + cd build_mksh/mksh + bash Build.sh -r || exit 1 + cp mksh "$TOPDIR"/bin/tools/ + cd "$TOPDIR" + rm -rf build_mksh fi -printf "Checking if mke2fs is installed" -mke2fs=$(which mke2fs) +test -n "$KSH_VERSION" || exec mksh "$me" "$@" +if test -z "$KSH_VERSION"; then + echo >&2 Fatal error: could not run myself with mksh! + exit 255 +fi -if [ ! -z $mke2fs -a -x $mke2fs ];then - printf "...okay\n" -else - printf "...failed\n" +### run with mksh from here onwards ### + +me=${me##*/} + +if (( USER_ID )); then + print -u2 Installation is only possible as root! exit 1 fi +TOPDIR=$(realpath .) +ostype=$(uname -s) + cfgfs=1 quiet=0 -console=0 serial=0 -while getopts "nq" option -do - case $option in - q) - quiet=1 - ;; - n) - cfgfs=0 - ;; - *) - printf "Option not recognized\n" +speed=115200 + +function usage { +cat >&2 < 5 )); then + print -u2 "$me: -c $OPTARG out of bounds" + exit 1 + fi ;; + (h) usage 0 ;; + (q) quiet=1 ;; + (+q) quiet=0 ;; + (s) if [[ $OPTARG != @(96|192|384|576|1152)00 ]]; then + print -u2 "$me: serial speed $OPTARG invalid" exit 1 - ;; - esac + fi + speed=$OPTARG ;; + (t) serial=1 ;; + (+t) serial=0 ;; + (*) usage 1 ;; + } done -shift $(($OPTIND - 1)) +shift $((OPTIND - 1)) +(( $# == 2 )) || usage 1 -if [ -z $1 ];then - printf "Please give your compact flash or USB device as first parameter\n" +f=0 +tools='mke2fs tune2fs' +case $ostype { +(DragonFly|*BSD*) + ;; +(Darwin) + tools="$tools fuse-ext2" + ;; +(Linux) + ;; +(*) + print -u2 Sorry, not ported to the OS "'$ostype'" yet. exit 1 -else - if [ -z $2 ];then - printf "Please give your install tar archive as second parameter\n" - exit 2 - fi - if [ -f $2 ];then - printf "Installing $2 on $1\n" - else - printf "$2 is not a file, Exiting\n" - exit 1 - fi - if [ -b $1 ];then - printf "Using $1 as CF/USB disk for installation\n" - if [ $quiet -eq 0 ];then - printf "This will destroy all data on $1, are you sure?\n" - printf "Type "y" to continue\n" - read y - fi + ;; +} +for tool in $tools; do + print -n Checking if $tool is installed... + if whence -p $tool >/dev/null; then + print " okay" else - printf "Sorry $1 is not a block device\n" - exit 1 + print " failed" + f=1 fi +done +(( f )) && exit 1 + +tgt=$1 +src=$2 + +if [[ ! -b $tgt ]]; then + print -u2 "'$tgt' is not a block device, exiting" + exit 1 fi - -if [ $(mount | grep $1| wc -l) -ne 0 ];then - printf "Block device $1 is in use, please umount first.\n" +if [[ ! -f $src ]]; then + print -u2 "'$src' is not a file, exiting" exit 1 fi +(( quiet )) || print "Installing $src on $tgt." -case $2 in - wrap*) - speed=38400 - ;; - *) - speed=115200 - ;; -esac - -rootpart=${1}1 -pt=$TOPDIR/bin/tools/pt -# get sector size from block device -maxsector=$(sudo $pt -g $1) -head=16 -sect=63 -rsize=$(($maxsector / 2)) - -printf "Creating partition table ...\n" -table=$(mktemp) -# generate partition table -$pt -o $table -s $sect -h $head -p ${rsize}K -# write partition table to block device -dd if=$table of=$1 bs=512 count=1 2> /dev/null -printf "Creating ext2 filesystem ...\n" -$mke2fs -q ${1}1 - -printf "Extracting install archive ...\n" -tmp=$(mktemp -d) -mount -t ext2 ${rootpart} $tmp -tar -C $tmp -xzpf $2 -printf "Fixing permissions ...\n" -chmod 1777 $tmp/tmp -chmod 4755 $tmp/bin/busybox - -printf "Installing GRUB bootloader ...\n" -mkdir -p $tmp/boot/grub -cat << EOF > $tmp/boot/grub/grub.cfg -set default=0 -set timeout=1 -terminal_output console -terminal_input console - -menuentry "GNU/Linux (OpenADK)" { - insmod ext2 - set root=(hd0,1) - linux /boot/vmlinuz-adk init=/init +case $ostype { +(DragonFly|*BSD*) + basedev=${tgt%c} + tgt=${basedev}c + part=${basedev}i + match=\'${basedev}\''[a-p]' + function mount_ext2fs { + mount -t ext2fs "$1" "$2" + } + ;; +(Darwin) + basedev=$tgt + part=${basedev}s1 + match=\'${basedev}\''?(s+([0-9]))' + function mount_ext2fs { + fuse-ext2 "$1" "$2" -o force + sleep 3 + } + ;; +(Linux) + basedev=$tgt + part=${basedev}1 + match=\'${basedev}\''+([0-9])' + function mount_ext2fs { + mount -t ext2 "$1" "$2" + } + ;; } -EOF -./bin/tools/sbin/grub-install \ - --grub-setup=./bin/tools/sbin/grub-setup \ - --grub-mkimage=./bin/tools/bin/grub-mkimage \ - --grub-mkdevicemap=./bin/tools/sbin/grub-mkdevicemap \ - --no-floppy --modules=ext2 --root-directory=$tmp $1 -umount $tmp -printf "Successfully installed.\n" -rm -rf $tmp + +mount | while read dev rest; do + [[ $dev = $match ]] || continue + print -u2 "Block device $tgt is in use, please umount first." + exit 1 +done + +if (( !quiet )); then + print "WARNING: This will overwrite $basedev - type Yes to continue!" + read x + [[ $x = Yes ]] || exit 0 +fi + +dksz=$(dkgetsz "$tgt") +heads=64 +secs=32 +(( cyls = dksz / heads / secs )) +if (( cyls < (cfgfs + 2) )); then + print -u2 "Size of $tgt is $dksz, this looks fishy?" + exit 1 +fi + +if stat --help >/dev/null 2>&1; then + statcmd='stat -c %s' # GNU stat +else + statcmd='stat -f %z' # BSD stat (or so we assume) +fi + +if ! T=$(mktemp -d /tmp/openadk.XXXXXXXXXX); then + print -u2 Error creating temporary directory. + exit 1 +fi +"$TOPDIR/scripts/tar" -xOzf "$src" ./usr/share/grub-bin/core.img >"$T/core.img" +integer coreimgsz=$($statcmd "$T/core.img") +if (( coreimgsz < 1024 )); then + print -u2 core.img is probably too small: $coreimgsz + rm -rf "$T" + exit 1 +fi +if (( coreimgsz > 65024 )); then + print -u2 core.img is larger than 64K-512: $coreimgsz + rm -rf "$T" + exit 1 +fi +(( coreendsec = (coreimgsz + 511) / 512 )) +# partition offset: at least coreendsec+1 but aligned on a multiple of secs +(( partofs = ((coreendsec / secs) + 1) * secs )) + +(( quiet )) || print Preparing MBR and GRUB2... +dd if=/dev/zero of="$T/firsttrack" count=$partofs 2>/dev/null +echo 1 $coreendsec | mksh "$TOPDIR/scripts/bootgrub.mksh" \ + -A -g $((cyls-cfgfs)):$heads:$secs -M 1:0x83 -O $partofs | \ + dd of="$T/firsttrack" conv=notrunc 2>/dev/null +dd if="$T/core.img" of="$T/firsttrack" conv=notrunc seek=1 2>/dev/null +# set partition where it can find /boot/grub +print -n '\0\0\0\0' | \ + dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x414)) 2>/dev/null + +# create cfgfs partition (mostly taken from bootgrub.mksh) +set -A thecode +typeset -Uui8 thecode +mbrpno=0 +set -A g_code $cyls $heads $secs +(( psz = g_code[0] * g_code[1] * g_code[2] )) +(( pofs = (cyls - cfgfs) * g_code[1] * g_code[2] )) +set -A o_code # g_code equivalent for partition offset +(( o_code[2] = pofs % g_code[2] + 1 )) +(( o_code[1] = pofs / g_code[2] )) +(( o_code[0] = o_code[1] / g_code[1] + 1 )) +(( o_code[1] = o_code[1] % g_code[1] + 1 )) +# boot flag; C/H/S offset +thecode[mbrpno++]=0x00 +(( thecode[mbrpno++] = o_code[1] - 1 )) +(( cylno = o_code[0] > 1024 ? 1023 : o_code[0] - 1 )) +(( thecode[mbrpno++] = o_code[2] | ((cylno & 0x0300) >> 2) )) +(( thecode[mbrpno++] = cylno & 0x00FF )) +# partition type; C/H/S end +(( thecode[mbrpno++] = 0x88 )) +(( thecode[mbrpno++] = g_code[1] - 1 )) +(( cylno = g_code[0] > 1024 ? 1023 : g_code[0] - 1 )) +(( thecode[mbrpno++] = g_code[2] | ((cylno & 0x0300) >> 2) )) +(( thecode[mbrpno++] = cylno & 0x00FF )) +# partition offset, size (LBA) +(( thecode[mbrpno++] = pofs & 0xFF )) +(( thecode[mbrpno++] = (pofs >> 8) & 0xFF )) +(( thecode[mbrpno++] = (pofs >> 16) & 0xFF )) +(( thecode[mbrpno++] = (pofs >> 24) & 0xFF )) +(( pssz = psz - pofs )) +(( thecode[mbrpno++] = pssz & 0xFF )) +(( thecode[mbrpno++] = (pssz >> 8) & 0xFF )) +(( thecode[mbrpno++] = (pssz >> 16) & 0xFF )) +(( thecode[mbrpno++] = (pssz >> 24) & 0xFF )) +# write partition table entry +ostr= +curptr=0 +while (( curptr < 16 )); do + ostr=$ostr\\0${thecode[curptr++]#8#} +done +print -n "$ostr" | \ + dd of="$T/firsttrack" conv=notrunc bs=1 seek=$((0x1CE)) 2>/dev/null + +(( quiet )) || print Writing MBR and GRUB2 to target device... +dd if="$T/firsttrack" of="$tgt" + +(( quiet )) || print "Creating ext2fs on ${part}..." +q= +(( quiet )) && q=-q +mke2fs $q "$part" +#partuuid=$(tune2fs -l /dev/sd0i | sed -n '/^Filesystem UUID:[ ]*/s///p') + +(( quiet )) || print Extracting installation archive... +mount_ext2fs "$part" "$T" +gzip -dc "$src" | (cd "$T"; tar -xpf -) +cd "$T" +rnddev=/dev/urandom +[[ -c /dev/arandom ]] && rnddev=/dev/arandom +dd if=$rnddev bs=16 count=1 >>etc/.rnd 2>/dev/null +(( quiet )) || print Fixing up permissions... +chown 0:0 tmp +chmod 1777 tmp +chmod 4755 bin/busybox +(( quiet )) || print Configuring GRUB2 bootloader... +mkdir -p boot/grub +( + print set default=0 + print set timeout=1 + if (( serial )); then + print serial --unit=0 --speed=$speed + print terminal_output serial + print terminal_input serial + consargs="console=ttyS0,$speed console=tty0" + else + print terminal_output console + print terminal_input console + consargs="console=tty0" + fi + print + print 'menuentry "GNU/Linux (OpenADK)" {' +# print "\tlinux /boot/vmlinuz-adk root=UUID=$partuuid $consargs panic=10" + print "\tlinux /boot/vmlinuz-adk $consargs panic=10" + print '}' +) >boot/grub/grub.cfg +set -A grubfiles +ngrubfiles=0 +for a in usr/lib/grub/*-pc/{*.mod,efiemu??.o,command.lst,moddep.lst,fs.lst,handler.lst,parttool.lst}; do + [[ -e $a ]] && grubfiles[ngrubfiles++]=$a +done +cp "${grubfiles[@]}" boot/grub/ +(( quiet )) || print Finishing up... +cd "$TOPDIR" +umount "$T" + +rm -rf "$T" exit 0 diff --git a/tools/adk/Makefile b/tools/adk/Makefile index 6d02b0d62..02171c99b 100644 --- a/tools/adk/Makefile +++ b/tools/adk/Makefile @@ -12,13 +12,10 @@ ${TOPDIR}/bin/tools/depmaker: $(TOPDIR)/bin/tools ${TOPDIR}/bin/tools/pkgrebuild: $(TOPDIR)/bin/tools $(HOSTCC) -o $(TOPDIR)/bin/tools/pkgrebuild pkgrebuild.c strmap.c -${TOPDIR}/bin/tools/pt: $(TOPDIR)/bin/tools - $(HOSTCC) -o $(TOPDIR)/bin/tools/pt pt.c - ${TOPDIR}/bin/tools/dkgetsz: ${TOPDIR}/bin/tools ${HOSTCC} -O2 -Wall -o $@ dkgetsz.c install: ${TOPDIR}/bin/tools/depmaker ${TOPDIR}/bin/tools/pkgrebuild \ - $(TOPDIR)/bin/tools/pt ${TOPDIR}/bin/tools/dkgetsz + ${TOPDIR}/bin/tools/dkgetsz include $(TOPDIR)/mk/tools.mk diff --git a/tools/adk/pt.c b/tools/adk/pt.c deleted file mode 100644 index 6f2e7ce25..000000000 --- a/tools/adk/pt.c +++ /dev/null @@ -1,243 +0,0 @@ -/* - * pt - partition table utility - * Copyright (C) 2010 by Waldemar Brodkorb - * - * just adds some required code to ptgen - partition table generator - * Copyright (C) 2006 by Felix Fietkau - * - * uses parts of afdisk - * Copyright (C) 2002 by David Roetzel - * - * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(__linux__) -#include -#endif - -#if defined(__APPLE__) -#include -#define BLKGETSIZE DKIOCGETBLOCKCOUNT -#endif - -/* Partition table entry */ -struct pte { - unsigned char active; - unsigned char chs_start[3]; - unsigned char type; - unsigned char chs_end[3]; - unsigned int start; - unsigned int length; -}; - -struct partinfo { - unsigned long size; - int type; -}; - -int verbose = 0; -int active = 1; -int heads = -1; -int sectors = -1; -struct partinfo parts[4]; -char *filename = NULL; - -/* - * get the sector size of the block device - * - * print the sector size - */ - -static void getmaxsize(char *device) { - int fd; - unsigned long maxsectors=0; - - fd = open(device, O_RDONLY); - ioctl(fd, BLKGETSIZE, &maxsectors); - printf("%lu\n", maxsectors); - close(fd); -} - -/* - * parse the size argument, which is either - * a simple number (K assumed) or - * K, M or G - * - * returns the size in KByte - */ -static long to_kbytes(const char *string) { - int exp = 0; - long result; - char *end; - - result = strtoul(string, &end, 0); - switch (tolower(*end)) { - case 'k' : - case '\0' : exp = 0; break; - case 'm' : exp = 1; break; - case 'g' : exp = 2; break; - default: return 0; - } - - if (*end) - end++; - - if (*end) { - fprintf(stderr, "garbage after end of number\n"); - return 0; - } - - /* result: number + 1024^(exp) */ - return result * ((2 << ((10 * exp) - 1)) ?: 1); -} - -/* convert the sector number into a CHS value for the partition table */ -static void to_chs(long sect, unsigned char chs[3]) { - int c,h,s; - - s = (sect % sectors) + 1; - sect = sect / sectors; - h = sect % heads; - sect = sect / heads; - c = sect; - - chs[0] = h; - chs[1] = s | ((c >> 2) & 0xC0); - chs[2] = c & 0xFF; - - return; -} - -/* round the sector number up to the next cylinder */ -static inline unsigned long round_to_cyl(long sect) { - int cyl_size = heads * sectors; - - return sect + cyl_size - (sect % cyl_size); -} - -/* check the partition sizes and write the partition table */ -static int gen_ptable(int nr) -{ - struct pte pte[4]; - unsigned long sect = 0; - unsigned int start, len; - int i, fd, ret = -1; - - memset(pte, 0, sizeof(struct pte) * 4); - for (i = 0; i < nr; i++) { - if (!parts[i].size) { - fprintf(stderr, "Invalid size in partition %d!\n", i); - return -1; - } - pte[i].active = ((i + 1) == active) ? 0x80 : 0; - pte[i].type = parts[i].type; - pte[i].start = start = sect + sectors; - sect = round_to_cyl(start + parts[i].size * 2); - pte[i].length = len = sect - start; - to_chs(start, pte[i].chs_start); - to_chs(start + len - 1, pte[i].chs_end); - if (verbose) - fprintf(stderr, "Partition %d: start=%u, end=%u, size=%u\n", i, start * 512, (start + len) * 512, len * 512); - } - - if ((fd = open(filename, O_WRONLY|O_CREAT|O_TRUNC, 0644)) < 0) { - fprintf(stderr, "Can't open output file '%s'\n",filename); - return -1; - } - - lseek(fd, 446, SEEK_SET); - if (write(fd, pte, sizeof(struct pte) * 4) != sizeof(struct pte) * 4) { - fprintf(stderr, "write failed.\n"); - goto fail; - } - lseek(fd, 510, SEEK_SET); - if (write(fd, "\x55\xaa", 2) != 2) { - fprintf(stderr, "write failed.\n"); - goto fail; - } - - ret = 0; -fail: - close(fd); - return ret; -} - -static void usage(char *prog) -{ - fprintf(stderr, "Usage: %s [-v] -h -s -o [-a 0..4] [[-t ] -p ...] \n", prog); - fprintf(stderr, "Usage: %s -g \n", prog); - exit(1); -} - -int main (int argc, char **argv) -{ - char type = 0x83; - int ch; - int part = 0; - - while ((ch = getopt(argc, argv, "h:s:p:a:t:o:vg:")) != -1) { - switch (ch) { - case 'o': - filename = optarg; - break; - case 'v': - verbose++; - break; - case 'h': - heads = (int) strtoul(optarg, NULL, 0); - break; - case 's': - sectors = (int) strtoul(optarg, NULL, 0); - break; - case 'p': - if (part > 3) { - fprintf(stderr, "Too many partitions\n"); - exit(1); - } - parts[part].size = to_kbytes(optarg); - parts[part++].type = type; - break; - case 't': - type = (char) strtoul(optarg, NULL, 16); - break; - case 'a': - active = (int) strtoul(optarg, NULL, 0); - if ((active < 0) || (active > 4)) - active = 0; - break; - case 'g': - getmaxsize(optarg); - exit(0); - case '?': - default: - usage(argv[0]); - } - } - argc -= optind; - if (argc || (heads <= 0) || (sectors <= 0) || !filename) - usage(argv[0]); - - return gen_ptable(part); -} -- cgit v1.2.3