home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2006 March / PCWELT_3_2006.ISO / tools / liblinuxlive < prev    next >
Encoding:
Neil Brown's ash script  |  2005-07-18  |  11.8 KB  |  425 lines

  1. #!/bin/ash
  2.  
  3. # Functions library :: for Linux Live scripts 5.x.y
  4. # Author: Tomas M. <http://www.linux-live.org>
  5. #
  6.  
  7. # ===========================================================
  8. # user interface functions
  9. # ===========================================================
  10.  
  11. # echolog
  12. # $1 = text to show and to write to /var/log/messages
  13. #
  14. echolog()
  15. {
  16.    echo "LIVECD:" "$@" >>/var/log/livedbg
  17.    echo "$@"
  18. }
  19.  
  20. # debug
  21. # commands executed when debug boot parameter is present
  22. #
  23. debug()
  24. {
  25.    echo
  26.    echo "====="
  27.    echo ": Debugging started. Here is the root shell for you."
  28.    echo ": Type your desired command or hit Ctrl+D to continue booting."
  29.    echo
  30.    ash
  31. }
  32.  
  33. # header
  34. # $1 = text to show
  35. #
  36. header()
  37. {
  38.    echolog "$1"
  39. }
  40.  
  41. fatal()
  42. {
  43.    header "Fatal error occured - $1"
  44.    echolog "Something went wrong and we can't continue booting :("
  45.    echolog "You may explore the system by using simple commands like ls, lsmod, mount, etc."
  46.    echolog "You may also try to hit Ctrl+D. Booting will continue. Use at your own risk."
  47.    echolog "To be safe, hit Ctrl+Alt+Delete to reboot."
  48.    echolog
  49.    ash
  50. }
  51.  
  52. allow_only_root()
  53. {
  54.   # test if the script is started by root user. If not, exit
  55.   if [ "0$UID" -ne 0 ]; then
  56.      echo "Only root can run `basename $0`"; exit 1
  57.   fi
  58. }
  59.  
  60. # ===========================================================
  61. # text processing functions
  62. # ===========================================================
  63.  
  64. # egrep_o is a replacement for "egrep -o". It prints only the last
  65. # matching text
  66. # $1 = regular expression
  67. #
  68. egrep_o()
  69. {
  70.    cat | egrep "$1" | sed -r "s/.*($1).*/\\1/"
  71. }
  72.  
  73. # look into cmdline and echo $1 back if $1 is set
  74. # $1 = value name, case sensitive, for example livecd_subdir
  75. # $2 = file to use instead /proc/cmdline, optional
  76. #
  77. cmdline_parameter()
  78. {
  79.    CMDLINE=/proc/cmdline
  80.    if [ "$2" != "" ]; then CMDLINE="$2"; fi
  81.    cat "$CMDLINE" | egrep_o "(^|[[:space:]]+)$1(\$|=|[[:space:]]+)" | egrep_o "$1"
  82. }
  83.  
  84. # look into cmdline and echo value of $1 option
  85. # $1 = value name, case sensitive, for example livecd_subdir
  86. # $2 = file to use instead /proc/cmdline, optional
  87. #
  88. cmdline_value()
  89. {
  90.    CMDLINE=/proc/cmdline
  91.    if [ "$2" != "" ]; then CMDLINE="$2"; fi
  92.    cat "$CMDLINE" | egrep_o "(^|[[:space:]]+)$1=([^[:space:]]+)" | egrep_o "=.*" | cut -b 2- | tail -n 1
  93. }
  94.  
  95. # ===========================================================
  96. # system functions
  97. # ===========================================================
  98.  
  99. # modprobe module $1, including all dependencies, suppress all messages
  100. # (own function because modprobe in busybox doesn't work with gzipped modules)
  101. # $1 = module name, eg. ehci-hcd
  102. # $2 = optional argument
  103. #
  104. modprobe_module()
  105. {
  106.   if [ "$1" = "" ]; then return 1; fi
  107.   PRINTK=`cat /proc/sys/kernel/printk`
  108.   echo "0" >/proc/sys/kernel/printk
  109.  
  110.   KERNEL="`uname -r`"; LSMOD=/tmp/_lsmod
  111.   MODULEDEPS="`cat /lib/modules/$KERNEL/modules.dep | egrep \"$1\\.ko(\\.gz)?:\"`"
  112.  
  113.   for MODULE in `echo $MODULEDEPS | cut -d ":" -f 2-` `echo $MODULEDEPS | cut -d ":" -f 1`; do
  114.      TMPMOD="/tmp/`basename $MODULE .gz`";
  115.      # if the module is not loaded already
  116.      if [ "`cat $LSMOD 2>/dev/null | egrep \"^$TMPMOD\\\$\"`" = "" ]; then
  117.         gunzip -c $MODULE 2>/dev/null >$TMPMOD
  118.         if [ "$?" -ne 0 ]; then cp $MODULE $TMPMOD; fi # can't gunzip? copy
  119.         insmod $TMPMOD $2 >/dev/null 2>/dev/null; err=$?
  120.         if [ "$err" -eq 0 ]; then echo $TMPMOD >>$LSMOD; fi # module log
  121.         rm $TMPMOD
  122.      fi
  123.   done
  124.  
  125.   echo "$PRINTK" >/proc/sys/kernel/printk
  126.   if [ "$err" -ne 0 ]; then echolog "error inserting module $1 ($err)"; fi
  127.   return $err
  128. }
  129.  
  130. # Mount device $1 to $2
  131. # $1 = /dev device to mount, eg. /dev/hda1
  132. # $2 = mountpoint, eg. /mnt/hda1
  133. # $3 = mount options, for example "loop", "ro", or "remount,rw"
  134. #
  135. mount_device()
  136. {
  137.   mkdir -p $2
  138.   if [ "$3" != "" ]; then OPTIONS="-o $3"; else OPTIONS=""; fi
  139.  
  140.   PRINTK=`cat /proc/sys/kernel/printk`
  141.   echo "0" >/proc/sys/kernel/printk
  142.  
  143.   mount -t auto $1 $2 $OPTIONS >/dev/null 2>/dev/null
  144.   err=$?
  145.  
  146.   if [ "$err" -ne 0 ]; then rmdir $2 2>/dev/null; fi
  147.   echo "$PRINTK" >/proc/sys/kernel/printk
  148.   return $err
  149. }
  150.  
  151. # ===========================================================
  152. # live module functions
  153. # ===========================================================
  154.  
  155. # Create module
  156. # call mksquashfs with apropriate arguments
  157. # $1 = directory which will be compressed to squashfs module
  158. # $2 = output .mo file
  159. # $3 = optional -keep-as-directory argument
  160. #
  161. create_module()
  162. {
  163.    mksquashfs "$1" "$2" $3 >/dev/null
  164.    if [ $? -ne 0 ]; then return 1; fi
  165.    chmod oga-x "$2" # remove execute attrib
  166. }
  167.  
  168. # Mount .mo module to destination directory
  169. # $1 = path to .mo livecd compressed module
  170. # $2 = destination folder
  171. #
  172. mount_module()
  173. {
  174.    mount -t squashfs -o loop,ro "$1" "$2"
  175.    echo "$1 $2" >>/tmp/_mounts
  176. }
  177.  
  178. # Insert a directory tree $2 to an union specified by $1
  179. # Top-level read-write branch is specified by it's index 0
  180. # $1 = union absolute path (starting with /)
  181. # $2 = path to data directory
  182. #
  183. union_insert_dir()
  184. {
  185.    unionctl "$1" --add --after 0 --mode ro "$2"
  186. }
  187.  
  188. # List all modules in all directories (base, modules, optional)
  189. # and filter out unneeded optional modules (not specified by load= kernel parameter)
  190. # $1 = root directory of mounted DATAdir
  191. #
  192. list_modules()
  193. {
  194.    LOAD="`cmdline_value load`"
  195.    ls -A1d $1/*.mo $1/*/*.mo 2>/dev/null | while read LINE; do
  196.       MODNAME="`basename $LINE .mo`"
  197.       if [ "$LOAD" != "*" -a "`echo $LINE | grep optional`" != "" -a "`echo $LOAD | egrep \"(^|,)$MODNAME(\\\$|,)\"`" = "" ]; then continue
  198.         else echo $LINE; fi
  199.    done
  200. }
  201.  
  202. # Insert one single .mo module to the union
  203. # $1 = union absolute path (starting with /)
  204. # $2 = module.mo full path
  205. # $3 = destination folder, where images will be mounted to
  206. #
  207. union_insert_module()
  208. {
  209.    TARGET="$3/`basename $2`"
  210.    while [ -e $TARGET ]; do TARGET=$TARGET.X; done
  211.    mkdir -p $TARGET
  212.    mount_module $2 $TARGET
  213.    if [ $? -ne 0 ]; then echo "can't read module data. corrupted download?" >&2; return 1; fi
  214.    union_insert_dir $1 $TARGET
  215.    if [ $? -ne 0 ]; then echo "can't insert module to union" >&2; return 1; fi
  216.    basename $TARGET
  217. }
  218.  
  219. # Insert all .mo modules, in $2 directory and subdirectories, to the union
  220. # $1 = union absolute path (starting with /)
  221. # $2 = LiveCD data dir (with directories /base, /modules, etc.)
  222. # $3 = destination folder, where images will be mounted to
  223. #
  224. union_insert_modules()
  225. {
  226.    list_modules $2 | while read MODULE; do
  227.       echo -n " -> "
  228.       union_insert_module $1 $MODULE $3
  229.    done
  230. }
  231.  
  232. # Copy modules to RAM directory
  233. # $1 = data directory
  234. # $2 = target directory in RAM
  235. #
  236. copy_to_ram()
  237. {
  238.    cp -R $1/* $2
  239.    if [ "$?" -ne 0 ]; then fatal "can't copy to RAM, not enough memory?"; fi
  240. }
  241.  
  242. # Copy content of "rootcopy" directory on the CD to $2 (union, usually)
  243. # $1 = source
  244. # $2 = destination
  245. #
  246. copy_rootchanges()
  247. {
  248.    cp -a $1/rootcopy/* $2 2>/dev/null # could be empty
  249. }
  250.  
  251. # ===========================================================
  252. # discovery functions
  253. # ===========================================================
  254.  
  255. # List all CD-ROMs
  256. # by using /proc entries
  257. #
  258. list_cdrom_devices()
  259. {
  260.    if [ "`cmdline_parameter nocd`" != "" ]; then return 1; fi
  261.    for CDDEVICE in `cat /proc/sys/dev/cdrom/info | head -n 3 | tail -n 1 | cut -d ":" -f 2`; do
  262.       echo "/dev/$CDDEVICE"
  263.    done
  264. }
  265.  
  266. # List all partition devices
  267. # take list of all partitions and output unique disks.
  268. # Return empty result when nohd parameter was given.
  269. #
  270. list_partition_devices()
  271. {
  272.    if [ "`cmdline_parameter nohd`" != "" ]; then return 1; fi
  273.    cat /proc/partitions | grep -v loop | sed -r "s/^[0-9[:space:]]+/\/dev\//" | grep /dev/
  274. }
  275.  
  276. # List all disk devices
  277. #
  278. list_disk_devices()
  279. {
  280.    list_partition_devices | egrep -v "[0-9]"
  281. }
  282.  
  283. # List all block devices
  284. #
  285. list_block_devices()
  286. {
  287.    list_cdrom_devices
  288.    list_partition_devices
  289. }
  290.  
  291. # Try to mount all disks, partitions and cdroms and Find where the LiveCD is.
  292. # If LiveCD found in the device, echo dirname of it's directory,
  293. # and leave the device mounted. Mounting is not ro, but without any argument.
  294. # $1 = directory where devices will be mounted
  295. #
  296. find_live_data_dir()
  297. {
  298.    list_block_devices | while read DEVICE; do
  299.       DIR="/$1/`basename $DEVICE`"
  300.       mount_device $DEVICE $DIR
  301.       if [ $? -ne 0 ]; then continue; fi
  302.       FOUND=`ls -A1d $DIR/livecd.sgn $DIR/*/livecd.sgn 2>/dev/null | head -n 1`
  303.       if [ "$FOUND" = "" ]; then umount $DIR 2>/dev/null; rmdir $DIR 2>/dev/null
  304.       else dirname "$FOUND"; return 1; fi
  305.    done
  306. }
  307.  
  308. # ===========================================================
  309. # hardware preparation functions
  310. # ===========================================================
  311.  
  312. # Create block devices to /dev described by /sys entries
  313. #
  314. create_block_devices()
  315. {
  316.    echolog "creating /dev entries for block devices"
  317.    ls -A1d /sys/block/*/dev /sys/block/*/*/dev 2>/dev/null | grep -v loop | while read BLOCK; do
  318.       DEVICE="/dev/`basename \`dirname $BLOCK\``"
  319.       if [ ! -b $DEVICE ]; then
  320.          MINORMAJOR="`head -n 1 $BLOCK | tr ':' ' '`"
  321.          mknod $DEVICE b $MINORMAJOR
  322.       fi
  323.    done
  324. }
  325.  
  326. # modprobe kernel modules needed for the LiveCD
  327. #
  328. modprobe_essential_modules()
  329. {
  330.    echolog "starting loop device support"
  331.    modprobe_module loop max_loop=255
  332.    echolog "starting cdrom filesystem support"
  333.    modprobe_module isofs
  334.    echolog "starting squashfs support"
  335.    modprobe_module squashfs
  336.    echolog "starting unionfs support"
  337.    modprobe_module unionfs
  338.    echolog "starting vfat support"
  339.    modprobe_module nls_cp437
  340.    modprobe_module nls_iso8859-1
  341.    modprobe_module nls_iso8859-2
  342.    modprobe_module vfat
  343.    echolog "starting ntfs support"
  344.    modprobe_module ntfs
  345.    create_block_devices
  346. }
  347.  
  348. # modprobe kernel modules needed for USB masstorage devices
  349. #
  350. modprobe_usb_modules()
  351. {
  352.    echolog "starting USB support"
  353.    modprobe_module ehci-hcd
  354.    modprobe_module ohci-hcd
  355.    modprobe_module uhci-hcd
  356.    modprobe_module usb-storage
  357.    create_block_devices
  358. }
  359.  
  360. # enable/disable CD autoejecting when unmounted
  361. # $1 = 1|0 ... enable|disable
  362. #
  363. cd_autoeject()
  364. {
  365.    echo $1 >/proc/sys/dev/cdrom/autoeject
  366. }
  367.  
  368. # Disable DMA if nodma boot parameter is present
  369. #
  370. setup_dma()
  371. {
  372.    if [ ! "`cmdline_parameter nodma`" = "" ]; then
  373.       for DEVICE in `list_cdrom_devices` `list_disk_devices`; do
  374.          echolog "setting DMA support off for $DEVICE"
  375.          hdparm -d 0 $DEVICE
  376.       done
  377.    fi
  378. }
  379.  
  380. # create correct fstab file in $1/etc/fstab and create apropriate
  381. # mount directories in $1
  382. # $1 = root directory (union)
  383. #
  384. activate_fstab()
  385. {
  386.    mkdir -p $1/etc
  387.    FSTAB="$1/etc/fstab"
  388.    echo "tmpfs            /                tmpfs       defaults         0   0" >$FSTAB
  389.    echo "devpts           /dev/pts         devpts      gid=5,mode=620   0   0" >>$FSTAB
  390.    echo "proc             /proc            proc        defaults         0   0" >>$FSTAB
  391.  
  392.    list_cdrom_devices | while read DEVICE; do
  393.       MOUNTDIR="/mnt/`basename $DEVICE`_cdrom"
  394.       mkdir -p $1/$MOUNTDIR
  395.       echo "$DEVICE $MOUNTDIR iso9660 noauto,users,exec 0 0" >>$FSTAB
  396.    done
  397.  
  398.    list_partition_devices | while read DEVICE; do
  399.       unset REMOVABLE; DEV="`basename $DEVICE`"; DEV0="`echo $DEV | cut -b 1-3`"
  400.       if [ "0`cat /sys/block/$DEV0/removable`" -ne 0 ]; then
  401.          REMOVABLE="_removable"
  402.       fi
  403.  
  404.       # skip this device if mountpoint exists
  405.       MOUNTDIR="/mnt/$DEV$REMOVABLE"
  406.       if [ -d "$1/$MOUNTDIR" ]; then continue; fi
  407.  
  408.       # try to mount the device and unmount it. If OK, we can add it to fstab
  409.       mount_device "$DEVICE" "$1/$MOUNTDIR"
  410.       FS="`cat /proc/mounts | grep $DEVICE | grep $MOUNTDIR | cut -d \" \" -f 3 | head -n 1`"
  411.       umount "$1/$MOUNTDIR" 2>/dev/null
  412.       if [ $? -eq 0 ]; then
  413.          echo "$DEVICE $MOUNTDIR $FS auto,users,suid,dev,exec 0 0" >>$FSTAB
  414.       else # remove empty directory
  415.          rmdir "$1/$MOUNTDIR" 2>/dev/null
  416.       fi
  417.    done
  418.  
  419.    fdisk -l 2>/dev/null | grep -i "Linux swap" | egrep "^/dev/" \
  420.      | cut -f 1 -d " " | sed -r "s/(.+)/\\1 swap swap defaults 0 0/" >>$FSTAB
  421.  
  422.    echo "/dev/fd0 /mnt/floppy auto noauto,users,suid,dev,exec 0 0" >>$FSTAB
  423.    mkdir -p $1/mnt/floppy
  424. }
  425.