No Next Item No Next Conference Can't Favor Can't Forget Item List Conference Home Entrance    Help
View Responses


Grex Garage Item 6: Grex software, maintainability, and libgrex.
Entered by cross on Sat Feb 12 22:17:10 UTC 2005:

It seems to me that we've developed quite a bit of software on grex
over the years.  Some of it is good, some not so good.  One thing
that I realized when rewriting the watch utility for the nextgrex
transition is that it is very beneficial to periodically review and
rewrite software applications.  This prevents code-rot and eases
the job of forward maintainability.

There was stuff in watch, for instance, dating back to System III
Unix.  These were the days prior to reasonaly efficient malloc()
implementations, prior to standard dynamic sorted container libraries,
prior to decent signal handling.  A lot of the stuff that got ripped
out had made watch brittle and difficult to move to more modern
systems, and paradoxically, a lot of that was kept in version mnet
ported to FreeBSD!  Going back and rewriting it to move to the new
system gave us a chance to fix some problems and update it to use
standard interfaces.  it was an instructive exercise to see how we
could modify a program that's evolved over many years.

And watch is a program that's fewer than 400 lines of code!

I think we might benefit from more of this sort of thing on grex.
I'd like to review the software we use, and selectively rewrite
portions of it.  We should take what we have that's custom, and
remove the use of old interface, standardize things like signal
handling and command line option parsing, etc.  We should work on
improving testability and maintainability, and in the process we
might fix a couple of stupid bugs.  We should also identify segments
of code that are similar between different programs and try to
extract those into reusable components that we can put into a
library.  This will improve maintainability of our code and make
developing new code a bit easier.

Some specific things I'm thinking about:

        * Examining our local C programs looking for things like
          argument processing loops, signal handling, etc, and
          making these fit standard interfaces (getopt(3), signal(2),
          etc).  There's a lot of historical baggage in there.
        * Changing error reporting code to use standard interfaces.
          BSD has err(3); let's use it!  If it's not on another
          platform, we can build a facade for it.
        * Modifying whatever local daemons we have to use standard
          logging interfaces, etc.
        * Looking at the command line arguments we pass to local
          programs and standardizing them.  Make sure each program
          can spit out a useful `Usage' message, and so on.
        * Try to find segments of code that are repeated frequently
          that we can put into a library for re-use.
        * Building Unit tests for library functions and functions
          in largish applications.
        * Building regression testing frameworks for programs and
          applications.
        * Having a consistent build procedure for our local programs.
          E.g., standard Makefile targets and structure, etc.
        * Building standard templates for writing new programs,
          Makefiles library functions, etc.

To this end, I've started working on a small library of useful
functions that I call, `libgrex'.  It's currently in my directory
under ~cross/src/libgrex.  As part of this, I found and modified
a very small unit testing tool called `minunit' and have written
some unit tests for some of the functions in libgrex.

Is anyone else interested in this effort?  If so, should discussion
stay here in the conferences or should I create a mailing list?

It'd be nice to get more of the community involved in this effort.

36 responses total.



#1 of 36 by jor on Sun Feb 13 01:52:32 2005:

        I want do to serious homework in this area.
        Will try soon.

        I'm experienced as a maintenance/cleanup coder,
        e.g. with C/unix. 

        Fell free to push me forward. Even with one small area.



#2 of 36 by blaise on Sun Feb 13 02:26:10 2005:

I also am interested.  I'm sadly out of practice in coding; I haven't
done much in five years or so.


#3 of 36 by naftee on Sun Feb 13 02:39:45 2005:

If you need me to do Java, I'm in


#4 of 36 by cross on Sun Feb 13 02:53:02 2005:

That's all right; you don't need to be a wizard to fix up some of grex's
utilities.

Some places to start: look over the existing libgrex code.  Let me know
if I've made any errors or if you have any additions (hey, I'm not a
saint either!).  Read up on some of the `standard' programming interfaces:

        err(3)
        getgrent(3)
        getopt(3)
        getpwent(3)
        printf(3)
        signal(3)
        string(3)
        tsearch(3)

All of these things conform to some sort of Unix standard, such as
Unix98 or the Single Unix spec; err(3) is an exception, but it's
easy to implement those functions in a compatibility layer if we
ever want to move libgrex to another machine.  Note that I only
mention printf(3) because there's a lot of `puts' cruft in our
source code, and I put in string(3) because there seems to be a lot
of hand-rolled stuff for skipping delimiters and parsing apart
strings, etc.  It'd be nice to replace that stuff with standard
functions like strsep(3), strcspn(3), etc.

Read the `libgrex/test/minunit.h' header file that describes the
unit testing framework (the comments give a terse discussion of how
to use it, and there are plenty of examples in the libgrex/test
subdirectory).  Write yourself some simple tests and suites to get
a hang of how it works; see libgrex/test/skeltest.c,
libgrex/test/skelsuite.c, and libgrex/test/testrunner.c as well
as the Makefile in libgrex/test.

Also read up on how to use the `doc++' documentation framework.
I'm using this for libgrex; it's not terribly complex, and looks
sort of like Javadoc but works on C and C++ code, too.

We need to come up with a standard for code layout with respect
to spacing, where to put the braces, etc.  I'm reasonably satisfied
with the output of the indent(1) tool for this.  It's sort of ugly,
and not precisely how I'd do it, but at this point I think
consistency is more important than individual preference.  Either
use indent or do it by hand, but make it look reasonably close.

Then start combing through /grex/grexdoc/misc/src looking for things
that you're interested in working on.  Some initial suggestions for
things that could be updated to be much simplifed or just generally
improved are the members and twit commands.  A lot of commands have
their own argument processing loops (complete with goto's to break
out of them) and don't use getopt(), which would be nice to fix.

Fortunately, most programs can also be tested in isolation, without
affecting the rest of the systems.  Once you've got something
working, put a notice here or send me an email.  I'll look over
your changes and put it into production if it looks good.

Note that this last step is rather cumbersome.  I'd much rather
have a shared source repository where multiple people, not necessarily
staff, can commit.  Part of that might mean divorcing our source
base from the grexdoc change management system that Jan put together.
Grexdoc is great for controlling changes to grex's configuration;
it might not be so great for controlling changes to grex's software.
This is something that needs a bit more thought and discussion, but
right now, I'd like to see something like a Subversion repository
that grexdoc hooked into to install grex's locally written and
maintained software.  As part of this, I might move libgrex under
another directory, called `grexsoft' that includes some source files
from elsewhere on the system.

Eventually, I'd like to wrap the scripts in /usr/local/grex-scripts
into this effort as well.  There's a lot of SunOS cruft left in those
(it's outstanding the number of places that /usr/ucb appears in
those files!), but the C stuff is enough of a start.


#5 of 36 by cross on Sun Feb 13 02:55:20 2005:

Regarding #3; There's not a lot of Java on grex.  For that matter, we
don't even have a Java compiler....  Hmm.


#6 of 36 by sj2 on Sun Feb 13 05:53:50 2005:

Ok, so we need CVS for maintaing the code tree. I'd like to sign up but
only if all code is GPL. Is it?


#7 of 36 by cross on Sun Feb 13 05:57:18 2005:

It's not really anything.  It's more or less public domain....

I was thinking Subversion instead of CVS, but that's not a huge
difference.

Hmm, actually, now I am curious what license the grex source code
is under.  Does anyone know?  I suppose it's up to the individual
authors.  For my own contributions, I'd be fine with any open
source or public domain license.  Siddhartha, how would you feel
about a BSD-style or public domain license?


#8 of 36 by cross on Sun Feb 13 21:57:29 2005:

Another task that needs to be accomplished is writing man pages for
the grex utilities.  This is going to require reading the source code
to them, figuring out what they do, and then writing the troff -man
source itself.  Note: if you write a manpage, use -man and not -mandoc,
which isn't easily portable.


#9 of 36 by sj2 on Mon Feb 14 14:50:03 2005:

Re #7, I prefer good ol' GPL. That way no one can take the code and use
it for a closed-source product. GPL will ensure that wherever the code
is used the source is also distributed alongwith.


#10 of 36 by cross on Mon Feb 14 16:39:44 2005:

Well, if you write something new, you can certainly put it under
the GPL.  I don't see why libgrex can't be GPL'ed, for that matter.
On the other hand, a bit of the Grex software already has a BSD
style license (most things by Marcus Watts, for instance).  I'm not
too into license holy wars, and I don't care if someone uses the
source code for a closed-source thing or not, but that's just me.


#11 of 36 by cross on Mon Feb 14 18:14:21 2005:

Okay, so in an effort to move things along, I've done a slight reorganization
of the directory structure for all this, putting a `grexsoft' directory
under ~cross and putting some commands there.  Currently, `grexsoft'
contains two subdirectories: cmd, and libgrex.  Libgrex is obvious, `cmd'
is the source to some of our local commands.  I'm going to symlink
~cross/src/libgrex to ~cross/grexsoft/libgrex and move my work to there.


#12 of 36 by cross on Wed Feb 16 20:42:52 2005:

I put grexsoft into a CVS repository under /a/n/c/ncvs.  I'm work on
it more later, but presently, I can commit from multiple places (which
is a lot nicer than what I had been doing.


#13 of 36 by naftee on Thu Feb 17 01:37:59 2005:

unl ul . lucky


#14 of 36 by cross on Thu Feb 17 03:59:56 2005:

I added a couple of new functions to libgrex: warning() and fatal().
These do basically what their names imply: print error-style messages
to standard output, and fatal() calls exit with EXIT_FAILURE.

Each function works like printf(): you can specify variable arguments
using normal printf(3) style verbs.  Additionally, if the verb "%r"
appears in the format string, it is replaced with the contents of
`strerror(errno)' for the current value of errno.  %r can appear
anywhere in the format string, and may appear multiple times.
Finally, if you've called the libgrex function `progname()' and it
has returned a meaningful value, the error message will be proceeded
by the return value of progname() and ": ".

Note that format specifiers to warning() and fatal() need not include
a trailing newline: that will be automatically appended, just like
in the perror() function.

warning() and fatal() have to possibly interpolate other strings
into the passed-in format string.  They try to do this in an
intelligent way that will minimize potential errors - after all,
your error reporting routine erroring out and producing no output
doesn't do you much good.  If they fail in their interpolation
attempts, they make a best-effort attempt to print out your error
message, but some %r verbs might not be interpreted correctly.

Typical uses might be:

        /* ... Say this is invoked as: /usr/local/bin/myprog */
        const char *OUTPUT_FILE = "/etc/output";
        prog = progname(argv[0]);
        while ((file = *++argv) != NULL) {
                fp = fopen(file, "r");
                if (fp == NULL) {
                        warning("Failed to open %s: %r", file);
                        continue;
                }
                /* ... */
                fclose(fp);
        }
        outfp = fopen(OUTPUT_FILE, "w");
        if (outfp == NULL)
                fatal("Can't open %s for writing: %r", OUTPUT_FILE);
        /* ... etc etc etc */

If one of the input files couldn't be opened and you couldn't write
to /etc/output, you would see the following errors:

myprog: Failed to open /some/file: No such file or directory.
myprog: Can't open /etc/output for writing: Permission denied.

And the program would exit after the printing the second message.
Exit status would be whatever EXIT_FAILURE is defined to (usually 1).


#15 of 36 by cross on Wed Feb 23 03:02:16 2005:

I set up the RT `request tracker' system for use in maintaining grexsoft.


#16 of 36 by cross on Sun Feb 27 05:34:52 2005:

I rewrote the twit filter and installed it today.  The original had
a lot of garbage like, `#define then {' in it, and was overly complex
for no good reason.  It also had a lot of pre-ANSI C'isms in it that I
removed, like forward declarations of functions inside of other
functions and stuff like that.  Ick.

I also have an awk version of the filter that's less than 15 lines
long.  The C version shrank to something like 60 lines.


#17 of 36 by cross on Sun Feb 27 07:04:23 2005:

More on RT:

RT is usually associated with system administration: It's essentially
helpdesk software.  Something like Bugzilla is usually associated
with software development, so why not Bugzilla?

Well, the grexsoft effort sort of straddles the worlds of system
administration and software development.  So it doesn't make sense
to use tools that are primarily targetted at software engineering
(like Bugzilla).  RT is an issue tracking system that works well
for both system administration and software development (for instance,
the RT developers use RT for their own efforts), and a tool for
issue tracking *is* needed, so that's what I went with.  Besides,
it'd be nice to wrap other grex management tasks into RT, and this
is a start in that direction.

For more information, have a look at Best Practical:

http://www.bestpractical.com/


#18 of 36 by cross on Sun Feb 27 09:21:07 2005:

I've configured CVS to log its commit messages to BBS.  See item
9 in garage.


#19 of 36 by cross on Sun Feb 27 09:27:58 2005:

I'd like to start building program-level tests for the grexsoft
commands.  Right now, we have unit tests for the libgrex functions,
which is good, but not the only thing we need.  In particular, we
need a suite of regression tests for the rest of our commands.

Using a framework like DejaGNU for this would be really nice, and
quite powerful, but there are problems installing DejaGNU on grex
without X11 support.  Actually, it's not so much X11 support that's
needed as much as it is expect and tk, which depend on the X11
programming libraries.  I've suggested in another item that we
install these libraries during the next grex upgrade; this will
make installing things like doc++ easier.


#20 of 36 by cross on Wed Mar 16 21:04:35 2005:

I installed the X11 programmer suite here on grex, and reinstalled
doc++ and DejaGNU.  DejaGNU is actually quite complex, so might be
overkill.  I'm investigating simple regression level testing
frameworks, but there isn't much out there.  We'll probably have
to build something.

This and documentation are the big priorities right now.  If you'll
notice from the CVS commit messages logged in item 9, many of the
things I'm checking in are fixes to little bugs I'm introducing.
This is due primarily to three reasons:  1) I'm human and I make
mistakes, especially with something I don't have too much time for.
2) Most grexsoft commands are undocumented, and it's not always
easy to figure out what the expected output for them should be.
3) I'm not testing commands after building them, generally, because
there's no cheap, easy way to automate doing so.

Well, being aware of my own limitations, I've figured out that I've
got to do things somewhat differently.  I've got to structure the
development process a little more efficiently....  How to do this?

I propose the following model for modifying grexsoft code:

        1) Pick a command to change.
        2) If it's not already documented, document it.
           Write a man page for it describing what it's
           supposed to do.  If documentation exists and
           is wrong, tweak it.
        3) Write a regression test for it.
        4) Peak through the source code and try and
           document that.
        5) Write unit-level tests for the major components
           inside the source (this may not be applicable).
        6) Refactor.
        7) Iterate from step 2.

In this model, documentation describes function and comes first,
followed by testing.  Testing is defined by function and drives the
process.  The process iterates, and development and refactoring and
refactoring are repeated throughout the entire procedure in a process
of successive refinement.

Now, we just need to come up with a regression testing framework.
Something like this looks promising:

        http://diveintopython.org/regression_testing/

Except that we have a lot more perl hackers on grex than python types,
I think.  It'd be interesting to take something like that and adapt it
to Perl and use it here.


#21 of 36 by eprom on Wed Jun 1 18:07:49 2005:

In Backtalk, please create larger buttons for the listing options
(i.e. 'New Items', 'Unforgotten', 'Forgotten', 'All')

On a 800x600 monitor they are ok, but on anything larger than 
1024x768 they are too tiny to click on.


#22 of 36 by gull on Wed Jun 1 18:36:39 2005:

Maybe we need a "large print edition" interface. :)


#23 of 36 by janc on Wed Sep 21 13:19:15 2005:

I do have a certain tendancy to retain code for obsolete Unix's in my
programs.  I believe, for instance, Backtalk has code to handle versions of
Unix without mkdir(), which is, admittedly, insane.  I have no objection to
updating stuff, but it doesn't entirely thrill me either.  I still do a lot
of things in old-fashioned ways.  After all, I've been programming Unix
systems for at least 20 years now.  One tends to keep doing what works.

If the buttons are too tiny to click on, is the text too tiny to read?  Or
do you have your browser scaling up the text?  Maybe you just have young eyes.
Me, I wear progressive bi-focals and keep my chin up at the computer. 
Luckily, I mostly type near the bottom of the screen.  Anyway, an option for
larger buttons in Pistachio would be doable, but not exacly simple.  I've put
it on my Backtalk TODO list - which contains hundreds of items.


#24 of 36 by remmers on Wed Sep 21 21:24:15 2005:

Hm, I use a 1440x900 display, and the pistachio buttons are plenty large
enough for me.

There are Unixes without mkdir()???


#25 of 36 by cross on Wed Sep 21 22:53:33 2005:

No.  According to the 1st Edition Unix manual (circa Nov., 1971), Unix
had a mkdir system call.  Perhaps Jan meant rename, which was rather
later, or opendir/readdir/closedir, which were BSD inventions.


#26 of 36 by janc on Thu Nov 10 04:15:49 2005:

rename? opendir?  Those are practically brand new.

My recollection is that seventh edition Unix didn't have a mkdir() call.
You used mknod() instead.

At http://www.freebsd.org/cgi/man.cgi you'll find a nice collection of
nice man page sets.  If you select "Seventh edition Unix" and search for
"mkdir" you'll only find the command line version.  If you search for
mknod, you'll find that the description of mknod(2) mentions the
creation of directories.  Note that mknod() only works for root users. 
The mkdir command was an suid-root program back in those days.

Interesting that the first edition had mkdir().  Maybe the renamed it to
mknod() when they added special devices and then brought back mkdir()
when the want a non-suid-root ability to create directories.



#27 of 36 by naftee on Thu Nov 10 04:28:30 2005:

janc ! can you answer our fronttalk questions, please ?


#28 of 36 by cross on Thu Nov 10 04:29:58 2005:

Perhaps you're right.  The filesystem in 1st Edition was quite different.


#29 of 36 by noorul on Mon Aug 28 19:42:34 2006:

Is this thread closed? Or still work is going on?


#30 of 36 by cross on Tue Aug 29 03:38:52 2006:

No one ever joined me and I got bored.  So, no work is going on, though I
wouldn't necessarily say that the thread is closed.


#31 of 36 by noorul on Wed Aug 30 17:03:30 2006:

I am ready to C/Shell programming. I am ready to learn Perl if necessary. I
can do little bit of python programming
May I know how can I help you?


#32 of 36 by cross on Wed Aug 30 18:13:36 2006:

Well, you can check out the current version and peek through it.  If you see
something you'd like to work on, go ahead and edit it and email me the
changes.  If they're good, I'll commit them.  Otherwise, I'll email you back
with suggestions.


#33 of 36 by noorul on Wed Aug 30 18:46:10 2006:

I e-mailed you sometime back. But it got bounced because it is getting
forwarded to some internet address. I dont have permissions to send e-mails
to internet addresses. I was going through the grex faq (!faq), still it has
got this SunOS listed as the OS used by grex. The web based faq seems to be
fine. I would like to know how to start reading the code. I mean where to find
the code? Do I have to use some version control system to checkout the code.
It will be better if you can send me some suggestions to do stuffs.


#34 of 36 by cross on Thu Aug 31 04:28:14 2006:

Yes, you need to check out the code first.  I was using CVS for version
control, because it came with OpenBSD, worked tolerably well, and subversion
(which would have been my first choice) wasn't in the ports collection at that
time.  For similar reasons, I used doc++ instead of doxygen.

Regardless, here is what you do:

1) create a directory where you'd like your working copy of the source code
   to live.  I usually call mine $HOME/work (that is, a subdirectory "work"
   under my home directory.  Change directories to that directory.
2) Check out a copy of the source code:
   cvs -d /a/n/c/ncvs co grexsoft
   This will create a directory called "grexsoft" under the current working
   directory.  You may get some CVS warnings related to being unable to update
   history files and the like; you can mostly ignore these.
3) Poke around the current grexsoft sources and see what's there; some of it
   is quite old, some much newer.  In either case, the best way to start is
   by reading what's there.  Given time, it becomes easier to spot the good
   code inside the bad, but at first this can be a bit difficult.

   A specific suggestion: the version of the "watch.c" program that's under
   grexsoft/cmd is much improved over the original; how could you improve it
   still further?  Look at the libgrex code; can you think of any other
   routines that would be useful to add?

That should get you started.

Also, read this item and the grexsoft commit item in this conference.  Get
familiar with the tools: make, indent, cvs, etc.


#35 of 36 by noorul on Thu Aug 31 14:50:47 2006:

cvs checkout: warning: cannot write to history file
/a/n/c/ncvs/CVSROOT/history: Permission denied
cvs checkout: Updating grexsoft
cvs checkout: failed to create lock directory for `/a/n/c/ncvs/grexsoft'
(/a/n/c/ncvs/grexsoft/#cvs.lock): Permission denied
cvs checkout: failed to obtain dir lock in repository `/a/n/c/ncvs/grexsoft'
cvs [checkout aborted]: read lock failed - giving up

I got that error. The grexsoft directory got created but no source files.


#36 of 36 by cross on Thu Aug 31 21:59:31 2006:

Oh. Hmm.  Yeah, that's a problem, but one I don't have access to fix anymore,
really.  You might be out of luck there.

Response not possible - You must register and login before posting.

No Next Item No Next Conference Can't Favor Can't Forget Item List Conference Home Entrance    Help

- Backtalk version 1.3.30 - Copyright 1996-2006, Jan Wolter and Steve Weiss