248 lines
7.2 KiB
C
248 lines
7.2 KiB
C
/*
|
|
Permission is hereby granted, free of charge, to any person obtaining a
|
|
copy of this software and associated documentation files (the "Software"), to
|
|
deal in the Software without restriction, including without limitation the
|
|
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
|
sell copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
|
|
Original Idea Copyright (c) 2006,2007 HPC2N, Umeå University, Sweden
|
|
Modifications Copyright (c) 2012-2013 by Deon George
|
|
*/
|
|
|
|
/* Enable Large File Support stuff */
|
|
#define _FILE_OFFSET_BITS 64
|
|
#define _LARGEFILE_SOURCE 1
|
|
#define _LARGE_FILES 1
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <limits.h>
|
|
|
|
#include "dsmrc.h"
|
|
#include "dsmapitd.h"
|
|
#include "dsmapifp.h"
|
|
|
|
extern dsUint32_t tsm_initsess(char *options);
|
|
extern void tsm_sessioninfo(dsUint32_t dsmHandle);
|
|
extern int tsm_listfile(dsUint32_t dsmHandle, char *fsname, char *filename, char *description, dsmSendType sendtype, char verbose, char *pitdate);
|
|
extern int tsm_sendfile(dsUint32_t dsmHandle, char *fsname, char *filename, long long length, char *description, dsmSendType sendtype, char verbose);
|
|
extern int tsm_restorefile(dsUint32_t dsmHandle, char *fsname, char *filename, char *description, dsmSendType sendtype, char verbose, char *pitdate);
|
|
extern int tsm_deletefile(dsUint32_t dsmHandle, char *fsname, char *filename, char *description, dsmSendType sendtype, char verbose);
|
|
|
|
int copy_env(const char *from, const char *to) {
|
|
char *e;
|
|
char n[PATH_MAX+1];
|
|
|
|
e = getenv(from);
|
|
if (!e) {
|
|
fprintf(stderr,"tsmpipe: Environment variable %s not set\n",from);
|
|
return 0;
|
|
}
|
|
|
|
n[PATH_MAX] = '\0';
|
|
snprintf(n, PATH_MAX, "%s=%s", to, e);
|
|
|
|
if (putenv(strdup(n))) {
|
|
perror("tsmpipe: Setting up environment");
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
void usage(void) {
|
|
fprintf(stderr,
|
|
"tsmpipe $Revision: 1.5-dg $, usage:\n"
|
|
"\n"
|
|
"tsmpipe [-i] [-A|-B] [-c|-x|-d|-t] -s fsname -f filepath [-l len]\n"
|
|
" -i Show session information:\n"
|
|
" -A and -B are mutually exclusive:\n"
|
|
" -A Use Archive objects\n"
|
|
" -B Use Backup objects\n"
|
|
" -c, -x, -d and -t are mutually exclusive:\n"
|
|
" -c Create: Read from stdin and store in TSM\n"
|
|
" -x eXtract: Recall from TSM and write to stdout\n"
|
|
" -d Delete: Delete object from TSM\n"
|
|
" -t lisT: Print filelist to stdout\n"
|
|
" -s and -f are required arguments for (-A/ -B operations):\n"
|
|
" -s fsname Name of filesystem in TSM\n"
|
|
" -f filepath Path to file within filesystem in TSM\n"
|
|
" -l length Length of object to store. If guesstimating too large\n"
|
|
" is better than too small\n"
|
|
" -D desc Description of archive object\n"
|
|
" -P pitdate PITDate (mmddYYYY) (BACKUP Objects)\n"
|
|
" -O options Extra options to pass to dsmInitEx\n"
|
|
" -v Verbose. More -v's gives more verbosity\n"
|
|
);
|
|
|
|
exit(1);
|
|
}
|
|
|
|
int main(int argc, char *argv[]) {
|
|
int c;
|
|
extern int optopt;
|
|
extern char *optarg;
|
|
char archive=0, backup=0, create=0, xtract=0, delete=0, verbose=0, info=0, list=0;
|
|
char *space=NULL, *filename=NULL, *lenstr=NULL, *desc=NULL, *pitdate=NULL, *options=NULL;
|
|
off_t length;
|
|
dsUint32_t dsmHandle;
|
|
dsmSendType sendtype;
|
|
|
|
while ((c = getopt(argc, argv, "hiABcxdtvs:f:l:D:O:P:")) != -1) {
|
|
switch(c) {
|
|
case 'h': usage(); break;
|
|
case 'i': info = 1; break;
|
|
case 'A': archive = 1; break;
|
|
case 'B': backup = 1; break;
|
|
case 'c': create = 1; break;
|
|
case 'x': xtract = 1; break;
|
|
case 'd': delete = 1; break;
|
|
case 't': list = 1; break;
|
|
case 'v': verbose++; break;
|
|
case 's': space = optarg; break;
|
|
case 'f': filename = optarg; break;
|
|
case 'l': lenstr = optarg; break;
|
|
case 'D': desc = optarg; break;
|
|
case 'O': options = optarg; break;
|
|
case 'P': pitdate = optarg; break;
|
|
|
|
case ':':
|
|
fprintf(stderr, "tsmpipe: Option -%c requires an operand\n", optopt);
|
|
exit(1);
|
|
case '?':
|
|
fprintf(stderr, "tsmpipe: Unrecognized option: -%c\n", optopt);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
if (archive+backup+info != 1) {
|
|
fprintf(stderr, "tsmpipe: ERROR: Must give one of -i, -A or -B\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (pitdate && ! backup) {
|
|
fprintf(stderr, "tsmpipe: ERROR: -P can only be used with -A\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (! info) {
|
|
if (create+xtract+delete+list != 1) {
|
|
fprintf(stderr, "tsmpipe: ERROR: Must give one of -c, -x, -d or -t\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (! space) {
|
|
fprintf(stderr, "tsmpipe: ERROR: Must give -s filespacename\n");
|
|
exit(1);
|
|
}
|
|
|
|
if (! filename) {
|
|
fprintf(stderr, "tsmpipe: ERROR: Must give -f filename\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(create && ! lenstr) {
|
|
fprintf(stderr, "tsmpipe: ERROR: Must give -l length with -c\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(! create && lenstr) {
|
|
fprintf(stderr, "tsmpipe: ERROR: -l length useless without -c\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(! archive && desc) {
|
|
fprintf(stderr, "tsmpipe: ERROR: -D desc useless without -A\n");
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
sendtype = archive ? stArchiveMountWait : stBackupMountWait;
|
|
|
|
/* Let the TSM api get the signals */
|
|
signal(SIGPIPE, SIG_IGN);
|
|
signal(SIGINT, SIG_IGN);
|
|
signal(SIGUSR1, SIG_IGN);
|
|
|
|
if (getenv("DSM_DIR") && ((! copy_env("DSM_DIR", "DSMI_DIR")) || (! copy_env("DSM_CONFIG", "DSMI_CONFIG")))) {
|
|
exit(1);
|
|
}
|
|
|
|
// OK, we are ready to talk to TSM
|
|
dsmHandle = tsm_initsess(options);
|
|
if (! dsmHandle) {
|
|
exit(2);
|
|
}
|
|
|
|
if (verbose > 1)
|
|
fprintf(stderr, "tsmpipe: Session initiated\n");
|
|
|
|
// Show our session information
|
|
if (info) {
|
|
tsm_sessioninfo(dsmHandle);
|
|
}
|
|
|
|
// If we are backing up
|
|
if (create) {
|
|
length = atof(lenstr);
|
|
if (length <= 0) {
|
|
fprintf(stderr,"tsmpipe: ERROR: Provide positive length, overestimate if guessing");
|
|
exit(1);
|
|
}
|
|
|
|
if (! tsm_sendfile(dsmHandle,space,filename,length,desc,sendtype,verbose)){
|
|
dsmTerminate(dsmHandle);
|
|
exit(3);
|
|
}
|
|
}
|
|
|
|
// Delete an object from TSM
|
|
if (delete) {
|
|
// @todo Delete Archives by date range.
|
|
if (! tsm_deletefile(dsmHandle,space,filename,desc,sendtype,verbose)) {
|
|
dsmTerminate(dsmHandle);
|
|
exit(3);
|
|
}
|
|
}
|
|
|
|
// Restore from TSM
|
|
if(xtract) {
|
|
// @todo Query Archives by date range.
|
|
if (! tsm_restorefile(dsmHandle,space,filename,desc,sendtype,verbose,(sendtype == stBackupMountWait ? pitdate : NULL))) {
|
|
dsmTerminate(dsmHandle);
|
|
exit(3);
|
|
}
|
|
}
|
|
|
|
// List objects in TSM
|
|
if (list) {
|
|
// @todo Query Archives by date range.
|
|
if (! tsm_listfile(dsmHandle,space,filename,desc,sendtype,verbose,(sendtype == stBackupMountWait ? pitdate : NULL))) {
|
|
dsmTerminate(dsmHandle);
|
|
exit(3);
|
|
}
|
|
}
|
|
|
|
dsmTerminate(dsmHandle);
|
|
|
|
if (verbose > 0)
|
|
fprintf(stderr, "tsmpipe: Success\n");
|
|
|
|
return 0;
|
|
}
|