#!/bin/bash # # Copyright (C) 2010 Bart Trojanowski # # This script imports patches generated from a linux/klips git tree into # an libreswan git tree. set -e prog=$(basename $0) say() { echo >&2 "$@" } warn() { say "$prog: $@" } die() { warn "$@" exit 1 } do_help() { local err=$1 local out=1 [[ -n "$err" && "$err" -eq 0 ]] || out=2 cat >&$out <] --patch[=] - import from stdin, -p is passed to patch (default is 1) Or import from an existing linux-2.6.git tree with klips applied: $prog -k [ -n ] [ -h ] -k --kernel - path to kernel git tree -n --number - number of patches to import (default is 1) -r --head - git ref/head to start from (default is HEAD) Generic options: -h --help - this help --dry-run - don't apply anything -q --quiet - pass quiet flag to git-am -t --tmp-dir - use this temporary directory END exit $err } # set defaults kernel_mode=false patch_mode=false dryrun_mode=false arg_head= arg_kernel= arg_count= arg_pnum= arg_quiet= arg_tmpdir=/tmp # this will queue a patch if it looks like it would apply queue_patch() { local queue="$1" local patch="$2" # make sure this patch contains only changes to files we care about diffstat -l -p1 "$patch" \ | while read fn ; do local dir=$(dirname "$fn") if ! [[ -d "linux/$dir" ]] ; then fn=$(basename "$fn") warn "Patch modifies $fn in $dir, but linux/$dir is not an libreswan" warn "directory. You could 'mkdir $dir' to skip this warning." exit 1 fi done # convert paths to contain linux/ prefix sed -ie 's,^\(\(---\|+++\) \([a-z]\+/\)\{'"$arg_pnum"'\}\)\(.*\)$,\1linux/\4,' "$patch" # add it to the queue cat "$patch" >> "$queue" # check if the patch applies (including all the ones that came before it git apply --check -p"$arg_pnum" "$queue" || die "patch doesn't apply" } apply_queue() { local queue="$1" $dryrun_mode && return 0 # import the patch git am < "$queue" } is_git_dir() { local dir="$1" [[ -d "$dir" \ && -f "$dir/HEAD" \ && -d "$dir/objects" \ && -d "$dir/refs" ]] } find_kernel_git_dir() { for dir in "$arg_kernel" "$arg_kernel/.git" ; do if is_git_dir "$dir" ; then echo "$dir" return 0 fi done die "cannot find git dir at $arg_kernel" } # imports $arg_count patches from $arg_kernel do_kernel_import() { local workdir="$arg_tmpdir/$prog-$$" local series="$workdir/series" local queue="$workdir/queue" [[ -d $workdir ]] && die "$workdir already exists, remove it" mkdir -p "$workdir" || die "failed to create: $workdir" trap "rm -rf $workdir" EXIT HUP INT QUIT ABRT # find the kernel dir local kernel_git=$(find_kernel_git_dir) # generate those patches git --git-dir "$kernel_git" \ format-patch \ -"$arg_count" \ --suffix=.patch \ --output-directory "$workdir" \ "$arg_head" \ > "$series" \ || die "failed to generate $arg_count patch(es) in from $kernel_git" for patch in $(cat "$series") ; do local name=$(basename "$patch") say "Testing $name..." queue_patch "$queue" "$patch" done say "Looks good, now applying..." apply_queue "$queue" say "DONE" } # import patch read from /dev/stdin do_patch_from_stdin() { local patch="$arg_tmpdir/$prog-$$.patch" local queue="$arg_tmpdir/$prog-$$.queue" trap "rm -f $patch $queue" EXIT HUP INT QUIT ABRT # read in the patch cat > "$patch" # reset the queue cat "$queue" say "Testing patch from stdin..." queue_patch "$queue" "$patch" say "Looks good, now applying..." apply_queue "$queue" say "DONE" } # parse parameters while [[ -n "$1" ]] ; do cmd="$1" shift case "$cmd" in -h|--help) do_help 0 ;; --dry-run) dryrun_mode=true ;; --debug) set -x ;; -r|--head) arg_head="$1" shift || die "--head requires an argument" ;; -k|--kernel) kernel_mode=true arg_kernel="$1" [[ -d "$arg_kernel" ]] || die "no such directory: $arg_kernel" shift ;; -p|--patch) patch_mode=true ;; -p[0-9]*) patch_mode=true arg_pnum="${cmd#-p}" ;; --patch=[0-9]*) patch_mode=true arg_pnum="${cmd#*=}" ;; -n|--number) arg_count="$1" shift || die "--number requires an argument" ;; -[0-9]*) arg_count="${cmd#-}" ;; -q|--quiet) arg_quiet="--quiet" ;; -t|--tmp-dir) arg_tmpdir="$1" [[ -d "$arg_tmpdir" ]] || die "no such directory: $arg_tmpdir" shift ;; *) warn "invalid option: $cmd" do_help 1 ;; esac done ( $kernel_mode || $patch_mode ) || die "need to use --kernel or --patch mode" ( $kernel_mode && $patch_mode ) && die "only use --kernel or --patch mode" for n in diffstat filterdiff ; do $n --help /dev/null 2>&1 || die "cannot find '$n' (part of patchutils package)" done if [[ -z "$arg_pnum" ]] ; then arg_pnum=1 elif [[ "$arg_pnum" -gt 0 ]] ; then die "--patch/-p level must be a number" fi if $kernel_mode; then [[ -z "$arg_count" ]] && arg_count=1 [[ -z "$arg_head" ]] && arg_head=HEAD do_kernel_import ret=$? elif $patch_mode; then do_patch_from_stdin ret=$? else ret=1 fi exit $ret