aboutsummaryrefslogtreecommitdiffstats
path: root/packages/openslug-init/openslug-init-0.10/functions
blob: 55f339746275f59283b0a2172d8fb00f82020d5e (plain)
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
# . this file to load the following utility functions
#
# mtdev "name"
#  return (output) the character device name for flash parition "name"
#  /proc/mtd has the general form:
#    dev:    size   erasesize  name
#    mtd5: 00020000 00020000 "FIS directory"
#  use this rather than hard-wiring the device because the partition
#  table can change - looking in /proc/mtd is more reliable.
mtdev(){
	sed -n 's!^\(mtd[0-9][0-9]*\):[^"]*"'"$1"'"$!/dev/\1!p' /proc/mtd
}
#
# mtblockdev "name"
#  as mtdev but output the name of the block (not character) device
mtblockdev(){
	sed -n 's!^mtd\([0-9][0-9]*\):[^"]*"'"$1"'"$!/dev/mtdblock\1!p' /proc/mtd
}
#
# mtsize "name"
#  the size of the partition as a hexadecimal value (with 0x at the front)
mtsize(){
	sed -n 's!^mtd[0-9][0-9]*: \([^ ]*\)[^"]*"'"$1"'"$!0x\1!p' /proc/mtd
}
#
# sysvalmatch "section" "name" 'pattern' "configuration file"
# sysvalof "section" "name" "configuration file"
# sysval "section" "name"
#  outputs the value of the SysConf variable 'name' from section 'section',
#  this is a bit gross, when it gets a match it copies the value to the
#  hold space, if no match it jumps over the copy, at the end ($) it copies
#  the hold space to the pattern space and prints the result, thus it only
#  ever prints the last match
# BUG FIX: busybox sed doesn't initialise the hold space and crashes if it
#  is used before initialisation, so temporarily this script does it's own
#  tail by hand.
# NOTE: these functions should only be used internally, add entries to 'config'
#  below if necessary.  This is because 'config' does the defaulting and in the
#  recovering case (zero or absent SysConf) /etc/default/sysconf only contains
#  the hw_addr entry!
sysvalmatch(){
	# sed -n '/^\['"$1"'\]$/,/^\[.*\]$/s/^'"$2"'=\('"$3"'\)$/\1/;tH;bE;:H;h;:E;$g;$p' "$4"
	sed -n '/^\['"$1"'\]$/,/^\[.*\]$/s/^'"$2"'=\('"$3"'\)$/\1/p' "$4" | sed -n '$p'
}
sysvalof(){
	sysvalmatch "$1" "$2" '.*' "$3"
}
sysval(){
	sysvalof "$1" "$2" /etc/default/sysconf
}
#
# config "value"
#  convenience callers for specific values to avoid mis-typing in scripts
#  NOTE: this function does the defaulting, 'sysval' does not!  Validity
#  of the sysconf file is determined by the presence of the all important
#  hw_addr.
config(){
	local mac
	mac=
	test -r /etc/default/sysconf &&
		mac="$(sysvalmatch network hw_addr '[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]:[0-9A-Za-z][0-9A-Za-z]' /etc/default/sysconf)"
	if test -n "$mac"
	then
		case "$1" in
		mac)	echo "$mac";;
		host)	if test -n "$(sysval network disk_server_name)"
			then
				sysval network disk_server_name
			elif test -n "$(sysval network default_server_name)"
			then
				sysval network default_server_name
			else
				echo "$mac" | sed -n 's/^..:..:..:\(..\):\(..\):\(..\)$/LKG\1\2\3/p'
			fi;;
		domain)	sysval network w_d_name;;
		iface)  if test -n "$(sysval network lan_interface)"
			then
				sysval network lan_interface
			else
				echo eth0
			fi;;
		ip)	if test -n "$(sysval network ip_addr)"
			then
				sysval network ip_addr
			else
				echo 192.168.1.77
			fi;;
		netmask)sysval network netmask;;
		gateway)sysval network gateway;;
		dns)	sysval network dns_server1;;
		dns2)	sysval network dns_server2;;
		dns3)	sysval network dns_server3;;
		boot)	if test -n "$(sysval network bootproto)"
			then
				sysval network bootproto
			else
				echo dhcp
			fi;;
		valid)	return 0;;
		*)	return 1;;
		esac
	else
		# These are the defaults for an invalid mac address, use the compiled
		# in hardware address.
		case "$1" in
		mac)	echo "00:02:B3:02:02:01";;
		host)	echo "brokenslug";;
		iface)  echo eth0;;
		ip)	echo 192.168.1.77;;
		boot)	echo dhcp;;
		*)	return 1;;
		esac
	fi
}
#
# checkif "iface"
#  Validate an interface name by making sure that it exists
#  in /proc/net/dev (and is not lo).  The listing outputs the
#  interface followed by a :, the check function looks for
#  something of the form '$1[a-zA-Z0-9]*:' and outputs the
#  part preceding the ':'
checkif(){
	sed -n '/^[ 	]*lo:/d;s/^[ 	]*\('"$1"'[a-zA-Z0-9]*\):.*$/\1/p;tE;d;:E;q' /proc/net/dev
}
#
# checkmount "mountpoint"
#  tests an already mounted mountpoint to see whether to attempt to
#  boot with this as root.  Returns success if it appears ok.
checkmount(){
	# basic test for init (the kernel will try to load this)
	# but require a shell in bin/sh and no .recovery too
	test	\( ! -f "$1/.recovery" \) -a \
		\( -d "$1/initrd" -o -d "$1/mnt" \) -a \
		\( -x "$1/bin/sh" -o -h "$1/bin/sh" \) -a \
		\( -x "$1/sbin/init" -o -h "$1/sbin/init" -o \
		-x "$1/etc/init" -o -h "$1/etc/init" -o \
		-x "$1/bin/init" -o -h "$1/bin/init" \)
}
#
# swivel "new root" "old root"
#  NOTE: the arguments must be paths relative to /, bad things
#  will happen if the arguments themselves start with /
#  Pivot to a new root.  This does all the fancy pivot_root stuff
#  including closing streams and does a umount /proc - it doesn't
#  matter if this fails (failure codes are ignored), but if /proc
#  was mounted it must be restored by the caller on return.
#  Normally this function never returns!
#  On return 0,1,2 are connected to /dev/console - this may not
#  have been true before!
swivel() {
	cd "$1"
	exec <&- >&- 2>&-
	# This is just-in-case the called mounted /proc and was
	# unable to close it because of the streams
	umount /proc 2>/dev/null
	if pivot_root . "$2"
	then
		# everything must move out of the old root, this process
		# is $2/bin/sh so it must die, IO is redirected
		# just in case - typically it will be to a device so it
		# won't hold the old root open.
		# the exec here is the first point at which the old root
		# is unused - before the exec regardless of the close of
		# 0,1,2 above ash still has *this* shell script open!
		# (it's on fd 10).
		# init closes all file descriptors, there's no point
		# supplying it with fds.
		exec "$2/usr/sbin/chroot" . bin/sh -c "\
			test -x sbin/init && exec sbin/init
			test -x etc/init && exec etc/init
			test -x bin/init && exec bin/init
			leds -A +gr1 '!g1'
			sleep 10 >/.recovery
			sync;sync;sync
			exit 1"
	fi
	#
	# recovery - must restore the old root
	cd "$2"
	sbin/pivot_root . "$1"
	# cd is back to $1 - either pivot_root doesn't change it and the
	# chroot above was not executed, or pivot_root does change it and
	# has just changed it back!
	exec <>/dev/console >&0 2>&0
}
#
# ifup "interface"
#  bring that interface up with the configured ip and other
#  information
ifup(){
	local ip hostname router subnet iface HOSTNAME NETMASK BROADCAST

	iface="$1"
	ip="$(config ip)"
	hostname="$(config host)"
	router="$(config gateway)"
	broadcast=

	if test -n "$ip"
	then
		# only if an ip was specified
		subnet="$(config netmask)"
	else
		ip=192.168.1.77
	fi

	# First try udhcpc - note that the /boot/udhcpc.script
	# simply records the values returned and the udhcpc
	# is not left running so this will only work for
	# the lease length time!
	ifconfig "$iface" up
	if test "$(config boot)" != static
	then
		test -n "$hostname" && HOSTNAME="-H $hostname"
		# The script writes the required shell variable assignments
		# to file descriptor 9
		eval $(udhcpc -i "$iface" -n -q -r "$ip" $HOSTNAME -s /boot/udhcpc.script 9>&1 >/dev/null)
	fi

	test -n "$broadcast" && BROADCAST="broadcast $broadcast"
	test -n "$subnet" && NETMASK="netmask $subnet"

	if ifconfig "$iface" "$ip" $NETMASK $BROADCAST
	then
		for route in $router
		do
			route add default gw "$route" dev "$iface"
		done
		return 0
	else
		ifconfig "$iface" down
		return 1
	fi
}
#
# ifdown "interface"
#  take the interface down
ifdown(){
	ifconfig "$1" down
}
#
# mountflash "flash device" "flash root directory" {mount options}
#  Finds and mounts the flash file system on the given directory
mountflash() {
	local ffsdev ffsdir

	ffsdev="$1"
	test -n "$ffsdev" -a -b "$ffsdev" || {
		echo "$0: unable to find flash file system to copy ($ffsdev)" >&2
		return 1
	}
	shift

	ffsdir="$1"
	test -n "$ffsdir" -a -d "$ffsdir" || {
		echo "$0: mountflash $ffsdir: not a directory (internal error)" >&2
		return 1
	}
	shift

	mount -t jffs2 "$@" "$ffsdev" "$ffsdir" || {
		echo "$0: $ffsdev: unable to mount flash file system on $ffsdir" >&2
		return 1
	}
	return 0
}
#
# umountflash [-r] "flash device"
#  unmount any instance of the given flash device, if -r is specified a mount on
#  root is an error, otherwise a mount on root is ignored (and remains).
umountflash() {
	local rootok ffsno ffsdev
	rootok=1
	case "$1" in
	-r)	rootok=
		shift;;
	esac
	#
	# The argument is ffsdev
	ffsdev="$1"
	ffsno="$(devio "<<$ffsdev" prd)"
	test -n "$ffsno" -a "$ffsno" -ge 0 || {
		echo "$0: $ffsdev: device number $ffsno is not valid, cannot continue." >&2
		return 1
	}
	#
	# Make sure that Flashdisk isn't mounted on /
	if test -z "$rootok" -a "$(devio "<</etc/init.d/sysconfsetup" prd)" -eq "$ffsno"
	then
		echo "$0: $ffsdev is mounted on /, use turnup ram" >&2
		return 1
	fi
	#
	# The function is currently always used interactively, so output 
	echo "$0: umounting any existing mount of $ffsdev" >&2
	#
	# check each mount point, do this last first because otherwise nested
	# mounts of ffsdev cannot be umounted.
	ffs_umount() {
		local device mp type options stuff

		read device mp type options stuff
		test -z "$device" && return 0

		# handle following entries first
		ffs_umount || return 1

		# handle this entry, since this is currently only used for unmounting
		# the flash root partition we know a file which must exist...
		case "$mp/$type" in
		//jffs2);; # skip /
		*/jffs2)test "$(devio "<<$mp/etc/init.d/sysconfsetup" prd 2>/dev/null)" -ne "$ffsno" ||
			umount "$mp" || {
				echo "$0: $mp: unable to umount $ffsdev" >&2
				return 1
			};;
		esac

		return 0
	}
	#
	ffs_umount </proc/mounts || {
		echo "$0: umount $ffsdev from all mount points then re-run reflash" >&2
		return 1
	}

	return 0
}