[comp.os.minix] Boon to ST users without a real-time clock

kirkenda@jove.cs.pdx.edu (Steve Kirkendall) (03/27/89)

This program sets the time-of-day by adding 120 seconds to the modification
time of the most recently modified file.  It is guaranteed to keep 'make' happy
even when you reboot frequently.  See the comments at the start of itime.c
(near the start of the shell archive) for more info.

I have included my own /etc/rc file, as an example of its use.

This was written and tested on an ST, but should work with a PC too... but you
will have to change the -DATARI_ST flag in Makefile, of course.

: ---- cut here ---- cut here ---- cut here ---- cut here ----
:
# This is a shell archive.  Execute it as a shell script, and it
# should unpack itself into the following files:
# -rw-r--r--  1   root     4095 Mar 24 10:52 itime.c
# -rw-r--r--  1   root       91 Mar 24 10:41 Makefile
# -rw-r--r--  1   root      104 Mar 24 10:44 rc
echo unpacking itime.c...
sed 's/^X//' >itime.c <<\EOF
X/* itime.c */
X
X/* This program is useful only to people who don't have a battery-powered
X * real time clock.  It scans through all inodes in a file-system, and sets
X * the system clock by adding 120 seconds to the time of the newest inode.
X * 
X * I wrote this because I reboot Minix as often as twenty times a day, to
X * test out kernel modifications.  I got tired of entering in the date every
X * time... but I had to do *something* to keep `make` from getting confused.
X *
X * By the way, when you *do* enter the date & time, you don't have to enter
X * all twelve digits.  You can use any of the following formats:
X *	MMDDYYhhmmss	- the full twelve digits
X *	MMDDYYhhmm	- ten digits, assumes seconds are zero
X *	MMDDYY		- six digits, sets the date but leaves time unchanged
X *	hhmm		- four digits, sets time but leaves date unchanged
X * In my /etc/rc file, I run 'itime hd1' before I run 'date -q'.  Then, the
X * date is usually correct and the time is usually close enough.  If the time
X * is not close enough, then I enter the four-digit time.  If the date is
X * wrong, I enter ten or twelve digits.
X *
X * On my Atari's Supra hard disk, this program can scan a 12Mb partition's
X * inodes in about 3 or 4 seconds.
X */
X
X#include <sys/types.h>
X#include <minix/blocksize.h>
X#include <minix/const.h>
X#include <minix/type.h>
X#include <fs/const.h>
X#include <fs/type.h>
X#include <fs/super.h>
X#undef printf
X#include <stdio.h>
X#define O_RDONLY 0
X#define O_WRONLY 1
X#define O_RDWR	 2
X
X#define SECONDS	 120	/* default number of seconds to add */
X#define BLKS	 8	/* number of blocks to do at one time */
X
Xextern long lseek();	/* from library */
Xextern long atol();	/* from library */
X
Xextern long itime();	/* defined below */
X
Xmain(argc, argv)
X	int	argc;	/* number of arguments */
X	char	**argv;	/* values of arguments */
X{
X	long	now;	/* "current" time */
X	long	inow;	/* time derived from inodes */
X
X	/* check arguments */
X	if (argc < 2 || argc > 3)
X	{
X		fputs("usage: itime bdev [seconds]\n\t- sets time from inodes\n", stderr);
X		exit(2);
X	}
X
X	/* get current time */
X	time(&now);
X
X	/* get time from inodes */
X	inow = itime(argv[1]);
X
X	/* if inode time is newer than "current" time, set the clock */
X	if (inow > now)
X	{
X		/* add a few seconds */
X		if (argc == 3)
X			inow += atol(argv[2]);
X		else
X			inow += SECONDS;
X
X		stime(&inow);
X		execl("/usr/bin/date", "date", NULL);
X	}
X
X	exit(0);
X}
X
X
X/* scan inodes & return the time of the newest one */
Xlong itime(bdevname)
X	char	*bdevname;	/* name of device containing inodes */
X{
X	int		bdev;	/* file descriptor used to access the dev */
X	unsigned short	ninodes;/* number of inodes to look through */
X	static union
X	{
X		char			bytes[BLKS * BLOCK_SIZE];
X		struct super_block	s;
X		d_inode			i[BLKS * INODES_PER_BLOCK];
X	}
X			buf;
X	long		itime;	/* newest time seen so far */
X	int		i;
X
X
X	/* open the device */
X	chdir("/dev");
X	bdev = open(bdevname, O_RDONLY);
X	if (bdev < 0)
X	{
X		perror(bdevname);
X		exit(11);
X	}
X
X	/* read the superblock */
X	lseek(bdev, (long)BLOCK_SIZE, 0);
X	if ((i = read(bdev, &buf, BLOCK_SIZE)) < BLOCK_SIZE)
X	{
X		perror("superblock");
X		exit(12);
X	}
X	if (buf.s.s_magic != SUPER_MAGIC)
X	{
X		fputs("superblock: bad magic number\n", stderr);
X	}
X
X	/* extract the number of inodes */
X	ninodes = buf.s.s_ninodes;
X
X	/* lseek to the start of the inode table */
X	lseek(bdev, (long)(BLOCK_SIZE * (2 + buf.s.s_imap_blocks + buf.s.s_zmap_blocks)), 0);
X
X	/* while there are more blocks of inodes... */
X	itime = 0;
X	while (ninodes > 0)
X	{
X		/* read the next block of inodes */
X		if (read(bdev, &buf, sizeof buf) < sizeof buf)
X		{
X			perror("inode block");
X			exit(14);
X		}
X
X		/* for all inodes in these blocks... */
X		for (i = 0;
X		     ninodes > 0 && i < INODES_PER_BLOCK * BLKS;
X		     ninodes--, i++)
X		{
X#ifdef NEVERDEF
X			/* if this inode is empty, ignore it */
X			if (buf.i[i].i_nlinks == 0)
X			{
X				continue;
X			}
X#endif
X
X			/* if this inode has newer time, remember the time */
X			if (buf.i[i].i_modtime > itime)
X			{
X				itime = buf.i[i].i_modtime;
X			}
X		}
X	}
X
X	/* close the device */
X	close(bdev);
X
X	/* return the newest time */
X	return itime;
X}
EOF
if test `wc -c <itime.c` -ne  4095 ; then echo itime.c unpacked to wrong size!; fi
echo unpacking Makefile...
sed 's/^X//' >Makefile <<\EOF
XCFLAGS=	-DACK -DATARI_ST
X
Xitime: itime.o
X	cc $(CFLAGS) itime.o -o itime
X	chmem =3000 itime
EOF
if test `wc -c <Makefile` -ne  91 ; then echo Makefile unpacked to wrong size!; fi
echo unpacking rc...
sed 's/^X//' >rc <<\EOF
X/etc/mount /dev/hd1 /usr
X/usr/local/itime hd1
X/usr/bin/date -q </dev/tty
Xcat /etc/message
X/etc/update &
EOF
if test `wc -c <rc` -ne  104 ; then echo rc unpacked to wrong size!; fi
exit