#!/bin/sh # initrd-do - run a command within an initrd # Copyright (C) 2008 Loïc Minier # Copyright (C) 2011 Linaro Limited # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the "Software"), # to deal in the Software without restriction, including without limitation # the rights to use, copy, modify, merge, publish, distribute, sublicense, # and/or sell copies of the Software, and to permit persons to whom the # Software is furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL # SOFTWARE IN THE PUBLIC INTEREST, INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # DEALINGS IN THE SOFTWARE. # # Except as contained in this notice, the name of the author shall not be used # in advertising or otherwise to promote the sale, use or other dealings in # this Software without prior written authorization from the author. # # depends: sudo set -e self="$(basename "$0")" work_dir="" new_initrd="" log() { echo "$*" >&2 } log_i() { log "I:" "$@" } log_w() { log "W:" "$@" } die() { log "E:" "$@" exit 1 } usage() { log "Usage: $self --initrd [-c [ ...]]" } getshell() { if [ -n "$SHELL" ]; then echo "$SHELL" return fi PASSWD="$(getent passwd $(id -u) | sed -n 's/.*://p')" if [ -n "$PASSWD" ]; then echo "$PASSWD" return fi echo "/bin/sh" } escape() { echo "$*" | sed "s/'/'\"'\"'/g; s/.*/'&'/" } # unused; use eval unescape () { eval "echo" "$*" } cleanup() { if [ -n "$new_initrd" ]; then rm -f "$new_initrd" fi if [ -n "$work_dir" ]; then rm -rf "$work_dir" fi } trap "cleanup" 0 1 2 3 9 11 13 15 initrd="" command="$(escape "$(getshell)")" while [ $# -gt 0 ]; do case $1 in --help) usage exit 0 ;; -i|--initrd) shift initrd="$1" if ! shift; then die "Need an initrd file after --initrd" fi ;; -c) shift if [ $# -le 0 ]; then die "Need a command after -c" fi command="" while :; do command="$command $(escape "$1")" shift if [ $# -eq 0 ]; then break fi done break ;; *) # clever handling of args: set initrd first if unset, otherwise set # command if [ -z "$initrd" ]; then initrd="$1" shift else command="" while :; do command="$command $(escape "$1")" shift if [ $# -eq 0 ]; then break fi done fi ;; esac done if [ -z "$initrd" ]; then usage exit 1 fi work_dir="$(mktemp -dt "$self.XXXXXXXXXX")" # subshell to not touch cwd as we will nuke it ( cd "$work_dir" log_i "Unpacking initrd $initrd" gunzip -c <"$initrd" | cpio -i --quiet log_i "Running command:" $command eval $command ) err=$? if [ 0 != $err ]; then log_w "Command exited with $err; aborting" exit 1 fi log_i "Generating new initrd" new_initrd="$(mktemp -t "$self.XXXXXXXXXX")" # subshell to not touch cwd as we will nuke it ( cd "$work_dir" find . | cpio -o -H newc -R 0:0 --quiet | gzip -c >"$new_initrd" ) log_i "Moving new initrd to $initrd" mv -f "$new_initrd" "$initrd"