slitaz-modular view initramfs/liblinuxlive @ rev 177

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