HP OpenVMS Systemsask the wizard |
The Question is: I was wondering if you could tell me how I might program a "purge" program that will give the option to purge all files or give the options to purge a certain file and keep certain version numbers(for a VAX system.) The Answer is :
Use of the existing PURGE command is the easiest approach, either
directly, via lib$spawn, via C system, via DECnet task-to-task, via
sys$sndjbc, or otherwise.
API-level program implementations are possible using lib$find_file,
lib$delete_file, and lib$find_file_end, or via RMS service calls
such as sys$search and sys$erase/sys$remove, or via XQP (F11XQP,
IO$_ACPCONTROL) calls (as described in the I/O User's Reference Manual).
The following C example shows a directory tree-deletion operation using
calls such as lib$find_file -- this example assumes that the getopt()
call is available.
--
/*
** COPYRIGHT (c) 1994-1999 BY
** DIGITAL EQUIPMENT CORPORATION, MAYNARD, MASSACHUSETTS.
** ALL RIGHTS RESERVED.
**
** THIS SOFTWARE IS FURNISHED UNDER A LICENSE AND MAY BE USED AND COPIED
** ONLY IN ACCORDANCE OF THE TERMS OF SUCH LICENSE AND WITH THE
** INCLUSION OF THE ABOVE COPYRIGHT NOTICE. THIS SOFTWARE OR ANY OTHER
** COPIES THEREOF MAY NOT BE PROVIDED OR OTHERWISE MADE AVAILABLE TO ANY
** OTHER PERSON. NO TITLE TO AND OWNERSHIP OF THE SOFTWARE IS HEREBY
** TRANSFERRED.
**
** THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE
** AND SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT
** CORPORATION.
**
** DIGITAL ASSUMES NO RESPONSIBILITY FOR THE USE OR RELIABILITY OF ITS
** SOFTWARE ON EQUIPMENT WHICH IS NOT SUPPLIED BY DIGITAL.
**
*/
/*
**++
** Facility:
**
** DELETE_TREE
**
** Version: V1.0
**
** Abstract:
**
** Deletes the specified directory tree.
**
** Author:
** Steve Hoffman
**
** Creation Date: 14-Mar-1994
**
** Modification History:
**--
*/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <ssdef.h>
#include <stsdef.h>
#include <str$routines.h>
#include <lib$routines.h>
#include <descrip.h>
#include <strdef.h>
#include <starlet.h>
#include <rms.h>
#include <fiddef.h>
#include <string.h>
#include <unistd.h>
typedef unsigned long int u_long;
typedef unsigned short int u_short;
typedef char u_char;
typedef struct dsc$descriptor desc_t;
/*
** ************************************************************************
** common definitions
** ************************************************************************
*/
typedef u_short fid_t[(FID$K_LENGTH/sizeof(u_short))];
typedef struct itemlist_s itemlist_t;
struct itemlist_s
{
/*
** A standard VMS itemlist `il3' data structure...
*/
u_short itmlen;
u_short itmcod;
u_char *itmadr;
u_short *itmrla;
};
typedef struct hdr_s hdr_t;
struct hdr_s
{
/*
** The common header; prefixes all heap-allocated internal
** data structures... Used by a couple of routines -- mostly
** in the area of memory management and corruption detection.
*/
u_short size;
u_short type;
void *core;
};
typedef struct dir_s dir_t;
struct dir_s
{
/*
** A standard VMS itemlist `il3' data structure...
*/
hdr_t hdr;
dir_t *nextdir;
u_short depth;
char fna[NAM$C_MAXRSS+1];
u_long fnl;
};
typedef struct core_s core_t;
struct core_s
{
/*
** This is the core data structure for this application...
*/
hdr_t hdr;
char fns;
char fna[NAM$C_MAXRSS+1];
char dns;
char dna[NAM$C_MAXRSS+1];
char esa[NAM$C_MAXRSS+1];
char rsa[NAM$C_MAXRSS+1];
desc_t userinput_d;
struct
{
char *target_dirspec;
u_long verbose;
u_long quit;
u_long confirm;
u_long noconfirm;
u_long errors;
} options;
u_short iosb[4];
u_long context;
fid_t didx_old;
dir_t *nextdir;
struct FAB fab;
struct NAM nam;
struct RAB rab;
};
/*
** ************************************************************************
** The externals; used by and required for getopt();
** ************************************************************************
*/
extern char *optarg;
extern int optind;
extern int opterr;
/*
** ************************************************************************
** The function prototypes...
** ************************************************************************
*/
u_long dt_parse_opt( core_t *, u_long, u_char ** );
u_long getopt( u_long, u_char **, u_char * );
u_long dt_file_scan( core_t * );
u_long dt_file_scan_ok( struct FAB * );
u_long dt_file_scan_ng( struct FAB * );
u_long dt_delete_confirm( desc_t *, struct FAB *, core_t * );
u_long dt_load_name( core_t *, char *, char * );
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** parses the user-specified options via a getopt().
**
** FORMAL PARAMETERS:
**
** {@subtags@}
**
** RETURN VALUE:
**
** 1: happiness
**
** SIDE EFFECTS:
**
** none
**
** DESIGN:
**
** This routine is highly UNIX-flavoured. This routine
** handles all argument parsing and processing. The key
** (and only) interface used by this routine to communicate
** with the rest of the program is the `options' substructure
** found within the core data structure.
**
**
**--
*/
u_long dt_parse_opt( core_t *core, u_long argc, u_char **argv )
{
u_long retstat;
u_long c;
u_long asciw;
u_char *validargs = (u_char *) "vcdf:";
u_long got_an_option = 0;
while ((c = getopt( argc, argv, validargs )) != EOF)
{
got_an_option++;
switch ( c )
{
case 'f':
/*
** Start processing at the specified file...
*/
asciw = strlen( (char *) optarg);
if ( asciw <= NAM$C_MAXRSS )
{
retstat = dt_load_name( core, optarg, 0 );
if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat;
}
break;
case 'd':
/*
** Start processing at the specified default file...
*/
asciw = strlen( (char *) optarg);
if ( asciw <= NAM$C_MAXRSS )
{
retstat = dt_load_name( core, 0, optarg );
if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat;
}
break;
case 'v':
/*
** The typical verbose (chatty) option...
*/
core->options.verbose++;
break;
case 'c':
/*
** Confirm the deletion.
*/
core->options.confirm++;
break;
case '?':
default:
core->options.errors++;
}
}
if ( !got_an_option )
core->options.errors++;
if ( core->options.errors )
{
fprintf (stderr,
"RMS directory tree deletion utility.\n" );
fprintf (stderr,
"Set up foreign command: dt :== $%s\n", argv[0]);
fprintf (stderr,
"usage: dt [-v] [-c] -f filespec [-d defspec]\n" );
fprintf (stderr, " -v\tverbose\n" );
fprintf (stderr, " -c\tconfirm\n" );
fprintf (stderr, " -f\tfile or directory tree to delete\n" );
fprintf (stderr, " -d\tdefault file specification\n" );
exit( SS$_NORMAL );
}
return 1;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This initializes some fields in the core structure.
**
** FORMAL PARAMETERS:
**
** a pointer to the core structure.
**
** RETURN VALUE:
**
** SS$_NORMAL: happiness
**
** SIDE EFFECTS:
**
** none.
**
** DESIGN:
**
**--
*/
dt_init( core_t *core )
{
unsigned long int retstat;
struct FAB *fab;
struct NAM *nam;
memset( core, 0, sizeof( core_t ) );
core->userinput_d.dsc$a_pointer = 0;
core->userinput_d.dsc$w_length = 0;
core->userinput_d.dsc$b_class = DSC$K_CLASS_D;
core->userinput_d.dsc$b_dtype = DSC$K_DTYPE_T;
core->dns = 0;
core->dna[0] = 0;
core->context = 0;
core->nextdir = 0;
memset( core->didx_old, 0, FID$K_LENGTH );
core->options.confirm = 0;
core->options.errors = 0;
fab = &core->fab;
nam = &core->nam;
core->fab = cc$rms_fab;
core->nam = cc$rms_nam;
fab->fab$l_fop = FAB$M_NAM;
fab->fab$b_fac = 0;
fab->fab$b_shr = 0;
fab->fab$l_nam = nam;
fab->fab$w_ifi = 0;
fab->fab$l_fna = 0;
fab->fab$b_fns = 0;
fab->fab$l_dna = 0;
fab->fab$b_dns = 0;
fab->fab$l_ctx = (u_long) core;
nam->nam$l_esa = core->esa;
nam->nam$b_ess = NAM$C_MAXRSS;
nam->nam$b_esl = 0;
nam->nam$l_rsa = core->rsa;
nam->nam$b_rss = NAM$C_MAXRSS;
nam->nam$b_rsl = 0;
return SS$_NORMAL;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This stuffs the directory specification or the default
** directory specification into the storage buffer.
**
** FORMAL PARAMETERS:
**
** the core, the file name, and the default file name.
**
** RETURN VALUE:
**
** SS$_NORMAL: happiness
**
** SIDE EFFECTS:
**
** none.
**
** DESIGN:
**
**--
*/
u_long dt_load_name( core_t *core, char *filename, char *defname )
{
unsigned long int retstat;
struct FAB *fab;
struct NAM *nam;
fab = &core->fab;
nam = &core->nam;
if ( (int) filename )
{
core->fns = strlen( filename );
strncpy( core->fna, filename, NAM$C_MAXRSS );
fab->fab$l_fna = core->fna;
fab->fab$b_fns = core->fns;
}
if ( (int) defname )
{
core->dns = strlen( defname );
strncpy( core->dna, defname, NAM$C_MAXRSS );
fab->fab$l_dna = core->dna;
fab->fab$b_dns = strlen( defname );
}
return SS$_NORMAL;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This scans for files, looking for the directories to be deleted.
**
** FORMAL PARAMETERS:
**
** the standard C main function arguments...
**
** RETURN VALUE:
**
** 1: happiness
**
** SIDE EFFECTS:
**
** none.
**
** DESIGN:
**
**--
*/
u_long dt_file_scan( core_t *core )
{
u_long retstat;
retstat = lib$file_scan( &core->fab,
dt_file_scan_ok, dt_file_scan_ng,
&core->context );
if ( retstat == RMS$_NMF ) retstat = SS$_NORMAL;
if ( retstat == RMS$_DNF ) retstat = SS$_NORMAL;
if ( retstat == RMS$_FNF ) retstat = SS$_NORMAL;
if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat;
return SS$_NORMAL;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This processes the specified file, and marks it for delete.
**
** FORMAL PARAMETERS:
**
** the standard C main function arguments...
**
** RETURN VALUE:
**
** 1: happiness
**
** SIDE EFFECTS:
**
** none.
**
** DESIGN:
**
**--
*/
u_long dt_file_scan_ok( struct FAB *fab )
{
u_long retstat;
char *wildcard = "*.*;*";
struct NAM *nam;
core_t *core;
fid_t fidx;
dir_t *dir;
u_long devdirsize;
nam = fab->fab$l_nam;
core = (core_t *) fab->fab$l_ctx;
retstat = memcmp( &core->didx_old, nam->nam$w_did, FID$K_LENGTH );
if ( retstat )
{
/*
** A new file. And the file is in a new directory file...
*/
dir = malloc( sizeof( dir_t ));
dir->nextdir = core->nextdir;
core->nextdir = dir;
devdirsize = 0;
memcpy( dir->fna + devdirsize, nam->nam$l_dev, nam->nam$b_dev );
devdirsize += nam->nam$b_dev;
memcpy( dir->fna + devdirsize, nam->nam$l_dir, nam->nam$b_dir );
devdirsize += nam->nam$b_dir;
memcpy( dir->fna + devdirsize, wildcard, strlen( wildcard ));
devdirsize += strlen( wildcard );
dir->fnl = devdirsize;
memcpy( &core->didx_old, nam->nam$w_did, FID$K_LENGTH );
}
return SS$_NORMAL;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This processes the specified file.
**
** FORMAL PARAMETERS:
**
** the standard C main function arguments...
**
** RETURN VALUE:
**
** 1: happiness
**
** SIDE EFFECTS:
**
** none.
**
** DESIGN:
**
**--
*/
u_long dt_file_scan_ng( struct FAB *fab )
{
u_long retstat;
struct NAM *nam;
nam = fab->fab$l_nam;
printf("Unable to process %*.*s\n",
nam->nam$b_rsl, nam->nam$b_rsl, nam->nam$l_rsa );
return SS$_NORMAL;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This scans for files, looking for the directories to be deleted.
**
** FORMAL PARAMETERS:
**
** the standard C main function arguments...
**
** RETURN VALUE:
**
** 1: happiness
**
** SIDE EFFECTS:
**
** none.
**
** DESIGN:
**
**--
*/
u_long dt_delete_confirm( desc_t *file_d, struct FAB *fab, core_t *core )
{
u_long retstat;
u_long delstat;
u_short nyaq_len;
char fao_b[NAM$C_MAXRSS];
desc_t fao_d;
$DESCRIPTOR( file_prompt, "Delete !AS?" );
$DESCRIPTOR( vnodelete, "Not deleting !AS" );
$DESCRIPTOR( faclete, "Deleting !AS" );
$DESCRIPTOR( nyaq_prompt, "Delete? (Y/N/Q/A) " );
delstat = SS$_NORMAL;
if ( core->options.quit )
{
/*
** Skip any sort of delete.
*/
delstat = SS$_NODELETE;
goto dt_delete_confirm_done;
}
if ( core->options.noconfirm )
{
/*
** We were asked to confirm each deletion, then countermanded.
*/
delstat = SS$_NORMAL;
goto dt_delete_confirm_done;
}
if ( core->options.confirm )
{
/*
** Confirm each deletion.
*/
delstat = SS$_NODELETE;
fao_d.dsc$a_pointer = fao_b;
fao_d.dsc$w_length = NAM$C_MAXRSS;
fao_d.dsc$b_class = DSC$K_CLASS_S;
fao_d.dsc$b_dtype = DSC$K_DTYPE_T;
retstat = sys$fao( &file_prompt,
&fao_d.dsc$w_length, &fao_d, file_d );
if ( !$VMS_STATUS_SUCCESS( retstat ) )
{
core->options.quit++;
delstat = SS$_NODELETE;
goto dt_delete_confirm_done;
}
lib$put_output( &fao_d );
retstat = lib$get_input( &core->userinput_d, &nyaq_prompt, &nyaq_len );
if ( !$VMS_STATUS_SUCCESS( retstat ) )
{
core->options.quit++;
delstat = SS$_NODELETE;
goto dt_delete_confirm_done;
}
str$upcase( &core->userinput_d, &core->userinput_d );
/*
** What the user answer means...
**
** YES causes the file to be deleted.
** TRUE causes the file to be deleted.
** ALL causes all files to be deleted.
** QUIT quits; no more files are deleted.
** FALSE the current deletion is not performed.
** NO the current deletion is not performed.
**
** Any other answer from the user is treated as a FALSE or a NO.
*/
retstat = strncmp( core->userinput_d.dsc$a_pointer, "YES", nyaq_len );
if ( !retstat )
delstat = SS$_NORMAL;
retstat = strncmp( core->userinput_d.dsc$a_pointer, "TRUE", nyaq_len );
if ( !retstat )
delstat = SS$_NORMAL;
retstat = strncmp( core->userinput_d.dsc$a_pointer, "QUIT", nyaq_len );
if ( !retstat )
core->options.quit++;
retstat = strncmp( core->userinput_d.dsc$a_pointer, "ALL", nyaq_len );
if ( !retstat )
delstat = core->options.noconfirm = SS$_NORMAL;
goto dt_delete_confirm_done;
}
dt_delete_confirm_done:
if ( core->options.verbose )
{
fao_d.dsc$a_pointer = fao_b;
fao_d.dsc$w_length = NAM$C_MAXRSS;
fao_d.dsc$b_class = DSC$K_CLASS_S;
fao_d.dsc$b_dtype = DSC$K_DTYPE_T;
if ( $VMS_STATUS_SUCCESS( delstat ) )
retstat = sys$fao( &faclete,
&fao_d.dsc$w_length, &fao_d, file_d );
else
retstat = sys$fao( &vnodelete,
&fao_d.dsc$w_length, &fao_d, file_d );
lib$put_output( &fao_d );
}
return delstat;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This scans for files, looking for the directories to be deleted.
**
** FORMAL PARAMETERS:
**
** the standard C main function arguments...
**
** RETURN VALUE:
**
** 1: happiness
**
** SIDE EFFECTS:
**
** none.
**
** DESIGN:
**
**--
*/
u_long dt_delete_all( core_t *core )
{
u_long retstat;
dir_t *dir;
dir_t *dir_old;
desc_t dsc;
dsc.dsc$b_dtype = DSC$K_DTYPE_T;
dsc.dsc$b_class = DSC$K_CLASS_S;
dir = core->nextdir;
while ((int) dir )
{
dsc.dsc$w_length = dir->fnl;
dsc.dsc$a_pointer = dir->fna;
retstat = lib$delete_file( &dsc, 0, 0,
0, 0, dt_delete_confirm,
core, 0, 0 );
if ( !$VMS_STATUS_SUCCESS( retstat ) )
break;
dir_old = dir;
dir = dir->nextdir;
free( dir_old );
}
return SS$_NORMAL;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This processes the specified file, and marks it for delete.
**
** FORMAL PARAMETERS:
**
** the standard C main function arguments...
**
** RETURN VALUE:
**
** 1: happiness
**
** SIDE EFFECTS:
**
** none.
**
** DESIGN:
**
**--
*/
dt_cleanup( core_t *core )
{
u_long retstat;
retstat = lib$file_scan_end( &core->fab, &core->context );
if ( !$VMS_STATUS_SUCCESS( retstat )) return retstat;
return SS$_NORMAL;
}
/*
**++
** FUNCTIONAL DESCRIPTION:
**
** This is the mainline of the program.
**
** FORMAL PARAMETERS:
**
** the standard C main function arguments...
**
** RETURN VALUE:
**
** 1: happiness
**
** SIDE EFFECTS:
**
** none.
**
** DESIGN:
**
**--
*/
main( u_long argc, u_char **argv )
{
u_long retstat;
core_t core_buffer, *core;
fid_t fid;
core = &core_buffer;
retstat = dt_init( core );
if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat;
retstat = dt_parse_opt( core, argc, argv );
if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat;
retstat = dt_file_scan( core );
if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat;
retstat = dt_delete_all( core );
if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat;
retstat = dt_cleanup( core );
if ( !$VMS_STATUS_SUCCESS( retstat ) ) return retstat;
return 1;
}
|