C FreeBSD Run
Matthew Alton
Welcome to C FreeBSD Run.
This is a column dedicated to the study and
discussion of the software development process as it applies to the FreeBSD
environment. The focus of this column will be on the tools available to us as
part of the FreeBSD distribution. This column is designed to fill a niche
between the abundant and readily available elementary tutorials on C language
programming and the somewhat terse system manual pages provided as
documentation for the tools used in the actual development process.
In each installment, we will examine one or more of the FreeBSD development
tools. We will first present a small synopsis of the intended function of the
tools and then we will apply the tools to actual system code in order to "see
them in action". This will provide us with exposure to some of the best C code
in the world.
It is my experience that students profit principally by doing. Therefore, I
encourage you to follow along in the sessions by actually doing the work in
a second X-window or virtual terminal.
For our first excursion, I have selected the source code for the ftp client
program /usr/bin/ftp. You should make a copy of this source code in a
subdirectory of your home directory on a FreeBSD system. If you have the
source code to the entire system available at your site, the relevant files
can likely be found in /usr/src/sys/usr.sbin/ftp/* or a similar location. If
not, you may download them from ftp.freebsd.org:/pub/FreeBSD/FreeBSD-current/
src/usr.bin/ftp/*. This latter method is preferred since that is where I got
the copy used here.
The ftp program is an excellent subject of study for the following reasons:
- It uses a well-defined internet protocol as a functional basis. This
protocol is freely available as RFC959 in ftp://nic.merit.edu/documents/
rfc/rfc0959.txt. Also relevant is RFC0412 as a language specification.
- It implements several elements of interest to UNIX-style programming,
namely command-line option and configuration-file parsing, networking
via the socket interface, a small internal command language and tty
input/output among others.
- It is widely available, implemented with very little variation on a
large variety of platforms.
Our source directory should look something like this:
[matta@monkey ftp]$ ls -lp
total 242
-rw-rw-r-- 1 matta matta 625 Aug 30 10:16 Makefile
-rw-rw-r-- 1 matta matta 41200 Aug 30 10:17 cmds.c
-rw-rw-r-- 1 matta matta 10836 Aug 30 10:17 cmdtab.c
-rw-rw-r-- 1 matta matta 860 Aug 30 11:15 column_0001.txt
-rw-rw-r-- 1 matta matta 9050 Aug 30 10:17 complete.c
-rw-rw-r-- 1 matta matta 4309 Aug 30 10:17 domacro.c
-rw-rw-r-- 1 matta matta 6495 Aug 30 10:17 extern.h
-rw-rw-r-- 1 matta matta 15414 Aug 30 10:17 fetch.c
-rw-rw-r-- 1 matta matta 36414 Aug 30 10:17 ftp.1
-rw-rw-r-- 1 matta matta 34168 Aug 30 10:18 ftp.c
-rw-rw-r-- 1 matta matta 7508 Aug 30 10:18 ftp_var.h
-rw-rw-r-- 1 matta matta 13647 Aug 30 10:18 main.c
-rw-rw-r-- 1 matta matta 2048 Aug 30 10:18 pathnames.h
-rw-rw-r-- 1 matta matta 7835 Aug 30 10:18 ruserpass.c
-rw-rw-r-- 1 matta matta 20627 Aug 30 10:18 util.c
The first tool we use is "ctags". Ctags correlates the data from the
various files and arranges them in a file called "tags" by default. This
"tagfile" is used by the vi editor as a navigational aid.
[matta@monkey ftp]$ ctags *.[ch]
[matta@monkey ftp]$ ls -lp tags
-rw-rw-r-- 1 matta matta 20620 Aug 30 10:18 tags
Now we invoke the vi editor using the "-t" option and the function name
"main" instead of a filename. This causes the editor to consult the
tagfile for the location of the function in the source files.
[matta@monkey ftp]$ vi -t main
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "ftp_var.h"
#include "pathnames.h"
int main __P((int, char **));
int
main(argc, argv)
int argc;
char *argv[];
{
struct servent *sp;
int ch, top, rval;
long port;
struct passwd *pw = NULL;
char *cp, *ep, homedir[MAXPATHLEN];
int dumbterm;
(void) setlocale(LC_ALL, "");
"main.c" 694 lines, 13647 characters
The vi editor is invoked on the file main.c with the cursor on the "m" in
the line:
main(argc, argv)
The fact that the main() function is defined in a file called "main.c" is
arbitrary. Vi will find main() from the tagfile regardless of which source
file happens to contain it.
Now, to get a feel for navigation in the source files we can enter the search
command
/lostpeer
at the vi command line. This will cause the cursor to move forward through
the text to the next occurrence of the string "lostpeer".
(void)signal(SIGPIPE, (sig_t)lostpeer);
The cursor lands on the "l" in "lostpeer". We do not know what "lostpeer" is
from this context alone. All that we know is that it is the second argument
to a function called signal() and that it is being typecast to "sig_t". In
order to discover the definition of signal(), we might try to move the cursor
into the word "signal" in the above line and strike Ctrl-]. If the function
signal() is defined in the source files used to generate the tagfile, this
will cause the cursor to leap to its definition just as it did for main()
before. This approach causes "tag not found" to appear at the bottom of the
screen telling us that the function signal() must be defined somewhere outside
the source files in our working directory. At this point we hypothesize that
signal() is a system call. In order to test this hypothesis we enter
:!man signal
at the vi command prompt. The section 2 system manual page for signal()
appears and we notice that the function takes as its second argument a pointer
to a function.
SYNOPSIS
#include <signal.h>
void (*signal(int signum, void (*handler)(int)))(int);
We press "q" and then RET to continue our vi session. Our hypothesis was
correct - signal is indeed a system call. Its function is to allow assignment
of customized functions for handling asynchronous signals. The line
(void)signal(SIGPIPE, (sig_t)lostpeer);
assigns the function lostpeer to handle the SIGPIPE signal. We may now move
the cursor to any letter in the word "lostpeer" and strike Ctrl-]
void
lostpeer()
{
alarmtimer(0);
if (connected) {
if (cout != NULL) {
(void)shutdown(fileno(cout), 1+1);
(void)fclose(cout);
cout = NULL;
... ... ...
And the cursor leaps to the "l" in the function definition. In order to get
back to the signal() line, we strike Ctrl-T. Vi will find the definition of
the function lostpeer regardless of which file in the source code contains it.
This ability to contextually navigate through C source code makes the ctags/vi
pair indispensable. The student should acquaint himself intimately with the
ctags/vi navigation facility and with the capabilities of the vi editor by
reading the ctags and vi manual pages and by reading the files in /usr/share/
doc/usd/12.vi/*.
FOOD FOR THOUGHT: How do we now return the cursor to the "m" in main()?
Why does another Ctrl-T not do the job? How is this
behavior The Right Thing?
Now, in order to facilitate our discussion of the code, I suggest that we
turn line numbering on. We do this by entering
:set number
at the vi prompt. This will cause the line numbers of the code to appear
at the left of the lines. The numbers do not become part of the text. The
main function appears on line number 73.
72 int
73 main(argc, argv)
74 int argc;
75 char *argv[];
This may look odd to programmers new to C. Programmers trained after the
ANSI standardization of the C language and programmers coming to Berkeley
code from other traditions expect to see something like
int main(int argc, char **argv)
The text conforms to the older K&R C standard. Most compilers, including
gcc can parse either dialect. One of the advantages of the K&R/Berkeley
method is that the UNIX command "grep ^foo *.c" will easily turn up the file
containing the function foo().
Continuing to line 84 we find
84 (void) setlocale(LC_ALL, "");
The function setlocale() is a library function which allows the programmer
a measure of control over the linguistic and typographical conventions used
in the user and environment interface. It is relevant to standards
conformance.
Lines 86 through 112 concern themselves with the initialization of a struct
of type servent named *sp declared on line 77. Here we enter the land of
socket programming - an excellent place to pause.
Join us in the next installment of C FreeBSD Run. We will build the ftp
client and learn about network programming and the use of the gdb debugger.
Until then, please study ctags/vi and the RFCs relevant to the ftp protocol.
Happy Hacking!