blob: b01b9164bf346db3abf75e873338191aaff8d713 [file] [log] [blame]
/*
* 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 <stdlib.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;
}