removed whitespace
[strongswan.git] / testing / hosts / winnetou / etc / init.d / net.eth0
1 #!/sbin/runscript
2 # Copyright (c) 2004-2006 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4
5 # Contributed by Roy Marples (uberlord@gentoo.org)
6 # Many thanks to Aron Griffis (agriffis@gentoo.org)
7 # for help, ideas and patches
8
9 #NB: Config is in /etc/conf.d/net
10
11 # For pcmcia users. note that pcmcia must be added to the same
12 # runlevel as the net.* script that needs it.
13 depend() {
14         need localmount
15         after bootmisc hostname
16         use isapnp isdn pcmcia usb wlan
17
18         # Load any custom depend functions for the given interface
19         # For example, br0 may need eth0 and eth1
20         local iface="${SVCNAME#*.}"
21         [[ $(type -t "depend_${iface}") == "function" ]] && depend_${iface}
22
23         if [[ ${iface} != "lo" && ${iface} != "lo0" ]] ; then
24                 after net.lo net.lo0
25
26                 # Support new style RC_NEED and RC_USE in one net file
27                 local x="RC_NEED_${iface}"
28                 [[ -n ${!x} ]] && need ${!x}
29                 x="RC_USE_${iface}"
30                 [[ -n ${!x} ]] && use ${!x}
31         fi
32
33         return 0
34 }
35
36 # Define where our modules are
37 MODULES_DIR="${svclib}/net"
38
39 # Make some wrappers to fudge after/before/need/use depend flags.
40 # These are callbacks so MODULE will be set.
41 after() {
42         eval "${MODULE}_after() { echo \"$*\"; }"
43 }
44 before() {
45         eval "${MODULE}_before() { echo \"$*\"; }"
46 }
47 need() {
48         eval "${MODULE}_need() { echo \"$*\"; }"
49 }
50 installed() {
51         # We deliberately misspell this as _installed will probably be used
52         # at some point
53         eval "${MODULE}_instlled() { echo \"$*\"; }"
54 }
55 provide() {
56         eval "${MODULE}_provide() { echo \"$*\"; }"
57 }
58 functions() {
59         eval "${MODULE}_functions() { echo \"$*\"; }"
60 }
61 variables() {
62         eval "${MODULE}_variables() { echo \"$*\"; }"
63 }
64
65 is_loopback() {
66         [[ $1 == "lo" || $1 == "lo0" ]]
67 }
68
69 # char* interface_device(char *iface)
70 #
71 # Gets the base device of the interface
72 # Can handle eth0:1 and eth0.1
73 # Which returns eth0 in this case
74 interface_device() {
75         local dev="${1%%.*}"
76         [[ ${dev} == "$1" ]] && dev="${1%%:*}"
77         echo "${dev}"
78 }
79
80 # char* interface_type(char* iface)
81 #
82 # Returns the base type of the interface
83 # eth, ippp, etc
84 interface_type() {
85         echo "${1%%[0-9]*}"
86 }
87
88 # int calculate_metric(char *interface, int base)
89 #
90 # Calculates the best metric for the interface
91 # We use this when we add routes so we can prefer interfaces over each other
92 calculate_metric() {
93         local iface="$1" metric="$2"
94
95         # Have we already got a metric?
96         local m=$(awk '$1=="'${iface}'" && $2=="00000000" { print $7 }' \
97                 /proc/net/route)
98         if [[ -n ${m} ]] ; then
99                 echo "${m}"
100                 return 0
101         fi
102
103         local i= dest= gw= flags= ref= u= m= mtu= metrics=
104         while read i dest gw flags ref u m mtu ; do
105                 # Ignore lo
106                 is_loopback "${i}" && continue
107                 # We work out metrics from default routes only
108                 [[ ${dest} != "00000000" || ${gw} == "00000000" ]] && continue
109                 metrics="${metrics}\n${m}"
110         done < /proc/net/route
111
112         # Now, sort our metrics
113         metrics=$(echo -e "${metrics}" | sort -n)
114
115         # Now, find the lowest we can use
116         local gotbase=false
117         for m in ${metrics} ; do
118                 [[ ${m} -lt ${metric} ]] && continue
119                 [[ ${m} == ${metric} ]] && ((metric++))
120                 [[ ${m} -gt ${metric} ]] && break
121         done
122         
123         echo "${metric}"
124 }
125
126 # int netmask2cidr(char *netmask)
127 #
128 # Returns the CIDR of a given netmask
129 netmask2cidr() {
130         local binary= i= bin=
131
132         for i in ${1//./ }; do
133                 bin=""
134                 while [[ ${i} != "0" ]] ; do
135                         bin=$[${i}%2]${bin}
136                         (( i=i>>1 ))
137                 done
138                 binary="${binary}${bin}"
139         done
140         binary="${binary%%0*}"
141         echo "${#binary}"
142 }
143
144
145 # bool is_function(char* name)
146 #
147 # Returns 0 if the given name is a shell function, otherwise 1
148 is_function() {
149         [[ -z $1 ]] && return 1
150         [[ $(type -t "$1") == "function" ]]
151 }
152
153 # void function_wrap(char* source, char* target)
154 #
155 # wraps function calls - for example function_wrap(this, that)
156 # maps function names this_* to that_*
157 function_wrap() {
158         local i=
159
160         is_function "${2}_depend" && return
161
162         for i in $(typeset -f | grep -o '^'"${1}"'_[^ ]*'); do
163                 eval "${2}${i#${1}}() { ${i} \"\$@\"; }"
164         done
165 }
166
167 # char[] * expand_parameters(char *cmd)
168 #
169 # Returns an array after expanding parameters. For example
170 # "192.168.{1..3}.{1..3}/24 brd +"
171 # will return
172 # "192.168.1.1/24 brd +"
173 # "192.168.1.2/24 brd +"
174 # "192.168.1.3/24 brd +"
175 # "192.168.2.1/24 brd +"
176 # "192.168.2.2/24 brd +"
177 # "192.168.2.3/24 brd +"
178 # "192.168.3.1/24 brd +"
179 # "192.168.3.2/24 brd +"
180 # "192.168.3.3/24 brd +"
181 expand_parameters() {
182         local x=$(eval echo ${@// /_})
183         local -a a=( ${x} )
184
185         a=( "${a[@]/#/\"}" )
186         a=( "${a[@]/%/\"}" )
187         echo "${a[*]//_/ }"
188 }
189
190 # void configure_variables(char *interface, char *option1, [char *option2])
191 #
192 # Maps configuration options from <variable>_<option> to <variable>_<iface>
193 # option2 takes precedence over option1
194 configure_variables() {
195         local iface="$1" option1="$2" option2="$3"
196
197         local mod= func= x= i=
198         local -a ivars=() ovars1=() ovars2=()
199         local ifvar=$(bash_variable "${iface}")
200
201         for mod in ${MODULES[@]}; do
202                 is_function ${mod}_variables || continue
203                 for v in $(${mod}_variables) ; do
204                         x=
205                         [[ -n ${option2} ]] && x="${v}_${option2}[@]"
206                         [[ -z ${!x} ]] && x="${v}_${option1}[@]"
207                         [[ -n ${!x} ]] && eval "${v}_${ifvar}=( \"\${!x}\" )"
208                 done
209         done
210
211         return 0
212 }
213 # bool module_load_minimum(char *module)
214 #
215 # Does the minimum checking on a module - even when forcing
216 module_load_minimum() {
217         local f="$1.sh" MODULE="${1##*/}"
218
219         if [[ ! -f ${f} ]] ; then
220                 eerror "${f} does not exist"
221                 return 1
222         fi
223
224         if ! source "${f}" ; then
225                 eerror "${MODULE} failed a sanity check"
226                 return 1
227         fi
228
229         for f in depend; do
230                 is_function "${MODULE}_${f}" && continue
231                 eerror "${MODULE}.sh does not support the required function ${f}"
232                 return 1
233         done
234
235         return 0
236 }
237
238 # bool modules_load_auto()
239 #
240 # Load and check each module for sanity
241 # If the module is not installed, the functions are to be removed
242 modules_load_auto() {
243         local i j inst
244
245         # Populate the MODULES array
246         # Basically we treat evey file in ${MODULES_DIR} as a module
247         MODULES=( $( cd "${MODULES_DIR}" ; ls *.sh ) )
248         j="${#MODULES[@]}"
249         for (( i=0; i<j; i++ )); do
250                 MODULES[i]="${MODULES_DIR}/${MODULES[i]}"
251                 [[ ! -f ${MODULES[i]} ]] && unset MODULES[i]
252         done
253         MODULES=( "${MODULES[@]}" )
254
255         # Each of these sources into the global namespace, so it's
256         # important that module functions and variables are prefixed with
257         # the module name, for example iproute2_
258
259         j="${#MODULES[@]}"
260         loaded_interface=false
261         for (( i=0; i<j; i++ )); do
262                 MODULES[i]="${MODULES[i]%.sh*}"
263                 if [[ ${MODULES[i]##*/} == "interface" ]] ; then
264                         eerror "interface is a reserved name - cannot load a module called interface"
265                         return 1
266                 fi
267                 
268                 (
269                 u=0;
270                 module_load_minimum "${MODULES[i]}" || u=1;
271                 if [[ ${u} == 0 ]] ; then
272                         inst="${MODULES[i]##*/}_check_installed";
273                         if is_function "${inst}" ; then
274                                 ${inst} false || u=1;
275                         fi
276                 fi
277                 exit "${u}";
278                 )
279
280                 if [[ $? == 0 ]] ; then
281                         source "${MODULES[i]}.sh"
282                         MODULES[i]="${MODULES[i]##*/}"
283                 else
284                         unset MODULES[i]
285                 fi
286         done
287
288         MODULES=( "${MODULES[@]}" )
289         return 0
290 }
291
292 # bool modules_check_installed(void)
293 #
294 # Ensure that all modules have the required modules loaded
295 # This enables us to remove modules from the MODULES array
296 # Whilst other modules can still explicitly call them
297 # One example of this is essidnet which configures network
298 # settings for the specific ESSID connected to as the user
299 # may be using a daemon to configure wireless instead of our
300 # iwconfig module
301 modules_check_installed() {
302         local i j missingdeps nmods="${#MODULES[@]}"
303
304         for (( i=0; i<nmods; i++ )); do
305                 is_function "${MODULES[i]}_instlled" || continue
306                 for j in $( ${MODULES[i]}_instlled ); do
307                         missingdeps=true
308                         if is_function "${j}_check_installed" ; then
309                                 ${j}_check_installed && missingdeps=false
310                         elif is_function "${j}_depend" ; then
311                                 missingdeps=false
312                         fi
313                         ${missingdeps} && unset MODULES[i] && unset PROVIDES[i] && break
314                 done
315         done
316
317         MODULES=( "${MODULES[@]}" )
318         PROVIDES=( "${PROVIDES[@]}" )
319 }
320
321 # bool modules_check_user(void)
322 modules_check_user() {
323         local iface="$1" ifvar=$(bash_variable "${IFACE}")
324         local i= j= k= l= nmods="${#MODULES[@]}"
325         local -a umods=()
326
327         # Has the interface got any specific modules?
328         umods="modules_${ifvar}[@]"
329         umods=( "${!umods}" )
330
331         # Global setting follows interface-specific setting
332         umods=( "${umods[@]}" "${modules[@]}" )
333
334         # Add our preferred modules
335         local -a pmods=( "iproute2" "dhcpcd" "iwconfig" "netplugd" )
336         umods=( "${umods[@]}" "${pmods[@]}" )
337
338         # First we strip any modules that conflict from user settings
339         # So if the user specifies pump then we don't use dhcpcd
340         for (( i=0; i<${#umods[@]}; i++ )); do
341                 # Some users will inevitably put "dhcp" in their modules
342                 # list.  To keep users from screwing up their system this
343                 # way, ignore this setting so that the default dhcp
344                 # module will be used.
345                 [[ ${umods[i]} == "dhcp" ]] && continue
346
347                 # We remove any modules we explicitly don't want
348                 if [[ ${umods[i]} == "!"* ]] ; then
349                         for (( j=0; j<nmods; j++ )); do
350                                 [[ -z ${MODULES[j]} ]] && continue
351                                 if [[ ${umods[i]:1} == "${MODULES[j]}" \
352                                         || ${umods[i]:1} == "${PROVIDES[j]}" ]] ; then
353                                         # We may need to setup a class wrapper for it even though
354                                         # we don't use it directly
355                                         # However, we put it into an array and wrap later as
356                                         # another module may provide the same thing
357                                         ${MODULES[j]}_check_installed \
358                                                 && WRAP_MODULES=(
359                                                         "${WRAP_MODULES[@]}"
360                                                         "${MODULES[j]} ${PROVIDES[j]}"
361                                                 )
362                                         unset MODULES[j]
363                                         unset PROVIDES[j]
364                                 fi
365                         done
366                         continue
367                 fi
368
369                 if ! is_function "${umods[i]}_depend" ; then
370                         # If the module is one of our preferred modules, then
371                         # ignore this error; whatever is available will be
372                         # used instead.
373                         (( i < ${#umods[@]} - ${#pmods[@]} )) || continue
374
375                         # The function may not exist because the modules software is
376                         # not installed. Load the module and report its error
377                         if [[ -e "${MODULES_DIR}/${umods[i]}.sh" ]] ; then
378                                 source "${MODULES_DIR}/${umods[i]}.sh"
379                                 is_function "${umods[i]}_check_installed" \
380                                         && ${umods[i]}_check_installed true
381                         else
382                                 eerror "The module \"${umods[i]}\" does not exist"
383                         fi
384                         return 1
385                 fi
386
387                 if is_function "${umods[i]}_provide" ; then
388                         mod=$(${umods[i]}_provide)
389                 else
390                         mod="${umods[i]}"
391                 fi
392                 for (( j=0; j<nmods; j++ )); do
393                         [[ -z ${MODULES[j]} ]] && continue
394                         if [[ ${PROVIDES[j]} == "${mod}" && ${umods[i]} != "${MODULES[j]}" ]] ; then
395                                 # We don't have a match - now ensure that we still provide an
396                                 # alternative. This is to handle our preferred modules.
397                                 for (( l=0; l<nmods; l++ )); do
398                                         [[ ${l} == "${j}" || -z ${MODULES[l]} ]] && continue
399                                         if [[ ${PROVIDES[l]} == "${mod}" ]] ; then
400                                                 unset MODULES[j]
401                                                 unset PROVIDES[j]
402                                                 break
403                                         fi
404                                 done
405                         fi
406                 done
407         done
408
409         # Then we strip conflicting modules.
410         # We only need to do this for 3rd party modules that conflict with
411         # our own modules and the preferred list AND the user modules
412         # list doesn't specify a preference.
413         for (( i=0; i<nmods-1; i++ )); do
414                 [[ -z ${MODULES[i]} ]] && continue                      
415                 for (( j=i+1; j<nmods; j++)); do
416                         [[ -z ${MODULES[j]} ]] && continue
417                         [[ ${PROVIDES[i]} == "${PROVIDES[j]}" ]] \
418                         && unset MODULES[j] && unset PROVIDES[j]
419                 done
420         done
421
422         MODULES=( "${MODULES[@]}" )
423         PROVIDES=( "${PROVIDES[@]}" )
424         return 0
425 }
426
427 # void modules_sort(void)
428 #
429 # Sort our modules
430 modules_sort() {
431         local i= j= nmods=${#MODULES[@]} m=
432         local -a provide=() provide_list=() after=() dead=() sorted=() sortedp=()
433
434         # Make our provide list
435         for ((i=0; i<nmods; i++)); do
436                 dead[i]="false"
437                 if [[ ${MODULES[i]} != "${PROVIDES[i]}" ]] ; then
438                         local provided=false
439                         for ((j=0; j<${#provide[@]}; j++)); do
440                                 if [[ ${provide[j]} == "${PROVIDES[i]}" ]] ; then
441                                         provide_list[j]="${provide_list[j]} ${MODULES[i]}"
442                                         provided=true
443                                 fi
444                         done
445                         if ! ${provided}; then
446                                 provide[j]="${PROVIDES[i]}"
447                                 provide_list[j]="${MODULES[i]}"
448                         fi
449                 fi
450         done
451
452         # Create an after array, which holds which modules the module at
453         # index i must be after
454         for ((i=0; i<nmods; i++)); do
455                 if is_function "${MODULES[i]}_after" ; then
456                         after[i]=" ${after[i]} $(${MODULES[i]}_after) "
457                 fi
458                 if is_function "${MODULES[i]}_before" ; then
459                         for m in $(${MODULES[i]}_before); do
460                                 for ((j=0; j<nmods; j++)) ; do
461                                         if [[ ${PROVIDES[j]} == "${m}" ]] ; then
462                                                 after[j]=" ${after[j]} ${MODULES[i]} "
463                                                 break
464                                         fi
465                                 done
466                         done
467                 fi
468         done
469
470         # Replace the after list modules with real modules
471         for ((i=0; i<nmods; i++)); do
472                 if [[ -n ${after[i]} ]] ; then
473                         for ((j=0; j<${#provide[@]}; j++)); do
474                                 after[i]="${after[i]// ${provide[j]} / ${provide_list[j]} }"
475                         done
476                 fi
477         done
478         
479         # We then use the below code to provide a topologial sort
480     module_after_visit() {
481         local name="$1" i= x=
482
483                 for ((i=0; i<nmods; i++)); do
484                         [[ ${MODULES[i]} == "$1" ]] && break
485                 done
486
487         ${dead[i]} && return
488         dead[i]="true"
489
490         for x in ${after[i]} ; do
491             module_after_visit "${x}"
492         done
493
494         sorted=( "${sorted[@]}" "${MODULES[i]}" )
495                 sortedp=( "${sortedp[@]}" "${PROVIDES[i]}" )
496     }
497
498         for x in ${MODULES[@]}; do
499                 module_after_visit "${x}"
500         done
501
502         MODULES=( "${sorted[@]}" )
503         PROVIDES=( "${sortedp[@]}" )
504 }
505
506 # bool modules_check_depends(bool showprovides)
507 modules_check_depends() {
508         local showprovides="${1:-false}" nmods="${#MODULES[@]}" i= j= needmod=
509         local missingdeps= p= interface=false
510
511         for (( i=0; i<nmods; i++ )); do
512                 if is_function "${MODULES[i]}_need" ; then
513                         for needmod in $(${MODULES[i]}_need); do
514                                 missingdeps=true
515                                 for (( j=0; j<nmods; j++ )); do
516                                         if [[ ${needmod} == "${MODULES[j]}" \
517                                                 || ${needmod} == "${PROVIDES[j]}" ]] ; then
518                                                 missingdeps=false
519                                                 break
520                                         fi
521                                 done
522                                 if ${missingdeps} ; then
523                                         eerror "${MODULES[i]} needs ${needmod} (dependency failure)"
524                                         return 1
525                                 fi
526                         done
527                 fi
528
529                 if is_function "${MODULES[i]}_functions" ; then
530                         for f in $(${MODULES[i]}_functions); do
531                                 if ! is_function "${f}" ; then
532                                         eerror "${MODULES[i]}: missing required function \"${f}\""
533                                         return 1
534                                 fi
535                         done
536                 fi
537
538                 [[ ${PROVIDES[i]} == "interface" ]] && interface=true
539
540                 if ${showprovides} ; then
541                         [[ ${PROVIDES[i]} != "${MODULES[i]}" ]] \
542                         && veinfo "${MODULES[i]} provides ${PROVIDES[i]}"
543                 fi
544         done
545
546         if ! ${interface} ; then
547                 eerror "no interface module has been loaded"
548                 return 1
549         fi
550
551         return 0
552 }
553
554 # bool modules_load(char *iface, bool starting)
555 #
556 # Loads the defined handler and modules for the interface
557 # Returns 0 on success, otherwise 1
558 modules_load()  {
559         local iface="$1" starting="${2:-true}" MODULE= p=false i= j= k=
560         local -a x=()
561         local RC_INDENTATION="${RC_INDENTATION}"
562         local -a PROVIDES=() WRAP_MODULES=()
563
564         if ! is_loopback "${iface}" ; then
565                 x="modules_force_${iface}[@]"
566                 [[ -n ${!x} ]] && modules_force=( "${!x}" )
567                 if [[ -n ${modules_force} ]] ; then
568                         ewarn "WARNING: You are forcing modules!"
569                         ewarn "Do not complain or file bugs if things start breaking"
570                         report=true
571                 fi
572         fi
573
574         veinfo "Loading networking modules for ${iface}"
575         eindent
576
577         if [[ -z ${modules_force} ]] ; then
578                 modules_load_auto || return 1
579         else
580                 j="${#modules_force[@]}"
581                 for (( i=0; i<j; i++ )); do
582                         module_load_minimum "${MODULES_DIR}/${modules_force[i]}" || return 1
583                         if is_function "${modules_force[i]}_check_installed" ; then
584                                 ${modules_force[i]}_check_installed || unset modules_force[i]
585                         fi
586                 done
587                 MODULES=( "${modules_force[@]}" )
588         fi
589
590         j="${#MODULES[@]}"
591         for (( i=0; i<j; i++ )); do
592                 # Now load our dependencies - we need to use the MODULE variable
593                 # here as the after/before/need functions use it
594                 MODULE="${MODULES[i]}"
595                 ${MODULE}_depend
596
597                 # expose does exactly the same thing as depend
598                 # However it is more "correct" as it exposes things to other modules
599                 # instead of depending on them ;)
600                 is_function "${MODULES[i]}_expose" && ${MODULES[i]}_expose
601
602                 # If no provide is given, assume module name
603                 if is_function "${MODULES[i]}_provide" ; then
604                         PROVIDES[i]=$(${MODULES[i]}_provide)
605                 else
606                         PROVIDES[i]="${MODULES[i]}"
607                 fi
608         done
609
610         if [[ -n ${modules_force[@]} ]] ; then
611                 # Strip any duplicate modules providing the same thing
612                 j="${#MODULES[@]}"
613                 for (( i=0; i<j-1; i++ )); do
614                         [[ -z ${MODULES[i]} ]] && continue
615                         for (( k=i+1; k<j; k++ )); do
616                                 if [[ ${PROVIDES[i]} == ${PROVIDES[k]} ]] ; then
617                                         unset MODULES[k]
618                                         unset PROVIDES[k]
619                                 fi
620                         done
621                 done
622                 MODULES=( "${MODULES[@]}" )
623                 PROVIDES=( "${PROVIDES[@]}" )
624         else
625                 if ${starting}; then
626                         modules_check_user "${iface}" || return 1
627                 else
628                         # Always prefer iproute2 for taking down interfaces
629                         if is_function iproute2_provide ; then
630                                 function_wrap iproute2 "$(iproute2_provide)"
631                         fi
632                 fi
633         fi
634         
635         # Wrap our modules
636         j="${#MODULES[@]}"
637         for (( i=0; i<j; i++ )); do
638                 function_wrap "${MODULES[i]}" "${PROVIDES[i]}"
639         done
640         j="${#WRAP_MODULES[@]}"
641         for (( i=0; i<j; i++ )); do
642                 function_wrap ${WRAP_MODULES[i]}
643         done
644         
645         if [[ -z ${modules_force[@]} ]] ; then
646                 modules_check_installed || return 1
647                 modules_sort || return 1
648         fi
649
650         veinfo "modules: ${MODULES[@]}"
651         eindent
652
653         ${starting} && p=true
654         modules_check_depends "${p}" || return 1
655         return 0
656 }
657
658 # bool iface_start(char *interface)
659 #
660 # iface_start is called from start.  It's expected to start the base
661 # interface (for example "eth0"), aliases (for example "eth0:1") and to start
662 # VLAN interfaces (for example eth0.0, eth0.1).  VLAN setup is accomplished by
663 # calling itself recursively.
664 iface_start() {
665         local iface="$1" mod config_counter="-1" x config_worked=false
666         local RC_INDENTATION="${RC_INDENTATION}"
667         local -a config=() fallback=() fallback_route=() conf=() a=() b=()
668         local ifvar=$(bash_variable "$1") i= j= metric=0
669
670         # pre Start any modules with
671         for mod in ${MODULES[@]}; do
672                 if is_function "${mod}_pre_start" ; then
673                         ${mod}_pre_start "${iface}" || { eend 1; return 1; }
674                 fi
675         done
676
677         x="metric_${ifvar}"
678         # If we don't have a metric then calculate one
679         # Our modules will set the metric variable to a suitable base
680         # in their pre starts.
681         if [[ -z ${!x} ]] ; then
682                 eval "metric_${ifvar}=\"$(calculate_metric "${iface}" "${metric}")\""
683         fi
684
685         # We now expand the configuration parameters and pray that the
686         # fallbacks expand to the same number as config or there will be
687         # trouble!
688         a="config_${ifvar}[@]"
689         a=( "${!a}" )
690         for (( i=0; i<${#a[@]}; i++ )); do 
691                 eval b=( $(expand_parameters "${a[i]}") )
692                 config=( "${config[@]}" "${b[@]}" )
693         done
694
695         a="fallback_${ifvar}[@]"
696         a=( "${!a}" )
697         for (( i=0; i<${#a[@]}; i++ )); do 
698                 eval b=( $(expand_parameters "${a[i]}") )
699                 fallback=( "${fallback[@]}" "${b[@]}" )
700         done
701
702         # We don't expand routes
703         fallback_route="fallback_route_${ifvar}[@]"
704         fallback_route=( "${!fallback_route}" )
705         
706         # We must support old configs
707         if [[ -z ${config} ]] ; then
708                 interface_get_old_config "${iface}" || return 1
709                 if [[ -n ${config} ]] ; then
710                         ewarn "You are using a deprecated configuration syntax for ${iface}"
711                         ewarn "You are advised to read /etc/conf.d/net.example and upgrade it accordingly"
712                 fi
713         fi
714
715         # Handle "noop" correctly
716         if [[ ${config[0]} == "noop" ]] ; then
717                 if interface_is_up "${iface}" true ; then
718                         einfo "Keeping current configuration for ${iface}"
719                         eend 0
720                         return 0
721                 fi
722
723                 # Remove noop from the config var
724                 config=( "${config[@]:1}" )
725         fi
726
727         # Provide a default of DHCP if no configuration is set and we're auto
728         # Otherwise a default of NULL
729         if [[ -z ${config} ]] ; then
730                 ewarn "Configuration not set for ${iface} - assuming DHCP"
731                 if is_function "dhcp_start" ; then
732                         config=( "dhcp" )
733                 else
734                         eerror "No DHCP client installed"
735                         return 1
736                 fi
737         fi
738
739         einfo "Bringing up ${iface}"
740         eindent
741         for (( config_counter=0; config_counter<${#config[@]}; config_counter++ )); do
742                 # Handle null and noop correctly
743                 if [[ ${config[config_counter]} == "null" \
744                         || ${config[config_counter]} == "noop" ]] ; then
745                         eend 0
746                         config_worked=true
747                         continue
748                 fi
749
750                 # We convert it to an array - this has the added
751                 # bonus of trimming spaces!
752                 conf=( ${config[config_counter]} )
753                 einfo "${conf[0]}"
754
755                 # Do we have a function for our config?
756                 if is_function "${conf[0]}_start" ; then
757                         eindent
758                         ${conf[0]}_start "${iface}" ; x=$?
759                         eoutdent
760                         [[ ${x} == 0 ]] && config_worked=true && continue
761                         # We need to test to see if it's an IP address or a function
762                         # We do this by testing if the 1st character is a digit
763                 elif [[ ${conf[0]:0:1} == [[:digit:]] || ${conf[0]} == *:* ]] ; then
764                         x="0"
765                         if ! is_loopback "${iface}" ; then
766                                 if [[ " ${MODULES[@]} " == *" arping "* ]] ; then
767                                         if arping_address_exists "${iface}" "${conf[0]}" ; then
768                                                 eerror "${conf[0]%%/*} already taken on ${iface}"
769                                                 x="1"
770                                         fi
771                                 fi
772                         fi
773                         [[ ${x} == "0" ]] && interface_add_address "${iface}" ${conf[@]}; x="$?"
774                         eend "${x}" && config_worked=true && continue
775                 else
776                         if [[ ${conf[0]} == "dhcp" ]] ; then
777                                 eerror "No DHCP client installed"
778                         else
779                                 eerror "No loaded modules provide \"${conf[0]}\" (${conf[0]}_start)"
780                         fi
781                 fi
782
783                 if [[ -n ${fallback[config_counter]} ]] ; then
784                         einfo "Trying fallback configuration"
785                         config[config_counter]="${fallback[config_counter]}"
786                         fallback[config_counter]=""
787
788                         # Do we have a fallback route?
789                         if [[ -n ${fallback_route[config_counter]} ]] ; then
790                                 x="fallback_route[config_counter]"
791                                 eval "routes_${ifvar}=( \"\${!x}\" )"
792                                 fallback_route[config_counter]=""
793                         fi
794
795                         (( config_counter-- )) # since the loop will increment it
796                         continue
797                 fi
798         done
799         eoutdent
800
801         # We return failure if no configuration parameters worked
802         ${config_worked} || return 1
803
804         # Start any modules with _post_start
805         for mod in ${MODULES[@]}; do
806                 if is_function "${mod}_post_start" ; then
807                         ${mod}_post_start "${iface}" || return 1
808                 fi
809         done
810
811         return 0
812 }
813
814 # bool iface_stop(char *interface)
815 #
816 # iface_stop: bring down an interface.  Don't trust information in
817 # /etc/conf.d/net since the configuration might have changed since
818 # iface_start ran.  Instead query for current configuration and bring
819 # down the interface.
820 iface_stop() {
821         local iface="$1" i= aliases= need_begin=false mod=
822         local RC_INDENTATION="${RC_INDENTATION}"
823
824         # pre Stop any modules
825         for mod in ${MODULES[@]}; do
826                 if is_function "${mod}_pre_stop" ; then
827                         ${mod}_pre_stop "${iface}" || return 1
828                 fi
829         done
830
831         einfo "Bringing down ${iface}"
832         eindent
833
834         # Collect list of aliases for this interface.
835         # List will be in reverse order.
836         if interface_exists "${iface}" ; then
837                 aliases=$(interface_get_aliases_rev "${iface}")
838         fi
839
840         # Stop aliases before primary interface.
841         # Note this must be done in reverse order, since ifconfig eth0:1 
842         # will remove eth0:2, etc.  It might be sufficient to simply remove 
843         # the base interface but we're being safe here.
844         for i in ${aliases} ${iface}; do
845                 # Stop all our modules
846                 for mod in ${MODULES[@]}; do
847                         if is_function "${mod}_stop" ; then
848                                 ${mod}_stop "${i}" || return 1
849                         fi
850                 done
851
852                 # A module may have removed the interface
853                 if ! interface_exists "${iface}" ; then
854                         eend 0
855                         continue
856                 fi
857
858                 # We don't delete ppp assigned addresses
859                 if ! is_function pppd_exists || ! pppd_exists "${i}" ; then
860                         # Delete all the addresses for this alias
861                         interface_del_addresses "${i}"
862                 fi
863
864                 # Do final shut down of this alias
865                 if [[ ${IN_BACKGROUND} != "true" \
866                         && ${RC_DOWN_INTERFACE} == "yes" ]] ; then
867                         ebegin "Shutting down ${i}"
868                         interface_iface_stop "${i}"
869                         eend "$?"
870                 fi
871         done
872
873         # post Stop any modules
874         for mod in ${MODULES[@]}; do
875                 # We have already taken down the interface, so no need to error
876                 is_function "${mod}_post_stop" && ${mod}_post_stop "${iface}"
877         done
878
879         return 0
880 }
881
882 # bool run_start(char *iface)
883 #
884 # Brings up ${IFACE}.  Calls preup, iface_start, then postup.
885 # Returns 0 (success) unless preup or iface_start returns 1 (failure).
886 # Ignores the return value from postup.
887 # We cannot check that the device exists ourselves as modules like
888 # tuntap make create it.
889 run_start() {
890         local iface="$1" IFVAR=$(bash_variable "$1")
891
892         # We do this so users can specify additional addresses for lo if they
893         # need too - additional routes too
894         # However, no extra modules are loaded as they are just not needed
895         if [[ ${iface} == "lo" ]] ; then
896                 metric_lo="0"
897                 config_lo=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
898                 routes_lo=( "127.0.0.0/8" "${routes_lo[@]}" )
899         elif [[ ${iface} == "lo0" ]] ; then
900                 metric_lo0="0"
901                 config_lo0=( "127.0.0.1/8 brd 127.255.255.255" "${config_lo[@]}" )
902                 routes_lo0=( "127.0.0.0/8" "${routes_lo[@]}" )
903         fi
904
905         # We may not have a loaded module for ${iface}
906         # Some users may have "alias natsemi eth0" in /etc/modules.d/foo
907         # so we can work with this
908         # However, if they do the same with eth1 and try to start it
909         # but eth0 has not been loaded then the module gets loaded as
910         # eth0.
911         # Not much we can do about this :(
912         # Also, we cannot error here as some modules - such as bridge
913         # create interfaces
914         if ! interface_exists "${iface}" ; then
915                 /sbin/modprobe "${iface}" &>/dev/null
916         fi
917
918         # Call user-defined preup function if it exists
919         if is_function preup ; then
920                 einfo "Running preup function"
921                 eindent
922                 ( preup "${iface}" )
923                 eend "$?" "preup ${iface} failed" || return 1
924                 eoutdent
925         fi
926
927         # If config is set to noop and the interface is up with an address
928         # then we don't start it
929         local config=
930         config="config_${IFVAR}[@]"
931         config=( "${!config}" )
932         if [[ ${config[0]} == "noop" ]] && interface_is_up "${iface}" true ; then
933                 einfo "Keeping current configuration for ${iface}"
934                 eend 0
935         else
936                 # Remove noop from the config var
937                 [[ ${config[0]} == "noop" ]] \
938                         && eval "config_${IFVAR}=( "\"\$\{config\[@\]:1\}\"" )"
939
940                 # There may be existing ip address info - so we strip it
941                 if [[ ${RC_INTERFACE_KEEP_CONFIG} != "yes" \
942                         && ${IN_BACKGROUND} != "true" ]] ; then
943                         interface_del_addresses "${iface}"
944                 fi
945
946                 # Start the interface
947                 if ! iface_start "${iface}" ; then
948                         if [[ ${IN_BACKGROUND} != "true" ]] ; then
949                                 interface_exists "${iface}" && interface_down "${iface}"
950                         fi
951                         eend 1
952                         return 1
953                 fi
954         fi
955
956         # Call user-defined postup function if it exists
957         if is_function postup ; then
958                 # We need to mark the service as started incase a
959                 # postdown function wants to restart services that depend on us
960                 mark_service_started "net.${iface}"
961                 end_service "net.${iface}" 0
962                 einfo "Running postup function"
963                 eindent
964                 ( postup "${iface}" )
965                 eoutdent
966         fi
967
968         return 0
969 }
970
971 # bool run_stop(char *iface) {
972 #
973 # Brings down ${iface}.  If predown call returns non-zero, then
974 # stop returns non-zero to indicate failure bringing down device.
975 # In all other cases stop returns 0 to indicate success.
976 run_stop() {
977         local iface="$1" IFVAR=$(bash_variable "$1") x
978
979         # Load our ESSID variable so users can use it in predown() instead
980         # of having to write code.
981         local ESSID=$(get_options ESSID) ESSIDVAR=
982         [[ -n ${ESSID} ]] && ESSIDVAR=$(bash_variable "${ESSID}")
983
984         # Call user-defined predown function if it exists
985         if is_function predown ; then
986                 einfo "Running predown function"
987                 eindent
988                 ( predown "${iface}" )
989                 eend $? "predown ${iface} failed" || return 1
990                 eoutdent
991         elif is_net_fs / ; then
992                 eerror "root filesystem is network mounted -- can't stop ${iface}"
993                 return 1
994         elif is_union_fs / ; then
995                 for x in $(unionctl "${dir}" --list \
996                 | sed -e 's/^\(.*\) .*/\1/') ; do
997                         if is_net_fs "${x}" ; then
998                                 eerror "Part of the root filesystem is network mounted - cannot stop ${iface}"
999                                 return 1
1000                         fi
1001                 done
1002         fi
1003
1004         iface_stop "${iface}" || return 1  # always succeeds, btw
1005
1006         # Release resolv.conf information.
1007         [[ -x /sbin/resolvconf ]] && resolvconf -d "${iface}"
1008         
1009         # Mark us as inactive if called from the background
1010         [[ ${IN_BACKGROUND} == "true" ]] && mark_service_inactive "net.${iface}"
1011
1012         # Call user-defined postdown function if it exists
1013         if is_function postdown ; then
1014                 # We need to mark the service as stopped incase a
1015                 # postdown function wants to restart services that depend on us
1016                 [[ ${IN_BACKGROUND} != "true" ]] && mark_service_stopped "net.${iface}"
1017                 end_service "net.${iface}" 0
1018                 einfo "Running postdown function"
1019                 eindent
1020                 ( postdown "${iface}" )
1021                 eoutdent
1022         fi
1023
1024
1025         return 0
1026 }
1027
1028 # bool run(char *iface, char *cmd)
1029 #
1030 # Main start/stop entry point
1031 # We load modules here and remove any functions that they
1032 # added as we may be called inside the same shell scope for another interface
1033 run() {
1034         local iface="$1" cmd="$2" r=1 RC_INDENTATION="${RC_INDENTATION}"
1035         local starting=true
1036         local -a MODULES=() mods=()
1037         local IN_BACKGROUND="${IN_BACKGROUND}"
1038
1039         if [[ ${IN_BACKGROUND} == "true" || ${IN_BACKGROUND} == "1" ]] ; then
1040                 IN_BACKGROUND=true
1041         else
1042                 IN_BACKGROUND=false
1043         fi
1044
1045         # We need to override the exit function as runscript.sh now checks
1046         # for it. We need it so we can mark the service as inactive ourselves.
1047         unset -f exit
1048
1049         eindent
1050         [[ ${cmd} == "stop" ]] && starting=false
1051
1052         # We force lo to only use these modules for a major speed boost
1053         if is_loopback "${iface}" ; then        
1054                 modules_force=( "iproute2" "ifconfig" "system" )
1055         fi
1056
1057         if modules_load "${iface}" "${starting}" ; then
1058                 if [[ ${cmd} == "stop" ]] ; then
1059                         # Reverse the module list for stopping
1060                         mods=( "${MODULES[@]}" )
1061                         for ((i = 0; i < ${#mods[@]}; i++)); do
1062                                 MODULES[i]=${mods[((${#mods[@]} - i - 1))]}
1063                         done
1064
1065                         run_stop "${iface}" && r=0
1066                 else
1067                         # Only hotplug on ethernet interfaces
1068                         if [[ ${IN_HOTPLUG} == 1 ]] ; then
1069                                 if ! interface_is_ethernet "${iface}" ; then
1070                                         eerror "We only hotplug for ethernet interfaces"
1071                                         return 1
1072                                 fi
1073                         fi
1074
1075                         run_start "${iface}" && r=0
1076                 fi
1077         fi
1078
1079         if [[ ${r} != "0" ]] ; then
1080                 if [[ ${cmd} == "start" ]] ; then
1081                         # Call user-defined failup if it exists
1082                         if is_function failup ; then
1083                                 einfo "Running failup function"
1084                                 eindent
1085                                 ( failup "${iface}" )
1086                                 eoutdent
1087                         fi
1088                 else
1089                         # Call user-defined faildown if it exists
1090                         if is_function faildown ; then
1091                                 einfo "Running faildown function"
1092                                 eindent
1093                                 ( faildown "${iface}" )
1094                                 eoutdent
1095                         fi
1096                 fi
1097                 [[ ${IN_BACKGROUND} == "true" ]] \
1098                         && mark_service_inactive "net.${iface}"
1099         fi
1100
1101         return "${r}"
1102 }
1103
1104 # bool start(void)
1105 #
1106 # Start entry point so that we only have one function
1107 # which localises variables and unsets functions
1108 start() {
1109         declare -r IFACE="${SVCNAME#*.}"
1110         einfo "Starting ${IFACE}"
1111         run "${IFACE}" start
1112 }
1113
1114 # bool stop(void)
1115 #
1116 # Stop entry point so that we only have one function
1117 # which localises variables and unsets functions
1118 stop() {
1119         declare -r IFACE="${SVCNAME#*.}"
1120         einfo "Stopping ${IFACE}"
1121         run "${IFACE}" stop
1122 }
1123
1124 # vim:ts=4