Cover V03, I04
Article

jul94.tar


New Messages

To the Editor,
In Larry Reznick's article, "Multiport Serial Installation," in the March/April 1994 issue of Sys Admin magazine, he includes an insert listing installable device programs. Therein he comments that a few of the programs that he found didn't have their functionality documented.

Hopefully, the following information will help. My references are the SVR4.2 source code that my company has bought (the advantages of working for a fairly large company).

idmkenv: This command is called at boot time by a sysinit entered in the /etc/inittab file. Its purpose is to update /etc/idrc.d, /etc/idsd.d, /etc/inittab, and the device nodes, in /dev. It also recovers the kernel environment when a reconfiguration is aborted due to losing power or the user hitting the big reset button.

idval: This program is used by the idtune shell script. It is used to do the actual comparison between the new tuneable parameter against its lower and upper bounds. It supports both decimal and hexadecimal numbers and therefore is more powerful than performing such a function strictly in "shell code."

idmaster: This one I couldn't find at all. I suspect therefore that it's an add-on by Esix.

Joe Berry
joe@landmark.com
Baltimore, MD

Thanks for the research and clarification. -rlw

To: saletter@rdpub.com
Subject: Reznick's "Time for UNIX"

Larry Reznick requested a program to set up a holidays file. Listing 1 (E-Media Production Manager's note: Listings referenced within the New Messages/Letters can be found by scrolling to the bottom of the current page.) is one I wrote on January 15, 1992, together with an input file. BTW, Larry doesn't say what system he uses, but my Sun system has lots of documentation on zic files, etc.

Samuel T Denton
sdenton@world.std.com

Thanks for following up on Larry Reznick's request. Readers will no doubt put your program to good use. -rlw

To: saletter@rdpub.com
Subject: A clever use of the TZ environment variable

In the May/June issue of Sys Admin Larry Reznick describes in great detail the TZ environment variable and how one might configure a system to correctly change the time at/around daylight savings time.

In Arizona, we stay on Mountain Standard time year round. In the process of trying to figure out how to make my Apollo DomainOS systems NOT automatically adjust the time when everyone else went on daylight savings time, I came up with a clever trick that I employ in scripts that perform time/day/date calculations.

The trick is to basically retard (shift backwards) the time in scripts by 12 hours. This is done by setting the TZ environment variable in the beginning of the script to something different than the default. In other words, instead of using the default "TZ=MST7MST7", I use "TZ=BST19BST19" to retard the time 12 hours (BST is Backward Standard Time) :-)

You may be wondering how this could be useful. Take backups for example. You usually start these late at night or even early in the morning on the NEXT day. If you are trying to perform date calculations, starting things after midnight become a problem because the day and date are different than the day you are backing up.

In my situation, I had a script that was checking the tape in the drive to make sure it was the correct tape. If I was doing a Wednesday backup (early on Thursday morning), the time shift would cause the date command to return "Wednesday" so that it would match the pre-labeled tape. This is a simple case involving days, but when you start performing date calculations involving the month or the year (for example Dec. 31, 1993 vs. Jan. 1, 1994), this makes a complex calculation easy to perform.

On DomainOS I am able to shift time as many hours backward/forward as I want just by using ever-increasing/decreasing values. Check your UNIX implementation to see if it behaves the same.

Here is a script called "tzdate" I wrote to replace the "date" command used in other scripts:

#!/bin/sh
############################################################################
#
#   Program to determine what the date is if the TZ is shifted "$1"
#   hours.  This program is necessary because if a backup occurs after
#   midnight on a certain day, the previous day's information is
#   usually desired for date calculations required for the backup.
#   This script allows for this by shifting the time zone so the
#   system thinks it is yesterday, and therefore any date calculations
#   are correct (even over day, month or year boundaries.
#
#   Usage:  tzdate <hours-to-shift>    +hours retards time
#                                      -hours advances time
############################################################################

GMTSHIFT=7                          # "Our" default shift from GMT
SHIFT=`echo "$GMTSHIFT + $1" | bc`  # New shift from GMT
TZ=BST$SHIFT                        # Shift time-zone setting "$SHIFT" hours
export TZ                           # Export for child process
date                                # What does it think date is now

David J. Young
davidy@hwcae.honeywell.com
Phoenix, AZ

That's a cool solution to an interesting problem! Guess Arizona has so much daylight that there's no need to save any of it. --rlw

Listing 1: holidays.conf

# Input file for /usr/local/bin/holidays, which runs in the wee hours of
# the morning of Jan. 1st, and generates /etc/holidays for the new year.
#
# New Year`s Day is Jan. 1st, unless it falls on a weekend
1       1       1-5     New Year's Day
1       2       1       New Year's Day
# Memorial Day is the last Monday in May
5       25-31   1       Memorial Day
# Independence Day is July 4th, unless it falls on a weekend
7       4       1-5     Independence Day
7       5       1       Independence Day
7       3       5       Independence Day
# Labor Day is the first Monday in September
9       1-7     1       Labor Day
# Election Day is the Tuesday after the first Monday in November
#11     2-8     2       Election Day
# Thanksgiving is the fourth Thurday in November
11      21-28   4       Thanksgiving Day
11      22-29   5       day after Thanksgiving
# Christmas Eve is December 24th, unless it falls on a weekend
12      23      4-5     Christmas Eve
12      24      1-5     Christmas Eve
Christmas is December 25th, unless it falls on a weekend
12      25      1-5     Christmas
12      26      1-2     Christmas
# New Year`s Eve, if it falls on a Friday
12      31      5       New Year`s Eve

==> holidays.c <==
#include <stdio.h>
#include <sysexits.h>
#include <time.h>

/*
* Creates /etc/holidays file
*
* Usage:  holidays [-year <year>] [-prime <start> <end>]
*
* Input file is of the form:
*      <month> <days-of-month> <days-of-week> <holiday name>
* where:
*      <month> is in the range 1 through 12
*      <days-of-month> is in the range 1 through 31
*      <days-of-week> is in the range 0 through 6, where 0 is Sunday
*      <holiday-name> is a character string extending to EOL
*
* Output file is the holidays file expected by the accounting system.
*
*/

char *progname;

void
usage()
{
static char *help_message[] = {
"where options include:\n",
"\t-year <year>\t\tyear for which holidays are to be calculated\n",
"\t-prime <start> <end>\tstarting and ending times for prime time\n",
"\n",
"Options may be abbreviated to the shortest unambiguous prefix.\n",
"\n",
NULL
}, **cpp;

fprintf (stderr, "usage: %s [-options ...]\n\n", progname);
for (cpp = help_message; *cpp; cpp++) {
fputs (*cpp, stderr);
}
exit(EX_USAGE);
}

void
dataerr(errmsg)
char *errmsg;
{
fprintf(stderr,"%s: %s\n",progname,errmsg);
exit(EX_DATAERR);
}

main(argc,argv)
int argc;
char **argv;
{
int i,j,n,mday_start,mday_end,wday_start,wday_end;
long t;
char buffer[1024],mdays[93],wdays[14];
char *name, *prime, *non_prime;
struct tm date, *u;

progname = argv[0];

/* default to current year; except in December, when we assume next year */
t = time(NULL);
memcpy(&date,gmtime(&t),sizeof date);
if (date.tm_mon == 11) date.tm_year += 1;

/* prime time defaults to 8:00 AM to 5:00 PM */
prime = "0800";
non_prime = "1700";

/* process arguments */
for (i=1;i<argc;i++) {
char *arg = argv[i];
if (arg[0] == '-') {    /* process command line switches */
switch (arg[1]) {
case 'y':         /* -year <year> */
if (++i >= argc) usage();
date.tm_year = atoi(argv[i]);
if (date.tm_year >= 1000) date.tm_year -= 1900;
if (date.tm_year <= 0) usage();
continue;
case 'p':         /* -prime <start> <end> */
if (i+2 >= argc) usage();
prime = argv[++i];
non_prime = argv[++i];
continue;

default:
usage();
/* NOTREACHED */
}
} else {
usage();
/* NOTREACHED */
}
}                           /* end argv for-loop */

fputs("*\n* Curr\tPrime\tNon-Prime\n* Year\tStart\tStart\n*\n",stdout);
fprintf(stdout,"  %4d  %s    %s\n",1900+date.tm_year,prime,non_prime);
fputs("*\n* Day of\tCalendar\tCompany\n* Year\t\tDate\t\tHoliday\n*\n",
stdout);

while ( 1 ) {
fgets(buffer,sizeof buffer,stdin);
if (feof(stdin)) break;
if (buffer[0] == '#') continue; /* comment to ignore */
if (buffer[0] == '*') {         /* comment to pass along */
fputs(buffer,stdout);
continue;
}
n = sscanf(buffer,"%d %92s %13s %n",&date.tm_mon,mdays,wdays,&i);
if (n != 3) dataerr("data error in input file");
if ((date.tm_mon < 1) || (date.tm_mon > 12)) exit (1);
date.tm_mon -= 1;
name = &buffer[i];
n = sscanf(mdays,"%d-%d",&mday_start,&mday_end);
if (n == 0) dataerr("bad days-of-month field in input file");
if (n == 1) mday_end = mday_start;
n = sscanf(wdays,"%d-%d",&wday_start,&wday_end);
if (n == 0) dataerr("bad days-of-week field in input file");
if (n == 1) wday_end = wday_start;
for (date.tm_mday=mday_start;date.tm_mday<=mday_end;date.tm_mday++) {
t = timegm(&date);
u = gmtime(&t);
if ((u->tm_wday >= wday_start) && (u->tm_wday <= wday_end)) {
char prefix[20];
strftime(prefix,sizeof prefix,"%j\t\t%b %d",u);
printf("  %s\t\t%s",prefix,name);
}
}
}
exit(EX_OK);
}