1#!/bin/sh -x
2
3# SPDX-License-Identifier: Apache-2.0
4# Copyright 2020 IBM Corp.
5
6set -eu
7
8ARG_IF=
9ARG_OF=
10ARG_BS=
11ARG_COUNT=
12ARG_SKIP=
13ARG_SEEK=
14ARG_APPEND=
15ARG_CONV_NOTRUNC=
16DD=/bin/dd
17
18for arg in "$@"
19do
20    case "$arg" in
21        if=*)
22            ARG_IF="${arg#*=}"
23            ;;
24        of=*)
25            ARG_OF="${arg#*=}"
26            ;;
27        bs=*)
28            ARG_BS="${arg#*=}"
29            ;;
30        count=*)
31            ARG_COUNT="${arg#*=}"
32            ;;
33        skip=*)
34            ARG_SKIP="${arg#*=}"
35            ;;
36        seek=*)
37            ARG_SEEK="${arg#*=}"
38            ;;
39        conv=notrunc)
40            ARG_CONV_NOTRUNC=1
41            ;;
42        *)
43            ARG_APPEND+="${arg#*=}"
44            ;;
45    esac
46done
47
48# If conv=notrunc isn't supplied, invoke system dd
49if [ -z "$ARG_CONV_NOTRUNC" ]
50then
51    exec $DD "$@"
52fi
53
54# If conv=notrunc is supplied and system dd supports it, invoke system dd
55if $DD conv=notrunc < /dev/null > /dev/null 2> /dev/null
56then
57    exec $DD "$@"
58fi
59
60# Otherwise, emulate conv=notrunc support
61
62# Examples:
63#
64# Inject foo into bar at offset 100:
65#
66# $ dd if=foo of=bar bs=1 seek=100 conv=notrunc
67if [ "$ARG_IF" = "$ARG_OF" ]
68then
69    >&2 echo "Add support for self-modification"
70    exit 1
71fi
72
73cleanup()
74{
75    rm -f $OF_FILE
76}
77
78filesize()
79{
80    # busybox stat(1) doesn't support --format=%s
81    wc -c "$1" | awk '{print $1}'
82}
83
84trap cleanup EXIT
85
86if [ -z "$ARG_OF" ]
87then
88    DATA_SOURCE=
89else
90    DATA_SOURCE='if='$ARG_OF
91fi
92
93# Intermediate output file
94OF_FILE=$(mktemp)
95
96# Generate the prefix
97if [ -z "$ARG_SEEK" ]
98then
99    PREFIX_COUNT=
100    INSERT_SEEK=
101else
102    PREFIX_COUNT='count='$ARG_SEEK
103    INSERT_SEEK='seek='$ARG_SEEK
104fi
105
106if [ -z "$ARG_BS" ]
107then
108    PREFIX_BS=
109    INSERT_BS=
110else
111    PREFIX_BS='bs='$ARG_BS
112    INSERT_BS='bs='$ARG_BS
113fi
114
115if [ -z "$ARG_SKIP" ]
116then
117    INSERT_SKIP=
118else
119    INSERT_SKIP='skip='$ARG_SKIP
120fi
121
122if [ -z "$ARG_IF" ]
123then
124    INSERT_IF=
125else
126    INSERT_IF='if='$ARG_IF
127fi
128
129if [ -z "$ARG_COUNT" ]
130then
131    INSERT_COUNT=
132else
133    INSERT_COUNT='count='$ARG_COUNT
134fi
135
136# Create the prefix
137$DD $DATA_SOURCE of="$OF_FILE" $PREFIX_BS $PREFIX_COUNT $ARG_APPEND
138OF_UPDATE_OFF=$(filesize "$OF_FILE")
139
140# Append the source data
141dd "$INSERT_IF" of="$OF_FILE" $INSERT_BS $INSERT_COUNT $INSERT_SEEK $INSERT_SKIP
142OF_SUFFIX_OFF=$(filesize "$OF_FILE")
143
144if [ -z "$ARG_OF" ]
145then
146    OF_SUFFIX_OFF=$(($OF_SUFFIX_OFF - $OF_UPDATE_OFF))
147fi
148
149# Append the suffix
150$DD $DATA_SOURCE of="$OF_FILE" bs=1 skip=$OF_SUFFIX_OFF seek=$OF_SUFFIX_OFF $ARG_APPEND
151
152mv "$OF_FILE" "$ARG_OF"
153