slitaz-modular view initramfs/liblinuxlive @ rev 0

first release
author Christopher Rogers <slaxemulator@gmail.com>
date Thu Nov 25 03:30:16 2010 +0000 (2010-11-25)
parents
children d52e861c9970
line source
1 #!/bin/bash
3 # Functions library :: for Linux Live scripts 6
4 # Author: Tomas M. <http://www.linux-live.org>
5 #
7 # ===========================================================
8 # GLOBAL variables
9 # ===========================================================
11 # linux live flag to fstab, if fstab line doesn't contain it,
12 # never remove it from fstab automatically (user added it)
13 FSTABLLFLAG="# AutoUpdate"
15 # We have to set these variables very carefully
16 UNION=union
17 MEMORY=memory
18 MOUNTDIR=mnt
19 CHANGES=$MEMORY/changes
20 XINO=$MEMORY/xino
21 COPY2RAM=$MEMORY/copy2ram
22 IMAGES=$MEMORY/images
23 INITRAMDISK=$MOUNTDIR/live
24 LOOPMOUNT=$MOUNTDIR/tmp
25 FINDISOMNT=$MOUNTDIR/findiso
27 # this will be replaced by build script, so never change the following line!
28 LIVECDNAME="slitaz"
30 # =================================================================
31 # debug and output functions
32 # =================================================================
34 # global variable
35 DEBUG_IS_ENABLED=$(cat /proc/cmdline 2>/dev/null | grep debug)
37 debug_log()
38 {
39 if [ "$DEBUG_IS_ENABLED" ]; then
40 echo "- debug: $*" >&2
41 log "- debug: $*"
42 fi
43 }
45 # echogreen will echo $@ in green color
46 # $1 = text
47 #
48 echogreen()
49 {
50 echo -ne " ""$@"""
51 }
53 # echolog
54 # $1 = text to show and to write to /var/log/messages
55 #
56 echolog()
57 {
58 if [ "$1" != "" ]; then
59 echogreen "* "
60 log "LIVECD:" "$@"
61 echo "$@"
62 fi
63 }
65 # log
66 # store given text in /var/log/livedbg
67 log()
68 {
69 echo "$@" 2>/dev/null >>/var/log/livedbg
70 }
72 # show information about the debug shell
73 show_debug_banner()
74 {
75 echo
76 echo "====="
77 echo ": Debugging started. Here is the root shell for you."
78 echo ": Type your desired commands or hit Ctrl+D to continue booting."
79 echo
80 }
82 # debug_shell
83 # executed when debug boot parameter is present
84 #
85 debug_shell()
86 {
87 if [ "$DEBUG_IS_ENABLED" ]; then
88 show_debug_banner
89 ash < /dev/console
90 echo
91 fi
92 }
94 # header
95 # $1 = text to show
96 #
97 header()
98 {
99 echo """$@"""
100 }
102 fatal()
103 {
104 echolog
105 header "Fatal error occured - $1"
106 echolog "Something went wrong and we can't continue. This should never happen."
107 echolog "Please reboot your computer with Ctrl+Alt+Delete ..."
108 echolog
109 ash < /dev/console
110 }
112 allow_only_root()
113 {
114 # test if the script is started by root user. If not, exit
115 if [ "0$UID" -ne 0 ]; then
116 echo "Only root can run $(basename $0)"; exit 1
117 fi
118 }
120 # ===========================================================
121 # text processing functions
122 # ===========================================================
124 # look into cmdline and echo $1 back if $1 is set
125 # $1 = value name, case sensitive, for example 'debug'
126 #
127 cmdline_parameter()
128 {
129 debug_log "cmdline_parameter" "$*"
130 log "searching for bootparam: $1"
131 egrep -o "(^|[[:space:]])$1([[:space:]]|\$)" /proc/cmdline | tr -d " " | tail -n 1
132 }
134 # look into cmdline and echo value of $1 option
135 # $1 = value name, case sensitive, for example 'changes'
136 #
137 cmdline_value()
138 {
139 debug_log "cmdline_value" "$*"
140 log "searching for bootparam value: $1"
141 egrep -o "(^|[[:space:]])$1=[^[:space:]]+" /proc/cmdline | cut -d "=" -f 2- | tail -n 1
142 }
144 # Make sure the part of a script after 'mutex_lock' call is atomic,
145 # that means the 'locked' part of the script can never be execuetd
146 # from several processes at the same time, in parallel.
147 # Every script waits until it gathers the lock.
148 # The lock directory is saved in /dev instead of /tmp, because /tmp may be
149 # readonly at the time when the lock is needed (eg. when udev is starting)
150 # $1 = name of the lock
151 #
152 mutex_lock()
153 {
154 debug_log "mutex_lock" "$*"
155 while ! mkdir "/dev/ll-mutex-lock-$1" 2>/dev/null; do
156 usleep 100000;
157 done
158 }
160 # Unlock the lock so another waiting process can reusse it and continue
161 # $1 = name of the lock
162 #
163 mutex_unlock()
164 {
165 debug_log "mutex_unlock" "$*"
166 rmdir "/dev/ll-mutex-lock-$1" 2>/dev/null
167 }
169 # ===========================================================
170 # system functions
171 # ===========================================================
173 # setup /usr from /usr.lzm inside initrd
174 mount_initrd_loops()
175 {
176 debug_log "mount_initrd_loops" "$*"
177 if [ -e /usr.lzm ]; then
178 mount_device /usr.lzm /usr loop,ro squashfs
179 fi
180 if [ -e /drivers.lzm ]; then
181 mount_device /drivers.lzm /lib/modules/*/kernel/drivers loop,ro squashfs
182 fi
183 }
185 # modprobe module $1, including all dependencies, suppress all messages
186 # This was own function, because modprobe in busybox didn't support
187 # neither gzipped modules nor dependencies. Seems to be fixed now, though.
188 # $1 = module name, eg. ehci-hcd
189 # $* = optional arguments
190 #
191 modprobe_module()
192 {
193 debug_log "modprobe_module" "$*"
194 local MODULE
196 MODULE="$1"
197 shift
199 if [ ! "$MODULE" ]; then return 1; fi
200 modprobe "$MODULE" $* 2>/dev/null
201 }
203 cdname()
204 {
205 if [ "$(cmdline_value cdname)" != "" ]; then
206 LIVECDNAME="$(cmdline_value cdname)"
207 else
208 LIVECDNAME="${LIVECDNAME}"
209 fi
210 }
212 cdname
214 # mknod next loop device
215 # - find biggest loop device in /dev/loop/, assume it to be used
216 # - preallocate (mknod) 20 more loop devices in one round
217 mknod_next_loop_dev()
218 {
219 debug_log "mknod_next_loop_dev" "$*"
220 local i NR END PFX
222 mutex_lock mknod_next_loop_dev
224 if [ -d /dev/loop ]; then
225 NR=$(find /dev/loop/ -maxdepth 1 | sed -r 's/[^0-9]+//' | sort -n | tail -n 1)
226 PFX="/"
227 else
228 NR=$(find /dev/ -maxdepth 1 | grep loop | sed -r 's/[^0-9]+//' | sort -n | tail -n 1)
229 PFX=""
230 fi
231 NR=$(expr 0$NR + 1)
232 END=$(expr 0$NR + 20)
233 for i in $(seq $NR $END); do
234 mknod /dev/loop$PFX$i b 7 $i 2>/dev/null
235 done
236 echo /dev/loop$PFX$NR
238 mutex_unlock mknod_next_loop_dev
239 }
241 # ===========================================================
242 # Filesystem functions
243 # ===========================================================
245 # Find out what locale is requested
246 # If no locale is given, use the firts one available (if any)
247 # $1 = locale (optional argument, if exists, no autodetection is made)
248 locale_id()
249 {
250 debug_log "locale_id" "$*"
251 local LOCALE i
253 # first try to find out locale from boot parameters
254 LOCALE="$1"
255 if [ "$LOCALE" = "" ]; then LOCALE=$(cmdline_value locale); fi
256 if [ "$LOCALE" = "" ]; then LOCALE=$(cmdline_value language); fi
257 if [ "$LOCALE" = "" ]; then LOCALE=$(cmdline_value lang); fi
259 # if not found, set it to locale from usr/lib/locale,
260 # but only if there is just ONE directory, nothing more
261 # (so we are sure which one to use)
262 if [ "$LOCALE" = "" ]; then
263 for LOCALE in $(ls -A1p /usr/lib/locale 2>/dev/null | grep / | sed -r "s:[/]|[.].*::"); do
264 i="1$i"
265 done
266 if [ "$i" != "1" ]; then LOCALE=""; fi
267 fi
269 if [ "$LOCALE" != "" -a -e /usr/share ]; then
270 cat /usr/share/locale/locale.alias | sed -r "s/#.*//" | egrep "$LOCALE|$LOCALE""_" | tail -n 1 | tr -s "[[:space:]]" " " | cut -d " " -f 2- | tr -d " "
271 fi
272 }
274 # Find out what iocharset to use
275 iocharset()
276 {
277 debug_log "iocharset" "$*"
278 local CHARSET IOCHARSET
280 # if iocharset is explicitly set at the boot prompt,
281 # return it regardless the locale settings
282 IOCHARSET=$(cmdline_value iocharset)
283 if [ "$IOCHARSET" != "" ]; then
284 echo $IOCHARSET
285 return 0;
286 fi
288 # else find out the iocharset from locale_id output, it should match
289 # some kernel module (after stripping out few of the dashes)
290 IOCHARSET=$(locale_id | cut -d . -f 2- | tr "[[:upper:]]" "[[:lower:]]" | tr -d -)
291 if [ "$IOCHARSET" = "" ]; then return 0; fi
293 find /lib/modules -name "nls_*" | sed -r 's:^.*/|[.]ko$::g' | cut -b 5- | while read CHARSET; do
294 if [ "$(echo $CHARSET | tr "[[:upper:]]" "[[:lower:]]" | tr -d -)" = "$IOCHARSET" ]; then
295 echo "$CHARSET"
296 return 0
297 fi
298 done
299 return 1
300 }
302 # Get filesystem options
303 # $1 = filesystem
304 # $2 = 'fstab' or 'mount' ... 'auto'/'noauto' string is enabled (fstab) or disabled (mount)
305 #
307 fs_options()
308 {
309 debug_log "fs_options" "$*"
310 local NOAUTO IOCHARSET
312 NOAUTO=$(cmdline_parameter noauto)
313 if [ "$NOAUTO" = "" ]; then NOAUTO="auto"; fi
314 if [ "$2" = "fstab" ]; then echo -n "$NOAUTO," ; fi
315 if [ "$1" = "swap" ]; then echo "defaults,pri=1"; return 0; fi
316 echo -n "noatime,users,suid,dev,exec"
318 IOCHARSET=$(iocharset)
320 if [ "$1" = "vfat" ]; then
321 echo -n ",quiet,umask=0,check=s,shortname=mixed"
322 if [ "$IOCHARSET" ]; then
323 echo ",iocharset=$IOCHARSET"
324 fi
325 fi
327 if [ "$1" = "iso9660" -o "$1" = "iso9660,udf" ]; then
328 echo -n ",ro"
329 if [ "$IOCHARSET" ]; then
330 echo ",iocharset=$IOCHARSET"
331 fi
332 fi
334 if [ "$1" = "ntfs" ]; then
335 echo -n ",ro"
336 if [ "$IOCHARSET" ]; then
337 echo ",nls=$IOCHARSET"
338 fi
339 fi
341 if [ "$1" = "ntfs-3g" ]; then
342 echo ",locale=$(locale_id)"
343 fi
345 if [ "$1" = "ext3" -o "$1" = "ext4" ]; then
346 echo ",barrier=1,data=ordered"
347 fi
349 }
351 # discover filesystem used on the given device
352 # Use vfat for msdos filesystem. Use ntfs-3g for ntfs if ntfs-3g exists.
353 # $1 = device, eg. /dev/hda1
354 #
355 device_filesystem()
356 {
357 debug_log "device_filesystem" "$*"
358 local NTFS
360 if [ -e /bin/ntfs-3g ]; then NTFS="ntfs-3g"; else NTFS="ntfs"; fi
361 blkid -s TYPE "$1" -o value | sed "s/msdos/vfat/" | sed "s/ntfs/$NTFS/"
362 }
364 # tell us if the given filesystem is supported
365 # (eg. it's in /proc/filesystems or we know it)
366 # $1 = filesystem name
367 #
368 is_supported_filesystem()
369 {
370 debug_log "is_supported_filesystem" "$*"
372 if [ -e /bin/ntfs-3g -a "$1" = "ntfs-3g" ]; then
373 return 0
374 fi
376 # the following command will set the return value
377 egrep -q "[[:space:]]$1\$" /proc/filesystems
378 }
380 # Mount device $1 to $2
381 # If the device is using vfat or ntfs filesystem, use iocharset as a mount option
382 # $1 = /dev device to mount, eg. /dev/hda1, or loop file, or directory
383 # $2 = mountpoint, eg. /mnt/hda1
384 # $3 = optional mount options, for example "ro", or "remount,rw"
385 # $4 = optional filesystem name, in order to skip autodetection
386 #
387 mount_device()
388 {
389 debug_log "mount_device" "$*"
390 local FS DEV LOOPDEV OPTIONS FILESYSTEM ERR
392 # make sure we have enough arguments
393 if [ "$2" = "" ]; then return 1; fi
394 if [ "$1" = "" ]; then rmdir "$2" 2>/dev/null; return 1; fi
395 mkdir -p "$2"
397 DEV="$1"
398 if [ "$4" != "" ]; then FS="$4"; else FS=$(device_filesystem "$1"); fi
399 if [ "$FS" ]; then OPTIONS=$(fs_options $FS mount); FS="-t $FS"; fi
400 if [ "$OPTIONS" ]; then OPTIONS="$OPTIONS"; else OPTIONS=""; fi
401 if [ -f "$DEV" ]; then OPTIONS="$OPTIONS,loop"; fi
402 if [ -d "$DEV" ]; then OPTIONS="$OPTIONS,rbind"; fi
403 if [ "$3" ]; then OPTIONS="$OPTIONS,$3"; fi
404 OPTIONS=$(echo "$OPTIONS" | sed -r "s/^,+//")
406 if [ "$FS" = "-t ntfs-3g" ]; then
407 ntfs-3g "$DEV" "$2" -o $OPTIONS >/dev/null 2>&1
408 ERR=$?
409 else
410 mount -n -o $OPTIONS $FS "$DEV" "$2" >/dev/null 2>&1
411 ERR=$?
412 fi
414 # not enough loop devices? try to create one.
415 if [ $ERR -eq 2 ]; then
416 LOOPDEV=$(mknod_next_loop_dev)
417 OPTIONS=$(echo "$OPTIONS" | sed -r "s/,loop//g")
418 losetup "$LOOPDEV" "$DEV" 2>/dev/null # busybox's losetup doesn't support -r
419 if [ $? -ne 0 ]; then
420 losetup -r "$LOOPDEV" "$DEV" 2>/dev/null # force read-only in case of error
421 fi
422 mount -n -o $OPTIONS $FS "$LOOPDEV" "$2" >/dev/null 2>&1
423 ERR=$?
424 fi
426 # if nothing works, try to force read-only mount
427 if [ $ERR -ne 0 ]; then
428 mount -n -r -o $OPTIONS $FS "$DEV" "$2" >/dev/null 2>&1
429 ERR=$?
430 fi
432 if [ $ERR -ne 0 ]; then rmdir $2 2>/dev/null; fi
433 return $ERR
434 }
436 # unmount all parameters. If the parameter is not mountpoint but
437 # it's a file or directory, umount the device where the file/dir is stored.
438 #
439 # First try normal umount, if that fails then remount read-only
440 # If -l parameter is specified, do lazy-umount when normal umount fails
441 # $1..$n = files/directories/devices to be unmounted
442 #
443 fumount()
444 {
445 debug_log "fumount" "$*"
446 local TARGET LAZY
448 while [ "$1" ]; do
449 if [ "$1" = "-l" ]; then LAZY="yes"; shift; fi
450 TARGET=$(readlink -f "$1")
451 if ! ismountpoint "$TARGET"; then
452 if [ -f "$TARGET" -o -d "$TARGET" ]; then
453 TARGET=$(df "$TARGET" | tail -n 1 | tr -s " " | cut -d " " -f 6)
454 fi
455 fi
457 if [ "$TARGET" != "" ]; then
458 umount -n "$TARGET" >/dev/null 2>&1
459 if [ $? -ne 0 ]; then
460 mount -n -o remount,ro -t ignored ignored "$TARGET" >/dev/null 2>&1
461 if [ "$LAZY" ]; then umount -n -l "$TARGET" >/dev/null 2>&1; fi
462 fi
463 fi
464 shift
465 done
466 }
468 # ===========================================================
469 # live module functions
470 # ===========================================================
472 # Create module
473 # call mksquashfs with apropriate arguments
474 # $1 = directory which will be compressed to squashfs module
475 # $2 = output filesystem module file
476 # $3..$9 = optional arguments like -keep-as-directory or -b 123456789
477 #
478 create_module()
479 {
480 debug_log "create_module" "$*"
481 rm -f "$2" # overwrite, never append to existing file
482 mksquashfs "$1" "$2" -b 256K $3 $4 $5 $6 $7 $8 $9>/dev/null
483 if [ $? -ne 0 ]; then return 1; fi
484 chmod a-wx "$2" # remove execute and write attrib
485 chmod a+r "$2" # add read for everyone
486 }
488 # ismountpoint exits with 0 if $1 is mountpoint, else exits with 1
489 # $1 = directory or loop_file
490 #
491 ismountpoint()
492 {
493 debug_log "ismountpoint" "$*"
494 local MDIR
496 MDIR=$(readlink -f "$1")
497 cat /proc/mounts | cut -d " " -f 2 | egrep "^$MDIR\$" >/dev/null 2>&1
498 }
500 # Mount filesystem module to destination directory
501 # $1 = path to the compressed module
502 # $2 = destination folder
503 #
504 mount_module()
505 {
506 debug_log "mount_module" "$*"
507 mount_device "$1" "$2" loop,ro squashfs
508 }
510 # Insert a directory tree $2 to an union specified by $1
511 # Top-level read-write branch is specified by it's index 0
512 # Using =rr enables aufs to optimize real readonly branches
513 # $1 = union absolute path (starting with /)
514 # $2 = path to data directory
515 #
516 union_insert_dir()
517 {
518 debug_log "union_insert_dir" "$*"
519 mount -n -o remount,add:1:$2=rr aufs $1
520 }
522 # Find LZM modules in given dir
523 # $1 = root directory of mounted DATAdir
524 #
525 find_modules()
526 {
527 debug_log "find_modules" "$*"
528 if [ "$(cmdline_parameter baseonly)" ]; then
529 find "$1/base" "$1/optional" -name "*.sqfs" 2>/dev/null | sort
530 find "$1/base" "$1/optional" -name "*.lzm" 2>/dev/null | sort
531 else
532 find "$1/base" "$1/modules" "$1/optional" "$1/tmp" -name "*.sqfs" 2>/dev/null | sort
533 find "$1/base" "$1/modules" "$1/optional" "$1/tmp" -name "*.lzm" 2>/dev/null | sort
534 fi
535 }
537 # List all modules in all directories (base, modules, optional)
538 # and filter out unneeded optional modules (not specified by load= kernel parameter)
539 # separator for load and noload arguments is "," or ";"
540 # $1 = root directory of mounted DATAdir
541 #
542 list_modules()
543 {
544 debug_log "list_modules" "$*"
545 local LOAD NOLOAD
547 LOAD=$(cmdline_value load | sed -r 's/\*/.\*/g' | sed -r 's/,|;/|/g')
548 NOLOAD=$(cmdline_value noload | sed -r 's/\*/.\*/g' | sed -r 's/,|;/|/g')
549 find_modules "$1" | while read LINE; do
550 MODNAME=$(echo $LINE | cut -b ${#1}- | cut -b 2-)
551 if [ "$(echo $LINE | grep /optional/)" ]; then
552 if [ ! "$LOAD" -o ! "$(echo $MODNAME | egrep -i "$LOAD")" ]; then continue; fi
553 fi
554 if [ "$NOLOAD" -a "$(echo $MODNAME | egrep -i "$NOLOAD")" ]; then continue; fi
555 echo $LINE
556 done
557 }
559 # Insert one single filesystem module to the union
560 # $1 = union absolute path
561 # $2 = module full path
562 # $3 = destination folder, where images will be mounted to
563 # $4 = preffix length strip (number of characters)
564 #
565 union_insert_module()
566 {
567 debug_log "union_insert_module" "$*"
568 local TARGET
570 TARGET="$3/$(basename $2)"
571 if ismountpoint $TARGET; then return 1; fi # skip already used modules
572 mkdir -p $TARGET
573 mount_module $2 $TARGET
574 if [ $? -ne 0 ]; then echo "Cannot read module data. corrupted download?" >&2; return 1; fi
575 union_insert_dir $1 $TARGET
576 if [ $? -ne 0 ]; then echo "can't insert module to union" >&2; return 2; fi
577 echo "$2" | cut -b $(($4+1))-
578 echolog "$2" >/dev/null
579 return 0
580 }
582 # Insert all filesystem modules from $2 directory and subdirectories, to the union
583 # $1 = union absolute path (starting with /)
584 # $2 = LiveCD data dir (with directories /base, /modules, etc.)
585 # $3 = destination folder, where images will be mounted to
586 #
587 union_insert_modules()
588 {
589 debug_log "union_insert_modules" "$*"
590 local INSERTED
592 list_modules $2 | while read MODULE; do
593 INSERTED=$(union_insert_module $1 $MODULE $3 ${#2})
594 if [ "$INSERTED" != "" ]; then echolog " -> $(echo $INSERTED | sed -r s:^/::)"; fi
595 done
596 }
598 # Copy LiveCD modules to RAM directory
599 # will copy only /boot, and module files from $1
600 # $1 = data directory
601 # $2 = target directory in RAM
602 #
603 copy_to_ram()
604 {
605 debug_log "copy_to_ram" "$*"
606 cp -a "$1/rootcopy" "$2" 2>/dev/null # could be empty
607 list_modules "$1" | while read MODULE; do
608 TARGET=$(dirname "$MODULE" | cut -b ${#1}- | cut -b 2-)
609 mkdir -p "$2/$TARGET"
610 cp "$MODULE" "$2/$TARGET"
611 if [ $? -ne 0 ]; then fatal "Not enough memory. Using ramsize=$RAMSIZE"; fi
612 done
613 }
615 # ===========================================================
616 # discovery functions
617 # ===========================================================
619 # List all supported network drivers
620 #
621 list_network_drivers()
622 {
623 debug_log "list_network_drivers" "$*"
625 # these drivers are probed in Slackware's initrd
626 # (see initrd.img/scripts/network.sh).
627 # I don't have personal experiences with most of these drivers
628 # so I'll be happy if you report any particular one to be not working
629 # (eg. causing hangups) in order to remove it from this list.
631 echo 3c59x acenic atl1 de4x5 dgrs eepro100 e1000 epic100 hp100 ne2k-pci \
632 olympic pcnet32 r8169 rcpci 8139too 8139cp sktr skge sky2 tulip via-rhine \
633 yellowfin tg3 dl2k ns83820 depca ibmtr 3c501 3c503 3c505 3c507 3c509 3c515 \
634 ac3200 acenic at1700 cosa cs89x0 de4x5 de600 de620 e2100 eepro eexpress \
635 es3210 eth16i ewrk3 fmv18x forcedeth hostess_sv11 hp-plus hp lne390 ne3210 \
636 ni5010 ni52 ni65 sb1000 sealevel smc-ultra sis900 smc-ultra32 smc9194 wd \
637 | tr " " "\n"
638 }
640 # List all CD-ROMs
641 # by using /proc entries
642 #
643 list_cdrom_devices()
644 {
645 debug_log "list_cdrom_devices" "$*"
646 local CDDEVICE
648 for CDDEVICE in $(cat /proc/sys/dev/cdrom/info 2>/dev/null | head -n 3 | tail -n 1 | cut -d ":" -f 2); do
649 echo "/dev/$CDDEVICE"
650 done
651 }
653 # List all mounted directories
654 #
655 list_mounted_directories()
656 {
657 debug_log "list_mounted_directories" "$*"
658 if [ "$MOUNTDIR" ]; then
659 ls -1 $MOUNTDIR | while read DIR; do
660 if ismountpoint $MOUNTDIR/$DIR; then echo $DIR; fi
661 done
662 fi
663 }
665 # List all devices with filesystems
666 # Return empty result when nohd parameter was given.
667 #
668 list_partition_devices()
669 {
670 debug_log "list_partition_devices" "$*"
671 if [ "$(cmdline_parameter nohd)" != "" ]; then return 1; fi
672 cat /proc/partitions | grep -v loop | grep -v major | grep -v '^$' | sed -r "s:^[0-9 ]+:/dev/:"
673 if [ -e /dev/mapper/control ]; then # list LVM partitions if available
674 ls -1 /dev/mapper/ | grep -v "^control\$" | sed -r "s:^:/dev/mapper/:"
675 fi
676 }
678 # List all disk devices
679 #
680 list_disk_devices()
681 {
682 debug_log "list_disk_devices" "$*"
683 list_partition_devices | egrep -v "[0-9]"
684 }
686 # List all partitions marked as Linux Swap
687 #
688 list_swap_devices()
689 {
690 debug_log "list_swap_devices" "$*"
691 if [ "$(cmdline_parameter nohd)" != "" -o "$(cmdline_parameter noswap)" != "" ]; then return 1; fi
692 blkid -t TYPE="swap" -o device
693 }
695 # List all block devices
696 #
697 list_block_devices()
698 {
699 debug_log "list_block_devices" "$*"
700 if [ "$(cmdline_parameter nocd)" = "" ]; then
701 list_cdrom_devices
702 fi
703 list_partition_devices
704 }
706 # Format mountdir for device. This function used to append _cdrom or _removable
707 # suffix to the directory name so KDE was able to assign a nice icon for evey
708 # device, but this should be done using HAL in KDE nowadays, so we do not
709 # support these stupid suffixes anymore. Many people will be happy :)
710 # $1 = device full path, eg. /dev/hda1
711 #
712 device_mountdir()
713 {
714 debug_log "device_mountdir" "$*"
715 echo "/$MOUNTDIR/$(basename "$1")" | tr -s /
716 }
718 # Find file-path on given device
719 # First it mounts the device read-only. If then the 'path' is found,
720 # then remount without RO flag (causes it to be mounted read-write if possible)
721 # and return the path, else unmount and exit.
722 # If the device/dev_directory is already mounted, preserve it mounted
723 # $1 = device
724 # $2 = path/filename
725 #
726 find_filepath()
727 {
728 debug_log "find_filepath" "$*"
729 local DIR FOUND PRESERVE
731 DIR=$(device_mountdir $1)
732 ismountpoint $DIR
733 if [ $? -eq 0 ]; then
734 PRESERVE="true"
735 else
736 mount_device $1 $DIR ro
737 if [ $? -ne 0 ]; then rmdir $DIR 2>/dev/null; return 1; fi
738 PRESERVE=""
739 fi
741 FOUND=$(ls -A1d $DIR/$2 2>/dev/null | head -n 1 | tr -s '/')
743 if [ "$FOUND" = "" ]; then
744 if [ "$PRESERVE" != "true" ]; then
745 fumount $DIR
746 rmdir $DIR 2>/dev/null
747 fi
748 return 1
749 else
750 # remount without the 'ro' option now, so use rw or defaults
751 # Only in the case it was not mounted already before.
752 if [ "$PRESERVE" != "true" ]; then
753 fumount $DIR
754 mount_device $1 $DIR
755 if [ $? -ne 0 ]; then
756 rmdir $DIR 2>/dev/null
757 return 2
758 fi
759 fi
760 echo "$FOUND"
761 return 0
762 fi
763 }
765 # Find file in computer by mounting disks or other storage devices
766 # and searching for $1 in the mounted directory
767 # $1 = filename or device-path or devicepath/filename
768 #
769 find_file()
770 {
771 debug_log "find_file" "$*"
772 local FIND DEVICE DEVPART PATHPART
774 # allow using /mnt/... as well as /dev/...
775 FIND=$(echo "$1" | sed -r "s:^/mnt/:/dev/:")
777 # if parameter is just a device, echo it and exit
778 if [ -b "$FIND" -o -c "$FIND" -o "$FIND" = "" ]; then echo "$FIND"; return; fi
780 # If path doesn't start with /dev/, try to find the exact path on all devices
781 # First, split DEV/PATH parts
782 DEVPART=$(echo "$FIND" | egrep -o "^/dev/[^/]+")
784 if [ "$DEVPART" = "" ]; then
785 # no device is specified. Search all devices for filename $FIND
786 PATHPART="$FIND";
787 for DEVICE in $(list_mounted_directories) $(list_block_devices); do
788 if ! grep -q ":$DEVICE@$PATHPART:" /tmp/_findfile 2>/dev/null; then
789 find_filepath "$DEVICE" "$PATHPART"
790 if [ $? -eq 0 ]; then return 0; fi
791 echo ":$DEVICE@$PATHPART:" >>/tmp/_findfile
792 fi
793 done
794 else
795 # try to find PATHPART only on the given device
796 PATHPART=$(echo "$FIND" | sed -r 's:^/dev/[^/]+(.*):\1:')
797 find_filepath $DEVPART $PATHPART
798 fi
799 }
801 # Find In Computer
802 # use 'find_file' function to find the given file/dir
803 # if nothing found, sleep for a while to allow devices to settle and try again.
804 # (is there any way to find out if there are devices queued through /sys?)
805 # $1 = file or directory to find
806 #
807 find_in_computer()
808 {
809 debug_log "find_in_computer" "$*"
810 local TIMEOUT RESULT
812 TIMEOUT=$(cmdline_value scantimeout | sed -r 's/[^0-9]*([0-9]+).*/\1/')
813 if [ "$TIMEOUT" = "" ]; then TIMEOUT=10; fi
815 RESULT=$(find_file "$1")
817 while [ $TIMEOUT -gt 0 -a "$RESULT" = "" ]; do
818 echo -ne "- wait a while\r" >&2
819 sleep 1
820 TIMEOUT=$((TIMEOUT-1))
821 RESULT=$(find_file "$1")
822 done
824 echo $RESULT
825 }
827 # Find and run all scripts from the given module
828 # This function is used by the activate and deactivate script when the distro
829 # is already started, not during live setup
830 # $1 = mounted module full path
831 # $2..$n = optional arguments for the scripts, eg. 'start'
832 #
833 find_n_run_scripts()
834 {
835 debug_log "find_n_run_scripts" "$*"
836 local MOD
838 MOD="$1"
839 shift
841 if [ -d $MOD/etc/rc.d -o -d $MOD/etc/rc.d/init.d -o -d $MOD/etc/init.d ]; then
842 ( find $MOD/etc/rc.d -type f -maxdepth 1 2>/dev/null ; \
843 find $MOD/etc/init.d -type f -maxdepth 1 2>/dev/null ; \
844 find $MOD/etc/rc.d/init.d -type f -maxdepth 1 2>/dev/null \
845 ) | cut -b ${#MOD}- | cut -b 2- | xargs -n 1 -r readlink -f | sort -u | while read SCRIPT; do
846 if [ "$SCRIPT" != "" -a -x "$SCRIPT" -a ! -d "$SCRIPT" ]; then
847 # call the script by real path, not from the module
848 log "starting '$SCRIPT $@'"
849 ${SCRIPT} "$@"
850 fi
851 done
852 fi
853 }
855 # ===========================================================
856 # hardware preparation functions
857 # ===========================================================
859 # Create block devices to /dev described by /sys entries
860 #
861 mdev_start_hotplug()
862 {
863 debug_log "mdev_start_hotplug" "$*"
864 echolog "Creating /dev entries for block devices"
865 mdev -s
866 #rm /dev/pty??* /dev/tty??* # remove unneeded pty and tty devices
867 echo /bin/mdev > /proc/sys/kernel/hotplug # use mdev as a hotplug handler
868 }
870 # Modprobe kernel modules needed for the LiveCD
871 #
872 modprobe_essential_modules()
873 {
874 debug_log "modprobe_essential_modules" "$*"
876 echolog "Loading filesystems modules ..."
877 modprobe_module loop
878 modprobe_module isofs
879 #modprobe_module sqlzma
880 modprobe_module squashfs
881 #modprobe_module unlzma
882 modprobe_module aufs brs=1
883 modprobe_module ext2
884 modprobe_module ext3
885 modprobe_module ext4
886 modprobe_module btrfs
887 modprobe_module reiserfs
888 modprobe_module xfs
889 modprobe_module vfat
890 modprobe_module fuse # for ntfs-3g
891 modprobe_module ntfs # for ro driver
892 }
894 # Modprobe kernel modules needed for USB masstorage devices
895 #
896 modprobe_usb_modules()
897 {
898 debug_log "modprobe_usb_modules" "$*"
899 local LSPCI
901 # skip module loading if nohotplug bootparam is present
902 if [ "$(cmdline_parameter nohotplug)" ]; then return 0; fi
904 LSPCI=$(lspci -v | grep -i prog-if)
905 if [ "$(echo $LSPCI | egrep -i [eou]hci)" = "" ]; then
906 return 0
907 fi
909 echolog "Loading USB modules ..."
910 if [ "$(echo $LSPCI | grep -i ehci)" != "" ]; then
911 modprobe_module ehci-hcd
912 fi
913 if [ "$(echo $LSPCI | grep -i ohci)" != "" ]; then
914 modprobe_module ohci-hcd
915 fi
916 if [ "$(echo $LSPCI | grep -i uhci)" != "" ]; then
917 modprobe_module uhci-hcd
918 fi
919 modprobe_module usb-storage
920 }
922 # Load drivers for PCMCIA CardBus devices
923 #
924 modprobe_pcmcia_modules()
925 {
926 debug_log "modprobe_pcmcia_modules" "$*"
928 # skip module loading if nohotplug bootparam is present
929 if [ "$(cmdline_parameter nohotplug)" ]; then return 0; fi
931 echolog "Loading PCMCIA CardBus modules ..."
932 modprobe_module pcmcia_core
933 modprobe_module pcmcia
934 modprobe_module rsrc_nonstatic
935 modprobe_module yenta_socket
936 }
938 # Load network drivers unless eth[0-9] is found
939 #
940 modprobe_network_modules()
941 {
942 debug_log "modprobe_network_modules" "$*"
943 local ETH
945 # skip module loading if nohotplug bootparam is present
946 if [ "$(cmdline_parameter nohotplug)" ]; then return 0; fi
948 # probe all drivers. Start by the ones mentioned in pcimodules' output
949 for module in $(list_network_drivers | egrep "$(pcimodules | tr "\n" "|")!") $(list_network_drivers); do
950 modprobe_module $module
951 ETH=$(cat /proc/net/dev | grep : | grep -v lo: | cut -d : -f 1 | tr -d " ")
952 if [ "$ETH" != "" ]; then
953 echo $ETH
954 return 0
955 fi
956 rmmod $module 2>/dev/null
957 done
958 }
960 # Start udhcpc to get IP address from DHCP server
961 # $1 = interface to use (optional)
962 #
963 init_dhcp()
964 {
965 debug_log "start_dhcp_client" "$*"
967 if [ "$1" != "" ]; then
968 ifconfig $1 up
969 udhcpc -i $1 -q
970 else
971 ifconfig eth0 up
972 udhcpc -q
973 fi
974 }
976 # Mount http filesystem from the given server
977 # $1 = server
978 # $2 = mountdir
979 #
980 mount_httpfs()
981 {
982 debug_log "mount_httpfs" "$*"
984 mkdir -p $2
985 httpfs $1 $2
986 }
989 # Unload modules loaded to kernel which are not used
990 # This function used to unload more modules, but it may cause
991 # problems to auto-remove some of them (eg. a network module
992 # can seem unneeded even if network is to be used very soon.
993 #
994 rmmod_unused_modules()
995 {
996 debug_log "rmmod_unused_modules" "$*"
997 rmmod usb-storage uhci-hcd ohci-hcd ehci-hcd 2>/dev/null
998 rmmod yenta_socket rsrc_nonstatic pcmcia pcmcia_core 2>/dev/null
999 }
1001 # kill all unneeded processes, which have bigger PID then the PID of
1002 # current shell. We can't use killall5, as it would kill some processes
1003 # which may be currently needed, for example ntfs-3g.
1004 # $1 = maximum pid (kill all lower)
1006 killall_unneeded()
1008 debug_log "killall_unneeded" "$*"
1009 local LIST PID
1011 PID=$1
1012 for pid in $(ps | grep -v "PID" | egrep -v "\[.*\]" | fgrep -v mount | fgrep -v posixovl | fgrep -v ntfs | sed -r "s/^[[:space:]]*([0-9]+).*/\\1/"); do
1013 if [ $pid -lt $PID ]; then
1014 LIST="$LIST $pid"
1015 fi
1016 done
1018 kill -SIGTERM $LIST 2>/dev/null # SIGTERM
1019 sleep 2
1020 kill -SIGKILL $LIST 2>/dev/null # SIGKILL
1023 # enable/disable CD autoejecting when unmounted
1024 # $1 = 1|0 ... enable|disable
1026 cd_autoeject()
1028 debug_log "cd_autoeject" "$*"
1029 echo $1 >/proc/sys/dev/cdrom/autoeject
1032 # ===========================================================
1033 # FSTAB functions
1034 # ===========================================================
1036 # $1 = fstab file
1037 # $2 = device name
1038 dev_is_in_fstab()
1040 debug_log "dev_is_in_fstab" "$*"
1041 cat "$1" | sed -r "s/#.*//" | egrep -q "^[[:space:]]*$2[[:space:]]"
1044 # update given line in fstab, add new values only if the device is not found
1045 # $1 = fstab file to parse
1046 # $2 = device name
1047 # $3 = mountpoint
1048 # $4 = filesystem
1049 # $5 = mount options
1051 fstab_add_line()
1053 debug_log "fstab_add_line" "$*"
1054 local DIR
1056 if [ "$4" != "swap" ]; then DIR="$3"; else DIR="none"; fi
1057 if ! dev_is_in_fstab "$1" "$2"; then
1058 echo "$2" "$DIR" "$4" "$5" 0 0 "$FSTABLLFLAG" >>$1
1059 fi
1062 # create correct fstab file in $1/etc/fstab and create apropriate
1063 # mount directories in $1/mnt. This function is only calld once,
1064 # during liveCD startup (even before init from the distro is started).
1065 # $1 = root directory (union)
1067 fstab_update()
1069 debug_log "fstab_update" "$*"
1070 local FSTAB FSTABTMP
1072 FSTAB="$1/etc/fstab"
1073 FSTABTMP=$FSTAB$$
1074 mkdir -p $1/etc $1/mnt
1075 cat $FSTAB 2>/dev/null | grep -v "$FSTABLLFLAG" >$FSTABTMP
1077 fstab_add_line $FSTABTMP none / unionfs defaults
1078 fstab_add_line $FSTABTMP none /proc proc defaults
1079 fstab_add_line $FSTABTMP none /sys sysfs defaults
1080 fstab_add_line $FSTABTMP none /dev/pts devpts gid=5,mode=620
1081 fstab_add_line $FSTABTMP tmpfs /dev/shm tmpfs defaults
1083 list_cdrom_devices | while read DEVICE; do
1084 MNT=$(device_mountdir $DEVICE)
1085 FS=$(device_filesystem $DEVICE)
1086 if [ "$FS" = "" ]; then FS=iso9660,udf; fi
1087 mkdir -p "$1/$MNT"
1088 fstab_add_line $FSTABTMP $DEVICE $MNT $FS $(fs_options $FS fstab)
1089 done
1090 list_partition_devices | while read DEVICE; do
1091 MNT=$(device_mountdir $DEVICE)
1092 FS=$(device_filesystem $DEVICE)
1093 OPT=$(fs_options $FS fstab)
1095 if [ "$FS" = "swap" ]; then
1096 fstab_add_line $FSTABTMP $DEVICE $MNT $FS $OPT
1097 fi
1099 # If the partition has a valid filesystem, add it to fstab
1100 if is_supported_filesystem "$FS"; then
1101 fstab_add_line $FSTABTMP $DEVICE $MNT $FS $OPT
1102 mkdir -p "$1/$MNT"
1103 fi
1104 done
1106 mv -f $FSTABTMP $FSTAB
1109 # create correct fstab file in $1/etc/fstab only with aufs,proc,sysfs and devpts
1110 # No partition will be mounted and mount point created
1111 # HAL is going to manage mount points and medias
1112 fstab_clean()
1114 debug_log "fstab_update" "$*"
1115 local FSTAB FSTABTMP
1117 FSTAB="$1/etc/fstab"
1118 FSTABTMP=$FSTAB$$
1119 mkdir -p $1/etc $1/mnt
1120 cat $FSTAB 2>/dev/null | grep -v "$FSTABLLFLAG" >$FSTABTMP
1122 fstab_add_line $FSTABTMP aufs / aufs defaults
1123 fstab_add_line $FSTABTMP proc /proc proc defaults
1124 fstab_add_line $FSTABTMP sysfs /sys sysfs defaults
1125 fstab_add_line $FSTABTMP devpts /dev/pts devpts gid=5,mode=620
1126 fstab_add_line $FSTABTMP tmpfs /dev/shm tmpfs defaults
1127 mv -f $FSTABTMP $FSTAB