Unix Help.

Click on the section to jump to that section:

Networking
Programming
System Administration

Items are alphabeticaly listed within their sections.

Introduction:

Please note that some of the items here reference techniques that are of historical interest only. This document first saw the light of day around 1992.

The notes listed below document the author's "show stoppers" which were made as he learned UNIX, after working on DOS, VMS, and other systems. There is a small chance that you will make exactly the same error, and this document will help you to solve it. What is far more likely is that you will skim through it, and hopefully learn one very important thing:

Almost all errors are trivial, and result from your understanding a Unix function almost completely. Gross errors in understanding are very rare, although when you hit a show stopper, you usually get the initial impression that you are hopelessly in left field and will never understand this cryptic operating system. Not True!! Do not give up!

I've been keeping this file for close to a decade now (2001), and some of the information in it is fairly dated. Even so, some of it might still be useful, so I haven't removed any of it.

I suppose that you have already guessed it, but the FAQs, man pages and emacs info documentation comes with Linux, and really help out. You have to really dig: there are bookshelves of documentation in the above sources. You will probably learn more about certain topics than you wanted to, but after a while all this knowledge begins to look good on your resume. While I have tried to avoid overlap in this document, some does exist. It should give you pause that there is so little overlap! A modern operating system is a complex, many faceted beast. Take it a facet at a time and you'll get around it!

UNIX is largely free of the system crashes that plague DOS and the MAC. This is because a user account is almost incapable of accessing the system resources required to crash the system. When you're running in DOS or MAC mode, you (or more often, programs that you run) can crash the system. I once complexly wiped my hard disk while running Borland's C++ compiler. I have never had this happen with Linux. I've never, in five years, crashed the system so badly that I had to reset. Granted, some functions (X windows and the modem) required a reset, but I could always get to a root virtual terminal to shut down gracefully. I've merrily crashed VMS, other Unicies, and of course, anything Microsoft has ever produced, from DOS 3.3 to Vista. Linux is robust.

2007: Macs, with their FreeBSD based unix base, are now quite robust. Some say more robust than Linux. The analysis of Microsofts offerings has not changed in the 15 years since the above was written. I've now gone 15 years without a reset only crash.

I suppose no introduction is complete without a testimonial. Here goes: I mentioned above that I had worked on a number of systems before embracing Unix. Unix (especially Linux) is the best system I have ever worked on. Give it a chance: it takes a while to collect a "critical mass" of Unix commands to make the system really fly, but once you do, you'll become one of those insufferable Unix propeller heads who claim (truthfully) that nothing else even comes close!

Please Note: The author has made every effort to insure the correctness of the information which follows. However, there are NO warranties, expressed or implied, for this information. In other words, if something goes wrong, you're on your own.


Networking


apache

I load the program as part of my normal Slackware distribution or you can download the most recent version, and then compile it and install it.

Configuration:

You need to edit the httpd.conf file, located in /var/lib/apache/conf in my Slackware distribution. Set the ServerName to the IP address of your machine (Your ISP should be able to provide you with this information).

Your HTML/CGI files must reside in the DocumentRoot directory. On my Slackware distribution, it's "/var/lib/apache/htdocs".

I create a directory under this with 777 permissions, so I can edit the files from my regular account. You never want to run as root.

You can run the client and server from you machine by accessing the web site http://localhost/

Perl scripts (in the /cgi-bin directory) must set the proper environment for text output by this print statement before any other output is attempted:

print "Content-type: text/html\n\n";


mail

To send a message with a subject:

mail -s "This is the subject" recipient@computer.full.ip.address < message

To forward your mail:

Create a file in your root directory called .forward. This file should contain the address of the machine that you want to send the mail to:

e.g. My .forward file reads:

Greg.Sherrord.1@hotmail.com


ethernet with modules.

You need to have the module installed.

As root:

depmod -a # Builds a module database. modprobe tulip.o # Check for Tulip's dependencies. lsmod # Lists loaded modules

Make sure that the tulip module is installed with lsmod.

Slakware's setup will do an initial configuration, but you'll have to edit the files resolv.conf, hosts, HOST_NAME in /etc.

Your sys adm or ISP should know your IP address, netmask, network address, broadcast address, and gateway address.

To check if the ethernet card is working, enter (from root):

ifconfig eth0


ftp

Make sure the line setting is binary. Zipped files will not transfer correctly if this is not set.


login

To disable the annoying wait after an unsuccessful login, edit the file /etc/login.defs. Change the parameter FAIL_DELAY from whatever it's set to to 0. You'll have to be root to do this.

To rerun your sh login, type ". ./.bash_login", where .bash_login is the name of your sh shell login file.

To rerun your csh login, type "source .cshrc", where .cshrc is the name of your C shell login file.


A quick check of transfered file integrity.

This is true for any other data transfer protocol as well, such as ftp.

Check the size of the files that you have transfered to the target system. If they are not the same size, something went wrong.


Packet sniffing

There are time when it's necessary to look at the raw data packets coming into and going from your machine. The tcpdump program, which you must run from the root account is your ticket. The man page is fairly descriptive. I use the following command to grab the first 1,000 packets in ASCII readable form, and dump them to a file called packets:

tcpdump -A -c 1000 > packets


2007: PPP is pretty much obsolete. Just take a gander at the setup hassle that follows, and you can see why.

PPP

Installation (for Author's PPP link -- a very brief reminder list):

Run time problems:

Try the ifconfig and netstat commands to find out what your current network configuration is.

Use the ping command to check you connections.

Make sure that your linux kernel has drivers both for your network card and ethernet. Networking will not work without them.

Installing PPP to work with Linux can be done, but it is not trivial.

I'll describe the steps that worked for me, so that you might get a variation on them to work for you.

Don't expect it to work perfectly the first time. You'll have to futz with it, unless you are very lucky.

PPP must first be installed in your kernel. To check if it is there:

dmesg | grep -i ppp

You should get something that looks like this:

PPP: version 0.2.7 (4 channels) NEW_TTY_DRIVERS OPTIMIZE_FLAGS PPP line discipline registered.


Update, Jan 2000: Newer Linux kernels will load ppp support as a module. You need to have an ppp object file ready to load when pppd is called. On my slakware system it's located in /lib/modules/2.2.13/net/ppp.o

If you don't, you'll have to recompile your kernel, or get a copy of a kernel that has ppp on it from the net. Instructions for doing this are found in the file /usr/doc/ppp/README.linux.gz. This is where it is in my Slackware release, yours will probably be similar. You need to read this file now. Before you go any further. Otherwise, what follows will read like gibberish.

Read the Readme? Good. Here's how my pppd/chat command looks:

/usr/sbin/pppd connect '/usr/sbin/chat "" ATDT7035551212 CONNECT "" ogin:\ gsherrod word: secret_password' /dev/modem 38400 -detach crtscts modem \ defaultroute noipdefault

Fill in your appropriate telephone number, user ID and password.

Run the script from your root directory,unless you have given pppd suid privileges (recommended).

To set the suid privileges, enter: chmod 4755 /usr/sbin/pppd. You will also need to allow users access to the modem: chmod 755 /dev/ttys3. Note that your will most likely be different and you need to chmod the actual device. A chmod to /dev/modem will not work, as /dev/modem is a link, already set at 777.

When I am running the script, I do so from an X windows term, so I can start netscape (or whatever X application I want) easily.

Once I've established the connection, then I can run netscape, ftp, or telent to other internet connected machines.

My ISP (Internet Service Provider) assigns me a different IP address each time I log on. This IP address can be found with ifconfig, or from the /var/log/messages file.

The last few lines have what you need:

Aug 28 20:01:23 3C273 pppd[168]: local IP address 205.252.11.62

To log off, the PPP-HOWTO.gz document has the following logoff script:

#!/bin/sh DEVICE=ppp0

# If the ppp0 pid file is present then the program is running. Stop it. if [ -r /var/run/$DEVICE.pid ]; then kill -INT `cat /var/run/$DEVICE.pid`

# If the kill did not work then there is no process running for this # pid. It may also mean that the lock file will be left. You may wish # to delete the lock file at the same time. if [ ! "$?" = "0" ]; then rm -f /var/run/$DEVICE.pid echo "ERROR: Removed stale pid file" exit 1 fi

# Success. Let pppd clean up its own junk. echo "PPP link to $DEVICE terminated." exit 0 fi

# The PPP process is not running for ppp0 echo "ERROR: PPP link is not active on $DEVICE" exit 1

Additional hints not in the README.linux file:

All exchanges between you and you host computer will be logged in the /var/log/messages file. Deducing what's going wrong is much easier if you just look at the end of this file:

tail /var/log/messages

Keep trying, don't be afraid to futz around. If you're well backed up (you ARE, aren't you?) you won't hurt any of you hardware, or permanently damage any software (even this is very unlikely). Good Luck!


Static IP setup

My new ISP rents me a static IP, which they configure in the router they've provided me with. When I initially set it up, I had them set up my internal IP address 192.168.1.1 to the static internet address they're renting me, 208.218.136.74.

This worked fine until the old server died, and I installed a new one. It wouldn't work, except internally. I could log onto my machines except from other machines on my network. All outside connections were refused. All of the futzing around I did with ifconfig, netstat, and the like were to no avail. Finally, in desperation, I shut the entire network down, swapped the cables between the old and new servers, rebooted everything, and Voila everything worked just as before.
It turns out that the ISP had hardwired the socket in their router to be the server socket.

I did, of course call them for assistance, but they were more clueless than I. I'm afraid that this is something to be expected with the help staff of most IP and other computer vendors today. Software and hardware are rather tricky, and those that are hired to man the phones are the least paid and least knowlegable in their companies. They either admit they don't know how to deal with the problem, or more likely, pass you on to someone else who's equally clueless. Sometimes their solutions are dangerously incorrect "just reformat your drive and start over, you're corrupted by a virus" and/or expensive "Buy a new machine and install our product..."

What I've found over the years is that it's cheaper and faster to research the problem over the internet (Google!) and fix it yourself. The education you gain from the process will be valuable in years to come.


System Administration


Backing up.

Having your system crash and not loosing valuable data is what separates the computer pros from the also rans. Here's how I do it.

All of the software on my system is safely contained on the CD that I used to load it in. There's no reason to back up this stuff. CDs are more stable than any tape or disk backup I know of.

I only back up files that I have fiddled with. My programs, configuration files, documents, etc. I have a script file, sall (save all) which goes to each directory that I have stuff in, tars it, gzips it and then saves it to floppy.

This stuff all fits on one 1.44 Mb disk. It represents about 730 pages of single spaced typewritten output. That's a lot of typing. Most books aren't that big. If you have more stuff than this, I'd suspect that 80% of it is stuff you haven't touched in a year. You can back it up to a disk, put the disk in a safe place and pretty much forget it. Of course, if you gzip the result, you can usually more than triple the amount of stuff you back up.

I have 15+ disks which I keep my backups on, and back up at the end of any day that I have done a substantial amount of input. This gives me access to a month or more of past versions.

You'll find your own way in this. The important thing is to do it. Then you can feel almost smug when you hard disk finally dies.

2007 update. Never mind a floppy. Now I use a writable CD_ROM. The basic ideas expressed above have not changed.


bash (and ksh and sh)

To set an environmental variable with bash use the following syntax:

VARIABLE=value

For example, to tell bash that your are a vt100 type terminal, enter:

TERM=vt100; export TERM

NOTE: There are no spaces around the equal sign. This is true for all bash commands, not just setting environmental variables. Remember this and be saved frustration down the road.



chmod

The command chmod XXX .* can have unforeseen after effects. It affects the directory you're in as well as the files in that directory! You might find that only root can access the files, and then only after chmoding them back to where they were supposed to be.


cpio (not often used, most Unix users use tar instead)

To use cpio, for backups, specify:

find (path name) [-name] | cpio -oc > (destination file and directory.)

To extract a cpio file:

cpio -i [-F (full file specification)] [-r rename files]


cshrc

To change the erase key from ctrl h to <-, one has to add the line:

stty erase \x7F

To the .cshrc file. Unfortunately, the C shell interpreter does not understand the sequence \x7F, and I needed to write a short C program to insert the byte with value 127 (7F hex) at the end of the file.

To set the terminal from 'console' or 'Linux' to vt100 (needed by elm (a mail handling utility)) on an SGI, put this line in your .cshrc file in you SGI home directory:

eval `tset -s -Q vt100`

If your etc/ttytype file is set up to recognize vt100s, this should work.

Note this does not work on all machines. These methods were useless on a motorola, for example


less

Less can't display ANSI color escape sequences like most of the other Unix text output utilities can. It instead tries to print them with ugly results. On other unicies, the work around is to use the pg function, but it's not available on Linux (yet).

To customize less to your keyboard, you need to create a .lesskey file in your root directory. Follow the instructions in the lesskey man page. The escape key is denoted as \e, BTW.


login

To disable the annoying wait after an unsuccessful login, edit the file /etc/login.defs. Change the parameter FAIL_DELAY from whatever it's set to to 0. You'll have to be root to do this.

To rerun your sh login, type ". ./.bash_login", where .bash_login is the name of your sh shell login file.

To rerun your csh login, type "source .cshrc", where .cshrc is the name of your C shell login file.

2007: Probably of only historical intrest now. Yes this is how we did it way back then.


Linux

To regain text that has scrolled off of the screen, try shift-PageUp and/or shift-PageDown. This will work on a given console until you shift to another one. When you shift back, however, you will find that the scrolled text has been lost.

To change from virtual console to virtual console, use left alt (only the left alt key works on my machine) FX where FX is one of the function keys F1 thru F6. F7 will be your X window, and isn't set up for you to log into it, but see the note below.

When you are in X, you can move back to the text consoles by simultaneously typing the control and alt keys, and then the function key of the virtual console you want to be in.

To add more virtual consoles edit your /etc/ inittab file and add a line to the getty configuration section. I added this line to inittab and it allowed me to add another virtual console:

c7:456:respawn:/sbin/agetty 38400 tty7

This let me log into F7, but not as root. To log in as root, I added this line to the /etc/securetty file:

tty7

I did not add further consoles, as 7 is the canonical number for the maximum number of things you want to juggle at one time, and each virtual console takes up precious RAM even if it is dormant.

When your screen gives weird output for lower case letters, try this:

echo "^V^[c"

(that's E C H O space control-V escape C return) to fix it.


find

find (path name) -name (file name) -print

wildcards at the beginning of a find names must be preceded by a \. e.g.:

find / -name "\*bozo*" -print

finds all files with the letters bozo in them. Some systems require the quotes as well.


link (ln)

to create a symbolic link:

ln -s <existing file or directory> <Linked file or directory>

e.g.: ln -s OldFile NewLink

This creates a symbolic link name NewLink that points to OldFile. When you access NewLink, Unix actually accesses OldFile.

Links are mainly used to save disk space, allowing you to have the same file in several different places without actually having maintain multiple copies of the file.


nroff

Many text files are quasi-readable, and filled with control characters. If the file turns out to be an nroff man page, you can read it with the command:

groff -Tascii -man file.name | less

Often a variation of this command is necessary. See the man pages for groff and grog. Grog tries to look at the file for you and suggest a command. This is one that repays a lot of fiddling. Back up the original file, and groff away. Usually you'll get it. Remember also that postscript files (usually denoted by a .ps suffix) are read with the ghostscript command from X.


rm

When a file absolutely refuses to go away, try surrounding its name with quotes. This might kill it. I needed to remove a file called #filename#. Here's how I fared.

rm #filename# Refused to work.
rm "#filename#" Worked.
rm '#filename#' Worked.
rm \#filename# Worked.

The top command worked on the older versions of Linux and SGI's IRIX. This is probably a Posix compatibility problem that caused the more recent versions of Linux to stop working.


setup

The setup script will not run unless you are in /usr/lib/setup, and running as root. Be careful. Back up everything before you start playing around with this. Don't be afraid to play, however, as you can always improve on the defaults Linux comes with.


sleep

To cause a program to wait for a given number of seconds, use sleep(). This will pause the program, and it will halt for the specified number of seconds before resuming.


The root account

There are a few commands, used for system administration, that you can only run as root. The root account is an essential part of Linux, but use it only when it's the only way to do something, like set up the network or for account management. All other time spent in Linux should be spent in a user account, as this account is prevented from mis-executing powerful commands such as rm -rf /* (This cleans your disk in a disastrously complete fashion.)

MORAL:
Always run in a user account.
Use root only for system administration.
When in root, proofread everything you've typed BEFORE you hit Enter!
This will insure a long and happy experience with Linux and other unicies.


swapon

To set up a swap file, (needed for installation)

1) Start you new Linux box with the boot and root disks.

2) make a partition (The rule of thumb is 1 - 2 times the size of the RAM on your machine.) using fdisk. Be sure and set the data type to Linux swap.

3) Format the partition: mkswap -c </dev/partitionName>

4) Enable swapping in /etc/rc.d/rc.S: /sbin/swapon -a


tar

To make a tar file:

tar -cf tarfilename filename (or directory. Directory is recursive) This creates the file.

tar -rf tarfilename filename (or directory. Directory is recursive) This appends to an existing file.

To extract a tar file: Get into the directory where you want to have the files. tar -xf (Complete filespec of the tar file to be extracted.)


test

NEVER NEVER NEVER name an executable test. This is a very easy, logical thing to do. When you try and run it, the shell will invoke it's test utility, find nothing there, and exit silently, leaving you very puzzled.


Time

To set the system clock (CMOS) from Linux:

Set the system time from the CMOS clock, adjusting the time to correct for systematic error, and writing it back into the CMOS clock.

This option uses the file /etc/adjtime to determine how the clock changes. It contains three numbers: The first number is the correction in seconds per day (for example, if your clock runs 5 seconds fast each day, the first number should read -5.0).

The second number tells when clock was last used, in seconds since 1/1/1970.

The third number is the remaining part of a second that was left over after the last adjustment.

The following instructions are from the source code:


useradd

When a user is added, you have to make sure that the user owns, or at least has read, write, and execute privileges on his/her home directory. If you neglect this step, the new user will be unable to function properly, and perhaps will not be able to log on!

The /usr/bin directory must have its privileges set to 755 in order for users to be able to execute the UNIX commands contained therein.


Virtual Terminals:

To change from terminal to terminal:

Left Alt + fn

(n is the terminal number, from 1 - 6 and f is a function key.)

To return to virtual terminal text mode from X:

Left Alt + Control + fn

n is again the number of the terminal you want.

To see text that has scrolled off of the screen:

Shift + Page up or Page down.

Moves you up and down by half a screen each time.

To see task information:

Control + Scroll Lock

To see memory information:

Shift + Scroll Lock


X:

There are few short X tips. You need to read much of the documentation that is out there, and but the O'Reilly series in X and Motif if you intend to do serious development. It's an extraordinary, platform independent, system that solves some very difficult problems with accessing system resources in a uniform way. It's also very complex, with all sorts of redundant functions and kludges. Good Luck.

If you're going to be building straightforward (no animation) user interfaces, I suggest that you bypass X entirely, and concentrate on HTML with Perl/CGI in the background.

X debug tips:

X is subtle, and hard to debug. Things work fine, until, deep into a series of X calls, the program aborts with a very cryptic message, or a segmentation fault. Ruthlessly check everything. Painstakingly walk through the guilty code using the debugger until you've located the bad instruction. X has been out for more than 10 years, and actual bugs are very rare. Subtle bugs are easy to create, however.

It has been said that programming in X is like extracting square roots using roman numerals. Perseverance furthers!


Programming


ar

Ar creates a library file, which, after you get a utility program you'll be using in other programs, allows you to easily access the object files of that program. The files are created by the following command:

ar -r libArchiveName.a objectfile.o

ArchiveName is, by convention, named libArchiveName.a. However, you refer to in your make file only by ArchiveName. e.g

LIBFILES = ... -lArchiveName ...

C

1) As Unix is currently configured, there is no easy way to get a single keystroke without using curses or changing the terminal characteristics. Your users will just have to get used to hitting Enter after an input. If they can't, uses curses or the GCC C manual (actually a superb reference for C libraries well worth the $50+ bucks!)

2) After you have output to an opened text file, it is a good idea to send a fflush(stdout) command. This will flush the buffer and keep you from overflowing it if you get over 2048 characters in it, which is easy to do.

3) To use math.h functions in a c program:

Link in the math libraries by typing:

gcc source.cxx -lm

Math libraries MUST be linked in last!!! Old UNIX linker convention!

4) When declaring pointers, every variable must be proceeded by an asterisk!

int *v1,
v2,
v3;

Results in compiler complaints of bad unary operator arguments! Correct:

int *v1,
*v2,
*v3;

5) To capture the output of a compile which is causing problems, and outputting reams of digital vomit, use this construct from a sh based shell like bash:

gcc -c flaw.cxx &> TextCapture or

gcc -c flaw.cxx 2> TextCapture

The errors will be captured in TextCapture.

6) A static variable is initialized only once in a function. All other calls to that function result in the existing value of the variable being used.

7) Shifts in most Unix C compliers are actually integer divides and multiplies by 2. Never mind what the ANSI spec says:

This code gives problems:

long n = 0x80000000;
for (i = 0; i < 24; i++)
{
     printf("\n n is now %lx.", n >> i);
}

n must be declared as an unsigned long for this to produce reasonable results. The fact that n starts negative fowls the compiler up. This also indicates that right and left shifts are implemented as divide and multiply by 2 with the GNU C++ compiler.

8) This is perhaps my favorite subtle error. If I only had a dollar for every hour I've spent searching for this self imposed klutziness...

for (i = 0; i < upper_limit; i++);
{
     this = cant_happen;
     the_loop = wont_execute;
}

See the semi-colon at the end of the for statement line? The program pauses for an empty loop of upper_limit cycles, and then proceeds to do just the first installment of the loop and nothing else. It's quite easy to to, too, even after you've been bitten a few times by it.

9) You can core dump a program sooner than quicker by writing too much stuff into a string, so that it doesn't end with that all important 0. e.g.:

double age = 1.5e10 * 3.15576e7 * 1e9;
char oops[52];
int len; ...
sprintf(oops,"The age of the universe in nanoseconds is %f.\n",age);
len = strlen(oops);

The fragment will die at the strlen call, as the string is longer than 50 characters, even if it is 10 character in the sprintf statement. The age of the universe in nanoseconds is about 19 characters long.

10) This code will pass a file pointer (tfile) to a function:

#include <stdio.h> /* fclose, fopen, printf.*/
#include <stdlib.h> /* exit. */
void main(int argc, char* argv[])
{
    /* Function Prototypes:*/
    int openfile(FILE** tfile);
    /* Variables:*/
    FILE *tfile; /* Test file.*/
    printf("Starting program. tfile = %p.\n", tfile);
    openfile(&tfile);
    printf("Back in main. tfile = %p\n", tfile);
    fclose(tfile);
}

/* Open the file and return the pointer.*/
int openfile(FILE **tfile)
{
    *tfile = fopen("junk","wb");
    printf("Tfile just opened. tfile = %p, *tfile = %p.\n", tfile, *tfile);
    return 1;
}

11) This code will allow you to reference an array of characters as an array of longs without using a union:

int bozo(void)

void use_long(long *array); // Function prototype. char *array; // The character array.

use_long((long*) array);

void use_long(long *array);

// Reference the array as longs here.

12) Profiling:

Compile with the flag -pg (for gprof compatible output). Link with the -pg flag AT THE END OF THE LINK LIST. e.g:

gcc -o run_time_image my_main.o my_other_stuff.o -pg

Even then, don't expect miracles. This does not work on an mpeg2 package I found on the net.

13) Reading in a globbed (wildcarded) file list:

If you want you program to work on all files in a directory, you can enter "myprog *". Argc will count the number of files out there, and argv will be the char **list of their names.

14) The code

string1[i++] = string2[i];

Will take the nth component of string2 and put it the into the nth component of string1, then increment i. This is how GCC and the SGI C compiler do it.

The Motorola C compiler takes the (n + 1)th component of string2 and puts it into the nth component of string1. I gets incremented before the assignment. Safer is to just use this code:

string1[i] = string2[i];

15) The code

if (index++ == NR_PTS) index = 0; // Fails to implement a circular buffer.

Does not implement the desired buffer. Let's say that NR_PTS is 100, and index is 99. The comparison is made when index is 99. Index is not reset, by then it is set to 100 by the ++. Next time, of course, the index will be reset to 0, but by then, it's overwritten whatever was in buffer[100], which is the 101st entry in buffer, a 100 int (or whatever) array.

use this instead:

if (++index == NR_PTS) index = 0; // Implements the circular buffer.

16) Occasionally, if you allocate a huge array (I needed one 10.7 MB to make this one happen) the program will bomb as it tries to pass the array to another function. For example:

char moby[20000000]; // A really big text file.

There simply wasn't enough room on the C/C++ stack to hold the array, and the program bombed as soon as it tried to access it. The compiler, of course, didn't complain.

The fix is to malloc (or new, in C++) the array:

char *moby; // A really big text file.

moby = (char*) malloc(20000000); if (moby == NULL)

printf("Hey! I'm not big enough to hold moby!\n");

17)

When you have to initialize an array of structures in a function other than the one in which it was declared, make the initialization function return the array of structures. Here's a short example:

#include <stdio.h>
#include <stdlib.h>
typedef struct
{
   int bar1,
       bar2;
} foo;


int main(void)
{
    foo* fnctn(void); // This function initializes foo.
    int i;
    foo* strctArr; // File and UDP output socket information.
    strctArr = fnctn();
    for (i = 0; i < 10; i++) printf("%d ", strctArr[i].bar1);
    printf("\n");
    return 1;
}


foo* fnctn(void) // Set up the array of structures, foo.
{
    int i;
    foo* strctArr;
    strctArr = (foo*) malloc(sizeof(foo) * 10);     if (strctArr == NULL)
    {
       printf("The foo array was not allocated.\n");
       return strctArr;
    }


    for (i = 0; i < 10; i++) // "Initialize" the array of structures.
    {
       strctArr[i].bar1 = i;
       strctArr[i].bar2 = i;
    }
    return strctArr;
}

18) Here's a weird one. I tried to do a system sort of a file that a program had created:

int iostat = system("sort -o sortedAf authorFile");

I hadn't bothered to close the file before doing the sort, and the sort almost worked, poorly enough to bomb the program, and well enough to make debugging difficult. Close all files before running a system command on them:

fclose(authorPtr);

19) When it works on one machine and not on others, or in the debugger and not out of it:

You might well be not initializing your variables properly. Sometimes one machine will just happen to initialize a variable to a non lethal value, and the others won't. See inexplicable errors item 3 as well.

20) Inexplicable errors:

Occasionally, you will face very odd errors. A function works perfectly most of the time. The rest of the time, it has very strange errors. Variables seem to change value in a capricious way, and your frustration index soars off of the charts. If you're a beginner, you decide that programming is beyond you, and give up. Don't despair, quite yet. There are a few tricks, not written in any book that I have seen, that I have developed over the years to help you over these rough spots. In general, try these in the order given.


Debugging

If you try to debug more than one error at a time you will most likely confuse yourself and take longer than you would have otherwise to fix your program.


gdb (and dbx)

To examine a core file:

gdb <executable file name> <core file name>

The core file name is usually "core".

To examine an array:

p *arrayName@number_of_bytes_you_want_to_see


imake

2007 update. This is obsolete. I leave it hear more as a museum piece than any practical advice. Look at what we used to have to do!
Use ant instead.

The new way of handling compiling and linking programs is with a utility called imake. It makes programs easier to move around from machine to machine. To use it:

0) Read the imake, make and xmkmf man pages. Also any README files that came with the program you're trying to build. If you're going to be getting into some serious program development, the emacs info page on make is a must read.


make

The make utility requires that commands (as listed under a target:dependency line) begin with a tab (ASCII 09).

If your emacs tab stops are set to under 8, emacs will insert spaces (ASCII 32), and not a tab. This will stop make dead in its tracks. You'll have to reset your tabs to edit a makefile.

If you break up the lines in your make file (a good idea: readability is king!) don't put anything after your backslash (line continuation symbol) or make will throw up on it:

LIBS = Lmylib Lyourlib ... \

No spaces or tabs or anything after here!!!


modem

When you install linux, your serial ports will not be configured. You have to enable the call to /etc/rc.d/rc.serial in /etc/rc/rc.S:

# Run serial port setup script: # (CAREFUL! This can make some systems hang if the rc.serial script isn't # set up correctly. If this happens, you may have to edit the file from a # boot disk)

# You need to enable this line (remove the # comment symbol):

. /etc/rc.d/rc.serial

# for your modem to work.


qsort

Here's a weird one. The qsort function has a hard time calling it's comparison function from a C file compiled with gcc. It works fine if gcc thinks it's compiling a C++ file. Here's a pixel value sort I did, heavily edited:

   int pixCmp(pixel, pixel>); // Return -1, 0, or 1. For the qsort call.
   qsort(data, BigNumber, sizeof(pixel), pixCmp);
   int pixCmp(pixel* a,
   pixel* b)
   if (a->clr > b->clr) return 1;
   else if (a->clr < b->clr) return -1;
   else return 0;

If the file is named pixels.c, it produces the following gcc error:

pixels.c: In function `readData': pixels.c:164: warning: passing arg 4 of `qsort' from incompatible pointer type

If the file is named pixels.C, it produces no errors: