summaryrefslogtreecommitdiffstats
path: root/source/a/mkinitrd/mkinitrd
blob: 8f77725fe88da03d1ab2f6d62021f31c0adc1559 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
#!/bin/sh
# Copyright 2004  Slackware Linux, Inc., Concord, CA, USA
# Copyright 2004  Patrick J. Volkerding, Concord, CA, USA
# Copyright 2007, 2008, 2009  Patrick J. Volkerding, Sebeka, MN, USA
# All rights reserved.
#
# Redistribution and use of this script, with or without modification, is
# permitted provided that the following conditions are met:
#
# 1. Redistributions of this script must retain the above copyright
#    notice, this list of conditions and the following disclaimer.
#
#  THIS SOFTWARE IS PROVIDED BY THE AUTHOR ''AS IS'' AND ANY EXPRESS OR IMPLIED
#  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
#  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
#  EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
#  SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
#  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
#  OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#  WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#  OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#  ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

# Modified by Robby Workman <rworkman@slackware.com> 26 November 2007
# to add support for mkinitrd.conf - No additional license terms added
# Modified by Alan Hicks <alan@slackware.com> 27 November 2007 to enable
# passing arguments to kernel modules - No additional license terms added
# volkerdi - feel free to remove these :)
# Modified by Eric Hameleers <alien@slackware.com> 3 April 2008
# to add support custom keymaps - No additional license terms added
# Modified by Patrick Volkerding <volkerdi@slackware.com> 17 Dec 2008
# Added support to bail out if kernel modules are requested for a kernel
# version that is not installed (thanks to Eric Hameleers), be more
# verbose about showing modules added to the initrd (thanks to
# Ellington Santos), and if "mount" returns /dev/root as the root device,
# use readlink to resolve the device pointed to by the /dev/root
# symlink, changed modprobe to use --ignore-install to avoid catching
# custom "install" lines and causing /sbin/modprobe to be copied to the
# initrd (thanks to Ken Milmore).
# Of course, license terms remain unchanged.

MKINITRD_VERSION=1.3.4

print_usage() {
  cat << EOF
Usage: mkinitrd [OPTION]

mkinitrd creates an initial ramdisk (actually an initramfs cpio+gzip
archive) used to load kernel modules that are needed to mount the
root filesystem, or other modules that might be needed before the
root filesystem is available.  Other binaries may be added to the
initrd, and the script is easy to modify.  Be creative.  :-)

  -F      Use the contents of /etc/mkinitrd.conf (optional)
          If this is used in conjunction with any other options passed
          on the command line, the command-line options will override
          the config file options.  See mkinitrd.conf(5) for details.
  -c      Clear the existing initrd tree first
  -f      Filesystem to use for root partition (must be used with -r)
  --help  Display this message
  -h      Device to resume from hibernation. Needs to be the name of
          the swap partition holding the hibernation image.
  -k      Kernel version to use
  -l      Custom keymap to load. Like, 'nl' or 'de-latin1-nodeadkeys'
  -m      A colon (:) delimited list of kernel modules to load.
          Additional options may be added to use when loading the
          kernel modules (but in this case the entire list must be
          wrapped with double quotes).  Any dependencies of requested
          modules will also be added to the initrd.
  -o      Output image (default /boot/initrd.gz)
  -r      Root partition device (must be used with -f)
  -s      Initrd source tree (default /boot/initrd-tree/)
  -w      Time to wait until all disks are detected
  -C      Use cryptsetup to unlock the underlying device of an
          encrypted root filesystem (must be used with '-r' parameter).
          Two scenarios are possible. (1) root filesystem was created on the
          encrypted disk/LVM partition, example:
            -C /dev/sda2 -r cryptroot
          where /dev/sda2 is the encrypted partition and
          the actual root device name in /etc/fstab is:
            /dev/mapper/cryptroot
          (2) the encrypted partition contains a LVM volume which holds the
          root filesystem, example:
            -C /dev/sda2 -r /dev/vg/root
          where /dev/sda2 is the encrypted partition and
          the actual root device name in /etc/fstab is:
            /dev/vg/root
  -L      Add support for LVM partitions
  -R      Add support for RAID partitions
  -V      Display version number

A simple example:  Build an initrd for a reiserfs root partition:

  mkinitrd -c -m reiserfs

Another example:  Build an initrd image using Linux 2.6.29.3-smp kernel
modules for a system with an ext3 root partition on /dev/hdb3:

  mkinitrd -c -k 2.6.29.3-smp -m mbcache:jbd:ext3 -f ext3 -r /dev/hdb3

Note that if you are already logged in with /dev/hdb3 as your /
partition, and it is running ext3, this command works just the same:

  mkinitrd -c -m ext3

If run without options, mkinitrd will rebuild an initrd image using
the contents of the $SOURCE_TREE directory, or, if that directory
does not exist it will be created and populated, and then mkinitrd
will exit.

EOF
}

create_new_source_tree() {
  mkdir -p $SOURCE_TREE
  # Make sure a kernel module directory exists:
  mkdir -p $SOURCE_TREE/lib/modules/${KERNEL_VERSION}
  # Add the initrd-tree skeleton:
  ( cd $SOURCE_TREE ; tar xzf /usr/share/mkinitrd/initrd-tree.tar.gz )
  # Make sure we have any block devices that might be needed:

  SLOPPY_DEV_LIST=$(cat /proc/partitions)
  for device in $SLOPPY_DEV_LIST ; do
    if [ ! -r $SOURCE_TREE/dev/$device ]; then
      if [ -b /dev/$device ]; then
        if [ -L /dev/$device ]; then
          cp -a --parents $(readlink -e /dev/$device) $SOURCE_TREE
        fi
        cp -a --parents /dev/$device $SOURCE_TREE
      fi
    fi
  done
}

clear_source_tree() {
  if [ -d "$SOURCE_TREE" ]; then
    rm -rf $SOURCE_TREE
  fi
}

build_initrd_image() {
  # Make sure we have any block devices that might be needed:
  SLOPPY_DEV_LIST=$(cat /proc/partitions)
  for device in $SLOPPY_DEV_LIST ; do
    if [ ! -r $SOURCE_TREE/dev/$device ]; then
      if [ -b /dev/$device ]; then
        if [ -L /dev/$device ]; then
          cp -a --parents $(readlink -e /dev/$device) $SOURCE_TREE
        fi
        cp -a --parents /dev/$device $SOURCE_TREE
      fi
    fi
  done
  # Wrap the initrd as an initramfs image and move it into place:
  ( cd $SOURCE_TREE
    rm -f $OUTPUT_IMAGE
    find . | cpio -o -H newc | gzip -9c > $OUTPUT_IMAGE
  )
}

badconf_file() {
  # This won't really help with what's *wrong* with the file,
  # but it will at least give them a clue that there's a problem
  echo "/etc/mkinitrd.conf is bad or does not exist."
  echo "If the file does not exist, do not pass -F to mkinitrd."
  exit 1
}

# If --help is given, print_usage and exit:
if echo $* | grep -wq '\--help' ; then
  print_usage
  exit 0
fi

# If -V given, print version and exit:
if echo $* | grep -wq '\-V' ; then
  echo "mkinitrd version $MKINITRD_VERSION"
  exit 0
fi

# Default values if these aren't previously set.
# Might be set from config file or by -s and -o options too.
SOURCE_TREE=${SOURCE_TREE:-/boot/initrd-tree}
OUTPUT_IMAGE=${OUTPUT_IMAGE:-/boot/initrd.gz}
KERNEL_VERSION=${KERNEL_VERSION:-"$(uname -r)"}

# Default actions without options:
if [ -z "$1" ]; then
  # If the output tree doesn't exist, create it and then exit:
  if [ ! -d $SOURCE_TREE ]; then
    echo "Nothing found at location $SOURCE_TREE, so we will create an"
    echo -n "initrd directory structure there... "
    create_new_source_tree
    echo "done."
    echo
    echo "Now cd to $SOURCE_TREE and install some modules in your"
    echo "module directory (lib/modules/${KERNEL_VERSION}).  Then see init"
    echo "for more information (there are a few other files to edit)."
    echo "Finally, run mkinitrd again once the initrd-tree is ready,"
    echo "and $OUTPUT_IMAGE will be created from it."
    echo
    exit 0
  else
    # If the source tree does exist, the default is to build the initrd
    # image from it and then exit:
    build_initrd_image
    echo "$OUTPUT_IMAGE created."
    echo "Be sure to run lilo again if you use it."
    exit 0
  fi
fi # default no-option actions

# Parse for the use config file option first or else the other command
# line options can not override /etc/mkinitrd.conf. 
for opt in "$@"; do
  if [ $opt = "-F" ]; then
      if [ -e /etc/mkinitrd.conf ]; then
        . /etc/mkinitrd.conf || badconf_file
      else
        badconf_file
      fi
  fi
done

# Parse options:
while [ ! -z "$1" ]; do
  case $1 in
    -c)
      CLEAR_TREE=1
      shift
      ;;
    -f)
      ROOTFS="$2"
      shift 2
      ;;
    -h)
      RESUMEDEV="$2" 
      shift 2
      ;;
    -k)
      KERNEL_VERSION="$2"
      shift 2
      ;;
    -l)
      KEYMAP="$2"
      shift 2
      ;;
    -m)
      MODULE_LIST="$2"
      shift 2
      ;;
    -o)
      OUTPUT_IMAGE="$2"
      if [ ! "$(echo $OUTPUT_IMAGE | cut -b1)" = "/" ]; then
        OUTPUT_IMAGE=$(pwd)/$OUTPUT_IMAGE
      fi
      shift 2
      ;;
    -r)
      ROOTDEV="$2"
      shift 2
      ;;
    -s)
      SOURCE_TREE="$2"
      shift 2
      ;;
    -w)
      WAIT="$2"
      shift 2
      ;;
    -C)
      CRYPT=1
      LUKSDEV="$2"
      shift 2
      ;;
    -L)
      LVM=1
      shift
      ;;
    -R)
      RAID=1
      shift
      ;;
    *) # unknown, prevent infinite loop
      shift
      ;;
  esac
done

# If kernel modules are needed but the kernel version is absent, exit now:
if [ ! -d /lib/modules/$KERNEL_VERSION ]; then
  echo "ERROR: No /lib/modules/$KERNEL_VERSION kernel modules tree found for kernel \"$KERNEL_VERSION\""
  exit 1
fi

# If clearing source tree was requested, do that first
if [ "$CLEAR_TREE" = "1" ]; then
  clear_source_tree
fi

# If there's no $SOURCE_TREE, make one now:
if [ ! -d "$SOURCE_TREE" ]; then
  create_new_source_tree
fi

# If $ROOTDEV and $ROOTFS are not set, assume we want the
# values for the currently mounted /
# (unless we find that values are already set in the initrd-tree):
if [ -z "$ROOTDEV" -a -z "$(cat $SOURCE_TREE/rootdev 2> /dev/null)" ]; then
  ROOTDEV=$(mount | grep ' on / ' | cut -f 1 -d ' ')
  if [ "$ROOTDEV" = "/dev/root" ]; then # find real root device
    ROOTDEV="/dev/$(readlink /dev/root)"
  fi
fi
if [ -z "$ROOTFS" -a -z "$(cat $SOURCE_TREE/rootfs 2> /dev/null)" ]; then
  ROOTFS=$(mount | grep ' on / ' | cut -f 5 -d ' ')
fi
# If needed, write them in the initrd-tree:
if [ ! -z "$ROOTDEV" ]; then
  echo $ROOTDEV > $SOURCE_TREE/rootdev
fi
if [ ! -z "$ROOTFS" ]; then
  echo $ROOTFS > $SOURCE_TREE/rootfs
fi

# If $WAIT is not set, assume we need only one second
# to have all devices done
# (unless we find that value is already set in the initrd-tree):
if [ -z "$WAIT" -a -z "$(cat $SOURCE_TREE/wait-for-root)" ]; then
  WAIT=1
fi
if [ ! -z "$WAIT" ]; then
  echo $WAIT > $SOURCE_TREE/wait-for-root
fi

# Useful to know which initrd is running:
INITRD_NAME=$(basename $OUTPUT_IMAGE)
echo $INITRD_NAME > $SOURCE_TREE/initrd-name

# Fill /resumedev with the swap partition holding the hibernation image
if [ ! -z "$RESUMEDEV" ]; then
  echo $RESUMEDEV > $SOURCE_TREE/resumedev
fi

# Add custom keymap support if one was given
if [ ! -z "$KEYMAP" ]; then
  echo $KEYMAP > $SOURCE_TREE/keymap
  cp /usr/share/mkinitrd/keymaps.tar.gz $SOURCE_TREE/etc/
fi

# If LUKSDEV was set in the config file, then we need to set CRYPT=1
if [ ! -z "$LUKSDEV" ]; then
  CRYPT=1
fi

# Include RAID support in initrd
if [ ! -z "$RAID" ]; then
  if [ -r /sbin/mdadm ]; then
    mkdir -p $SOURCE_TREE/sbin
    cp /sbin/mdadm $SOURCE_TREE/sbin/mdadm
    chmod 755 $SOURCE_TREE/sbin/mdadm
  else
    echo "ERROR:  mdadm binary is missing, RAID support not installed"
  fi
fi

# Include LVM support in initrd
if [ ! -z "$LVM" ]; then
  if [ -f /sbin/lvm.static ]; then
    mkdir -p $SOURCE_TREE/sbin
    cp /sbin/lvm.static $SOURCE_TREE/sbin/lvm.static
    cp /sbin/dmsetup.static $SOURCE_TREE/sbin/dmsetup.static
    ( cd $SOURCE_TREE/sbin
      ln -s lvm.static vgchange 2>/dev/null
      ln -s lvm.static vgscan 2>/dev/null )
    if [ -z "${MODULE_LIST}" ] ; then
      MODULE_LIST="dm-mod"
    elif ! echo ${MODULE_LIST} | grep -q dm-mod ; then
      MODULE_LIST="$MODULE_LIST:dm-mod"
    fi
  else
    echo "LVM static binary is missing, LVM support isn't installed"
  fi
fi

# Include cryptsetup (LUKS) support in initrd
if [ ! -z "$CRYPT" ]; then
  if [ -e /sbin/cryptsetup.static ]; then
    mkdir -p $SOURCE_TREE/sbin
    cp /sbin/cryptsetup.static $SOURCE_TREE/sbin/cryptsetup.static
    ( cd $SOURCE_TREE/sbin
      ln -s cryptsetup.static cryptsetup 2>/dev/null
    )
    cat << EOF > $SOURCE_TREE/sbin/udevadm
#!/bin/sh
sleep 3
EOF
    chmod 0755 $SOURCE_TREE/sbin/udevadm

    if [ -z "${MODULE_LIST}" ] ; then
      MODULE_LIST="dm-mod"
    elif ! echo ${MODULE_LIST} | grep -q dm-mod ; then
      MODULE_LIST="$MODULE_LIST:dm-mod"
    fi
    # Write the underlying luks device to the initrd-tree:
    echo $LUKSDEV > $SOURCE_TREE/luksdev
  else
    echo "Cryptsetup static binary is missing, CRYPT support isn't installed"
  fi
fi

# Make module directory:
if [ ! -d $SOURCE_TREE/lib/modules/$KERNEL_VERSION ]; then
  mkdir -p $SOURCE_TREE/lib/modules/$KERNEL_VERSION
fi

# If a module list was given, copy the modules into place:
if [ ! -z "$MODULE_LIST" ]; then
  if grep -q "#insmod /lib/modules/2.6.18.8-smp/reiserfs.ko" $SOURCE_TREE/load_kernel_modules ; then
    rm -f $SOURCE_TREE/load_kernel_modules
    touch $SOURCE_TREE/load_kernel_modules
    chmod 755 $SOURCE_TREE/load_kernel_modules
    echo "# This is a script used to load the kernel modules." >> $SOURCE_TREE/load_kernel_modules
    echo "# To use it, chmod it 755, and then add the insmod" >> $SOURCE_TREE/load_kernel_modules
    echo "# lines needed to load your modules, like this:" >> $SOURCE_TREE/load_kernel_modules
    echo >> $SOURCE_TREE/load_kernel_modules
  fi

  # Count number of modules
  # This INDEX number gives us an easy way to find individual
  # modules and their arguments, as well as tells us how many
  # times to run through the list
  if ! echo $MODULE_LIST | grep ':' > /dev/null ; then  # only 1 module specified
    INDEX=1
  else
    INDEX=1
    while [ ! "$(echo "$MODULE_LIST" | cut -f $INDEX -d ':' )" = "" ]; do
      INDEX=$(expr $INDEX + 1)
    done
    INDEX=$(expr $INDEX - 1)      # Don't include the null value
  fi

# Wrap everything in a while loop
i=0
while [ $i -ne $INDEX ]; do
  i=$(( $i + 1 ))

  # FULL_MOD is the module plus any arguments (if any)
  # MODULE is the module name
  # ARGS is any optional arguments to be passed to the kernel
  FULL_MOD="$(echo "$MODULE_LIST" | cut -d ':' -f $i)"
  MODULE="$(echo "$FULL_MOD" | cut -d ' ' -f 1 )"
  # Test for arguments
  if echo "$FULL_MOD" | grep ' ' > /dev/null; then
    ARGS=" $(echo "$FULL_MOD" | cut -d ' ' -f 2- )"
  else
    unset ARGS
  fi

  # Get MODULE deps and prepare insmod lines
  /sbin/modprobe --set-version $KERNEL_VERSION --show-depends --ignore-install $MODULE 2> /dev/null \
    | grep "^insmod " | cut -f 2 -d ' ' | while read SRCMOD; do

    if ! grep -q "$SRCMOD" $SOURCE_TREE/load_kernel_modules 2>/dev/null ; then
      LINE="$(echo "insmod -v $SRCMOD" | sed -e "s/$KERNEL_VERSION/\$(uname -r)/")"

      # Test to see if arguments should be passed
      # Over-ride the previously defined LINE variable if so
      if [ "$(basename $SRCMOD .ko)" = "$MODULE" ]; then
        # SRCMOD and MODULE are same, ARGS can be passed
        LINE="$LINE$ARGS"
      fi

    fi

    if ! grep -qx "$LINE" $SOURCE_TREE/load_kernel_modules ; then
      echo "$LINE" >> $SOURCE_TREE/load_kernel_modules
    fi

    if cp -a --parents $SRCMOD $SOURCE_TREE 2> /dev/null; then
      echo "OK: $SRCMOD added."
    else
      echo "WARNING:  Could not find module \"$SRCMOD\""
    fi

  done

done

fi

# And finally, build the initrd:
build_initrd_image