Difference between revisions of "Archbootstrap"

From ArchWiki
Jump to: navigation, search
(Change the outdated script)
Line 1: Line 1:
 
[[Category:Boot process (English)]]
 
[[Category:Boot process (English)]]
  
This Bash script creates a base Arch Linux system where you can chroot to (it should work in any UNIX environment). Download the last version [http://tokland.googlecode.com/svn/trunk/archlinux/arch-bootstrap.sh here] (and report bugs [http://code.google.com/p/tokland/issues/list here]).
+
This Bash script creates a base Arch Linux system where you can chroot to. You should be able tu run it in any UNIX environment.
 +
 
 +
[http://tokland.googlecode.com/svn/trunk/archlinux/arch-bootstrap.sh Download] | [http://code.google.com/p/tokland/issues/list Report bugs]
  
 
<pre>
 
<pre>
Line 8: Line 10:
 
# arch-bootstrap: Bootstrap a base Arch Linux system.
 
# arch-bootstrap: Bootstrap a base Arch Linux system.
 
#
 
#
# Example:
+
# Depends: bash, coreutils, wget, sed, awk, tar, gzip, chroot
 +
# Author: Arnau Sanchez <tokland@gmail.com>
 +
# Report bugs to http://code.google.com/p/tokland/issues
 +
#
 +
# Some examples:
 
#
 
#
 
# $ bash arch-bootstrap.sh myarch x86_64
 
# $ bash arch-bootstrap.sh myarch x86_64
 +
# $ bash arch-bootstrap.sh myarch x86_64 "ftp://ftp.archlinux.org"
 +
# $ bash arch-bootstrap.sh myarch x86_64 "" "file_containing_core_os_index.html"
 
#  
 
#  
# Depends: wget, tar, gzip, chroot
+
# Packages list needed by pacman can be obtained this way:
# Author: Arnau Sanchez <tokland@gmail.com>
+
#
+
# Packages needed by pacman can be obtained that way:
+
 
#  
 
#  
 
# $ for PACKAGE in $(ldd /usr/bin/pacman | grep "=> /" | awk '{print $3}'); do  
 
# $ for PACKAGE in $(ldd /usr/bin/pacman | grep "=> /" | awk '{print $3}'); do  
Line 32: Line 37:
  
 
# Extract href attribute from HTML link
 
# Extract href attribute from HTML link
extract_href() { sed -n "s/^.*<a [^>]*href=\"\([^\"]*\)\".*$/\1/p"; }
+
extract_href() { sed -n '/<a / s/^.*<a [^>]*href="\([^\"]*\)".*$/\1/p'; }
  
 
# Simple wrapper around wget
 
# Simple wrapper around wget
Line 41: Line 46:
 
BASIC_PACKAGES=(acl attr bzip2 glibc libarchive libfetch openssl pacman  
 
BASIC_PACKAGES=(acl attr bzip2 glibc libarchive libfetch openssl pacman  
 
                 pacman-mirrorlist xz-utils zlib)
 
                 pacman-mirrorlist xz-utils zlib)
EXTRA_PACKAGES=(coreutils bash)
+
EXTRA_PACKAGES=(coreutils bash grep awk file tar filesystem)
 +
DEFAULT_REPO_URL="http://mirrors.kernel.org/archlinux"
 +
 
 +
configure_pacman() {
 +
  local DEST=$1; local ARCH=$2
 +
  cp "/etc/resolv.conf" "$DEST/etc/resolv.conf"
 +
  echo "Server = $REPO_URL/\$repo/os/$ARCH" >> "$DEST/etc/pacman.d/mirrorlist"
 +
}
 +
 
 +
minimal_configuration() {
 +
  local DEST=$1
 +
  echo "root:x:0:0:root:/root:/bin/bash" > "$DEST/etc/passwd"
 +
  echo "root:$1$GT9AUpJe$oXANVIjIzcnmOpY07iaGi/:14657::::::" > "$DEST/etc/shadow"
 +
  touch "$DEST/etc/group"
 +
  echo "bootstrap" > "$DEST/etc/hostname"
 +
  mkdir -p "$DEST/dev"
 +
  test -c "$DEST/dev/null" || mknod "$DEST/dev/null" c 1 3
 +
}
 +
 
 +
### Main
  
 
test $# -ge 2 || {  
 
test $# -ge 2 || {  
Line 49: Line 73:
 
    
 
    
 
DEST=$1
 
DEST=$1
ARCH=$2
+
ARCH=${2:-i686}
REPO_URL=${3:-"http://mirrors.kernel.org/archlinux"}
+
REPO_URL=${3:-$DEFAULT_REPO_URL}
LIST_HTML=$4
+
LIST_HTML_FILE=$4
  
 
REPO="${REPO_URL%/}/core/os/$ARCH"
 
REPO="${REPO_URL%/}/core/os/$ARCH"
debug "using core repository: $REPO"
+
debug "core repository: $REPO"
  
if test "$LIST_HTML"; then
+
# Get filename list for packages
   debug "using packages HTML index: $LIST_HTML"
+
if test "$LIST_HTML_FILE"; then
   LIST=$(extract_href < "$LIST_HTML")
+
   debug "packages HTML index: $LIST_HTML_FILE"
 +
   LIST_HTML=$(< "$LIST_HTML_FILE") ||
 +
    { debug "Error: packages list file not found: $LIST_HTML_FILE"; exit 1; }
 
else
 
else
   debug "fetching packages list: $REPO"
+
   debug "fetch packages list: $REPO/"
   # Force trailing '/' needed for FTPs server. Also, get only package relative paths
+
   # Force trailing '/' needed by FTP servers.
   LIST=$(fetch -O - "$REPO/" | extract_href | awk -F"/" '{print $NF}') ||
+
   LIST_HTML=$(fetch -O - "$REPO/") ||
     { debug "cannot fetch packages list: $REPO"; exit 1; }
+
     { debug "Error: cannot fetch packages list: $REPO"; exit 1; }
 
fi  
 
fi  
 +
LIST=$(echo "$LIST_HTML" | extract_href | awk -F"/" '{print $NF}' | sort -r -n)
  
debug "creating destination directory: $DEST"
+
debug "create destination directory: $DEST"
 
mkdir -p "$DEST"
 
mkdir -p "$DEST"
  
debug "fetching pacman and dependencies: ${BASIC_PACKAGES[*]}"
+
debug "pacman package and dependencies: ${BASIC_PACKAGES[*]}"
 
for PACKAGE in ${BASIC_PACKAGES[*]}; do
 
for PACKAGE in ${BASIC_PACKAGES[*]}; do
   FILE=$(echo "$LIST" | grep "^$PACKAGE-[[:digit:]]" | sort -n | tail -n1)
+
   FILE=$(echo "$LIST" | grep -m1 "^$PACKAGE-[[:digit:]]")
   test "$FILE" || { debug "cannot find package: $PACKAGE"; exit 1; }
+
   test "$FILE" || { debug "Error: cannot find package: $PACKAGE"; exit 1; }
   test -f "$FILE" && gunzip -t "$FILE" || {
+
   test -f "$FILE" && gunzip -q -t "$FILE" || {
     debug "downloading: $REPO/$FILE"
+
     debug "download: $REPO/$FILE"
 
     fetch "$REPO/$FILE"
 
     fetch "$REPO/$FILE"
 
   }
 
   }
   debug "uncompressing package: $FILE"
+
   debug "uncompress package: $FILE"
 
   tar xzf "$FILE" -C "$DEST"
 
   tar xzf "$FILE" -C "$DEST"
 
done
 
done
  
debug "doing minimal system configuration (DNS, passwd, hostname, mirrorlist)"  
+
debug "configure DNS and pacman"
cp "/etc/resolv.conf" "$DEST/etc/resolv.conf"
+
configure_pacman "$DEST" "$ARCH"
echo "root:x:0:0:root:/root:/bin/bash" > "$DEST/etc/passwd"
+
 
echo "bootstrap" > "$DEST/etc/hostname"
+
debug "clean re-install of basic packages and extra packages: ${BASICK_PACKAGES[*]}"
echo "Server = $REPO_URL/\$repo/os/$ARCH" >> "$DEST/etc/pacman.d/mirrorlist"
+
chroot "$DEST" /usr/bin/pacman --noconfirm -Syf ${BASIC_PACKAGES[*]} ${BASIC_PACKAGES[*]}
  
debug "installing extra packages: ${EXTRA_PACKAGES[*]}"
+
debug "minimal configuration (DNS, passwd, hostname, mirrorlist, ...)"  
chroot "$DEST" /usr/bin/pacman --noconfirm -Syf ${EXTRA_PACKAGES[*]}
+
configure_pacman "$DEST" "$ARCH"
 +
minimal_configuration "$DEST"
  
debug "done - you should now be able to use the system (i.e. chroot \"$DEST\")"
+
debug "done! you should now be able to use the system (i.e. chroot \"$DEST\")"
 
</pre>
 
</pre>

Revision as of 20:04, 17 February 2010


This Bash script creates a base Arch Linux system where you can chroot to. You should be able tu run it in any UNIX environment.

Download | Report bugs

#!/bin/bash
#
# arch-bootstrap: Bootstrap a base Arch Linux system.
#
# Depends: bash, coreutils, wget, sed, awk, tar, gzip, chroot
# Author: Arnau Sanchez <tokland@gmail.com>
# Report bugs to http://code.google.com/p/tokland/issues
#
# Some examples:
#
# $ bash arch-bootstrap.sh myarch x86_64
# $ bash arch-bootstrap.sh myarch x86_64 "ftp://ftp.archlinux.org"
# $ bash arch-bootstrap.sh myarch x86_64 "" "file_containing_core_os_index.html"
# 
# Packages list needed by pacman can be obtained this way:
# 
# $ for PACKAGE in $(ldd /usr/bin/pacman | grep "=> /" | awk '{print $3}'); do 
#     pacman -Qo $PACKAGE 
#   done | awk '{print $5}' | sort -u | xargs
#
set -e

### Generic functions

# Output to standard error
stderr() { echo "$@" >&2; }

# Output debug message to standard error
debug() { stderr "--- $@"; }

# Extract href attribute from HTML link
extract_href() { sed -n '/<a / s/^.*<a [^>]*href="\([^\"]*\)".*$/\1/p'; }

# Simple wrapper around wget
fetch() { wget -c --passive-ftp --quiet "$@"; }

### Main

BASIC_PACKAGES=(acl attr bzip2 glibc libarchive libfetch openssl pacman 
                pacman-mirrorlist xz-utils zlib)
EXTRA_PACKAGES=(coreutils bash grep awk file tar filesystem)
DEFAULT_REPO_URL="http://mirrors.kernel.org/archlinux"

configure_pacman() {
  local DEST=$1; local ARCH=$2
  cp "/etc/resolv.conf" "$DEST/etc/resolv.conf"
  echo "Server = $REPO_URL/\$repo/os/$ARCH" >> "$DEST/etc/pacman.d/mirrorlist"
}

minimal_configuration() {
  local DEST=$1
  echo "root:x:0:0:root:/root:/bin/bash" > "$DEST/etc/passwd"
  echo "root:$1$GT9AUpJe$oXANVIjIzcnmOpY07iaGi/:14657::::::" > "$DEST/etc/shadow"
  touch "$DEST/etc/group"
  echo "bootstrap" > "$DEST/etc/hostname"
  mkdir -p "$DEST/dev"
  test -c "$DEST/dev/null" || mknod "$DEST/dev/null" c 1 3
}

### Main

test $# -ge 2 || { 
  stderr "Usage: $(basename "$0") DESTDIR i686|x86_64 [REPO_URL] [CORE_OS_HTMLFILE]"
  exit 2
}
   
DEST=$1
ARCH=${2:-i686}
REPO_URL=${3:-$DEFAULT_REPO_URL}
LIST_HTML_FILE=$4

REPO="${REPO_URL%/}/core/os/$ARCH"
debug "core repository: $REPO"

# Get filename list for packages
if test "$LIST_HTML_FILE"; then
  debug "packages HTML index: $LIST_HTML_FILE"
  LIST_HTML=$(< "$LIST_HTML_FILE") ||
    { debug "Error: packages list file not found: $LIST_HTML_FILE"; exit 1; }
else
  debug "fetch packages list: $REPO/"
  # Force trailing '/' needed by FTP servers.
  LIST_HTML=$(fetch -O - "$REPO/") ||
    { debug "Error: cannot fetch packages list: $REPO"; exit 1; }
fi 
LIST=$(echo "$LIST_HTML" | extract_href | awk -F"/" '{print $NF}' | sort -r -n) 

debug "create destination directory: $DEST"
mkdir -p "$DEST"

debug "pacman package and dependencies: ${BASIC_PACKAGES[*]}"
for PACKAGE in ${BASIC_PACKAGES[*]}; do
  FILE=$(echo "$LIST" | grep -m1 "^$PACKAGE-[[:digit:]]")
  test "$FILE" || { debug "Error: cannot find package: $PACKAGE"; exit 1; }
  test -f "$FILE" && gunzip -q -t "$FILE" || {
    debug "download: $REPO/$FILE"
    fetch "$REPO/$FILE"
  }
  debug "uncompress package: $FILE"
  tar xzf "$FILE" -C "$DEST"
done

debug "configure DNS and pacman"
configure_pacman "$DEST" "$ARCH"

debug "clean re-install of basic packages and extra packages: ${BASICK_PACKAGES[*]}"
chroot "$DEST" /usr/bin/pacman --noconfirm -Syf ${BASIC_PACKAGES[*]} ${BASIC_PACKAGES[*]}

debug "minimal configuration (DNS, passwd, hostname, mirrorlist, ...)" 
configure_pacman "$DEST" "$ARCH"
minimal_configuration "$DEST"

debug "done! you should now be able to use the system (i.e. chroot \"$DEST\")"