"Linux Gazette...making Linux just a little more fun!"

Tom's 2 cent Tips

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 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 NT. Linux is
robust.

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, it's
your problem.

You can only run this from root, but it is an essential command. Almost
all of your time spent in Linux should be spent in a user account of your
own creation, as this account is prevented from executing disastrous
commands such as rm -rf /* (This cleans your disk in a disastrously
complete fashion.)

MORAL: Always run in a user account, not root unless you are doing some
system administration which will only work in root.

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 ...

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.

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.

C

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!)

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.

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!

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

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.

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...

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.

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.:

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.

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.

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.

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:

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.

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.

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.

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.

Rewrite your code until it is remorselessly neat.

Step through it line by line with a good debugger (I recommend
GNU's GDB for C code. It's a bit flaky (1998) for C++).

If these steps did not fix the problem, try recompiling
everything with a command like:

rm *.o // Important!
make // Or whatever compilation command you use.

If you have inconsistent program results, so that the program
works most of the time, and inexplicably fails occasionally,
carefully check to see that all of your variables have been
initialized properly.

Sometimes the memory can be corrupted by new routines not fitting
into word boundaries on your machine. Granted, this is *not*
supposed to happen, but it does anyway, even in the best
compilers and linkers. Try declaring arrays to be 1 index larger
than they should be and see if that fixes it. (This is getting to
be a rare C error (1998)).

There are times when the program does not misbehave in the
debugger, and if you put a few diagnostic printfs in it to further
check it out, it still does not die. These temporary measures may
need to be made permanent as the extra variables you created to
let you see what is going on have pushed the memory usage
boundaries of the function to a more robust spot (i.e. to a word
boundary).

Once you think you've fixed the problem, *TEST EVERYTHING* before
you release anything.

Keep at it. With practice, you can dumb yourself down to the
intelligence level of a compiler. Good Luck!

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.

To change the erase key from ctrl h to
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

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.

ftp

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

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

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:

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.

Back up everything! Source, Makefile, imakefile, etc.

imake

If imake doesn't work, try xmkmf

If it *still* doesn't work, go back to step 0.

kermit (quick check of 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.

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.

link (ln)

to create a symbolic link:

ln -s <existing file or directory> <Linked file or directory$gt;

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 yu to have the same
file in several different places without actually having maintain
multiple copies of the file.

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 avalible on Linux (yet).

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 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.

Networking

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

Load the networking module in the slakware file.
Create or copy the /etc/hosts file.
Create or copy the /etc/resolve.conf.
Edit /etc/rc.d/rc.serial.

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.

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.

qsort

Here's a wierd 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:

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.

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

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!

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.

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.

swapon

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

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

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.

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

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 writ- ting 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:

create a file /etc/adjtime containing as the
first and only line: '0.0 0 0.0'

run clock -au or clock -a, depending on whether your CMOS is
in Universal or Local Time. This updates the second number.

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:

+ 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'Rielly series in X and Motif if you
intend to do serious developemt. It's an extrodinary, 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 just start getting into building user interfaces, I
suggest that you bypass X entirely, and concentrate on Java. Of course,
Java for Unix platforms is based on X, but you shouldn't have to worry
about that.