if [ ! "$_MEDIA_TCPIP_SUBR" ]; then _MEDIA_TCPIP_SUBR=1 # # Copyright (c) 2012-2013 Devin Teske # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions # are met: # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND # ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE # FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS # OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT # LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY # OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF # SUCH DAMAGE. # # $FreeBSD$ # ############################################################ INCLUDES BSDCFG_SHARE="/usr/share/bsdconfig" . $BSDCFG_SHARE/common.subr || exit 1 f_dprintf "%s: loading includes..." media/tcpip.subr f_include $BSDCFG_SHARE/device.subr f_include $BSDCFG_SHARE/dialog.subr f_include $BSDCFG_SHARE/struct.subr f_include $BSDCFG_SHARE/variable.subr BSDCFG_LIBE="/usr/libexec/bsdconfig" f_include_lang $BSDCFG_LIBE/include/messages.subr TCP_HELPFILE=$BSDCFG_LIBE/include/tcp.hlp NETWORK_DEVICE_HELPFILE=$BSDCFG_LIBE/include/network_device.hlp ############################################################ GLOBALS # # Path to resolv.conf(5). # : ${RESOLV_CONF:="/etc/resolv.conf"} # # Path to nsswitch.conf(5). # : ${NSSWITCH_CONF:="/etc/nsswitch.conf"} # # Path to hosts(5) # : ${ETC_HOSTS:="/etc/hosts"} # # Structure of dhclient.leases(5) lease { ... } entry # f_struct_define DHCP_LEASE \ interface \ fixed_address \ filename \ server_name \ script \ medium \ host_name \ subnet_mask \ routers \ domain_name_servers \ domain_name \ broadcast_address \ dhcp_lease_time \ dhcp_message_type \ dhcp_server_identifier \ dhcp_renewal_time \ dhcp_rebinding_time \ renew \ rebind \ expire ############################################################ FUNCTIONS # f_validate_hostname $hostname # # Returns zero if the given argument (a fully-qualified hostname) is compliant # with standards set-forth in RFC's 952 and 1123 of the Network Working Group: # # RFC 952 - DoD Internet host table specification # http://tools.ietf.org/html/rfc952 # # RFC 1123 - Requirements for Internet Hosts - Application and Support # http://tools.ietf.org/html/rfc1123 # # See http://en.wikipedia.org/wiki/Hostname for a brief overview. # # The return status for invalid hostnames is one of: # 255 Entire hostname exceeds the maximum length of 255 characters. # 63 One or more individual labels within the hostname (separated by # dots) exceeds the maximum of 63 characters. # 1 One or more individual labels within the hostname contains one # or more invalid characters. # 2 One or more individual labels within the hostname starts or # ends with a hyphen (hyphens are allowed, but a label cannot # begin or end with a hyphen). # 3 One or more individual labels within the hostname are null. # # f_dialog_validate_hostname $hostname # # If the hostname is determined to be invalid, the appropriate error will be # displayed using the f_show_msg function. # f_validate_hostname() { local fqhn="$1" # Return error if the hostname exceeds 255 characters [ ${#fqhn} -gt 255 ] && return 255 local IFS="." # Split on `dot' for label in $fqhn; do # Return error if the label exceeds 63 characters [ ${#label} -gt 63 ] && return 63 # Return error if the label is null [ "$label" ] || return 3 # Return error if label begins/ends with dash case "$label" in -*|*-) return 2; esac # Return error if the label contains any invalid chars case "$label" in *[!0-9a-zA-Z-]*) return 1; esac done return $SUCCESS } # f_inet_atoi $ipv4_address [$var_to_set] # # Convert an IPv4 address or mask from dotted-quad notation (e.g., `127.0.0.1' # or `255.255.255.0') to a 32-bit unsigned integer for the purpose of network # and broadcast calculations. For example, one can validate that two addresses # are on the same network: # # f_inet_atoi 1.2.3.4 ip1num # f_inet_atoi 1.2.4.5 ip2num # f_inet_atoi 255.255.0.0 masknum # if [ $(( $ip1num & $masknum )) -eq \ # $(( $ip2num & $masknum )) ] # then # : IP addresses are on same network # fi # # See f_validate_ipaddr() below for an additional example usage, on calculating # network and broadcast addresses. # # If $var_to_set is missing or NULL, the converted IP address is printed to # standard output for capturing in a sub-shell (which is less-recommended # because of performance degredation; for example, when called in a loop). # f_inet_atoi() { local __addr="$1" __var_to_set="$2" __num=0 if f_validate_ipaddr "$__addr"; then __num=$( IFS=.; set -- $__addr; \ echo $(( ($1 << 24) + ($2 << 16) + ($3 << 8) + $4 )) ) fi if [ "$__var_to_set" ]; then setvar "$__var_to_set" $__num else echo $__num fi } # f_validate_ipaddr $ipaddr [$netmask] # # Returns zero if the given argument (an IP address) is of the proper format. # # The return status for invalid IP address is one of: # 1 One or more individual octets within the IP address (separated # by dots) contains one or more invalid characters. # 2 One or more individual octets within the IP address are null # and/or missing. # 3 One or more individual octets within the IP address exceeds the # maximum of 255 (or 2^8, being an octet comprised of 8 bits). # 4 The IP address has either too few or too many octets. # # If a netmask is provided, the IP address is checked further: # # 5 The IP address must not be the network or broadcast address. # f_validate_ipaddr() { local ip="$1" mask="$2" # Track number of octets for error checking local noctets=0 local oldIFS="$IFS" local IFS="." # Split on `dot' for octet in $ip; do # Return error if the octet is null [ "$octet" ] || return 2 # Return error if not a whole integer f_isinteger "$octet" || return 1 # Return error if not a positive integer [ $octet -ge 0 ] || return 1 # Return error if the octet exceeds 255 [ $octet -gt 255 ] && return 3 noctets=$(( $noctets + 1 )) done IFS="$oldIFS" [ $noctets -eq 4 ] || return 4 # # The IP address must not be network or broadcast address. # if [ "$mask" ]; then local ipnum masknum netnum bcastnum local max_addr=4294967295 # 255.255.255.255 f_inet_atoi $ip ipnum f_inet_atoi $mask masknum netnum=$(( $ipnum & $masknum )) bcastnum=$(( ($ipnum & $masknum)+$max_addr-$masknum )) if [ "$masknum" ] && [ $ipnum -eq $netnum -o $ipnum -eq $bcastnum ] then return 5 fi fi return $SUCCESS } # f_validate_ipaddr6 $ipv6_addr # # Returns zero if the given argument (an IPv6 address) is of the proper format. # # The return status for invalid IP address is one of: # 1 One or more individual segments within the IP address # (separated by colons) contains one or more invalid characters. # Segments must contain only combinations of the characters 0-9, # A-F, or a-f. # 2 Too many/incorrect null segments. A single null segment is # allowed within the IP address (separated by colons) but not # allowed at the beginning or end (unless a double-null segment; # i.e., "::*" or "*::"). # 3 One or more individual segments within the IP address # (separated by colons) exceeds the length of 4 hex-digits. # 4 The IP address entered has either too few (less than 3), too # many (more than 8), or not enough segments, separated by # colons. # 5* The IPv4 address at the end of the IPv6 address is invalid. # * When there is an error with the dotted-quad IPv4 address at the # end of the IPv6 address, the return value of 5 is OR'd with a # bit-shifted (<< 4) return of f_validate_ipaddr. # f_validate_ipaddr6() { local ip="${1%\%*}" # removing the interface specification if-present local IFS=":" # Split on `colon' set -- $ip: # Return error if too many or too few segments # Using 9 as max in case of leading or trailing null spanner [ $# -gt 9 -o $# -lt 3 ] && return 4 local h="[0-9A-Fa-f]" local nulls=0 nsegments=$# contains_ipv4_segment= while [ $# -gt 0 ]; do segment="${1%:}" shift # # Return error if this segment makes one null too-many. A # single null segment is allowed anywhere in the middle as well # as double null segments are allowed at the beginning or end # (but not both). # if [ ! "$segment" ]; then nulls=$(( $nulls + 1 )) if [ $nulls -eq 3 ]; then # Only valid syntax for 3 nulls is `::' [ "$ip" = "::" ] || return 2 elif [ $nulls -eq 2 ]; then # Only valid if begins/ends with `::' case "$ip" in ::*|*::) : fall thru ;; *) return 2 esac fi continue fi # # Return error if not a valid hexadecimal short # case "$segment" in $h|$h$h|$h$h$h|$h$h$h$h) : valid segment of 1-4 hexadecimal digits ;; *[!0-9A-Fa-f]*) # Segment contains at least one invalid char # Return error immediately if not last segment [ $# -eq 0 ] || return 1 # Otherwise, check for legacy IPv4 notation case "$segment" in *[!0-9.]*) # Segment contains at least one invalid # character even for an IPv4 address return 1 esac # Return error if not enough segments if [ $nulls -eq 0 ]; then [ $nsegments -eq 7 ] || return 4 fi contains_ipv4_segment=1 # Validate the IPv4 address f_validate_ipaddr "$segment" || return $(( 5 | $? << 4 )) ;; *) # Segment characters are all valid but too many return 3 esac done if [ $nulls -eq 1 ]; then # Single null segment cannot be at beginning/end case "$ip" in :*|*:) return 2 esac fi # # A legacy IPv4 address can span the last two 16-bit segments, # reducing the amount of maximum allowable segments by-one. # maxsegments=8 if [ "$contains_ipv4_segment" ]; then maxsegments=7 fi case $nulls in # Return error if missing segments with no null spanner 0) [ $nsegments -eq $maxsegments ] || return 4 ;; # Return error if null spanner with too many segments 1) [ $nsegments -le $maxsegments ] || return 4 ;; # Return error if leading/trailing `::' with too many segments 2) [ $nsegments -le $(( $maxsegments + 1 )) ] || return 4 ;; esac return $SUCCESS } # f_validate_netmask $netmask # # Returns zero if the given argument (a subnet mask) is of the proper format. # # The return status for invalid netmask is one of: # 1 One or more individual fields within the subnet mask (separated # by dots) contains one or more invalid characters. # 2 One or more individual fields within the subnet mask are null # and/or missing. # 3 One or more individual fields within the subnet mask exceeds # the maximum of 255 (a full 8-bit register). # 4 The subnet mask has either too few or too many fields. # 5 One or more individual fields within the subnet mask is an # invalid integer (only 0,128,192,224,240,248,252,254,255 are # valid integers). # f_validate_netmask() { local mask="$1" # Track number of fields for error checking local nfields=0 local IFS="." # Split on `dot' for field in $mask; do # Return error if the field is null [ "$field" ] || return 2 # Return error if not a whole positive integer f_isinteger "$field" || return 1 # Return error if the field exceeds 255 [ $field -gt 255 ] && return 3 # Return error if the field is an invalid integer case "$field" in 0|128|192|224|240|248|252|254|255) : ;; *) return 5 ;; esac nfields=$(( $nfields + 1 )) done [ $nfields -eq 4 ] || return 4 } # f_validate_gateway $gateway $ipaddr $netmask # # Validate an IPv4 default gateway (aka router) address for a given IP address # making sure the two are in the same network (able to ``talk'' to each other). # Returns success if $ipaddr and $gateway are in the same network given subnet # mask $netmask. # f_validate_gateway() { local gateway="$1" ipaddr="$2" netmask="$3" local gwnum ipnum masknum f_validate_ipaddr "$gateway" "$netmask" || return $FAILURE f_inet_atoi "$netmask" masknum f_inet_atoi "$ipaddr" ipnum f_inet_atoi "$gateway" gwnum # Gateway must be within set of IPs reachable through interface [ $(( $ipnum & $masknum )) -eq \ $(( $gwnum & $masknum )) ] # Return status } # f_dialog_validate_tcpip $hostname $gateway $nameserver $ipaddr $netmask # # Returns success if the arguments provided are valid for accessing a TCP/IP # network, otherwise returns failure. # f_dialog_validate_tcpip() { local hostname="$1" gateway="$2" nameserver="$3" local ipaddr="$4" netmask="$5" local ipnum masknum if [ ! "$hostname" ]; then f_show_msg "$msg_must_specify_a_host_name_of_some_sort" elif ! f_validate_hostname "$hostname"; then f_show_msg "$msg_invalid_hostname_value" elif [ "$netmask" ] && ! f_validate_netmask "$netmask"; then f_show_msg "$msg_invalid_netmask_value" elif [ "$nameserver" ] && ! f_validate_ipaddr "$nameserver" && ! f_validate_ipaddr6 "$nameserver"; then f_show_msg "$msg_invalid_name_server_ip_address_specified" elif [ "$ipaddr" ] && ! f_validate_ipaddr "$ipaddr" "$netmask"; then f_show_msg "$msg_invalid_ipv4_address" elif [ "$gateway" -a "$gateway" != "NO" ] && ! f_validate_gateway "$gateway" "$ipaddr" "$netmask"; then f_show_msg "$msg_invalid_gateway_ipv4_address_specified" else return $SUCCESS fi return $FAILURE } # f_ifconfig_inet $interface [$var_to_set] # # Returns the IPv4 address associated with $interface. If $var_to_set is # missing or NULL, the IP address is printed to standard output for capturing # in a sub-shell (which is less-recommended because of performance degredation; # for example, when called in a loop). # # This function is a two-parter. Below is the awk(1) portion of the function, # afterward is the sh(1) function which utilizes the below awk script. # f_ifconfig_inet_awk=' BEGIN { found = 0 } ( $1 == "inet" ) \ { print $2 found = 1 exit } END { exit ! found } ' f_ifconfig_inet() { local __interface="$1" __var_to_set="$2" if [ "$__var_to_set" ]; then local __ip __ip=$( ifconfig "$__interface" 2> /dev/null | awk "$f_ifconfig_inet_awk" ) setvar "$__var_to_set" "$__ip" else ifconfig "$__interface" 2> /dev/null | awk "$f_ifconfig_inet_awk" fi } # f_ifconfig_inet6 $interface [$var_to_set] # # Returns the IPv6 address associated with $interface. If $var_to_set is # missing or NULL, the IP address is printed to standard output for capturing # in a sub-shell (which is less-recommended because of performance degredation; # for example, when called in a loop). # # This function is a two-parter. Below is the awk(1) portion of the function, # afterward is the sh(1) function which utilizes the below awk script. # f_ifconfig_inet6_awk=' BEGIN { found = 0 } ( $1 == "inet6" ) \ { print $2 found = 1 exit } END { exit ! found } ' f_ifconfig_inet6() { local __interface="$1" __var_to_set="$2" if [ "$__var_to_set" ]; then local __ip6 __ip6=$( ifconfig "$__interface" 2> /dev/null | awk "$f_ifconfig_inet6_awk" ) setvar "$__var_to_set" "$__ip6" else ifconfig "$__interface" 2> /dev/null | awk "$f_ifconfig_inet6_awk" fi } # f_ifconfig_netmask $interface [$var_to_set] # # Returns the IPv4 subnet mask associated with $interface. If $var_to_set is # missing or NULL, the netmask is printed to standard output for capturing in a # sub-shell (which is less-recommended because of performance degredation; for # example, when called in a loop). # f_ifconfig_netmask() { local __interface="$1" __var_to_set="$2" __octets __octets=$( ifconfig "$__interface" 2> /dev/null | awk \ ' BEGIN { found = 0 } ( $1 == "inet" ) \ { printf "%s %s %s %s\n", substr($4,3,2), substr($4,5,2), substr($4,7,2), substr($4,9,2) found = 1 exit } END { exit ! found } ' ) || return $FAILURE local __octet __netmask= for __octet in $__octets; do __netmask="$__netmask.$( printf "%u" "0x$__octet" )" done __netmask="${__netmask#.}" if [ "$__var_to_set" ]; then setvar "$__var_to_set" "$__netmask" else echo $__netmask fi } # f_route_get_default [$var_to_set] # # Returns the IP address of the currently active default router. If $var_to_set # is missing or NULL, the IP address is printed to standard output for # capturing in a sub-shell (which is less-recommended because of performance # degredation; for example, when called in a loop). # # This function is a two-parter. Below is the awk(1) portion of the function, # afterward is the sh(1) function which utilizes the below awk script. # f_route_get_default_awk=' BEGIN { found = 0 } ( $1 == "gateway:" ) \ { print $2 found = 1 exit } END { exit ! found } ' f_route_get_default() { local __var_to_set="$1" if [ "$__var_to_set" ]; then local __ip __ip=$( route -n get default 2> /dev/null | awk "$f_route_get_default_awk" ) setvar "$__var_to_set" "$__ip" else route -n get default 2> /dev/null | awk "$f_route_get_default_awk" fi } # f_resolv_conf_nameservers [$var_to_set] # # Returns nameserver(s) configured in resolv.conf(5). If $var_to_set is missing # or NULL, the list of nameservers is printed to standard output for capturing # in a sub-shell (which is less-recommended because of performance degredation; # for example, when called in a loop). # # This function is a two-parter. Below is the awk(1) portion of the function, # afterward is the sh(1) function which utilizes the below awk script. # f_resolv_conf_nameservers_awk=' BEGIN { found = 0 } ( $1 == "nameserver" ) \ { print $2 found = 1 } END { exit ! found } ' f_resolv_conf_nameservers() { local __var_to_set="$1" if [ "$__var_to_set" ]; then local __ns __ns=$( awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \ 2> /dev/null ) setvar "$__var_to_set" "$__ns" else awk "$f_resolv_conf_nameservers_awk" "$RESOLV_CONF" \ 2> /dev/null fi } # f_config_resolv # # Attempts to configure resolv.conf(5) and ilk. Returns success if able to # write the file(s), otherwise returns error status. # # Variables from variable.subr that are used in configuring resolv.conf(5) are # as follows (all of which can be configured automatically through functions # like f_dhcp_get_info() or manually): # # VAR_NAMESERVER # The nameserver to add in resolv.conf(5). # VAR_DOMAINNAME # The domain to configure in resolv.conf(5). Also used in the # configuration of hosts(5). # VAR_IPADDR # The IPv4 address to configure in hosts(5). # VAR_IPV6ADDR # The IPv6 address to configure in hosts(5). # VAR_HOSTNAME # The hostname to associate with the IPv4 and/or IPv6 address in # hosts(5). # f_config_resolv() { local cp c6p dp hp f_getvar $VAR_NAMESERVER cp if [ "$cp" ]; then case "$RESOLV_CONF" in */*) f_quietly mkdir -p "${RESOLV_CONF%/*}" ;; esac # Attempt to create/truncate the file ( :> "$RESOLV_CONF" ) 2> /dev/null || return $FAILURE f_getvar $VAR_DOMAINNAME dp && printf "domain\t%s\n" "$dp" >> "$RESOLV_CONF" printf "nameserver\t%s\n" "$cp" >> "$RESOLV_CONF" f_dprintf "Wrote out %s" "$RESOLV_CONF" fi f_getvar $VAR_DOMAINNAME dp f_getvar $VAR_IPADDR cp f_getvar $VAR_IPV6ADDR c6p f_getvar $VAR_HOSTNAME hp # Attempt to create the file if it doesn't already exist if [ ! -e "$ETC_HOSTS" ]; then case "$ETC_HOSTS" in */*) f_quietly mkdir -p "${ETC_HOSTS%/*}" ;; esac ( :> "$ETC_HOSTS" ) 2> /dev/null || return $FAILURE fi # Scan the file and add ourselves if not already configured awk -v dn="$dp" -v ip4="$cp" -v ip6="$c6p" -v hn="$hp" ' BEGIN { local4found = local6found = 0 hn4found = hn6found = h4found = h6found = 0 h = ( match(hn, /\./) ? substr(hn, 0, RSTART-1) : "" ) } ($1 == "127.0.0.1") { local4found = 1 } ($1 == "::1") { local6found = 1 } { for (n = 2; n <= NF; n++) { if ( $1 == ip4 ) { if ( $n == h ) h4found = 1 if ( $n == hn ) hn4found = 1 if ( $n == hn "." ) hn4found = 1 } if ( $1 == ip6 ) { if ( $n == h ) h6found = 1 if ( $n == hn ) hn6found = 1 if ( $n == hn "." ) hn6found = 1 } } } END { hosts = FILENAME if ( ! local6found ) printf "::1\t\t\tlocalhost%s\n", ( dn ? " localhost." dn : "" ) >> hosts if ( ! local4found ) printf "127.0.0.1\t\tlocalhost%s\n", ( dn ? " localhost." dn : "" ) >> hosts if ( ip6 && ! (h6found && hn6found)) { printf "%s\t%s %s\n", ip6, hn, h >> hosts printf "%s\t%s.\n", ip6, hn >> hosts } else if ( ip6 ) { if ( ! h6found ) printf "%s\t%s.\n", ip6, h >> hosts if ( ! hn6found ) printf "%s\t%s\n", ip6, hn >> hosts } if ( ip4 && ! (h4found && hn4found)) { printf "%s\t\t%s %s\n", ip4, hn, h >> hosts printf "%s\t\t%s.\n", ip4, hn >> hosts } else if ( ip4 ) { if ( ! h4found ) printf "%s\t\t%s.\n", ip4, h >> hosts if ( ! hn4found ) printf "%s\t\t%s\n", ip4, hn >> hosts } } ' "$ETC_HOSTS" 2> /dev/null || return $FAILURE f_dprintf "Wrote out %s" "$ETC_HOSTS" return $SUCCESS } # f_dhcp_parse_leases $leasefile struct_name # # Parse $leasefile and store the information for the most recent lease in a # struct (see struct.subr for additional details) named `struct_name'. See # DHCP_LEASE struct definition in the GLOBALS section above. # f_dhcp_parse_leases() { local leasefile="$1" struct_name="$2" [ "$struct_name" ] || return $FAILURE if [ ! -e "$leasefile" ]; then f_dprintf "%s: No such file or directory" "$leasefile" return $FAILURE fi f_struct "$struct_name" && f_struct_free "$struct_name" f_struct_new DHCP_LEASE "$struct_name" eval "$( awk -v struct="$struct_name" ' BEGIN { lease_found = 0 keyword_list = " \ interface \ fixed-address \ filename \ server-name \ script \ medium \ " split(keyword_list, keywords, FS) time_list = "renew rebind expire" split(time_list, times, FS) option_list = " \ host-name \ subnet-mask \ routers \ domain-name-servers \ domain-name \ broadcast-address \ dhcp-lease-time \ dhcp-message-type \ dhcp-server-identifier \ dhcp-renewal-time \ dhcp-rebinding-time \ " split(option_list, options, FS) } function set_value(prop,value) { lease_found = 1 gsub(/[^[:alnum:]_]/, "_", prop) sub(/;$/, "", value) sub(/^"/, "", value) sub(/"$/, "", value) sub(/,.*/, "", value) printf "%s set %s \"%s\"\n", struct, prop, value } /^lease {$/, /^}$/ \ { if ( $0 ~ /^lease {$/ ) next if ( $0 ~ /^}$/ ) exit for (k in keywords) { keyword = keywords[k] if ( $1 == keyword ) { set_value(keyword, $2) next } } for (t in times) { time = times[t] if ( $1 == time ) { set_value(time, $2 " " $3 " " $4) next } } if ( $1 != "option" ) next for (o in options) { option = options[o] if ( $2 == option ) { set_value(option, $3) next } } } EXIT { if ( ! lease_found ) { printf "f_struct_free \"%s\"\n", struct print "return $FAILURE" } } ' "$leasefile" )" } # f_dhcp_get_info $interface # # Parse the dhclient(8) lease database for $interface to obtain all the # necessary IPv4 details necessary to communicate on the network. The retrieved # information is stored in VAR_IPADDR, VAR_NETMASK, VAR_GATEWAY, and # VAR_NAMESERVER. # # If reading the lease database fails, values are obtained from ifconfig(8) and # route(8). If the DHCP lease did not provide a nameserver (or likewise, we # were unable to parse the lease database), fall-back to resolv.conf(5) for # obtaining the nameserver. Always returns success. # f_dhcp_get_info() { local interface="$1" cp local leasefile="/var/db/dhclient.leases.$interface" # If it fails, do it the old-fashioned way if f_dhcp_parse_leases "$leasefile" lease; then lease get fixed_address $VAR_IPADDR lease get subnet_mask $VAR_NETMASK lease get routers cp setvar $VAR_GATEWAY "${cp%%,*}" lease get domain_name_servers cp setvar $VAR_NAMESERVER "${cp%%,*}" lease get host_name cp && setvar $VAR_HOSTNAME "$cp" f_struct_free lease else # Bah, now we have to get the information from ifconfig if f_debugging; then f_dprintf "DHCP configured interface returns %s" \ "$( ifconfig "$interface" )" fi f_ifconfig_inet "$interface" $VAR_IPADDR f_ifconfig_netmask "$interface" $VAR_NETMASK f_route_get_default $VAR_GATEWAY fi # If we didn't get a name server value, hunt for it in resolv.conf local ns if [ -r "$RESOLV_CONF" ] && ! { f_getvar $VAR_NAMESERVER ns || [ "$ns" ] }; then f_resolv_conf_nameservers cp && setvar $VAR_NAMESERVER ${cp%%[$IFS]*} fi return $SUCCESS } # f_rtsol_get_info $interface # # Returns the rtsol-provided IPv6 address associated with $interface. The # retrieved IP address is stored in VAR_IPV6ADDR. Always returns success. # f_rtsol_get_info() { local interface="$1" cp cp=$( ifconfig "$interface" 2> /dev/null | awk \ ' BEGIN { found = 0 } ( $1 == "inet6" ) && ( $2 ~ /^fe80:/ ) \ { print $2 found = 1 exit } END { exit ! found } ' ) && setvar $VAR_IPV6ADDR "$cp" } # f_host_lookup $host [$var_to_set] # # Use host(1) to lookup (or reverse) an Internet number from (or to) a name. # Multiple answers are returned separated by a single space. If host(1) does # not exit cleanly, its full output is provided and the return status is 1. # # If nsswitch.conf(5) has been configured to query local access first for the # `hosts' database, we'll manually check hosts(5) first (preventing host(1) # from hanging in the event that DNS goes awry). # # If $var_to_set is missing or NULL, the list of IP addresses is printed to # standard output for capturing in a sub-shell (which is less-recommended # because of performance degredation; for example, when called in a loop). # # The variables from variable.subr used in looking up the host are as follows # (which are set manually): # # VAR_IPV6_ENABLE [Optional] # If set to "YES", enables the lookup of IPv6 addresses and IPv4 # address. IPv6 addresses, if any, will come before IPv4. Note # that if nsswitch.conf(5) shows an affinity for "files" for the # "host" database and there is a valid entry in hosts(5) for # $host, this setting currently has no effect (an IPv4 address # can supersede an IPv6 address). By design, hosts(5) overrides # any preferential treatment. Otherwise, if this variable is not # set, IPv6 addresses will not be used (IPv4 addresses will # specifically be requested from DNS). # # This function is a two-parter. Below is the awk(1) portion of the function, # afterward is the sh(1) function which utilizes the below awk script. # f_host_lookup_awk=' BEGIN{ addrs = "" } !/^[[:space:]]*(#|$)/ \ { for (n=1; n++ < NF;) if ($n == name) addrs = addrs (addrs ? " " : "") $1 } END { if (addrs) print addrs exit !addrs } ' f_host_lookup() { local __host="$1" __var_to_set="$2" f_dprintf "f_host_lookup: host=[%s]" "$__host" # If we're configured to look at local files first, do that if awk '/^hosts:/{exit !($2=="files")}' "$NSSWITCH_CONF"; then if [ "$__var_to_set" ]; then local __cp if __cp=$( awk -v name="$__host" \ "$f_host_lookup_awk" "$ETC_HOSTS" ) then setvar "$__var_to_set" "$__cp" return $SUCCESS fi else awk -v name="$__host" \ "$f_host_lookup_awk" "$ETC_HOSTS" && return $SUCCESS fi fi # # Fall back to host(1) -- which is further governed by nsswitch.conf(5) # local __output __ip6 __addrs="" __wait="" f_getvar $VAR_MEDIA_TIMEOUT __wait [ "$__wait" ] && __wait="-W $(( $__wait / 2 ))" f_getvar $VAR_IPV6_ENABLE __ip6 if [ "$__ip6" = "YES" ]; then if ! __output=$( host -t AAAA $__wait -- "$__host" 2>&1 ); then # An error occurred, display in-full and return error [ "$__var_to_set" ] && setvar "$__var_to_set" "$__output" return $FAILURE fi __addrs=$( echo "$__output" | awk '/ address /{print $NF}' ) fi if ! __output=$( host -t A $__wait -- "$__host" 2>&1 ); then # An error occurred, display it in-full and return error [ "$__var_to_set" ] && setvar "$__var_to_set" "$__output" return $FAILURE fi __addrs="$__addrs${__addrs:+ }$( echo "$__output" | awk '/ address /{print $NF}' )" if [ "$__var_to_set" ]; then setvar "$__var_to_set" "$__addrs" else echo $__addrs fi } # f_device_dialog_tcp $device # # This is it - how to get TCP setup values. Prompt the user to edit/confirm the # interface, gateway, nameserver, and hostname settings -- all required for # general TCP/IP access. # # Variables from variable.subr that can be used to sript user input: # # VAR_NO_INET6 # If set, prevents asking the user if they would like to use # rtsol(8) to check for an IPv6 router. # VAR_TRY_RTSOL # If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the # user if they would like to try the IPv6 RouTer SOLicitation # utility (rtsol(8)) to get IPv6 information. Ignored if # VAR_NO_INET6 is set. # VAR_TRY_DHCP # If set to "YES" (and VAR_NONINTERACTIVE is unset), asks the # user if they would like to try to acquire IPv4 connection # settings from a DHCP server using dhclient(8). # # VAR_GATEWAY Default gateway to use. # VAR_IPADDR Interface address to assign. # VAR_NETMASK Interface subnet mask. # VAR_EXTRAS Extra interface options to ifconfig(8). # VAR_HOSTNAME Hostname to set. # VAR_DOMAINNAME Domain name to use. # VAR_NAMESERVER DNS nameserver to use when making lookups. # VAR_IPV6ADDR IPv6 interface address. # # In addition, the following variables are used in acquiring network settings # from the user: # # VAR_NONINTERACTIVE # If set (such as when running in a script), prevents asking the # user questions or displaying the usual prompts, etc. # VAR_NETINTERACTIVE # The one exception to VAR_NONINTERACTIVE is VAR_NETINTERACTIVE, # which if set will prompt the user to try RTSOL (unless # VAR_TRY_RTSOL has been set), try DHCP (unless VAR_TRY_DHCP has # been set), and display the network verification dialog. This # allows you to have a mostly non-interactive script that still # prompts for network setup/confirmation. # # After successfull execution, the following variables are set: # # VAR_IFCONFIG + $device (e.g., `ifconfig_em0') # Defines the ifconfig(8) properties specific to $device. # f_device_dialog_tcp() { local dev="$1" cp n local use_dhcp="" use_rtsol="" local _ipaddr _netmask _extras [ "$dev" ] || return $FAILURE # Initialize vars from previous device values local private device_$dev get private private if [ "$private" ] && f_struct "$private"; then $private get ipaddr _ipaddr $private get netmask _netmask $private get extras _extras $private get use_dhcp use_dhcp $private get use_rtsol use_rtsol else # See if there are any defaults # # This is a hack so that the dialogs below are interactive in a # script if we have requested interactive behavior. # local old_interactive= if ! f_interactive && f_netinteractive; then f_getvar $VAR_NONINTERACTIVE old_interactive unset $VAR_NONINTERACTIVE fi # # Try a RTSOL scan if such behavior is desired. # If the variable was configured and is YES, do it. # If it was configured to anything else, treat it as NO. # Otherwise, ask the question interactively. # local try6 if ! f_isset $VAR_NO_INET6 && { { f_getvar $VAR_TRY_RTSOL try6 && [ "$try6" = "YES" ]; } || { # Only prompt the user when VAR_TRY_RTSOL is unset ! f_isset $VAR_TRY_RTSOL && f_dialog_noyes "$msg_try_ipv6_configuration" } }; then local i f_quietly sysctl net.inet6.ip6.forwarding=0 f_quietly sysctl net.inet6.ip6.accept_rtadv=1 f_quietly ifconfig $dev up i=$( sysctl -n net.inet6.ip6.dad_count ) sleep $(( $i + 1 )) f_quietly mkdir -p /var/run f_dialog_info "$msg_scanning_for_ra_servers" if f_quietly rtsol $dev; then i=$( sysctl -n net.inet6.ip6.dad_count ) sleep $(( $i + 1 )) f_rtsol_get_info $dev use_rtsol=1 else use_rtsol= fi fi # # Try a DHCP scan if such behavior is desired. # If the variable was configured and is YES, do it. # If it was configured to anything else, treat it as NO. # Otherwise, ask the question interactively. # local try4 if { f_getvar $VAR_TRY_DHCP try4 && [ "$try4" = "YES" ]; } || { # Only prompt the user when VAR_TRY_DHCP is unset ! f_isset $VAR_TRY_DHCP && f_dialog_noyes "$msg_try_dhcp_configuration" }; then f_quietly ifconfig $dev delete f_quietly mkdir -p /var/db f_quietly mkdir -p /var/run f_quietly mkdir -p /tmp local msg="$msg_scanning_for_dhcp_servers" trap - SIGINT ( # Execute in sub-shell to allow/catch Ctrl-C trap 'exit $FAILURE' SIGINT if [ "$USE_XDIALOG" ]; then f_quietly dhclient $dev | f_xdialog_info "$msg" else f_dialog_info "$msg" f_quietly dhclient $dev fi ) local retval=$? trap 'f_interrupt' SIGINT if [ $retval -eq $SUCCESS ]; then f_dhcp_get_info $dev use_dhcp=1 else use_dhcp= fi fi # Restore old VAR_NONINTERACTIVE if needed. [ "$old_interactive" ] && setvar $VAR_NONINTERACTIVE "$old_interactive" # Special hack so it doesn't show up oddly in the menu local gw if f_getvar $VAR_GATEWAY gw && [ "$gw" = "NO" ]; then setvar $VAR_GATEWAY "" fi # Get old IP address from variable space, if available if [ ! "$_ipaddr" ]; then if f_getvar $VAR_IPADDR cp; then _ipaddr="$cp" elif f_getvar ${dev}_$VAR_IPADDR cp; then _ipaddr="$cp" fi fi # Get old netmask from variable space, if available if [ ! "$_netmask" ]; then if f_getvar $VAR_NETMASK cp; then _netmask="$cp" elif f_getvar ${dev}_$VAR_NETMASK cp; then _netmask="$cp" fi fi # Get old extras string from variable space, if available if [ ! "$_extras" ]; then if f_getvar $VAR_EXTRAS cp; then _extras="$cp" elif f_getvar ${dev}_$VAR_EXTRAS cp; then _extras="$cp" fi fi fi # Look up values already recorded with the system, or blank the string # variables ready to accept some new data local _hostname _gateway _nameserver f_getvar $VAR_HOSTNAME _hostname case "$_hostname" in *.*) : do nothing ;; # Already fully-qualified *) f_getvar $VAR_DOMAINNAME cp [ "$cp" ] && _hostname="$_hostname.$cp" esac f_getvar $VAR_GATEWAY _gateway f_getvar $VAR_NAMESERVER _nameserver # Re-check variables for initial inheritance before heading into dialog [ "$_hostname" ] || _hostname="${HOSTNAME:-$( hostname )}" [ "$_gateway" ] || f_route_get_default _gateway [ ! "$_nameserver" ] && f_resolv_conf_nameservers cp && _nameserver=${cp%%[$IFS]*} [ "$_ipaddr" ] || f_ifconfig_inet $dev _ipaddr [ "$_netmask" ] || f_ifconfig_netmask $dev _netmask # If non-interactive, jump over dialog section and into config section if f_netinteractive || f_interactive || [ ! "$_hostname" ] then [ ! "$_hostname" ] && f_interactive && f_show_msg "$msg_hostname_variable_not_set" local title=" $msg_network_configuration " local hline="$hline_alnum_arrows_punc_tab_enter" local extras_help="$tcplayout_extras_help" # Modify the help line for PLIP config [ "${dev#plip}" != "$dev" ] && extras_help="$tcplayout_extras_help_for_plip" f_getvar $VAR_IPV6ADDR cp && [ "$cp" ] && title="$title($msg_ipv6_ready) " if [ ! "$USE_XDIALOG" ]; then local prompt="$msg_dialog_mixedform_navigation_help" # Calculate center position for displaying device label local devlabel="$msg_configuration_for_interface $dev" local width=54 local n=$(( $width/2 - (${#devlabel} + 4)/2 - 2 )) while :; do cp=$( $DIALOG \ --title "$title" \ --backtitle "$DIALOG_BACKTITLE" \ --hline "$hline" \ --item-help \ --ok-label "$msg_ok" \ --cancel-label "$msg_cancel" \ --help-button \ --help-label "$msg_help" \ --mixedform "$prompt" 16 $width 9 \ "$msg_host_name_including_domain:" 1 2 \ "$_hostname" 2 3 45 255 0 \ "$tcplayout_hostname_help" \ "$msg_ipv4_gateway:" 3 2 \ "$_gateway" 4 3 16 15 0 \ "$tcplayout_gateway_help" \ "$msg_name_server:" 3 31 \ "$_nameserver" 4 32 16 15 0 \ "$tcplayout_nameserver_help" \ "- $devlabel -" 5 $n "" 0 0 0 0 3 "" \ "$msg_ipv4_address:" 6 6 \ "$_ipaddr" 7 7 16 15 0 \ "$tcplayout_ipaddr_help" \ "$msg_netmask:" 6 31 \ "$_netmask" 7 32 16 15 0 \ "$tcplayout_netmask_help" \ "$msg_extra_options_to_ifconfig" 8 6 \ "$_extras" 9 7 41 2048 0 \ "$extras_help" \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) # --mixed-form always returns 0, we have to # use the returned data to determine button if [ ! "$cp" ]; then # User either chose "Cancel", pressed # ESC, or blanked every form field return $FAILURE else n=$( echo "$cp" | f_number_of_lines ) [ $n -eq 1 ] && case "$cp" in HELP*) # User chose "Help" f_show_help "$TCP_HELPFILE" continue esac fi # Turn mixed-form results into env variables eval "$( echo "$cp" | awk ' BEGIN { n = 0 field[++n] = "_hostname" field[++n] = "_gateway" field[++n] = "_nameserver" field[++n] = "_ipaddr" field[++n] = "_netmask" field[++n] = "_extras" nfields = n n = 0 } { gsub(/'\''/, "'\'\\\\\'\''") sub(/[[:space:]]*$/, "") value[field[++n]] = $0 } END { for ( n = 1; n <= nfields; n++ ) { printf "%s='\''%s'\'';\n", field[n], value[field[n]] } }' )" f_dialog_validate_tcpip \ "$_hostname" \ "$_gateway" \ "$_nameserver" \ "$_ipaddr" \ "$_netmask" \ && break done else # Xdialog(1) does not support --mixed-form # Create a persistent menu instead f_dialog_title "$msg_network_configuration" local prompt= while :; do cp=$( $DIALOG \ --title "$DIALOG_TITLE" \ --backtitle "$DIALOG_BACKTITLE" \ --hline "$hline" \ --item-help \ --ok-label "$msg_ok" \ --cancel-label "$msg_cancel" \ --help "" \ --menu "$prompt" 21 60 8 \ "$msg_accept_continue" "" \ "$tcplayout_accept_cont_help" \ "$msg_host_name_including_domain:" \ "$_hostname" \ "$tcplayout_hostname_help" \ "$msg_ipv4_gateway:" "$_gateway" \ "$tcplayout_gateway_help" \ "$msg_name_server:" "$_nameserver" \ "$tcplayout_nameserver_help" \ "$msg_ipv4_address:" "$_ipaddr" \ "$tcplayout_ipaddr_help" \ "$msg_netmask:" "$_netmask" \ "$tcplayout_netmask_help" \ "$msg_extra_options_to_ifconfig" \ "$_extras" "$extras_help" \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) local retval=$? f_dialog_data_sanitize cp f_dprintf "retval=%u mtag=[%s]" $retval "$cp" if [ $retval -eq 2 ]; then # The Help button was pressed f_show_help "$TCP_HELPFILE" continue elif [ $retval -ne 0 ]; then # User chose "Cancel" or pressed ESC f_dialog_title_restore return $FAILURE fi case "$cp" in "$msg_accept_continue") f_dialog_validate_tcpip \ "$_hostname" \ "$_gateway" \ "$_nameserver" \ "$_ipaddr" \ "$_netmask" \ && break ;; "$msg_host_name_including_domain:") f_dialog_input cp "$cp" "$_hostname" \ && _hostname="$cp" ;; "$msg_ipv4_gateway:") f_dialog_input cp "$cp" "$_gateway" \ && _gateway="$cp" ;; "$msg_name_server:") f_dialog_input cp "$cp" "$_nameserver" \ && _nameserver="$cp" ;; "$msg_ipv4_address:") f_dialog_input cp "$cp" "$_ipaddr" \ && _ipaddr="$cp" ;; "$msg_netmask:") f_dialog_input cp "$cp" "$_netmask" \ && _netmask="$cp" ;; "$msg_extra_options_to_ifconfig") f_dialog_input cp "$cp" "$_extras" \ && _extras="$cp" ;; esac done f_dialog_title_restore fi # XDIALOG fi # interactive # We actually need to inform the rest of bsdconfig about this # data now if the user hasn't selected cancel. if [ "$_hostname" ]; then setvar $VAR_HOSTNAME "$_hostname" f_quietly hostname "$_hostname" case "$_hostname" in *.*) setvar $VAR_DOMAINNAME "${_hostname#*.}" ;; esac fi [ "$_gateway" ] && setvar $VAR_GATEWAY "$_gateway" [ "$_nameserver" ] && setvar $VAR_NAMESERVER "$_nameserver" [ "$_ipaddr" ] && setvar $VAR_IPADDR "$_ipaddr" [ "$_netmask" ] && setvar $VAR_NETMASK "$_netmask" [ "$_extras" ] && setvar $VAR_EXTRAS "$_extras" f_dprintf "Creating struct DEVICE_INFO devinfo_%s" "$dev" f_struct_new DEVICE_INFO devinfo_$dev device_$dev set private devinfo_$dev devinfo_$dev set ipaddr $_ipaddr devinfo_$dev set netmask $_netmask devinfo_$dev set extras $_extras devinfo_$dev set use_rtsol $use_rtsol devinfo_$dev set use_dhcp $use_dhcp if [ "$use_dhcp" -o "$_ipaddr" ]; then if [ "$use_dhcp" ]; then cp="DHCP${extras:+ $extras}" else cp="inet $_ipaddr netmask $_netmask${extras:+ $extras}" fi setvar $VAR_IFCONFIG$dev "$cp" fi [ "$use_rtsol" ] && setvar $VAR_IPV6_ENABLE "YES" [ "$use_dhcp" ] || f_config_resolv # XXX this will do it on the MFS copy return $SUCCESS } # f_device_scan_tcp [$var_to_set] # # Scan for the first active/configured TCP/IP device. The name of the interface # is printed to stderr like other dialog(1)-based functions (stdout is reserved # for dialog(1) interaction) if $var_to_set is missing or NULL. Returns failure # if no active/configured interface # f_device_scan_tcp() { local __var_to_set="$1" __iface for __iface in $( ifconfig -l ); do if ifconfig $__iface | awk ' BEGIN { has_inet = has_inet6 = is_ethernet = 0 is_usable = 1 } ( $1 == "status:" && $2 != "active" ) { is_usable = 0; exit } ( $1 == "inet" ) { if ($2 == "0.0.0.0") { is_usable = 0; exit } has_inet++ } ( $1 == "inet6") { has_inet6++ } ( $1 == "media:" ) { if ($2 != "Ethernet") { is_usable = 0; exit } is_ethernet = 1 } END { if (!(is_ethernet && (has_inet || has_inet6))) is_usable = 0 exit ! is_usable }'; then f_interactive && f_show_msg "$msg_using_interface" "$__iface" f_dprintf "f_device_scan_tcp found %s" "$__iface" if [ "$__var_to_set" ]; then setvar "$__var_to_set" "$__iface" else echo "$__iface" >&2 fi return $SUCCESS fi done return $FAILURE } # f_device_select_tcp # # Prompt the user to select network interface to use for TCP/IP access. # Variables from variable.subr that can be used to script user input: # # VAR_NETWORK_DEVICE [Optional] # Either a comma-separated list of network interfaces to try when # setting up network access (e.g., "fxp0,em0") or "ANY" (case- # sensitive) to indicate that the first active and configured # interface is acceptable. If unset, the user is presented with a # menu of all available network interfaces. # # Returns success if a valid network interface has been selected. # f_device_select_tcp() { local devs dev cnt network_dev f_getvar $VAR_NETWORK_DEVICE network_dev f_dprintf "f_device_select_tcp: %s=[%s]" \ VAR_NETWORK_DEVICE "$network_dev" if [ "$network_dev" ]; then # # This can be set to several types of values. If set to ANY, # scan all network devices looking for a valid link, and go # with the first device found. Can also be specified as a # comma delimited list, with each network device tried in # order. Can also be set to a single network device. # [ "$network_dev" = "ANY" ] && f_device_scan_tcp network_dev while [ "$network_dev" ]; do case "$network_dev" in *,*) dev="${network_dev%%,*}" network_dev="${network_dev#*,}" ;; *) dev="$network_dev" network_dev= esac f_device_find "$dev" $DEVICE_TYPE_NETWORK devs cnt=$( set -- $devs; echo $# ) if [ ${cnt:=0} -gt 0 ]; then dev="${devs%%[$IFS]*}" f_device_dialog_tcp $dev if [ $? -eq $SUCCESS ]; then setvar $VAR_NETWORK_DEVICE $dev return $SUCCESS fi fi done f_interactive && f_show_msg "$msg_no_network_devices" return $FAILURE fi # $network_dev f_device_find "" $DEVICE_TYPE_NETWORK devs cnt=$( set -- $devs; echo $# ) dev="${devs%%[$IFS]*}" f_quietly f_getvar NETWORK_CONFIGURED # for debugging info if ! f_running_as_init && ! [ "${NETWORK_CONFIGURED+set}" -a "$NETWORK_CONFIGURED" = "NO" ] then trap 'f_interrupt' SIGINT if f_dialog_yesno "$msg_assume_network_is_already_configured" then setvar $VAR_NETWORK_DEVICE $dev return $SUCCESS fi fi local retval=$SUCCESS if [ ${cnt:=0} -eq 0 ]; then f_show_msg "$msg_no_network_devices" retval=$FAILURE elif [ $cnt -eq 1 ]; then f_device_dialog_tcp $dev retval=$? [ $retval -eq $SUCCESS ] && setvar $VAR_NETWORK_DEVICE $dev else local title="$msg_network_interface_information_required" local prompt="$msg_please_select_ethernet_device_to_configure" local hline="$hline_arrows_tab_enter" dev=$( f_device_menu \ "$title" "$prompt" "$hline" $DEVICE_TYPE_NETWORK \ "$NETWORK_DEVICE_HELPFILE" \ 2>&1 >&$DIALOG_TERMINAL_PASSTHRU_FD ) retval=$? [ "$dev" ] || return $FAILURE f_device_find "$dev" $DEVICE_TYPE_NETWORK devs [ "$devs" ] || return $FAILURE dev="${devs%%[$IFS]*}" f_device_dialog_tcp $dev retval=$? if [ $retval -eq $SUCCESS ]; then f_struct_copy device_$dev device_network setvar $VAR_NETWORK_DEVICE network else f_struct_free device_network fi fi return $retval } # f_dialog_menu_select_tcp # # Like f_dialog_select_tcp() above, but do it from a menu that doesn't care # about status. In other words, where f_dialog_select_tcp() will not display a # menu if scripted, this function will always display the menu of available # network interfaces. # f_dialog_menu_select_tcp() { local private use_dhcp name NETWORK_CONFIGURED=NO f_device_select_tcp if f_struct device_network && device_network get private private && f_struct_copy "$private" di && di get use_dhcp use_dhcp && [ ! "$use_dhcp" ] && device_network get name name && f_yesno "$msg_would_you_like_to_bring_interface_up" "$name" then if ! f_device_init network; then f_show_msg "$msg_initialization_of_device_failed" \ "$name" fi fi return $SUCCESS } ############################################################ MAIN f_dprintf "%s: Successfully loaded." media/tcpip.subr fi # ! $_MEDIA_TCPIP_SUBR