Difference between revisions of "Archbootstrap"

From ArchWiki
Jump to: navigation, search
m
(Change the outdated script)
Line 1: Line 1:
 
[[Category:Boot process (English)]]
 
[[Category:Boot process (English)]]
{{out of date}}
 
You can simply install this script using this command:
 
<nowiki>target='/usr/bin/archbootstrap';
 
curl http://wiki.archlinux.org/index.php/Archbootstrap |
 
grep -A 99999 '<pre>' | grep -B 99999 '</pre>' |
 
sed -e 's/\(<pre>\|<\/pre>\)//g' > "$target"; chmod +x "$target";
 
</nowiki>
 
  
Or you can copypasta it from here:
+
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]).
<pre>#!/bin/bash
 
#########################################################################
 
# archbootstrap                                                        #
 
#                                                                      #
 
# archbootstrap is to archlinux what debootstrap is to Debian.         #
 
#                                                                      #
 
#                                                                      #
 
# archbootstrap is public domain though i wouldn't mind getting credit. #
 
#                                                                      #
 
# by David Leinhäuser (archlinux@calavera.de)                          #
 
# (minor tweak by lucke)                                               #
 
#########################################################################
 
  
 +
<pre>
 +
#!/bin/bash
 +
#
 +
# arch-bootstrap: Bootstrap a base Arch Linux system.
 +
#
 +
# Example:
 +
#
 +
# $ bash arch-bootstrap.sh myarch x86_64
 +
#
 +
# Depends: wget, tar, gzip, chroot
 +
# 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
 +
#    pacman -Qo $PACKAGE
 +
#  done | awk '{print $5}' | sort -u | xargs
 +
#
 +
set -e
  
####################
+
### Generic functions
# Default Settings #
 
####################
 
MYVERSION="0.3"                              # Version number of this script.
 
GETCMD="${GETCMD:-wget --passive-ftp -c -q}" # What we use to download files.
 
PREINSTALL="${PREINSTALL:-glibc iputils}"    # Packages to install before using
 
                                            # pacman to fetch the rest.
 
IGNORE="${IGNORE:-}"                        # Packages not to be installed.
 
TARGET="${1:---help}"                        # Where to bootstrap to
 
SERVER="${2:-ftp://ftp.archlinux.org}"      # Where to fetch all the files.
 
INTERACTIVE="${INTERACTIVE:-1}"              # Interactive mode or batch mode
 
  
REPOS="current"                              # Which repository to use.
+
# Output to standard error
PKG_PACMAN="setup/pacman.pkg.tar.gz"         # Where to find pacman.
+
stderr() { echo "$@" >&2; }
PKGLIST="setup/packages.txt"                # Where to find the packages list.
 
PKG_PREFIX="base"                            # Install pkgs with this prefix.
 
  
####################
+
# Output debug message to standard error
# Helper Functions #
+
debug() { stderr "--- $@"; }
####################
 
PREV_DIR="$(pwd)" # remember current directory so we can chdir back later.
 
  
# Print an error message to stderr and quit.
+
# Extract href attribute from HTML link
function error() {
+
extract_href() { sed -n "s/^.*<a [^>]*href=\"\([^\"]*\)\".*$/\1/p"; }
echo "Error: $*" >&2
 
cd "${PREV_DIR}"
 
exit 1;
 
}
 
 
 
# Simply exit the script.
 
function quit() {
 
cd "${PREV_DIR}"
 
exit 0;
 
}
 
 
 
# Wrapper around cd for lazy people like me.
 
function chngdir() {
 
cd "$@" || error "chdir failed."
 
}
 
  
#Wrapper around mkdir for lazy people like me.
+
# Simple wrapper around wget
function makedir() {
+
fetch() { wget -c --passive-ftp --quiet "$@"; }
mkdir -p "$@" || error "mkdir failed."
 
}
 
  
#Fetch given URLs into current dir.
+
### Main
function fetch() {
 
while [ -n "${1}" ]; do
 
if [ -z "${1##file://*}" ]; then
 
F="${1#file://}"
 
echo "Copying ${F}."
 
cp "${1#file://}" . || error "Error copying ${F}."
 
else
 
echo "Fetching ${1}."
 
${GETCMD} "${1}" || error "Error fetching ${1}."
 
fi
 
shift
 
done
 
}
 
  
#Read the package list
+
BASIC_PACKAGES=(acl attr bzip2 glibc libarchive libfetch openssl pacman
PACKAGES=()
+
                pacman-mirrorlist xz-utils zlib)
function read_pkglist() {
+
EXTRA_PACKAGES=(coreutils bash)
while read -s; do
 
PACKAGES=("${PACKAGES[@]}" "${REPLY}")
 
done <"${BOOTSTRAP}/${PKGLIST##*/}"
 
}
 
  
#Return 1 if the first argument does not equal any of the other arguments.
+
test $# -ge 2 || {  
function match() {
+
  stderr "Usage: $(basename "$0") DESTDIR i686|x86_64 [REPO_URL] [CORE_OS_HTMLFILE]"
PATTERN="${1}"
+
  exit 2
shift
 
while [ -n "${1}" ]; do
 
[ "${PATTERN}" == "${1}" ] && return 0
 
shift
 
done
 
return 1
 
 
}
 
}
 +
 
 +
DEST=$1
 +
ARCH=$2
 +
REPO_URL=${3:-"http://mirrors.kernel.org/archlinux"}
 +
LIST_HTML=$4
  
######################
+
REPO="${REPO_URL%/}/core/os/$ARCH"
# Sanity checks etc. #
+
debug "using core repository: $REPO"
######################
 
case "${TARGET}" in
 
--help|-h)
 
cat <<-EOT
 
Usage: $0 DIR [SERVER]
 
Bootstrap Archlinux into DIR (from SERVER).
 
EOT
 
quit;
 
;;
 
--version)
 
echo "archbootstrap ${MYVERSION}";
 
quit;
 
;;
 
esac
 
 
 
[ "$UID" == "0" ] || error "You need to be root."
 
 
 
# This is an easy way to get an useful absolute path.
 
chngdir "${TARGET}"
 
TARGET="$(pwd)"
 
 
 
#[ -n "$(ls)" ] && error "${1} is not empty."
 
 
 
# Create working directory.
 
TEMP="${TARGET}/tmp"
 
makedir -m 1777 -p "${TEMP}"
 
BOOTSTRAP="${TEMP}/bootstrap"
 
PKG_CACHE="${TARGET}/var/cache/pacman/pkg"
 
makedir -m 0755 -p "${BOOTSTRAP}" "${PKG_CACHE}"
 
chngdir "${BOOTSTRAP}"
 
 
 
########################################
 
# Stuff we need for our staged install #
 
########################################
 
STAGEFILE="${BOOTSTRAP}/stage"
 
function set_stage() {
 
echo "${1}" >"${STAGEFILE}"
 
STAGE="${1}"
 
}
 
  
if [ -e "${STAGEFILE}" ]; then
+
if test "$LIST_HTML"; then
STAGE="$(< "${STAGEFILE}")"
+
  debug "using packages HTML index: $LIST_HTML"
 +
  LIST=$(extract_href < "$LIST_HTML")
 
else
 
else
STAGE="start"
+
  debug "fetching packages list: $REPO"
fi
+
  # Force trailing '/' needed for FTPs server. Also, get only package relative paths
 +
  LIST=$(fetch -O - "$REPO/" | extract_href | awk -F"/" '{print $NF}') ||
 +
    { debug "cannot fetch packages list: $REPO"; exit 1; }
 +
fi  
  
##################
+
debug "creating destination directory: $DEST"
# pacman wrapper #
+
mkdir -p "$DEST"
##################
 
PACMAN=("$(which chroot)" "${TARGET}" "${BOOTSTRAP#${TARGET}}/usr/bin/pacman.static")
 
function add_pkgs() {
 
PKGS=()
 
while [ -n "${1}" ]; do
 
PKGS=("${PKGS[@]}" "${1#${TARGET}}")
 
shift
 
done
 
"${PACMAN[@]}" -A "${PKGS[@]}" || error "Could not add a package."
 
}
 
  
function sync_pkgs() {
+
debug "fetching pacman and dependencies: ${BASIC_PACKAGES[*]}"
if [ "${INTERACTIVE}" == "1" ]; then
+
for PACKAGE in ${BASIC_PACKAGES[*]}; do
"${PACMAN[@]}" -Syf "${@}" || error "Could not sync a package."
+
  FILE=$(echo "$LIST" | grep "^$PACKAGE-[[:digit:]]" | sort -n | tail -n1)
else
+
  test "$FILE" || { debug "cannot find package: $PACKAGE"; exit 1; }
echo y | "${PACMAN[@]}" -Syf "${@}" || \
+
  test -f "$FILE" && gunzip -t "$FILE" || {
error "Could not sync a package."
+
    debug "downloading: $REPO/$FILE"
fi
+
    fetch "$REPO/$FILE"
}
+
  }
 +
  debug "uncompressing package: $FILE"
 +
  tar xzf "$FILE" -C "$DEST"
 +
done
  
#############
+
debug "doing minimal system configuration (DNS, passwd, hostname, mirrorlist)"
# Main loop #
+
cp "/etc/resolv.conf" "$DEST/etc/resolv.conf"
#############
+
echo "root:x:0:0:root:/root:/bin/bash" > "$DEST/etc/passwd"
PREV_STAGE=""
+
echo "bootstrap" > "$DEST/etc/hostname"
FURL="${SERVER}/${REPOS}/os/i686"
+
echo "Server = $REPO_URL/\$repo/os/$ARCH" >> "$DEST/etc/pacman.d/mirrorlist"
  
echo "archbootstrap $MYVERSION"
+
debug "installing extra packages: ${EXTRA_PACKAGES[*]}"
 +
chroot "$DEST" /usr/bin/pacman --noconfirm -Syf ${EXTRA_PACKAGES[*]}
  
until [ "${PREV_STAGE}" == "${STAGE}" ]; do
+
debug "done - you should now be able to use the system (i.e. chroot \"$DEST\")"
PREV_STAGE="${STAGE}"
+
</pre>
case "${STAGE}" in
 
start)
 
chngdir "${BOOTSTRAP}"
 
fetch "${FURL}/${PKG_PACMAN}" "${FURL}/${PKGLIST}"
 
tar xfz ${PKG_PACMAN##*/} || \
 
error "Could not untar ${BOOTSTRAP}${PKG_PACMAN##*/}."
 
makedir "${TARGET}/etc"
 
{ echo "[${REPOS}]";
 
  echo "Server = ${FURL}"; } >"${TARGET}/etc/pacman.conf" || \
 
error "Could not create ${TARGET}/etc/pacman.conf."
 
cp -f "/etc/resolv.conf" "${TARGET}/etc/resolv.conf" || \
 
error "Could not copy /etc/resolv.conf."
 
set_stage "pre_packages"
 
;;
 
pre_packages)
 
chngdir "${PKG_CACHE}"
 
[ "${#PACKAGES[@]}" == "0" ] && read_pkglist;
 
for I in "${PACKAGES[@]}"; do
 
PKGPREFIX="${I%%/*}"
 
PKGFILE="${I##*/}"
 
PKGNAME="${PKGFILE%-*-*.pkg.tar.gz}"
 
if match "${PKGNAME}" ${PREINSTALL}; then
 
fetch "${FURL}/${PKGFILE}"
 
add_pkgs "${PKG_CACHE}/${PKGFILE}"
 
fi
 
done
 
set_stage "packages"
 
;;
 
packages)
 
chngdir "${BOOTSTRAP}"
 
PKGS=()
 
[ "${#PACKAGES[@]}" == "0" ] && read_pkglist;
 
for I in "${PACKAGES[@]}"; do
 
PKGPREFIX="${I%%/*}"
 
PKGFILE="${I##*/}"
 
PKGNAME="${PKGFILE%-*-*.pkg.tar.gz}"
 
[ "${PKGPREFIX}" == "${PKG_PREFIX}" ] || continue
 
match "${PKGNAME}" ${IGNORE} ${PREINSTALL} && continue
 
PKGS=("${PKGS[@]}" "${PKGNAME}")
 
done
 
sync_pkgs "${PKGS[@]}"
 
set_stage "cleanup"
 
;;
 
cleanup)
 
echo "Cleaning up..."
 
chngdir "${TARGET}"
 
rm -Rf "${BOOTSTRAP}" || error "Could not remove ${BOOTSTRAP}."
 
quit
 
;;
 
esac
 
done</pre>
 

Revision as of 22:10, 10 February 2010


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 here (and report bugs here).

#!/bin/bash
#
# arch-bootstrap: Bootstrap a base Arch Linux system.
#
# Example:
#
# $ bash arch-bootstrap.sh myarch x86_64
# 
# Depends: wget, tar, gzip, chroot
# 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 
#     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 "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)

test $# -ge 2 || { 
  stderr "Usage: $(basename "$0") DESTDIR i686|x86_64 [REPO_URL] [CORE_OS_HTMLFILE]"
  exit 2
}
   
DEST=$1
ARCH=$2
REPO_URL=${3:-"http://mirrors.kernel.org/archlinux"}
LIST_HTML=$4

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

if test "$LIST_HTML"; then
  debug "using packages HTML index: $LIST_HTML"
  LIST=$(extract_href < "$LIST_HTML")
else
  debug "fetching packages list: $REPO"
  # Force trailing '/' needed for FTPs server. Also, get only package relative paths
  LIST=$(fetch -O - "$REPO/" | extract_href | awk -F"/" '{print $NF}') ||
    { debug "cannot fetch packages list: $REPO"; exit 1; }
fi 

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

debug "fetching pacman and dependencies: ${BASIC_PACKAGES[*]}"
for PACKAGE in ${BASIC_PACKAGES[*]}; do
  FILE=$(echo "$LIST" | grep "^$PACKAGE-[[:digit:]]" | sort -n | tail -n1)
  test "$FILE" || { debug "cannot find package: $PACKAGE"; exit 1; }
  test -f "$FILE" && gunzip -t "$FILE" || {
    debug "downloading: $REPO/$FILE"
    fetch "$REPO/$FILE"
  }
  debug "uncompressing package: $FILE"
  tar xzf "$FILE" -C "$DEST"
done

debug "doing minimal system configuration (DNS, passwd, hostname, mirrorlist)" 
cp "/etc/resolv.conf" "$DEST/etc/resolv.conf"
echo "root:x:0:0:root:/root:/bin/bash" > "$DEST/etc/passwd"
echo "bootstrap" > "$DEST/etc/hostname"
echo "Server = $REPO_URL/\$repo/os/$ARCH" >> "$DEST/etc/pacman.d/mirrorlist"

debug "installing extra packages: ${EXTRA_PACKAGES[*]}"
chroot "$DEST" /usr/bin/pacman --noconfirm -Syf ${EXTRA_PACKAGES[*]}

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