d852cf861d526afa7f91163117e79e66ee4b62e1
[kai/samba-autobuild/.git] / ctdb / tests / eventscripts / stubs / ip
1 #!/bin/sh
2
3 not_implemented ()
4 {
5     echo "ip stub command: \"$1\" not implemented"
6     exit 127
7 }
8
9 ######################################################################
10
11 ip_link ()
12 {
13     case "$1" in
14         set)
15             shift
16             # iface="$1"
17             case "$2" in
18                 up)   ip_link_set_up "$1"  ;;
19                 down) ip_link_down_up "$1" ;;
20                 *)    not_implemented "\"$2\" in \"$orig_args\"" ;;
21             esac
22             ;;
23         show) shift ; ip_link_show "$@" ;;
24         del*) shift ; ip_link_delete "$@" ;;
25         *) not_implemented "$*" ;;
26     esac
27 }
28
29 ip_link_delete ()
30 {
31     mkdir -p "${FAKE_IP_STATE}/interfaces-deleted"
32     touch "${FAKE_IP_STATE}/interfaces-deleted/$1"
33 }
34
35 ip_link_set_up ()
36 {
37     rm -f "${FAKE_IP_STATE}/interfaces-down/$1"
38     rm -f "${FAKE_IP_STATE}/interfaces-deleted/$1"
39 }
40
41 ip_link_set_down ()
42 {
43     rm -f "${FAKE_IP_STATE}/interfaces-deleted/$1"
44     mkdir -p "${FAKE_IP_STATE}/interfaces-down"
45     touch "${FAKE_IP_STATE}/interfaces-down/$1"
46 }
47
48 ip_link_show ()
49 {
50     dev="$1"
51     if [ "$dev" = "dev" -a -n "$2" ] ; then
52         dev="$2"
53     fi
54
55     if [ -e "${FAKE_IP_STATE}/interfaces-deleted/$dev" ] ; then
56         echo "Device \"${dev}\" does not exist." >&2
57         exit 255
58     fi
59
60     mac=$(echo $dev | md5sum | sed -r -e 's@(..)(..)(..)(..)(..)(..).*@\1:\2:\3:\4:\5:\6@')
61     _state="UP"
62     _flags=",UP,LOWER_UP"
63     if [ -e "${FAKE_IP_STATE}/interfaces-down/$dev" ] ; then
64         _state="DOWN"
65         _flags=""
66     fi
67     echo "${n}: ${dev}: <BROADCAST,MULTICAST${_flags}> mtu 1500 qdisc pfifo_fast state ${_state} qlen 1000"
68     echo "    link/ether ${mac} brd ff:ff:ff:ff:ff:ff"
69 }
70
71 # This is incomplete because it doesn't actually look up table ids in
72 # /etc/iproute2/rt_tables.  The rules/routes are actually associated
73 # with the name instead of the number.  However, we include a variable
74 # to fake a bad table id.
75 [ -n "$IP_ROUTE_BAD_TABLE_ID" ] || IP_ROUTE_BAD_TABLE_ID=false
76
77 ip_check_table ()
78 {
79     _cmd="$1"
80
81     [ -n "$_table" ] || not_implemented "ip rule/route without \"table\""
82
83     # Only allow tables names from 13.per_ip_routing.  This is a cheap
84     # way of avoiding implementing the default/main/local tables.
85     case "$_table" in
86         ctdb.*)
87             if $IP_ROUTE_BAD_TABLE_ID ; then
88                 # Ouch.  Simulate inconsistent errors from ip.  :-(
89                 case "$_cmd" in
90                     route)
91                         echo "Error: argument "${_table}" is wrong: table id value is invalid" >&2
92                         
93                         ;;
94                     *)
95                         echo "Error: argument "${_table}" is wrong: invalid table ID" >&2
96                 esac
97                 exit 255
98             fi
99             ;;
100         *) not_implemented "table=${_table} ${orig_args}" ;;
101     esac
102 }
103
104 ######################################################################
105
106 ip_addr ()
107 {
108     case "$1" in
109         show|list|"") shift ; ip_addr_show "$@" ;;
110         add*)         shift ; ip_addr_add  "$@" ;;
111         del*)         shift ; ip_addr_del  "$@" ;;
112         *) not_implemented "\"$1\" in \"$orig_args\"" ;;
113     esac
114 }
115
116 ip_addr_show ()
117 {
118     dev=""
119     primary=true
120     secondary=true
121     _to=""
122     while [ -n "$1" ] ; do
123         case "$1" in
124             dev)
125                 dev="$2" ; shift 2
126                 ;;
127             # Do stupid things and stupid things will happen!
128             primary)
129                 primary=true ; secondary=false ; shift
130                 ;;
131             secondary)
132                 secondary=true ; primary=false ; shift
133                 ;;
134             to)
135                 _to="$2" ; shift 2
136                 ;;
137             *)
138                 # Assume an interface name
139                 dev="$1" ; shift 1
140         esac
141     done
142     devices="$dev"
143     if [ -z "$devices" ] ; then
144         # No device specified?  Get all the primaries...
145         devices=$(ls "${FAKE_IP_STATE}/addresses/"*-primary 2>/dev/null | \
146             sed -e 's@.*/@@' -e 's@-primary$@@')
147     fi
148     calc_brd ()
149     {
150         case "${local#*/}" in
151             24)
152                 brd="${local%.*}.255"
153                 ;;
154             *)
155                 not_implemented "list ... fake bits other than 24: ${local#*/}"
156         esac
157     }
158     show_iface()
159     {
160         pf="${FAKE_IP_STATE}/addresses/${dev}-primary"
161         sf="${FAKE_IP_STATE}/addresses/${dev}-secondary"
162         ip_link_show "$dev"
163         if $primary && [ -r "$pf" ] ; then
164             read local <"$pf"
165             if [ -z "$_to" -o "${_to%/*}" = "${local%/*}" ] ; then
166                 calc_brd
167                 echo "    inet ${local} brd ${brd} scope global ${dev}"
168             fi
169         fi
170         if $secondary && [ -r "$sf" ] ; then
171             while read local ; do
172                 if [ -z "$_to" -o "${_to%/*}" = "${local%/*}" ] ; then
173                     calc_brd
174                     echo "    inet ${local} brd ${brd} scope global secondary ${dev}"
175                 fi
176             done <"$sf"
177         fi
178         if [ -z "$_to" ] ; then
179             echo "       valid_lft forever preferred_lft forever"
180         fi
181     }
182     n=1
183     for dev in $devices ; do
184         if [ -z "$_to" ] || \
185             grep -F "${_to%/*}/" "${FAKE_IP_STATE}/addresses/${dev}-"* >/dev/null ; then
186             show_iface
187         fi
188         n=$(($n + 1))
189     done
190 }
191
192 ip_addr_add ()
193 {
194     local=""
195     dev=""
196     brd=""
197     while [ -n "$1" ] ; do
198         case "$1" in
199             *.*.*.*/*)
200                 local="$1" ; shift
201                 ;;
202             local)
203                 local="$2" ; shift 2
204                 ;;
205             broadcast|brd)
206                 # For now assume this is always '+'.
207                 if [ "$2" != "+" ] ; then
208                     not_implemented "addr add ... brd $2 ..."
209                 fi
210                 shift 2
211                 ;;
212             dev)
213                 dev="$2" ; shift 2
214                 ;;
215             *)
216                 not_implemented "$@"
217         esac
218     done
219     if [ -z "$dev" ] ; then
220         not_implemented "addr add (without dev)"
221     fi
222     mkdir -p "${FAKE_IP_STATE}/addresses"
223     pf="${FAKE_IP_STATE}/addresses/${dev}-primary"
224     sf="${FAKE_IP_STATE}/addresses/${dev}-secondary"
225     # We could lock here... but we should be the only ones playing
226     # around here with these stubs.
227     if [ ! -f "$pf" ] ; then
228         echo "$local" >"$pf"
229     elif grep -Fq "$local" "$pf" ; then 
230         echo "RTNETLINK answers: File exists" >&2
231         exit 254
232     elif [ -f "$sf" ] && grep -Fq "$local" "$sf" ; then 
233         echo "RTNETLINK answers: File exists" >&2
234         exit 254
235     else
236         echo "$local" >>"$sf"
237     fi
238 }
239
240 ip_addr_del ()
241 {
242     local=""
243     dev=""
244     while [ -n "$1" ] ; do
245         case "$1" in
246             *.*.*.*/*)
247                 local="$1" ; shift
248                 ;;
249             local)
250                 local="$2" ; shift 2
251                 ;;
252             dev)
253                 dev="$2" ; shift 2
254                 ;;
255             *)
256                 not_implemented "addr del ... $1 ..."
257         esac
258     done
259     if [ -z "$dev" ] ; then
260         not_implemented "addr del (without dev)"
261     fi
262     mkdir -p "${FAKE_IP_STATE}/addresses"
263     pf="${FAKE_IP_STATE}/addresses/${dev}-primary"
264     sf="${FAKE_IP_STATE}/addresses/${dev}-secondary"
265     # We could lock here... but we should be the only ones playing
266     # around here with these stubs.
267     if [ ! -f "$pf" ] ; then
268         echo "RTNETLINK answers: Cannot assign requested address" >&2
269         exit 254
270     elif grep -Fq "$local" "$pf" ; then
271         # Remove primaries AND SECONDARIES.
272         rm -f "$pf" "$sf"
273     elif [ -f "$sf" ] && grep -Fq "$local" "$sf" ; then 
274         grep -Fv "$local" "$sf" >"${sf}.new"
275         mv "${sf}.new" "$sf"
276     else
277         echo "RTNETLINK answers: Cannot assign requested address" >&2
278         exit 254
279     fi
280 }
281
282 ######################################################################
283
284 ip_rule ()
285 {
286     case "$1" in
287         show|list|"") shift ; ip_rule_show "$@" ;;
288         add)          shift ; ip_rule_add  "$@" ;;
289         del*)         shift ; ip_rule_del  "$@" ;;
290         *) not_implemented "$1 in \"$orig_args\"" ;;
291     esac
292
293 }
294
295 # All non-default rules are in $FAKE_IP_STATE_RULES/rules.  As with
296 # the real version, rules can be repeated.  Deleting just deletes the
297 # 1st match.
298
299 ip_rule_show ()
300 {
301     ip_rule_show_1 ()
302     {
303         _pre="$1"
304         _table="$2"
305         _selectors="$3"
306         # potentially more options
307
308         printf "%d:\t%s lookup %s \n" $_pre "$_selectors" "$_table"
309     }
310
311     ip_rule_show_some ()
312     {
313         _min="$1"
314         _max="$2"
315
316         [ -f "${FAKE_IP_STATE}/rules" ] || return
317
318         while read _pre _table _selectors ; do
319             # Only print those in range
320             [ $_min -le $_pre -a $_pre -le $_max ] || continue
321
322             ip_rule_show_1 $_pre "$_table" "$_selectors"
323         done <"${FAKE_IP_STATE}/rules"
324     }
325
326     ip_rule_show_1 0 "local" "from all"
327
328     ip_rule_show_some 1 32765
329
330     ip_rule_show_1 32766 "main" "from all"
331     ip_rule_show_1 32767 "default" "from all"
332
333     ip_rule_show_some 32768 2147483648
334 }
335
336 ip_rule_common ()
337 {
338     _from=""
339     _pre=""
340     _table=""
341     while [ -n "$1" ] ; do
342         case "$1" in
343             from)  _from="$2"  ; shift 2 ;;
344             pref)  _pre="$2"   ; shift 2 ;;
345             table) _table="$2" ; shift 2 ;;
346             *) not_implemented "$1 in \"$orig_args\"" ;;
347         esac
348     done
349
350     [ -n "$_pre" ]   || not_implemented "ip rule without \"pref\""
351     ip_check_table "rule"
352     # Relax this if more selectors added later...
353     [ -n "$_from" ]  || not_implemented "ip rule without \"from\""
354 }
355
356 ip_rule_add ()
357 {
358     ip_rule_common "$@"
359
360     _f="${FAKE_IP_STATE}/rules"
361     touch "$_f"
362     (
363         flock 0
364         # Filter order must be consistent with the comparison in ip_rule_del()
365         echo "$_pre $_table${_from:+ from }$_from" >>"$_f"
366     ) <"$_f"
367 }
368
369 ip_rule_del ()
370 {
371     ip_rule_common "$@"
372
373     _f="${FAKE_IP_STATE}/rules"
374     touch "$_f"
375     (
376         flock 0
377         _tmp="$(mktemp)"
378         _found=false
379         while read _p _t _s ; do
380             if ! $_found && \
381                 [ "$_p" = "$_pre" -a "$_t" = "$_table" -a \
382                 "$_s" = "${_from:+from }$_from" ] ; then
383                 # Found.  Skip this one but not future ones.
384                 _found=true
385             else
386                 echo "$_p $_t $_s" >>"$_tmp"
387             fi
388         done
389         if cmp -s "$_tmp" "$_f" ; then
390             # No changes, must not have found what we wanted to delete
391             echo "RTNETLINK answers: No such file or directory" >&2
392             rm -f "$_tmp"
393             exit 2
394         else
395             mv "$_tmp" "$_f"
396         fi
397     ) <"$_f" || exit $?
398 }
399
400 ######################################################################
401
402 ip_route ()
403 {
404     case "$1" in
405         show|list)    shift ; ip_route_show  "$@" ;;
406         flush)        shift ; ip_route_flush "$@" ;;
407         add)          shift ; ip_route_add   "$@" ;;
408         *) not_implemented "$1 in \"ip route\"" ;;
409     esac
410 }
411
412 ip_route_common ()
413 {
414     [ "$1" = table ] || not_implemented "$1 in \"$orig_args\""
415     _table="$2"
416
417     ip_check_table "route"
418 }
419
420 # Routes are in a file per table in the directory
421 # $FAKE_IP_STATE/routes.  These routes just use the table ID
422 # that is passed and don't do any lookup.  This could be "improved" if
423 # necessary.
424
425 ip_route_show ()
426 {
427     ip_route_common "$@"
428
429     # Missing file is just an empty table
430     cat "$FAKE_IP_STATE/routes/${_table}" 2>/dev/null || true
431 }
432
433 ip_route_flush ()
434 {
435     ip_route_common "$@"
436
437     rm -f "$FAKE_IP_STATE/routes/${_table}"
438 }
439
440 ip_route_add ()
441 {
442     _prefix=""
443     _dev=""
444     _gw=""
445     _table=""
446
447     while [ -n "$1" ] ; do
448         case "$1" in
449             *.*.*.*/*|*.*.*.*) _prefix="$1" ; shift 1 ;;
450             local) _prefix="$2" ; shift 2 ;;
451             dev)   _dev="$2"   ; shift 2 ;;
452             via)   _gw="$2"    ; shift 2 ;;
453             table) _table="$2" ; shift 2 ;;
454             *) not_implemented "$1 in \"$orig_args\"" ;;
455         esac
456     done
457
458     ip_check_table "route"
459     [ -n "$_prefix" ] || not_implemented "ip route without inet prefix in \"$orig_args\""
460     [ -n "$_dev" ] || not_implemented "ip route without \"dev\" in \"$orig_args\""
461
462     # Alias or add missing bits
463     case "$_prefix" in
464         0.0.0.0/0) _prefix="default" ;;
465         */*) : ;;
466         *) _prefix="${_prefix}/32" ;;
467     esac
468
469     _f="$FAKE_IP_STATE/routes/${_table}"
470     mkdir -p "$FAKE_IP_STATE/routes"
471     touch "$_f"
472
473     (
474         flock 0
475
476         if [ -n "$_gw" ] ; then
477             echo "${_prefix} via ${_gw} dev ${_dev} "
478         else
479             echo "${_prefix} dev ${_dev}  scope link "
480         fi >>"$_f"
481     ) <"$_f"
482 }
483
484
485 ######################################################################
486
487 orig_args="$*"
488
489 case "$1" in
490     link)   shift ; ip_link  "$@" ;;
491     addr*)  shift ; ip_addr  "$@" ;;
492     rule)   shift ; ip_rule  "$@" ;;
493     route)  shift ; ip_route "$@" ;;
494     *) not_implemented "$1" ;;
495 esac
496
497 exit 0