![]() |
| October 2001 | Get BSD | New to BSD? | Search BSD | Submit News | FAQ | Contact Us | Join Us |
|
For several years now, I've been using FreeBSD on my laptop at work. Since I am often at different customer sites on any given day, I must adjust my laptop settings according to their network, which means a new IP address, new name server, new default gateway and so on. Editing rc.conf, resolv.conf and friends by hand was tedious. I needed something that was easy to set up, use, develop and maintain.
After experimenting with shell scripts, it became clear that I needed a manageable method of entering parameters. When I arrive at a customer's site, they usually have a fairly urgent problem and expect me to start working immediately - not to take several minutes to connect to their LAN. Therefore, I wanted some form of menu-based interaction with a program that asks me to enter parameters, then does the rest for me. The key parameters to change are:
the network interface name
any additional flags or arguments suitable for ifconfig(8)
the IP address
the subnet mask
the host name
the domain name
the default gateway
and the name server.
And, because you never know, I wanted to be able to specify the name of a site-specific shell script that should be executed to do any additional customization.
In addition, it should be possible to put all of the information in some form of a database. Once an entry was set up or chosen, the information should be persistent between reboots.
Well, I sat down one day and aggregated some curses menuing subroutines that I had used in earlier projects and wrote setnetparm using the curses library (for those who don't know, curses is a programming library for writing character-based, full-screen applications and is part of FreeBSD's base system) and some scripts needed to interface to the FreeBSD startup and boot system.
The data that setnetparm operates on, and most of the scripts, reside in a newly created directory, /etc/mobile.
First, we need some form of database to store the information for the places that I regularly visit. Because I was in a hurry, I settled on a simple line-oriented, fixed-format text file database. It's not one of the brightest ideas I've had, but it has worked quite well until now. This database is called laptop.menu and contains all the setup information I need for a given site as well as a site name, which I can choose in a menu.
At the beginning of laptop.menu the user must set two parameters: (a) the time in seconds between the initial menu display to the continuation of the boot process with the currently configured values, (b) a list of the allowed network interface names.
The first line in each entry is a description or name of the entry. This line is displayed in the menu, and allows you to choose by this name a set of predefined values from the database.
This file contains the current settings that are the result of the last run of setnetparm. It has the same format as one entry in the laptop.menu file. When the user has chosen an entry or entered new parameters, setnetparm saves this parameter set to the file laptop.curr where it is kept until the user decides to select a different set of parameters.
Now it's time for a screen shot - it shows the setnetparm initial screen two seconds after it was invoked:

In the upper half of the window you see two blocks of information: the current values show the content of laptop.curr and the new values, which are empty because the user has not yet chosen anything else. The timeout counter counts down (currently 8 seconds left). In case the user does nothing at this point, setnetparm terminates in 8 seconds and the current values will be used to configure the laptop.
Any key press will stop the timeout, and then you are able to use the menu in the lower half of the screen. Items 1, 2 and 3 are special in that they allow you to exit setnetparm with the current values (item 1), or the new values (item 3), or to enter new values on the fly (item 2). Items 4 to 10 are symbolic names taken from the first line of each entry in the laptop.menu database file.
In case the user decides to enter new values on the fly, he chooses item 2: Enter new values. He is presented several editable entry fields to enter new values; this is how it looks:

New values have already been entered for the IP address, subnet mask, interface flags and host name, and the user is currently entering or editing the new value for the domain name. After the user has entered values for the remaining parameters, the main menu is displayed:

Usually one just presses Enter here to get the new values and leave the setnetparm program. The values displayed in the New Values column are saved in the laptop.curr file upon exit of setnetparm.
The main part of the FreeBSD boot process and initial machine configuration is done by the /etc/rcshell script, If you would like more information on this, have a look at the FreeBSD handbook and at the rc(8) manual page.
In order to call setnetparm at boot time, one must intercept the boot process, run setnetparm, change the machine configuration and then continue with the boot process. For this to work, /etc/rc has to be patched with a diff provided with the package.
To understand how the patch to /etc/rc works, two additional files need to be mentioned: /etc/mobile/rc.special and /etc/mobile/rc.conf.mobile. The first one is a copy of the optional shell script, which can be executed to perform additional customization; the second one is used to help configure the host name, the default gateway and the ifconfig flags. The following code gets patched to /etc/rc to run at boot time right after the file systems are mounted and swap is configured:
1 if [ -r /etc/rc.mobile ] 2 then 3 # remove old rc.special if one exists 4 if [ -r /etc/mobile/rc.special ]; then 5 rm -f /etc/mobile/rc.special 6 fi 7 # remove old rc.conf.mobile if one exists 8 if [ -r /etc/mobile/rc.conf.mobile ]; then 9 rm -f /etc/mobile/rc.conf.mobile 10 fi 11 # execute rc.mobile 12 . /etc/rc.mobile 13 # execute new rc.conf.mobile if one exists 14 if [ -r /etc/mobile/rc.conf.mobile ]; then 15 . /etc/mobile/rc.conf.mobile 16 fi 17 # execute new rc.special if one exists 18 if [ -r /etc/mobile/rc.special ]; then 19 . /etc/mobile/rc.special 20 fi 21 fi
After a sanity check if /etc/rc.mobile (discussed below) does really exist, old copies of the just mentioned two files are deleted (lines 3-10). After that the script /etc/rc.mobile is executed (line 12) and if it produces new copies of /etc/mobile/rc.special and /etc/mobile/rc.conf.mobile they also get executed after that (lines 13-20). That's quite simple, isn't it?
This is the shell script that gets called from the aforementioned patch to /etc/rc. It is somewhat more complicated and the real workhouse of the boot process integration of the setnetparms package:
1 MOBILE=/etc/mobile 2 DEFS=$MOBILE/laptop.curr 3 PROGPATH=/root/bin 4 RCCONF=$MOBILE/rc.conf.mobile 5 RCSPEC=$MOBILE/rc.special 6 # check for /etc/mobile/laptop.curr, if no available, create it 7 if [ ! -r $DEFS ] 8 then 9 echo "card" >$DEFS 10 echo "192.168.168.168" >>$DEFS 11 echo "255.255.255.0" >>$DEFS 12 echo "link0 -link1" >>$DEFS 13 echo "myname" >>$DEFS 14 echo "mydomain.org" >>$DEFS 15 echo "192.168.168.1" >>$DEFS 16 echo "192.168.168.1" >>$DEFS 17 echo "script.myname" >>$DEFS 18 fi 19 # adjust permissions for /etc/mobile/laptop.curr 20 chown root:wheel $DEFS 21 chmod u=rw,og=r $DEFS 22 # prepare for running setnetparm 23 if [ -x $PROGPATH/setnetparm ] 24 then 25 # set TERM environment variable, curses needs it! 26 TERM=cons25 27 # check for pcvt (VT100/VT220 emulator). pcvt is runtime detectable! 28 if test -x /usr/sbin/ispcvt; then 29 if /usr/sbin/ispcvt; then 30 TERM=pcvt25 31 fi 32 fi 33 export TERM 34 # init terminal 35 # tput init 36 # run setnetparm 37 $PROGPATH/setnetparm 38 # process the resulting /etc/mobile/laptop.curr file 39 # first, suck the contents of /etc/mobile/laptop.curr into variables 40 index=1 41 exec 3<$DEFS 42 while read LINE 0<&3 43 do 44 case $index in 45 1) newiface=$LINE ;; 46 2) newipaddr=$LINE ;; 47 3) newsubnetmask=$LINE ;; 48 4) newflags=$LINE ;; 49 5) newhostname=$LINE ;; 50 6) newdomainname=$LINE ;; 51 7) newgwaddr=$LINE ;; 52 8) newnameserver=$LINE ;; 53 9) newscript=$LINE ;; 54 esac 55 index=`expr $index + 1` 56 done 57 if [ $newipaddr = "DHCP" ] 58 then 59 # second, patch /etc/rc.conf and /etc/resolv.conf using the variables 60 exec 3<&- 61 cat $MOBILE/rc.conf.t | /usr/bin/sed \ 62 -e "s/IFNAMETEMPLATE/\"$newiface\"/g" \ 63 -e "s/IFNQNAMETEMPLATE/$newiface/g" \ 64 -e "s/HOSTTEMPLATE/\"$newhostname.$newdomainname\"/g" \ 65 -e "s/DEFGWTEMPLATE/\"$newgwaddr\"/g" \ 66 -e "s/IFTEMPLATE/\"$newipaddr\"/g" \ 67 > $RCCONF 68 else 69 # second, patch /etc/rc.conf and /etc/resolv.conf using the variables 70 exec 3<&- 71 cat $MOBILE/rc.conf.t | /usr/bin/sed \ 72 -e "s/IFNAMETEMPLATE/\"$newiface\"/g" \ 73 -e "s/IFNQNAMETEMPLATE/$newiface/g" \ 74 -e "s/HOSTTEMPLATE/\"$newhostname.$newdomainname\"/g" \ 75 -e "s/DEFGWTEMPLATE/\"$newgwaddr\"/g" \ 76 -e "s/IFTEMPLATE/\"$newipaddr netmask $newsubnetmask $newflags\"/g" \ 77 > $RCCONF 78 cat $MOBILE/resolv.conf.t | /usr/bin/sed \ 79 -e "s/DOMAINTEMPLATE/$newdomainname/g" \ 80 -e "s/NAMESERVERTEMPLATE/$newnameserver/g" \ 81 > /etc/resolv.conf 82 fi 83 # cp special configuration script into place to get it executed 84 if [ -r $MOBILE/$newscript ] 85 then 86 cp $MOBILE/$newscript $RCSPEC 87 fi 88 fi
| line | description |
|---|---|
| 1-5 | assign values to some variables |
| 7-18 | in case /etc/mobile/laptop.curr does not (yet) exist, create the file and assign default values to it |
| 20-21 | set permissions for /etc/mobile/laptop.curr |
| 23 | check for the existence of the setnetparm program and terminate if it is not found |
| 26-35 | find out which console driver runs on the console and set up the environment variable TERM accordingly. Curses programs need this variable to run. |
| 37 | run the setnetparm program |
| 40-56 | read in /etc/mobile/laptop.curr and assign its contents to variables |
| 60-67 | in case user selected to use DHCP, use the variables from the previous step to set up a new /etc/mobile/rc.conf.mobile |
| 70-81 | for non-DHCP usage, use the variables from the previous step to setup a new /etc/mobile/rc.conf.mobile and a new /etc/resolv.conf |
| 84-87 | if there is a shell script available for further system customization, execute it. |
Another thing to mention is that you must apply another patch to /etc/pccard_ether to make PCMCIA cards work together with the setnetparms package.
All the aforementioned programs and some optional scripts and examples are part of the setnetparms package. I released the first version in 1997 - since then it has seen many FreeBSD versions and quite some laptops. It started as a hack (and you see it all over the code), but it just suits my needs. The current version of setnetparms is 3.41, and you can download it from http://www.freebsd-support.de/misc/.
Have fun!