DæmonNews: News and views for the BSD community

October 1998 Get BSD New to BSD? Search BSD Submit News FAQ Contact Us Join Us
Search


Get BSD Stuff
Daemon News '199810' : '"<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> "'
Monthly Columns

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:

  1. 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.
  2. 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.
  3. 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!

Matthew Alton, alton@plantnet.com





Author maintains all copyrights on this article.
Images and layout Copyright © 1998-2004 Dæmon News. All Rights Reserved.