| /* |
| * Copyright (c) 2000-2002 Silicon Graphics, Inc. |
| * All Rights Reserved. |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation. |
| * |
| * This program is distributed in the hope that it would be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
| */ |
| |
| #include <stdio.h> |
| #include <unistd.h> |
| #include <sys/stat.h> |
| #include <time.h> |
| #include <assert.h> |
| #include <string.h> |
| #include <uuid/uuid.h> |
| |
| #include "config.h" |
| |
| #include "types.h" |
| #include "mlog.h" |
| #include "dlog.h" |
| #include "path.h" |
| #include "getopt.h" |
| #include "global.h" |
| #include "drive.h" |
| |
| /* drive.c - selects and initializes a drive strategy |
| */ |
| |
| |
| /* structure definitions used locally ****************************************/ |
| |
| |
| /* declarations of externally defined global symbols *************************/ |
| |
| extern void usage( void ); |
| extern char *homedir; |
| |
| /* declare all drive strategies here |
| */ |
| extern drive_strategy_t drive_strategy_simple; |
| extern drive_strategy_t drive_strategy_scsitape; |
| extern drive_strategy_t drive_strategy_rmt; |
| |
| |
| /* forward declarations of locally defined static functions ******************/ |
| |
| static drive_t *drive_alloc( char *, size_t ); |
| static void drive_allochdrs( drive_t *drivep, |
| global_hdr_t *gwhdrtemplatep, |
| ix_t driveix ); |
| |
| |
| /* definition of locally defined global variables ****************************/ |
| |
| drive_t **drivepp; |
| size_t drivecnt; |
| size_t partialmax; |
| |
| /* definition of locally defined static variables *****************************/ |
| |
| /* drive strategy array - ordered by precedence |
| */ |
| static drive_strategy_t *strategypp[] = { |
| &drive_strategy_simple, |
| &drive_strategy_scsitape, |
| &drive_strategy_rmt, |
| }; |
| |
| |
| /* definition of locally defined global functions ****************************/ |
| |
| /* drive_init1 - select and instantiate a drive manager for each drive |
| * specified on the command line. |
| */ |
| bool_t |
| drive_init1( int argc, char *argv[ ] ) |
| { |
| int c; |
| ix_t driveix; |
| |
| /* sanity check asserts |
| */ |
| assert( sizeof( drive_hdr_t ) == DRIVE_HDR_SZ ); |
| |
| /* count drive arguments |
| */ |
| optind = 1; |
| opterr = 0; |
| drivecnt = 0; |
| while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { |
| switch ( c ) { |
| case GETOPT_DUMPDEST: |
| drivecnt++; |
| break; |
| } |
| } |
| |
| /* allocate an array to hold ptrs to drive descriptors |
| */ |
| if (drivecnt > 0) { |
| drivepp = ( drive_t ** )calloc( drivecnt, sizeof( drive_t * )); |
| assert( drivepp ); |
| } |
| |
| /* initialize the partialmax value. Each drive can be completing a file |
| * started in another drive (except for drive 0) and leave one file to |
| * be completed by another drive. This value is used to limit the |
| * search in the list of partially completed files shared between all |
| * restore streams. Note, if drivecnt is one, then partialmax is zero |
| * to indicate no partial files can span streams. |
| */ |
| partialmax = (drivecnt <= 1 ? 0 : (drivecnt * 2) - 1); |
| |
| /* initialize drive descriptors from command line arguments |
| */ |
| optind = 1; |
| opterr = 0; |
| driveix = 0; |
| while ( ( c = getopt( argc, argv, GETOPT_CMDSTRING )) != EOF ) { |
| switch ( c ) { |
| case GETOPT_DUMPDEST: |
| if ( ! optarg || optarg[ 0 ] == '-' ) { |
| mlog( MLOG_NORMAL, |
| _("-%c argument missing\n"), |
| c ); |
| usage( ); |
| return BOOL_FALSE; |
| } |
| |
| /* allocate a drive descriptor |
| */ |
| drivepp[ driveix ] = drive_alloc( optarg, driveix ); |
| driveix++; |
| break; |
| } |
| } |
| assert( driveix == drivecnt ); |
| |
| /* the user may specify stdin as the source, by |
| * a single dash ('-') with no option letter. This must appear |
| * between all lettered arguments and the file system pathname. |
| */ |
| if ( optind < argc && ! strcmp( argv[ optind ], "-" )) { |
| if ( driveix > 0 ) { |
| mlog( MLOG_NORMAL, |
| #ifdef DUMP |
| _("cannot specify source files and stdout together\n") |
| #endif /* DUMP */ |
| #ifdef RESTORE |
| _("cannot specify source files and stdin together\n") |
| #endif /* RESTORE */ |
| ); |
| usage( ); |
| return BOOL_FALSE; |
| } |
| |
| drivecnt = 1; |
| |
| /* Adding this alloc to fix malloc corruption. |
| * Bug #393618 - prasadb 04/16/97 |
| * allocate an array to hold ptrs to drive descriptors |
| */ |
| drivepp = ( drive_t ** )calloc( drivecnt, sizeof( drive_t * )); |
| assert( drivepp ); |
| |
| drivepp[ 0 ] = drive_alloc( "stdio", 0 ); |
| |
| #ifdef DUMP /* ifdef added around dlog_desist() by prasadb to fix 435626 */ |
| dlog_desist( ); |
| #endif |
| } |
| |
| /* verify that some dump destination(s) / restore source(s) specified |
| */ |
| if ( drivecnt == 0 ) { |
| mlog( MLOG_NORMAL | MLOG_ERROR, |
| #ifdef DUMP |
| _("no destination file(s) specified\n") |
| #endif /* DUMP */ |
| #ifdef RESTORE |
| _("no source file(s) specified\n") |
| #endif /* RESTORE */ |
| ); |
| usage( ); |
| return BOOL_FALSE; |
| } |
| |
| /* run each drive past each strategy, pick the best match |
| * and instantiate a drive manager. |
| */ |
| for ( driveix = 0 ; driveix < drivecnt ; driveix++ ) { |
| drive_t *drivep = drivepp[ driveix ]; |
| int bestscore = 0 - INTGENMAX; |
| ix_t six; |
| ix_t scnt = sizeof( strategypp ) / sizeof( strategypp[ 0 ] ); |
| drive_strategy_t *bestsp = 0; |
| bool_t ok; |
| |
| for ( six = 0 ; six < scnt ; six++ ) { |
| drive_strategy_t *sp = strategypp[ six ]; |
| int score; |
| score = ( * sp->ds_match )( argc, |
| argv, |
| drivep ); |
| if ( ! bestsp || score > bestscore ) { |
| bestsp = sp; |
| bestscore = score; |
| } |
| } |
| assert( bestsp ); |
| drivep->d_strategyp = bestsp; |
| drivep->d_recmarksep = bestsp->ds_recmarksep; |
| drivep->d_recmfilesz = bestsp->ds_recmfilesz; |
| mlog( MLOG_VERBOSE, |
| _("using %s strategy\n"), |
| bestsp->ds_description ); |
| ok = ( * bestsp->ds_instantiate )( argc, |
| argv, |
| drivep ); |
| if ( ! ok ) { |
| return BOOL_FALSE; |
| } |
| } |
| |
| return BOOL_TRUE; |
| } |
| |
| |
| /* drive_init2 - second phase strategy initialization. |
| * allocates global read and write hdrs, copying global hdr template |
| * into the write hdrs (DUMP only). kicks off async init for each drive, |
| * which will be synchronized with drive_init3. |
| */ |
| /* ARGSUSED */ |
| bool_t |
| drive_init2( int argc, |
| char *argv[ ], |
| global_hdr_t *gwhdrtemplatep ) |
| { |
| ix_t driveix; |
| |
| for ( driveix = 0 ; driveix < drivecnt ; driveix++ ) { |
| drive_t *drivep = drivepp[ driveix ]; |
| bool_t ok; |
| |
| drive_allochdrs( drivep, gwhdrtemplatep, driveix ); |
| ok = ( * drivep->d_opsp->do_init )( drivep ); |
| if ( ! ok ) { |
| return BOOL_FALSE; |
| } |
| } |
| |
| return BOOL_TRUE; |
| } |
| |
| |
| /* drive_init3 - third phase strategy initialization. |
| * synchronizes with async operations begun by drive_init2. |
| */ |
| bool_t |
| drive_init3( void ) |
| { |
| ix_t driveix; |
| |
| for ( driveix = 0 ; driveix < drivecnt ; driveix++ ) { |
| drive_t *drivep = drivepp[ driveix ]; |
| bool_t ok; |
| |
| ok = ( * drivep->d_opsp->do_sync )( drivep ); |
| if ( ! ok ) { |
| return BOOL_FALSE; |
| } |
| } |
| |
| return BOOL_TRUE; |
| } |
| |
| |
| /* drive_mark_commit - commits and unlinks all accumulated marks with |
| * offsets less than or equal to the offset of the next (as yet unwritten) |
| * byte in the media file. |
| * utility function for use by drive-specific strategies. |
| */ |
| void |
| drive_mark_commit( drive_t *drivep, off64_t ncommitted ) |
| { |
| drive_markrec_t *dmp; |
| |
| for ( dmp = drivep->d_markrecheadp |
| ; |
| dmp && dmp->dm_log <= ( drive_mark_t )ncommitted |
| ; |
| ) { |
| drivep->d_markrecheadp = dmp->dm_nextp; |
| ( * dmp->dm_cbfuncp )( dmp->dm_cbcontextp, dmp, BOOL_TRUE ); |
| dmp = drivep->d_markrecheadp; |
| } |
| } |
| |
| /* drive_mark_discard - unlinks all accumulated marks, calling their callbacks |
| * indicating the mark was NOT committed. |
| * utility function for use by drive-specific strategies. |
| */ |
| void |
| drive_mark_discard( drive_t *drivep ) |
| { |
| drive_markrec_t *dmp; |
| |
| for ( dmp = drivep->d_markrecheadp |
| ; |
| dmp |
| ; |
| drivep->d_markrecheadp = dmp->dm_nextp, dmp = dmp->dm_nextp ) { |
| |
| ( * dmp->dm_cbfuncp )( dmp->dm_cbcontextp, dmp, BOOL_FALSE ); |
| } |
| } |
| |
| /* drive_display_metrics - called by main thread during interactive dialog |
| * to print drive throughput and streaming metrics. |
| */ |
| void |
| drive_display_metrics( void ) |
| { |
| ix_t driveix; |
| |
| for ( driveix = 0 ; driveix < drivecnt ; driveix++ ) { |
| drive_t *drivep = drivepp[ driveix ]; |
| drive_ops_t *dop = drivep->d_opsp; |
| if ( dop->do_display_metrics ) { |
| ( * dop->do_display_metrics )( drivep ); |
| } |
| } |
| } |
| |
| |
| /* definition of locally defined static functions ****************************/ |
| |
| /* drive_alloc - allocate and initialize the generic portions of a drive |
| * descriptor. do NOT allocate hdr buffers. |
| */ |
| static drive_t * |
| drive_alloc( char *pathname, ix_t driveix ) |
| { |
| drive_t *drivep; |
| struct stat64 statbuf; |
| |
| /* allocate the descriptor |
| */ |
| drivep = ( drive_t * )calloc( 1, sizeof( drive_t )); |
| assert( drivep ); |
| |
| /* convert the pathname to an absolute pathname |
| * NOTE: string "stdio" is reserved to mean send to standard out |
| */ |
| if ( strcmp( pathname, "stdio" )) { |
| pathname = path_reltoabs( pathname, homedir ); |
| } |
| |
| /* set pipe flags |
| */ |
| if ( ! strcmp( pathname, "stdio" )) { |
| drivep->d_isunnamedpipepr = BOOL_TRUE; |
| } else if ( ! stat64( pathname, &statbuf ) |
| && |
| ( statbuf.st_mode & S_IFMT ) == S_IFIFO ) { |
| drivep->d_isnamedpipepr = BOOL_TRUE; |
| } |
| |
| /* complete the drive manager |
| */ |
| drivep->d_pathname = pathname; |
| drivep->d_index = driveix; |
| |
| return drivep; |
| } |
| |
| /* drive_allochdrs - allocate and initialize the drive read and write |
| * hdrs, and ptrs into the hdrs. |
| */ |
| static void |
| drive_allochdrs( drive_t *drivep, global_hdr_t *gwhdrtemplatep, ix_t driveix ) |
| { |
| global_hdr_t *grhdrp; |
| drive_hdr_t *drhdrp; |
| global_hdr_t *gwhdrp; |
| drive_hdr_t *dwhdrp; |
| |
| /* allocate the read header |
| */ |
| grhdrp = ( global_hdr_t * )calloc( 1, sizeof( global_hdr_t )); |
| assert( grhdrp ); |
| gwhdrp = NULL; |
| dwhdrp = NULL; |
| |
| /* calculate pointer to the drive portion of the read header |
| */ |
| drhdrp = ( drive_hdr_t * )grhdrp->gh_upper; |
| |
| /* global write hdr used only for dumps. will be NULL for restore |
| */ |
| if ( gwhdrtemplatep ) { |
| /* allocate the write header |
| */ |
| gwhdrp = ( global_hdr_t * )calloc( 1, sizeof( global_hdr_t )); |
| assert( gwhdrp ); |
| |
| /* copy the template |
| */ |
| *gwhdrp = *gwhdrtemplatep; |
| |
| /* calculate pointer to the drive portion of the read header |
| */ |
| dwhdrp = ( drive_hdr_t * )gwhdrp->gh_upper; |
| |
| /* fill in generic drive fields of write hdr |
| */ |
| dwhdrp->dh_strategyid = drivep->d_strategyp->ds_id; |
| dwhdrp->dh_driveix = driveix; |
| dwhdrp->dh_drivecnt = drivecnt; |
| } |
| |
| /* complete the drive manager |
| */ |
| drivep->d_greadhdrp = grhdrp; |
| drivep->d_readhdrp = drhdrp; |
| drivep->d_gwritehdrp = gwhdrp; |
| drivep->d_writehdrp = dwhdrp; |
| } |