home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume44
/
typhoon
/
part02
< prev
next >
Wrap
Internet Message Format
|
1994-09-17
|
62KB
From: zeppelin@login.dknet.dk (Thomas B. Pedersen)
Newsgroups: comp.sources.misc
Subject: v44i058: typhoon - Typhoon Relational Database Management System, Part02/09
Date: 17 Sep 1994 21:44:15 -0500
Organization: Sterling Software
Sender: kent@sparky.sterling.com
Approved: kent@sparky.sterling.com
Message-ID: <35g9hv$ofg@sparky.sterling.com>
X-Md4-Signature: ae0f28b0c926f38174b9f245402b9fdc
Submitted-by: zeppelin@login.dknet.dk (Thomas B. Pedersen)
Posting-number: Volume 44, Issue 58
Archive-name: typhoon/part02
Environment: SCO UNIX, Tandem NonStop UNIX, Sun Solaris, AIX, Linux, OS/2
#! /bin/sh
# This is a shell archive. Remove anything before this line, then feed it
# into a shell via "sh file" or similar. To overwrite existing files,
# type "sh file -c".
# Contents: typhoon/src/os2.c typhoon/src/ty_open.c
# typhoon/src/util/backup.c typhoon/src/util/import.c
# typhoon/src/util/restore.c
# Wrapped by kent@sparky on Sat Sep 17 21:38:15 1994
PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
echo If this archive is complete, you will see the following message:
echo ' "shar: End of archive 2 (of 9)."'
if test -f 'typhoon/src/os2.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'typhoon/src/os2.c'\"
else
echo shar: Extracting \"'typhoon/src/os2.c'\" \(3660 characters\)
sed "s/^X//" >'typhoon/src/os2.c' <<'END_OF_FILE'
X/*----------------------------------------------------------------------------
X * File : os2.c
X * Library : typhoon
X * OS : UNIX, OS/2, DOS
X * Author : Thomas B. Pedersen
X *
X * Copyright (c) 1994 Thomas B. Pedersen. All rights reserved.
X *
X * Permission is hereby granted, without written agreement and without
X * license or royalty fees, to use, copy, modify, and distribute this
X * software and its documentation for any purpose, provided that the above
X * copyright notice and the following two paragraphs appear (1) in all
X * source copies of this software and (2) in accompanying documentation
X * wherever the programatic interface of this software, or any derivative
X * of it, is described.
X *
X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN
X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
X * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
X *
X * Description:
X * Contains functions specific to OS/2.
X *
X * Functions:
X * ty_openlock - Create/open the locking resource.
X * ty_closelock - Close the locking resource.
X * ty_lock - Obtain the lock.
X * ty_unlock - Release the lock.
X *
X * $Log: os2.c,v $
X * Revision 1.1 1994/09/13 21:28:31 tbp
X * Added to repository.
X *
X *
X *--------------------------------------------------------------------------*/
X
Xstatic char rcsid[] = "$Id";
X
X#define INCL_NOPMAPI
X#define INCL_DOSSEMAPHORES
X#include <os2.h>
X
X#define TIMEOUT -1 /* Wait maximum 30 seconds for excl. access */
X
X/*---------------------------- Global variables ----------------------------*/
Xstatic HMTX block_sem; /* Blocking semaphore used by d_block() */
Xstatic HMTX ty_sem; /* API function semaphore */
X
X
X#ifdef __BORLANDC__
XULONG _dllmain(ULONG termflag, HMODULE modhandle)
X#endif
X#ifdef __IBMC__
Xvoid _CRT_init(void);
XULONG _System _DLL_InitTerm(ULONG modhandle, ULONG termflag)
X#endif
X{
X static char fname[] = "\\SEM32\\TYPHOON";
X
X switch( termflag )
X {
X case 0:
X#ifdef __IBMC__
X _CRT_init();
X#endif
X if( DosOpenMutexSem(fname, &ty_sem) )
X if( DosCreateMutexSem(fname, &ty_sem, 0, 0) )
X return 0;
X
X if( DosCreateMutexSem(NULL, &block_sem, 0, 0) )
X return 0;
X break;
X
X case 1:
X /* Never release the ty_sem semaphore */
X DosCloseMutexSem(ty_sem);
X DosCloseMutexSem(block_sem);
X break;
X }
X
X return 1;
X}
X
X/*------------------------------ ty_openlock ------------------------------*\
X *
X * Purpose : This function ensures that only one instance of a Typhoon
X * function is active at the time, at least in its critical
X * section.
X *
X * Parameters: None.
X *
X * Returns : -1 - Semaphore could not be created.
X * 0 - Successful.
X *
X */
X
Xty_openlock()
X{
X/*
X static char fname[] = "\\SEM32\\TYPHOON";
X
X if( DosOpenMutexSem(fname, &ty_sem) )
X if( DosCreateMutexSem(fname, &ty_sem, 0, 0) )
X return -1;
X
X locked = 0;
X*/
X return 0;
X}
X
X
Xty_closelock()
X{
X/* DosCloseMutexSem(ty_sem);*/
X return 0;
X}
X
X
Xty_lock()
X{
X if( DosRequestMutexSem(ty_sem, TIMEOUT) )
X return -1;
X
X return 0;
X}
X
X
Xty_unlock()
X{
X DosReleaseMutexSem(ty_sem);
X return 0;
X}
X
X
Xvoid os2_block()
X{
X DosRequestMutexSem(block_sem, -1L);
X}
X
X
Xvoid os2_unblock()
X{
X DosReleaseMutexSem(block_sem);
X}
X
X/* end-of-file */
END_OF_FILE
if test 3660 -ne `wc -c <'typhoon/src/os2.c'`; then
echo shar: \"'typhoon/src/os2.c'\" unpacked with wrong size!
fi
# end of 'typhoon/src/os2.c'
fi
if test -f 'typhoon/src/ty_open.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'typhoon/src/ty_open.c'\"
else
echo shar: Extracting \"'typhoon/src/ty_open.c'\" \(13441 characters\)
sed "s/^X//" >'typhoon/src/ty_open.c' <<'END_OF_FILE'
X/*----------------------------------------------------------------------------
X * File : ty_open.c
X * Library : typhoon
X * OS : UNIX, OS/2, DOS
X * Author : Thomas B. Pedersen
X *
X * Copyright (c) 1994 Thomas B. Pedersen. All rights reserved.
X *
X * Permission is hereby granted, without written agreement and without
X * license or royalty fees, to use, copy, modify, and distribute this
X * software and its documentation for any purpose, provided that the above
X * copyright notice and the following two paragraphs appear (1) in all
X * source copies of this software and (2) in accompanying documentation
X * wherever the programatic interface of this software, or any derivative
X * of it, is described.
X *
X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN
X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
X * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
X *
X * Description:
X *
X * Functions:
X * Contains functions for opening and closing the database.
X *
X * $Log: ty_open.c,v $
X * Revision 1.2 1994/09/17 16:00:19 tbp
X * typhoon.h and environ.h are now included from <>.
X *
X * Revision 1.1 1994/09/13 21:28:36 tbp
X * Added to repository.
X *
X *
X *--------------------------------------------------------------------------*/
X
Xstatic char rcsid[] = "$Id";
X
X#ifdef UNIX
X# include <unistd.h>
X# include <stdio.h>
X# ifdef __STDC__
X# include <stdlib.h>
X# endif
X# define DIR_SWITCH '/'
X#else
X# include <stdlib.h>
X# include <io.h>
X# define DIR_SWITCH '\\'
X#endif
X#include <fcntl.h>
X#include <assert.h>
X#include <string.h>
X#include <stdio.h>
X#include <typhoon.h>
X#include "ty_dbd.h"
X#include "ty_type.h"
X#include "ty_glob.h"
X#include "ty_prot.h"
X
X/*--------------------------- Function prototypes --------------------------*/
Xstatic void fixpath PRM( (char *, char *); )
X int read_dbdfile PRM( (Dbentry *, char *); )
Xstatic int perform_rebuild PRM( (unsigned); )
X
X
Xstatic void (*rebuildverbose_fn) PRM((char *, ulong, ulong);)
X
X
Xstatic void fixpath(path, s)
Xchar *path, *s;
X{
X int len = strlen(s);
X
X if( len > 0 )
X {
X strcpy(path, s);
X
X if( path[len-1] != DIR_SWITCH )
X {
X path[len++] = DIR_SWITCH;
X path[len] = 0;
X }
X }
X else
X {
X path[0] = '.';
X path[1] = DIR_SWITCH;
X path[2] = 0;
X }
X}
X
X
X
X/*-------------------------------- d_dbdpath -------------------------------*\
X *
X * Purpose : Set the path of the dbd-file. This function is called prior
X * d_open().
X *
X * Parameters: path - The path of the dbd-file.
X *
X * Returns : S_OKAY - Successful.
X *
X */
X
X
XFNCLASS d_dbdpath(path)
Xchar *path;
X{
X fixpath(typhoon.dbdpath, path);
X
X return S_OKAY;
X}
X
X
X
X/*-------------------------------- d_dbfpath -------------------------------*\
X *
X * Purpose : Set the path of the database files. This function is called
X * prior to d_open().
X *
X * Parameters: path - The path of the database files.
X *
X * Returns : S_OKAY - Successful.
X *
X */
X
X
XFNCLASS d_dbfpath(path)
Xchar *path;
X{
X fixpath(typhoon.dbfpath, path);
X
X return S_OKAY;
X}
X
X
X
X/*--------------------------------- d_dbget --------------------------------*\
X *
X * Purpose : Gets the current database ID.
X *
X * Parameters: id - Pointer to database ID.
X *
X * Returns : S_OKAY - The database ID is stored in <id>.
X * S_NOCD - There is no current database.
X *
X */
X
XFNCLASS d_dbget(id)
Xint *id;
X{
X if( CURR_DB == -1 )
X RETURN S_NOCD;
X
X *id = CURR_DB;
X
X RETURN S_OKAY;
X}
X
X
X
X/*--------------------------------- d_dbset --------------------------------*\
X *
X * Purpose : Sets the current database ID.
X *
X * Parameters: id - Database ID obtained by call to d_dbget().
X *
X * Returns : S_OKAY - The database ID is stored in <id>.
X * S_INVDB - Invalid database ID.
X *
X */
X
XFNCLASS d_dbset(id)
Xint id;
X{
X int i;
X
X /* Ensure that the id is valid */
X if( id < 0 || id >= DB_MAX )
X RETURN S_INVDB;
X
X /* Ensure that the database is actually open */
X if( typhoon.dbtab[id].clients == 0 )
X RETURN S_INVDB;
X
X DB->db_status = db_status;
X
X typhoon.curr_db = id;
X typhoon.db = typhoon.dbtab + id;
X
X db_status = DB->db_status;
X
X RETURN S_OKAY;
X}
X
X
X/*------------------------------- d_setfiles -------------------------------*\
X *
X * Purpose : Set the maximum number of open files.
X *
X * Parameters: maxfiles - The maximum number of open files allowed.
X *
X * Returns : S_OKAY - Ok.
X * S_INVPARM- The maximum is invalid.
X *
X */
XFNCLASS d_setfiles(maxfiles)
Xint maxfiles;
X{
X if( maxfiles < 2 )
X RETURN S_INVPARM;
X
X if( maxfiles < typhoon.max_open )
X {
X /* maxfiles is less than max_open, so we need minimize the number
X * of open files right away.
X */
X int diff = typhoon.max_open - maxfiles;
X
X while( typhoon.cur_open > maxfiles && diff-- )
X ty_closeafile();
X
X /* If it was not possible to closed the required number of files
X * anyway, an error code is returned
X */
X if( typhoon.cur_open > maxfiles )
X RETURN S_INVPARM;
X }
X
X typhoon.max_open = maxfiles;
X
X RETURN S_OKAY;
X}
X
X
X
XFNCLASS d_keybuild(fn)
Xvoid (*fn)PRM((char *, ulong, ulong);)
X{
X typhoon.do_rebuild = 1;
X rebuildverbose_fn = fn;
X}
X
X
Xstatic perform_rebuild(biggest_rec)
Xunsigned biggest_rec;
X{
X ulong recno;
X ulong recid;
X ulong datasize;
X ulong records;
X char *buf;
X int fh, i;
X Record *rec;
X RECORD filehd;
X char fname[128];
X int preamble;
X int foreign_keys;
X
X if( (buf = (void *)malloc(biggest_rec)) == NULL )
X RETURN S_NOMEM;
X
X for( i=0, rec=DB->record; i<DB->header.records; i++, rec++ )
X {
X sprintf(fname, "%s%c%s_tmp", DB->dbfpath, DIR_SWITCH,
X DB->file[rec->fileid].name);
X
X fh = os_open(fname, O_RDWR|O_BINARY, 0);
X read(fh, &filehd.H, sizeof filehd.H);
X
X recno = (sizeof(filehd.H) + filehd.H.recsize - 1) / filehd.H.recsize;
X recid = INTERN_TO_RECID(i);
X records = lseek(fh, 0, SEEK_END) / filehd.H.recsize;
X
X rebuildverbose_fn(rec->name, records, 0);
X
X if( rec->first_foreign == -1 )
X foreign_keys = 0;
X else
X foreign_keys = rec->keys - (rec->first_foreign - rec->first_key);
X preamble= sizeof(long) * foreign_keys + offsetof(RECORDHEAD, data[0]);
X datasize= filehd.H.recsize - preamble;
X
X for( ;; )
X {
X lseek(fh, filehd.H.recsize * recno + preamble, SEEK_SET);
X if( read(fh, buf, datasize) != datasize )
X break;
X
X if( d_fillnew(recid, buf) != S_OKAY )
X printf("%s: d_fillnew failed\n", rec->name);
X
X recno++;
X
X rebuildverbose_fn(rec->name, records, recno);
X }
X
X close(fh);
X unlink(fname);
X
X rebuildverbose_fn(rec->name, records, records);
X }
X free(buf);
X
X RETURN S_OKAY;
X}
X
X
X
X/*--------------------------------- d_open ---------------------------------*\
X *
X * Purpose : Opens a database of the name <dbname>. The dbd-file is
X * expected to be in <dbdpath> and the data and index file are
X * expected to be in (or will be created in) <dbfpath>, set by
X * d_dbdpath() and d_dbfpath().
X *
X * If the database is opened in exclusive or one-user mode the
X * first file is locked. This will make future calls to d_open()
X * return S_UNAVAIL.
X *
X * Parameters: dbname - Database name.
X * mode - [s]hared, e[x]clusive or [o]ne user mode.
X *
X * Returns : S_OKAY - Database successfully opened.
X * S_NOTAVAIL - Database is currently not available.
X * S_NOMEM - Not enough memory to open database.
X * S_INVDB - Invalid database name.
X * S_BADTYPE - The mode parmeter was invalid.
X *
X */
X
XFNCLASS d_open(dbname, mode)
Xchar *dbname, *mode;
X{
X char fname[129];
X Record *rec;
X int i, n;
X unsigned biggest_rec = 0;
X Dbentry *_db;
X
X db_status = S_OKAY;
X
X /* Validate the mode parameter */
X if( *mode != 's' && *mode != 'x' && *mode != 'o' )
X RETURN_RAP(S_BADTYPE);
X
X /* Initialize locking resource */
X if( ty_openlock() == -1 )
X RETURN S_FATAL;
X
X ty_lock();
X
X /* Find an available database slot */
X for( i=0, _db=typhoon.dbtab; i<DB_MAX; i++, _db++ )
X if( !_db->clients )
X break;
X
X if( i == DB_MAX )
X {
X ty_unlock();
X RETURN S_NOTAVAIL;
X }
X
X DB = _db;
X DB->mode = *mode;
X strcpy(DB->name, dbname);
X strcpy(DB->dbfpath, typhoon.dbfpath);
X
X /* dbd-file is located in <dbdpath> */
X sprintf(fname, "%s%s.dbd", typhoon.dbdpath, dbname);
X if( read_dbdfile(DB, fname) != S_OKAY )
X {
X ty_unlock();
X return db_status;
X }
X
X /* Allocate 'current record' buffer (add room for record numbers of
X * parent records (one per foreign key)
X */
X for( i=0, rec=DB->record; i<DB->header.records; i++, rec++ )
X {
X if( rec->first_foreign == -1 )
X n = rec->size;
X else
X n = rec->size + (rec->keys - (rec->first_foreign - rec->first_key))
X * sizeof(ulong);
X
X if( n > biggest_rec )
X biggest_rec = n;
X }
X
X if( (DB->real_recbuf = (char *)malloc(biggest_rec)) == NULL )
X {
X ty_unlock();
X free(DB->dbd);
X RETURN S_NOMEM;
X }
X
X if( shm_alloc(DB) == -1 )
X {
X ty_unlock();
X free(DB->dbd);
X return S_NOMEM;
X }
X
X /* The database cannot be opened during a restore (except for rebuild) */
X if( DB->shm->restore_active && !typhoon.do_rebuild )
X {
X ty_unlock();
X free(DB->dbd);
X shm_free(DB);
X RETURN S_NOTAVAIL;
X }
X
X DB->recbuf = DB->real_recbuf;
X DB->clients++;
X
X /* If the indices should be rebuilt we'll remove them first */
X if( typhoon.do_rebuild )
X {
X char fname[256];
X char new_fname[256];
X
X for( i=0; i<DB->header.files; i++ )
X if( DB->file[i].type == 'k' )
X {
X sprintf(fname, "%s%c%s", typhoon.dbfpath, DIR_SWITCH, DB->file[i].name);
X unlink(fname);
X }
X else
X {
X sprintf(fname, "%s%c%s", typhoon.dbfpath, DIR_SWITCH, DB->file[i].name);
X sprintf(new_fname, "%s_tmp", fname);
X unlink(new_fname);
X rename(fname, new_fname);
X }
X }
X
X /* Before opening the database we mark all file handles are closed */
X for( i=0; i<DB->header.files; i++ )
X DB->fh[i].any = NULL;
X
X /* Open all the database files */
X for( i=0; i<DB->header.files && db_status == S_OKAY; i++ )
X ty_openfile(DB->file + i, DB->fh + i, *mode == 's');
X
X /* Roll back if a file could not be opened */
X if( db_status != S_OKAY )
X {
X i--;
X while( i-- )
X ty_closefile(DB->fh + i);
X
X DB->clients--;
X CURR_DB = -1;
X shm_free(DB);
X free(DB->real_recbuf);
X free(DB->dbd);
X ty_unlock();
X RETURN db_status;
X }
X
X CURR_DB = _db - typhoon.dbtab;
X CURR_REC = 0;
X CURR_RECID = 0;
X CURR_BUFREC = 0;
X CURR_BUFRECID = 0;
X
X if( typhoon.do_rebuild )
X {
X perform_rebuild(biggest_rec);
X typhoon.do_rebuild = 0;
X }
X
X typhoon.dbs_open++;
X ty_unlock();
X
X /* Return the status of the last db_open command */
X return db_status;
X}
X
X
X
X/*--------------------------------- d_close --------------------------------*\
X *
X * Purpose : Close the current database.
X *
X * Parameters: None.
X *
X * Returns : S_NOCD - No current database.
X * S_OKAY - Database successfully closed.
X *
X */
X
XFNCLASS d_close()
X{
X int i;
X
X if( CURR_DB == -1 )
X RETURN_RAP(S_NOCD);
X
X DB->clients--;
X
X for( i=0; i<DB->header.files; i++ )
X ty_closefile(DB->fh + i);
X
X /* If there is currently a transaction active the transaction counter
X * in shared memory must be decremented.
X */
X d_abortwork();
X
X shm_free(DB);
X FREE(DB->dbd);
X FREE(DB->real_recbuf);
X
X CURR_DB = -1;
X CURR_REC = 0;
X
X if( !--typhoon.dbs_open )
X ty_closelock();
X
X RETURN S_OKAY;
X}
X
X
X
X/*-------------------------------- d_destroy -------------------------------*\
X *
X * Purpose : Destroy a database.
X *
X * Parameters: dbname - Database name.
X *
X * Returns : S_NOMEM - Not enough memory to open database and destroy.
X * S_INVDB - Invalid database name.
X * S_OKAY - Database successfully closed.
X * S_NOTAVAIL - The database is already opened in non-shared
X * mode.
X *
X *
X * INSERT LOCK CHECK HERE!!!!!
X *
X *
X */
X
XFNCLASS d_destroy(dbname)
Xchar *dbname;
X{
X int i, dbdfile;
X char fname[80];
X Header header;
X File *file;
X Dbentry *_db = typhoon.dbtab;
X
X ty_lock();
X
X for( i=0; i<DB_MAX; i++, _db++ ) /* Find database name in table */
X if( !strcmp(_db->name, dbname) )
X break;
X
X if( i == DB_MAX )
X { /* Database currently not open */
X sprintf(fname, "%s%s.dbd", typhoon.dbdpath, dbname);
X
X if( (dbdfile = open(fname, O_BINARY|O_RDONLY)) == -1 )
X {
X ty_unlock();
X RETURN S_INVDB; /* Database name not found */
X }
X read(dbdfile, &header, sizeof header);
X
X if( !(file = (File *)malloc(sizeof(File) * header.files)) )
X {
X close(dbdfile);
X ty_unlock();
X RETURN S_NOMEM;
X }
X
X read(dbdfile, file, sizeof(File) * header.files);
X close(dbdfile);
X
X for( i=0; i < header.files; i++ ) /* Now remove all files */
X unlink(file[i].name);
X
X ty_unlock();
X RETURN S_OKAY;
X }
X
X /*---------- Destroy current database ----------------------------------*/
X for( i=0; i<DB->header.files; i++ )
X {
X ty_closefile(DB->fh + i); /* Close all database files */
X unlink(DB->file[i].name); /* and remove them */
X }
X
X FREE(DB->dbd);
X
X _db->clients = 0;
X CURR_DB = -1;
X CURR_REC = 0;
X
X ty_unlock();
X RETURN S_OKAY;
X}
X
X/* end-of-file */
END_OF_FILE
if test 13441 -ne `wc -c <'typhoon/src/ty_open.c'`; then
echo shar: \"'typhoon/src/ty_open.c'\" unpacked with wrong size!
fi
# end of 'typhoon/src/ty_open.c'
fi
if test -f 'typhoon/src/util/backup.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'typhoon/src/util/backup.c'\"
else
echo shar: Extracting \"'typhoon/src/util/backup.c'\" \(12068 characters\)
sed "s/^X//" >'typhoon/src/util/backup.c' <<'END_OF_FILE'
X/*----------------------------------------------------------------------------
X * File : backup.c
X * Program : tybackup
X * OS : UNIX, OS/2, DOS
X * Author : Thomas B. Pedersen
X *
X * Copyright (c) 1994 Thomas B. Pedersen. All rights reserved.
X *
X * Permission is hereby granted, without written agreement and without
X * license or royalty fees, to use, copy, modify, and distribute this
X * software and its documentation for any purpose, provided that the above
X * copyright notice and the following two paragraphs appear (1) in all
X * source copies of this software and (2) in accompanying documentation
X * wherever the programatic interface of this software, or any derivative
X * of it, is described.
X *
X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN
X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
X * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
X *
X * Description:
X * Contains the tybackup utility.
X *
X * Functions:
X *
X * $Log: backup.c,v $
X * Revision 1.2 1994/09/17 16:00:49 tbp
X * typhoon.h and environ.h are now included from <>.
X *
X * Revision 1.1 1994/09/13 21:28:50 tbp
X * Added to repository.
X *
X * Added to repository.
X *
X *
X *--------------------------------------------------------------------------*/
X
Xstatic char rcsid[] = "$Id: backup.c,v 1.2 1994/09/17 16:00:49 tbp Exp $";
X
X#include <sys/types.h>
X#include <sys/ipc.h>
X#include <sys/shm.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <fcntl.h>
X#include <time.h>
X#include <setjmp.h>
X#include <errno.h>
X#include <assert.h>
X#include <signal.h>
X#include <typhoon.h>
X#include "../ty_dbd.h"
X#include "../ty_type.h"
X#include "../ty_glob.h"
X#include "../ty_prot.h"
X#include "../ty_log.h"
X#include "util.h"
X
X/*------------------------------- Constants --------------------------------*/
X#define VERSION "1.00"
X#define BLOCK_SIZE 512
X#define OUTBUF_SIZE (BLOCK_SIZE * 512)
X#define INBUF_SIZE (64 * 1024)
X
X/*-------------------------- Function prototypes ---------------------------*/
Xstatic void SignalHandler PRM( (int); )
Xstatic void Write PRM( (void *, ulong); )
Xstatic void Flush PRM( (void); )
Xstatic void DisplayProgress PRM( (char *, ulong); )
Xstatic void BackupDatabase PRM( (void); )
Xstatic void BackupFile PRM( (char *); )
Xstatic void help PRM( (void); )
X
X/*---------------------------- Global variables ----------------------------*/
Xstatic ArchiveMediaHeader mediahd; /* Archive media header */
Xstatic jmp_buf err_jmpbuf; /* Jumped to on error */
Xstatic Dbentry dbd; /* DBD anchor */
Xstatic int verbose = 0; /* Be verbose? */
Xstatic int archive_fh = -1; /* Archive file handle */
Xstatic char *dbname = ""; /* Database name */
Xstatic char *datapath = ""; /* Path for database files */
Xstatic char *device = "/dev/null"; /* Backup device */
Xstatic char *outbuf; /* Output buffer */
Xstatic ulong outbytes; /* Number of bytes in outbuf */
Xstatic ulong total_written = 0; /* Total number of bytes written */
X int db_status; /* Required by ../read_dbd.c */
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : SignalHandler
X *
X * Purpose :
X *
X * Parameters:
X *
X * Returns :
X *
X */
Xstatic void SignalHandler(sig)
Xint sig;
X{
X if( sig == SIGSEGV )
X puts("Segmentation violation");
X else if( sig == SIGBUS )
X puts("Bus error");
X
X dbd.shm->backup_active = 0;
X shm_free(&dbd);
X unlink(LOG_FNAME);
X puts("Restore aborted.");
X exit(1);
X}
X
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : Write
X *
X * Purpose : Write a block of data to the archive. If data cannot be
X * written because the backup media is full, the user will
X * be prompted to insert a new media.
X *
X * Parameters: buf - Buffer to write.
X * size - Number of bytes in buffer.
X *
X * Returns : Nothing.
X *
X */
Xstatic void Write(buf, size)
Xvoid *buf;
Xulong size;
X{
X ArchiveBlockHeader blockhd;
X char s[20];
X ulong copymax;
X long rc;
X
X /* Copy as much as possible to the output buffer */
X copymax = size;
X if( copymax > OUTBUF_SIZE-outbytes )
X copymax = OUTBUF_SIZE-outbytes;
X
X memcpy(outbuf+outbytes, buf, copymax);
X outbytes += copymax;
X
Xretry:
X while( archive_fh == -1 )
X {
X clock_off();
X printf("Insert backup media no %d [enter, q]", mediahd.seqno);
X fflush(stdout);
X gets(s);
X clock_on();
X
X if( s[0] == 'q' )
X return;
X
X if( (archive_fh = open(device, O_WRONLY)) == -1 )
X printf("Cannot open '%s' (errno %d)\n", device, errno);
X }
X
X if( outbytes == OUTBUF_SIZE )
X {
X rc = write(archive_fh, outbuf, OUTBUF_SIZE);
X
X if( rc == -1 )
X {
X printf("Write error (errno %d)\n", errno);
X longjmp(err_jmpbuf, 1);
X }
X else if( rc != OUTBUF_SIZE )
X {
X close(archive_fh);
X goto retry;
X }
X
X /* Now copy the rest of the buffer */
X outbytes = size - copymax;
X memcpy(outbuf, (char *)buf + copymax, outbytes);
X
X total_written += rc;
X }
X}
X
X
Xstatic void Flush()
X{
X long rc;
X
X /* Ensure that a complete block is written to archive */
X outbytes += (BLOCK_SIZE - (outbytes % BLOCK_SIZE));
X
X if( (rc = write(archive_fh, outbuf, outbytes)) != outbytes )
X {
X printf("Write error (errno %d, rc %ld)\n", errno, rc);
X longjmp(err_jmpbuf, 1);
X }
X
X total_written += rc;
X outbytes = 0;
X}
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : DisplayProgress
X *
X * Purpose : Prints the number of bytes read so far from the current table.
X *
X * Parameters: table - Table name.
X * bytes - Number of bytes read.
X *
X * Returns : Nothing.
X *
X */
Xstatic void DisplayProgress(table, bytes)
Xchar *table;
Xulong bytes;
X{
X printf("\rReading %-26.26s %10s bytes", table, printlong(bytes));
X fflush(stdout);
X}
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : BackupDatabase
X *
X * Purpose : Controls the backup.
X *
X * Parameters: None.
X *
X * Returns : Nothing.
X *
X */
Xstatic void BackupDatabase()
X{
X ArchiveRecordHeader recordhd;
X ArchiveTableHeader tablehd;
X Record *rec;
X ulong recid; /* Record ID of current table */
X ulong recno; /* Current record in current table */
X ulong recsize; /* Record size in current table */
X ulong bytecount; /* Number of bytes read in current table*/
X ulong numread; /* Number of bytes read */
X ulong timeout;
X int fh;
X int maxread, i, rc;
X char fname[128], objname[128];
X char buf[INBUF_SIZE];
X RECORD filehd;
X
X dbd.shm->backup_active = 1;
X
X for( rec=dbd.record, recid=0; recid<dbd.header.records; recid++, rec++ )
X {
X dbd.shm->curr_recid = recid;
X
X sprintf(fname, "%s/%s", datapath, dbd.file[rec->fileid].name);
X sprintf(objname, "table %s", rec->name);
X
X if( (fh = os_open(fname, O_RDONLY|O_BINARY, 0)) == -1 )
X {
X printf("Cannot open '%s'\n", fname);
X return;
X }
X
X /* Because of referential integrity data, the record size may
X * be different from rec->size, so we read the header for H.recsize.
X */
X read(fh, &filehd.H, sizeof filehd.H);
X
X recsize = filehd.H.recsize;
X maxread = INBUF_SIZE / recsize;
X bytecount = 0;
X recno = 0;
X
X /* Write table header */
X strcpy(tablehd.fname, dbd.file[rec->fileid].name);
X strcpy(tablehd.table, rec->name);
X tablehd.id = ARCHIVE_TABLE;
X tablehd.recsize = recsize;
X Write(&tablehd, sizeof tablehd);
X
X if( verbose )
X DisplayProgress(objname, 0);
X
X do
X {
X for( i=0; i<maxread; i++ )
X {
X dbd.shm->curr_recno = recno;
X
X lseek(fh, recno * recsize, SEEK_SET);
X numread = read(fh, buf, recsize);
X
X if( numread != recsize )
X break;
X
X recordhd.id = ARCHIVE_RECORD;
X recordhd.recid = recid;
X recordhd.recno = recno;
X
X Write(&recordhd, sizeof recordhd);
X Write(buf, numread);
X
X bytecount += recsize;
X recno++;
X }
X
X if( verbose )
X DisplayProgress(objname, bytecount);
X }
X while( i == maxread );
X
X if( verbose )
X puts("");
X
X close(fh);
X }
X
X /* Set curr_recid to max value, so that all changes are logged */
X dbd.shm->curr_recid = 0xffffffff;
X dbd.shm->backup_active = 0;
X
X /* Wait for last transaction to complete */
X timeout = 120;
X while( dbd.shm->num_trans_active > 0 && timeout-- )
X sleep(1);
X}
X
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : BackupFile
X *
X * Purpose : Write a sequential file to archive.
X *
X * Parameters: fname - File name.
X *
X * Returns : Nothing.
X *
X */
Xstatic void BackupFile(fname)
Xchar *fname;
X{
X ArchiveFileHeader filehd;
X ArchiveFileDataHeader datahd;
X int fh;
X char buf[INBUF_SIZE];
X ulong numread;
X ulong bytecount=0;
X
X if( (fh = open(fname, O_RDONLY)) == -1 )
X {
X printf("Cannot open '%s'\n", fname);
X return;
X }
X
X datahd.id = ARCHIVE_FILEDATA;
X filehd.id = ARCHIVE_FILE;
X strcpy(filehd.fname, fname);
X Write(&filehd, sizeof filehd);
X
X while( numread = read(fh, buf, INBUF_SIZE) )
X {
X datahd.size = numread;
X Write(&datahd, sizeof datahd);
X Write(buf, numread);
X
X bytecount += numread;
X
X if( verbose )
X DisplayProgress(fname, bytecount);
X }
X
X datahd.size = 0;
X Write(&datahd, sizeof datahd);
X
X if( verbose )
X puts("");
X
X close(fh);
X}
X
X
X
X
Xstatic void help()
X{
X puts("Syntax: tybackup database [option]...\n"
X "Options:\n"
X " -d<device> Backup device\n"
X " -f<path> Path for data files\n"
X " -v Be verbose\n");
X exit(1);
X}
X
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X ArchiveEnd end;
X char dbdname[20];
X int i;
X
X /* The output buffer MUST be bigger than the input buffer */
X assert(INBUF_SIZE < OUTBUF_SIZE);
X
X printf("Typhoon Online Backup version %s\n", VERSION);
X
X if( argc < 3 )
X help();
X
X for( i=2; i<argc; i++ )
X {
X switch( *argv[i] )
X {
X case '-':
X case '/':
X switch( argv[i][1] )
X {
X case 'd':
X device = argv[i]+2;
X break;
X case 'f':
X datapath = argv[i]+2;
X break;
X case 'v':
X verbose = 1;
X break;
X default:
X printf("Invalid option '%c'\n", argv[i][1]);
X break;
X }
X break;
X default:
X printf("Invalid switch '%c'\n", *argv[i]);
X exit(1);
X }
X }
X
X dbname = argv[1];
X sprintf(dbdname, "%s.dbd", dbname);
X if( read_dbdfile(&dbd, dbdname) != S_OKAY )
X {
X printf("Invalid dbd-file '%s'\n", dbdname);
X return;
X }
X
X if( !(outbuf = (char *)malloc(OUTBUF_SIZE)) )
X {
X puts("Cannot allocate output buffer");
X return;
X }
X outbytes = 0;
X
X strcpy(dbd.name, dbname);
X if( shm_alloc(&dbd) == -1 )
X {
X printf("Cannot allocate shared memory");
X return;
X }
X
X signal(SIGINT, SignalHandler);
X signal(SIGTERM, SignalHandler);
X signal(SIGQUIT, SignalHandler);
X signal(SIGSEGV, SignalHandler);
X signal(SIGBUS, SignalHandler);
X signal(SIGHUP, SIG_IGN);
X
X if( setjmp(err_jmpbuf) )
X {
X if( verbose )
X puts("Backup aborted.");
X goto out;
X }
X
X /* Initialize media header */
X memset(&mediahd, 0, sizeof mediahd);
X strcpy(mediahd.dbname, dbname);
X mediahd.id = ARCHIVE_MEDIA;
X mediahd.date = time(NULL);
X mediahd.seqno = 1;
X
X if( verbose )
X printf("Backing up to %s\n", device);
X
X Write(&mediahd, sizeof mediahd);
X
X BackupFile(dbdname);
X BackupDatabase();
X BackupFile(LOG_FNAME);
X
X end.id = ARCHIVE_END;
X Write(&end, sizeof end);
X Flush();
X close(archive_fh);
X clock_off();
X
X if( verbose )
X {
X ulong secs = clock_secs();
X
X /* Guard against division by zero */
X if( !secs )
X secs = 1;
X
X printf("\rTotal %40s bytes\n", printlong(total_written));
X printf("%s bytes/second\n", printlong(total_written / secs));
X puts("Done.");
X }
X
Xout:
X free(outbuf);
X shm_free(&dbd);
X free(dbd.dbd);
X
X unlink(LOG_FNAME);
X
X return 0;
X}
X
X/* end-of-file */
END_OF_FILE
if test 12068 -ne `wc -c <'typhoon/src/util/backup.c'`; then
echo shar: \"'typhoon/src/util/backup.c'\" unpacked with wrong size!
fi
# end of 'typhoon/src/util/backup.c'
fi
if test -f 'typhoon/src/util/import.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'typhoon/src/util/import.c'\"
else
echo shar: Extracting \"'typhoon/src/util/import.c'\" \(12523 characters\)
sed "s/^X//" >'typhoon/src/util/import.c' <<'END_OF_FILE'
X/*----------------------------------------------------------------------------
X * File : import.c
X * Program : tyimport
X * OS : UNIX, OS/2, DOS
X * Author : Thomas B. Pedersen
X *
X * Copyright (c) 1994 Thomas B. Pedersen. All rights reserved.
X *
X * Permission is hereby granted, without written agreement and without
X * license or royalty fees, to use, copy, modify, and distribute this
X * software and its documentation for any purpose, provided that the above
X * copyright notice and the following two paragraphs appear (1) in all
X * source copies of this software and (2) in accompanying documentation
X * wherever the programatic interface of this software, or any derivative
X * of it, is described.
X *
X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN
X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
X * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
X *
X * Description:
X * Typhoon import utility.
X *
X * $Log: import.c,v $
X * Revision 1.2 1994/09/17 16:00:55 tbp
X * typhoon.h and environ.h are now included from <>.
X *
X * Revision 1.1 1994/09/13 21:28:58 tbp
X * Added to repository.
X *
X * Added to repository.
X *
X *
X *--------------------------------------------------------------------------*/
X
Xstatic char rcsid[] = "$Id: import.c,v 1.2 1994/09/17 16:00:55 tbp Exp $";
X
X#include <stdio.h>
X#include <string.h>
X#include <ctype.h>
X#include <fcntl.h>
X#include <stdarg.h>
X#ifndef UNIX
X# include <sys\types.h>
X# include <sys\stat.h>
X# include <stdlib.h>
X# include <io.h>
X#endif
X#define DEFINE_GLOBALS
X#include <typhoon.h>
X#include "../ty_dbd.h"
X#include "../ty_type.h"
X#include "import.h"
X
X#define DEBUG(x)
X
X
X/*-------------------------------- prototypes ------------------------------*/
Xstatic int ReadValue PRM( (int); )
Xstatic int ReadString PRM( (void); )
Xstatic int ReadChar PRM( (void); )
Xstatic int ReadField PRM( (Field *, unsigned); )
Xstatic int GetControlField PRM( (Structdef *, unsigned); )
Xstatic int ReadFields PRM( (Structdef *, int, unsigned, int); )
Xstatic void Import PRM( (char *); )
X int yyparse PRM( (void); )
Xstatic void import_error PRM( (char * ELLIPSIS); )
X
X/*------------------------------ public variables --------------------------*/
X FILE *lex_file;
Xstatic FILE *infile;
Xstatic char *recbuf;
Xstatic char *fldptr;
Xstatic int fldtype;
Xstatic int lineno;
Xstatic char import_fname[256];
X
X/*------------------------------ local variables ---------------------------*/
Xstatic char paramhelp[] = "\
XSyntax: tyimport [option]... database[.dbd]\n\
XOptions:\n\
X -f<path> Specify data files path\n\
X -g Generate import specification\n";
X
X
X
Xistrcmp(s1, s2)
Xchar *s1, *s2;
X{
X while( tolower(*s1) == tolower(*s2) && *s1 && *s2 )
X s1++, s2++;
X
X return tolower(*s1) - tolower(*s2);
X}
X
X
X#ifdef PROTOTYPES
Xvoid err_quit(char *s, ...)
X#else
Xvoid err_quit(s)
Xchar *s;
X#endif
X{
X va_list ap;
X
X va_start(ap, s);
X vfprintf(stderr, s, ap);
X puts("");
X va_end(ap);
X exit(1);
X}
X
X
X#ifdef PROTOTYPES
Xvoid import_error(char *fmt, ...)
X#else
Xvoid import_error(fmt ELLIPSIS)
Xchar *fmt;
X#endif
X{
X va_list ap;
X
X printf("%s %d: ", import_fname, lineno);
X va_start(ap, fmt);
X vprintf(fmt, ap);
X puts("");
X va_end(ap);
X errors++;
X}
X
X
X
X/* Floats not supported!!! */
X
Xstatic ReadValue(c)
Xint c;
X{
X /* Integer formats: 002 (octal) 0x29 (hex) 231 (decimal) */
X ulong value;
X int negate = 0;
X
X if( c == '-' )
X {
X negate = 1;
X c = getc(infile);
X }
X
X if( c == '0' )
X {
X value = 0;
X
X c = getc(infile);
X
X if( c == 'x' )
X {
X while( (c = getc(infile)) && isxdigit(c) )
X {
X if( isdigit(c) )
X value = value * 16 + c - '0';
X else
X value = value * 16 + 6 + tolower(c) - 'a';
X }
X ungetc(c, infile);
X }
X else if( isdigit(c) )
X {
X do
X {
X value = value * 8 + c - '0';
X c = getc(infile);
X }
X while( isdigit(c) );
X ungetc(c, infile);
X }
X else
X ungetc(c, infile);
X }
X else
X {
X value = c - '0';
X
X c = getc(infile);
X
X while( isdigit(c) )
X {
X value = value * 10 + c - '0';
X c = getc(infile);
X }
X
X/*
X do
X {
X value = value * 10 + c - '0';
X c = getc(infile);
X }
X while( isdigit(c) );*/
X ungetc(c, infile);
X }
X
X if( fldtype & FT_UNSIGNED )
X {
X switch( fldtype )
X {
X case FT_UNSIGNED|FT_CHAR: *(uchar *)fldptr = value; break;
X case FT_UNSIGNED|FT_SHORT: *(ushort *)fldptr = value; break;
X case FT_UNSIGNED|FT_INT: *(unsigned *)fldptr = value; break;
X case FT_UNSIGNED|FT_LONG: *(ulong *)fldptr = value; break;
X }
X
X DEBUG( printf("%lu \n", (ulong)value); )
X }
X else
X {
X long svalue = negate ? -value : value;
X
X switch( fldtype )
X {
X case FT_CHAR: *(char *)fldptr = svalue; break;
X case FT_SHORT: *(short *)fldptr = svalue; break;
X case FT_INT: *(int *)fldptr = svalue; break;
X case FT_LONG: *(long *)fldptr = svalue; break;
X case FT_FLOAT:
X case FT_DOUBLE: puts("floats not supported"); exit(1);
X }
X
X DEBUG( printf("%ld \n", (long)value); )
X }
X
X return 0;
X}
X
X
X
X/* check for max length */
X
Xstatic ReadString()
X{
X char *p = fldptr;
X int c;
X
X while( (*p = getc(infile)) != '"' )
X {
X if( *p == '\\' )
X {
X switch( c = getc(infile) )
X {
X case 'n': /* Newline */
X *p = '\n';
X break;
X case '\\': /* Backslash */
X *p = '\\';
X break;
X case '\"': /* Double-quote */
X *p = '"';
X break;
X case 'x': /* Hexadecimal number */
X case 'X':
X c = getc(infile);
X if( isxdigit(c) )
X {
X *p = isalpha(c) ? tolower(c) - 'a' + 10 : c - '0';
X c = getc(infile);
X if( isxdigit(c) )
X {
X *p <<= 4;
X *p += isalpha(c) ? tolower(c) - 'a' + 10 : c - '0';
X }
X else
X ungetc(c, infile);
X }
X/* *p = 0;
X c = getc(infile);
X
X while( isxdigit(c) )
X {
X if( isdigit(c) )
X *p = *p * 16 + c - '0';
X else
X *p = *p * 16 + 10 + tolower(c) - 'a';
X c = getc(infile);
X }
X
X ungetc(c, infile);*/
X break;
X default:
X import_error("illegal character '%c' following '\\'", c);
X break;
X }
X }
X
X p++;
X }
X *p = 0;
X
X DEBUG( printf("\"%s\"\n", fldptr); )
X
X return 0;
X}
X
X
Xstatic ReadChar()
X{
X int c = getc(infile);
X int value, tmp;
X
X if( c == '\\' )
X {
X switch( tmp = getc(infile) )
X {
X case 'n': value = '\n'; break;
X case 'r': value = '\r'; break;
X case 't': value = '\t'; break;
X case '\"':
X case '\\':
X case '\'': value = tmp; break;
X case 'x':
X c = getc(infile);
X value = 0;
X
X while( isxdigit(c) )
X {
X if( isdigit(c) )
X value = value * 16 + c - '0';
X else
X value = value * 16 + 10 + tolower(c) - 'a';
X c = getc(infile);
X }
X
X ungetc(c, infile);
X break;
X default:
X import_error("invalid character constant");
X return -1;
X }
X }
X else
X value = c;
X
X if( getc(infile) != '\'' )
X import_error("unterminated character constant");
X
X switch( FT_GETBASIC(fldtype) )
X {
X case FT_CHAR: *(char *)fldptr = value; break;
X case FT_INT: *(int *)fldptr = value; break;
X case FT_SHORT: *(short *)fldptr = value; break;
X case FT_LONG: *(long *)fldptr = value; break;
X }
X
X DEBUG( printf("'%c'\n", value); )
X
X return 0;
X}
X
X
Xstatic ReadField(fld, offset)
XField *fld;
Xunsigned offset;
X{
X int c;
X
X fldptr = recbuf + offset;
X fldtype = FT_GETBASIC(fld->type);
X
X for( ;; )
X {
X c = getc(infile);
X
X if( c == ' ' || c == '\t' || c == '{' || c == '}' || c == ',' )
X ;
X else if( isdigit(c) || c == '-' )
X return ReadValue(c);
X else if( c == '"' )
X return ReadString();
X else if( c == '\'' )
X return ReadChar();
X else if( c == '\n' )
X lineno++;
X else if( c == '/' )
X {
X if( (c = getc(infile)) == '*' ) /* C comment */
X lex_skip_comment();
X else if( c == '/' ) /* C++ comment */
X {
X while( getc(infile) != '\n' && !feof(infile) )
X ;
X lineno++;
X }
X else
X import_error("unexpected '/'\n");
X }
X else if( c == EOF )
X return -1;
X else
X import_error("unexpected '%c'\n", c);
X }
X}
X
X
X
Xstatic GetControlField(str, offset)
XStructdef *str;
Xunsigned offset;
X{
X return recbuf[offset + dbd.field[str->control_field].offset];
X}
X
X
X
Xstatic ReadFields(str, nest, offset, control_value)
XStructdef *str;
Xint nest;
Xunsigned offset;
X{
X Field *fld = dbd.field + str->first_member;
X int fields = str->members;
X int old_fields = fields;
X int i, n, rc;
X
X if( str->is_union )
X fld += control_value;
X
X while( fields-- )
X {
X if( fld->size != fld->elemsize && FT_GETBASIC(fld->type) != FT_CHARSTR )
X {
X if( fld->type & FT_VARIABLE )
X n = *(ushort *)(recbuf + dbd.field[ fld->keyid ].offset);
X else
X n = fld->size / fld->elemsize;
X }
X else
X n = 1;
X
X for( i=0; i<n; i++ )
X {
X if( FT_GETBASIC(fld->type) == FT_STRUCT )
X {
X Structdef *struc = dbd.structdef + fld->structid;
X
X rc = ReadFields(struc, nest+1,
X offset + fld->offset + i * fld->elemsize,
X struc->is_union ? GetControlField(struc, offset) : 0);
X }
X else if( fld->nesting == nest && fld->type & FT_INCLUDE )
X {
X DEBUG( printf("%s = ", fld->name); )
X
X if( ReadField(fld, offset + fld->offset + fld->elemsize * i) == -1 )
X return -1;
X }
X }
X
X /* If n was 0 this array was a variable length array of size 0.
X * Move fld to the next field at the same nesting.
X */
X if( n == 0 )
X {
X rc = 0;
X
X if( !fields )
X break;
X
X do
X rc++;
X while( fld[rc].nesting != fld->nesting );
X rc--;
X }
X
X if( FT_GETBASIC(fld->type) == FT_STRUCT )
X {
X old_fields += rc;
X fld += rc;
X }
X
X fld++;
X
X if( str->is_union )
X break;
X }
X
X return old_fields;
X}
X
X
Xstatic void ImportTable(recid)
Xulong recid;
X{
X Record *rec = &dbd.record[recid];
X ulong count=0;
X
X recid = INTERN_TO_RECID(recid);
X
X memset(recbuf, 0, rec->size);
X
X while( ReadFields(&dbd.structdef[rec->structid], 0, 0, 0) != -1 )
X {
X if( d_fillnew(recid, recbuf) != S_OKAY )
X printf("d_fillnew: db_status %d, db_subcode %d\n",
X db_status, db_subcode);
X memset(recbuf, 0, rec->size);
X
XDEBUG( puts(""); )
X }
X}
X
X
Xstatic void Import(dbname)
Xchar *dbname;
X{
X int i;
X
X if( d_open(dbname, "s") != S_OKAY )
X err_quit("Cannot open database '%s'", dbname);
X
X for( i=0; i<dbd.header.records; i++ )
X {
X if( dbd.record[i].aux )
X {
X lineno = 1;
X sprintf(import_fname, "%s.kom", dbd.record[i].name);
X
X if( !(infile = fopen(import_fname, "r")) )
X err_quit("Cannot open '%s'", import_fname);
X
X printf("importing from '%s'\n", import_fname);
X ImportTable(i);
X fclose(infile);
X }
X }
X
X d_close();
X}
X
X
X
Xmain(argc, argv)
Xchar *argv[];
X{
X char *p, *realname;
X int i;
X long n=0, prev;
X unsigned biggest_rec=0;
X
X puts("Typhoon Import Utility version 1.06");
X
X if( argc == 1 )
X {
X printf(paramhelp);
X exit(1);
X }
X
X /* Imtract the real name of the file */
X if( (realname = strrchr(argv[argc-1], DIR_SWITCH)) != NULL )
X realname++;
X else
X realname = argv[argc-1];
X
X /* remove extension if present */
X if( p = strstr(realname, ".") )
X *p = 0;
X
X /* generate file names for .ddl-file, .dbd-file and header file */
X sprintf(dbd_fname, "%s.dbd", realname);
X sprintf(spec_fname, "%s.imp", realname);
X
X if( read_dbdfile(&dbd, dbd_fname) != S_OKAY )
X err_quit("Cannot open '%s'\n", dbd_fname);
X
X /* Find the size of the biggest record */
X for( i=0; i<dbd.header.records; i++ )
X if( biggest_rec < dbd.record[i].size )
X biggest_rec = dbd.record[i].size;
X
X /* Allocate record buffer */
X if( !(recbuf = (char *)malloc(biggest_rec)) )
X err_quit("Out of memory");
X
X /* process command line options */
X for( i=1; i<argc-1; i++ )
X {
X if( argv[i][0] == '-' || argv[i][0] == '/' )
X {
X switch( argv[i][1] )
X {
X case 'f':
X if( d_dbfpath(argv[i]+2) != S_OKAY )
X err_quit("Invalid data files path");
X break;
X case 'g':
X GenerateImportSpec(realname);
X exit(1);
X default:
X err_quit("unknown command line option");
X }
X }
X else
X err_quit("unknown command line option");
X }
X
X /* Read the import specification */
X ReadImportSpec(realname);
X
X if( !errors )
X Import(realname);
X
X free(dbd.dbd);
X free(recbuf);
X}
X
X
X/* end-of-file */
END_OF_FILE
if test 12523 -ne `wc -c <'typhoon/src/util/import.c'`; then
echo shar: \"'typhoon/src/util/import.c'\" unpacked with wrong size!
fi
# end of 'typhoon/src/util/import.c'
fi
if test -f 'typhoon/src/util/restore.c' -a "${1}" != "-c" ; then
echo shar: Will not clobber existing file \"'typhoon/src/util/restore.c'\"
else
echo shar: Extracting \"'typhoon/src/util/restore.c'\" \(13959 characters\)
sed "s/^X//" >'typhoon/src/util/restore.c' <<'END_OF_FILE'
X/*----------------------------------------------------------------------------
X * File : restore.c
X * Program : tybackup
X * OS : UNIX, OS/2, DOS
X * Author : Thomas B. Pedersen
X *
X * Copyright (c) 1994 Thomas B. Pedersen. All rights reserved.
X *
X * Permission is hereby granted, without written agreement and without
X * license or royalty fees, to use, copy, modify, and distribute this
X * software and its documentation for any purpose, provided that the above
X * copyright notice and the following two paragraphs appear (1) in all
X * source copies of this software and (2) in accompanying documentation
X * wherever the programatic interface of this software, or any derivative
X * of it, is described.
X *
X * IN NO EVENT SHALL THOMAS B. PEDERSEN BE LIABLE TO ANY PARTY FOR DIRECT,
X * INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF
X * THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF HE HAS BEEN
X * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
X *
X * THOMAS B. PEDERSEN SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT
X * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
X * A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS"
X * BASIS, AND THOMAS B. PEDERSEN HAS NO OBLIGATION TO PROVIDE MAINTENANCE,
X * SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
X *
X * Description:
X * Contains the tyrestore utility.
X *
X * Functions:
X *
X * $Log: restore.c,v $
X * Revision 1.2 1994/09/17 16:00:56 tbp
X * typhoon.h and environ.h are now included from <>.
X *
X * Revision 1.1 1994/09/13 21:29:00 tbp
X * Added to repository.
X *
X * Added to repository.
X *
X *
X *--------------------------------------------------------------------------*/
X
Xstatic char rcsid[] = "$Id: restore.c,v 1.2 1994/09/17 16:00:56 tbp Exp $";
X
X#include <sys/types.h>
X#include <sys/ipc.h>
X#include <sys/shm.h>
X#include <stdio.h>
X#include <stdlib.h>
X#include <string.h>
X#include <fcntl.h>
X#include <time.h>
X#include <setjmp.h>
X#include <errno.h>
X#include <assert.h>
X#include <signal.h>
X#include <typhoon.h>
X#include "../ty_dbd.h"
X#include "../ty_type.h"
X#include "../ty_glob.h"
X#include "../ty_prot.h"
X#include "../ty_log.h"
X#include "util.h"
X
X/*------------------------------- Constants --------------------------------*/
X#define VERSION "1.00"
X#define BLOCK_SIZE 512
X#define OUTBUF_SIZE (BLOCK_SIZE * 128)
X#define INBUF_SIZE (256 * 1024)
X
X/*-------------------------- Function prototypes ---------------------------*/
Xstatic void SignalHandler PRM( (int); )
Xstatic void Read PRM( (void *, ulong); )
Xstatic void DisplayProgress PRM( (char *, ulong); )
Xstatic void RestoreDatabase PRM( (void); )
Xstatic void RestoreFile PRM( (char *); )
Xstatic void RestoreDbdFile PRM( (void); )
Xstatic void RestoreLogFile PRM( (void); )
Xstatic void help PRM( (void); )
X void FixLog PRM( (char *); )
X
X/*---------------------------- Global variables ----------------------------*/
Xstatic ArchiveMediaHeader mediahd; /* Archive media header */
Xstatic Dbentry dbd; /* DBD anchor */
Xstatic int archive_fh = -1; /* Archive file handle */
Xstatic char dbname[DBNAME_LEN+1]; /* Database name */
Xstatic char *device = "/dev/null"; /* Archive device */
Xstatic ulong curr_id; /* Current block header id */
Xstatic char *inbuf; /* Input buffer */
Xstatic ulong inreadpos; /* Current read position in buffer */
Xstatic ulong inbytes; /* Number of bytes in outbuf */
Xstatic ulong total_read = 0; /* Total number of bytes read */
X jmp_buf err_jmpbuf; /* Jumped to on error */
X char *datapath = ""; /* Database file path */
X int db_status; /* Required by ../read_dbd.c */
X int verbose = 0; /* Be verbose? */
X
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : SignalHandler
X *
X * Purpose :
X *
X * Parameters:
X *
X * Returns :
X *
X */
Xstatic void SignalHandler(sig)
Xint sig;
X{
X printf("signal %d\n", sig);
X
X if( sig == SIGSEGV )
X puts("Segmentation violation");
X else if( sig == SIGBUS )
X puts("Bus error");
X
X dbd.shm->restore_active = 0;
X shm_free(&dbd);
X d_close();
X unlink(LOG_FNAME);
X puts("Restore aborted.");
X exit(1);
X}
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : Read
X *
X * Purpose : Read x bytes from the archive. If the data is not entirely
X * in the buffer, the rest will read immediately. If the end
X * of the current media has been reached, the user is promted
X * for the next media.
X *
X * Parameters: buf - Buffer to write.
X * size - Number of bytes in buffer.
X *
X * Returns : Nothing.
X *
X */
Xstatic void Read(buf, size)
Xvoid *buf;
Xulong size;
X{
X char s[20];
X ulong copymax;
X long numread;
X
X
X/*printf("Read: size=%d, inbytes=%ld, inreadpos=%ld\n",
X size, inbytes, inreadpos);*/
X
X /* Copy as much as possible to the output buffer */
X if( inbytes > inreadpos )
X {
X copymax = size;
X if( copymax > inbytes-inreadpos )
X copymax = inbytes-inreadpos;
X
X memcpy(buf, inbuf+inreadpos, copymax);
X inreadpos += copymax;
X
X if( copymax == size )
X return;
X }
X else
X copymax = 0;
X
X while( archive_fh == -1 )
X {
X clock_off();
X printf("Insert backup media no %d [enter]", mediahd.seqno);
X fflush(stdout);
X gets(s);
X
X if( s[0] == 'q' )
X longjmp(err_jmpbuf, 2);
X
X clock_on();
X if( (archive_fh = open(device, O_RDONLY)) == -1 )
X printf("Cannot open '%s' (errno %d)\n", device, errno);
X }
X
X if( inreadpos == inbytes )
X {
X numread = read(archive_fh, inbuf, INBUF_SIZE);
X/*printf("size=%ld, read=%ld, copymax=%ld, inreadpos=%ld, inbytes=%ld\n",
X size, numread, copymax, inreadpos, inbytes);*/
X
X if( numread == -1 )
X {
X printf("Read error (errno %d)\n", errno);
X longjmp(err_jmpbuf, 1);
X }
X else if( numread != INBUF_SIZE )
X {
X /* The number of bytes read is less than requested. If the
X * Read request can be satisfied by the number of bytes actually
X * returned by read(), we assume that the end of the current
X * media has been reached.
X */
X if( numread + copymax < size )
X {
X printf("Read error (errno %d)\n", errno);
X longjmp(err_jmpbuf, 1);
X }
X
X mediahd.seqno++;
X close(archive_fh);
X archive_fh = -1;
X }
X
X /* Now copy the rest of the buffer */
X inbytes = numread;
X inreadpos = size - copymax;
X memcpy((char *)buf + copymax, inbuf, inreadpos);
X
X total_read += numread;
X
X/*printf("size=%ld, read=%ld, copymax=%ld, inreadpos=%ld, inbytes=%ld\n",
X size, numread, copymax, inreadpos, inbytes);*/
X }
X}
X
X
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : DisplayProgress
X *
X * Purpose : Prints the number of bytes read so far from the current table.
X *
X * Parameters: table - Table name.
X * bytes - Number of bytes read.
X *
X * Returns : Nothing.
X *
X */
Xstatic void DisplayProgress(table, bytes)
Xchar *table;
Xulong bytes;
X{
X printf("\rWriting %-26.26s %10s bytes", table, printlong(bytes));
X fflush(stdout);
X}
X
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : RestoreDatabase
X *
X * Purpose :
X *
X * Parameters: None.
X *
X * Returns : Nothing.
X *
X */
Xstatic void RestoreDatabase()
X{
X ArchiveTableHeader tablehd;
X ArchiveRecordHeader recordhd;
X ulong prev_bytecount;
X ulong bytecount;
X char outbuf[OUTBUF_SIZE];
X char fname[128];
X char objname[128];
X int fh;
X
X Read(&curr_id, sizeof curr_id);
X
X for( ;; )
X {
X if( curr_id != ARCHIVE_TABLE )
X break;
X
X Read(&tablehd.recsize, sizeof(tablehd) - sizeof(tablehd.id));
X
X sprintf(fname, "%s/%s", datapath, tablehd.fname);
X sprintf(objname, "table %s", tablehd.table);
X
X if( (fh = open(fname, O_WRONLY|O_TRUNC|O_CREAT|O_BINARY, CREATMASK)) == -1 )
X {
X printf("Cannot open file '%s'\n", fname);
X longjmp(err_jmpbuf, 1);
X }
X prev_bytecount = bytecount = 0;
X
X for( ;; )
X {
X Read(&curr_id, sizeof curr_id);
X
X if( curr_id != ARCHIVE_RECORD )
X break;
X
X Read(&recordhd.recid, sizeof(recordhd) - sizeof(recordhd.id));
X Read(outbuf, tablehd.recsize);
X
X lseek(fh, tablehd.recsize * recordhd.recno, SEEK_SET);
X write(fh, outbuf, tablehd.recsize);
X
X bytecount += tablehd.recsize;
X
X if( verbose && bytecount > prev_bytecount + 100000 )
X {
X prev_bytecount = bytecount;
X DisplayProgress(objname, bytecount);
X }
X }
X
X if( verbose )
X {
X DisplayProgress(objname, bytecount);
X puts("");
X }
X
X
X close(fh);
X }
X}
X
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : RestoreFile
X *
X * Purpose : Read a sequential file from archive.
X *
X * Parameters: fname - File name.
X *
X * Returns : Nothing.
X *
X */
Xstatic void RestoreFile(fname)
Xchar *fname;
X{
X ArchiveFileDataHeader datahd;
X int fh;
X char buf[OUTBUF_SIZE];
X ulong numread;
X ulong readmax;
X ulong bytecount=0;
X
X if( (fh = open(fname, O_WRONLY|O_TRUNC|O_CREAT, CREATMASK)) == -1 )
X {
X printf("Cannot open '%s'\n", fname);
X return;
X }
X
X for( ;; )
X {
X Read(&curr_id, sizeof curr_id);
X
X if( curr_id != ARCHIVE_FILEDATA )
X {
X printf("Unexpected header id %d in middle of file \n", curr_id);
X longjmp(err_jmpbuf, 1);
X }
X
X Read(&datahd.size, sizeof(datahd) - sizeof(datahd.size));
X
X if( !datahd.size ) /* End-of-file reached */
X break;
X
X while( datahd.size > 0 )
X {
X /* Determine number of bytes to read */
X readmax = sizeof buf;
X if( readmax > datahd.size )
X readmax = datahd.size;
X
X Read(buf, readmax);
X write(fh, buf, readmax);
X
X bytecount += readmax;
X
X if( verbose )
X DisplayProgress(fname, bytecount);
X
X datahd.size -= readmax;
X }
X }
X
X if( verbose )
X puts("");
X
X close(fh);
X}
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : RestoreDbdFile
X *
X * Purpose : Restores the dbd-file from the archive.
X *
X * Parameters: None.
X *
X * Returns : Nothing.
X *
X */
Xstatic void RestoreDbdFile()
X{
X ArchiveFileHeader filehd;
X
X /* Restore dbd-file */
X Read(&filehd, sizeof filehd);
X
X if( filehd.id != ARCHIVE_FILE )
X {
X printf("Unexpected header id %d\n", filehd.id);
X longjmp(err_jmpbuf, 1);
X }
X
X RestoreFile(filehd.fname);
X}
X
X
X/*--------------------------------------------------------------------------*\
X *
X * Function : RestoreLogFile
X *
X * Purpose : Restores the log file from the archive.
X *
X * Parameters: None.
X *
X * Returns : Nothing.
X *
X */
Xstatic void RestoreLogFile()
X{
X ArchiveFileHeader filehd;
X
X if( curr_id == ARCHIVE_END )
X return;
X
X /* Restore the database */
X if( curr_id != ARCHIVE_FILE )
X {
X printf("Unexpected header id %ld\n", curr_id);
X longjmp(err_jmpbuf, 1);
X }
X
X Read(filehd.fname, sizeof(filehd) - sizeof(filehd.id));
X
X RestoreFile(filehd.fname);
X}
X
X
X
Xstatic void VerboseFn(table, records, curr_rec)
Xchar *table;
Xulong records, curr_rec;
X{
X static int old_percent = 0;
X int percent = curr_rec * 100 / records;
X
X if( curr_rec == 0 )
X {
X printf("\nRebuilding %-32.32s 0%%", table);
X fflush(stdout);
X old_percent = 0;
X }
X else if( percent != old_percent )
X {
X printf("\b\b\b\b%3d%%", percent);
X fflush(stdout);
X old_percent = percent;
X }
X}
X
X
X
Xstatic void help()
X{
X puts("Syntax: tyrestore [option]...\n"
X "Options:\n"
X " -d<device> Backup device\n"
X " -f<path> Path for data files\n"
X " -v Be verbose\n");
X exit(1);
X}
X
X
X
Xmain(argc, argv)
Xint argc;
Xchar *argv[];
X{
X char dbdname[20];
X int i;
X struct tm *tm;
X
X /* The input buffer MUST be bigger than the output buffer */
X assert(OUTBUF_SIZE < INBUF_SIZE);
X
X printf("Typhoon Restore version %s\n", VERSION);
X
X if( argc < 2 )
X help();
X
X for( i=1; i<argc; i++ )
X {
X switch( *argv[i] )
X {
X case '-':
X case '/':
X switch( argv[i][1] )
X {
X case 'd':
X device = argv[i]+2;
X break;
X case 'f':
X datapath = argv[i]+2;
X break;
X case 'v':
X verbose = 1;
X break;
X default:
X printf("Invalid option '%c'\n", argv[i][1]);
X break;
X }
X break;
X default:
X printf("Invalid switch '%c'\n", *argv[i]);
X break;
X }
X }
X
X if( *datapath )
X {
X mkdir(datapath);
X chmod(datapath, 0777);
X }
X
X if( !(inbuf = (char *)malloc(INBUF_SIZE)) )
X {
X puts("Cannot allocate output buffer");
X return;
X }
X inbytes = 0;
X inreadpos = 0;
X
X if( setjmp(err_jmpbuf) )
X {
X if( verbose )
X puts("Restore aborted.");
X goto out;
X }
X
X if( verbose )
X printf("Restoring from %s\n", device);
X
X Read(&mediahd, sizeof mediahd);
X if( mediahd.id != ARCHIVE_MEDIA )
X {
X printf("Unexpected header id %d\n", mediahd.id);
X longjmp(err_jmpbuf, 1);
X }
X
X strcpy(dbd.name, mediahd.dbname);
X if( shm_alloc(&dbd) == -1 )
X {
X printf("Cannot allocate shared memory");
X return;
X }
X dbd.shm->restore_active = 1;
X
X signal(SIGINT, SignalHandler);
X signal(SIGTERM, SignalHandler);
X signal(SIGQUIT, SignalHandler);
X signal(SIGSEGV, SignalHandler);
X signal(SIGBUS, SignalHandler);
X signal(SIGHUP, SIG_IGN);
X
X if( dbd.shm->use_count > 1 )
X {
X puts("The database is currenly in use. Cannot restore");
X goto out;
X }
X
X /* Confirm restore */
X clock_off();
X tm = localtime(&mediahd.date);
X printf("Database '%s' from %s", mediahd.dbname, asctime(tm));
X printf("Restore? [y/n]: ");
X fflush(stdout);
X if( getchar() != 'y' )
X goto out;
X clock_on();
X
X RestoreDbdFile();
X RestoreDatabase();
X RestoreLogFile();
X clock_off();
X
X if( verbose )
X {
X ulong secs = clock_secs();
X
X /* Guard against division by zero */
X if( !secs )
X secs = 1;
X
X printf("\rTotal %40s bytes\n", printlong(total_read));
X printf("%s bytes/second\n", printlong(total_read / secs));
X }
X
X FixLog(mediahd.dbname);
X
X printf("Rebuilding index files");
X d_keybuild(VerboseFn);
X d_dbfpath(datapath);
X
X if( d_open(mediahd.dbname, "o") != S_OKAY )
X puts("Cannot open database");
X else
X {
X d_close();
X puts("");
X }
X
Xout:
X free(inbuf);
X dbd.shm->restore_active = 0;
X shm_free(&dbd);
X free(dbd.dbd);
X unlink(LOG_FNAME);
X
X return 0;
X}
X
X/* end-of-file */
END_OF_FILE
if test 13959 -ne `wc -c <'typhoon/src/util/restore.c'`; then
echo shar: \"'typhoon/src/util/restore.c'\" unpacked with wrong size!
fi
# end of 'typhoon/src/util/restore.c'
fi
echo shar: End of archive 2 \(of 9\).
cp /dev/null ark2isdone
MISSING=""
for I in 1 2 3 4 5 6 7 8 9 ; do
if test ! -f ark${I}isdone ; then
MISSING="${MISSING} ${I}"
fi
done
if test "${MISSING}" = "" ; then
echo You have unpacked all 9 archives.
rm -f ark[1-9]isdone ark[1-9][0-9]isdone
else
echo You still must unpack the following archives:
echo " " ${MISSING}
fi
exit 0
exit 0 # Just in case...