#!/bin/bash ######################################################################################### # 本脚本属于 archlive 项目一部分 作者 Carbon Jiao (Email: carbonjiao alt gmail dot com) # 详情 http://archlive.googlecode.com http://archlive-pkg.googlecode.com # # 本工具可以在任何符合条件的linux系统上构建基于Arch GNU/Linux包管理系统pacman的live系统—— # 可以是桌面环境、专业服务器甚至是防火墙。mkarchlive给你充分定制机会。 # # mkarchlive 可以运行于符合如下条件的linux系统中: # A、目标镜像类型为iso时,宿主系统需要安装3.72以上版本的syslinux; # B、宿主系统需要安装如下常用软件: cdrkit(mkisofs) wget tar links shell # sed grep gawk module-init-tools(depmod) util-linux-ng(mount) findutils(find) # coreutils(ls, cut, tr, echo, rm, mkdir, cp, cat, chown, chmod, head, mknod, tee, touch, ln, md5sum) # # 支持i686 x86_64的目标系统创建, 理论上还支持mips,只要有对应软件仓 # (i686平台可以创建x86_64 Archlive, 反之亦准备完毕. # 制作iso镜像时,无论使用什么bootloader,宿主系统都需要syslinux中的isohybrid程序来产生iso的md5sum # # 支持全方位定制: 定制启动脚本、定制目标系统软件、定制软件仓、预配置文件。。。 ######################################################################################### # 2011-04-01 改变判断宿主系统是否存在命令的方式;统一 mirrorlist, pacman.conf # 2010-11-20 整合配置文件指定和参数判断 # 2010-11-19 细化软件清单内容 # 2010-11-16 加入单独制作overlay模块, 以便重复制作时,单独更新overlay内容(需要在配置文件夹中修改,在工作目录中直接修改会被覆盖) # 2010-06-11 将双模式嵌入到每个步骤, 同一在制作配置文件中或者参数 -A 来设置 # 2010-06-10 添加双模式制作(i686和x86_64同存在于一个iso或者img中) # 2010-02-20 添加功能:将devel独立出来(/usr/src等) # 2010-02-12 修改iso目录结构,使得使用UltraISO U+方式正确运行 # 2010-01-12 使用Busybox代替klibc 启动,简化掉基本模块 # 2009-11-25 更新说明相关, 减少岐义; 删除文件、文件夹罗列到删除清单 # 2009-10-15 加入覆盖制作过程中对软件组的判断 # 2009-09-22 修改目标系统内核版本判断方式,加快速度。普通用户可以使用 -h 来获取帮助 # 2009-09-14 加入检测宿主系统是否存在必须命令的判断 # 2009-09-07 独立hg repo, 使脚本独立运行 # 2009-09-04 优化更新。 # 2009-08-25 加入pacman.static 在非Arch环境下也可运行本脚本制作基于Arch GNU/Linux的Live系统。 # 2009-08-24 加入ARCH选项,在i686环境下可以制作x86_64的live系统,反之亦然。 # 2009-08-23 加入附加模块独立制作的支持,加入grub2的支持 # 2009-08-22 加入判断 archlive.conf的模块可以采用加#来去掉,简化更新创建archlive的步骤 # 2009-08-21 加入查找archlive.conf配置文件的文件夹层数限制 # 2009-08-13 检误,并智能化检测、判断制作配置文件archlive.conf # 2009-08-12 将是否采用overlay个性化定制目录设置放于archlive.conf中 # 2009-08-10 修改运行目录结构,并将模块压缩方式的选择放到配置文件中 # 2009-08-10 修改判断软件仓是否已经在pacman.conf中定义的判断方式 # APPNAME=$(basename "${0}") export cmdline=$@ time=5 # 消息提示风格, 默认 有颜色输出 export COLOR=y #START_DIR=$(pwd) START_DIR=. # 两种方式均可 . ${START_DIR}/lib/functions case "$cmdline" in *-h*) usage 1;; esac [ "$EUID" != "0" ] && (error "错误: 必须以root用户运行本制作脚本." && exit 1) start_notice check_host_aufs check_host_cmd host_isnot_arch export QUIET export FORCE export CONFIG_FILE export PROFILE_DIR export ARCH export arch export CPIOCONFIG export ZIP_MODE export CACHE export BOOT export CDNAME # 检测输入的参数 while getopts 'P:c:A:i:b:z:C:nfvh' arg; do case "${arg}" in c) cdname="${OPTARG}" ;; P) config_file="${OPTARG}" ;; A) arch1="${OPTARG}" ;; i) boot_kernel_config1="${OPTARG}" ;; b) boot="${OPTARG}" ;; z) zip_mode="${OPTARG}" ;; C) cache_dir="${OPTARG}" ;; f) FORCE="y" ;; v) QUIET="n" ;; h|?) usage 0 ;; *) error "无效参数 '${arg}'"; usage 1 ;; esac done shift $(($OPTIND - 1)) CMD_NAME="${1}" # 载入配置文件、配置相关参数 check_config # 检查命令有效性 case "${CMD_NAME}" in prepare) WORK_DIR="${2}";; solemodules) WORK_DIR="${2}";; install) WORK_DIR="${2}";; remount) WORK_DIR="${2}";; clean) WORK_DIR="${2}";; squash) WORK_DIR="${2}";; overlay) WORK_DIR="${2}";; bootimage) WORK_DIR="${2}";; img) WORK_DIR="${2}"; IMGNAME="${3}";; all) WORK_DIR="${2}"; IMGNAME="${3}";; *) error "无效命令 '${CMD_NAME}'"; usage 1 ;; esac case $cmdline in *-f*) FORCE="y";; esac # 实际需要的模块 (去掉#) MODULES=$(echo $MODULES | tr -s " " "\n" | grep -v "#") EXTRAMODULES=$(echo $EXTRAMODULES | tr -s " " "\n" | grep -v "#") #------------------------------------------------------------------- LIBS="${START_DIR}/lib/mkinitcpio/initcpio/liblinuxlive" MKINITCPIO="${START_DIR}/lib/mkinitcpio" PACMAN_STATIC="${START_DIR}/lib/bin/pacman.static" #------------------------------------------------------------------- # 如果archlive.conf没有定义则采用如下默认配置 # 包含内核的模块, 如果archlive.conf中没有定义则默认为list中的第一个 if [ "x${KERNEL_MOD}" = "x" ]; then KERNEL_MOD="$(ls -1 ${PROFILE_DIR}/$LISTDIR | head -1)" fi if [ "x$QUIET" = "x" ]; then QUIET="y"; fi if [ "x$FORCE" = "x" ]; then FORCE="y"; fi if [ "x$CDNAME" = "x" ]; then CDNAME="archlive"; fi if [ "x$CACHE" = "x" ]; then if [ -f /etc/pacman.conf ]; then CACHE="$(grep "^CacheDir" /etc/pacman.conf | awk -F '=' '{print $2}')" else plain "系统不存在pacman.conf,宿主系统不是Arch, 将创建软件包缓存位置/var/cache/pacman/pkg" CACHE="/var/cache/pacman/pkg" fi fi [ -d ${CACHE} ] || mkdir -p ${CACHE} if [ "x$PUBLISHER" = "x" ]; then PUBLISHER="http://archlive.googlecode.com/"; fi if [ "x$AUTHOR" = "x" ]; then AUTHOR="Carbon Jiao"; fi # 检测模块压缩模式 case ${ZIP_MODE} in 1) MKSQUASHFS="${START_DIR}/lib/bin/mksquashfs4" EXT="sqfs" OPTION="-nolzma" ;; 2) MKSQUASHFS="${START_DIR}/lib/bin/mksquashfs4" EXT="lzm" OPTION="lzma" ;; *) MKSQUASHFS="${START_DIR}/lib/bin/mksquashfs4" EXT="sqfs" OPTION="" ;; esac # 目标系统是否支持必须的文件系统:aufs squashfs if [ "${KERNEL_KEY_FS_INCLUDED}" = "y" ]; then SUPPORT_ESSENTIAL_MODULES="y" else SUPPORT_ESSENTIAL_MODULES="n" fi case $IMG_TYPE in iso*) IMG_TYPE="iso" ;; img*) IMG_TYPE="iso"; warn "目前均mkisofs来创建为iso启动格式,可以采用dd或者UltraISO写到U盘" ;; disk*) IMG_TYPE="iso"; warn "目前均mkisofs来创建为iso启动格式,可以采用dd或者UltraISO写到U盘" ;; cd*) IMG_TYPE="iso" ;; *) IMG_TYPE="iso"; warn "无效的目标类型,采用默认的iso";; esac if [ "x${WORK_DIR}" = "x" ]; then # plain "命令行没有指定工作目录,查看配置文件中是否有设置的工作目录" WORK_DIR=$(grep "WORK_DIR=" ${CONFIG_FILE} | cut -d "=" -f2) if [ "x${WORK_DIR}" = "x" ]; then WORK_DIR="/Archlive_working_dir" #warn "配置文件也没有指定工作目录,采用默认设置${WORK_DIR}" fi fi WORK_DIR=${WORK_DIR%/} if [ "x${IMGNAME}" = "x" ]; then IMGNAME="${WORK_DIR}/archlive-${arch}-$(date +%F).${IMG_TYPE}" elif [ "$(basename ${IMGNAME})" = "${IMGNAME}" ]; then IMGNAME="${WORK_DIR}/${IMGNAME}" fi ###---------------------------程序运行相关目录设置-------------------------------- # 制作的Archlive镜像目录(该文件夹下所有内容全部包含于目标镜像) IMGROOT="${WORK_DIR}/${arch}-img" # 制作Archlive的aufs文件系统挂载点 UNION="${WORK_DIR}/union" # 模块软件清单(包含版本信息)目录 PACKLIST="${WORK_DIR}/${arch}-list" # .new 存放目前对应模块最新软件清单(需要安装的) # .old 存放运行本脚本前对应模块的软件清单 # .list 存放对应模块更新详情 # mod_模块.new 为最终 对应模块的实际软件清单 # 模块安装日志存放目录 BUILDLOG="${WORK_DIR}/${arch}-log" # 该目录下 # -errors.log 为对应模块安装错误日志 # 附加独立程序模块EXTRAMODULES的存放位置(sqfs或者lzm模块) EXTRA_MODULES_TARGET="${IMGROOT}/${CDNAME}/modules/extra_modules" # 不需要的模块备份位置 NO_NEED_MODULES_DIR="${WORK_DIR}/${NO_NEED_MODULES}" # archlive.conf 中定义的 EXTRAPACKAGEDIR 的存放位置 EXTRA_PACKAGE_TARGET="${IMGROOT}/${CDNAME}/modules/extra_package" # 需要特别初始化的配置 function init_config () { # 装载archlive软件仓等相关配置 PACMANCONF="${WORK_DIR}/pacman_${ARCH}.conf" # 清单文件夹 LISTDIR=list-${ARCH} # Arch软件仓数据库存放位置 SYNC="${WORK_DIR}/$ARCH-sync" # 更新安装时候的软件缓存位置 [ -f $PACMANCONF ] && sed -i "s%.*CacheDir.*%CacheDir = $CACHE%g" $PACMANCONF #archlive最终软件清单 PKGFILE="${WORK_DIR}/$ARCH-packages.list" # 制作的Archlive的模块实际存放目录(安装的实际位置) MODULEDIR="${WORK_DIR}/${ARCH}-modules" # archlive.conf中定义的EXTRAMODULES的安装位置 EXTRA_MODULES_INS_DIR="${MODULEDIR}/extra_modules" # 内核模块的安装位置 比如 ${WORK_DIR}/modules/0_000_core 制作启动内核镜像需要此变量 INSTROOT="${MODULEDIR}/$(basename ${KERNEL_MOD} .list)" # 附加模块清单(最终,包含版本信息) EXTRA_MODULE_LIST=${PACKLIST}/${ARCH}-extra_module.list # 将宿主系统可用执行程序排序输出到工作目录下 [ -d ${PACKLIST} ] && sort /tmp/cmd_list > "${PACKLIST}/host_cmd_list" # 安装清理删除的文件、目录的备份目录 CLEANED_BACKUP_DIR="${WORK_DIR}/${ARCH}-Cleaned_files_backup" } sleep $time init_config # 列出任务描述 case "${CMD_NAME}" in prepare) DESCRIPTION="准备工作: 准备安装程序,准备镜像目录结构,Overlay目录等.";; solemodules) DESCRIPTION="在工作目录 ${WORK_DIR} 下制作独立程序模块:安装后用 mksquash 压缩." ;; install) DESCRIPTION="将程序清单或者附加模块指定的程序安装到工作目录${UNION},放置于${MODULEDIR}." ;; clean) DESCRIPTION="根据配置文件清理 ${MODULEDIR},删除或者移动运行时无需的文件." ;; remount) DESCRIPTION="将之前制作的模块文件夹重新可写挂载到$UNION." ;; squash) DESCRIPTION="将 ${MODULEDIR} 目录用 mksquash 压缩为模块." ;; overlay) DESCRIPTION="准备Overlay目录到 ${WORK_DIR}下,并用 mksquash 压缩为模块." ;; bootimage) DESCRIPTION="从指定目录 ${MODULEDIR}/${KERNEL_MOD} 制作 $CDNAME 启动内核" ;; img) DESCRIPTION="将目录 ${IMGROOT} 制作为 ${IMG_TYPE} 镜像." ;; all) DESCRIPTION="根据配置文件或者参数指定的设置制作${IMGNAME/*\//}" ;; esac #------------------------------------------------------------------- echo "" green " 输入的选项及命令: $cmdline" green " 执行的动作: ${DESCRIPTION}" echo "" "-----------------------------------------------------------------------------" hgreen " *** ${APPNAME} 程序设置结果: ***" echo "" echo " 宿主系统是否是Arch GNU/Linux: ${ARCH_HOST} " echo " ${APPNAME}程序执行操作: ${CMD_NAME}" echo " Archlive定制配置文件: ${CONFIG_FILE}" echo " Archlive配置文件夹: ${PROFILE_DIR}" if [ "$arch" = "dul" ]; then echo " 目标系统: 双模式(i686 + x86_64)" else echo " 目标系统: ${arch}" fi echo " 工作目录: ${WORK_DIR}" if [ "${CMD_NAME}" = "prepare" -o "${CMD_NAME}" = "install" -o "${CMD_NAME}" = "all" ]; then echo " 目标镜像源文件存放目录: ${IMGROOT} " fi if [ "${CMD_NAME}" = "install" -o "${CMD_NAME}" = "all" ]; then echo " 软件包缓存目录: ${CACHE} " fi if [ "$arch" != "dul" ]; then echo " pacman.conf文件: ${PACMANCONF}" fi if [ "${CMD_NAME}" = "img" -o "${CMD_NAME}" = "all" ]; then echo " 目标镜像类型: ${IMG_TYPE}" echo " 目标镜像名: ${IMGNAME}" echo " 启动程序: ${BOOT}" fi if [ "${CMD_NAME}" = "squash" -o "${CMD_NAME}" = "solemodules" -o "${CMD_NAME}" = "all" ]; then echo " 模块类型: ${EXT}" fi if [ "${CMD_NAME}" = "bootimage" -o "${CMD_NAME}" = "all" ]; then echo " Archlive启动内核镜像配置文件: ${CPIOCONFIG}" fi if [ "${CMD_NAME}" = "bootimage" -o "${CMD_NAME}" = "all" ]; then echo " 包含内核程序的模块: ${KERNEL_MOD}" fi if [ "${CMD_NAME}" = "install" -o "${CMD_NAME}" = "all" ]; then echo " 是否覆盖: ${FORCE}" fi if [ "${CMD_NAME}" = "install" -o "${CMD_NAME}" = "squash" -o "${CMD_NAME}" = "all" ]; then echo " 需要制作的模块为: $(echo ${MODULES} | tr -s "\n" " ")" fi if [ "${CMD_NAME}" = "install" -o "${CMD_NAME}" = "squash" -o "${CMD_NAME}" = "solemodules" -o "${CMD_NAME}" = "all" ]; then echo " 需要制作的附加独立程序模块为: $(echo ${EXTRAMODULES} | tr -s "\n" " ")" fi echo " 不显示制作详情: ${QUIET}" echo "" hgreen "***如果以上不是你想要的,Ctrl+C 终止程序的执行,并检测相关配置文件.***" echo -n " "; yellow "5 秒后开始程序" echo "-----------------------------------------------------------------------------" sleep $time echo "" function second_confirm () { echo "------------------------------ 目前工作状态 ----------------------------------" echo " ARCH: ${ARCH}" echo " pacman.conf文件: ${PACMANCONF}" hgreen "***如果以上不是你想要的,Ctrl+C 终止程序的执行,并检测相关配置文件.***" echo -n " "; yellow "5 秒后开始程序" echo "-----------------------------------------------------------------------------" sleep $time } msg "现在开始执行 ${APPNAME} ${CMD_NAME}" echo "" ###--------------------------------------主程序调用------------------------------------------------------ case ${CMD_NAME} in prepare) check_host_cmds find grep sed wget gettext openssl # gettext openssl 被create_repo需要 cmd_prepare ;; install) check_host_cmds awk diff depmod find grep sed chroot if [ "$arch" = "dul" ]; then export ARCH="i686"; init_config; second_confirm; cmd_install; export ARCH="x86_64"; init_config; second_confirm; cmd_install; else init_config; second_confirm; cmd_install; fi ;; clean) check_host_cmds find if [ "$arch" = "dul" ]; then export ARCH="i686"; init_config; second_confirm; cmd_clean; export ARCH="x86_64"; init_config; second_confirm; cmd_clean; else init_config; second_confirm; cmd_clean; fi ;; remount) check_host_cmds tee if [ "$arch" = "dul" ]; then error "重新挂载必须用 -A 来指定 i686 或者 x86_64" usage 1 else init_config; cmd_re_mount_all; fi ;; solemodules) check_host_cmds sed find grep depmod if [ "$arch" = "dul" ]; then export ARCH="i686"; init_config; second_confirm; prepare_pacman; cmd_extramodules_install; cmd_extramodules_squash; export ARCH="x86_64"; init_config; second_confirm; prepare_pacman; cmd_extramodules_install; cmd_extramodules_squash; else init_config; second_confirm; prepare_pacman; cmd_extramodules_install; cmd_extramodules_squash; fi ;; squash) check_host_cmds sed find depmod if [ "$arch" = "dul" ]; then export ARCH="i686"; init_config; second_confirm; cmd_squash; export ARCH="x86_64"; init_config; second_confirm; cmd_squash; else init_config; second_confirm; cmd_squash; fi ;; overlay) check_host_cmds find grep sed wget prepare_overlay; cmd_overlay_sqfs; ;; bootimage) check_host_cmds find grep sed cut depmod if [ "$arch" = "dul" ]; then export ARCH="i686"; init_config; second_confirm; cmd_boot_kernel_image; export ARCH="x86_64"; init_config; second_confirm; cmd_boot_kernel_image; else init_config; second_confirm; cmd_boot_kernel_image; fi ;; img) check_host_cmds mkisofs find isosize init_config; cmd_img; ;; all) check_host_cmds find grep sed wget gettext openssl awk mkisofs isosize diff depmod chroot cmd_prepare; if [ "$arch" = "dul" ]; then export ARCH="i686"; init_config; second_confirm; cmd_install; cmd_clean; cmd_squash; cmd_boot_kernel_image; export ARCH="x86_64"; init_config; second_confirm; cmd_install; cmd_clean; cmd_squash; cmd_boot_kernel_image; else init_config; second_confirm; cmd_install; cmd_clean; cmd_squash; cmd_boot_kernel_image; fi cmd_img; ;; *) error "错误的命令" && usage 1 ;; esac msg "程序执行 ${APPNAME} $cmdline 结束!"