slave/ 40700 6031 0 0 6265216217 10655 5ustar delgadorootslave/config_file.c100444 6031 145 5643 6240131023 13730 0ustar delgadooraweb#include #include #include #include <../master/abs_msg.h> extern char master_server[256]; extern char master_princ[1024]; extern char slave_princ[1024]; extern char abs_admin_dir[PATH_MAX]; extern char log_dir[PATH_MAX]; extern char device_name[PATH_MAX]; extern char device_type[10]; extern int online; /* keep tapes on-line after use */ /* * Procedure: read_config_file * * Parameters: conf - address of configuration file name * int - reread - non-zero if this is a forced re-read of the file * * Description: This function reads the slave configuration file specified * by the parameters "conf" and modifies various variables in "globals.c" * to contain the value specified by the config file.. If "reread" is * 0, then all parameters specified in the config file are read and set. * Other wise only those variables which can be safely modified while * the slave is running are set. */ read_config_file(char *conf, int reread) { int rc, lines; char line[1024]; char param[128], data[PATH_MAX]; char buf[PATH_MAX+60]; FILE *fp; if ((fp = fopen(conf, "r")) == (FILE *) NULL){ sprintf(buf,"Cann't open config file %s", conf); slave_log_error(ABS_ERROR, "read_config_file", buf); return; } lines=0; while( fgets(line,1024,fp) != (char *) NULL){ lines++; errno=0; rc = sscanf(line,"%s : %s", param, data); if (rc != 2 ){ /* no items converted */ sprintf(buf,"format error in config file line %d\n",lines); slave_log_error(ABS_ERROR, "read_config_file", buf); continue; } if (!strcmp("master_server", param)){ strcpy(master_server, data, PATH_MAX); continue; } if (!strcmp("master_principal", param)){ strcpy(master_princ, data, 1024); continue; } if (!strcmp("slave_principal", param)){ strcpy(slave_princ, data, 1024); continue; } if (!strcmp("device_online", param)){ online = atoi(data); if (errno){ fprintf(stderr,"bad data at line %d\n", lines); return(errno); } continue; } /* * The remaining parameters cannot be changed while * the slave is running */ if (reread) continue; if (!strcmp("admin_dir", param)){ strncpy(abs_admin_dir, data, PATH_MAX); continue; } if (!strcmp("device_name", param)){ strncpy(device_name, data, PATH_MAX); continue; } if (!strcmp("device_type", param)){ strncpy(device_type, data, 10); continue; } fprintf(stderr,"Invalid parameter line %dn", lines); } fclose(fp); return(0); } slave/defs.h100400 6031 145 1454 6240131023 12376 0ustar delgadooraweb/* * Please do not edit this file. * It was generated using rpcgen. */ #ifndef _DEFS_H_RPCGEN #define _DEFS_H_RPCGEN #include #include #include #ifdef __cplusplus extern "C" { #endif struct abs_vol_header { int magic; int absvolid_low; int abs_volid_high; longlong_t size; char name[MEDIA_NAME_MAX]; char server[MEDIA_SERVER_MAX]; char device[MEDIA_DEVICE_MAX]; int fstype; int fs_volid1; int fs_volid2; char fs_private[128]; char reserved[32]; }; typedef struct abs_vol_header abs_vol_header; /* the xdr functions */ #if defined(__STDC__) || defined(__cplusplus) extern bool_t xdr_abs_vol_header(XDR *, abs_vol_header*); #else /* K&R C */ extern bool_t xdr_abs_vol_header(); #endif /* K&R C */ #ifdef __cplusplus } #endif #endif /* !_DEFS_H_RPCGEN */ slave/slave_dispatch.c100600 6031 145 13336 6263011715 14477 0ustar delgadooraweb/* * Please do not edit this file. * It was generated using rpcgen. */ #include "slave.h" #include #include /* getenv, exit */ #include /* for pmap_unset */ #include /* strcmp */ #include #ifdef __cplusplus #include /* getdtablesize, open */ #endif /* __cplusplus */ #include /* setsid */ #include #include #include #include #include /* rlimit */ #include #ifndef SIG_PF #define SIG_PF void(*)(int) #endif #ifdef DEBUG #define RPC_SVC_FG #endif #define _RPCSVC_CLOSEDOWN 120 #include static int _rpcpmstart; /* Started by a port monitor ? */ /* States a server can be in wrt request */ #define _IDLE 0 #define _SERVED 1 #define _SERVING 2 static int _rpcsvcstate = _IDLE; /* Set when a request is serviced */ mutex_t _svcstate_lock; /* Mutex lock for variable _rpcsvcstate */ static void _msgout(char* msg) { #ifdef RPC_SVC_FG if (_rpcpmstart) syslog(LOG_ERR, msg); else (void) fprintf(stderr, "%s\n", msg); #else syslog(LOG_ERR, msg); #endif } void closedown(int sig) { mutex_lock(&_svcstate_lock); if (_rpcsvcstate == _IDLE) { extern fd_set svc_fdset; static int size; int i, openfd; struct t_info tinfo; if (!t_getinfo(0, &tinfo) && (tinfo.servtype == T_CLTS)) exit(0); if (size == 0) { struct rlimit rl; rl.rlim_max = 0; getrlimit(RLIMIT_NOFILE, &rl); if ((size = rl.rlim_max) == 0) { mutex_unlock(&_svcstate_lock); return; } } for (i = 0, openfd = 0; i < size && openfd < 2; i++) if (FD_ISSET(i, &svc_fdset)) openfd++; if (openfd <= 1) exit(0); } if (_rpcsvcstate == _SERVED) _rpcsvcstate = _IDLE; mutex_unlock(&_svcstate_lock); (void) signal(SIGALRM, (SIG_PF) closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } int _abs_backup_1(abs_backup_1_argument *argp, void *result, struct svc_req *rqstp) { return (abs_backup_1_svc(argp->arg1, argp->arg2, argp->arg3, result, rqstp)); } int _abs_restore_1(abs_restore_1_argument *argp, void *result, struct svc_req *rqstp) { return (abs_restore_1_svc(argp->arg1, argp->arg2, argp->arg3, result, rqstp)); } int _abs_scan_1(abs_scan_1_argument *argp, void *result, struct svc_req *rqstp) { return (abs_scan_1_svc(argp->arg1, argp->arg2, result, rqstp)); } int _abs_label_media_1(abs_label_media_1_argument *argp, void *result, struct svc_req *rqstp) { return (abs_label_media_1_svc(argp->arg1, argp->arg2, argp->arg3, result, rqstp)); } int _abs_abort_job_1(abs_abort_job_1_argument *argp, void *result, struct svc_req *rqstp) { return (abs_abort_job_1_svc(argp->arg1, argp->arg2, result, rqstp)); } int _abs_shutdown_slave_1(void *argp, void *result, struct svc_req *rqstp) { return (abs_shutdown_slave_1_svc(result, rqstp)); } void absslave_1(struct svc_req *rqstp, register SVCXPRT *transp) { union { abs_backup_1_argument abs_backup_1_arg; abs_restore_1_argument abs_restore_1_arg; abs_scan_1_argument abs_scan_1_arg; abs_label_media_1_argument abs_label_media_1_arg; abs_abort_job_1_argument abs_abort_job_1_arg; } argument; union { int abs_backup_1_res; int abs_restore_1_res; int abs_scan_1_res; int abs_label_media_1_res; int abs_abort_job_1_res; int abs_shutdown_slave_1_res; } result; bool_t retval; xdrproc_t xdr_argument, xdr_result; bool_t (*local)(char *, void *, struct svc_req *); mutex_lock(&_svcstate_lock); _rpcsvcstate = _SERVING; mutex_unlock(&_svcstate_lock); switch (rqstp->rq_proc) { case NULLPROC: (void) svc_sendreply(transp, (xdrproc_t) xdr_void, (char *)NULL, rqstp); mutex_lock(&_svcstate_lock); _rpcsvcstate = _SERVED; mutex_unlock(&_svcstate_lock); return; case abs_backup: xdr_argument = (xdrproc_t) xdr_abs_backup_1_argument; xdr_result = (xdrproc_t) xdr_int; local = (bool_t (*) (char *, void *, struct svc_req *))_abs_backup_1; break; case abs_restore: xdr_argument = (xdrproc_t) xdr_abs_restore_1_argument; xdr_result = (xdrproc_t) xdr_int; local = (bool_t (*) (char *, void *, struct svc_req *))_abs_restore_1; break; case abs_scan: xdr_argument = (xdrproc_t) xdr_abs_scan_1_argument; xdr_result = (xdrproc_t) xdr_int; local = (bool_t (*) (char *, void *, struct svc_req *))_abs_scan_1; break; case abs_label_media: xdr_argument = (xdrproc_t) xdr_abs_label_media_1_argument; xdr_result = (xdrproc_t) xdr_int; local = (bool_t (*) (char *, void *, struct svc_req *))_abs_label_media_1; break; case abs_abort_job: xdr_argument = (xdrproc_t) xdr_abs_abort_job_1_argument; xdr_result = (xdrproc_t) xdr_int; local = (bool_t (*) (char *, void *, struct svc_req *))_abs_abort_job_1; break; case abs_shutdown_slave: xdr_argument = (xdrproc_t) xdr_void; xdr_result = (xdrproc_t) xdr_int; local = (bool_t (*) (char *, void *, struct svc_req *))_abs_shutdown_slave_1; break; default: svcerr_noproc(transp, rqstp); mutex_lock(&_svcstate_lock); _rpcsvcstate = _SERVED; mutex_unlock(&_svcstate_lock); return; } (void) memset((char *)&argument, 0, sizeof (argument)); if (!svc_getargs(transp, xdr_argument, (caddr_t) &argument)) { svcerr_decode(transp, rqstp); mutex_lock(&_svcstate_lock); _rpcsvcstate = _SERVED; mutex_unlock(&_svcstate_lock); return; } retval = (bool_t) (*local)((char *)&argument, (void *)&result, rqstp); if (retval > 0 && !svc_sendreply(transp, xdr_result, (char *)&result, rqstp)) { svcerr_systemerr(transp, rqstp); } if (!svc_freeargs(transp, xdr_argument, (caddr_t) &argument)) { _msgout("unable to free arguments"); exit(1); } if (!absslave_1_freeresult(transp, xdr_result, (caddr_t) &result)) _msgout("unable to free results"); mutex_lock(&_svcstate_lock); _rpcsvcstate = _SERVED; mutex_unlock(&_svcstate_lock); return; } slave/globals.c100444 6031 145 1302 6240131025 13075 0ustar delgadooraweb#include #include "private.h" char abs_admin_dir[PATH_MAX]="/var/abs/slave"; char log_dir[]="logs"; char device_name[PATH_MAX]=""; char device_type[10]=""; char config_file[PATH_MAX]=""; char master_server[256]=""; /* hostname of master server */ char master_princ[1024]="abs-master"; /* principal name for master server */ char slave_princ[1024] = "abs-slave"; /* slave principal name */ int online = 0; /* keep tapes on-line after use */ int slave_state=SLAVE_INIT; void set_slave_state(int state) { /* * should have locks for threads */ slave_state = state; } int get_slave_state() { /* * should have locks for threads */ return(slave_state); } slave/.sh_history100600 6031 0 144 6016147435 13126 0ustar delgadoroot. /u1/home/oracle/.profile env dbx /var/tmp/master dbx /var/tmp/master sqlplus fg exit slave/job_info.c100400 6031 145 11511 6240131025 13252 0ustar delgadooraweb#include #include #include #include #include #include "../master/abs_msg.h" #include "../master/os_defs.h" #include "private.h" #include "prototypes.h" #undef d_name #include static char _jobs_dir[PATH_MAX]; /* * Procedure: delete_job_info * * Parameters: jobid - jobid for job whose info is to be deleted. * * Description: this function removes the on-disk copy of the * job results information associated with "jobid". */ int delete_job_info(int jobid) { char name[PATH_MAX]; int code; sprintf(name,"%s/%d",get_jobs_dir(), jobid); code = unlink(name); return(code); } char * get_jobs_dir() { return(_jobs_dir); } int set_jobs_dir(char *name) { if (strlen(name) > PATH_MAX){ slave_log_error(ABS_FATAL,"set_jobs_dir", "Jobs directory name too long"); return(ABS_INVALID_SPEC); } strcpy(_jobs_dir, name); return(0); } free_job_info(job_done_res_t *jdp) { XDR xdrs; xdrmem_create(&xdrs, (caddr_t)jdp, sizeof(job_done_res_t),XDR_FREE); /* xdr_job_done_res_t(&xdrs, jdp); */ } int save_job_info(int jobid, int status, void *data, int datatype) { FILE *fp; char name[PATH_MAX]; XDR xdrs; sprintf(name,"%s/%d",get_jobs_dir(), jobid); fp = fopen(name,"w+"); if (fp == (FILE *) NULL){ /* * Send criticla message! */ return(ABS_OS_ERROR); } xdrstdio_create(&xdrs, fp, XDR_ENCODE); if (xdr_int(&xdrs, &jobid) == FALSE){ return(ABS_CANT_ENCODE); } if (xdr_int(&xdrs, &status) == FALSE){ return(ABS_CANT_ENCODE); } if (xdr_int(&xdrs, &datatype) == FALSE){ return(ABS_CANT_ENCODE); } if (datatype == DUMPSET_TYPE){ if (xdr_net_dumpset_pt(&xdrs, (net_dumpset_t **)&data) == FALSE){ return(ABS_CANT_ENCODE); } }else if (datatype == TOC_TYPE){ if (xdr_toc_res_pt(&xdrs, (toc_res_pt *)&data) == FALSE){ return(ABS_CANT_ENCODE); } }else if (datatype == VOLUME_TYPE){ if (xdr_net_volume_pt(&xdrs, (net_volume_t **)&data) == FALSE){ return(ABS_CANT_ENCODE); } } return(0); } void recover_saved_jobs( char *master) { FILE *fp; int status, jobid, datatype; char name[PATH_MAX]; char buf[PATH_MAX+30]; job_done_res jd; XDR xdrs; DIR *dp; struct dirent *entp; slave_log_error(ABS_INFORMATIONAL,"recover_saved_jobs", "Scanning for old job info"); dp = opendir(_jobs_dir); if (dp == (DIR *) NULL){ sprintf(buf,"Cant open directory %s\n", _jobs_dir); slave_log_error(ABS_ERROR,"recover_saved_jobs", buf); return; } while ((entp=readdir(dp)) != (struct dirent *) NULL){ if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, "..")) continue; sprintf(name,"%s/%s", _jobs_dir, entp->d_name); sprintf(buf, "Found file %s\n", name); slave_log_error(ABS_INFORMATIONAL,"recover_saved_jobs", buf); fp = fopen(name,"r"); if (fp == (FILE *) NULL){ sprintf(buf,"Cant open file %s\n", name); slave_log_error(ABS_ERROR,"recover_saved_jobs", buf); continue; } xdrstdio_create(&xdrs, fp, XDR_DECODE); if (xdr_int(&xdrs, &jobid) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } if (xdr_int(&xdrs, &status) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } if (xdr_int(&xdrs, &datatype) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } if (datatype == DUMPSET_TYPE){ jd.jdr_type = jdr_type_dumpset; if (xdr_net_dumpset_pt(&xdrs, &jd.jdr_dumpset) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } }else if (datatype == VOLUME_TYPE){ jd.jdr_type = jdr_type_volume; if (xdr_net_volume_pt(&xdrs, &jd.jdr_volume) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } }else{ continue; } slave_notify_master(status, jobid, &jd, 0); fclose(fp); unlink(name); free_job_info(&jd); } slave_log_error(ABS_INFORMATIONAL,"recover_saved_jobs", "Done recovering old job info"); } slave/onc_int.c100400 6031 145 4162 6240131025 13102 0ustar delgadooraweb#include #include #include #include #include "../master/abs_msg.h" #include "private.h" static char realm[REALM_SZ]; static int have_realm; extern char master_server[]; int abs_marshall_volheader(char *buf, int buflen, abs_volheader_pt vhp, int marshall) { XDR xdrs; int code; int xdr_op; long start, finish; xdr_op = (marshall == 1) ? XDR_ENCODE: XDR_DECODE; xdrmem_create(&xdrs, buf, buflen, xdr_op); start = (long)XDR_INLINE(&xdrs, 0); code = xdr_abs_volheader_t(&xdrs, vhp); finish = (long)XDR_INLINE(&xdrs, 0); if (code == TRUE) return(finish - start); else return(-1); } int abs_marshall_label(char *buf, int buflen, abs_label_pt lp, int marshall) { XDR xdrs; int code; int xdr_op; long start, finish; xdr_op = (marshall == 1) ? XDR_ENCODE: XDR_DECODE; xdrmem_create(&xdrs, buf, buflen, xdr_op); start = (long)XDR_INLINE(&xdrs, 0); code = xdr_abs_label(&xdrs, lp); finish = (long)XDR_INLINE(&xdrs, 0); if (code == TRUE) return(finish - start); else return(-1); } /* * We only use "jobs_dir" because we chdir'd to the admin * dir when the slave started */ int save_job_info(int jobid, int status, void *data, int datatype) { FILE *fp; char name[ABS_MAX_PATH]; XDR xdrs; sprintf(name,"%s/%d",get_jobs_dir(), jobid); fp = fopen(name,"w+"); if (fp == (FILE *) NULL){ /* * Send criticla message! */ return(ABS_OS_ERROR); } xdrstdio_create(&xdrs, fp, XDR_ENCODE); if (xdr_int(&xdrs, &status) == FALSE){ return(ABS_CANT_ENCODE); } if (datatype == DUMPSET_TYPE){ if (xdr_net_dumpset_pt(&xdrs, &data) == FALSE){ return(ABS_CANT_ENCODE); } }else if (datatype == TOC_TYPE){ if (xdr_toc_res_pt(&xdrs, &data) == FALSE){ return(ABS_CANT_ENCODE); } }else if (datatype == VOLUME_TYPE){ if (xdr_net_volume_pt(&xdrs, &data) == FALSE){ return(ABS_CANT_ENCODE); } } return(0); } slave/private.h100400 6031 145 6334 6240131025 13133 0ustar delgadooraweb #define SLAVE_CHECK_AUTH( handle) slave_check_authentication(handle) #define ABS_MAX_DEVTYPES 10 /* * indeces for the various device types */ #define ABS_NO_DEV 0 #define ABS_DEV_FS 1 #define ABS_DEV_MT 2 /* * record size for control data (label, headers, footers) */ #define ABS_REC_SIZE 4096 typedef struct dev_table{ int (* media_next_record)(); int (* media_rewind)(); int (* media_next_item)(); int (* media_read)(); int (* media_write)(); int (* media_open)(); int (* media_close)(); int (* media_offline)(); void (* media_devtype)(); }dev_table_t; extern struct dev_table *devp; typedef struct dev_handle { int fd; char devname[PATH_MAX]; dev_table_t *dev_ops; char *buf; int bufsize; void *data; }dev_handle_t; #define SLAVE_OPEN(devp, dh, path, flags, jobid) devp->media_open(devp, dh, path, flags, jobid) #define SLAVE_CLOSE(dh) dh->dev_ops->media_close(dh, 1) #define SLAVE_CLOSE_PARTIAL(dh) dh->dev_ops->media_close(dh, 0) #define SLAVE_WRITE(dh, buf, len, cp) dh->dev_ops->media_write(dh, buf, len, cp) #define SLAVE_READ(dh, buf, len, cp) dh->dev_ops->media_read(dh, buf, len, cp) #define SLAVE_SEEK(dh, offset, flag) dh->dev_ops->media_read(dh, offset, flag) #define SLAVE_NEXT_MEDIA(dh, extid, id, valid) \ dh->dev_ops->media_next_item(dh, extid, id, valid) #define SLAVE_REWIND(dh) dh->dev_ops->media_rewind(dh) #define SLAVE_OFFLINE(dh) dh->dev_ops->media_offline(dh) #define SLAVE_NEXT_RECORD(dh, count) dh->dev_ops->media_next_record(dh, count) #define SLAVE_DEVICE_TYPE(dh, dpp) dh->dev_ops->media_devtype(dh, dpp) /* * Macros for error checking */ #define UNRECOVERABLE(code) \ (code == ABS_NOSUCH_VOLUME || code == ABS_VOLUME_MOVED || \ code == ABS_VOLUME_DAMAGED || code == ABS_PROTOCOL_MISMATCH) /* * Definitions to support the filesystem abstraction layer */ #define MAX_FSTYPES 5 #define FS_NOOP 0 #define AFS_OPS 1 typedef struct fs_ops{ void * (* fs_connect)(); int (* fs_dump_volume)(); int (* fs_restore_volume)(); int (* fs_disconnect)(); }fs_ops; #define FS_CONNECT(fsp, host, cell, id, codep, op) \ fsp->fs_connect(host, cell, id, codep, op) #define FS_DUMP(fsp, handle, dh, level, jobp, volp, wrflg, labelp, params) \ fsp->fs_dump_volume(handle, dh, level, jobp, volp, wrflg, labelp, params) #define FS_RESTORE(fsp, handle, dh, volp, mp, jobid, params, do_rewind) \ fsp->fs_restore_volume(handle, dh, volp, mp, jobid, params, do_rewind) #define FS_DISCONNECT(fsp, handle) fsp->fs_disconnect(handle) #define ABS_MIN_RETRY 5 #define ABS_DEFAULT_RETRY 300 #define ABS_MAX_RETRY 600 #define DISABLE_CANCEL() #define ENABLE_CANCEL() /* * Types passed to save job results */ #define DUMPSET_TYPE 1 #define TOC_TYPE 2 #define VOLUME_TYPE 3 #define ROUND_UP(x, y) (((x)+ (y)-1) & ~((y) - 1)) #define NEXT_VOLHEADER(dhp) find_control_rec(dhp, 1, ABS_VOLHEADER_MAGIC) #define NEXT_VOLFOOTER(dhp) find_control_rec(dhp, 1, ABS_VOLFOOTER_MAGIC) #define PREV_VOLHEADER(dhp) find_control_rec(dhp, -1, ABS_VOLHEADER_MAGIC) #define ABS_MOUNT_INTERVAL 120 /* * Slave states for handling SIGTERM */ #define SLAVE_INIT 0 #define SLAVE_RUNNING 1 #define SLAVE_TERMINATED 2 slave/Makefile100600 6031 145 11622 6154640334 13002 0ustar delgadooraweb# # RPCGEN=/mit/athena-backup/tools/tirpc/usr/bin/rpcgen SRC=/mit/athena-backup/tools/tirpc SRCROOT=/mit/athena-backup/src COMMON_INC = ${SRCROOT}/common/include COMMON_SRC = ${SRCROOT}/common/src COMMON_UTIL = ${SRCROOT}/common/util COMMON_ERROR = ${SRCROOT}/common/error AFSROOT=/mit/afsdev/dist/sun4m_54 AFSLIBPATH1=$(AFSROOT)/lib AFSLIBPATH2=$(AFSROOT)/lib/afs AFSINCLUDE=$(AFSROOT)/include LIBSRC=/mit/athena-backup/tools/tirpc/usr/lib LIBFLGS = -L$(LIBSRC) -L$(AFSLIBPATH1) -L$(AFSLIBPATH2) #LIBFLGS = -L$(LIBSRC) AFS = -L$(AFSLIBPATH1) -L$(AFSLIBPATH2) XLIBS= -lucb /usr/athena/lib/libresolv.a AFSSRCDIR=/mit/afsdev/dist/sun4m_54/ STDLIBS = -lm -lsocket -lnsl -laio -lposix4 -lintl -ldl -lc AFSLIBS = ${AFSSRCDIR}lib/afs/libvolser.a \ ${AFSSRCDIR}lib/afs/libsys.a ${AFSSRCDIR}lib/afs/libvldb.a \ ${AFSSRCDIR}lib/libubik.a \ ${AFSSRCDIR}lib/afs/libauth.a ${AFSSRCDIR}lib/afs/libsys.a \ ${AFSSRCDIR}lib/afs/libcmd.a ${AFSSRCDIR}lib/librxkad.a \ ${AFSSRCDIR}lib/libdes.a \ ../master/lib/librx.a ${AFSSRCDIR}lib/liblwp.a \ ${AFSSRCDIR}lib/afs/libcom_err.a ${AFSSRCDIR}lib/afs/libkauth.a \ ${AFSSRCDIR}lib/afs/libaudit.a \ ${AFSSRCDIR}lib/afs/util.a ${XLIBS} LIBS= -L $(SRC)/usr/lib -lrpc -lzephyr -lkrb -ldes \ $(STDLIBS) $(AFSLIBS) -lucb CFLAGS = -g -I. -D_ANSI_C_SOURCE -I$(SRC)/usr/include -I.. -I$(SRCROOT)/common/include \ -I/usr/athena/include -I/usr/include -I$(AFSINCLUDE) -D_SOLARIS_ \ -DRPC_SVC_FG -DONC_RPC FOBJS = slave_main.o slave_dispatch.o slave_int.o \ slaveservice_clnt.o slaveservice_xdr.o \ sig_handlers.o \ restore.o dump.o scan.o job_info.o\ slave_xdr.o master_xdr.o master_clnt.o onc_utils.o slave_utils.o \ slave_error.o slave_auth.o slave_verify.o\ basic_mtio.o config_file.o \ afs_ops.o abs_error.o globals.o MGENFILES= ${COMMON_INC}/master.h ${COMMON_SRC}/master_xdr.c \ ${COMMON_SRC}/master_clnt.c SLV_GENFILES = ${COMMON_SRC}/slaveservice_xdr.c ${COMMON_INC}/slaveservice.h \ ${COMMON_SRC}/slaveservice_clnt.c FGENFILES = ${COMMON_SRC}/slave_xdr.c ${COMMON_INC}/slave.h \ slave_svc.c slave: ${MGENFILES} ${FGENFILES} ${FOBJS} $(CC) -go /var/tmp/slave $(LIBFLGS) -L/usr/athena/lib $(FOBJS) $(LIBS) local_build_genfiles: ${MGENFILES} ${FGENFILES} ${SLV_GENFILES} genfiles: ${FGENFILES} ${SLV_GENFILES} slave.h: slave.x $(RPCGEN) -M -N -C slave.x mv slave.h ${COMMON_INC} mv slave_xdr.c slave_clnt.c ${COMMON_SRC} ${SLV_GENFILES}: ../master/slaveservice.x (cd .. ; make -e master_gen); ${MGENFILES}: ../master/master.x (cd .. ; make -e master_gen); ${FGENFILES}: slave.x $(RPCGEN) -M -N -C slave.x mv slave.h ${COMMON_INC} mv slave_xdr.c slave_clnt.c ${COMMON_SRC} master_xdr.o: ${COMMON_SRC}/master_xdr.c $(CC) -c -o $@ $(CFLAGS) ${COMMON_SRC}/master_xdr.c master_clnt.o: ${COMMON_SRC}/master_clnt.c $(CC) -c -o $@ $(CFLAGS) ${COMMON_SRC}/master_clnt.c slaveservice_xdr.o: ${COMMON_SRC}/slaveservice_xdr.c $(CC) -c -o $@ $(CFLAGS) ${COMMON_SRC}/slaveservice_xdr.c slaveservice_clnt.o: ${COMMON_SRC}/slaveservice_clnt.c $(CC) -c -o $@ $(CFLAGS) ${COMMON_SRC}/slaveservice_clnt.c onc_utils.o: ${COMMON_UTIL}/onc_utils.c $(CC) -c -o $@ $(CFLAGS) ${COMMON_UTIL}/onc_utils.c slave_dispatch.c: slave_svc.c sed -f ../master/remove-main slave_svc.c > slave_dispatch.c slave_xdr.o: ${COMMON_SRC}/slave_xdr.c $(CC) -c -o $@ $(CFLAGS) ${COMMON_SRC}/slave_xdr.c slave_int.o: slave_int.c ${COMMON_INC}/slave.h ${COMMON_INC}/master.h private.h prototypes.h $(CC) -c -o $@ $(CFLAGS) slave_int.c slave_main.o: $(CC) -c -o $@ $(CFLAGS) slave_main.c slave_utils.o: slave_utils.c private.h $(CC) -c -o $@ $(CFLAGS) slave_utils.c slave_error.o: slave_error.c private.h $(CC) -c -o $@ $(CFLAGS) slave_error.c devfs_ops.o: devfs/devfs_ops.c private.h devfs/devfs.h $(CC) -c -o $@ $(CFLAGS) devfs/devfs_ops.c devfs_ops1.o: devfs/devfs_ops1.c private.h devfs/devfs.h $(CC) -c -o $@ $(CFLAGS) devfs/devfs_ops1.c job_info.o:job_info.c $(CC) -c -o $@ $(CFLAGS) job_info.c dump.o: dump.c private.h prototypes.h $(CC) -c -o $@ $(CFLAGS) dump.c slave_auth.o: slave_auth.c private.h prototypes.h $(CC) -c -o $@ $(CFLAGS) slave_auth.c restore.o: restore.c private.h prototypes.h $(CC) -c -o $@ $(CFLAGS) restore.c slave_verify.o: slave_verify.c private.h prototypes.h $(CC) -c -o $@ $(CFLAGS) slave_verify.c scan.o: scan.c private.h prototypes.h $(CC) -c -o $@ $(CFLAGS) scan.c onc_int.o: onc_int.c private.h $(CC) -c -o $@ $(CFLAGS) onc_int.c basic_mtio.o: private.h basic/basic_mtio.c $(CC) -c -o $@ $(CFLAGS) basic/basic_mtio.c afs_ops.o: afs_ops.c $(CC) -c -o $@ -I $(AFSINCLUDE) $(CFLAGS) afs_ops.c abs_error.o: ${SRCROOT}/common/error/abs_error.c $(CC) $(CFLAGS) -c -o $@ ${SRCROOT}/common/error/abs_error.c %.o: %.c $(CC) $(CFLAGS) -c -o $@ $< clean: rm -f $(FOBJS) slave.h slave_xdr.c slave_svc.c \ slave_clnt.c slave/prototypes.h100400 6031 145 2700 6240131025 13702 0ustar delgadooraweb /* * Prototypes */ int slave_log_error(int sev, char *routine, char *msg); int slave_notify_master(int status, int jobid, job_done_res_pt jdp, int save); int validate_label(dev_handle_t *dh, media_id_pt mip, int validate_type, abs_label_t *labelp); int cycle_through_tapes(dev_handle_t *dh, int jobid, char *extid, media_id_pt mip, int valid); int request_media_mount(int jobid, int request_type, tapeid_t *mp); fs_ops * get_fs_ops(char *fstype); int send_status(int jobid, job_status_pt job_stat); int GetServer(char *aname); int abs_marshall_label(char *buf, int buflen, abs_label_pt lp, int marshall); int abs_marshall_volheader(char *buf, int buflen, abs_volheader_pt vhp, int marshall); int read_label(dev_handle_t *dh, abs_label_t *labelp); int write_label(dev_handle_t *dh, abs_label_t *labelp); void netvol_to_volheader(net_volume_t *vp, abs_volheader_t *vh); int read_volume_footer(dev_handle_t *dh, abs_volfooter_pt vf); int write_volume_footer(dev_handle_t *dh, net_volume_pt vp, int status); int find_control_rec(dev_handle_t *dh, int direction, int rec_type); int do_dump(dev_handle_t *dh, net_dumpset_pt dp, job_pt jp, dump_params_pt params, job_status_pt job_stat); int do_restore(dev_handle_t *dh, media_t *mp, int jobid, restore_pt params, job_status_pt job_stat); char * get_jobs_dir(); int get_slave_tgt(); int get_slave_state(); slave/dump.c100644 6031 145 71015 6242362165 12466 0ustar delgadooraweb#include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" extern char *device_name; extern char *master_server; #define RETRY_INTERVAL 300 int label_tape_for_dump(dev_handle_t *dh, int jobid); int try_hard_to_write_footer(dev_handle_t *dh, net_volume_t *cvp, int *error_count, int error_max, net_dumpset_t *dp, job_pt jp, abs_label_t *label, dump_params_pt params); int handle_eom(dev_handle_t *dh, job_pt jp, abs_label_t *info, net_dumpset_t *dp, char *verfmode); void set_volume_dump_status(net_volume_t *vp, int status); void mark_tape_log_status(media_t *mp, int threshold); /* * Procedure: do_dump * * Parameters: dh - address of device specific information * dp - address of dumpset information for to be dumped * jp - address of job description info * params - address of job parameters info * * Description: do_dump is the high-level routine which controls the * dump processing for the dumpset represented by "dp". This routine * iterates through all volumes in the dumpset invoking FS_DUMP (filesystem- * specific dump operation) on each volume until all volumes are dumped * successfully or the maximum retry count for each volume is exceeded. * * The master expects the slave to return the following information * after the dump is completed: * - summary of dump statistics (this info is in 2 places * in the "job_stat" structure and in the * dumpstats field of the dumpset. * - status code for each volume dumped (contained in the volume's * "net_volume_t" structure); * * - list of tapes used (returned as part of the dumpset structure) * * - volume to tape mappings; each volume entry will contain informaation * indicating which tape it was successfully written to. This is * to support dumps which consist of multiple tapes. * * * The slave will send a status report to the master before it begins * the dump of a volume. as a result of this status report, the slave * can receive a cancellation request from the master. If the slave * does receive a cancellation request, it will stop the dump at * this time. For canceled jobs, no results are returned to the master. * * On failed volumes, do_dump will attempt to move the device backward * over any data which was written for the failed volume, thus overwriting * the bad data. If the underlying device does not support reverse operation, * the do_dump will add the volume entry to the tape footer block. The tape * footer block is written at the end of the last tape of the dump. */ #define curr_media tape_sets->tapes int do_dump(dev_handle_t *dh, net_dumpset_t *dp, job_pt jp, dump_params_pt params, job_status_pt job_stat) { int code, media_errors, i, rpc_code, fileno; int percent, bad, total, data_written; int abort_job , last_requested=0, scode; net_volume_t *cvp, *retry, *prev, *bad_vols; abs_label_t label; void *handlep; char buf[512]; fs_ops *fsp; struct timeval now; char *datep; float p,t; memset(job_stat, 0, sizeof(job_status_t)); job_stat->total_volumes = dp->nvolumes; if (dp->nvolumes <=0 ) return(ABS_NO_DUMPSET); fsp = get_fs_ops(dp->d_fstype); if (fsp == (fs_ops *) NULL){ set_volume_dump_status(dp->volumes, ABS_INVALID_FSTYPE); return(ABS_INVALID_FSTYPE); } /* * Locate the media item in the specified media device * and validate its internal id with the master. * cycle through will make a best effort to come up with * a tape which we can write on. */ while (( code = cycle_through_tapes(dh, jp->jobid, (char *)NULL, (media_id_pt) NULL, ABS_FREE_MEDIA)) == ABS_INVALID_MEDIA_ID){ /* * Request a mount of something useable */ if (last_requested == 0){ code = request_service(jp->jobid, ABS_TAPE_MOUNT_REQ, NULL); if (code) return(code); last_requested = 1; }else last_requested = 0; sleep(ABS_MOUNT_INTERVAL); } if (code){ if (code != ABS_BLANK_MEDIUM){ set_volume_dump_status(dp->volumes, code); return(code); } code = label_tape_for_dump(dh, jp->jobid); if (code){ set_volume_dump_status(dp->volumes, code); return(code); } } /* * Create Tapeset info for this tape; during the course * of normal operation dp->tapes_sets may have one * or more "tapes" chained off of it. When a media * chage occurs on end-of-medium, the slave executes * a checkpoint, which causes the data for that tape * to be sent to the master. IF the checkpoint fails, * the slave will keep the tape entry and its data around * and send it the next time that a check point occurs * or at the end of this job. * * New media entries are added at the beginning of the list. * * "curr_media" is a shorthand for dp->tape_sets->tapes */ dp->tape_sets = (tapeset_t *) malloc(sizeof(tapeset_t)); if (dp->tape_sets == (tapeset_t *) NULL){ return(ABS_NO_MEM); } memset(dp->tape_sets, 0 , sizeof(tapeset_t)); dp->curr_media = (media_pt)malloc(sizeof(media_t)); if (dp->curr_media == (media_pt)NULL){ free(dp->tape_sets); dp->tape_sets = (tapeset_t *) NULL; return(ABS_NO_MEM); } memset(dp->curr_media, 0, sizeof(media_t)); /* * Read the current label information to get the * static info from the label */ code = SLAVE_REWIND(dh); if (code){ set_volume_dump_status(dp->volumes, code); return(code); } if ((code = read_label(dh, &label))){ set_volume_dump_status(dp->volumes, code); return(code); } /* * save the internal id info for this tape in the tapeset entry */ memcpy(&dp->curr_media->internal, &label.tapeid, sizeof(media_id)); dp->curr_media->log_tape = 1; dp->curr_media->total_vols = 0; dp->curr_media->bad_vols = 0; /* * modify the label fields which change with each dump; */ gettimeofday(&now); label.block_size = dh->bufsize; label.level = params->dump_from; label.uses++; label.sequence = 1; dp->tape_sets->date_dumped = now.tv_sec; label.tape_created = now.tv_sec; strncpy(&label.cell, dp->d_cell, ABS_MAX_DOMAIN); strncpy(&label.dumpset, dp->d_name, ABS_MAX_DNAME); /* * Write the new label to the medium; Also writes an EOF marker. */ code = SLAVE_REWIND(dh); if (code){ set_volume_dump_status(dp->volumes, code); return(code); } if ((code = write_label(dh, &label))){ set_volume_dump_status(dp->volumes, code); return(code); } /* * Start out with all volumes on the retry list. Move them * to dp->curr_media->volumes as they complete successfully. We * stop when the retry list is empty or when we have exceeded * the maximum number of retries defined in the dumpset structure. */ bad_vols = (net_volume_t *) NULL; retry = dp->volumes; dp->volumes = (net_volume_t *) NULL; prev = (net_volume_t *) NULL; bad = media_errors = 0; gettimeofday(&now); datep = ctime(&now.tv_sec); strcpy(dp->dumpstats.start, datep); dp->dumpstats.ntapes = 1; dp->dumpstats.bytes_processed = 0; fileno=1; abort_job = 0; if (dp->d_retry <= 0 ) dp->d_retry = 1; sprintf(buf,"Starting dump of dumpset %s, level %d\n", dp->d_name, dp->dumpstats.level); slave_log_error(ABS_INFORMATIONAL,"do_dump", buf); /* * the big Loop */ for (i = 0; i< dp->d_retry; i++){ if (abort_job) break; for(cvp = retry; cvp != (net_volume_t *)NULL;){ if (abort_job) break; if (i > 0) sleep(RETRY_INTERVAL); /* * Get a connection to this server which hosts the * volume. */ sprintf(buf,"Connecting to Server %s",cvp->v_server); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); handlep = FS_CONNECT(fsp, cvp->v_server, dp->d_cell, (char *)NULL, &code, ABS_BACKUP_OP); if (handlep == (void *) NULL){ sprintf(buf,"Failed to Connect to %s",cvp->v_server); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); cvp->v_status = ABS_FS_CONNECT; prev = cvp; cvp = cvp->next; job_stat->failures++; continue; } /* * Send a quick status report to the master telling * it which volume we are about to dump. This is * necessary because dump jobs are quite lengthy and * the Slave isn't threaded, so it can't accept status * queries while the job is running */ strcpy(job_stat->current_volume, cvp->v_name); gettimeofday(&now); job_stat->date = now.tv_sec; sprintf(buf,"Dumping volume %s, retry = %d\n",cvp->v_name, i); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); code = send_status(jp->jobid, job_stat); if (code == ABS_JOB_CANCELED || get_slave_state() == SLAVE_TERMINATED){ /* * We've been requested to stop our work at the * next convenient point. Here is a good place * to stop; we do not return any results if * we are canceled. */ if (retry != (net_volume_t *) NULL) abs_free_netvol(retry); if (bad_vols != (net_volume_t *) NULL) abs_free_netvol(retry); if (code == ABS_JOB_CANCELED) slave_log_error(ABS_INFORMATIONAL, "do_dump", "Job cancel received"); else{ slave_log_error(ABS_INFORMATIONAL, "do_dump", "slave termination received"); } return(ABS_JOB_CANCELED); } data_written = 0; code = FS_DUMP(fsp, handlep, dh, params->dump_from, jp, cvp, &data_written, &label, params); /* * Sort through the error codes. Those which are * deemed recoverable indicate that the volume should * be retried later (comm failure, call timeout, auth * failures). Those which are unrecoverable will not * be retried (volume does not exist on server, is * damaged or protocol version mismatch). */ sprintf(buf,"Finished volume %s, code = %d\n",cvp->v_name, code); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); if (code || cvp->v_status){ job_stat->failures++; if (code == ABS_EOM_DETECTED){ /* * Reverse one record and write volume footer * */ scode = SLAVE_NEXT_RECORD(dh, -1); if (scode == 0) write_volume_footer(dh, cvp, code); /* * handle eom will worry about dismounting * the current tape and asking for a new one * It also fills in the label information for * the newly mounted tape; it also executes * a checkpoint which may change the value * of dp->tape_sets->tapes. */ code = handle_eom(dh, jp, &label, dp, params->verf_mode); if (code){ /* * we were unable to properly deal with end of medium */ slave_log_error(ABS_FATAL, "do_dump", "unable to handle End of Medium situation - Dump Aborted"); goto dump_cleanup; } dp->dumpstats.ntapes++; /* * redo this volume - don't advance the cvp pointer */ continue; }else if (code == ABS_MEDIA_ERROR){ /* * We abort if the media error threshold has been * exceeded. If the threshold is not exceeded * Then a footer will be written by the code * following this if statement. */ media_errors++; slave_log_error(ABS_ERROR,"do_dump","Media errors on device"); if (media_errors > params->media_errors){ /* * This tape is bad. Set "log_tape" to false * so the info for this tape does not get * logged in the database */ dp->curr_media->log_tape = 0; goto dump_error; } }else if (UNRECOVERABLE(code)){ /* * Remove from retry queue and * place volume on bad list */ bad++; if (prev){ prev->next = cvp->next; cvp->next = bad_vols; bad_vols = cvp; cvp = prev->next; } else{ retry=retry->next; cvp->next = bad_vols; bad_vols = cvp; cvp = retry; } job_stat->failures++; code = try_hard_to_write_footer(dh, cvp, &media_errors, params->media_errors, dp, jp, &label, params); if (code != 0 && code != ABS_EOM_DETECTED){ slave_log_error(ABS_ERROR, "do_dump", "Dump aborted due to media/device errors"); goto dump_cleanup; } continue; } /* else EOM */ /* * This volume will be retried later */ prev = cvp; cvp = cvp->next; if (data_written){ dp->curr_media->bad_vols++; /* * If something was written to the tape, try to backup * to the previous file mark. If the devices does not * support this type of operation, then create a bad * volume entry in the volume summary table. */ #ifdef REVERSE code = SLAVE_NEXT_FILE(dh, -1); if (code){ fileno++; } #else /* * Write a volume footer indicating that this volume * is bad */ code = try_hard_to_write_footer(dh, cvp, &media_errors, params->media_errors, dp, jp, &label, params); if (code != 0 && code != ABS_EOM_DETECTED){ slave_log_error(ABS_ERROR, "do_dump", "Dump aborted due to media/device errors"); goto dump_cleanup; } #endif } continue; } /* if code */ /* * we are here because we have successfully dumped the * volume. Increment the total dumped and remove the * the volume from the retry queue */ code = try_hard_to_write_footer(dh, cvp, &media_errors, params->media_errors, dp, jp, &label, params); if (code != 0 && code != ABS_EOM_DETECTED){ slave_log_error(ABS_ERROR, "do_dump", "Dump aborted due to media/device errors"); goto dump_cleanup; } job_stat->vols_processed++; dp->curr_media->total_vols++; /* * The volume must be re-dumped since all of its * data, including the footer must fit on the same tape * Do not advance the cvp pointer. */ job_stat->bytes_processed += cvp->v_size; cvp->position = fileno; fileno++; if (prev){ prev->next = cvp->next; cvp->next = dp->curr_media->volumes; dp->curr_media->volumes = cvp; cvp = prev->next; } else{ retry=retry->next; cvp->next = dp->curr_media->volumes; dp->curr_media->volumes = cvp; cvp = retry; } } /* for cvp */ /* * no more volumes on the retry list - we are done */ if (retry == (net_volume_t *) NULL) break; } /* for retry */ dump_cleanup: mark_tape_log_status(dp->curr_media, dp->d_failthresh); /* * count the volumes which could not be dumped in "dp-d_retry" times * and add it to the total bad volume count */ if (retry != (net_volume_t *) NULL){ for( cvp = retry; cvp->next != (net_volume_t *) NULL; bad++, cvp = cvp->next); } if (bad_vols != (net_volume_t *) NULL){ for( cvp = bad_vols; cvp->next != (net_volume_t *) NULL; cvp = cvp->next); /* * Add the bad volumes back to the dumpset volume chain */ cvp->next = dp->volumes; dp->volumes = bad_vols; } if (bad > 0 ){ /* * Determine whether the fail threshold has been exceeded for this * job */ t = (float) job_stat->total_volumes; p = (float) bad; percent = (int)((p/t) * 100.0); if (percent > dp->d_failthresh){ code = ABS_ERROR_THRESH; } } dp->dumpstats.bytes_processed = job_stat->bytes_processed; dump_error: sprintf(buf,"Finished dump of dumpset %s, status %d - %d of %d volumes dumped\n", dp->d_name, code, job_stat->vols_processed, dp->nvolumes); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); gettimeofday(&now); datep = ctime(&now.tv_sec); strcpy(dp->dumpstats.stop, datep); return(code); } /* * Cycle through all the media items on the device looking * for the specified item * Search by (for devices that support * scanning the external label) * - medium with matching internal id * - any medium with valid abs label * - any medium * * */ int cycle_through_tapes(dev_handle_t *dh, int jobid, char *extid, media_id_pt mip, int valid) { int code, rpc_code; char buf[512]; abs_label_t abs_label; dev_table_t *dp = dh->dev_ops; /* * Find a tape with matching the caller's selection critera. * This can be a match by id, by * internal id only, or by any tape with valid abs label or * any tape * */ code = 1; while (code != 0){ /* * loop through allof the media on the device. For * single cartrige tape systems this funciton is a no-op * for multi-cartridge systems, the device dependent routine * is responsible for informing the master if the a media * mount is required */ code = SLAVE_NEXT_MEDIA(dh, extid, mip, valid); if (code){ /* fatal, unrecoverable error */ sprintf(buf, "Media/Device errors from device %s \n", device_name); slave_log_error(ABS_FATAL,"do_dump", buf); return(code); } } if (valid != 0){ /* * For valid !=0 we must validate the tape with the * master. First we call validate_label telling it that we * are expecting a tape with a valid abs label. * validate_label will try to read the tape and determine * whether the tape meets our expectations (has a valid label). * A null media id is specified when the caller is not looking * for a specific tape; i.e., any labeled tape will do. */ if (mip != (media_id_pt *) NULL){ code = validate_label(dh, mip, ABS_VALID_LABELID, &abs_label); /* * This is a restore request, so we don't need to validate the * tape with the master * * If there isn't any tape in the drive, sometimes we get * "BLANK_MEDIUM" - map this to INVALID_MEDI_ID to force a * media mount request to happen. */ if (code == ABS_BLANK_MEDIUM) return(ABS_INVALID_MEDIA_ID); if (code) return(code); }else{ code = validate_label(dh, (media_id_pt)NULL, ABS_VALID_LABEL, &abs_label); if (code) return(code); /* * We now have a tape whose label appears to be valid. * Request a tape status query from the master to see what state * this tape is in (e.g. VALID, FREE). "code" will actually contain * the tape status inforamtion. */ rpc_code = slave_validate(&abs_label.tapeid, jobid, &code); if (rpc_code) return(rpc_code); if (code == ABS_JOB_CANCELED) return(code); if (code == ABS_INVALID_JOB) return(code); /* * "valid" contains the state which the caller requests (e.g. needs * a free tape, etc). "code " contains the tape's state as * listed in the abs database. */ if (valid != code){ sprintf(buf,"Media validation with master fails, media state = %d, expected %d\n", code, valid); slave_log_error(ABS_WARNING, "cycle_through_tapes", buf); return(ABS_INVALID_MEDIA_ID); } code = 0; } } /* * We are here because the medium we wanted is mounted so * Rewind it. */ code = SLAVE_REWIND(dh); if (code){ sprintf(buf, "device %s Rewind failure \n", device_name); slave_log_error(ABS_FATAL,"do_dump", buf); } return(code); } /* * Procedure: perform_media_verification * * Parameters: -dh address of device information * dp - address of dumpset information * verf_mode - verification mode to use * job_stat - address of job status information * jobid - job id assigned by master * * Description: This function closes the media, causing an EOM marker * to be written at the end of the dump data and rewinds the tape. The * tape is then re-opened for read only access. We send a status report * to the master informing it that we are now performing media verification. * We then proceed to call the appropriate media verification function */ int perform_media_verification(dev_handle_t *dh, net_dumpset_t *dp, char *verf_mode, job_status_t *job_stat, int jobid) { int code; abs_label_t label; /* * All modes of verification verify the label, so let's * do it here. */ if (!strcmp(verf_mode, "NONE")) return(0); /* * Tell Master we are verifying the tape */ strcpy(job_stat->current_volume, "VERIFY MEDIA"); code = send_status(jobid, job_stat); code = SLAVE_REWIND(dh); code = SLAVE_CLOSE_PARTIAL(dh); code = SLAVE_OPEN(dh->dev_ops, &dh, dh->devname, O_RDONLY, jobid); if (code) return(code); code = read_label(dh, &label); if (code) return(code); if (!strcmp(verf_mode, "FULL")){ return(slave_full_verification(dh, dp)); }else if (!strcmp(verf_mode, "QUICK")){ return(slave_quick_verification(dh, dp)); }else { return(ABS_INVALID_VERF); } } /* * Procedure: try_hard_to_write_footer * * Parameters: dh - address of device information. * cvp - address of volume information * error_count - address of current media error count * error_max - media error threshold * dp - address of dumpset information * jp - address of job information. * label - address to write label inforamtion. * * Description: This procedure attempts to write a volume footer * using the inforamtion provided by cvp. It will repeatedly attemp * to write the footer until it is successful or the media error threshold * is exceeded, or it detects EOM. IF EOM is detected, it will request * a mount of a new tape and return an error code indicating so. * * In the case of EOM, we do not attempt to write a footer on the new * tape since volumes are not allowed to span tapes. * * Modifies: label, only if a new tape is mounted * dp->tapesets , only if a new tape is mounted * * Memory allocation: memory allocated to dp will be freed by the RPC * when the dump service routine completes. */ int try_hard_to_write_footer(dev_handle_t *dh, net_volume_t *cvp, int *error_count, int error_max, net_dumpset_t *dp, job_pt jp, abs_label_t *label, dump_params_pt params) { int code; media_t *mp; do { code = write_volume_footer(dh, cvp, cvp->v_status); if (code == ABS_MEDIA_ERROR) *error_count = *error_count +1; }while(code == ABS_MEDIA_ERROR && *error_count <= error_max); if (code == 0) return(code); if (code == ABS_MEDIA_ERROR){ slave_log_error(ABS_ERROR,"try_hard_to_write_footer", "Media errors on device"); return(code); } if (code == ABS_EOM_DETECTED){ code = handle_eom(dh, jp, label, dp, params->verf_mode); if (code){ /* * we were unable to properly deal with end of medium */ slave_log_error(ABS_FATAL, "try_hard_to_write_footer", "unable to handle End of Medium situation - Dump Aborted"); return(code); }else{ dp->dumpstats.ntapes++; /* * So that the caller knows the footer could not * be written on the same tape; */ return(ABS_EOM_DETECTED); } } return(code); } /* * Procedure: label_tape_for_dump * * Parameters: dh -address of device information * jobid - job id assigned by master for this job * * Description: This functionr equ3ests the master to generate * an internal label identifier and proceeds to label the tape * using that internal identifier. */ int label_tape_for_dump(dev_handle_t *dh, int jobid) { media_id_t mip; int code; /* * Get an intenal label from the master */ code = request_internal_label(jobid, &mip); if (code) return(code); code = slave_label_medium(NULL, dh, NULL, &mip); return(code); } /* * Procedure: set_volume_dump_status * * Parameters: vp - address of linked list of volume structures * status - status code * * Description: This function sets the status code of each * volume in the linked list to "status" * * Modifies: "v_status" field of each volume in list */ void set_volume_dump_status(net_volume_t *vp, int status) { net_volume_t *cvp; for (cvp = vp; cvp != (net_volume_t *)NULL; cvp = cvp->next){ cvp->v_status = status; } } void mark_tape_log_status(media_t *mp, int threshold) { float t, b; int percent; t = (float) mp->total_vols; b = (float) mp->bad_vols; percent = (int)((b/t) * 100.0); if (percent > threshold){ mp->log_tape = 0; } } slave/RCS/ 40755 6031 145 0 6263011264 11655 5ustar delgadoorawebslave/RCS/restore.c,v100400 6031 145 55642 6242361324 14067 0ustar delgadoorawebhead 6.1; branch ; access ; symbols autolabel-baseline:3.5 alpha:2.1; locks delgado:6.1; strict; comment @ * @; 6.1 date 96.11.13.09.17.18; author delgado; state Exp; branches ; next 6.0; 6.0 date 96.11.06.10.39.48; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.36; author delgado; state Exp; branches ; next 4.1; 4.1 date 96.05.20.11.09.32; author delgado; state Exp; branches ; next 4.0; 4.0 date 96.04.19.11.22.40; author delgado; state Exp; branches ; next 3.6; 3.6 date 96.03.19.16.03.13; author delgado; state Exp; branches ; next 3.5; 3.5 date 96.03.12.12.36.18; author delgado; state Exp; branches ; next 2.3; 2.3 date 96.03.10.17.30.17; author delgado; state Exp; branches ; next 2.2; 2.2 date 96.03.01.12.47.35; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.23.37; author delgado; state Exp; branches ; next 1.7; 1.7 date 96.02.06.10.00.27; author delgado; state Exp; branches ; next 1.6; 1.6 date 96.01.25.16.35.15; author delgado; state Exp; branches ; next 1.5; 1.5 date 96.01.17.13.57.13; author delgado; state Exp; branches ; next 1.4; 1.4 date 96.01.10.11.21.48; author delgado; state Exp; branches ; next 1.3; 1.3 date 96.01.07.13.37.44; author delgado; state Exp; branches ; next 1.2; 1.2 date 96.01.03.17.07.28; author delgado; state Exp; branches ; next 1.1; 1.1 date 95.11.15.14.05.21; author delgado; state Exp; branches ; next ; desc @ Support for dump and restore to AFS servers @ 6.1 log @Fix walthrlkthrough linked list of tapes with multi-tape restore. @ text @#include #include #include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" extern char *device; extern char *master_server; /* * Function: do_restore * * Parameters: dh - pointer to device device information for media * vp - pointer to linked list of volumes to be restored * * jobid - id of job on master * params - address of parameters affecting restore operation. * * Description: This function performs a restore operation for each * volume in the list pointed to by "vp". It invokes the filesystem * specific "connect" and "restore" functions for each volume in * the list. If the restore operation fails for a volume with a * transient error then that volume is retried up to the maximum * number of retries indicated in the restore parameters. This * function will also request a media mount if it determines that * the proper media is not inserted into the device. */ int do_restore( dev_handle_t *dh, media_t *mp, int jobid, restore_pt params, job_status_pt job_stat) { int code, retries, needs_rewind; int percent, total, fileno, last_requested=0; net_volume_t *cvp; media_t *cmp; abs_label_t label; void *handlep; char buf[1024]; fs_ops *fsp; char *datep; int restore_error; abs_volheader_t vh; abs_volfooter_t vf; struct timeval now; /* * "restore_error keeps track of whether we've encountered any * serious errors which will cause us to give up restoreing any * other volumes which are located on the medium which has the * error. If we hit this state for a medium, we mark all the remaining * volumes on that medium as having an error and move on to the next * medium. Currently, the only error which would cause restore_error * to be non-zero is exceeding the media error threshold. */ restore_error = 0; job_stat->media_errors = 0; /* * Get the operations vector for this filesystem type. * All volumes must have the same type */ fsp = get_fs_ops(params->fstype); if (fsp == (fs_ops *) NULL){ return(ABS_INVALID_FSTYPE); } memset(job_stat, 0, sizeof(job_status_t)); /* * Ensure the retry value makes sense */ if (params->retries <= 0){ params->retries = 1; } if (params->media_errors < 0){ params->media_errors = 0; } /* * count the number of volumes in this restore operation. * We are supposed to provide statistics for the restore * and the total number of volumes involved is part of this. */ job_stat->total_volumes = 0; for(cmp = mp; cmp != (media_t *) NULL; cmp = cmp->next){ for (cvp = cmp->volumes; cvp != (net_volume_t *) NULL; cvp = cvp->next){ job_stat->total_volumes++; } } /* * Walk through each media on the list. Although the code * here supports the specification of more than one medium, * the Master does not yet support this. */ for(cmp = mp; cmp != (media_t *) NULL; cmp = cmp->next){ if (cmp->volumes == (net_volume_t *) NULL){ sprintf(buf,"Media has no volumes!\n", cmp->extern_id); slave_log_error(ABS_ERROR, "do_restore", buf); cvp->v_status = ABS_INVALID_MEDIA_ID; continue; } /* * reset the restore error state for this media; * check to see if it is mounted. */ restore_error = 0; while((code = cycle_through_tapes(dh, jobid, cmp->extern_id, (media_id_pt) &cmp->internal, ABS_VALID_MEDIA)) == ABS_INVALID_MEDIA_ID){ /* * keep trying until the guy mounts something we * can actually use. We are looking for a specific tape. */ if (last_requested == 0){ code = request_service(jobid, ABS_TAPE_MOUNT_REQ, cmp->extern_id); last_requested = 1; }else{ last_requested = 0; sleep(ABS_MOUNT_INTERVAL); } } if (code){ /* * A serious error, possibly a device error which * can't be fixed has occurred. Error has already been logged. */ return(code); } /* * Advance past the label and position at the beginning * of the first volume header on the tape. */ code = SLAVE_NEXT_RECORD(dh, 1); fileno=1; /* * Restore all of the volumes which are chained of this * media entry */ for (cvp = cmp->volumes; cvp != (net_volume_t *) NULL; cvp = cvp->next){ /* * Tape is positioned at beginning of a volume header. * Seek to the correct volume as indicated by cvp->media->position * and start reading the volume information from the tape. */ for (fileno; fileno < cvp->position; fileno++){ /* * This is executed twice, once for the volume header and * once for the corresponding volume footer */ code = read_volume_header(dh, &vh); if (code == ABS_MEDIA_ERROR) job_stat->media_errors++; if (job_stat->media_errors > params->media_errors){ restore_error = ABS_MEDIA_ERROR; break; } if (code == ABS_INVALID_MAGIC){ sprintf(buf,"Bad Media Format, Expected Volume header, file %d\n", fileno); slave_log_error(ABS_WARNING,"do_restore",buf); } /* skip volume data */ code = NEXT_VOLFOOTER(dh); if (code == ABS_MEDIA_ERROR) job_stat->media_errors++; if (job_stat->media_errors > params->media_errors){ restore_error = ABS_MEDIA_ERROR; break; } /* skip footer */ code = read_volume_footer(dh, &vf); if (code == ABS_MEDIA_ERROR) job_stat->media_errors++; if (job_stat->media_errors > params->media_errors){ restore_error = ABS_MEDIA_ERROR; break; } if (code == ABS_INVALID_MAGIC){ sprintf(buf,"Bad Media Format, Expected Volume footer, file %d\n", fileno); slave_log_error(ABS_WARNING,"do_restore",buf); } } if (restore_error != 0){ cvp->v_status = restore_error; continue; } /* * allocate space to store status information * to tell master what happened to this volume * The master uses this info to print out a report * for each volume at the end of the restore operation */ if (cvp->res == (job_status_pt) NULL){ cvp->res = (job_status_pt)malloc(sizeof(job_status_t)); if (cvp->res == (job_status_pt) NULL){ return(ABS_NO_MEM); } } for(retries = 0; retries < params->retries; retries ++){ /* * Connect to the filesystem entity which will * execute the restore */ handlep = FS_CONNECT(fsp, cvp->v_server, params->cell, (char *)NULL, &code, ABS_RESTORE_OP); if (code == ABS_SERVER_NOEXIST ){ /* * don't retry on unrecoverable errors such as * cell does not exist, server does not exist */ cvp->v_status = code; break; } if (handlep == (void *) NULL){ /* * failed to connect, so retry. */ continue; } /* * Send the master a little status report telling * which volume we're on */ strcpy(cvp->res->current_volume, cvp->v_name); gettimeofday(&now); cvp->res->date = now.tv_sec; cvp->res->vols_processed = job_stat->vols_processed; cvp->res->bytes_processed = job_stat->bytes_processed; cvp->res->failures = job_stat->failures; code = send_status(jobid, cvp->res); if (code == ABS_JOB_CANCELED ){ slave_log_error(ABS_ERROR, "do_restore", "Job canceld at user's request\n"); /* * Mark remaining volumes as "canceled" */ for(;cvp != (net_volume_t *) NULL; cvp = cvp->next){ cvp->v_status = ABS_JOB_CANCELED; } return(ABS_JOB_CANCELED); } if (get_slave_state() == SLAVE_TERMINATED){ slave_log_error(ABS_ERROR, "do_restore", "Slave termination request received \n"); return(ABS_SLAVE_TERMINATED); } /* * Initiate the restore with the filesystem */ sprintf(buf,"Initiating restore of %s\n", cvp->v_name); slave_log_error(ABS_INFORMATIONAL,"do_restore", buf); code = FS_RESTORE(fsp, handlep, dh, cvp, cmp, jobid, params, &needs_rewind); cvp->v_status = code; sprintf(buf,"Completed restore of %s, code = %d\n", cvp->v_name, code); slave_log_error(ABS_INFORMATIONAL,"do_restore", buf); /* * Check whether the call should be retried */ if (code != 0){ job_stat->failures++; } if (code == ABS_MEDIA_ERROR){ job_stat->media_errors++; if (job_stat->media_errors > params->media_errors) restore_error = ABS_MEDIA_ERROR; } if (code == 0 || (code != ABS_COMM_FAILURE) || (code != ABS_CALL_TIMEOUT) || (code != ABS_VOLUME_BUSY)) break; /* * seek back to the volume header and try again. */ if (needs_rewind) code = PREV_VOLHEADER(dh); sleep(ABS_DEFAULT_RETRY); } /* end for retries */ /* * We have either successfully restored the volume * or we have given up on restoring it. */ if (code){ if (code == ABS_MEDIA_ERROR){ job_stat->media_errors++; if (job_stat->media_errors > params->media_errors){ restore_error = ABS_MEDIA_ERROR; break; } } /* * Tape was left positioned after current volume footer; * increment the fileno to indicate we are at the start * of the next volume. */ if (needs_rewind){ fileno++; } }else{ /* * Success! Fs_restore has left us at the record following * the footer. */ job_stat->vols_processed++; job_stat->bytes_processed += cvp->v_size; fileno++; } } /* end for cvp */ } return(code); } @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @d91 2 a92 2 for(cmp = mp; cmp != (media_t *) NULL; cmp = mp->next){ for (cvp = mp->volumes; cvp != (net_volume_t *) NULL; cvp = cvp->next){ d101 1 a101 1 for(cmp = mp; cmp != (media_t *) NULL; cmp = mp->next){ @ 5.0 log @remove fakeslave names @ text @@ 4.1 log @*** empty log message *** @ text @@ 4.0 log @"slaveint" changed to "slaveservice" @ text @d2 1 a2 1 #include d34 1 a34 1 do_restore( dev_handle_t *dh, net_volume_pt vp, int jobid, restore_pt params, d40 2 a41 1 net_volume_pt cvp; a45 1 media_id_t curr_id; a73 1 memset(&curr_id, 0, sizeof(media_id)); d91 4 a94 2 for (cvp = vp; cvp != (net_volume_pt) NULL; cvp = cvp->next){ job_stat->total_volumes++; d97 3 a99 7 * Walk through all of the volumes in the list. * For each volume check to see if it is located on the media * which we currently have mounted; if not, then request a * mount of the media which it is on. * * After the media is mounted, seek to the proper location and * issue the "connect" followed by "restore". d101 4 a104 3 for (cvp = vp; cvp != (net_volume_pt) NULL; cvp = cvp->next){ if (cvp->media == (tapelist_pt) NULL){ sprintf(buf,"Volume %s has no media information!\n", cvp->v_name); d108 9 a116 12 } /* * Check to see if this volume is on the same media as * the previous. If the internal id's are different, then * we must request a mount of a new media */ if (memcmp(&curr_id, &(cvp->media->internal), sizeof(media_id_t))){ /* * reset the restore error state for this media */ restore_error = 0; d118 2 a119 1 * mount needed a120 8 memcpy(&curr_id, &(cvp->media->internal), sizeof(media_id_t)); while((code = cycle_through_tapes(dh, jobid, vp->media->extern_id, (media_id_pt) &curr_id, ABS_VALID_MEDIA)) == ABS_INVALID_MEDIA_ID){ /* * keep trying until the guy mounts something we * can actually use. We are looking for a specific tape. */ d122 7 a128 7 if (last_requested == 0){ code = request_service(jobid, ABS_TAPE_MOUNT_REQ, cvp->media->extern_id); last_requested = 1; }else last_requested = 0; sleep(ABS_MOUNT_INTERVAL); d131 7 a137 21 if (code){ /* * A serious error, possibly a device error which * can't be fixed has occurred. */ return(code); } /* * Advance past the label and position at the beginning * of the first volume header on the tape. */ code = SLAVE_NEXT_RECORD(dh, 1); fileno=1; } else { /* does not need mount */ if (restore_error != 0){ /* Mark the rest of the volumes on this medium as * having an error for the restore operation. */ cvp->v_status = restore_error; continue; } d139 15 d159 1 a159 1 for (fileno; fileno < cvp->media->position; fileno++){ d270 1 a270 1 code = FS_RESTORE(fsp, handlep, dh, cvp, jobid, params, &needs_rewind); d329 1 @ 3.6 log @Restore now returns results to the master when the job is canceled @ text @d4 1 a4 1 #include @ 3.5 log @autolabel baseline @ text @d259 1 a259 2 if (code == ABS_JOB_CANCELED || get_slave_state() == SLAVE_TERMINATED){ d262 6 d270 6 @ 2.3 log @Support graceful termination with SIGTERM @ text @@ 2.2 log @Change NEXT_CONTROL_REC macro and replace with NEXT_VOLHEADER or NEXT_VOLFOOTER. Also fix find_control_rec so that backupward spacing to the previous control rec will now work @ text @d259 5 a263 3 if (code == ABS_JOB_CANCELED){ slave_log_error(ABS_ERROR, "do_restore", "Job canceld at user's request\n"); break; a303 3 if (code == ABS_JOB_CANCELED){ break; } @ 2.1 log @alpha release @ text @d187 1 a187 1 code = NEXT_CONTROL_REC(dh); d293 1 a293 1 code = PREV_CONTROL_REC(dh); d312 8 a320 3 job_stat->vols_processed++; job_stat->bytes_processed += cvp->v_size; } d325 4 a328 1 fileno++; @ 1.7 log @Check  point for code review @ text @d38 1 a38 1 int code, media_errors, retries, needs_rewind; d65 1 a65 1 media_errors = 0; d177 2 a178 2 media_errors++; if (media_errors > params->media_errors){ d189 2 a190 2 media_errors++; if (media_errors > params->media_errors){ d197 2 a198 2 media_errors++; if (media_errors > params->media_errors){ d281 2 a282 2 media_errors++; if (media_errors > params->media_errors) d306 2 a307 2 media_errors++; if (media_errors > params->media_errors){ @ 1.6 log @handle cancellation requests from the ABSSLAVE interface calls @ text @d135 2 a136 2 code = request_media_mount(jobid, ABS_TAPE_MOUNT_REQ, cvp->media->external); @ 1.5 log @Many changes to the job_done and status reporting interfaces to collect more data for the job reports. @ text @d39 1 a39 1 int percent, total, fileno; d126 3 a128 1 do { d133 10 a142 3 code = cycle_through_tapes(dh, jobid, vp->media->extern_id, (media_id_pt) &curr_id, ABS_VALID_MEDIA); } while(code == ABS_INVALID_MEDIA_ID); d182 4 d193 1 a193 1 } d202 4 d258 5 a262 1 send_status(jobid, cvp->res); d302 3 @ 1.4 log @Change job_done interface to report returning restore results and statisi  stifcs    ics. Kpob    job done now uses a sturcture w         ructure which c has room for job statistics and also ahas      has a union of a dumpset and a volume for returning indif     job resturels      ults. @ text @d39 1 a39 1 int percent, bad, total, fileno, current; d43 1 a43 1 char buf[512]; d47 1 d52 1 d54 1 a54 1 d56 11 a73 1 bad = 0; d83 3 d87 9 d105 1 a105 1 if (vp->media == (tapelist_pt) NULL){ d116 6 a121 1 if (memcmp,&curr_id, vp->media->internal, sizeof(media_id_t)){ d125 1 a125 1 memcpy(&curr_id, &(vp->media->internal), sizeof(media_id_t)); d146 10 a155 2 current=1; } /* end needs mount */ d161 1 a161 1 for (fileno = current; fileno < cvp->media->position; fileno++){ d167 6 d175 6 d183 6 d190 17 d235 1 a235 1 strcpy(job_stat->current_volume, cvp->v_name); d237 5 a241 5 datep = ctime(&now.tv_sec); strncpy(&job_stat->date, datep, ABS_MAX_DATE); job_stat->date[ABS_MAX_DATE-1]='\0'; job_stat->absvolid_low = cvp->v_id; send_status(jobid, &job_stat); d259 5 a280 1 bad++; d283 4 d296 1 a296 1 current++; @ 1.3 log @Multi-volume restore now works. Because of the tape head positioning, we have to ad read_volume_header and read_volume_footer afsurrounding the calls to NEXT_)CONTROL_REC @ text @d34 2 a35 1 do_restore( dev_handle_t *dh, net_volume_pt vp, int jobid, restore_pt params) a40 1 job_status_t job_stat; d63 1 a63 1 memset(&job_stat, 0, sizeof(job_stat)); d163 1 a163 1 strcpy(job_stat.current_volume, cvp->v_name); d166 3 a168 3 strncpy(&job_stat.date, datep, ABS_MAX_DATE); job_stat.date[ABS_MAX_DATE-1]='\0'; job_stat.absvolid_low = cvp->v_id; d185 1 a185 1 job_stat.failures++; d209 2 a210 2 job_stat.vols_processed++; job_stat.bytes_processed += cvp->v_size; @ 1.2 log @Success at last with restore! @ text @d13 18 a31 4 #define DEQUEUE(curr, prev, newq) { \ prev->next = curr->next; \ curr->next = newq; \ newq = curr; } a32 3 d39 1 a39 1 net_volume_pt cvp, retry, prev, lastvp, bad_vols; d46 1 d53 4 d63 5 d71 9 d112 5 a118 1 d120 2 a121 1 * The correct media is mounted. Seek to the proper position d129 2 d132 3 a134 2 code = NEXT_CONTROL_REC(dh); } d137 4 d145 2 a146 1 /* don't retry unrecoverable things such as d149 1 d154 1 a154 1 * retry the connection; d159 14 d180 1 d184 3 d188 1 a188 1 (code != ABS_CALL_TIMEOUT)) d190 1 d208 4 a211 1 } d213 2 a214 1 * seek past the footer for this volume d216 1 a216 1 code = NEXT_CONTROL_REC(dh); @ 1.1 log @Initial revision @ text @d1 1 d4 1 d23 1 a23 2 do_restore(struct dev_table *devp, dev_handle_t *dh, net_volume_pt vp, job_pt jp, rest_params_pt params) d26 2 a27 6 int code, media_errors, retries; int percent, bad, total; d36 3 d47 3 d51 6 d72 1 a72 1 code = cycle_through_tapes(dh, jp, vp->media->extern_id, d82 1 a82 1 a84 1 for(retries = 0; retries < params->retries; retries ++){ d89 10 a98 6 code = SLAVE_SEEK(dh, vp->media->position, SEEK_SET); if (code){ /* * handle weird device errors */ } d100 1 a100 1 (char *)NULL, &code); d115 7 a121 2 code = FS_RESTORE(fsp, handlep, dh, cvp, params); d128 8 a135 1 } /* end for retries */ d140 1 a140 2 vp->v_status = code; if (code){ d145 5 a149 2 } @ slave/RCS/dump.c,v100444 6031 145 147505 6242357435 13411 0ustar delgadoorawebhead 6.0; branch ; access ; symbols autolabel-baseline:3.5 alpha:2.1; locks delgado:6.0; strict; comment @ * @; 6.0 date 96.11.06.10.39.46; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.30; author delgado; state Exp; branches ; next 4.0; 4.0 date 96.04.19.11.22.22; author delgado; state Exp; branches ; next 3.8; 3.8 date 96.03.29.10.21.21; author delgado; state Exp; branches ; next 3.6; 3.6 date 96.03.26.20.18.48; author delgado; state Exp; branches ; next 3.5; 3.5 date 96.03.12.12.36.18; author delgado; state Exp; branches ; next 2.6; 2.6 date 96.03.10.17.30.15; author delgado; state Exp; branches ; next 2.5; 2.5 date 96.03.08.15.13.40; author delgado; state Exp; branches ; next 2.4; 2.4 date 96.03.08.12.23.03; author delgado; state Exp; branches ; next 2.3; 2.3 date 96.03.06.16.00.15; author delgado; state Exp; branches ; next 2.2; 2.2 date 96.02.23.14.49.57; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.25.19; author delgado; state Exp; branches ; next 1.10; 1.10 date 96.02.08.13.11.13; author delgado; state Exp; branches ; next 1.9; 1.9 date 96.01.25.16.35.18; author delgado; state Exp; branches ; next 1.8; 1.8 date 96.01.23.13.20.46; author delgado; state Exp; branches ; next 1.7; 1.7 date 96.01.17.13.57.37; author delgado; state Exp; branches ; next 1.6; 1.6 date 96.01.10.11.21.51; author delgado; state Exp; branches ; next 1.5; 1.5 date 96.01.03.17.07.30; author delgado; state Exp; branches ; next 1.4; 1.4 date 95.12.27.11.44.09; author delgado; state Exp; branches ; next 1.3; 1.3 date 95.12.07.12.17.08; author delgado; state Exp; branches ; next 1.2; 1.2 date 95.11.27.21.51.16; author delgado; state Exp; branches ; next 1.1; 1.1 date 95.11.15.14.05.30; author delgado; state Exp; branches ; next ; desc @ Support for dump and restore to AFS servers @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" extern char *device_name; extern char *master_server; #define RETRY_INTERVAL 300 int label_tape_for_dump(dev_handle_t *dh, int jobid); int try_hard_to_write_footer(dev_handle_t *dh, net_volume_t *cvp, int *error_count, int error_max, net_dumpset_t *dp, job_pt jp, abs_label_t *label, dump_params_pt params); int handle_eom(dev_handle_t *dh, job_pt jp, abs_label_t *info, net_dumpset_t *dp, char *verfmode); void set_volume_dump_status(net_volume_t *vp, int status); void mark_tape_log_status(media_t *mp, int threshold); /* * Procedure: do_dump * * Parameters: dh - address of device specific information * dp - address of dumpset information for to be dumped * jp - address of job description info * params - address of job parameters info * * Description: do_dump is the high-level routine which controls the * dump processing for the dumpset represented by "dp". This routine * iterates through all volumes in the dumpset invoking FS_DUMP (filesystem- * specific dump operation) on each volume until all volumes are dumped * successfully or the maximum retry count for each volume is exceeded. * * The master expects the slave to return the following information * after the dump is completed: * - summary of dump statistics (this info is in 2 places * in the "job_stat" structure and in the * dumpstats field of the dumpset. * - status code for each volume dumped (contained in the volume's * "net_volume_t" structure); * * - list of tapes used (returned as part of the dumpset structure) * * - volume to tape mappings; each volume entry will contain informaation * indicating which tape it was successfully written to. This is * to support dumps which consist of multiple tapes. * * * The slave will send a status report to the master before it begins * the dump of a volume. as a result of this status report, the slave * can receive a cancellation request from the master. If the slave * does receive a cancellation request, it will stop the dump at * this time. For canceled jobs, no results are returned to the master. * * On failed volumes, do_dump will attempt to move the device backward * over any data which was written for the failed volume, thus overwriting * the bad data. If the underlying device does not support reverse operation, * the do_dump will add the volume entry to the tape footer block. The tape * footer block is written at the end of the last tape of the dump. */ #define curr_media tape_sets->tapes int do_dump(dev_handle_t *dh, net_dumpset_t *dp, job_pt jp, dump_params_pt params, job_status_pt job_stat) { int code, media_errors, i, rpc_code, fileno; int percent, bad, total, data_written; int abort_job , last_requested=0, scode; net_volume_t *cvp, *retry, *prev, *bad_vols; abs_label_t label; void *handlep; char buf[512]; fs_ops *fsp; struct timeval now; char *datep; float p,t; memset(job_stat, 0, sizeof(job_status_t)); job_stat->total_volumes = dp->nvolumes; if (dp->nvolumes <=0 ) return(ABS_NO_DUMPSET); fsp = get_fs_ops(dp->d_fstype); if (fsp == (fs_ops *) NULL){ set_volume_dump_status(dp->volumes, ABS_INVALID_FSTYPE); return(ABS_INVALID_FSTYPE); } /* * Locate the media item in the specified media device * and validate its internal id with the master. * cycle through will make a best effort to come up with * a tape which we can write on. */ while (( code = cycle_through_tapes(dh, jp->jobid, (char *)NULL, (media_id_pt) NULL, ABS_FREE_MEDIA)) == ABS_INVALID_MEDIA_ID){ /* * Request a mount of something useable */ if (last_requested == 0){ code = request_service(jp->jobid, ABS_TAPE_MOUNT_REQ, NULL); if (code) return(code); last_requested = 1; }else last_requested = 0; sleep(ABS_MOUNT_INTERVAL); } if (code){ if (code != ABS_BLANK_MEDIUM){ set_volume_dump_status(dp->volumes, code); return(code); } code = label_tape_for_dump(dh, jp->jobid); if (code){ set_volume_dump_status(dp->volumes, code); return(code); } } /* * Create Tapeset info for this tape; during the course * of normal operation dp->tapes_sets may have one * or more "tapes" chained off of it. When a media * chage occurs on end-of-medium, the slave executes * a checkpoint, which causes the data for that tape * to be sent to the master. IF the checkpoint fails, * the slave will keep the tape entry and its data around * and send it the next time that a check point occurs * or at the end of this job. * * New media entries are added at the beginning of the list. * * "curr_media" is a shorthand for dp->tape_sets->tapes */ dp->tape_sets = (tapeset_t *) malloc(sizeof(tapeset_t)); if (dp->tape_sets == (tapeset_t *) NULL){ return(ABS_NO_MEM); } memset(dp->tape_sets, 0 , sizeof(tapeset_t)); dp->curr_media = (media_pt)malloc(sizeof(media_t)); if (dp->curr_media == (media_pt)NULL){ free(dp->tape_sets); dp->tape_sets = (tapeset_t *) NULL; return(ABS_NO_MEM); } memset(dp->curr_media, 0, sizeof(media_t)); /* * Read the current label information to get the * static info from the label */ code = SLAVE_REWIND(dh); if (code){ set_volume_dump_status(dp->volumes, code); return(code); } if ((code = read_label(dh, &label))){ set_volume_dump_status(dp->volumes, code); return(code); } /* * save the internal id info for this tape in the tapeset entry */ memcpy(&dp->curr_media->internal, &label.tapeid, sizeof(media_id)); dp->curr_media->log_tape = 1; dp->curr_media->total_vols = 0; dp->curr_media->bad_vols = 0; /* * modify the label fields which change with each dump; */ gettimeofday(&now); label.block_size = dh->bufsize; label.level = params->dump_from; label.uses++; label.sequence = 1; dp->tape_sets->date_dumped = now.tv_sec; label.tape_created = now.tv_sec; strncpy(&label.cell, dp->d_cell, ABS_MAX_DOMAIN); strncpy(&label.dumpset, dp->d_name, ABS_MAX_DNAME); /* * Write the new label to the medium; Also writes an EOF marker. */ code = SLAVE_REWIND(dh); if (code){ set_volume_dump_status(dp->volumes, code); return(code); } if ((code = write_label(dh, &label))){ set_volume_dump_status(dp->volumes, code); return(code); } /* * Start out with all volumes on the retry list. Move them * to dp->curr_media->volumes as they complete successfully. We * stop when the retry list is empty or when we have exceeded * the maximum number of retries defined in the dumpset structure. */ bad_vols = (net_volume_t *) NULL; retry = dp->volumes; dp->volumes = (net_volume_t *) NULL; prev = (net_volume_t *) NULL; bad = media_errors = 0; gettimeofday(&now); datep = ctime(&now.tv_sec); strcpy(dp->dumpstats.start, datep); dp->dumpstats.ntapes = 1; dp->dumpstats.bytes_processed = 0; fileno=1; abort_job = 0; if (dp->d_retry <= 0 ) dp->d_retry = 1; sprintf(buf,"Starting dump of dumpset %s, level %d\n", dp->d_name, dp->dumpstats.level); slave_log_error(ABS_INFORMATIONAL,"do_dump", buf); /* * the big Loop */ for (i = 0; i< dp->d_retry; i++){ if (abort_job) break; for(cvp = retry; cvp != (net_volume_t *)NULL;){ if (abort_job) break; if (i > 0) sleep(RETRY_INTERVAL); /* * Get a connection to this server which hosts the * volume. */ sprintf(buf,"Connecting to Server %s",cvp->v_server); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); handlep = FS_CONNECT(fsp, cvp->v_server, dp->d_cell, (char *)NULL, &code, ABS_BACKUP_OP); if (handlep == (void *) NULL){ sprintf(buf,"Failed to Connect to %s",cvp->v_server); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); cvp->v_status = ABS_FS_CONNECT; prev = cvp; cvp = cvp->next; job_stat->failures++; continue; } /* * Send a quick status report to the master telling * it which volume we are about to dump. This is * necessary because dump jobs are quite lengthy and * the Slave isn't threaded, so it can't accept status * queries while the job is running */ strcpy(job_stat->current_volume, cvp->v_name); gettimeofday(&now); job_stat->date = now.tv_sec; sprintf(buf,"Dumping volume %s, retry = %d\n",cvp->v_name, i); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); code = send_status(jp->jobid, job_stat); if (code == ABS_JOB_CANCELED || get_slave_state() == SLAVE_TERMINATED){ /* * We've been requested to stop our work at the * next convenient point. Here is a good place * to stop; we do not return any results if * we are canceled. */ if (retry != (net_volume_t *) NULL) abs_free_netvol(retry); if (bad_vols != (net_volume_t *) NULL) abs_free_netvol(retry); if (code == ABS_JOB_CANCELED) slave_log_error(ABS_INFORMATIONAL, "do_dump", "Job cancel received"); else{ slave_log_error(ABS_INFORMATIONAL, "do_dump", "slave termination received"); } return(ABS_JOB_CANCELED); } data_written = 0; code = FS_DUMP(fsp, handlep, dh, params->dump_from, jp, cvp, &data_written, &label, params); /* * Sort through the error codes. Those which are * deemed recoverable indicate that the volume should * be retried later (comm failure, call timeout, auth * failures). Those which are unrecoverable will not * be retried (volume does not exist on server, is * damaged or protocol version mismatch). */ sprintf(buf,"Finished volume %s, code = %d\n",cvp->v_name, code); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); if (code || cvp->v_status){ job_stat->failures++; if (code == ABS_EOM_DETECTED){ /* * Reverse one record and write volume footer * */ scode = SLAVE_NEXT_RECORD(dh, -1); if (scode == 0) write_volume_footer(dh, cvp, code); /* * handle eom will worry about dismounting * the current tape and asking for a new one * It also fills in the label information for * the newly mounted tape; it also executes * a checkpoint which may change the value * of dp->tape_sets->tapes. */ code = handle_eom(dh, jp, &label, dp, params->verf_mode); if (code){ /* * we were unable to properly deal with end of medium */ slave_log_error(ABS_FATAL, "do_dump", "unable to handle End of Medium situation - Dump Aborted"); goto dump_cleanup; } dp->dumpstats.ntapes++; /* * redo this volume - don't advance the cvp pointer */ continue; }else if (code == ABS_MEDIA_ERROR){ /* * We abort if the media error threshold has been * exceeded. If the threshold is not exceeded * Then a footer will be written by the code * following this if statement. */ media_errors++; slave_log_error(ABS_ERROR,"do_dump","Media errors on device"); if (media_errors > params->media_errors){ /* * This tape is bad. Set "log_tape" to false * so the info for this tape does not get * logged in the database */ dp->curr_media->log_tape = 0; goto dump_error; } }else if (UNRECOVERABLE(code)){ /* * Remove from retry queue and * place volume on bad list */ bad++; if (prev){ prev->next = cvp->next; cvp->next = bad_vols; bad_vols = cvp; cvp = prev->next; } else{ retry=retry->next; cvp->next = bad_vols; bad_vols = cvp; cvp = retry; } job_stat->failures++; code = try_hard_to_write_footer(dh, cvp, &media_errors, params->media_errors, dp, jp, &label, params); if (code != 0 && code != ABS_EOM_DETECTED){ slave_log_error(ABS_ERROR, "do_dump", "Dump aborted due to media/device errors"); goto dump_cleanup; } continue; } /* else EOM */ /* * This volume will be retried later */ prev = cvp; cvp = cvp->next; if (data_written){ dp->curr_media->bad_vols++; /* * If something was written to the tape, try to backup * to the previous file mark. If the devices does not * support this type of operation, then create a bad * volume entry in the volume summary table. */ #ifdef REVERSE code = SLAVE_NEXT_FILE(dh, -1); if (code){ fileno++; } #else /* * Write a volume footer indicating that this volume * is bad */ code = try_hard_to_write_footer(dh, cvp, &media_errors, params->media_errors, dp, jp, &label, params); if (code != 0 && code != ABS_EOM_DETECTED){ slave_log_error(ABS_ERROR, "do_dump", "Dump aborted due to media/device errors"); goto dump_cleanup; } #endif } continue; } /* if code */ /* * we are here because we have successfully dumped the * volume. Increment the total dumped and remove the * the volume from the retry queue */ code = try_hard_to_write_footer(dh, cvp, &media_errors, params->media_errors, dp, jp, &label, params); if (code != 0 && code != ABS_EOM_DETECTED){ slave_log_error(ABS_ERROR, "do_dump", "Dump aborted due to media/device errors"); goto dump_cleanup; } job_stat->vols_processed++; dp->curr_media->total_vols++; /* * The volume must be re-dumped since all of its * data, including the footer must fit on the same tape * Do not advance the cvp pointer. */ job_stat->bytes_processed += cvp->v_size; cvp->position = fileno; fileno++; if (prev){ prev->next = cvp->next; cvp->next = dp->curr_media->volumes; dp->curr_media->volumes = cvp; cvp = prev->next; } else{ retry=retry->next; cvp->next = dp->curr_media->volumes; dp->curr_media->volumes = cvp; cvp = retry; } } /* for cvp */ /* * no more volumes on the retry list - we are done */ if (retry == (net_volume_t *) NULL) break; } /* for retry */ dump_cleanup: mark_tape_log_status(dp->curr_media, dp->d_failthresh); /* * count the volumes which could not be dumped in "dp-d_retry" times * and add it to the total bad volume count */ if (retry != (net_volume_t *) NULL){ for( cvp = retry; cvp->next != (net_volume_t *) NULL; bad++, cvp = cvp->next); } if (bad_vols != (net_volume_t *) NULL){ for( cvp = bad_vols; cvp->next != (net_volume_t *) NULL; cvp = cvp->next); /* * Add the bad volumes back to the dumpset volume chain */ cvp->next = dp->volumes; dp->volumes = bad_vols; } if (bad > 0 ){ /* * Determine whether the fail threshold has been exceeded for this * job */ t = (float) job_stat->total_volumes; p = (float) bad; percent = (int)((p/t) * 100.0); if (percent > dp->d_failthresh){ code = ABS_ERROR_THRESH; } } dp->dumpstats.bytes_processed = job_stat->bytes_processed; dump_error: sprintf(buf,"Finished dump of dumpset %s, status %d - %d of %d volumes dumped\n", dp->d_name, code, job_stat->vols_processed, dp->nvolumes); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); gettimeofday(&now); datep = ctime(&now.tv_sec); strcpy(dp->dumpstats.stop, datep); return(code); } /* * Cycle through all the media items on the device looking * for the specified item * Search by (for devices that support * scanning the external label) * - medium with matching internal id * - any medium with valid abs label * - any medium * * */ int cycle_through_tapes(dev_handle_t *dh, int jobid, char *extid, media_id_pt mip, int valid) { int code, rpc_code; char buf[512]; abs_label_t abs_label; dev_table_t *dp = dh->dev_ops; /* * Find a tape with matching the caller's selection critera. * This can be a match by id, by * internal id only, or by any tape with valid abs label or * any tape * */ code = 1; while (code != 0){ /* * loop through allof the media on the device. For * single cartrige tape systems this funciton is a no-op * for multi-cartridge systems, the device dependent routine * is responsible for informing the master if the a media * mount is required */ code = SLAVE_NEXT_MEDIA(dh, extid, mip, valid); if (code){ /* fatal, unrecoverable error */ sprintf(buf, "Media/Device errors from device %s \n", device_name); slave_log_error(ABS_FATAL,"do_dump", buf); return(code); } } if ((mip == (media_id_pt) NULL) && (valid != 0)){ /* * For valid !=0 we must validate the tape with the * master. First we call validate_label telling it that we * are expecting a tape with a valid abs label. * validate_label will try to read the tape and determine * whether the tape meets our expectations (has a valid label). * A null media id is specified when the caller is not looking * for a specific tape; i.e., any labeled tape will do. */ code = validate_label(dh, (media_id_pt)NULL, ABS_VALID_LABEL, &abs_label); if (code) return(code); /* * We now have a tepe whose label appears to be valid. * Request a tape status query from the master to see what state * this tape is in (e.g. VALID, FREE). "code" will actually contain * the tape status inforamtion. */ rpc_code = slave_validate(&abs_label.tapeid, jobid, &code); if (rpc_code) return(rpc_code); if (code == ABS_JOB_CANCELED) return(code); if (code == ABS_INVALID_JOB) return(code); /* * "valid" contains the state which the caller requests (e.g. needs * a free tape, etc). "code " contains the tape's state as * listed in the abs database. */ if (valid != code){ sprintf(buf,"Media validation with master fails, media state = %d, expected %d\n", code, valid); slave_log_error(ABS_WARNING, "cycle_through_tapes", buf); return(ABS_INVALID_MEDIA_ID); } code = 0; } /* * We are here because the medium we wanted is mounted so * Rewind it. */ code = SLAVE_REWIND(dh); if (code){ sprintf(buf, "device %s Rewind failure \n", device_name); slave_log_error(ABS_FATAL,"do_dump", buf); } return(code); } /* * Procedure: perform_media_verification * * Parameters: -dh address of device information * dp - address of dumpset information * verf_mode - verification mode to use * job_stat - address of job status information * jobid - job id assigned by master * * Description: This function closes the media, causing an EOM marker * to be written at the end of the dump data and rewinds the tape. The * tape is then re-opened for read only access. We send a status report * to the master informing it that we are now performing media verification. * We then proceed to call the appropriate media verification function */ int perform_media_verification(dev_handle_t *dh, net_dumpset_t *dp, char *verf_mode, job_status_t *job_stat, int jobid) { int code; abs_label_t label; /* * All modes of verification verify the label, so let's * do it here. */ if (!strcmp(verf_mode, "NONE")) return(0); /* * Tell Master we are verifying the tape */ strcpy(job_stat->current_volume, "VERIFY MEDIA"); code = send_status(jobid, job_stat); code = SLAVE_REWIND(dh); code = SLAVE_CLOSE_PARTIAL(dh); code = SLAVE_OPEN(dh->dev_ops, &dh, dh->devname, O_RDONLY, jobid); if (code) return(code); code = read_label(dh, &label); if (code) return(code); if (!strcmp(verf_mode, "FULL")){ return(slave_full_verification(dh, dp)); }else if (!strcmp(verf_mode, "QUICK")){ return(slave_quick_verification(dh, dp)); }else { return(ABS_INVALID_VERF); } } /* * Procedure: try_hard_to_write_footer * * Parameters: dh - address of device information. * cvp - address of volume information * error_count - address of current media error count * error_max - media error threshold * dp - address of dumpset information * jp - address of job information. * label - address to write label inforamtion. * * Description: This procedure attempts to write a volume footer * using the inforamtion provided by cvp. It will repeatedly attemp * to write the footer until it is successful or the media error threshold * is exceeded, or it detects EOM. IF EOM is detected, it will request * a mount of a new tape and return an error code indicating so. * * In the case of EOM, we do not attempt to write a footer on the new * tape since volumes are not allowed to span tapes. * * Modifies: label, only if a new tape is mounted * dp->tapesets , only if a new tape is mounted * * Memory allocation: memory allocated to dp will be freed by the RPC * when the dump service routine completes. */ int try_hard_to_write_footer(dev_handle_t *dh, net_volume_t *cvp, int *error_count, int error_max, net_dumpset_t *dp, job_pt jp, abs_label_t *label, dump_params_pt params) { int code; media_t *mp; do { code = write_volume_footer(dh, cvp, cvp->v_status); if (code == ABS_MEDIA_ERROR) *error_count = *error_count +1; }while(code == ABS_MEDIA_ERROR && *error_count <= error_max); if (code == 0) return(code); if (code == ABS_MEDIA_ERROR){ slave_log_error(ABS_ERROR,"try_hard_to_write_footer", "Media errors on device"); return(code); } if (code == ABS_EOM_DETECTED){ code = handle_eom(dh, jp, label, dp, params->verf_mode); if (code){ /* * we were unable to properly deal with end of medium */ slave_log_error(ABS_FATAL, "try_hard_to_write_footer", "unable to handle End of Medium situation - Dump Aborted"); return(code); }else{ dp->dumpstats.ntapes++; /* * So that the caller knows the footer could not * be written on the same tape; */ return(ABS_EOM_DETECTED); } } return(code); } /* * Procedure: label_tape_for_dump * * Parameters: dh -address of device information * jobid - job id assigned by master for this job * * Description: This functionr equ3ests the master to generate * an internal label identifier and proceeds to label the tape * using that internal identifier. */ int label_tape_for_dump(dev_handle_t *dh, int jobid) { media_id_t mip; int code; /* * Get an intenal label from the master */ code = request_internal_label(jobid, &mip); if (code) return(code); code = slave_label_medium(NULL, dh, NULL, &mip); return(code); } /* * Procedure: set_volume_dump_status * * Parameters: vp - address of linked list of volume structures * status - status code * * Description: This function sets the status code of each * volume in the linked list to "status" * * Modifies: "v_status" field of each volume in list */ void set_volume_dump_status(net_volume_t *vp, int status) { net_volume_t *cvp; for (cvp = vp; cvp != (net_volume_t *)NULL; cvp = cvp->next){ cvp->v_status = status; } } void mark_tape_log_status(media_t *mp, int threshold) { float t, b; int percent; t = (float) mp->total_vols; b = (float) mp->bad_vols; percent = (int)((b/t) * 100.0); if (percent > threshold){ mp->log_tape = 0; } } @ 5.0 log @remove fakeslave names @ text @d18 2 a19 1 net_dumpset_t *dp, job_pt jp, abs_label_t *label); d21 4 d28 3 d184 3 a186 1 d221 1 d334 1 a334 1 code = handle_eom(dh, jp, &label, dp); d359 6 d387 1 a387 1 params->media_errors, dp, jp, &label); d402 1 d420 1 a420 1 params->media_errors, dp, jp, &label); d436 1 a436 1 params->media_errors, dp, jp, &label); d443 1 d477 1 d504 1 a504 1 if (percent > dp->d_failthresh) d506 1 d658 2 d707 2 a708 1 net_dumpset_t *dp, job_pt jp, abs_label_t *label) d728 1 a728 1 code = handle_eom(dh, jp, label, dp); d803 17 @ 4.0 log @"slaveint" changed to "slaveservice" @ text @d8 1 a8 1 extern char *device; d20 3 d64 3 a79 1 media_pt mp; d92 1 d119 1 d123 2 a124 1 if (code) d126 1 d130 13 a142 1 * Create Tapeset info for this tape d149 3 a151 2 dp->tape_sets->tapes = (media_pt)malloc(sizeof(media_t)); if (dp->tape_sets->tapes == (media_pt)NULL){ d156 2 a157 1 memset(dp->tape_sets->tapes, 0, sizeof(media_t)); d163 2 a164 1 if (code) d166 1 d168 2 a169 1 return(code); d175 1 a175 1 memcpy(&dp->tape_sets->tapes->internal, &label.tapeid, sizeof(media_id)); d193 2 a194 1 if (code) d196 2 d200 1 d205 1 a205 1 * to "dp->volume " as they complete successfully. We d210 1 a210 2 retry = dp->volume; dp->volume = (net_volume_t *) NULL; d225 3 d236 1 a237 12 * Create storage to place the information about * which tape this volume is on and its position * on the tape */ if (cvp->media == (tapelist_pt) NULL){ cvp->media = (tapelist_pt) malloc(sizeof(tapelist_t)); if (cvp->media == (tapelist_pt) NULL){ return(ABS_NO_MEM); } memset(cvp->media, 0, sizeof(tapelist_t)); } /* d273 2 a274 2 * Here is a good place to stop. We do not return * any dump results if we are canceled. d319 3 a321 1 * the newly mounted tape d323 1 a323 1 code = handle_eom(dh, jp, &label); a331 8 /* * Allocate another tapeset member */ mp = (media_pt)malloc(sizeof(media_t)); memset(mp, 0, sizeof(media_t)); memcpy(&mp->internal, &label.tapeid, sizeof(media_id_t)); mp->next = dp->tape_sets->tapes; dp->tape_sets->tapes = mp; a429 2 if (code == ABS_EOM_DETECTED) continue; d431 1 a431 1 cvp->media->position = fileno; a432 2 memcpy(&cvp->media->internal, &label.tapeid, sizeof(media_id_t)); d435 2 a436 2 cvp->next = dp->volume; dp->volume = cvp; d441 2 a442 2 cvp->next = dp->volume; dp->volume = cvp; d458 1 d465 2 a466 6 bad++, cvp = cvp->next); /* for ends here */ /* * Add the leftover volumes back to the dumpset volume chain */ cvp->next = dp->volume; dp->volume = retry; d473 2 a474 2 cvp->next = dp->volume; dp->volume = bad_vols; d539 1 a539 1 sprintf(buf, "Media/Device errors from device %s \n", device); d593 1 a593 1 sprintf(buf, "device %s Rewind failure \n", device); d704 1 a704 1 code = handle_eom(dh, jp, label); a712 9 /* * Allocate another tapeset member */ mp = (media_pt)malloc(sizeof(media_t)); memset(mp, 0, sizeof(media_t)); memcpy((void *)(&mp->internal.internal1), (void *)(&label->tapeid.internal1), sizeof(media_id_t)); mp->next = dp->tape_sets->tapes; dp->tape_sets->tapes = mp; d757 22 @ 3.8 log @Slave now supports quick and full verification @ text @d2 1 a2 1 #include d272 1 a272 1 &data_written, &label); @ 3.6 log @support perform_media_Verification @ text @d592 15 d609 2 a610 1 perform_media_verification(dev_handle_t *dh, net_dumpset_t *dp, char *verf_mode) d622 6 d645 1 d647 1 d649 22 a670 3 * What can happen when we try to write a volume footer? * MEDIA/DEVICE errors - try writing until max_tries exceeded. * EOM - d727 13 @ 3.5 log @autolabel baseline @ text @d13 1 a14 1 d112 7 a118 1 return(code); d594 1 a594 1 perform_media_verification(dev_handle_t *dh, net_dumpset_t *dp) d597 2 d600 21 a620 1 return(0); d682 18 @ 2.6 log @Support graceful termination with SIGTERM @ text @@ 2.5 log @try_hard_to_write_footer needs to handle the EOM case @ text @d241 2 a242 1 if (code == ABS_JOB_CANCELED){ d253 9 a261 2 slave_log_error(ABS_INFORMATIONAL, "Job cancel received", buf); return(code); @ 2.4 log @Incorporate code reivew comments and simplify code with respect to cancellation handling. @ text @d14 1 d16 3 a18 2 try_hard_to_write_footer(dev_handle_t *dh, net_volume_t *cvp, int *error_count, int error_max); a19 1 d305 1 a305 1 * redo this volume d340 7 a346 1 write_volume_footer(dh, cvp, code); d373 2 a374 2 params->media_errors); if (code){ a378 1 a379 1 d389 2 a390 2 params->media_errors); if (code){ a394 1 d396 7 d526 6 a531 3 * master. The master will return the status of the * tape which should match valid ("valid" contains the * expected result) d539 3 a541 1 * Find out if the master has this tape in its database d551 5 d596 2 a597 1 int *error_count, int error_max) d600 1 d602 1 d608 34 a641 6 if (code){ if (code == ABS_MEDIA_ERROR){ slave_log_error(ABS_ERROR,"do_dump","Media errors on device"); } if (code == ABS_EOM_DETECTED){ } @ 2.3 log @handlafter a dump is completed, the code which addes s the bad list and the retry list to the dp->d_volume list to send back result list was incorrect and resulted in dropping some volumes from the list. @ text @a12 4 #define DEQUEUE(curr, prev, newq) { \ prev->next = curr->next; \ curr->next = newq; \ newq = curr; } d14 5 d33 21 d61 1 a61 1 do_dump(dev_handle_t *dh, net_dumpset_pt dp, d68 1 a68 1 net_volume_pt cvp, retry, prev, bad_vols; d155 1 a155 1 strncpy(&label.dumpset, dp->d_name, ABS_MAX_DOMAIN); d172 1 a172 1 bad_vols = (net_volume_pt) NULL; d174 2 a175 2 dp->volume = (net_volume_pt) NULL; prev = (net_volume_pt) NULL; d177 1 d192 1 a192 1 for(cvp = retry; cvp != (net_volume_pt)NULL;){ d244 2 a245 1 * to stop d247 7 a253 1 break; d282 2 d290 3 a292 2 abort_job = 1; break; d310 4 a313 2 * For now we abort on media errors - Is there * anything else which can be done? d361 14 a374 2 write_volume_footer(dh, cvp, code); #endif d383 8 a390 1 write_volume_footer(dh, cvp, code); a411 2 if (code == ABS_JOB_CANCELED) break; d415 1 a415 1 if (retry == (net_volume_pt) NULL) d418 4 a421 8 if (code == ABS_JOB_CANCELED){ if (retry != (net_volume_t *) NULL) abs_free_netvol(retry); if (bad_vols != (net_volume_t *) NULL) abs_free_netvol(retry); slave_log_error(ABS_INFORMATIONAL, "Job cancel received", buf); return(code); } d427 1 a427 1 for( cvp = retry; cvp->next != (net_volume_pt) NULL; d436 1 a436 1 for( cvp = bad_vols; cvp->next != (net_volume_pt) NULL; cvp = cvp->next); d463 1 a463 1 return(code); d559 1 a559 1 perform_media_verification(dev_handle_t *dh, net_dumpset_pt dp) d566 6 d573 23 @ 2.2 log @Fix problem with linked list manipulations in do_dump  @ text @d54 1 d366 8 d378 2 a379 2 if (retry != (net_volume_pt) NULL && code != ABS_JOB_CANCELED){ for( cvp = retry, bad=1; cvp->next != (net_volume_pt) NULL; d381 3 a383 9 { float p,t; t = (float) job_stat->total_volumes; p = (float) bad; percent = (int)((p/t) * 100.0); } /* * Add the bad volumes back to the dumpset volume chain */ d385 1 a385 3 dp->volume = cvp; }else{ percent = 0; d387 1 a387 1 if (bad_vols != (net_volume_pt) NULL){ d389 3 a391 3 /* * Add the bad volumes back to the dumpset volume chain */ d393 1 a393 1 dp->volume = cvp; d395 12 a406 13 /* * If we've exceeded the failure threshold for this dumpset, then * the whole dump is considered bad, and the tape content information * won't be logged in the Master's database */ if (percent > dp->d_failthresh || code == ABS_JOB_CANCELED){ if (code != ABS_JOB_CANCELED) code = ABS_ERROR_THRESH; abs_free_netvol(retry); abs_free_netvol(dp->volume); dp->volume = (net_volume_pt)NULL; } dp->dumpstats.bytes_processed = job_stat->bytes_processed; @ 2.1 log @alpha release @ text @d289 16 a304 11 bad++; if (prev){ DEQUEUE(cvp, prev, bad_vols); cvp = prev->next; }else { DEQUEUE(cvp, retry, bad_vols); cvp = retry; } job_stat->failures++; write_volume_footer(dh, cvp, code); continue; d343 4 a346 2 DEQUEUE(cvp, prev, dp->volume); cvp = prev->next; d354 1 @ 1.10 log @Fix loop forever problem caused when a job cancelation notice is issued during a media mount request. basically validate tape was overwriting the error code which was returned from the Master telling it to cancel the job @ text @@ 1.9 log @handle cancellation requests from the ABSSLAVE interface calls @ text @d45 1 a45 1 int abort_job , last_requested=0; d78 3 a80 1 code = request_media_mount(jp->jobid, ABS_TAPE_MOUNT_REQ, NULL); d128 3 a130 1 dp->tape_sets->date_dumped = label.tape_created = now.tv_sec; d157 1 a157 1 dp->dumpstats.bytes_dumped = 0; d244 3 d260 9 a268 1 d336 1 a336 12 if (memcmp(&dp->tape_sets->tapes->internal, &label.tapeid, sizeof(media_id_t))){ /* * a new tape was mounted */ mp = (media_pt)malloc(sizeof(media_t)); memset(mp, 0, sizeof(media_t)); memcpy(&mp->internal, &label.tapeid, sizeof(media_id_t)); mp->next = dp->tape_sets->tapes; dp->tape_sets->tapes = mp; dp->dumpstats.ntapes++; } a346 4 /* * TBD - Check for things like a system shutdown request between * volumes and abort the dump gracefully */ d361 1 a361 1 if (retry != (net_volume_pt) NULL || code != ABS_JOB_CANCELED){ d398 1 a398 1 dp->dumpstats.bytes_dumped = job_stat->bytes_processed; d475 4 @ 1.8 log @Add calls to request_media_mount to request a tape mount if cycle_through_tapes finds that the correct tape is not in the drive @ text @d211 9 a219 1 send_status(jp->jobid, job_stat); d349 2 a350 1 d361 1 a361 1 if (retry != (net_volume_pt) NULL){ d363 1 a363 1 bad++, cvp = cvp->next); d377 1 a377 1 } d391 3 a393 3 if (abort_job == 0){ if (percent > dp->d_failthresh){ code = ABS_ERROR_THRESH; d397 1 a397 2 } } @ 1.7 log @Many changes to the job_done and status reporting interfaces to collect more data for the job reports. @ text @d45 1 a45 1 int abort_job; d55 4 a64 1 memset(job_stat, 0, sizeof(job_status_t)); d77 6 a153 2 job_stat->total_volumes = dp->nvolumes; job_stat->vols_processed = job_stat->failures = 0; a311 1 dp->dumpstats.bytes_dumped += cvp->v_size; d390 2 @ 1.6 log @Change job_done interface to report returning restore results and statisi  stifcs    ics. Kpob    job done now uses a sturcture w         ructure which c has room for job statistics and also ahas      has a union of a dumpset and a volume for returning indif     job resturels      ults. @ text @d115 1 a115 1 label.level = params->level; d117 1 a117 1 dp->tape_sets->date_written = label.tape_created = now.tv_sec; d201 1 a201 4 datep = ctime(&now.tv_sec); strncpy(&job_stat->date, datep, ABS_MAX_DATE); job_stat->date[ABS_MAX_DATE-1]='\0'; job_stat->absvolid_low = cvp->v_id; d204 1 a204 1 send_status(jp->jobid, &job_stat); d206 1 a206 1 code = FS_DUMP(fsp, handlep, dh, params->level, jp, cvp, @ 1.5 log @Success at last with restore! @ text @d40 1 a40 1 job_pt jp, dump_params_pt params) d46 1 a46 2 net_volume_pt cvp, retry, prev, lastvp, bad_vols; job_status_t job_stat; a49 1 long amount; d61 1 a61 1 memset(&job_stat, 0, sizeof(job_status_t)); d145 2 a146 2 job_stat.total_volumes = dp->nvolumes; job_stat.vols_processed = job_stat.failures = 0; d188 1 a188 1 job_stat.failures++; d199 1 a199 1 strcpy(job_stat.current_volume, cvp->v_name); d202 3 a204 3 strncpy(&job_stat.date, datep, ABS_MAX_DATE); job_stat.date[ABS_MAX_DATE-1]='\0'; job_stat.absvolid_low = cvp->v_id; d222 1 a222 1 job_stat.failures++; d270 1 a270 1 job_stat.failures++; d304 2 a305 1 job_stat.vols_processed++; a344 2 dp->dumpstats.failures = job_stat.failures; dp->dumpstats.success = job_stat.vols_processed; d354 1 a354 1 t = (float) job_stat.total_volumes; d389 1 a389 1 dp->d_name, code, job_stat.vols_processed, dp->nvolumes); @ 1.4 log @Tape format was changed to dispense with the media footer and use a volume footer for each volume @ text @d71 1 a71 1 while (( code = cycle_through_tapes(dh, jp, (char *)NULL, d183 1 a183 1 (char *)NULL, &code); d413 1 a413 1 cycle_through_tapes(dev_handle_t *dh, job_pt jp, d461 1 a461 1 rpc_code = slave_validate(&abs_label.tapeid, jp->jobid, @ 1.3 log @checkpoint for code review @ text @a5 1 #include "foot.h" d11 1 d45 1 a52 3 vol_summary_t *vsp; abs_footer_t foot; footer_block_t fb; d55 1 a62 2 memset(&foot, 0, sizeof(abs_footer_t)); memset(&fb, 0, sizeof(fb)); d71 7 a77 8 do { /* * keep trying until the guy mounts something we * can actually use */ code = cycle_through_tapes(dh, jp, (char *)NULL, (media_id_pt) NULL, ABS_FREE_MEDIA); } while(code == ABS_INVALID_MEDIA_ID); d120 2 a121 2 strncpy(label.cell, dp->d_cell, ABS_MAX_DOMAIN); strncpy(label.dumpset, dp->d_name, ABS_MAX_DOMAIN); d143 2 a144 1 dp->dumpstats.start = now.tv_sec; d146 1 d148 1 a148 1 job_stat.vols_processed = 0; d150 1 d157 2 d160 4 d190 1 d203 3 a205 1 job_stat.date = now.tv_sec; d221 2 d224 2 a225 1 if (code == ABS_MEDIA_ERROR){ d227 24 d273 1 d275 2 a276 1 } a279 1 job_stat.failures++; d289 2 a290 1 code = SLAVE_NEXT_FILE(dh, -1); a292 6 add_to_vol_summary(&fb, cvp); /* * Write the end of filemarker to separate * this volume from the next */ code = SLAVE_EOF(dh); d294 3 d299 1 a299 1 } d305 1 d309 1 d321 1 a321 1 d326 1 a326 1 } a333 6 * Write the end of filemarker to separate * this volume from the next */ code = SLAVE_EOF(dh); /* d338 2 a339 1 } d345 3 a347 1 } d353 1 a353 1 for( cvp = retry; cvp->next != (net_volume_pt) NULL; d355 6 a360 1 percent = (int)((bad/(job_stat.total_volumes)) * 100); d382 6 a387 14 if (percent > dp->d_failthresh){ code = ABS_ERROR_THRESH; abs_free_netvol(retry); }else{ /* * Write the footer */ code = write_footer(dh, &fb); /* * Write the final eof marker to signal the logical end of * medium */ code = SLAVE_EOF(dh); if (code){ d389 1 a389 1 } d395 2 a396 1 dp->dumpstats.stop = now.tv_sec; @ 1.2 log @Checkpoint; we have successfully dumped an AFS volujme    ume @ text @d1 1 d18 20 a37 1 d39 1 a39 1 do_dump(struct dev_table *devp, dev_handle_t *dh, net_dumpset_pt dp, d43 1 a43 1 int code, media_errors, i, rpc_code, volumes; d55 1 a55 1 d58 1 a58 1 if (dp->nvolumes <=0 ) d66 1 a66 12 /* * Estimate how much space will be consumed by * the volume headers and tape footer in the * worst case. Use this along with the tape capacity * to estimate how much space is available for writing * volume data to the tape. */ amount = sizeof(abs_volheader_t) * dp->nvolumes * dp->d_retry + sizeof(abs_label_t) + (dp->nvolumes * sizeof(vol_summary_t))+ sizeof(abs_footer_t); memset(&job_stat, 0, sizeof(job_status_t)); job_stat.total_volumes = dp->nvolumes; d81 1 a81 1 } while(code == ABS_INVALID_MEDIA_ID); d86 15 d111 1 a111 1 * modify the fields which change with each dump; d113 6 d123 1 a123 1 label.tape_created = now.tv_sec; d142 1 a145 1 d149 3 d160 12 a187 4 strcpy(job_stat.current_volume, cvp->v_name); gettimeofday(&now); job_stat.date = now.tv_sec; job_stat.absvolid_low = cvp->v_id; d195 4 d203 2 a204 2 code = FS_DUMP(fsp, handlep, dh, params->level, cvp, &data_written); job_stat.vols_processed++; a223 6 }else if (code == ABS_MEDIA_OVERRUN){ slave_log_error(ABS_ERROR,"do_dump","media overrun detected"); code = media_overrun(devp, dh); if (code) goto dump_error; dp->dumpstats.ntapes++; d254 2 a255 1 if (code) d257 6 d271 16 a286 1 volumes++; d302 6 d319 4 a322 4 for( cvp = retry; cvp != (net_volume_pt) NULL; bad++, cvp = cvp->next); percent = (int)((bad/(volumes+bad) * 100)); d324 16 d346 1 d362 1 a362 1 dp->d_name, code, volumes, dp->nvolumes); a398 1 code = SLAVE_NEXT_MEDIA(dh, extid, mip, valid); d400 5 a404 3 * If there is no media mounted then issue a request to the * master. The master will pester the initiator to mount * the tape. d406 1 a406 1 d408 5 a412 10 if (code == ABS_NEEDS_MOUNT){ sprintf(buf,"device %s Needs Media Mount\n",device); slave_log_error(ABS_WARNING,"do_dump", buf); request_media_mount(devp, dh, extid, mip, valid); }else{ /* fatal, unrecoverable error */ sprintf(buf, "Media/Device errors from device %s \n", device); slave_log_error(ABS_FATAL,"do_dump", buf); return(code); } a413 1 } d434 3 a436 1 if (valid != code) d438 1 d458 1 a458 2 perform_media_verification(struct dev_table *devp, dev_handle_t *dh, net_dumpset_pt dp) @ 1.1 log @Initial revision @ text @d1 1 a1 2 #include #include d5 1 d24 1 a24 1 int percent, bad, total; d32 3 d38 2 d44 2 d53 1 a53 1 amount = sizeof(abs_vol_header_t) * dp->nvolumes * dp->d_retry + d76 26 d103 3 a105 3 retry = dp->volume; dp->volume = (net_volume_pt) NULL; prev = (net_volume_pt) NULL; d112 3 a116 1 gettimeofday(&now); d119 2 d135 2 a139 2 sprintf(buf,"Failed to Connect to %s",cvp->v_server); slave_log_error(ABS_INFORMATIONAL, "do_dump", buf); d157 2 a158 1 code = FS_DUMP(fsp, handlep, dh, params->level, cvp); d168 1 a168 2 if (code){ cvp->v_status = code; d170 4 d207 11 d231 3 a233 1 DEQUEUE(cvp, retry, dp->volume); d236 5 d254 2 a255 5 if (volumes > 0){ percent = (int)((volumes/(volumes+bad) * 100)); }else{ percent = 0; } d261 1 a261 1 if (percent < dp->d_failthresh){ d263 13 a275 2 }else code = 0; d343 8 a371 47 } /* * Procedure: send status * * parameters: vp - pointer to volume structure * * Description: Send a status update to the master informing it * of which volume we are currently dumping. This function * requests a UDP connection with "no-wait" mode since we don't * care if the message actually arrives. */ void send_status(int jobid, job_status_pt job_stat) { CLIENT *clnt_handle; struct timeval cv; char buf[512], *msgp; int code; clnt_handle = clnt_create(master_server, ABS_SLAVEINT, ABS_SLVVERS, "ucp"); if (clnt_handle == (CLIENT *) NULL){ clnt_pcreateerror(master_server); slave_log_error(ABS_FATAL, "send_status", "Cannot create connection to Master"); return; } /* * setting timeout to 0 has the effect of just queuing * the request with the master and not waiting for it * to respond. */ cv.tv_sec = 0; cv.tv_usec = 0; clnt_control(clnt_handle, CLSET_TIMEOUT, (char *) &cv); /* * place the status information in "job_stat" and * send it off to the master */ abs_job_status_1(job_stat, jobid, &code, clnt_handle); if (clnt_handle) clnt_destroy(clnt_handle); @ slave/RCS/slave_error.c,v100400 6031 145 5412 6256053633 14703 0ustar delgadoorawebhead 6.0; branch ; access ; symbols alpha:2.1; locks delgado:6.0; strict; comment @ * @; 6.0 date 96.11.06.10.39.59; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.48; author delgado; state Exp; branches ; next 2.2; 2.2 date 96.03.12.12.30.46; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.23.18; author delgado; state Exp; branches ; next 1.1; 1.1 date 95.12.12.09.24.14; author delgado; state Exp; branches ; next ; desc @initial revision @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include #include #include #include #include "../master/abs_msg.h" FILE *logfile; void initialize_slave_log(char *logdir, char *devname) { char *fname; char buf[PATH_MAX]; char msg[2048]; int i; /* * syslog -related stuff */ openlog("abs_slave", LOG_PID|LOG_CONS, LOG_LOCAL2); setlogmask(LOG_UPTO(LOG_ERR)); /* * create/open the slave's private log file * The private logfile name is derived from the device * name with the '/' characters converted to '.' characters. */ if (strlen(logdir)+ strlen(devname) > PATH_MAX -6){ syslog(LOG_CRIT, "Cannot open Slave log file: name too long - Exiting\n"); closelog(); exit(1); } fname = strdup(devname); for (i = 0; i< strlen(fname); i++){ if (fname[i] == '/') fname[i] = '.'; } sprintf(buf,"%s/slave%s",logdir, fname); if ( (logfile = fopen(buf,"w")) == (FILE *) NULL){ sprintf(msg,"Can't open log file %s: %s\n", buf, strerror(errno)); syslog(LOG_CRIT,msg); fputs(stderr,msg); closelog(); exit(1); } } slave_stop_logging() { closelog(); fclose(logfile); } void timestamp(char *timebuf) { struct timeval tv; time_t tval; struct tm tm; gettimeofday(&tv); tval = (time_t)tv.tv_sec; localtime_r(&tval, &tm); sprintf(timebuf,"%.2d-%.2d-%.2d %.2d:%.2d:%.2d ", tm.tm_mday, tm.tm_mon+1, tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); } int slave_log_error(int sev, char *routine, char *msg) { char timebuf[30]; if (logfile != (FILE *) NULL){ timestamp(timebuf); fprintf(logfile, "\n%s %s %s", timebuf, routine, msg); fflush(logfile); } if (sev == ABS_FATAL){ syslog(LOG_ALERT, msg); } } @ 5.0 log @remove fakeslave names @ text @@ 2.2 log @autolabel baseline @ text @d45 1 @ 2.1 log @alpha release @ text @@ 1.1 log @Initial revision @ text @d24 1 a24 1 openlog("abs_slave", LOG_PID|LOG_CONS, LOG_LOCAL0); @ slave/RCS/afs_ops.c,v100400 6031 145 107316 6263010717 14052 0ustar delgadoorawebhead 6.0; branch ; access ; symbols ; locks delgado:6.0; strict; comment @ * @; 6.0 date 96.11.06.10.41.19; author delgado; state Exp; branches ; next 1.1; 1.1 date 96.11.06.10.41.07; author delgado; state Exp; branches ; next ; desc @@ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include #include #include #include #include "../master/abs_msg.h" #include "../master/os_defs.h" #include "private.h" #define __XDR_INCLUDE__ #include #include #include #include #include #include #include #include /* * This is the "rock" thing that is setup by abs_dump and abs_restore; * It is passed to UV_DumpVolume/UV_RestoreVolume and then provided as * a parameter to the transaction handler routines AB_DumpFunc and ABS_RestoreFunc * when AFS is ready to receive/send data from and to the Slave. * This is how AFS requires us to do things. */ struct abs_rock{ dev_handle_t *dh; job_pt jp; int data_written; int data_read; int status; abs_label_t *labelp; unsigned int volsize; media_pt media; abs_volheader_t vh; }; /* * Global variables which keep track of our state with * respect to AFS, RX, etc. These should have locks around * them if the slave is ever threaded. */ short rx_inited; char realm[REALM_SZ]; /* * Data structure for connection management for AFS fileservers. * */ typedef struct afs_conn{ int server_addr; int rx_sec_index; struct abs_rock *rockp; struct rx_securityClass *rxsec; CREDENTIALS cred; KTEXT_ST auth; struct rx_connection *vldb_conns[VLDB_MAXSERVERS]; }afs_conn; static afs_conn dummy; int ABS_RestoreFunc(struct rx_call *call, char *restore_rock); int ABS_DumpFunc(struct rx_call *call, char *dump_rock); int setup_auth_vldb_connection(afs_conn *handlep, char *cellname); int GetServer(char *aname); /* * Note the security index which is passed to UV_SetSecurity is all * hard coded in the AFS sources, so code maintainers must check * that the meaning of the indeces have not changed or our connection * management may cease to work. * */ void * afs_connect(char *host, char *cell, char *id, int *code, int op) { int index, i; struct timeval now; char buf[512]; gettimeofday(&now); /* * Get a tgt for us so that we can run authenticated. * It would be better if there were a refresh thread which * could refresh our credentials for us when they are about * to expire. That way we wouldn't have to litter the code * with "get_tgt" calls every time we need to use a service * which requires us to have credentials. */ if (get_slave_tgt()){ /* * this routine has already logged the error for us */ *code = ABS_AUTH_ERROR; } *code = 0; dummy.server_addr = GetServer(host); if (dummy.server_addr == 0){ *code = ABS_SERVER_NOEXIST; return(NULL); } if (rx_inited == 0){ *code = rx_Init(0); if (*code) return(NULL); rx_inited = 1; *code = krb_get_lrealm(realm, 1); if (*code){ slave_log_error(ABS_ERROR,"afs_connect", "cannot get local realm"); return(NULL); } } if (dummy.rockp == (struct abs_rock *) NULL){ dummy.rockp = (struct abs_rock *) malloc(sizeof(struct abs_rock)); if (dummy.rockp == (struct abs_rock *) NULL){ *code = ABS_NO_MEM; return(NULL); } memset(dummy.rockp, 0, sizeof (struct abs_rock)); } /* * Get authentication information to pass to rx * We don't deal with requests for other realms. */ for(i=0; cell[i] != '\0'; i++){ cell[i] = tolower(cell[i]); } *code = krb_mk_req(&dummy.auth,"afs", cell, realm, &dummy.cred); if (*code == KDC_PR_UNKNOWN){ *code = krb_mk_req(&dummy.auth, "afs", "", realm, &dummy.cred); } if (*code){ sprintf(buf,"failed to get ticket to afs.%s@@%s - Kerberos error %d\n", cell, realm, *code); slave_log_error(ABS_ERROR,"afs_connect",buf); *code = ABS_AUTH_ERROR; return(NULL); } *code = krb_get_cred("afs",cell, realm, &dummy.cred); /* * We have Kerberos tickets to the specified afs service; * now pass the info to RX so that it will send the auth info * on the authenticated RX connection. */ if (*code == 0 ){ dummy.rx_sec_index = 2; dummy.rxsec = (struct rx_securityClass *) rxkad_NewClientSecurityObject(rxkad_clear, &dummy.cred.session, dummy.cred.kvno, dummy.cred.ticket_st.length, dummy.cred.ticket_st.dat); }else{ dummy.rx_sec_index = 0; sprintf(buf,"Kerberos Error code %d while authenticating\n",*code); slave_log_error(ABS_ERROR,"afs_connect", "Could not authenticate to AFS -Running unauthenticated"); dummy.rxsec = (struct rx_securityClass *)rxnull_NewClientSecurityObject(); dummy.rx_sec_index = 0; } /* * Preliminary setup work for the UV_DumpVolume Call */ UV_SetSecurity( dummy.rxsec, dummy.rx_sec_index); if (op == ABS_RESTORE_OP){ *code = setup_auth_vldb_connection(&dummy, cell); } return((void *)&dummy); } /* * Procedure: setup_auth_vldb_connection * * Parameters: handlep - pointer to afs connection information. * cell - pointer to name of cell for which connection is requested * * Modifies: handlep->vld_conns * * Description: This function initializes an authenticated connection * to the VLDB servers for "cell". It uses the afsconf library calls * to read the afs configuration information to locate the addresses * of the VLDB servers for "cell". It then uses the Kerberos * authentication information stored in "handlep" to pass to * "rx_NewConnection" to create an authenticated connection to * each VLDB server in the cell. This setup is necessary for * any VLDB library calls. * * UGLY CODE WARNING: Because we are using the UV_RestoreVolume routines, * they expect that the caller has initialzed the AFS global variable * "cstruct" with the UBIK VLDB connection information. Thus the * external reference below to "cstruct" which does not appear in * our sources but is actually part of the AFS library. We * could avoid this by writing our own version of UV_RestoreVolume, * but that is too much work for now. * */ extern struct ubik_client *cstruct; int setup_auth_vldb_connection(afs_conn *handlep, char *cell) { int i, code; struct afsconf_dir *confdir; struct afsconf_cell info; char buf[512]; confdir = afsconf_Open(AFSCONF_CLIENTNAME); if (confdir == (struct afsconf_dir *) NULL){ slave_log_error(ABS_ERROR,"setup_auth_vldb", "Could not open afs cell conf file\n"); return(ABS_FS_ERROR); } code = afsconf_GetCellInfo(confdir, cell, AFSCONF_VLDBSERVICE, &info); if (code){ sprintf(buf,"Can't get AFS cell info for cell %s\n", cell); slave_log_error(ABS_ERROR,"setup_auth_vldb_conection", buf); } if (info.numServers > VLDB_MAXSERVERS) info.numServers = VLDB_MAXSERVERS; for(i=0; i< info.numServers; i++){ handlep->vldb_conns[i] = rx_NewConnection(info.hostAddr[i].sin_addr.s_addr, info.hostAddr[i].sin_port, USER_SERVICE_ID, handlep->rxsec, handlep->rx_sec_index); } afsconf_Close(confdir); code = ubik_ClientInit(handlep->vldb_conns, &cstruct); if (code){ sprintf(buf," ubik_ClientInit fails for cell %s\n", cell); slave_log_error(ABS_ERROR,"setup_auth_vldb_conection", buf); } return(code); } /* * Function: afs_dump * * Parameters: handle - pointer to server's network connection info * dh - pointer to device-specific state info * level - level of dump * jp - pointer to job info for this job * vp - pointer to net_volume describing volume to be dumped * data_written - flag indicating (on error) whether any data * was written to the medium. * * Description: Perform preliminary tasks preceeding the volume dump * Call UV_DumpVolume (afs library routine) to start a transaction on * the appropriate volserver. ABS_DumpFunc will take care of the * data transfer from the volserver to the media. */ int afs_dump(afs_conn *handle, dev_handle_t *dh, long dump_from, job_t *jp, net_volume_t *vp, int *data_written, abs_label_t *labelp, dump_params_t *params) { int code, partid, dumpid; struct afs_data *fsb; char buf[256]; if (vp->fs_private.fstype != voltype_afs){ sprintf(buf, "bad volume type for %s\n", vp->v_name); slave_log_error(ABS_ERROR, "afs_dump", buf); return(ABS_INVALID_SPEC); } fsb = &vp->fs_private.afs_volume_data; /* * get server partition id from partition name */ partid = afs_partname_to_id(vp->v_part); if (partid < 0){ return(ABS_NO_DEVICE_SPEC); } /* * Setup the abs_rock with data which is needed to * manage the dump operation. This includes the * device-specific info, the job parameters, and * the volume header, which our dump partner, ABS_DumpFunc * will write to the tape. */ handle->rockp->dh = dh; handle->rockp->jp = jp; netvol_to_volheader(vp, &handle->rockp->vh); handle->rockp->vh.fs_volid1 = fsb->afs_rwid; handle->rockp->vh.fs_volid2 = fsb->afs_backid; handle->rockp->data_written = handle->rockp->status = 0; handle->rockp->labelp = labelp; /* * UV_Dumpvolume initiates a transaction with the volserver * to begin the dump. "ABS_DumpFunc" will actually do the * work of reading the volume's data from the network and * writing it to tape. */ if (params->dump_flags == ABS_DUMP_CLONE){ dumpid = fsb->afs_backid; sprintf(buf, "Dump using CLONE %d\n", dumpid); slave_log_error(ABS_INFORMATIONAL, "afs_dump", buf); if (dumpid == 0){ /* * No clone exists for this volume - log an error */ sprintf(buf,"No clone for AFS volume %d %s\n", fsb->afs_rwid, vp->v_name); slave_log_error(ABS_ERROR,"afs_dump", buf); code = ABS_NO_CLONE; vp->v_status = ABS_NO_CLONE; *data_written = 0; return(code); } }else{ dumpid = fsb->afs_rwid; sprintf(buf, "Dump using RW %d\n", dumpid); slave_log_error(ABS_INFORMATIONAL, "afs_dump", buf); } code = UV_DumpVolume(dumpid, handle->server_addr, partid, dump_from, ABS_DumpFunc, handle->rockp); if (code == -1){ /* error writing to tape - the actual ABS error * is stored in the rock */ if (handle->rockp->status != 0) code = handle->rockp->status; else code = ABS_COMM_FAILURE; }else if (code == 0){ /* * success - update size for this volume */ LLSET(vp->v_size, handle->rockp->vh.size_high, handle->rockp->vh.size_low ); }else { /* * Map any non-abs errors from AFS or RX to an abs error. */ code = map_afs_errors(code); } vp->v_status = code; *data_written = handle->rockp->data_written; return(code); } /* * Procedure: afs_restore * * Parameters: handlep - pointer to afs connection and other information * specific to this restore operation. * dh - pointer to device-specific information. * params - pointer to restore operation paramters. * vp - pointer to volume info for volume to be restored. * do_rewind - integer indicating whether any data from the * tape was actually read. * * Modifies: handlep, vp, do_rewind * * Description: This function initiates a restore operation with * the indicated server to restore a single volume. Upon entry * the media is positioned at the start of the volume header for * the volume to be restored. This function will read the volume * header and ensure it corresponds to the volume information indicated * by "vp". This function will also check if the volume currently * exists in the AFS VLDB and on the specified server before * initiating the restore operation with the server. If the volume * is found to exist on the server and the overwrite flag is not set, * the the operation will be aborted, otherwise, the restore operation * will be initiated with the appropriate AFS server. * * This function specifies ABS_RestoreFunc as the function for * UV_RestoreVolume to call to handle the actual reading of the * volume data from the media. UV_RestoreVolume is an AFS library * function. */ int afs_restore(afs_conn *handlep, dev_handle_t *dh, net_volume_pt vp, media_t *mp, job_pt jp, restore_pt params, int *do_rewind) { int code, partid, server_addr, noval; int volid, overwrite, len, tape_code = 0; struct afs_data *fsb; struct nvldbentry vent; struct volintInfo *volent; char *server, *part; abs_volheader_t vh; abs_volfooter_t vf; char buf[1024]; struct diskPartition diskp; *do_rewind = 0; if (vp->fs_private.fstype != voltype_afs){ sprintf(buf, "bad volume type for %s\n", vp->v_name); slave_log_error(ABS_ERROR, "afs_restore", buf); return(ABS_INVALID_SPEC); } fsb = &vp->fs_private.afs_volume_data; /* * Get the volume id, destination server, * destination partition and destination volume name. */ if (strlen(params->dest_host) > 0){ server = params->dest_host; }else server = vp->v_server; if (strlen(params->dest_dev) > 0) part = params->dest_dev; else part = vp->v_part; /* * get server AFS partition id from partition name */ partid = afs_partname_to_id(part); if (partid < 0){ return(ABS_NO_DEVICE_SPEC); } /* * get server address from server name */ server_addr = GetServer(server); if (server_addr == 0){ return(ABS_SERVER_NOEXIST); } /* * Read the volume header from the media. The media * is already positioned at the correct offset for this * volume */ code = read_volume_header(dh, &handlep->rockp->vh); *do_rewind = 1; if (code){ sprintf(buf,"Cannot read volume header volume %s\n", vp->v_name); slave_log_error(ABS_ERROR, "afs_restore",buf); return(code); } /* * Ensure that the volume id listed on the tape is the one that * the caller is really asking for */ if (handlep->rockp->vh.fs_volid1 != fsb->afs_rwid){ sprintf(buf, "Wrong volume on tape: wanted %d, got %d\n", fsb->afs_rwid, handlep->rockp->vh.fs_volid1); slave_log_error(ABS_ERROR, "afs_restore",buf); return(ABS_VOLID_MISMATCH); } /* * Check if the restore target volume name is different than * the original volume name */ if (params->suffix != (char *)NULL){ len = strlen(params->suffix); if (len + strlen(vp->v_name) +1 > ABS_MAX_VOLNAME){ /* save space for '.' and null terminator */ strncpy(vp->res->restore_target, vp->v_name, ABS_MAX_VOLNAME-(len+2)); sprintf(buf,"Truncating target name volume %s suffix: %s\n", vp->v_name, params->suffix); slave_log_error(ABS_WARNING,"afs_restore", buf); }else{ strcpy(vp->res->restore_target,vp->v_name); } strcat(vp->res->restore_target,"."); strcat(vp->res->restore_target, params->suffix); volid = 0; }else{ strcpy(vp->res->restore_target, vp->v_name); volid = fsb->afs_rwid; } overwrite = (params->restore_flags & ABS_OVERWRITE_VOLUME); /* * Setup the abs_rock */ handlep->rockp->dh = dh; handlep->rockp->jp = jp; handlep->rockp->data_read = 0; /* * AFS supports only 32-bit volume sizes */ LLGET(vp->v_size, noval, handlep->rockp->volsize); handlep->rockp->media = mp; /* * AFS does not handle very well the case where we overwrite * an existing volume. So check to see if the volume exists * in the VLDB first; if so, get its id and check with the server * to ensure that there is not really a volume with this id. */ if (overwrite == 0){ code = VLDB_GetEntryByName(vp->res->restore_target, &vent); if (code == 0){ /* * Now get its volumeid and verify with the target server * that the volume does not physically exist on the partition. */ code = UV_ListOneVolume(htonl(server_addr), partid, vent.volumeId[RWVOL], &volent); if (code == 0){ sprintf(buf,"Restore target volume %s already exists in VLDB and on server \n",vp->res->restore_target); slave_log_error(ABS_ERROR, "afs_restore",buf); vp->v_status = ABS_VOL_EXISTS; NEXT_VOLHEADER(dh); return(vp->v_status); }else if (code == ENODEV){ /* * Yes AFS returns ENODEV if the volume does not exist * * The volume exists only in the VLDB's mind; we * can reuse its id. Specifying a non-zero id * will save a step in UV_RestoreVolume where * AFS will execut a VLDB_GetEntryByName as we * just did. */ volid = vent.volumeId[RWVOL]; }else{ /* * Some other error; we can't determine if it really * exists. Play it safe and disallow the restore. */ code = map_afs_errors(code); sprintf(buf,"Error retrieving volume %s location info \n", vp->v_name, code); slave_log_error(ABS_ERROR, "afs_restore",buf); vp->v_status = code; NEXT_VOLHEADER(dh); return(code); } }else{ if (code != VL_NOENT){ /* * can't determine if the volume exists * disallow the restore. */ code = map_afs_errors(code); code = map_afs_errors(code); sprintf(buf,"Error retrieving volume %s location info \n", vp->v_name, code); slave_log_error(ABS_ERROR, "afs_restore",buf); vp->v_status = code; NEXT_VOLHEADER(dh); return(code); } } } /* * Now check to see if there is enough space on the target * partition. AFS does not behave well when the partition is * over 100% full; since we are privileged operation, AFS * will actually let us fill the filesystem beyond 100% */ server_addr = htonl(server_addr); code = UV_PartitionInfo(server_addr, part, &diskp); if (code){ sprintf(buf,"Cannot get parition information for %s %s, code %d\n", server, part, code); slave_log_error(ABS_ERROR, "afs_restore", buf); code = map_afs_errors(code); vp->v_status = code; NEXT_VOLHEADER(dh); *do_rewind = 1; return(code); } /* * Partition usage is given in units of K */ if (diskp.free < ((handlep->rockp->volsize + 1023) >> 10) ){ vp->v_status = ABS_FS_FULL; NEXT_VOLHEADER(dh); *do_rewind = 1; sprintf(buf,"Insufficient space on %s %s - free %d K volsize %d K\n", server, part, diskp.free, (handlep->rockp->volsize +1023) >> 10); slave_log_error(ABS_ERROR, "afs_restore", buf); return(ABS_FS_FULL); } sprintf(buf,"Initiate restore of volume %d to Server %s, partition %s\n", fsb->afs_rwid, server, part); slave_log_error(ABS_INFORMATIONAL, "afs_restore",buf); code = UV_RestoreVolume(server_addr, partid, volid, vp->res->restore_target, overwrite, ABS_RestoreFunc, handlep->rockp); /* * If ABS_RestoreFunc was successfully called it will leave the * tape positioned after this volume's footer. If not, the tape * is positioned after this volume's header. "data_read" indicates * whether ABS_RestoreFunc was ever called. The idea is that we * leave the tape positioned at the start of the volume header * which is closest to our current position to reduce the amount * of physical tape movement. * */ if (code && (handlep->rockp->data_read == 0)){ /* * Reverse tape so that it is positioned at the start of this * volume header. */ tape_code = PREV_VOLHEADER(dh); *do_rewind = 0; } if (code == -1){ /* error reading from tape - the actual ABS error * is stored in the rock if ABS_RestoreFunc was called. * If ABS_RestoreFunc was not called (because the transaction * could not be initiated, then there isn't any status to save. */ if (handlep->rockp->status) code = handlep->rockp->status; else code = ABS_COMM_FAILURE; /* Assume vlserver was down */ }else if ( code != 0){ code = map_afs_errors(code); } if (tape_code) code = tape_code; vp->v_status = code; return(code); } /* * Function: afs_disconnect * * Parameters: handle - address of afs-specific connection information. * * Description: This is curently a NOOP for AFS; it is provided solely * to fill the requirements of the filesystem abstraction layer for * the slave */ int afs_disconnect(void *handle) { return(0); } /* * Procedure: afs_partname_to_id * * Parameters: part - address of string represendint afs partition name * * Description: convert an AFS partition name to a numeric id. * Takes the last letter in "vicex" or "/vicex" and converts it to * a number in the range 0-25 - This is how AFS does it. */ int afs_partname_to_id(char *part) { char c; int id; if (!strncmp(part, "vicep", 5)){ c = part[5]; }else if (!strncmp(part, "/vicep", 6)){ c = part[6]; }else return(-1); id = (int)c - 'a'; return(id); } /* * Procedure: ABS_RestoreFunc * * Parameters: call - address of rx connection information used * to communicate with volserver * restore_rock - address of abs_rock structure * used to communicate information between this * routine and afs_restore * Modifies: restore_rock * * Description: This routine is called indirectly from afs_restore * as a result of invoking the AFS library call UV_RestoreVolume * to perform the restore of one volume. This function assumes * that the tape has been position at the start of the dump data * for the volume to be restored. It uses the size information * stored in restore_rock to determine the size of the dump data * for the volume. It reads fixed size tape records and transfers * them to the volserver via the rx_write call. * * Actual error codes are stored in restore_rock->status upon * return, if the return value from ABS_RestoreFunc is non-zero. * * The return of -1 for error is modeled after the afs * sources which also use UV_DumpVolume. * * Upon return, this function attempts to leave the tape positioned * at the start of the volume header of the volume which follows the * current volume being restored. */ int ABS_RestoreFunc(struct rx_call *call, char *restore_rock) { int count, bytes, code, magic; longlong_t i; char *buffer, buf[512]; struct abs_rock *rockp; abs_volfooter_t vf; rockp = (struct abs_rock *)restore_rock; buffer = rockp->dh->buf; count = rockp->dh->bufsize; /* * Here we are called by the RX after the volserver * is ready to accept data from us. The tape is * already positioned just after the volume header * so start reading the data */ bytes = rockp->dh->bufsize; /* * Read a tape record's worth of data from the tape and * transfer it to the server which is executing the restore. */ rockp->data_read = 1; for (i=rockp->volsize; i> 0; i-= count){ count = SLAVE_READ(rockp->dh, rockp->dh->buf, bytes, &code); if (count != bytes){ if ((code == ABS_EOF_DETECTED) || (code == ABS_EOM_DETECTED) || (code == ABS_INVALID_RECSIZE)){ /* * The above errors indicate a premature end-of-volume * Issue a warning and fail the restore operation */ sprintf(buf,"Premature end of data encountered for volume %s, code= %s\n", rockp->vh.name, get_abs_msg(code)); slave_log_error(ABS_ERROR,"ABS_RestoreFunc",buf); rockp->status = code; if (code == ABS_INVALID_RECSIZE){ /* * see if what we just read is a volheader or footer * Tape needs to be alinged on inter-record gap before * the next volume header following this volume when * we return. */ memcpy(&magic, rockp->dh->buf, sizeof(int)); magic = ntohl(magic); if (magic == ABS_VOLFOOTER_MAGIC){ return(-1); } else if (magic == ABS_VOLHEADER_MAGIC){ /* * It's a volume header */ SLAVE_NEXT_RECORD(rockp->dh, -1); }else{ /* * This shouldn't happen unless the tape somehow * was somehow corrupted. */ sprintf(buf,"Corrupt control record encountered while reading volume %s\n", rockp->vh.name); slave_log_error(ABS_ERROR,"ABS_RestoreFunc", buf); } } return(-1); }else{ /* * Error Reading from the device - The requirements don't state * exactly what we are supposed to do in this case, so this may * change. */ rockp->status = ABS_MEDIA_ERROR; return(-1); } } /* * Because dump data is written in fixed size records, the last * chunk of data may be less than the tape record size, so * we must check for this and send to rx the correct amount of data. */ if (i < bytes) count = i; if ( rx_Write(call,buffer,count) != count ){ /* * Error transferring the data to the Server * the assumption here is that rx tries hard enough * to do this, so we don't have to retry. */ switch(rx_Error(call)){ case RX_CALL_DEAD: rockp->status = ABS_COMM_FAILURE; case RX_CALL_TIMEOUT: rockp->status = ABS_CALL_TIMEOUT; break; default: rockp->status = ABS_FS_ERROR; break; } /* * Ensure we leave tape aligned after the footer */ code = NEXT_VOLFOOTER(rockp->dh); if (code) rockp->status = code; code = read_volume_footer(rockp->dh, &vf); if (code) rockp->status = code; return(-1); } } /* * Read the Footer for the volume. If we can't read the * footer return a -1 so that AFS will not put this volume on-line * and instead will mark for delete on salvage */ rockp->status = read_volume_footer(rockp->dh, &vf); if (rockp->status != 0 || vf.status != ABS_VS_VALID){ if (rockp->status != 0){ sprintf(buf,"Failed to read volume %s footer after restore: %s\n", rockp->vh.name, get_abs_msg(rockp->status)); }else{ sprintf(buf, "Volume footer indicates volume %s is invalid\n", rockp->vh.name); } slave_log_error(ABS_ERROR, "ABS_RestoreFunc", buf); return(-1); } rockp->status = 0; return(0); } /* * Function: ABS_DumpFunc * * Parameters: call - address of rx connection info * dump_rock - address of "rock" information which was setup by * "afs_dump" * * Modifies: dump_rock * * Returns: integer indicating whether the dump was successful * values: 0 - success * -1 - device/media errors * non-zero - RX error codes for RX errors * * Description: This function is called by UV_DumpVolume after the dump * transaction has been initiated with the appropriate volserver. Its * purpose is to read the data arriving on the rx connection from the volserver * and write it to the media. * * This function does not write the volume footer at the end of a * successful dump. * * This function will place an actual error code in dump_rock->status * if a non-zero value is returned. * * Note: we do not handle end-of-medium here; that is handled in the * high-level dump routine "do_dump". Volumes are not allowed to * span tapes, because this actually will create more problems than * it solves! */ int ABS_DumpFunc(struct rx_call *call, /* modified */ char *dump_rock) { unsigned int bytes_read, bytes_requested, bytes_written; unsigned int bytes_left, start; int code, done; longlong_t i, total; char *bp, buf[256]; struct abs_rock *rockp; /* * cast "dump_rock" to its real data type. The call * signature for the AFS dump handler declares the rock * parameter as a char pointer, and this is not what * we need */ rockp = (struct abs_rock *) dump_rock; bp = rockp->dh->buf; /* * Here we are called by the RX after our dump transaction has * been initiated with the volserver. The medium * already positioned just after the last EOF markser * so write the vol header and begin reading the data. * Our predecessor, afs_dump * has stored the volume header information in the "rock" * so we can now write it to the device. */ code = write_volume_header(rockp->dh, &(rockp->vh)); if (code){ rockp->status = code; sprintf(buf, "Received Error %d while writing volume header for volume %s: %s\n", code, &rockp->vh.name, get_abs_msg(code)); slave_log_error(ABS_ERROR,"ABS_DumpFunc",buf); return(-1); } /* * Keep track of whether any data was actually written for * this volume. The high level dump routine uses this * information to determivne whether it needs to create a * record for the volume footer should the dump of this * volume fail */ rockp->data_written = 1; /* * Now write the volume data to the medium as it comes in * from the network via RX. Total is used to produce an * accurate count of the amount of data associated with the * volume, this value will be returned as part of the dump * information for each volume and entered into the database * along with the tape information. */ total = 0; bytes_requested = rockp->dh->bufsize; /* * Keep asking for one buffer's worth of data * from the RX until we either get an RX error * or the amount of data received is less than * the amount of data requested and there is no error. */ memset(bp, 0, rockp->dh->bufsize); bytes_read = rx_Read(call, bp, bytes_requested); while (rx_Error(call) == 0){ if (bytes_read == 0) break; done = (bytes_read < bytes_requested); total+= bytes_read; if (done) bytes_read = rockp->dh->bufsize; bytes_written = SLAVE_WRITE(rockp->dh, bp, bytes_read, &code); if (bytes_written != bytes_read){ sprintf(buf,"Error while writing data for volume %s, code= %s\n", &rockp->vh.name, get_abs_msg(code)); slave_log_error(ABS_ERROR,"ABS_DumpFunc",buf); rockp->status = code; return(-1); } if (done) break; bytes_read = rx_Read(call, bp, bytes_requested); } /* end While */ /* * We are here because we either have finished reading all * of the data or we have an RX transmission error. */ if (rx_Error(call)){ rockp->status = rx_Error(call); sprintf(buf, "Received RX Error %d while writing volume data for volume %s\n", rockp->status, rockp->vh.name); slave_log_error(ABS_ERROR,"ABS_DumpFunc",buf); return(rx_Error(call)); } LLGET(total, rockp->vh.size_high, rockp->vh.size_low ); rockp->status = 0; return(0); } /* * Function: GetServer * * Parameters: aname - address of a server name * * Returens: ip address of server or 0 if can't convert. * * Description: this function takes a string server name and * converts it to an ip address. * * * UGLY CODE WARNING: We would rather call this from the AFS * library directly but it is declared static so we just copied * it. */ int GetServer(aname) char *aname; { register struct hostent *th; int addr; int b1, b2, b3, b4; register int code; struct in_addr *in; char *a; code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4); if (code == 4) { /* parsed as 128.2.9.4, or similar, just use it */ addr = (b1<<24) | (b2<<16) | (b3<<8) | b4; return htonl(addr); /* convert to network order (128 in byte 0) */ } th = gethostbyname(aname); /* this may return a non-null pointer even if it * did not really retrieve the address * e.g., name = " cumin" instead of "cumin" */ if (!th) return 0; in = (struct in_addr *)(th->h_addr); return (in->s_addr); } /* * Procedure: map_afs_errors * * Parameters: code - error code value to be converted * * Description: Map AFS-specific error codes to ABS error codes */ int map_afs_errors(int code) { if (ABS_MIN_ERR < code && code < ABS_MAX_ERR) return(code); switch(code){ case 0: return(0); case VOLSERNOVOL: case VOFFLINE: case VNOSERVICE: /* volume not in service */ case VNOVOL: /* volume does not exist, is not attached,is off line */ return(ABS_NOSUCH_VOLUME); case VSALVAGE: /* volume needs to be salvaged */ return(ABS_VOLUME_DAMAGED); case VOLSERVOLBUSY: case VBUSY: return(ABS_VOLUME_BUSY); case VOLSERVOLMOVED: case VMOVED: return(ABS_VOLUME_MOVED); case VL_PERM: return(ABS_FS_PERM); case RX_CALL_DEAD: return(ABS_COMM_FAILURE); case RX_CALL_TIMEOUT: return(ABS_CALL_TIMEOUT); case RX_EOF: return(0); default: return(ABS_FS_ERROR); } } @ 1.1 log @Initial revision @ text @@ slave/RCS/slave.x,v100400 6031 145 7236 6263011265 13516 0ustar delgadoorawebhead 6.0; branch ; access ; symbols ; locks delgado:6.0; strict; comment @@; 6.0 date 96.11.06.10.40.07; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.13.02; author delgado; state Exp; branches ; next ; desc @@ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @%#include /* * Definitions having to do with media labels */ const ABS_LABEL_MAGIC = 0x0AB123AB; const ABS_VOLHEADER_MAGIC = 0x0AB678AB; const ABS_VOLFOOTER_MAGIC = 0x0AB456AB; struct abs_label{ int magic; /* ABS magic number for verification */ int abs_version; /* ABS version number */ media_id tapeid; /* tape id */ long label_created; /* date tape was labeled */ /* items below here are written each time the tape date is written */ int block_size; /* media block size */ int dump_type; /* type of dump */ int level; /* dump level */ int sequence; /* ordinal number of tape in tapeset */ int uses; /* how many times tape has been written */ long tape_created; /* date data on tape was written */ char device_type[ABS_MAX_DEVICE]; /* type of device used to write this tape */ char domain[ABS_MAX_DOMAIN]; /* ABS domain */ char cell[ABS_MAX_DOMAIN]; /* cell data was dumped from */ char dumpset[ABS_MAX_DNAME]; /* dumpset contained on tape */ int reserved[16]; }; typedef struct abs_label abs_label_t; typedef struct abs_label *abs_label_pt; /* * validate label flags */ const ABS_VALID_LABEL = 0x00; /* The caller expects to find a valid label*/ const ABS_VALID_LABELID = 0x01; /* valid label with matching id */ const ABS_NO_LABEL = 0x02; /* The call expects to find no label */ /* * Dump Flags */ const ABS_DUMP_CLONE = 0x0; /* Dump from cloned volume */ const ABS_DUMP_RW = 0x01; /* Dump from RW volume */ struct dump_params{ string verf_mode; int media_errors; int media_eof; long dump_from; longlong_t media_capacity; short dump_flags; }; typedef struct dump_params dump_params_t; typedef struct dump_params *dump_params_pt; struct abs_vol_header{ int magic; int absvolid_low; int absvolid_high; int size_low; int size_high; char name[ABS_MAX_VOLNAME]; char server[ABS_MAX_SERVER]; char device[ABS_MAX_DEVICE]; char fstype[ABS_MAX_TAG]; int fs_volid1; int fs_volid2; char fs_private[128]; /* 128 bytes of fs-specific data */ int reserved[8]; }; typedef struct abs_vol_header abs_volheader_t; typedef struct abs_vol_header *abs_volheader_pt; const ABS_VS_INVALID = 0; const ABS_VS_VALID = 1; struct volume_footer{ int magic; int absvolid; int size_high; int size_low; int status; int spare[8]; }; typedef struct volume_footer abs_volfooter_t; typedef struct volume_footer *abs_volfooter_pt; program ABSSLAVE{ version ABSVERS{ int abs_backup(net_dumpset_pt, job_pt, dump_params_pt) = 1; int abs_restore(media_pt, int, restore_pt) = 2; int abs_scan(int, job_pt) = 3; int abs_label_media(string, media_id_pt, job_pt) = 4; int abs_abort_job(tapehost_pt, job_pt) = 5; int abs_shutdown_slave() = 6; }=1; } = 3001; @ 5.0 log @remove fakeslave names @ text @d28 1 a28 1 char reserved[64]; /* reserved for future use */ d65 1 a65 1 char server[ABS_MAX_HOST_LEN]; d71 1 a71 1 char reserved[32]; d84 2 a85 2 int size_high; int size_low; d87 1 @ slave/RCS/private.h,v100400 6031 145 15215 6240130526 14047 0ustar delgadoorawebhead 6.0; branch ; access ; symbols full-auth:3.1 alpha:2.1; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.40.06; author delgado; state Exp; branches ; next 5.2; 5.2 date 96.11.05.16.07.25; author delgado; state Exp; branches ; next 5.1; 5.1 date 96.10.31.20.07.01; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.13.57; author delgado; state Exp; branches ; next 3.2; 3.2 date 96.03.10.17.29.59; author delgado; state Exp; branches ; next 3.1; 3.1 date 96.02.22.09.05.39; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.23.53; author delgado; state Exp; branches 2.1.1.1; next 1.1; 1.1 date 95.11.06.16.41.32; author delgado; state Exp; branches ; next ; 2.1.1.1 date 96.03.01.12.47.40; author delgado; state Exp; branches ; next ; desc @initial REvision @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @ #define SLAVE_CHECK_AUTH( handle) slave_check_authentication(handle) #define ABS_MAX_DEVTYPES 10 /* * indeces for the various device types */ #define ABS_NO_DEV 0 #define ABS_DEV_FS 1 #define ABS_DEV_MT 2 /* * record size for control data (label, headers, footers) */ #define ABS_REC_SIZE 4096 typedef struct dev_table{ int (* media_next_record)(); int (* media_rewind)(); int (* media_next_item)(); int (* media_read)(); int (* media_write)(); int (* media_open)(); int (* media_close)(); int (* media_offline)(); void (* media_devtype)(); }dev_table_t; extern struct dev_table *devp; typedef struct dev_handle { int fd; char devname[PATH_MAX]; dev_table_t *dev_ops; char *buf; int bufsize; void *data; }dev_handle_t; #define SLAVE_OPEN(devp, dh, path, flags, jobid) devp->media_open(devp, dh, path, flags, jobid) #define SLAVE_CLOSE(dh) dh->dev_ops->media_close(dh, 1) #define SLAVE_CLOSE_PARTIAL(dh) dh->dev_ops->media_close(dh, 0) #define SLAVE_WRITE(dh, buf, len, cp) dh->dev_ops->media_write(dh, buf, len, cp) #define SLAVE_READ(dh, buf, len, cp) dh->dev_ops->media_read(dh, buf, len, cp) #define SLAVE_SEEK(dh, offset, flag) dh->dev_ops->media_read(dh, offset, flag) #define SLAVE_NEXT_MEDIA(dh, extid, id, valid) \ dh->dev_ops->media_next_item(dh, extid, id, valid) #define SLAVE_REWIND(dh) dh->dev_ops->media_rewind(dh) #define SLAVE_OFFLINE(dh) dh->dev_ops->media_offline(dh) #define SLAVE_NEXT_RECORD(dh, count) dh->dev_ops->media_next_record(dh, count) #define SLAVE_DEVICE_TYPE(dh, dpp) dh->dev_ops->media_devtype(dh, dpp) /* * Macros for error checking */ #define UNRECOVERABLE(code) \ (code == ABS_NOSUCH_VOLUME || code == ABS_VOLUME_MOVED || \ code == ABS_VOLUME_DAMAGED || code == ABS_PROTOCOL_MISMATCH) /* * Definitions to support the filesystem abstraction layer */ #define MAX_FSTYPES 5 #define FS_NOOP 0 #define AFS_OPS 1 typedef struct fs_ops{ void * (* fs_connect)(); int (* fs_dump_volume)(); int (* fs_restore_volume)(); int (* fs_disconnect)(); }fs_ops; #define FS_CONNECT(fsp, host, cell, id, codep, op) \ fsp->fs_connect(host, cell, id, codep, op) #define FS_DUMP(fsp, handle, dh, level, jobp, volp, wrflg, labelp, params) \ fsp->fs_dump_volume(handle, dh, level, jobp, volp, wrflg, labelp, params) #define FS_RESTORE(fsp, handle, dh, volp, mp, jobid, params, do_rewind) \ fsp->fs_restore_volume(handle, dh, volp, mp, jobid, params, do_rewind) #define FS_DISCONNECT(fsp, handle) fsp->fs_disconnect(handle) #define ABS_MIN_RETRY 5 #define ABS_DEFAULT_RETRY 300 #define ABS_MAX_RETRY 600 #define DISABLE_CANCEL() #define ENABLE_CANCEL() /* * Types passed to save job results */ #define DUMPSET_TYPE 1 #define TOC_TYPE 2 #define VOLUME_TYPE 3 #define ROUND_UP(x, y) (((x)+ (y)-1) & ~((y) - 1)) #define NEXT_VOLHEADER(dhp) find_control_rec(dhp, 1, ABS_VOLHEADER_MAGIC) #define NEXT_VOLFOOTER(dhp) find_control_rec(dhp, 1, ABS_VOLFOOTER_MAGIC) #define PREV_VOLHEADER(dhp) find_control_rec(dhp, -1, ABS_VOLHEADER_MAGIC) #define ABS_MOUNT_INTERVAL 120 /* * Slave states for handling SIGTERM */ #define SLAVE_INIT 0 #define SLAVE_RUNNING 1 #define SLAVE_TERMINATED 2 @ 5.2 log @Increase control record size to 4096 - 2048 was not large enought to accommodate the expanded sizes for some of the fields in the vol header and tape label. @ text @@ 5.1 log @Increate size of tape control records to 2048 to accommodate longer names for volumes, servers, and devices. @ text @d16 1 a16 1 #define ABS_REC_SIZE 2048 @ 5.0 log @remove fakeslave names @ text @d16 1 a16 1 #define ABS_REC_SIZE 512 @ 3.2 log @Support graceful termination with SIGTERM @ text @d27 1 d60 3 d95 4 a98 4 #define FS_DUMP(fsp, handle, dh, level, jobp, volp, wrflg, labelp) \ fsp->fs_dump_volume(handle, dh, level, jobp, volp, wrflg, labelp) #define FS_RESTORE(fsp, handle, dh, volp, jobid, params, do_rewind) \ fsp->fs_restore_volume(handle, dh, volp, jobid, params, do_rewind) @ 3.1 log @Master now has credentials, auth checking is turned on @ text @d118 1 a118 1 #define NEXT_CONTROL_REC(dhp) find_control_rec(dhp, 1) d120 2 a121 1 #define PREV_CONTROL_REC(dhp) find_control_rec(dhp, -1) a123 1 #define ABS_MOUNT_INTERVAL 120 d126 1 d128 3 d133 3 @ 2.1 log @alpha release @ text @d2 1 a2 1 #define SLAVE_CHECK_AUTH( handle) 0 @ 2.1.1.1 log @Change NEXT_CONTROL_REC macro and replace with NEXT_VOLHEADER or NEXT_VOLFOOTER. Also fix find_control_rec so that backupward spacing to the previous control rec will now work @ text @d2 1 a2 1 #define SLAVE_CHECK_AUTH( handle) slave_check_authentication(handle) d118 1 a118 2 #define NEXT_VOLHEADER(dhp) find_control_rec(dhp, 1, ABS_VOLHEADER_MAGIC) #define NEXT_VOLFOOTER(dhp) find_control_rec(dhp, 1, ABS_VOLFOOTER_MAGIC) d120 1 a120 2 #define PREV_VOLHEADER(dhp) find_control_rec(dhp, -1, ABS_VOLHEADER_MAGIC) @ 1.1 log @Initial revision @ text @d1 4 d11 1 d13 5 d20 1 a20 2 int (* media_write_eof)(); int (* media_next_file)(); d27 1 d35 4 d43 1 a43 1 #define SLAVE_OPEN(devp, dh, path, flags) devp->media_open(dh, path, flags) d45 2 a46 1 #define SLAVE_CLOSE(devp, dh) devp->media_open(dh) d48 1 a48 1 #define SLAVE_WRITE(devp, dh, buf, len) devp->media_write(dh, buf, len) d50 1 a50 1 #define SLAVE_READ(devp, dh, buf, len) devp->media_read(dh, buf, len) d52 1 a52 1 #define SLAVE_NEXT_MEDIA(devp, dh, extid, id) devp->media_next_item(dh, extid, id) d54 2 a55 1 #define SLAVE_REWIND(devp, dh) devp->media_rewind(dh) d57 1 a57 1 #define SLAVE_NEXT_FILE(devp, dh, count) devp->media_next_file(dh, count) d59 1 a59 1 #define SLAVE_EOF(devp, dh) devp->media_write_eof(dh) d62 36 d99 1 d101 29 @ slave/RCS/prototypes.h,v100400 6031 145 5013 6240130526 14600 0ustar delgadoorawebhead 6.0; branch ; access ; symbols alpha:2.1; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.40.06; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.13.57; author delgado; state Exp; branches ; next 2.2; 2.2 date 96.03.12.12.31.08; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.23.42; author delgado; state Exp; branches ; next 1.1; 1.1 date 95.11.06.16.41.56; author delgado; state Exp; branches ; next ; desc @initial REvision @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @ /* * Prototypes */ int slave_log_error(int sev, char *routine, char *msg); int slave_notify_master(int status, int jobid, job_done_res_pt jdp, int save); int validate_label(dev_handle_t *dh, media_id_pt mip, int validate_type, abs_label_t *labelp); int cycle_through_tapes(dev_handle_t *dh, int jobid, char *extid, media_id_pt mip, int valid); int request_media_mount(int jobid, int request_type, tapeid_t *mp); fs_ops * get_fs_ops(char *fstype); int send_status(int jobid, job_status_pt job_stat); int GetServer(char *aname); int abs_marshall_label(char *buf, int buflen, abs_label_pt lp, int marshall); int abs_marshall_volheader(char *buf, int buflen, abs_volheader_pt vhp, int marshall); int read_label(dev_handle_t *dh, abs_label_t *labelp); int write_label(dev_handle_t *dh, abs_label_t *labelp); void netvol_to_volheader(net_volume_t *vp, abs_volheader_t *vh); int read_volume_footer(dev_handle_t *dh, abs_volfooter_pt vf); int write_volume_footer(dev_handle_t *dh, net_volume_pt vp, int status); int find_control_rec(dev_handle_t *dh, int direction, int rec_type); int do_dump(dev_handle_t *dh, net_dumpset_pt dp, job_pt jp, dump_params_pt params, job_status_pt job_stat); int do_restore(dev_handle_t *dh, media_t *mp, int jobid, restore_pt params, job_status_pt job_stat); char * get_jobs_dir(); int get_slave_tgt(); int get_slave_state(); @ 5.0 log @remove fakeslave names @ text @@ 2.2 log @autolabel baseline @ text @d10 1 a10 1 slave_notify_master(int status, int jobid, job_done_res_pt jdp); d71 1 a71 1 do_restore(dev_handle_t *dh, net_volume_pt vp, int jobid, @ 2.1 log @alpha release @ text @d63 1 a63 1 find_control_rec(dev_handle_t *dh, int direction); d76 5 @ 1.1 log @Initial revision @ text @d10 1 a10 1 slave_notify_master(int status, int jobid, net_dumpset_pt dp); d15 61 @ slave/RCS/onc_int.c,v100400 6031 145 14137 6121333021 14014 0ustar delgadoorawebhead 3.5; branch ; access ; symbols autolabel-baseline:3.5 full-auth:3.1 alpha:2.1; locks ; strict; comment @ * @; 3.5 date 96.03.12.12.36.17; author delgado; state Exp; branches ; next 3.2; 3.2 date 96.02.23.15.47.13; author delgado; state Exp; branches ; next 3.1; 3.1 date 96.02.22.09.05.25; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.25.57; author delgado; state Exp; branches ; next 1.1; 1.1 date 95.12.12.13.53.24; author delgado; state Exp; branches ; next ; desc @interface with onc support routines @ 3.5 log @autolabel baseline @ text @#include #include #include #include #include "../master/abs_msg.h" #include "private.h" static char realm[REALM_SZ]; static int have_realm; extern char master_server[]; int abs_marshall_volheader(char *buf, int buflen, abs_volheader_pt vhp, int marshall) { XDR xdrs; int code; int xdr_op; long start, finish; xdr_op = (marshall == 1) ? XDR_ENCODE: XDR_DECODE; xdrmem_create(&xdrs, buf, buflen, xdr_op); start = (long)XDR_INLINE(&xdrs, 0); code = xdr_abs_volheader_t(&xdrs, vhp); finish = (long)XDR_INLINE(&xdrs, 0); if (code == TRUE) return(finish - start); else return(-1); } int abs_marshall_label(char *buf, int buflen, abs_label_pt lp, int marshall) { XDR xdrs; int code; int xdr_op; long start, finish; xdr_op = (marshall == 1) ? XDR_ENCODE: XDR_DECODE; xdrmem_create(&xdrs, buf, buflen, xdr_op); start = (long)XDR_INLINE(&xdrs, 0); code = xdr_abs_label(&xdrs, lp); finish = (long)XDR_INLINE(&xdrs, 0); if (code == TRUE) return(finish - start); else return(-1); } /* * We only use "jobs_dir" because we chdir'd to the admin * dir when the slave started */ int save_job_info(int jobid, int status, void *data, int datatype) { FILE *fp; char name[ABS_MAX_PATH]; XDR xdrs; sprintf(name,"%s/%d",get_jobs_dir(), jobid); fp = fopen(name,"w+"); if (fp == (FILE *) NULL){ /* * Send criticla message! */ return(ABS_OS_ERROR); } xdrstdio_create(&xdrs, fp, XDR_ENCODE); if (xdr_int(&xdrs, &status) == FALSE){ return(ABS_CANT_ENCODE); } if (datatype == DUMPSET_TYPE){ if (xdr_net_dumpset_pt(&xdrs, &data) == FALSE){ return(ABS_CANT_ENCODE); } }else if (datatype == TOC_TYPE){ if (xdr_toc_res_pt(&xdrs, &data) == FALSE){ return(ABS_CANT_ENCODE); } }else if (datatype == VOLUME_TYPE){ if (xdr_net_volume_pt(&xdrs, &data) == FALSE){ return(ABS_CANT_ENCODE); } } return(0); } @ 3.2 log @move auth related functions to "slave_auth.c" @ text @@ 3.1 log @Master now has credentials, auth checking is turned on @ text @a98 39 int slave_check_authentication(struct svc_req *client) { struct authkerb_clnt_cred *cred; int rc; /* * client is not using Kerberos with data integrity, then deny * the request since we can't trust it! */ if (client->rq_cred.oa_flavor != AUTH_KERB_INTEGRITY){ return(0); } cred = (struct authkerb_clnt_cred *) client->rq_clntcred; /* First check the client's realm; if it's not the same as * ours, then reject the request */ if (! have_realm){ rc = krb_get_lrealm(realm, 1); if (rc != KSUCCESS){ slave_log_error(ABS_ERROR, "abs_check_auth", "krb_get_lrealm failed\n!"); return(ABS_AUTH_ERROR); } have_realm = 1; } if (strcmp(realm, cred->prealm)){ return(ABS_AUTH_ERROR); } if (strcmp(cred->pname, "rcmd")){ return(ABS_AUTH_ERROR); } if (strcmp(cred->pinst, master_server )){ return(ABS_AUTH_ERROR); } return(0); } @ 2.1 log @alpha release @ text @d5 1 d8 2 d11 2 d95 40 @ 1.1 log @Initial revision @ text @a5 1 #include "foot.h" a52 68 int write_footer(dev_handle_t *dh, footer_block_t *vsp) { XDR xdrs; int code, count, blocks, entries, i, j; int magic = ABS_FOOTER_MAGIC, bytes, pad; vol_summary_t *ptr; xdrmem_create(&xdrs, dh->buf, dh->bufsize, XDR_ENCODE); if (xdr_int(&xdrs, &magic) == FALSE){ return(-1); } if (xdr_int(&xdrs, &(vsp->count)) == FALSE){ return(-1); } if (vsp->count <= 0){ bytes = SLAVE_WRITE(dh, dh->buf, 2*sizeof(int), &code); return(code); } pad = sizeof(vol_summary_t)%4; /* * Reset the marshalling pointer to the beginning of the * buffer. */ XDR_SETPOS(&xdrs, 0); blocks = (int)(vsp->count/ABS_VOLSUMS_PER_BLOCK); entries = vsp->count%ABS_VOLSUMS_PER_BLOCK; for(i=0; i< blocks-1; i++){ if (!vsp->vs[i]) continue; for(j=0, ptr=vsp->vs[i]; j< ABS_VOLSUMS_PER_BLOCK; j++){ if (xdr_vol_summary_t(&xdrs, &ptr[j]) == FALSE) return(-1); if (!XDR_INLINE(&xdrs, pad) == FALSE){ return(-1); } } /* * If the buffer is full, then flush it to the tape */ if (XDR_GETPOS(&xdrs) < sizeof(vol_summary_t) +pad){ bytes = SLAVE_WRITE(dh, dh->buf, 2*sizeof(int), &code); if (bytes != XDR_GETPOS(&xdrs)){ return(code); } } } /* last block is probably a partial block */ for(j=0, ptr=vsp->vs[blocks]; j< entries; j++){ if (xdr_vol_summary_t(&xdrs, &ptr[j]) == FALSE) return(-1); if (XDR_GETPOS(&xdrs) < sizeof(vol_summary_t)+pad){ bytes = SLAVE_WRITE(dh, dh->buf, 2*sizeof(int), &code); if (bytes != XDR_GETPOS(&xdrs)){ return(code); } } } bytes = SLAVE_WRITE(dh, dh->buf, 2*sizeof(int), &code); if (bytes != XDR_GETPOS(&xdrs)){ return(code); } return(0); } d59 1 a59 1 save_job_info(int jobid, int status, net_dumpset_pt dp) d77 13 a89 2 if (xdr_net_dumpset_pt(&xdrs, &dp) == FALSE){ return(ABS_CANT_ENCODE); @ slave/RCS/slave_utils.c,v100400 6031 145 160353 6240130524 14744 0ustar delgadoorawebhead 6.0; branch ; access ; symbols autolabel-baseline:3.5 alpha:2.1; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.40.04; author delgado; state Exp; branches ; next 5.1; 5.1 date 96.10.01.19.14.06; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.13.00; author delgado; state Exp; branches ; next 4.0; 4.0 date 96.04.19.11.22.43; author delgado; state Exp; branches ; next 3.6; 3.6 date 96.03.26.20.18.11; author delgado; state Exp; branches ; next 3.5; 3.5 date 96.03.12.12.36.20; author delgado; state Exp; branches ; next 2.5; 2.5 date 96.03.06.16.02.57; author delgado; state Exp; branches ; next 2.4; 2.4 date 96.03.06.10.35.23; author delgado; state Exp; branches ; next 2.3; 2.3 date 96.03.01.12.46.51; author delgado; state Exp; branches ; next 2.2; 2.2 date 96.02.29.10.21.35; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.23.10; author delgado; state Exp; branches ; next 1.1; 1.1 date 96.02.08.13.16.45; author delgado; state Exp; branches ; next ; desc @Replace old file which was corrupted by afs @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include #include "../master/abs_msg.h" #include "../master/os_defs.h" #include "private.h" #include "prototypes.h" extern int online; extern char master_server[256]; extern char slave_princ[]; extern char master_princ[]; int media_checkpoint(dev_handle_t *dh, job_pt jp, net_dumpset_t *dp, char *verfmode); int nodev(); void noname(dev_handle_t *dh, char **dpp); extern int devfs_next_file(), devfs_rewind(); extern int devfs_next_medium(), devfs_read(), devfs_write(), devfs_seek(); extern int devfs_open(), devfs_close(); extern int mtio_next_record(), mtio_rewind(), mtio_next_medium(); extern int mtio_read(), mtio_write(), mtio_seek(), mtio_open(), mtio_close(); extern int mtio_offline(); void mtio_devtype(); /* * This is the operations vector table for the vaiours device types. * each device type must supply its own set of routines for device * mangement. */ static struct dev_table __devices[ABS_MAX_DEVTYPES] = { {nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, noname}, {nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, noname}, {mtio_next_record, mtio_rewind, mtio_next_medium, mtio_read, mtio_write, mtio_open, mtio_close, mtio_offline, mtio_devtype}, {0,0,0,0,0,0,0} }; struct dev_table *devp = &__devices[ABS_NO_DEV]; int nofs(), delete_job_info(int jobid); void *nofs_connect(); extern void *afs_connect(); extern int afs_dump(), afs_restore(), afs_disconnect(); /* * This is the operations vectory table for the various filesystem * types. In order for a filesystem to interact properly with an * ABS slave, it must support the operations listed in this table. */ static fs_ops fs_ops_array[MAX_FSTYPES] = { {nofs_connect, nofs, nofs, nofs}, {afs_connect, afs_dump, afs_restore, afs_disconnect}}; fs_ops *fsp; /* * Function: set_devtype * * Parameters: devtype - address of string containing device type * * Description: This function determines of "type" is a supported device * type and if so sets the global device operations vector pointer "devp" * to point to the appropriate set of operations from the __devices table. */ int set_devtype(char *type) { if (!strcmp(type, "fs")){ devp = &__devices[ABS_DEV_FS]; return(0); } if (!strcmp(type,"mt")){ devp = &__devices[ABS_DEV_MT]; return(0); } return(ABS_INVALID_SPEC); } /* * The following routine is a filler so that devp points to something * valid upon startup */ int nodev() { return(ABS_NO_DEVICE_SPEC); } void noname(dev_handle_t *dh, char **dpp) { *dpp = (char *) NULL; } /* * Dummy routines for filesystem types */ int nofs() { return(ABS_INVALID_FSTYPE); } void * nofs_connect() { return((void *) NULL); } /* * Function: get_fs_ops * * Parameters: type - pointer to string containing filesystem type * * Description: Determint if "type" represents a supported filesystem type * and if so return the address of the matching filesystems operations vector. */ fs_ops * get_fs_ops(char *type) { if (!strcmp(type, "AFS")) return(&fs_ops_array[AFS_OPS]); return((fs_ops *) NULL); } /* * Procedure: slave_label_medium * * Parameters: dtp - address of device operations vector * dh - address of device i/o specific info * eid - address of external medium label * mip - address of internal media id. * * Description: labels the medium with the id specified in "mip" * The label is written in network byte format for portability. */ int slave_label_medium(dev_table_t *dtp, dev_handle_t *dh, char *eid, media_id_pt mip) { abs_label_t label; struct timeval tv; int rc; long bytes_requested, bytes_written; memset(&label, 0, sizeof(label)); label.magic = ABS_LABEL_MAGIC; label.abs_version = ABSVERS; memcpy(&label.tapeid, mip, sizeof(media_id_t)); gettimeofday(&tv); label.label_created = tv.tv_sec; rc = SLAVE_REWIND(dh); if (rc) return(rc); /* * Write the label to the device */ rc = write_label(dh, &label); if (rc) return(rc); /* * TBD -Now Read it back and verify that this is the * same as what we wrote */ rc = SLAVE_REWIND(dh); if (rc) return(rc); } /* * Function: read_label * * Parameters: dh - address of device info for medium * labelp - addres of area to store label info * * Modifies: labelp * * Description: read_label attempts to read the abs label from * the medium associated with dh. The function will convert the * label which is stored in network byte order to host byte order. * This function assumes that the device is set to the beginning of * the medium. */ int read_label(dev_handle_t *dh, abs_label_t *labelp) { int bytes, code; char buffer[ABS_REC_SIZE]; code = SLAVE_REWIND(dh); if (code) return(code); bytes = SLAVE_READ(dh, buffer, ABS_REC_SIZE, &code); if (bytes != ABS_REC_SIZE){ return(code); } memcpy(labelp, buffer, sizeof(abs_label_t)); labelp->magic = ntohl(labelp->magic); labelp->abs_version = ntohl(labelp->abs_version); labelp->tapeid.internal1 = ntohl(labelp->tapeid.internal1); labelp->tapeid.internal2 = ntohl(labelp->tapeid.internal2); labelp->label_created = ntohl(labelp->label_created); labelp->block_size = ntohl(labelp->block_size); labelp->dump_type = ntohl(labelp->dump_type); labelp->level = ntohl(labelp->level); labelp->uses = ntohl(labelp->uses); labelp->tape_created = ntohl(labelp->tape_created); return(0); } /* * Function: write_label * * Parameters: dh - address of device info for medium * labelp - addres of area to store label info * * Description: write_label writes the information in "labelp" to * the medium associated with dh. The label information will be written * in network byte order for portability. This function assumes that * the device is set to beginning of medium. */ int write_label(dev_handle_t *dh, abs_label_t *labelp) { int bytes, code; char buffer[ABS_REC_SIZE]; char *devtype; memset(buffer, 0, ABS_REC_SIZE); labelp->magic = htonl(labelp->magic); labelp->abs_version = htonl(labelp->abs_version); labelp->tapeid.internal1 = htonl(labelp->tapeid.internal1); labelp->tapeid.internal2 = htonl(labelp->tapeid.internal2); labelp->label_created = htonl(labelp->label_created); labelp->block_size = htonl(labelp->block_size); labelp->dump_type = htonl(labelp->dump_type); labelp->level = htonl(labelp->level); labelp->uses = htonl(labelp->uses); labelp->tape_created = htonl(labelp->tape_created); SLAVE_DEVICE_TYPE(dh, &devtype); if (devtype != (char *) NULL){ strncpy(labelp->device_type, devtype, ABS_MAX_DEVICE); } memcpy(buffer, labelp, sizeof(abs_label_t)); bytes = SLAVE_WRITE(dh, buffer, ABS_REC_SIZE, &code); if (bytes != ABS_REC_SIZE){ return(code); } return(0); } /* * Function: validate_label * * Parameters: dh - address of device info for medium * mip - address of internal media id * validate_type - type of validation requested. * labelp - address to store label information. * * Description: This function reads a label from the specified medium * and determines if the label matches the caller's expectatations. * The caller's expectations are defined as follows * ABS_NO_LABEL - expect the medium has no label * ABS_VALID_LABEL - expects the medium has an abs label with * valid abs magic number. * ABS_VALID_LABELID - expects medium has an abs label with valid * abs magic number and internal media id which * matches "mip" * Returns 0 if tape label matches caller's expectations, non-zero otherwise. */ int validate_label(dev_handle_t *dh, media_id_pt mip, int validate_type, abs_label_t *labelp) { int code, bytes; dev_table_t *dtp = dh->dev_ops; if ((code = read_label(dh, labelp))){ if ((code == ABS_EOM_DETECTED || code == ABS_EOF_DETECTED || code == ABS_CANT_ENCODE) && (validate_type == ABS_NO_LABEL)){ /* * This is a blank tape */ return(0); } if (code == ABS_EOM_DETECTED || ABS_EOF_DETECTED) /* blank tape */ return(ABS_BLANK_MEDIUM); return(code); } /* * We've read one label's worth of data, let's see * if we have a valid label */ switch(validate_type){ case ABS_NO_LABEL: if (labelp->magic != ABS_LABEL_MAGIC) return(0); return(ABS_VALID_MEDIA); case ABS_VALID_LABEL: if (labelp->magic != ABS_LABEL_MAGIC) return(ABS_INVALID_MAGIC); return(0); case ABS_VALID_LABELID: if (labelp->magic != ABS_LABEL_MAGIC) return(ABS_INVALID_MAGIC); if (labelp->tapeid.internal1 != mip->internal1){ return(ABS_INVALID_MEDIA_ID); } if (labelp->tapeid.internal1 != mip->internal1){ return(ABS_INVALID_MEDIA_ID); } return(0); default: return(ABS_INVALID_SPEC); } } /* * Procedure: write_volume_footer * * Parameters: dh - address of device-specific information * vp - address of volume information * status - volume's dump status code. * * Description: write_volume_footer writes a volume footer for the * volume "vp" to the device associated with "dh". It sets the footer * "status" field to ABS_VS_VALID if status is 0, and ABS_VS_INVALID * otherwise. It copies the size and volumeid information from "vp" * Footer is written in network byte order. */ int write_volume_footer(dev_handle_t *dh, net_volume_pt vp, int status) { abs_volfooter_t vf; int bytes, code; vf.magic = ABS_VOLFOOTER_MAGIC; vf.absvolid = vp->v_id; LLGET(vp->v_size, vf.size_high, vf.size_low); if (status) vf.status = ABS_VS_INVALID; else vf.status = ABS_VS_VALID; memcpy(dh->buf, &vf, sizeof(vf)); bytes = SLAVE_WRITE(dh, dh->buf, ABS_REC_SIZE, &code); if (bytes != ABS_REC_SIZE){ return(code); } return(0); } /* * Procedure: read_volume_footer * * Parameters: dh - address of device speicific information * vf - address of area to copy footer data * * Modifies - vf * * Description: This function attempts to read a volume footer * from the device associated with "dh" and copies the information * into the area referenced by "vf". */ int read_volume_footer(dev_handle_t *dh, abs_volfooter_pt vf) { int bytes, code; bytes = SLAVE_READ(dh, dh->buf, ABS_REC_SIZE, &code); if (bytes != ABS_REC_SIZE){ return(code); } memcpy(vf, dh->buf, sizeof(abs_volfooter_t)); if (vf->magic != ABS_VOLFOOTER_MAGIC) return(ABS_INVALID_MAGIC); return(0); } /* * Procedure: find_control_rec * * Parameters: dh - address of device-specific information * count - advance forward or backward * * Description: This function move the medium to the next control * record (header or footer) on the medium by invoking the * SLAVE_READ function using a 512 byte record size. Note * that a read request for an incorrect record size (e.g. data record) * will advance us past that record to the interrecord gap preceeding * the next record. * * We move forward if the count is positive and backward if count * is negative. The medium is left positioned at the start of * the control record. */ int find_control_rec(dev_handle_t *dh, int count, int rec_type) { int bytes, code, magic; abs_volheader_t *vhp; abs_volfooter_t *vfp; vhp =(abs_volheader_t *) dh->buf; vfp = (abs_volfooter_t *)dh->buf; code = 0; if ( count < 0){ code = SLAVE_NEXT_RECORD(dh, -1); if (code) return(code); } while (1){ if ( (bytes = SLAVE_READ(dh, dh->buf, ABS_REC_SIZE, &code)) != ABS_REC_SIZE){ if (code == ABS_INVALID_RECSIZE){ /* * Record size is not the same as the control record size * so this record can't possibly be a volume header or footer */ if ( count < 0){ /* * If we are reversing, then we must backup over the record * we just read plus another record to reach the record * just before the one just read. */ code = SLAVE_NEXT_RECORD(dh, -2); if (code) return(code); } continue; }else if (code != 0){ /* some other error */ break; } } memcpy(&magic, dh->buf, sizeof(int)); magic = ntohl(magic); if (magic == rec_type){ code = SLAVE_NEXT_RECORD(dh, -1); break; } } if (code) code = convert_system_error(code); return(code); } destroy_handle( CLIENT * clnt_handle) { if (clnt_handle){ if (clnt_handle->cl_auth) auth_destroy(clnt_handle->cl_auth); clnt_destroy(clnt_handle); } } CLIENT * connect_to_master(char *protseq) { CLIENT *clnt_handle = (CLIENT *) NULL; struct timeval cv; AUTH *authp = (AUTH *) NULL; int interval = 5; int rc; do{ destroy_handle(clnt_handle); authp = (AUTH *) NULL; clnt_handle = (CLIENT *) NULL; while ((clnt_handle = clnt_create(master_server, ABS_SLAVESERVICE, ABS_SLVVERS, protseq)) == (CLIENT *) NULL){ /* * The master has disappeared completely! */ clnt_pcreateerror(master_server); slave_log_error(ABS_FATAL, "connect_to_master", "Cannot create connection to Master"); sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } /* * got a handle to the master now add the authentication * info to it */ }while(get_slave_tgt()); authkerb_create(master_princ, master_server, 0, AUTH_KERB, &rc, &authp, clnt_handle); /* * Bump up the patience factor; the default timeout value of 15 * seconds is too low */ cv.tv_sec = 180; cv.tv_usec = 0; clnt_control(clnt_handle, CLSET_TIMEOUT, (char *) &cv); return(clnt_handle); } /* * Procedure: slave_notify_master * * Parameters: status - integer containing job status code to send to master * jobid - integer representing job id for executed job * dp - address of dumpset/volume information for routines * such as dump/restore/scan to send to master * * Description: This procedure creates an RPC connection to the Master * and attempts to send the results to the master via the slaveservice_job_done * interface. The procedure will execute exponential retry on RPC failures * It keeps retrying until the data is delivered successfully to the master. */ int slave_notify_master(int status, int jobid, job_done_res_pt jdp, int save) { CLIENT *clnt_handle; int code, rc, interval = ABS_MIN_RETRY, retries; char buf[ABS_REC_SIZE], *msgp; retries = 0; /* * Save the job info to disk just in case */ if (save){ if (jdp->jdr_type == jdr_type_dumpset) code = save_job_info(jobid, status, jdp->jdr_dumpset, DUMPSET_TYPE); else if (jdp->jdr_type == jdr_type_volume){ code = save_job_info(jobid, status, jdp->jdr_volume, VOLUME_TYPE); } } while (1){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = code = 0; rc = slaveservice_job_done_1(status, jobid, jdp, &code, clnt_handle); if (rc == 0){ /* check for transport errors */ if (code == 0) /* check for call errors */ break; else{ if (ABS_MIN_ERR < code < ABS_MAX_ERR){ /* * The master had some trouble with our results. * this is fatal, however we continue to retry. */ sprintf(buf,"slaveservice_job_done_1: Errors from Master for job %d: %s\n", jobid, get_abs_msg(code)); slave_log_error(ABS_FATAL, "slave_notify_master", buf); }else{ sprintf(buf,"slaveservice_job_done_1: RPC Int Errors from Master %d\n", code); slave_log_error(ABS_ERROR, "slave_notify_master", buf); } } }else{ /* transport errors */ msgp = clnt_sperrno(rc); if (rc != RPC_TIMEDOUT || rc != RPC_INTR || rc != RPC_TLIERROR || rc != RPC_FAILED || rc != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, "slave_notify_master", msgp); } slave_log_error(ABS_ERROR, "slave_notify_master", msgp); sprintf(buf,"slaveservice_job_done_1: RPC Errors from Master %d\n",rc); } /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); /* * Exponential Backoff */ sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } /* end while(1) */ /* * We are finished calling the master - destroy the * the connection */ destroy_handle(clnt_handle); delete_job_info(jobid); return(code); } /* * Procedure: slave_validate * * Parameters: mip - address of media id to validate * jobid - integer representing job id for executed job * rcp - address of integer to contain media status upon return * * Description: This procedure creates an RPC connection to the Master * and attempts to request validation of the specified medium with the master * via the slaveservice_validate_media interface. The procedure will execute exponential * retry on RPC failures */ int slave_validate(media_id_pt mip, int jobid, int *rcp) { CLIENT *clnt_handle; int code, interval = ABS_MIN_RETRY; char buf[ABS_REC_SIZE]; while (1){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ code = slaveservice_validate_media_1(mip, jobid, rcp ,clnt_handle); if (code == 0){ break; } sprintf(buf,"slaveservice_validate_media: RPC Errors from Master %d\n", code); slave_log_error(ABS_FATAL, "slave_validate", buf); /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); /* * Exponential Backoff */ sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } /* end while(1) */ /* * We are finished calling the master - destroy the * the connection */ destroy_handle(clnt_handle); return(0); } /* * Function: request_service * * Parameters: devname - pointer to string containing name of device * jobid - integer identifiying job which requires mount * * Description: This function issues a "job_attention" call to the master * to request the initiator to mount the media on "device". * */ int request_service(int jobid, int request_type, tapeid_t *mp) { CLIENT *clnt_handle; int code, interval = ABS_MIN_RETRY; int rc; job_attn_t ja; char buf[512], *msgp; ja.jobid = jobid; ja.cond = request_type; if (mp == (tapeid_t *)NULL) memset(&ja.media_id, 0, sizeof(tapeid_t)); else memcpy(&ja.media_id, mp, sizeof(tapeid_t)); if (request_type == ABS_TAPE_MOUNT_REQ){ slave_log_error(ABS_ERROR, "request_service", "requesting media mount from master"); } else if (request_type == ABS_RO_DEVICE){ slave_log_error(ABS_ERROR, "request_service", "Device not writeable!\n"); } while (1){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = code = 0; rc = slaveservice_job_attention_1(&ja, &code, clnt_handle); if (rc == 0){ /* check for transport errors */ if (code != 0){ /* check for call errors */ sprintf(buf, "slaveservice_job_attention: RPC Errors from Master %d\n", code); slave_log_error(ABS_ERROR, "request_mount", buf); } break; }else{ msgp = clnt_sperrno(rc); if (rc != RPC_TIMEDOUT || rc != RPC_INTR || rc != RPC_TLIERROR || rc != RPC_FAILED || rc != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, "request_mount", msgp); code = rc; break; } slave_log_error(ABS_ERROR, "request_mount", msgp); sprintf(buf,"slaveservice_job_done_1: RPC Errors from Master %d\n",rc); } slave_log_error(ABS_ERROR, "request_mount", buf); /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } destroy_handle(clnt_handle); return(code); } /* * Function: read_volume_header * * Parameters: dh - address of device information. * vhp - address of volume header * * Description: read_volume_header reads data from the device associated * with dh and places it in the area pointed to by vhp. The header * on the medium is written in network-byte-order and read_volume_header * will convert the data to host byte order. */ int read_volume_header(dev_handle_t *dh, abs_volheader_pt vhp) { int bytes, code; code = 0; bytes = SLAVE_READ(dh, dh->buf, ABS_REC_SIZE, &code); if (code) return(code); memcpy(vhp, dh->buf, sizeof(abs_volheader_t)); vhp->magic = ntohl(vhp->magic); vhp->absvolid_low = ntohl(vhp->absvolid_low); vhp->absvolid_high = ntohl(vhp->absvolid_high); vhp->size_low = ntohl(vhp->size_low); vhp->size_high = ntohl(vhp->size_high); vhp->fs_volid1 = ntohl(vhp->fs_volid1); vhp->fs_volid2 = ntohl(vhp->fs_volid2); if (vhp->magic != ABS_VOLHEADER_MAGIC){ return(ABS_INVALID_MAGIC); } return(0); } /* * Function: write_volume_header * * Parameters: dh - pointer to device information containing media state * vhp - address of media volume header to be written * * Description - Write a volume header to the medea asociated with * dh in machine independent format. * */ int write_volume_header(dev_handle_t *dh, abs_volheader_pt vhp) { int code, bytes, count; memset(dh->buf, 0, ABS_REC_SIZE); vhp->magic = htonl(vhp->magic); vhp->absvolid_low = htonl(vhp->absvolid_low); vhp->absvolid_high = htonl(vhp->absvolid_high); vhp->size_low = htonl(vhp->size_low); vhp->size_high = htonl(vhp->size_high); vhp->fs_volid1 = htonl(vhp->fs_volid1); vhp->fs_volid2 = htonl(vhp->fs_volid2); memcpy(dh->buf, vhp, sizeof(abs_volheader_t)); /* * write the volume header */ count = SLAVE_WRITE(dh, dh->buf, ABS_REC_SIZE, &code); if (count != ABS_REC_SIZE ){ return(code); } return(0); } int convert_system_error(int code) { switch(code){ case 0: return(0); case EIO: return(ABS_MEDIA_ERROR); case EAGAIN: return(ABS_DEVICE_BUSY); default: return(ABS_OS_ERROR); } } /* * Function: netvol_to_volheader * * Parameters: vp - address of netvol structure to be converted * vh - address of vol header * Description: convert a net_volume_t structure to a tape volume * header structure */ void netvol_to_volheader(net_volume_t *vp, abs_volheader_t *vh) { vh->magic = ABS_VOLHEADER_MAGIC; vh->absvolid_high = 0; vh->absvolid_low = vp->v_id; LLGET(vp->v_size, vh->size_high, vh->size_low); strcpy(vh->name, vp->v_name); strcpy(vh->server, vp->v_server); strcpy(vh->device, vp->v_part); strcpy(vh->fstype, vp->v_fstype); } void suicide(char *msg) { fprintf(stderr,msg); exit(1); } /* * Procedure: send status * * parameters:jobid - integer identifying job * job_status_pt - address of job status information * job_stat - status code for job. * * Description: Send a status update to the master informing it * of which volume we are currently dumping. This function * requests a UDP connection with "no-wait" mode since we don't * care if the message actually arrives. * * It can return * 0 - success * ABS_JOB_CANCELED - A user has requested that the job be canceled. * other non-zero - transmission errors */ int send_status(int jobid, job_status_pt job_stat) { CLIENT *clnt_handle = (CLIENT *) NULL; AUTH *authp = (AUTH *) NULL; struct timeval cv; char buf[ABS_REC_SIZE], *msgp; int code, rpc_code; strcpy(buf, master_server); clnt_handle = clnt_create(buf, ABS_SLAVESERVICE, ABS_SLVVERS, "tcp"); if (clnt_handle == (CLIENT *) NULL){ slave_log_error(ABS_FATAL, "send_status", "Cannot create connection to Master"); return(ABS_COMM_FAILURE); } if (get_slave_tgt()){ destroy_handle(clnt_handle); return(ABS_AUTH_ERROR); } code = 0; authkerb_create(master_princ, master_server, 0, AUTH_KERB, &code, &authp, clnt_handle); if (code){ slave_log_error(ABS_WARNING, "send_status", "Failed to setup RPC auth information"); destroy_handle(clnt_handle); return(ABS_AUTH_ERROR); } /* */ /* * place the status information in "job_stat" and * send it off to the master */ code = 0; rpc_code = slaveservice_job_status_1(job_stat, jobid, &code, clnt_handle); if (rpc_code){ msgp = clnt_sperrno(rpc_code); slave_log_error(ABS_ERROR,"send_status", msgp); } destroy_handle(clnt_handle); return(code); } /* * Procedure: handle_eom * * Parameters: dh - pointer to device specific info * jp - pointer to job information. * info - pointer to label info for tape which is at eom * verfmode - type of tape verification to use * * Description: handle_eom will rewind the tape which is at eom * and then request a media mount for a new media from the master. * handle_eom, upon detecting a tape in the drive, will attempt to * read and validate the tape label to ensure that the state * of the tape is "FREE". handle_eom will keep asking for a new * tape if the tape which is mounted to satisfy the eom condition * has a label which is not readable or writeable due to media * errors. */ int handle_eom(dev_handle_t *dh, job_pt jp, abs_label_t *label, net_dumpset_t *dp, char *verfmode) { int code, sequence, did_checkpoint; char buf[256]; media_t *tmp, *mp; abs_label_t old; sequence = label->sequence + 1; code = ABS_EOM_DETECTED; did_checkpoint = 0; tmp = (media_t *) NULL; memcpy(&old, label, sizeof(abs_label_t)); while( code == ABS_MEDIA_ERROR || code == ABS_EOM_DETECTED){ do { /* * The inner loop tries hard to get a tape mounted. * * Send the info for this tape back to the master * If we fail, then we keep the tape/vol info around * and it will be sent with the next tape checkpoint * or when the job completes. */ if (did_checkpoint == 0) { code = media_checkpoint(dh, jp, dp, verfmode); if (code == ABS_JOB_CANCELED) return(ABS_JOB_CANCELED); if (code == 0){ did_checkpoint = 1; } }else{ code = SLAVE_REWIND(dh); if (code){ return(code); } SLAVE_CLOSE_PARTIAL(dh); } /* * Keep asking for a tape mount until the operator * mounts something we can use */ code = request_service(jp->jobid, ABS_TAPE_OVERRUN, NULL); if (code){ /* * Something really bad happened and we couldn't get the * tape mount request over to the master. */ sprintf(buf, "Request for media mount failed code = %d\n",code); slave_log_error(ABS_ERROR, "handle_eom", buf); return(code); } /* * Give the guy time to mount a new tape after we ask */ sleep(180); /* * The request is sent, so try to see if there is * something we can use in the drive. */ code = SLAVE_OPEN(dh->dev_ops, &dh, dh->devname, O_RDWR, jp->jobid); if (code) continue; /* * Now try to find a tape with a label which is * marked as FREE in the master's database */ code = cycle_through_tapes(dh, jp->jobid, (char *)NULL, (media_id_pt) NULL, ABS_FREE_MEDIA); }while(code != 0 && code != ABS_BLANK_MEDIUM); if (code == ABS_BLANK_MEDIUM){ code = label_tape_for_dump(dh, jp->jobid); if (code) continue; } /* * We now have a tape which we are able to use so * rewrite the dynamic portion of the label */ code = SLAVE_REWIND(dh); if (code){ continue; } if ((code = read_label(dh, label))){ continue; } if (!memcmp(&label->tapeid, &old.tapeid, sizeof(media_id))){ /* * The old tape is still in the drive; We need to * check this separately since it's possible that * we were unable to checkpoint and the Master's database * doesn't have any info about the tapes we used. */ code = ABS_NEEDS_MOUNT; continue; } label->block_size = dh->bufsize; label->level = old.level; label->uses++; label->sequence = sequence; label->tape_created = old.tape_created; strncpy(label->cell, old.cell, ABS_MAX_DOMAIN); strncpy(label->dumpset, old.dumpset, ABS_MAX_DNAME); /* * Write the new label to the medium */ code = SLAVE_REWIND(dh); if (code){ continue; } if ((code = write_label(dh, label))){ continue; } } /* end of big loop */ /* * Copy the internal id of the new media to the * tapeset record */ if (code == 0){ /* * if we failed to checkpoint, then we need to allocate * a new tapeset member; otherwise we just copy the * new id into the old media_t area. */ if (!(did_checkpoint)){ tmp = (media_t *) malloc(sizeof(media_t)); if (tmp == (media_t *) NULL){ return(ABS_NO_MEM); } memset(tmp, 0, sizeof(media_t)); tmp->next = dp->tape_sets->tapes; dp->tape_sets->tapes = tmp; } memcpy(&dp->tape_sets->tapes->internal, &label->tapeid, sizeof(media_id_t)); dp->tape_sets->tapes->log_tape = 1; } return(code); } /* * Procedure: slave_scan_results * * Parameters: status - integer containing job status code to send to master * jobid - integer representing job id for executed job * tocp - address of table of contents info to send * * Description: This procedure creates an RPC connection to the Master * and attempts to send the results to the master via the abs_toc_results * interface. The procedure will execute exponential retry on RPC failures */ int slave_scan_results(int status, int jobid, toc_res_pt tocp) { CLIENT *clnt_handle = (CLIENT *) NULL; int code, rc, interval = ABS_MIN_RETRY, retries, again; char buf[ABS_REC_SIZE], *msgp; /* * Save the job info to disk just in case */ code = save_job_info(jobid, status, tocp, TOC_TYPE); retries = 0; again = 1; do{ if (retries){ destroy_handle(clnt_handle); /* * Exponential Backoff */ sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = code = 0; rc = slaveservice_scan_results_1(jobid, tocp, &code, clnt_handle); again = check_call_completion(rc, code, "slave_scan_results"); retries++; }while(again == ABS_COMM_FAILURE); /* end while(1) */ /* * We are finished calling the master - destroy the * the connection. We arrive here because the call either * completed successfully or there is an unrecoverable error * which we will not retry at this time. */ destroy_handle(clnt_handle); if (again == 0) delete_job_info(jobid); return(code); } int check_call_completion(int rpc_code, int call_code, char *routine) { char buf[1024]; char *msgp; if (rpc_code == 0){ /* check for transport errors */ if (call_code == 0) /* check for call errors */ return(0); sprintf(buf,"Errors from Master Interface %d\n", call_code); slave_log_error(ABS_ERROR,routine, buf); return(call_code); }else{ msgp = clnt_sperrno(rpc_code); if (rpc_code != RPC_TIMEDOUT || rpc_code != RPC_INTR || rpc_code != RPC_TLIERROR || rpc_code != RPC_FAILED || rpc_code != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, routine, msgp); return(-1); } slave_log_error(ABS_ERROR, routine, msgp); sprintf(buf,"slaveservice_job_done_1: RPC Errors from Master %d\n",rpc_code); return(ABS_COMM_FAILURE); } } int request_internal_label(int jobid, media_id_t *mip) { CLIENT *clnt_handle; int interval = ABS_MIN_RETRY; int rc, code; internal_label_res_t res; job_attn_t ja; char buf[512], *msgp; code = 0; while (1){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = 0; rc = slaveservice_gen_label_1(jobid, &res, clnt_handle); if (rc == 0){ /* check for transport errors */ code = res.code; break; }else{ msgp = clnt_sperrno(rc); if (rc != RPC_TIMEDOUT || rc != RPC_INTR || rc != RPC_TLIERROR || rc != RPC_FAILED || rc != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, "request_internal_label", msgp); code = rc; break; } slave_log_error(ABS_ERROR, "request_internal_label", msgp); sprintf(buf,"slaveservice_gen_label_1: RPC Errors from Master %d\n",rc); } slave_log_error(ABS_ERROR, "request_mount", buf); /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } destroy_handle(clnt_handle); if (code == 0){ memcpy(mip, &res.internal_label_res_u.value, sizeof( media_id_t)); } return(code); } /* * Procedure: media_checkpoint * * Parameters: jp - address of job information for this job * dp - address of dumpset * * Description - this function attempts to send the volume/tape * information to the master as part of the media checkpoint. * It tries a maximum of 3 times. The volume/tape information * is deleted if the data was sent successfully. * * Modifies: dp->tape_sets->tapes */ int media_checkpoint(dev_handle_t *dh, job_pt jp, net_dumpset_t *dp, char *verfmode) { CLIENT *clnt_handle; int code, interval = ABS_MIN_RETRY; int rc, retries; job_done_res_t jd; char buf[512], *msgp; media_id_t *mid; media_t *mp; /* * Perform media verification */ rc = perform_media_verification(dh, dp, verfmode); SLAVE_REWIND(dh); SLAVE_CLOSE_PARTIAL(dh); if (!online){ SLAVE_OFFLINE(dh); } /* * setup the results structure */ jd.jdr_type = jdr_type_dumpset; jd.jdr_dumpset = dp; retries = 0; while (retries < 3){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = code = 0; rc = slaveservice_dump_checkpoint_1(jp->jobid, &jd, &code, clnt_handle); if (rc == 0){ /* check for transport errors */ if (code == 0) /* check for call errors */ break; else{ if (ABS_MIN_ERR < code < ABS_MAX_ERR){ /* * The master had some trouble with our results. * this is fatal and we won't retry. */ sprintf(buf,"slaveservice_dump_checkpoint_1: Errors from Master for job %d: %s\n", jp->jobid, get_abs_msg(code)); slave_log_error(ABS_FATAL, "slave_notify_master", buf); }else{ sprintf(buf,"slaveservice_dump_checkpoint_1: RPC Int Errors from Master %d\n", code); slave_log_error(ABS_ERROR, "slave_notify_master", buf); } break; } }else{ /* transport errors */ msgp = clnt_sperrno(rc); if (rc != RPC_TIMEDOUT || rc != RPC_INTR || rc != RPC_TLIERROR || rc != RPC_FAILED || rc != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, "slave_notify_master", msgp); break; } slave_log_error(ABS_ERROR, "slave_notify_master", msgp); sprintf(buf,"slaveservice_dump_checkpoint_1: RPC Errors from Master %d\n",rc); } /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); clnt_handle = (CLIENT *) NULL; /* * Exponential Backoff */ sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } /* end while(1) */ /* * We are finished calling the master - destroy the * the connection */ if (clnt_handle) destroy_handle(clnt_handle); /* * success - we can delete the media information for * the data we just sent */ if (code == 0){ for (mp = dp->tape_sets->tapes; mp != (media_pt) NULL; mp = mp->next){ if (mp->volumes){ abs_free_netvol(mp->volumes); mp->volumes = (net_volume_t *) NULL; } } /* * Free up any extra tape structures, keeping * only one to be reused. */ if (dp->tape_sets->tapes->next){ abs_free_media(dp->tape_sets->tapes->next); mp->next = (media_t *) NULL; } } return(code); } @ 5.1 log @Make slave_notify_master retry when it gets Errors from the master (e.g., dbms update error) @ text @d537 1 a537 1 * and attempts to send the results to the master via the abs_job_done d539 1 d547 1 a547 1 int code, rc, interval = ABS_MIN_RETRY, retries, again; d563 1 a563 2 again = 1; while (again){ d569 1 a569 1 rc = abs_job_done_1(status, jobid, jdp, &code, clnt_handle); d580 1 a580 1 sprintf(buf,"abs_job_done_1: Errors from Master for job %d: %s\n", jobid, get_abs_msg(code)); a581 1 again=1; d583 1 a583 1 sprintf(buf,"abs_job_done_1: RPC Int Errors from Master %d\n", a599 1 again=0; d602 1 a602 1 sprintf(buf,"abs_job_done_1: RPC Errors from Master %d\n",rc); d640 1 a640 1 * via the abs_validate_media interface. The procedure will execute exponential d657 1 a657 1 code = abs_validate_media_1(mip, jobid, rcp ,clnt_handle); d662 1 a662 1 sprintf(buf,"abs_validate_media: RPC Errors from Master %d\n", code); d729 1 a729 1 rc = abs_job_attention_1(&ja, &code, clnt_handle); d734 1 a734 1 "abs_job_attention: RPC Errors from Master %d\n", d755 1 a755 1 sprintf(buf,"abs_job_done_1: RPC Errors from Master %d\n",rc); d951 1 a951 1 rpc_code = abs_job_status_1(job_stat, jobid, &code, clnt_handle); d1171 1 a1171 1 rc = abs_toc_results_1(jobid, tocp, &code, clnt_handle); d1218 1 a1218 1 sprintf(buf,"abs_job_done_1: RPC Errors from Master %d\n",rpc_code); d1244 1 a1244 1 rc = abs_gen_label_1(jobid, &res, clnt_handle); d1265 1 a1265 1 sprintf(buf,"abs_job_done_1: RPC Errors from Master %d\n",rc); d1337 1 a1337 1 rc = abs_dump_checkpoint_1(jp->jobid, &jd, &code, clnt_handle); d1348 1 a1348 1 sprintf(buf,"abs_dump_checkpoint_1: Errors from Master for job %d: %s\n", jp->jobid, get_abs_msg(code)); d1351 1 a1351 1 sprintf(buf,"abs_dump_checkpoint_1: RPC Int Errors from Master %d\n", d1372 1 a1372 1 sprintf(buf,"abs_dump_checkpoint_1: RPC Errors from Master %d\n",rc); @ 5.0 log @remove fakeslave names @ text @d11 1 d13 2 d16 2 a17 1 int media_checkpoint(job_pt jp, net_dumpset_t *dp); d38 2 a39 2 {nodev, nodev, nodev, nodev, nodev, nodev, nodev, noname}, {nodev, nodev, nodev, nodev, nodev, nodev, nodev, noname}, d514 1 a514 1 authkerb_create("rcmd", master_server, 0, AUTH_KERB, &rc, &authp, d578 1 a578 1 * this is fatal and we won't retry. d582 1 a582 1 again=0; d937 1 a937 1 authkerb_create("rcmd", master_server, 0, AUTH_KERB, &code, &authp, d968 1 d981 2 a982 1 handle_eom(dev_handle_t *dh, job_pt jp, abs_label_t *info, net_dumpset_t *dp) a985 1 abs_label_t label; d987 3 a989 2 media_t *tmp; d991 1 a991 1 sequence = label.sequence + 1; d994 2 a997 5 code = SLAVE_REWIND(dh); if (code){ return(code); } SLAVE_CLOSE_PARTIAL(dh); d999 2 d1006 15 a1020 8 code = media_checkpoint(jp, dp); if (code == ABS_JOB_CANCELED) return(ABS_JOB_CANCELED); if (code == 0){ did_checkpoint = 1; } memset(tmp, 0, sizeof(media_t)); d1025 2 a1026 5 if ( code == ABS_NEEDS_MOUNT){ code = request_service(jp->jobid, ABS_TAPE_OVERRUN, NULL); }else{ code = request_service(jp->jobid, ABS_REPLACE_TAPE, NULL); } d1046 1 a1046 1 code = SLAVE_OPEN(dh->dev_ops, dh, dh->devname, O_RDWR, jp->jobid); d1055 7 a1061 4 } while(code == ABS_INVALID_MEDIA_ID || code == ABS_NEEDS_MOUNT); if (code){ continue; } d1070 1 a1070 1 if ((code = read_label(dh, &label))){ d1073 1 a1073 1 if (!memcmp(&label.tapeid, &info->tapeid, sizeof(media_id))){ d1075 4 a1078 1 * The old tape is still in the drive d1083 7 a1089 7 label.block_size = dh->bufsize; label.level = info->level; label.uses++; label.sequence = sequence; label.tape_created = info->tape_created; strncpy(label.cell, info->cell, ABS_MAX_DOMAIN); strncpy(label.dumpset, info->dumpset, ABS_MAX_DOMAIN); d1097 1 a1097 1 if ((code = write_label(dh, &label))){ d1101 1 a1101 1 }/* end while media error */ d1122 2 a1123 2 memcpy(&dp->tape_sets->tapes->internal, &label.tapeid, sizeof(media_id_t)); a1124 2 return(code); } a1125 70 int next_medium(dev_handle_t *dh, job_pt jp, media_id_pt midp) { int code; abs_label_t label; char buf[256]; code = ABS_EOM_DETECTED; while( code == ABS_WRONG_TAPE || code == ABS_EOM_DETECTED){ do { code = SLAVE_REWIND(dh); if (code){ return(code); } SLAVE_CLOSE_PARTIAL(dh); /* * Keep asking for a tape mount until the operator * mounts something we can use */ if ( code == ABS_NEEDS_MOUNT ){ code = request_service(jp->jobid, ABS_TAPE_OVERRUN, NULL); }else{ code = request_service(jp->jobid, ABS_WRONG_TAPE, NULL); } if (code){ /* * Something really bad happened and we couldn't get the * tape mount request over to the master. */ sprintf(buf, "Request for media mount failed code = %d\n",code); slave_log_error(ABS_ERROR, "handle_eom", buf); return(code); } /* * Give the guy time to mount a new tape after we ask */ sleep(180); /* * The request is sent, so try to see if there is * something we can use in the drive. */ code = SLAVE_OPEN(dh->dev_ops, dh, dh->devname, O_RDWR, jp->jobid); if (code) continue; /* * Now try to find a tape with a label which is * marked as FREE in the master's database */ code = cycle_through_tapes(dh, jp->jobid, (char *)NULL, midp, ABS_VALID_MEDIA); } while(code == ABS_INVALID_MEDIA_ID || code == ABS_NEEDS_MOUNT); if (code){ continue; } /* * We now have a tape which we are able to use so * rewrite the dynamic portion of the label */ code = SLAVE_REWIND(dh); if (code){ continue; } if ((code = read_label(dh, &label))){ continue; } } d1306 1 a1306 1 media_checkpoint(job_pt jp, net_dumpset_t *dp) d1314 2 a1315 1 media_id_t *mp; d1317 9 d1405 13 a1417 1 if (dp->tape_sets->tapes->next != (media_t *) NULL){ d1419 1 a1419 1 dp->tape_sets->tapes = (media_t *) NULL; d1421 1 a1421 1 abs_free_netvol(dp->tape_sets->tapes->volumes); @ 4.0 log @"slaveint" changed to "slaveservice" @ text @d11 4 a14 1 char master_server[256]=""; d35 1 a35 2 {devfs_next_file, devfs_rewind, devfs_next_medium, devfs_read, devfs_write, devfs_open, devfs_close, nodev, noname}, d538 1 a538 1 slave_notify_master(int status, int jobid, job_done_res_pt jdp) d549 3 a551 2 if (jdp->jdr_type == jdr_type_dumpset) code = save_job_info(jobid, status, jdp->jdr_dumpset, d553 2 a554 2 else if (jdp->jdr_type == jdr_type_volume){ code = save_job_info(jobid, status, jdp->jdr_volume, d556 1 d976 1 a976 1 handle_eom(dev_handle_t *dh, job_pt jp, abs_label_t *info) d978 2 a979 1 int code, sequence; d982 2 d987 1 a994 1 d996 14 d1085 1 a1085 5 /* * Now copy the new label information into "info" so that * the high-level dump routine knows about the new tape */ memcpy(info, &label, sizeof(abs_label_t)); d1087 23 d1113 1 d1347 118 @ 3.6 log @Support SLAVE_OFFLINE device routine D @ text @d3 1 a3 1 #include a11 1 static char _jobs_dir[PATH_MAX]; a44 1 extern char *jobs_dir; d490 1 a490 1 while ((clnt_handle = clnt_create(master_server, ABS_SLAVEINT, d915 1 a915 1 clnt_handle = clnt_create(buf, ABS_SLAVEINT, a1070 36 } /* * Procedure: delete_job_info * * Parameters: jobid - jobid for job whose info is to be deleted. * * Description: this function removes the on-disk copy of the * job results information associated with "jobid". */ int delete_job_info(int jobid) { char name[ABS_MAX_PATH]; int code; sprintf(name,"%s/%d",get_jobs_dir(), jobid); code = unlink(name); return(code); } char * get_jobs_dir() { return(_jobs_dir); } int set_jobs_dir(char *name) { if (strlen(name) > PATH_MAX){ slave_log_error(ABS_FATAL,"set_jobs_dir", "Jobs directory name too long"); return(ABS_INVALID_SPEC); } strcpy(_jobs_dir, name); return(0); @ 3.5 log @autolabel baseline @ text @d22 1 d34 1 a34 1 devfs_read, devfs_write, devfs_open, devfs_close, noname}, d36 1 a36 1 mtio_read, mtio_write, mtio_open, mtio_close, mtio_devtype}, d299 1 a299 1 return(ABS_INVALID_MEDIA_ID); d483 1 d512 9 d1280 64 @ 2.5 log @ "request_service" passed a null pointer to "slave_log_error" in the case where the rpc request successed eded but the executeion code was non-xzero @ text @@ 2.4 log @validate_label convertes eom or oefeof detected errors to ABS_INVALID_MEDIA in the case where the caller expectexzs the media to have a valid abs label. this will allow the caller to requredetect dcesthe cases where a media mount needs to be issued @ text @d721 1 a721 1 slave_log_error(ABS_ERROR, "request_mount", msgp); @ 2.3 log @Change NEXT_CONTROL_REC macro and replace with NEXT_VOLHEADER or NEXT_VOLFOOTER. Also fix find_control_rec so that backupward spacing to the previous control rec will now work @ text @d297 2 @ 2.2 log @routines which deal with RPC connection management need to desttroy the client auth information when the ey destroy the client handle @ text @d386 1 a386 1 return(ABS_BAD_MAGIC); d409 1 a409 1 find_control_rec(dev_handle_t *dh, int count) d411 1 a411 1 int bytes, code, magic, direction; d415 1 a415 4 if (count < 0) direction = 1; else direction = -1; d419 5 d432 11 d450 2 a451 2 if (magic == ABS_VOLHEADER_MAGIC || magic == ABS_VOLFOOTER_MAGIC){ code = SLAVE_NEXT_RECORD(dh, direction); a461 1 d786 1 a786 1 return(ABS_BAD_MAGIC); a1264 34 } /* * Procedure: next_volume_header * * Parameters: dh - address of device-specific information * * Description: This function moves the media to the start of the * Next volume header record. This function reads each record, begining * with the current record to determine if it is a volume header. * The function continues to reach records until EOM is reach or a volume * header is found (512 byte record size and matching magic number). */ int next_volume_header(dev_handle_t *dh) { int code, bytes; int magic; magic = 0; bytes = SLAVE_READ(dh, dh->buf, ABS_REC_SIZE, &code); memcpy(&magic, dh->buf, sizeof(int)); magic = ntohl(magic); while (magic != ABS_VOLFOOTER_MAGIC){ code = NEXT_CONTROL_REC(dh); if (code) return(code); bytes = SLAVE_READ(dh, dh->buf, ABS_REC_SIZE, &code); memcpy(&magic, dh->buf, sizeof(int)); magic = ntohl(magic); } @ 2.1 log @alpha release @ text @d450 2 d453 11 d467 2 a468 1 CLIENT *clnt_handle; d470 1 d472 5 a476 1 while ((clnt_handle = clnt_create(master_server, ABS_SLAVEINT, d478 10 d489 2 a490 1 * The master has disappeared completely! d492 5 a496 8 clnt_pcreateerror(master_server); slave_log_error(ABS_FATAL, "connect_to_master", "Cannot create connection to Master"); sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } return(clnt_handle); d582 1 a582 1 clnt_destroy(clnt_handle); d596 1 a596 2 if (clnt_handle) clnt_destroy(clnt_handle); d641 1 a641 1 clnt_destroy(clnt_handle); d655 1 a655 2 if (clnt_handle) clnt_destroy(clnt_handle); d677 1 a677 1 char buf[ABS_REC_SIZE], *msgp; d703 3 a705 2 if (code != 0) /* check for call errors */ sprintf(buf,"abs_job_attention: RPC Errors from Master %d\n", d707 2 d736 1 a736 1 clnt_destroy(clnt_handle); d741 1 a741 2 if (clnt_handle) clnt_destroy(clnt_handle); d885 2 a886 1 CLIENT *clnt_handle; d900 15 a914 1 } d927 1 a927 2 if (clnt_handle) clnt_destroy(clnt_handle); d1176 1 a1176 1 CLIENT *clnt_handle; d1189 1 a1189 1 clnt_destroy(clnt_handle); d1214 1 a1214 2 if (clnt_handle) clnt_destroy(clnt_handle); @ 1.1 log @Initial revision @ text @@ slave/RCS/scan.c,v100400 6031 145 11652 6240130505 13312 0ustar delgadoorawebhead 6.0; branch ; access ; symbols autolabel-baseline:3.5 alpha:2.1; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.39.49; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.37; author delgado; state Exp; branches ; next 4.0; 4.0 date 96.04.19.11.22.41; author delgado; state Exp; branches ; next 3.5; 3.5 date 96.03.12.12.36.19; author delgado; state Exp; branches ; next 2.2; 2.2 date 96.03.10.17.30.19; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.23.28; author delgado; state Exp; branches ; next 1.1; 1.1 date 95.12.27.11.43.30; author delgado; state Exp; branches ; next ; desc @Read new tape format @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" int do_scan(dev_handle_t *dh, toc_res_pt trp, int full_scan) { toc_pt tocp, tmp; int abort_now=0, bytes, code; abs_label_pt labelp; tocp = (toc_pt) malloc(sizeof(toc_t)); if (tocp == (toc_pt) NULL){ trp->code = ABS_NO_MEM; } memset(tocp, 0, sizeof(toc)); labelp = &tocp->data.tt_label; tocp->data.tt_type = label; code = read_label(dh, labelp); if (code){ trp->code = code; free(tocp); trp->toc_res_u.value = NULL; return(code); } if (!full_scan){ if (labelp->magic != ABS_LABEL_MAGIC){ trp->code = ABS_INVALID_LABEL; free(tocp); trp->toc_res_u.value = NULL; return(ABS_INVALID_LABEL); } trp->code = 0; trp->toc_res_u.value = tocp; return(0); } /* * Full scan is requested - we try hard to see if there * is ABS data on the tape. If we can't read the label * the see if the next record contains a volume header. */ if (labelp->magic != ABS_LABEL_MAGIC){ /* * Try to see if the next record on the tape * might be a valid volume header */ abort_now = 1; } trp->toc_res_u.value = tocp; tmp = tocp; while (1){ if (get_slave_state() == SLAVE_TERMINATED){ return(ABS_JOB_CANCELED); } tocp = (toc *) malloc(sizeof(toc)); if (tocp == (toc *) NULL){ trp->code = ABS_NO_MEM; break; } memset(tocp, 0, sizeof(toc)); tocp->data.tt_type = volheader; code = read_volume_header(dh, &(tocp->data.tt_volume)); if ((code == ABS_EOF_DETECTED) || (code == ABS_EOM_DETECTED)){ /* end of medium */ free(tocp); code = 0; break; } if (code && abort_now){ free(tocp); trp->code = ABS_INVALID_LABEL; break; } /* * try to space forward to the next volume * maybe we can read the tape then. */ if (code){ abort_now = 1; /* * indicate that there is a bad record on the * tape */ tocp->data.tt_volume.magic = 0; }else abort_now = 0; tmp->next = tocp; tmp = tmp->next; /* * The "next file" is considered to be the next * control record which is actually the volume footer * The volume footer should be followed by another control * record which is the volume header. */ code = NEXT_VOLFOOTER(dh); if ((code == ABS_EOF_DETECTED) || (code == ABS_EOM_DETECTED)){ /* end of medium */ code = 0; break; } if (code && abort_now){ trp->code = code; break; } tocp = (toc *) malloc(sizeof(toc)); if (tocp == (toc *) NULL){ trp->code = ABS_NO_MEM; break; } memset(tocp, 0, sizeof(toc)); tocp->data.tt_type = volfooter; if (code) abort_now = 1; code = read_volume_footer(dh, &(tocp->data.tt_volfooter)); if (code && abort_now){ free(tmp); trp->code = code; break; } if (code) abort_now = 1; tmp->next = tocp; tmp = tmp->next; } trp->code = code; if (trp->code){ free(trp->toc_res_u.value); trp->toc_res_u.value = NULL; } return(code); } @ 5.0 log @remove fakeslave names @ text @@ 4.0 log @"slaveint" changed to "slaveservice" @ text @@ 3.5 log @autolabel baseline @ text @d2 1 a2 1 #include @ 2.2 log @Support graceful termination with SIGTERM @ text @@ 2.1 log @alpha release @ text @d56 3 d101 1 a101 1 code = NEXT_CONTROL_REC(dh); @ 1.1 log @Initial revision @ text @d98 1 a98 1 code = next_control_rec(dh); @ slave/RCS/defs.h,v100400 6031 145 2473 6240130525 13277 0ustar delgadoorawebhead 6.0; branch ; access ; symbols alpha:2.1; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.40.05; author delgado; state Exp; branches ; next 2.2; 2.2 date 96.03.12.12.31.02; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.24.58; author delgado; state Exp; branches ; next ; desc @@ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @/* * Please do not edit this file. * It was generated using rpcgen. */ #ifndef _DEFS_H_RPCGEN #define _DEFS_H_RPCGEN #include #include #include #ifdef __cplusplus extern "C" { #endif struct abs_vol_header { int magic; int absvolid_low; int abs_volid_high; longlong_t size; char name[MEDIA_NAME_MAX]; char server[MEDIA_SERVER_MAX]; char device[MEDIA_DEVICE_MAX]; int fstype; int fs_volid1; int fs_volid2; char fs_private[128]; char reserved[32]; }; typedef struct abs_vol_header abs_vol_header; /* the xdr functions */ #if defined(__STDC__) || defined(__cplusplus) extern bool_t xdr_abs_vol_header(XDR *, abs_vol_header*); #else /* K&R C */ extern bool_t xdr_abs_vol_header(); #endif /* K&R C */ #ifdef __cplusplus } #endif #endif /* !_DEFS_H_RPCGEN */ @ 2.2 log @autolabel baseline @ text @@ 2.1 log @alpha release @ text @@ slave/RCS/slave_auth.c,v100400 6031 145 7606 6240130506 14506 0ustar delgadoorawebhead 6.0; branch ; access ; symbols full-auth:3.2 alpha:3.1; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.39.50; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.15.59; author delgado; state Exp; branches ; next 3.4; 3.4 date 96.05.20.11.09.45; author delgado; state Exp; branches ; next 3.3; 3.3 date 96.03.12.12.30.25; author delgado; state Exp; branches ; next 3.2; 3.2 date 96.02.23.15.48.51; author delgado; state Exp; branches ; next 3.1; 3.1 date 96.02.23.15.47.48; author delgado; state Exp; branches ; next ; desc @Support for managing slaves credentials @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include #include "../master/abs_msg.h" #include "private.h" extern char myhost[]; extern char master_server[]; extern char slave_princ[]; extern char master_princ[]; static int have_realm=0; static char realm[REALM_SZ]; /* keeps track of our realm so we don't have to * keep calling "krb_get_lrealm" */ int get_slave_tgt() { int rc; char msg[512]; if (! have_realm){ rc = krb_get_lrealm(realm, 1); if (rc != KSUCCESS){ slave_log_error(ABS_FATAL, "abs_check_auth", "krb_get_lrealm failed\n!"); return(ABS_AUTH_ERROR); } have_realm = 1; } /* * Get rid of any tickets which we may be currently holding * since the prinicpal may not be valid or might have been * inherited from the shell which spawned us. */ rc = dest_tkt(); if (rc){ sprintf(msg, "Error %d from dest_tkt - %s\n", rc, krb_err_txt[rc]); slave_log_error(ABS_ERROR, "get_slave_tgt", msg); } /* * Get a tgt so that we can get tickets to the master and * file servers. */ rc = krb_get_svc_in_tkt(slave_princ, myhost, realm , "krbtgt", realm, 24*60, "/etc/athena/srvtab" ); if (rc){ sprintf(msg, "Error %d from krb_get_svc_in_tkt - %s\n", rc, krb_err_txt[rc]); slave_log_error(ABS_ERROR, "get_slave_tgt", msg); return(ABS_AUTH_ERROR); } return(0); } int slave_check_authentication(struct svc_req *client) { struct authkerb_clnt_cred *cred; int rc; /* * client is not using Kerberos with data integrity, then deny * the request since we can't trust it! */ if (client->rq_cred.oa_flavor != AUTH_KERB_INTEGRITY){ return(0); } cred = (struct authkerb_clnt_cred *) client->rq_clntcred; /* First check the client's realm; if it's not the same as * ours, then reject the request */ if (! have_realm){ rc = krb_get_lrealm(realm, 1); if (rc != KSUCCESS){ slave_log_error(ABS_ERROR, "abs_check_auth", "krb_get_lrealm failed\n!"); return(ABS_AUTH_ERROR); } have_realm = 1; } /* * We do not accept requests from Masters in * different realms or on servers other than the one * we were configured with. */ if (strcmp(realm, cred->prealm)){ return(ABS_AUTH_ERROR); } if (strcmp(cred->pname, master_princ)){ return(ABS_AUTH_ERROR); } if (strcmp(cred->pinst, master_server )){ return(ABS_AUTH_ERROR); } return(0); } @ 5.0 log @change fakeslave names to slave @ text @d11 2 d50 1 a50 1 rc = krb_get_svc_in_tkt("rcmd", myhost, realm , "krbtgt", realm, 24*60, d101 1 a101 1 if (strcmp(cred->pname, "rcmd")){ @ 3.4 log @*** empty log message *** @ text @@ 3.3 log @autolabel baseline @ text @d2 1 a2 1 #include @ 3.2 log @Full authentication revision @ text @a109 1 @ 3.1 log @Support for managing slaves credentials @ text @@ slave/RCS/job_info.c,v100400 6031 145 13725 6240130504 14155 0ustar delgadoorawebhead 6.0; branch ; access ; symbols ; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.39.48; author delgado; state Exp; branches ; next 5.1; 5.1 date 96.10.31.20.07.51; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.35; author delgado; state Exp; branches ; next 4.0; 4.0 date 96.04.19.11.22.27; author delgado; state Exp; branches ; next ; desc @mange saved job info @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include #include #include "../master/abs_msg.h" #include "../master/os_defs.h" #include "private.h" #include "prototypes.h" #undef d_name #include static char _jobs_dir[PATH_MAX]; /* * Procedure: delete_job_info * * Parameters: jobid - jobid for job whose info is to be deleted. * * Description: this function removes the on-disk copy of the * job results information associated with "jobid". */ int delete_job_info(int jobid) { char name[PATH_MAX]; int code; sprintf(name,"%s/%d",get_jobs_dir(), jobid); code = unlink(name); return(code); } char * get_jobs_dir() { return(_jobs_dir); } int set_jobs_dir(char *name) { if (strlen(name) > PATH_MAX){ slave_log_error(ABS_FATAL,"set_jobs_dir", "Jobs directory name too long"); return(ABS_INVALID_SPEC); } strcpy(_jobs_dir, name); return(0); } free_job_info(job_done_res_t *jdp) { XDR xdrs; xdrmem_create(&xdrs, (caddr_t)jdp, sizeof(job_done_res_t),XDR_FREE); /* xdr_job_done_res_t(&xdrs, jdp); */ } int save_job_info(int jobid, int status, void *data, int datatype) { FILE *fp; char name[PATH_MAX]; XDR xdrs; sprintf(name,"%s/%d",get_jobs_dir(), jobid); fp = fopen(name,"w+"); if (fp == (FILE *) NULL){ /* * Send criticla message! */ return(ABS_OS_ERROR); } xdrstdio_create(&xdrs, fp, XDR_ENCODE); if (xdr_int(&xdrs, &jobid) == FALSE){ return(ABS_CANT_ENCODE); } if (xdr_int(&xdrs, &status) == FALSE){ return(ABS_CANT_ENCODE); } if (xdr_int(&xdrs, &datatype) == FALSE){ return(ABS_CANT_ENCODE); } if (datatype == DUMPSET_TYPE){ if (xdr_net_dumpset_pt(&xdrs, (net_dumpset_t **)&data) == FALSE){ return(ABS_CANT_ENCODE); } }else if (datatype == TOC_TYPE){ if (xdr_toc_res_pt(&xdrs, (toc_res_pt *)&data) == FALSE){ return(ABS_CANT_ENCODE); } }else if (datatype == VOLUME_TYPE){ if (xdr_net_volume_pt(&xdrs, (net_volume_t **)&data) == FALSE){ return(ABS_CANT_ENCODE); } } return(0); } void recover_saved_jobs( char *master) { FILE *fp; int status, jobid, datatype; char name[PATH_MAX]; char buf[PATH_MAX+30]; job_done_res jd; XDR xdrs; DIR *dp; struct dirent *entp; slave_log_error(ABS_INFORMATIONAL,"recover_saved_jobs", "Scanning for old job info"); dp = opendir(_jobs_dir); if (dp == (DIR *) NULL){ sprintf(buf,"Cant open directory %s\n", _jobs_dir); slave_log_error(ABS_ERROR,"recover_saved_jobs", buf); return; } while ((entp=readdir(dp)) != (struct dirent *) NULL){ if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, "..")) continue; sprintf(name,"%s/%s", _jobs_dir, entp->d_name); sprintf(buf, "Found file %s\n", name); slave_log_error(ABS_INFORMATIONAL,"recover_saved_jobs", buf); fp = fopen(name,"r"); if (fp == (FILE *) NULL){ sprintf(buf,"Cant open file %s\n", name); slave_log_error(ABS_ERROR,"recover_saved_jobs", buf); continue; } xdrstdio_create(&xdrs, fp, XDR_DECODE); if (xdr_int(&xdrs, &jobid) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } if (xdr_int(&xdrs, &status) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } if (xdr_int(&xdrs, &datatype) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } if (datatype == DUMPSET_TYPE){ jd.jdr_type = jdr_type_dumpset; if (xdr_net_dumpset_pt(&xdrs, &jd.jdr_dumpset) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } }else if (datatype == VOLUME_TYPE){ jd.jdr_type = jdr_type_volume; if (xdr_net_volume_pt(&xdrs, &jd.jdr_volume) == FALSE){ sprintf(buf,"Bad format for job file %s \n", name); slave_log_error(ABS_WARNING,"recover_saved_jobs", buf); continue; } }else{ continue; } slave_notify_master(status, jobid, &jd, 0); fclose(fp); unlink(name); free_job_info(&jd); } slave_log_error(ABS_INFORMATIONAL,"recover_saved_jobs", "Done recovering old job info"); } @ 5.1 log @Change ABS_MAX_PATH to use posx PATH_MAX for pathname lengths. @ text @@ 5.0 log @remove fakeslave names @ text @d27 1 a27 1 char name[ABS_MAX_PATH]; d65 1 a65 1 char name[ABS_MAX_PATH]; d109 2 a110 2 char name[ABS_MAX_PATH]; char buf[ABS_MAX_PATH+30]; @ 4.0 log @"slaveint" changed to "slaveservice" @ text @d3 1 d10 2 d13 1 d53 7 d77 4 d84 3 d88 1 a88 1 if (xdr_net_dumpset_pt(&xdrs, &data) == FALSE){ d92 1 a92 1 if (xdr_toc_res_pt(&xdrs, &data) == FALSE){ d96 1 a96 1 if (xdr_net_volume_pt(&xdrs, &data) == FALSE){ d107 8 d117 11 d129 39 d169 10 d180 2 @ slave/RCS/slave_verify.c,v100444 6031 145 16065 6240130525 15101 0ustar delgadoorawebhead 6.0; branch ; access ; symbols ; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.40.05; author delgado; state Exp; branches ; next 4.0; 4.0 date 96.04.19.11.22.45; author delgado; state Exp; branches ; next 3.8; 3.8 date 96.03.29.10.21.00; author delgado; state Exp; branches ; next 1.2; 1.2 date 96.03.29.09.50.00; author delgado; state Exp; branches ; next 1.1; 1.1 date 96.03.26.20.17.37; author delgado; state Exp; branches ; next ; desc @Support tape verification after dump @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" /* * Procedure: slave_vol_check * * Parameters: dh - address of device information * fileno - which volume we're checking * * Description: This function reads the volume header, spaces * over the data which follows and reads the volume footer. * It returns 0 if data was successfully read; non-zero otherwise. */ int slave_vol_check(dev_handle_t *dh, int fileno) { abs_volheader_t vh; abs_volfooter_t vf; int code; char buf[256]; code = read_volume_header(dh, &vh); if (code){ sprintf(buf,"Error reading header for volume, file number %d: %s\n", fileno, get_abs_msg(code)); slave_log_error(ABS_ERROR, "slave_vol_check", buf); return(code); } /* * Skip over data and read footer */ code = NEXT_VOLFOOTER(dh); if (code){ sprintf(buf,"Error spacing to footer for volume %s, file number %d: %s\n", vh.name, fileno, get_abs_msg(code)); slave_log_error(ABS_ERROR, "slave_vol_check", buf); return(code); } code = read_volume_footer(dh, &vf); if (code){ sprintf(buf,"Error reading footer for volume %s, file number %d: %s\n", vh.name, fileno, get_abs_msg(code)); slave_log_error(ABS_ERROR, "slave_volcheck", buf); return(code); } return(code); } /* * Function: long_compare * * Parameters: i - value 1 for comparison * j - value 2 for compairson * * Description: This comparison function is provided for use with * the "qsort" C library routine to compare two long values */ static int long_compare(long *i, long *j) { return(*i - *j); } /* * Procedure: generate_random_positions * * Parameters: positions - array of longs to store positions * count - number of slots in "positions" array. * max - maximum number of volumes on tape * * Description: generate_random_positions uses the "lrand48" * function to generate random numbers. We then take * random-value mod "max" to get a number which is between * 0 and "max". We call qsort to order the positions in * ascending order. * * Modifies - positions; this array will be filled in with * random numbers. */ int generate_random_positions(unsigned long *positions, int count, int max) { unsigned short xi[3]; /* for the random number generator */ double rvalue; unsigned long rnum; int i; for (i=0; i< count; i++){ rnum = (long) lrand48(); positions[i] = rnum % max; } qsort(positions, count, sizeof(long), long_compare); } /* * Procedure: slave_quick_verification * * Parameters: dh - address of device information * dp - address of dumpset information * * Description: * verify a few random headers and footers on the tape * We verify about 10% of the volheader/footer pairs on the tape. * Verification consists of reading the header, footer structures * and nothing more. */ int slave_quick_verification(dev_handle_t *dh, net_dumpset_t *dp) { unsigned long *positions; /* array of random tape positions */ int i, fileno; int nvols, code; char buf[256]; sprintf(buf,"Performing quick verification for dumpset %s\n", dp->d_name); slave_log_error(ABS_INFORMATIONAL, "slave_quick_verification", buf); nvols = (int)((dp->nvolumes+9)/10 ); if (nvols == 0) return(0); /* * Generate nvols worth of random numbers representing * which volumes we're going to check out. */ positions = (unsigned long *) memalign(sizeof(long), nvols*sizeof(long)); generate_random_positions(positions, nvols, dp->nvolumes); for (i=0, fileno=0; i< nvols; i++){ if (fileno > positions[i]){ /* * This is the rare case where consecutive randomly * generated positions might be the same */ continue; } while(fileno < positions[i]){ code = NEXT_VOLHEADER(dh); if (code){ free(positions); return(code); } fileno++; } sprintf(buf,"Checking volume at position %d\n", fileno); slave_log_error(ABS_INFORMATIONAL, "slave_quick_verification", buf); code = slave_vol_check(dh, fileno); if (code){ break; } fileno++; } /* * It is possible that the last volume on this tape did not * fit, and in this case there may not be a footer */ if (code == ABS_EOM_DETECTED || code == ABS_EOF_DETECTED && (fileno >= dp->nvolumes && dp->dumpstats.ntapes > 1)){ code = 0; } free(positions); return(code); } /* * Procedure: slave_full_verification * * Parameters: dh - address of device information * dp - address of dumpset information * * Description: * verify a all headers and footers on the tape * Verification consists of reading the header, footer structures * and nothing more. */ int slave_full_verification(dev_handle_t *dh, net_dumpset_t *dp) { int count, code; char buf[256]; sprintf(buf,"Performing full verification for dumpset %s\n", dp->d_name); slave_log_error(ABS_INFORMATIONAL, "slave_full_verification", buf); count=0; while ((code = slave_vol_check(dh, count)) == 0){ count++; } if (code == ABS_EOM_DETECTED || code == ABS_EOF_DETECTED) code = 0; return(code); } @ 4.0 log @"slaveint" changed to "slaveservice" @ text @@ 3.8 log @Slave now supports quick and full verification @ text @d2 1 a2 1 #include @ 1.2 log @Generate better random number sequence add functioon comment headers @ text @@ 1.1 log @Initial revision @ text @d9 10 d53 9 d71 14 a84 4 * erand retunrs a number between 0.0 and 0.1 we have to convert * this to a value between 0 and max. In doing so, we probably * dilute the uniformity of the distribution of the random * values, but that's okay. d90 1 a90 1 short xi[3]; /* for the random number generator */ d92 1 d97 2 a98 2 rvalue = erand48(xi); positions[i] = (unsigned long) (rvalue *1000000.0) % max; d105 6 d112 3 a114 3 * We verify 10% of the volheader/footer pairs on the tape. * Verification consists of reading the header, footer. * d140 7 d164 9 d176 12 @ slave/RCS/slave_int.c,v100400 6031 145 53124 6240130520 14347 0ustar delgadoorawebhead 6.0; branch ; access ; symbols ; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.40.00; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.48; author delgado; state Exp; branches ; next 1.1; 1.1 date 96.05.20.10.20.47; author delgado; state Exp; branches ; next ; desc @D @ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" extern int slave_state; struct dev_table *devp; /* points to the ops vector for our device */ extern char master_server[PATH_MAX]; extern char device_name[PATH_MAX]; /* name of our device */ extern struct utsname un; /* contains our hostname */ extern int online; /* * Procedure: abs_backup_1_svc (RPC service routine entry point) * * Parameters: ndp - address of dumpset information to be dumped * jp - address of job information (containing jobid) * params - address of dump parameters for dump operation * rcp - return value * * Modifies: rcp - set according to the outcome of the dump (0 - success * non-zero failure) * * Description: This function is the entry point from the RPC into the * Slave's backup service routine. This routine will verify incoming * parameters, open the media device, and invoke "do_dump" to perform * the actual dump. */ bool_t abs_backup_1_svc(net_dumpset_pt ndp, job_pt jp, dump_params_pt params, int *rcp, struct svc_req *clp) { dev_handle_t *dh = (dev_handle_t *) NULL; char buf[512]; job_done_res_t jdone; char *datep; struct timeval now; memset(&jdone, 0, sizeof(job_done_res_t)); /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) goto dump_error; /* * Validate incoming parameters */ if (ndp == (net_dumpset_pt) NULL){ slave_log_error(ABS_ERROR,"dump", "Master specifies null dumpset \n"); *rcp = ABS_NO_DUMPSET; goto dump_error; } if (jp == (job_pt) NULL){ slave_log_error(ABS_ERROR,"dump", "Master specifies null job descriptor \n"); *rcp = ABS_INVALID_JOB; goto dump_error; } /* * check for unspecified fields in the dumpset structure */ if (ndp->d_name == (char *) NULL){ sprintf(buf, "Job %d Dumpset has no name!\n",jp->jobid); slave_log_error(ABS_ERROR, "dump", buf); *rcp = ABS_INVALID_SPEC; goto dump_error; } /* * Check for dumpset with no volumes */ if (ndp->volumes == (net_volume_pt) NULL){ sprintf(buf, "Dumpset %s has no volumes \n", ndp->d_name); slave_log_error(ABS_ERROR,"dump", buf); *rcp = ABS_NO_VOLUME_SPEC; goto dump_error; } if (params == (dump_params_pt) NULL){ slave_log_error(ABS_ERROR, "dump","Null dump parameters structure"); } /* * validate client's requested device type and host name * Ensure it's really me that is requested */ if (strcmp(jp->host, un.nodename)){ *rcp = ABS_NO_SERVER_SPEC; slave_log_error(ABS_ERROR,"dump", "Received incorrect hostname from Master"); goto dump_error; } if (strcmp(jp->device, device_name)){ *rcp = ABS_NO_DEVICE_SPEC; slave_log_error(ABS_FATAL,"dump", "Received incorrect devicename from Master"); goto dump_error; } /* * open the device. On some tape devices, the open will fail if there * The call to "request_service" within this loop * is to request a mount in case the device needs something to be present * in the drive inorder for the open to succeed. */ while((*rcp = SLAVE_OPEN(devp, &dh, device_name, O_RDWR, jp->jobid)) == ABS_NEEDS_MOUNT){ /* * Send mesasges to the master periodically to request a mount. * The master will annoy the user until he mounts a tape. */ *rcp = request_service(jp->jobid, ABS_TAPE_MOUNT_REQ, (tapeid_t *)NULL); } /* * We are here because we either have successfully opened the device * or we have encountered some unrecoverable error */ if (*rcp ){ if (*rcp == ABS_JOB_CANCELED){ slave_log_error(ABS_ERROR,"abs_backup","Job canceled at user's request\n"); SLAVE_CLOSE( dh); return(RPC_SUCCESS); } sprintf(buf, "Cannot open device %s \n", device_name); slave_log_error(ABS_FATAL,"dump",buf); goto dump_error; } /* * Everything is set up, "do_dump" will now execute the * dump for us */ *rcp = do_dump(dh, ndp, jp, params, &jdone.stats); if (*rcp == ABS_JOB_CANCELED){ SLAVE_CLOSE( dh); return(RPC_SUCCESS); } jdone.jdr_type = jdr_type_dumpset; jdone.jdr_dumpset = ndp; gettimeofday(&now); jdone.stats.date = now.tv_sec; if (*rcp == 0){ *rcp = perform_media_verification(dh, ndp, params->verf_mode, &jdone.stats, jp->jobid); } dump_done: if (!online){ SLAVE_OFFLINE(dh); } SLAVE_CLOSE(dh); dump_error: /* * We have to make an actual RPC to the Master to inform * it that we are done with the job. The master only * queues requests with us; it does not wait for us to complete * our work as in a normal RPC */ *rcp = slave_notify_master(*rcp, jp->jobid, &jdone, 1); return(RPC_SUCCESS); } /* * Procedure: abs_restore_1_svc * * Parameters: mp - address of media with list of volumes to restore. * jobid - job id assigned by master * rp - address of restore parameters * rcp - address of return code from call * clp - address of client rpc info * * Description: This function is the entry point from the RPC into the * Slave's restore service routine. This routine will verify incoming * parameters, open the media device, and invoke "do_restore" to perform * the actual restore. * */ bool_t abs_restore_1_svc(media_t *mp, int jobid, restore_pt rp, int *rcp, struct svc_req *clp) { dev_handle_t *dh = (dev_handle_t *)NULL; job_done_res_t jdone; char buf[512]; char *datep; struct timeval now; /* * Validate the caller's credentails. We only accept calls from * our Master */ memset(&jdone, 0, sizeof(job_done_res_t)); *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) goto restore_error; /* * Validate incoming parameters */ if (rp == (restore_pt) NULL){ slave_log_error(ABS_ERROR, "restore", "Master specifies null restore descriptor \n"); *rcp = ABS_INVALID_JOB; goto restore_error; } /* * Check for Request with no media */ if (mp == (media_t *) NULL){ sprintf(buf,"Restore job %d has no media specified\n", jobid); slave_log_error(ABS_ERROR,"restore",buf); *rcp = ABS_NO_VOLUME_SPEC; goto restore_error; } /* * validate client's requested device type and host name * Ensure it's really me that is requested */ if (rp->media_host == (char *) NULL || rp->media_device == (char *) NULL){ sprintf(buf,"Restore job %d has no media host/devce specified\n", jobid); slave_log_error(ABS_ERROR,"restore",buf); *rcp = ABS_NO_SERVER_SPEC; } if (strcmp(rp->media_host, un.nodename)){ slave_log_error(ABS_ERROR,"restore", "Received incorrect hostname from Master"); goto restore_error; } if (strcmp(rp->media_device, device_name)){ *rcp = ABS_NO_DEVICE_SPEC; slave_log_error(ABS_FATAL,"restore", "Received incorrect devicename from Master"); goto restore_error; } /* * open the device */ *rcp = SLAVE_OPEN(devp, &dh, device_name, O_RDONLY, jobid); if (*rcp == ABS_JOB_CANCELED){ slave_log_error(ABS_ERROR,"abs_backup","Job canceled at user's request\n"); SLAVE_CLOSE( dh); return(RPC_SUCCESS); } if (*rcp){ sprintf(buf, "Cannot open device %s \n", device_name); slave_log_error(ABS_FATAL,"restore",buf); goto restore_error; } *rcp = do_restore(dh, mp, jobid, rp, &jdone.stats); if (*rcp == ABS_SLAVE_TERMINATED){ return(RPC_SUCCESS); } jdone.jdr_type = jdr_type_media; jdone.jdr_media = mp; gettimeofday(&now); jdone.stats.date = now.tv_sec; restore_done: if (!online){ SLAVE_OFFLINE(dh); } SLAVE_CLOSE( dh); restore_error: /* * We have to make an actual RPC to the Master to inform * it that we are done with the job. The master only * queues requests with us; it does not wait for us to complete * our work as in a normal RPC */ *rcp = slave_notify_master(*rcp, jobid, &jdone, 1); return(RPC_SUCCESS); } /* * Prodcedure: abs_scan_1_svc * * Parameters: full_scan - indicates whether slave should perform full * scan of media * jp - address of job-related information. * rcp - address of return value from call * clp - address of client rpc information * * Description: This function is the entry point from the RPC into the * Slave's scan_media service routine. This routine will verify incoming * parameters, open the media device, and invoke "do_scan" to perform * the actual scan. */ bool_t abs_scan_1_svc(int full_scan, job_pt jp, int *rcp, struct svc_req *clp) { int master_rc, master_code; dev_handle_t *dh=(dev_handle_t *)NULL; abs_label_t abs_label; char buf[512]; net_dumpset_pt dp = (net_dumpset_pt) NULL; struct toc_res toc; /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) goto scan_error; if (jp == (job_pt) NULL){ *rcp = ABS_INVALID_SPEC; slave_log_error(ABS_FATAL,"scan_media", "Received NULL job from Master"); goto scan_error; } /* * validate client's requested device type and host name * Ensure it's really me that is requested */ if (strcmp(jp->host, un.nodename)){ *rcp = ABS_NO_SERVER_SPEC; slave_log_error(ABS_ERROR,"scan_media", "Received incorrect hostname from Master"); goto scan_error; } if (strcmp(jp->device, device_name)){ *rcp = ABS_NO_DEVICE_SPEC; slave_log_error(ABS_FATAL,"scan_media", "Received incorrect devicename from Master"); goto scan_error; } /* * open the device */ while((*rcp = SLAVE_OPEN(devp, &dh, device_name, O_RDONLY, jp->jobid)) == ABS_NEEDS_MOUNT){ /* * Send mesasges to the master periodically to request a mount. * The master will annoy the user until he mounts a tape. * For single-cartridge tapes the open fails if there is not a tape * in the drive. */ *rcp = request_service(jp->jobid, ABS_TAPE_MOUNT_REQ, (tapeid_t *)NULL); } if (*rcp){ sprintf(buf, "Cannot open device %s \n", device_name); slave_log_error(ABS_FATAL,"scan_media",buf); goto scan_error; } /* * Get the next media item; for single cartridge systems * This is essentially a no-op; for multi-cartridge we * expect the device to cyle around until it finds a * medium in one of its slots. */ *rcp = SLAVE_NEXT_MEDIA(dh, NULL, (media_id_pt) NULL, 0); if (*rcp){ sprintf(buf, "Cannot advance device %s \n", device_name); slave_log_error(ABS_FATAL,"scan_media", buf); goto scan_done; } /* * Rewind the device just in case */ *rcp = SLAVE_REWIND(dh); if (*rcp){ sprintf(buf, "device %s Rewind failure \n", device_name); slave_log_error(ABS_FATAL,"scan_media", buf); goto scan_done; } *rcp = do_scan(dh, &toc, full_scan); scan_done: if (!online){ SLAVE_OFFLINE(dh); } SLAVE_CLOSE(dh); scan_error: /* * We have to make an actual RPC to the Master to inform * it that we are done with the job. The master only * queues requests with us; it does not wait for us to complete * our work as in a normal RPC */ if (*rcp == ABS_JOB_CANCELED){ return(RPC_SUCCESS); } *rcp = slave_scan_results(*rcp, jp->jobid, &toc); return(RPC_SUCCESS); } /* * Procedure: abs_label_media_1_svc * * Parameters: extid - external id of medium * mip - internal id of medium, generated by master * jp - job information created by master * rcp - address of return code * clp - address of client specific information. * * * Description: This function is the entry point from the RPC into the * Slave's label service routine. This routine will verify incoming * parameters, open the media device, and invoke "slave_label_medium" * to perform the actual label operation. */ bool_t abs_label_media_1_svc(char *extid, media_id_pt mip, job_pt jp, int *rcp, struct svc_req *clp) { int master_rc, master_code; dev_handle_t *dh = (dev_handle_t *)NULL; abs_label_t abs_label; char buf[512]; job_done_res_t jdone; char *datep; struct timeval now; memset(&jdone, 0, sizeof(job_done_res_t)); /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) goto label_error; /* * validate incoming parameters */ if (extid == (char *) NULL || strlen(extid) == 0){ *rcp = ABS_INVALID_MEDIA_ID; slave_log_error(ABS_FATAL,"label_media", "Received NULL extid from Master"); goto label_error; } if (mip == (media_id_pt) NULL){ *rcp = ABS_INVALID_MEDIA_ID; slave_log_error(ABS_FATAL, "label_media", "Received NULL internal id from Master"); goto label_error; } if (jp == (job_pt) NULL){ *rcp = ABS_INVALID_SPEC; slave_log_error(ABS_FATAL,"label_media", "Received NULL job from Master"); goto label_error; } /* * validate client's requested device type and host name * Ensure it's really me that is requested */ if (strcmp(jp->host, un.nodename)){ *rcp = ABS_NO_SERVER_SPEC; slave_log_error(ABS_ERROR,"label_media", "Received incorrect hostname from Master"); goto label_error; } if (strcmp(jp->device, device_name)){ *rcp = ABS_NO_DEVICE_SPEC; slave_log_error(ABS_FATAL,"label_media", "Received incorrect devicename from Master"); goto label_error; } /* * open the device */ while( (*rcp = SLAVE_OPEN(devp, &dh, device_name, O_RDWR, jp->jobid)) == ABS_NEEDS_MOUNT){ /* * Send mesasges to the master periodically to request a mount. * The master will annoy the user until he mounts a tape. * For single-cartridge tapes the open fails if there is not a tape * in the drive. */ *rcp = request_service(jp->jobid, ABS_TAPE_MOUNT_REQ, (tapeid_t *)NULL); } if (*rcp != 0){ /* * some other fatal error which we cannot handle. * Tell the master and quit */ sprintf(buf, "Cannot open device %s \n", device_name); slave_log_error(ABS_FATAL,"label_media",buf); goto label_error; } /* * Get the next media item; for single cartridge systems * This is essentially a no-op; for multi-cartridge we * expect the device to cyle around until it finds a * medium in one of its slots. If all slots are empty it will * request a mount from the master */ *rcp = SLAVE_NEXT_MEDIA(dh, extid, (media_id_pt) NULL, 0); if (*rcp){ sprintf(buf, "Cannot advance media on device %s \n", device_name); slave_log_error(ABS_FATAL,"label_media", buf); goto label_done; } /* * Rewind the tape */ *rcp = SLAVE_REWIND(dh); if (*rcp){ sprintf(buf, "device %s Rewind failure \n", device_name); slave_log_error(ABS_FATAL,"label_media", buf); goto label_done; } /* * Device is open and media is mounted, * Check for an already-existing label. If the tape * has a label, we will need to verify the label with * the master. */ *rcp = validate_label(dh, mip, ABS_NO_LABEL, &abs_label); if (*rcp == ABS_VALID_MEDIA){ /* * The medium appears to have a valid abs label. We * must verify the status of this medium with the master * before we overwrite it. */ master_rc = slave_validate(&abs_label.tapeid, jp->jobid, &master_code); if (master_rc == 0){ /* no transmission errors */ if (master_code != ABS_UNKNOWN_MEDIA){ /* * tape status is something other than unknown. * in this case we abort since the tape could * be valid, bad (media errors), or expired */ goto label_done; } } else{ /* unrecoverable transmission errors * since we have no knowledge of the medium's state, we * abort the operation */ *rcp = master_rc; goto label_done; } }else if (*rcp != 0){ /* * some other type of error occurred * either it's already labeled or a media/device error */ slave_log_error(ABS_ERROR,"abs_label_medium","can't read tape"); goto label_done; } /* * We have determined that this tape is ok to use * So let's label it */ *rcp = slave_label_medium(devp, dh, extid, mip); label_done: /* * Close the device - we are finished with the * device portion of this operation. * Now tell the master how the operation completed. * we'll need to get an rpc connection to the master first */ if (!online){ SLAVE_OFFLINE(dh); } SLAVE_CLOSE(dh); label_error: jdone.jdr_type = jdr_type_label; gettimeofday(&now); jdone.stats.date = now.tv_sec; /* * We have to make an actual RPC to the Master to inform * it that we are done with the job. The master only * queues requests with us; it does not wait for us to complete * our work as in a normal RPC */ *rcp = slave_notify_master(*rcp, jp->jobid, &jdone, 1); return(RPC_SUCCESS); } /* * Procedure: abs_abort_job_1_svc * * Description: placeholder for remote abort */ bool_t abs_abort_job_1_svc(tapehost_pt thp, job_pt jp, int *rcp, struct svc_req *clp) { /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) return(RPC_SUCCESS); *rcp = ABS_NOT_SUPPORTED; } /* * Procedure: abs_shutdown_slave_1_svc * * Parameters: rcp - address of return value from call * clp - address of client info * * Description: This function will cause the slave to * return from "svc_run" by instructing the rpc to * stop listening for requests. */ bool_t abs_shutdown_slave_1_svc(int *rcp, struct svc_req *clp) { char msgbuf[256]; /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) return(RPC_SUCCESS); /* * Shutdown only works if the slave is not busy. * If we had threads, we could actually perform a remote shutdown * from this interface while the slave is busy dumping. */ *rcp = stop_listening(); /* Don't Accept any more RPC's */ if (*rcp){ /* failed - tell user */ sprintf(msgbuf," Failed to stop the RPC, error %d\n", *rcp); slave_log_error(ABS_ERROR, "abs_shutdown", msgbuf); return(RPC_SUCCESS); } sprintf(msgbuf,"Shutdown initiated by master"); slave_log_error(ABS_INFORMATIONAL, "abs_shutdown", msgbuf); return(RPC_SUCCESS); } /* * Procedure: absslave_1_freeresult * * Description: Required to interface with onc rpc. The rpc will * call this to free up any memory allocated for the results after * the results are delivered to the caller. We are not returning * any results through the slave service interfaces, so we don't * need to free up anything here. */ bool_t absslave_1_freeresult(transp, xdr_result, rp) SVCXPRT *transp; xdrproc_t xdr_result; caddr_t rp; { return(TRUE); } static int noauth=0; void set_noauth() { noauth = 1; } @ 5.0 log @remove fakeslave names @ text @@ 1.1 log @Initial revision @ text @@ slave/RCS/Makefile,v100400 6031 145 12423 6153576427 13703 0ustar delgadoorawebhead 5.0; branch ; access ; symbols ; locks delgado:5.0; strict; comment @# @; 5.0 date 96.05.20.11.12.20; author delgado; state Exp; branches ; next 1.1; 1.1 date 96.05.20.11.09.05; author delgado; state Exp; branches ; next ; desc @@ 5.0 log @remove fakeslave names @ text @# # RPCGEN=/mit/athena-backup/tools/tirpc/usr/bin/rpcgen SRC=/mit/athena-backup/tools/tirpc SRCROOT=/mit/athena-backup/src COMMON_INC = ${SRCROOT}/common/include COMMON_SRC = ${SRCROOT}/common/src COMMON_UTIL = ${SRCROOT}/common/util COMMON_ERROR = ${SRCROOT}/common/error AFSROOT=/mit/afsuser/3.3a.1/sun4m_53 AFSLIBPATH1=$(AFSROOT)/lib AFSLIBPATH2=$(AFSROOT)/lib/afs AFSINCLUDE=$(AFSROOT)/include LIBSRC=/mit/athena-backup/tools/tirpc/usr/lib LIBFLGS = -L$(LIBSRC) -L$(AFSLIBPATH1) -L$(AFSLIBPATH2) #LIBFLGS = -L$(LIBSRC) AFS = -L$(AFSLIBPATH1) -L$(AFSLIBPATH2) XLIBS= -lucb /usr/athena/lib/libresolv.a AFSSRCDIR=/mit/afsdev/bld/sun4m_53/dest/ STDLIBS = -lm -lsocket -lnsl -laio -lposix4 -lintl -ldl -lc AFSLIBS = ${AFSSRCDIR}lib/afs/libvolser.a \ ${AFSSRCDIR}lib/afs/libsys.a ${AFSSRCDIR}lib/afs/libvldb.a \ ${AFSSRCDIR}lib/libubik.a \ ${AFSSRCDIR}lib/afs/libauth.a ${AFSSRCDIR}lib/afs/libsys.a \ ${AFSSRCDIR}lib/afs/libcmd.a ${AFSSRCDIR}lib/librxkad.a \ ${AFSSRCDIR}lib/libdes.a \ ../master/lib/librx.a ${AFSSRCDIR}lib/liblwp.a \ ${AFSSRCDIR}lib/afs/libcom_err.a ${AFSSRCDIR}lib/afs/libkauth.a \ ${AFSSRCDIR}lib/afs/libaudit.a \ ${AFSSRCDIR}lib/afs/util.a ${XLIBS} LIBS= -L $(SRC)/usr/lib -lrpc -lzephyr -lkrb -ldes \ $(STDLIBS) $(AFSLIBS) -lucb CFLAGS = -g -I. -D_ANSI_C_SOURCE -I$(SRC)/usr/include -I.. -I$(SRCROOT)/common/include \ -I/usr/athena/include -I/usr/include -I$(AFSINCLUDE) -D_SOLARIS_ \ -DRPC_SVC_FG -DONC_RPC FOBJS = slave_main.o slave_dispatch.o slave_int.o \ slaveservice_clnt.o slaveservice_xdr.o \ sig_handlers.o \ restore.o dump.o scan.o job_info.o\ slave_xdr.o master_xdr.o master_clnt.o onc_utils.o slave_utils.o \ slave_error.o slave_auth.o slave_verify.o\ basic_mtio.o config_file.o \ afs_ops.o abs_error.o globals.o MGENFILES= ${COMMON_INC}/master.h ${COMMON_SRC}/master_xdr.c \ ${COMMON_SRC}/master_clnt.c SLV_GENFILES = ${COMMON_SRC}/slaveservice_xdr.c ${COMMON_INC}/slaveservice.h \ ${COMMON_SRC}/slaveservice_clnt.c FGENFILES = ${COMMON_SRC}/slave_xdr.c ${COMMON_INC}/slave.h \ slave_svc.c slave: ${MGENFILES} ${FGENFILES} ${FOBJS} $(CC) -o /var/tmp/slave $(LIBFLGS) -L/usr/athena/lib $(FOBJS) $(LIBS) local_build_genfiles: ${MGENFILES} ${FGENFILES} ${SLV_GENFILES} genfiles: ${FGENFILES} ${SLV_GENFILES} slave.h: slave.x $(RPCGEN) -M -N -C slave.x mv slave.h ${COMMON_INC} mv slave_xdr.c slave_clnt.c ${COMMON_SRC} ${SLV_GENFILES}: ../master/slaveservice.x (cd .. ; make -e master_gen); ${MGENFILES}: ../master/master.x (cd .. ; make -e master_gen); ${FGENFILES}: slave.x $(RPCGEN) -M -N -C slave.x mv slave.h ${COMMON_INC} mv slave_xdr.c slave_clnt.c ${COMMON_SRC} master_xdr.o: ${COMMON_SRC}/master_xdr.c $(CC) -c -o $@@ $(CFLAGS) ${COMMON_SRC}/master_xdr.c master_clnt.o: ${COMMON_SRC}/master_clnt.c $(CC) -c -o $@@ $(CFLAGS) ${COMMON_SRC}/master_clnt.c slaveservice_xdr.o: ${COMMON_SRC}/slaveservice_xdr.c $(CC) -c -o $@@ $(CFLAGS) ${COMMON_SRC}/slaveservice_xdr.c slaveservice_clnt.o: ${COMMON_SRC}/slaveservice_clnt.c $(CC) -c -o $@@ $(CFLAGS) ${COMMON_SRC}/slaveservice_clnt.c onc_utils.o: ${COMMON_UTIL}/onc_utils.c $(CC) -c -o $@@ $(CFLAGS) ${COMMON_UTIL}/onc_utils.c slave_dispatch.c: slave_svc.c sed -f ../master/remove-main slave_svc.c > slave_dispatch.c slave_xdr.o: ${COMMON_SRC}/slave_xdr.c $(CC) -c -o $@@ $(CFLAGS) ${COMMON_SRC}/slave_xdr.c slave_int.o: slave_int.c ${COMMON_INC}/slave.h ${COMMON_INC}/master.h private.h prototypes.h $(CC) -c -o $@@ $(CFLAGS) slave_int.c slave_main.o: $(CC) -c -o $@@ $(CFLAGS) slave_main.c slave_utils.o: slave_utils.c private.h $(CC) -c -o $@@ $(CFLAGS) slave_utils.c slave_error.o: slave_error.c private.h $(CC) -c -o $@@ $(CFLAGS) slave_error.c devfs_ops.o: devfs/devfs_ops.c private.h devfs/devfs.h $(CC) -c -o $@@ $(CFLAGS) devfs/devfs_ops.c devfs_ops1.o: devfs/devfs_ops1.c private.h devfs/devfs.h $(CC) -c -o $@@ $(CFLAGS) devfs/devfs_ops1.c job_info.o:job_info.c $(CC) -c -o $@@ $(CFLAGS) job_info.c dump.o: dump.c private.h prototypes.h $(CC) -c -o $@@ $(CFLAGS) dump.c slave_auth.o: slave_auth.c private.h prototypes.h $(CC) -c -o $@@ $(CFLAGS) slave_auth.c restore.o: restore.c private.h prototypes.h $(CC) -c -o $@@ $(CFLAGS) restore.c slave_verify.o: slave_verify.c private.h prototypes.h $(CC) -c -o $@@ $(CFLAGS) slave_verify.c scan.o: scan.c private.h prototypes.h $(CC) -c -o $@@ $(CFLAGS) scan.c onc_int.o: onc_int.c private.h $(CC) -c -o $@@ $(CFLAGS) onc_int.c basic_mtio.o: private.h basic/basic_mtio.c $(CC) -c -o $@@ $(CFLAGS) basic/basic_mtio.c afs_ops.o: afs_ops.c $(CC) -c -o $@@ -I $(AFSINCLUDE) $(CFLAGS) afs_ops.c abs_error.o: ${SRCROOT}/common/error/abs_error.c $(CC) $(CFLAGS) -c -o $@@ ${SRCROOT}/common/error/abs_error.c %.o: %.c $(CC) $(CFLAGS) -c -o $@@ $< clean: rm -f $(FOBJS) slave.h slave_xdr.c slave_svc.c \ slave_clnt.c @ 1.1 log @Initial revision @ text @@ slave/RCS/config_file.c,v100444 6031 145 6476 6240130502 14627 0ustar delgadoorawebhead 6.0; branch ; access ; symbols ; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.39.46; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.21; author delgado; state Exp; branches ; next ; desc @@ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include <../master/abs_msg.h> extern char master_server[256]; extern char master_princ[1024]; extern char slave_princ[1024]; extern char abs_admin_dir[PATH_MAX]; extern char log_dir[PATH_MAX]; extern char device_name[PATH_MAX]; extern char device_type[10]; extern int online; /* keep tapes on-line after use */ /* * Procedure: read_config_file * * Parameters: conf - address of configuration file name * int - reread - non-zero if this is a forced re-read of the file * * Description: This function reads the slave configuration file specified * by the parameters "conf" and modifies various variables in "globals.c" * to contain the value specified by the config file.. If "reread" is * 0, then all parameters specified in the config file are read and set. * Other wise only those variables which can be safely modified while * the slave is running are set. */ read_config_file(char *conf, int reread) { int rc, lines; char line[1024]; char param[128], data[PATH_MAX]; char buf[PATH_MAX+60]; FILE *fp; if ((fp = fopen(conf, "r")) == (FILE *) NULL){ sprintf(buf,"Cann't open config file %s", conf); slave_log_error(ABS_ERROR, "read_config_file", buf); return; } lines=0; while( fgets(line,1024,fp) != (char *) NULL){ lines++; errno=0; rc = sscanf(line,"%s : %s", param, data); if (rc != 2 ){ /* no items converted */ sprintf(buf,"format error in config file line %d\n",lines); slave_log_error(ABS_ERROR, "read_config_file", buf); continue; } if (!strcmp("master_server", param)){ strcpy(master_server, data, PATH_MAX); continue; } if (!strcmp("master_principal", param)){ strcpy(master_princ, data, 1024); continue; } if (!strcmp("slave_principal", param)){ strcpy(slave_princ, data, 1024); continue; } if (!strcmp("device_online", param)){ online = atoi(data); if (errno){ fprintf(stderr,"bad data at line %d\n", lines); return(errno); } continue; } /* * The remaining parameters cannot be changed while * the slave is running */ if (reread) continue; if (!strcmp("admin_dir", param)){ strncpy(abs_admin_dir, data, PATH_MAX); continue; } if (!strcmp("device_name", param)){ strncpy(device_name, data, PATH_MAX); continue; } if (!strcmp("device_type", param)){ strncpy(device_type, data, 10); continue; } fprintf(stderr,"Invalid parameter line %dn", lines); } fclose(fp); return(0); } @ 5.0 log @remove fakeslave names @ text @d8 2 d58 8 @ slave/RCS/globals.c,v100444 6031 145 2130 6240130503 13766 0ustar delgadoorawebhead 6.0; branch ; access ; symbols ; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.39.47; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.31; author delgado; state Exp; branches ; next ; desc @@ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include "private.h" char abs_admin_dir[PATH_MAX]="/var/abs/slave"; char log_dir[]="logs"; char device_name[PATH_MAX]=""; char device_type[10]=""; char config_file[PATH_MAX]=""; char master_server[256]=""; /* hostname of master server */ char master_princ[1024]="abs-master"; /* principal name for master server */ char slave_princ[1024] = "abs-slave"; /* slave principal name */ int online = 0; /* keep tapes on-line after use */ int slave_state=SLAVE_INIT; void set_slave_state(int state) { /* * should have locks for threads */ slave_state = state; } int get_slave_state() { /* * should have locks for threads */ return(slave_state); } @ 5.0 log @remove fakeslave names @ text @d11 2 @ slave/RCS/slave_main.c,v100400 6031 145 26033 6240130521 14501 0ustar delgadoorawebhead 6.0; branch ; access ; symbols ; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.40.00; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.49; author delgado; state Exp; branches ; next ; desc @@ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include /* getenv, exit */ #include /* for pmap_unset */ #include /* strcmp */ #include #include #include /* setsid */ #include #include #include #include #include /* rlimit */ #include #include #include #include #include #include #include #include "../master/abs_msg.h" #include "private.h" extern void sigterm_handler(int param); extern void sighup_handler(int param); extern char slave_princ[]; extern char master_princ[]; char usage[] = "slave -f "; /* * client handle to master process -used by all * slave service routines to deliver results or * status messages */ CLIENT *cl; /* * The following variables are actually defined in globals.c * */ extern char master_server[]; extern char abs_admin_dir[PATH_MAX]; extern char log_dir[PATH_MAX]; extern char device_name[PATH_MAX]; extern char device_type[10]; extern char config_file[PATH_MAX]; extern int online; char myhost[256]; struct utsname un; int dflag = 0; int mflag = 0; extern void absslave_1(struct svc_req *rqstp, register SVCXPRT *transp); extern void closedown(int sig); extern marshall_sockaddr(char *, int, struct sockaddr_in *, int ); #ifdef DEBUG #define RPC_SVC_FG #endif #define _RPCSVC_CLOSEDOWN 120 static void _msgout(char* msg) { (void) fprintf(stderr, "%s\n", msg); } server_thread() { pid_t pid; int i, rc, code; struct netbuf nbuf; char buf[32], *msgp; char mname[FMNAMESZ + 1]; struct netconfig *nconf = NULL; SVCXPRT *transp; slave_info_t slave; char addr_buf[512]; AUTH *auth; nbuf.buf = buf; nbuf.maxlen = 32; nbuf.len = 0; if (!ioctl(0, I_LOOK, mname) && (!strcmp(mname, "sockmod") || !strcmp(mname, "timod"))) { char *netid; int pmclose; openlog("master", LOG_PID, LOG_DAEMON); if ((netid = getenv("NLSPROVIDER")) == NULL) { /* started from inetd */ pmclose = 1; } else { if ((nconf = getnetconfigent(netid)) == NULL) _msgout("cannot get transport info"); pmclose = (t_getstate(0) != T_DATAXFER); } if (strcmp(mname, "sockmod") == 0) { if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) { _msgout("could not get the right module"); exit(1); } } if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { _msgout("cannot create server handle"); exit(1); } if (rpcb_getaddr(ABSSLAVE, ABSVERS, nconf, &nbuf, myhost) == TRUE){ fprintf(stderr,"Program already registered - exiting! \n"); exit(1); } if (nconf) freenetconfigent(nconf); /* svc_dg_enablecache(transp, 500) */ if (!svc_reg(transp, ABSSLAVE, ABSVERS, absslave_1, 0)) { _msgout("unable to register (ABSSLAVE, ABSVERS)."); exit(1); } if (pmclose) { (void) signal(SIGALRM, closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } svc_run(); exit(1); /* NOTREACHED */ } uname(&un); if ((nconf = getnetconfigent("udp")) == NULL){ fprintf(stderr,"Cannot get transort information for udp!\n"); exit(1); } transp = svc_tli_create(RPC_ANYFD, nconf, (struct t_bind *)NULL, 0,0); if (transp == (SVCXPRT *)NULL) { _msgout("svc_tli_create for udp fails"); exit(1); } if (svc_reg(transp, ABSSLAVE, ABSVERS, absslave_1, 0) == FALSE) { _msgout("unable to create (ABSSLAVE, ABSVERS) for tcp."); exit(1); } /* Note - the return values for this call are opposite * of what the documentation states */ if (svc_dg_enablecache(transp, 50) == 0){ fprintf(stderr,"Unable to initialize duplicate request cache"); exit(1); } /* * Register the server's principal, instance and realm * with the rpc auth functions */ if (svc_kerb_reg(NULL, slave_princ, myhost, (char *) NULL, AUTH_KERB)){ fprintf(stderr,"svc_kerb_reg failed !\n"); exit(1); } #ifdef INTEGRITY /* * force use of integrity for this transport */ svc_control(transp, SVCSET_INTEGRITY, 0); freenetconfigent(nconf); #endif if ((nconf = getnetconfigent("tcp")) == NULL){ fprintf(stderr,"Cannot get transort information for tcp!\n"); exit(1); } transp = svc_tli_create(RPC_ANYFD, nconf, (struct t_bind *)NULL, 8192, 8192); if (transp == (SVCXPRT *)NULL) { _msgout("svc_tli_create for tcp fails"); exit(1); } if (svc_reg(transp, ABSSLAVE, ABSVERS, absslave_1, 0) == FALSE) { _msgout("unable to create (ABSSLAVE, ABSVERS) for tcp."); exit(1); } #ifdef INTEGRITY /* * force use of integrity for this transport */ svc_control(transp, SVCSET_INTEGRITY, 0); #endif freenetconfigent(nconf); /* * Send any leftover results back to the master. * This is the case where we had trouble sending our * results to the master and we've saved them to a * file */ recover_saved_jobs(master_server); /* * Now register the tcp interface with the Master so * it knows which port to contact us on */ cl = clnt_create(master_server, ABS_SLAVESERVICE, ABS_SLVVERS, "tcp"); if (cl == NULL){ clnt_pcreateerror(master_server); fprintf(stderr,"Can't create connection to master %s\n",master_server); exit(1); } /* * Use kerberos authentication with data integrity */ if (authkerb_create(master_princ, master_server, (char *) NULL, AUTH_KERB, &code, &auth, cl)){ fprintf(stderr,"authkerb_create fails code = %d\n", code); exit(1); } slave.hostname = myhost; slave.device = device_name; slave.s.type = sockaddr_type; slave.s.slave_addr_u.sa.sa_len = sizeof(struct sockaddr_in); slave.s.slave_addr_u.sa.sa_val = addr_buf; marshall_sockaddr(addr_buf, sizeof(struct sockaddr_in), (struct sockaddr_in *)transp->xp_ltaddr.buf, 1); rc = code = 0; code = slaveservice_register_device_1(&slave, NULL, &rc, cl); if (code ){ msgp = clnt_sperrno(code); slave_log_error(ABS_FATAL,"server_thread", msgp); exit(code); } if (rc){ fprintf(stderr,"failed to register with master %d\n",rc); exit(rc); } clnt_destroy(cl); set_slave_state(SLAVE_RUNNING); svc_run(); /* The only way we return from svc_run is if someone * calls the shutdown interface which will disable * the rpc listen */ _msgout("svc_run returned"); svc_unreg(ABSSLAVE, ABSVERS); slave_log_error(ABS_WARNING,"server", "Interfaces unregisterd"); slave_log_error(ABS_WARNING,"server", "Slave exiting"); exit(1); /* NOTREACHED */ } main(argc, argv) int argc; char *argv[]; { int retval, fflag=0; int *arg, i; char jobs_dir[] = "jobs"; int c, errflg=0; int bootstrap = 0; struct stat sb; extern char *optarg; extern int optind, opterr, optopt; while ((c = getopt(argc, argv, "f:n")) != EOF){ switch (c) { case 'f': strncpy(config_file, optarg, PATH_MAX); fflag++; break; case 'n': set_noauth(); break; case '?': errflg++; break; } } if (errflg){ fprintf(stderr,usage); exit(EINVAL); } if (fflag == 0){ fprintf(stderr,"Configuration file not specified - exiting!\n"); exit(1); } read_config_file(config_file, 0); if (strlen(device_name) == 0){ fprintf(stderr, "No device name specified - exiting\n"); exit(1); } if (strlen(device_type) == 0){ fprintf(stderr,"No device type specified - exiting\n"); exit(1); } if (set_devtype(device_type)){ fprintf(stderr,"Invalid device type %s\n", device_type); exit(EINVAL); } if (chdir(abs_admin_dir)){ fprintf(stderr,"Cannot chdir to %s\n", abs_admin_dir); exit(errno); } umask(007); /* * Create the various admin directories if necessary */ retval = stat(jobs_dir, &sb); if (retval && (errno == ENOENT)){ if (mkdir(jobs_dir, 0750)){ fprintf(stderr,"Cannot create directory - exiting! %s\n",jobs_dir); exit(errno); } }else if (retval != 0){ fprintf(stderr,"errno %d\n", retval); fprintf(stderr,"Cannot Access directory -exiting ! %s\n", jobs_dir); perror(jobs_dir); exit(errno); } retval = stat(log_dir, &sb); if (retval &&( errno == ENOENT)){ if (mkdir(log_dir, 0750)){ fprintf(stderr,"Cannot create directory %s- exiting! \n", log_dir); exit(errno); } }else if (retval != 0 ){ fprintf(stderr,"Cannot Access directory %s -exiting !\n", log_dir); perror(log_dir); exit(errno); } /* * If logs can't be initialized, then this * routine will exit */ initialize_slave_log(log_dir, device_name); retval = set_jobs_dir(jobs_dir); if (retval){ exit(retval); } uname(&un); strcpy(myhost, un.nodename); /* * Get a tgt so that we have credentials and can * request service tickets. This routine logs its * errors so we don't have to. */ if (get_slave_tgt()){ exit(1); } /* * set up handler for SIGTERM to allow * graceful termination */ retval = signal(SIGTERM, sigterm_handler); if (retval){ slave_log_error(ABS_FATAL, "main", "cant setup TERM signal handler -exiting"); exit(1); } retval = signal(SIGHUP, sighup_handler); if (retval){ slave_log_error(ABS_FATAL, "main", "cant setup HUP signal handler -exiting"); exit(1); } /* * Startup our RPC server business */ server_thread(); } @ 5.0 log @remove fakeslave names @ text @d28 3 d176 1 a176 1 if (svc_kerb_reg(NULL, "rcmd", myhost, d230 1 a230 1 if (authkerb_create("rcmd", master_server, (char *) NULL, d243 1 a243 1 code = abs_register_device_1(&slave, &rc, cl); @ slave/RCS/sig_handlers.c,v100444 6031 145 2112 6240130506 15010 0ustar delgadoorawebhead 6.0; branch ; access ; symbols ; locks ; strict; comment @ * @; 6.0 date 96.11.06.10.39.49; author delgado; state Exp; branches ; next 5.0; 5.0 date 96.05.20.11.12.37; author delgado; state Exp; branches ; next ; desc @@ 6.0 log @bump up for protocol changes - larger server, volume and paritionnames @ text @#include #include #include #include "../master/abs_msg.h" #include "private.h" void sigterm_handler(int param) { slave_log_error(ABS_WARNING,"sigterm_handler", "SIGTERM received will initiate shutdown.."); if (get_slave_state() == SLAVE_INIT){ exit(0); } set_slave_state(SLAVE_TERMINATED); /* * Don't Accept any more RPC's. The server will stop listening * after it is finished with its current call. */ stop_listening(); } void sighup_handler(int param) { slave_log_error(ABS_WARNING,"sighup_handler", "SIGHUP received will re-read configuration file.."); read_config_file(); } @ 5.0 log @remove fakeslave names @ text @@ slave/scan.c100400 6031 145 7276 6240131025 12406 0ustar delgadooraweb#include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" int do_scan(dev_handle_t *dh, toc_res_pt trp, int full_scan) { toc_pt tocp, tmp; int abort_now=0, bytes, code; abs_label_pt labelp; tocp = (toc_pt) malloc(sizeof(toc_t)); if (tocp == (toc_pt) NULL){ trp->code = ABS_NO_MEM; } memset(tocp, 0, sizeof(toc)); labelp = &tocp->data.tt_label; tocp->data.tt_type = label; code = read_label(dh, labelp); if (code){ trp->code = code; free(tocp); trp->toc_res_u.value = NULL; return(code); } if (!full_scan){ if (labelp->magic != ABS_LABEL_MAGIC){ trp->code = ABS_INVALID_LABEL; free(tocp); trp->toc_res_u.value = NULL; return(ABS_INVALID_LABEL); } trp->code = 0; trp->toc_res_u.value = tocp; return(0); } /* * Full scan is requested - we try hard to see if there * is ABS data on the tape. If we can't read the label * the see if the next record contains a volume header. */ if (labelp->magic != ABS_LABEL_MAGIC){ /* * Try to see if the next record on the tape * might be a valid volume header */ abort_now = 1; } trp->toc_res_u.value = tocp; tmp = tocp; while (1){ if (get_slave_state() == SLAVE_TERMINATED){ return(ABS_JOB_CANCELED); } tocp = (toc *) malloc(sizeof(toc)); if (tocp == (toc *) NULL){ trp->code = ABS_NO_MEM; break; } memset(tocp, 0, sizeof(toc)); tocp->data.tt_type = volheader; code = read_volume_header(dh, &(tocp->data.tt_volume)); if ((code == ABS_EOF_DETECTED) || (code == ABS_EOM_DETECTED)){ /* end of medium */ free(tocp); code = 0; break; } if (code && abort_now){ free(tocp); trp->code = ABS_INVALID_LABEL; break; } /* * try to space forward to the next volume * maybe we can read the tape then. */ if (code){ abort_now = 1; /* * indicate that there is a bad record on the * tape */ tocp->data.tt_volume.magic = 0; }else abort_now = 0; tmp->next = tocp; tmp = tmp->next; /* * The "next file" is considered to be the next * control record which is actually the volume footer * The volume footer should be followed by another control * record which is the volume header. */ code = NEXT_VOLFOOTER(dh); if ((code == ABS_EOF_DETECTED) || (code == ABS_EOM_DETECTED)){ /* end of medium */ code = 0; break; } if (code && abort_now){ trp->code = code; break; } tocp = (toc *) malloc(sizeof(toc)); if (tocp == (toc *) NULL){ trp->code = ABS_NO_MEM; break; } memset(tocp, 0, sizeof(toc)); tocp->data.tt_type = volfooter; if (code) abort_now = 1; code = read_volume_footer(dh, &(tocp->data.tt_volfooter)); if (code && abort_now){ free(tmp); trp->code = code; break; } if (code) abort_now = 1; tmp->next = tocp; tmp = tmp->next; } trp->code = code; if (trp->code){ free(trp->toc_res_u.value); trp->toc_res_u.value = NULL; } return(code); } slave/sig_handlers.c100444 6031 145 1272 6240131025 14122 0ustar delgadooraweb#include #include #include #include "../master/abs_msg.h" #include "private.h" void sigterm_handler(int param) { slave_log_error(ABS_WARNING,"sigterm_handler", "SIGTERM received will initiate shutdown.."); if (get_slave_state() == SLAVE_INIT){ exit(0); } set_slave_state(SLAVE_TERMINATED); /* * Don't Accept any more RPC's. The server will stop listening * after it is finished with its current call. */ stop_listening(); } void sighup_handler(int param) { slave_log_error(ABS_WARNING,"sighup_handler", "SIGHUP received will re-read configuration file.."); read_config_file(); } slave/slave.x100600 6031 145 6116 6263011321 12614 0ustar delgadooraweb%#include /* * Definitions having to do with media labels */ const ABS_LABEL_MAGIC = 0x0AB123AB; const ABS_VOLHEADER_MAGIC = 0x0AB678AB; const ABS_VOLFOOTER_MAGIC = 0x0AB456AB; struct abs_label{ int magic; /* ABS magic number for verification */ int abs_version; /* ABS version number */ media_id tapeid; /* tape id */ long label_created; /* date tape was labeled */ /* items below here are written each time the tape date is written */ int block_size; /* media block size */ int dump_type; /* type of dump */ int level; /* dump level */ int sequence; /* ordinal number of tape in tapeset */ int uses; /* how many times tape has been written */ long tape_created; /* date data on tape was written */ char device_type[ABS_MAX_DEVICE]; /* type of device used to write this tape */ char domain[ABS_MAX_DOMAIN]; /* ABS domain */ char cell[ABS_MAX_DOMAIN]; /* cell data was dumped from */ char dumpset[ABS_MAX_DNAME]; /* dumpset contained on tape */ int reserved[16]; }; typedef struct abs_label abs_label_t; typedef struct abs_label *abs_label_pt; /* * validate label flags */ const ABS_VALID_LABEL = 0x00; /* The caller expects to find a valid label*/ const ABS_VALID_LABELID = 0x01; /* valid label with matching id */ const ABS_NO_LABEL = 0x02; /* The call expects to find no label */ /* * Dump Flags */ const ABS_DUMP_CLONE = 0x0; /* Dump from cloned volume */ const ABS_DUMP_RW = 0x01; /* Dump from RW volume */ struct dump_params{ string verf_mode; int media_errors; int media_eof; long dump_from; longlong_t media_capacity; short dump_flags; }; typedef struct dump_params dump_params_t; typedef struct dump_params *dump_params_pt; struct abs_vol_header{ int magic; int absvolid_low; int absvolid_high; int size_low; int size_high; char name[ABS_MAX_VOLNAME]; char server[ABS_MAX_SERVER]; char device[ABS_MAX_DEVICE]; char fstype[ABS_MAX_TAG]; int fs_volid1; int fs_volid2; char fs_private[128]; /* 128 bytes of fs-specific data */ int dump_date; int reserved[4]; }; typedef struct abs_vol_header abs_volheader_t; typedef struct abs_vol_header *abs_volheader_pt; const ABS_VS_INVALID = 0; const ABS_VS_VALID = 1; struct volume_footer{ int magic; int absvolid; int size_high; int size_low; int status; int spare[8]; }; typedef struct volume_footer abs_volfooter_t; typedef struct volume_footer *abs_volfooter_pt; program ABSSLAVE{ version ABSVERS{ int abs_backup(net_dumpset_pt, job_pt, dump_params_pt) = 1; int abs_restore(media_pt, int, restore_pt) = 2; int abs_scan(int, job_pt) = 3; int abs_label_media(string, media_id_pt, job_pt) = 4; int abs_abort_job(tapehost_pt, job_pt) = 5; int abs_shutdown_slave() = 6; }=1; } = 3001; slave/slave_auth.c100400 6031 145 5321 6240131025 13602 0ustar delgadooraweb#include #include #include #include #include "../master/abs_msg.h" #include "private.h" extern char myhost[]; extern char master_server[]; extern char slave_princ[]; extern char master_princ[]; static int have_realm=0; static char realm[REALM_SZ]; /* keeps track of our realm so we don't have to * keep calling "krb_get_lrealm" */ int get_slave_tgt() { int rc; char msg[512]; if (! have_realm){ rc = krb_get_lrealm(realm, 1); if (rc != KSUCCESS){ slave_log_error(ABS_FATAL, "abs_check_auth", "krb_get_lrealm failed\n!"); return(ABS_AUTH_ERROR); } have_realm = 1; } /* * Get rid of any tickets which we may be currently holding * since the prinicpal may not be valid or might have been * inherited from the shell which spawned us. */ rc = dest_tkt(); if (rc){ sprintf(msg, "Error %d from dest_tkt - %s\n", rc, krb_err_txt[rc]); slave_log_error(ABS_ERROR, "get_slave_tgt", msg); } /* * Get a tgt so that we can get tickets to the master and * file servers. */ rc = krb_get_svc_in_tkt(slave_princ, myhost, realm , "krbtgt", realm, 24*60, "/etc/athena/srvtab" ); if (rc){ sprintf(msg, "Error %d from krb_get_svc_in_tkt - %s\n", rc, krb_err_txt[rc]); slave_log_error(ABS_ERROR, "get_slave_tgt", msg); return(ABS_AUTH_ERROR); } return(0); } int slave_check_authentication(struct svc_req *client) { struct authkerb_clnt_cred *cred; int rc; /* * client is not using Kerberos with data integrity, then deny * the request since we can't trust it! */ if (client->rq_cred.oa_flavor != AUTH_KERB_INTEGRITY){ return(0); } cred = (struct authkerb_clnt_cred *) client->rq_clntcred; /* First check the client's realm; if it's not the same as * ours, then reject the request */ if (! have_realm){ rc = krb_get_lrealm(realm, 1); if (rc != KSUCCESS){ slave_log_error(ABS_ERROR, "abs_check_auth", "krb_get_lrealm failed\n!"); return(ABS_AUTH_ERROR); } have_realm = 1; } /* * We do not accept requests from Masters in * different realms or on servers other than the one * we were configured with. */ if (strcmp(realm, cred->prealm)){ return(ABS_AUTH_ERROR); } if (strcmp(cred->pname, master_princ)){ return(ABS_AUTH_ERROR); } if (strcmp(cred->pinst, master_server )){ return(ABS_AUTH_ERROR); } return(0); } slave/afs_ops.c100600 6031 145 106706 6263011650 13162 0ustar delgadooraweb#include #include #include #include #include #include #include #include "../master/abs_msg.h" #include "../master/os_defs.h" #include "private.h" #define __XDR_INCLUDE__ #include #include #include #include #include #include #include #include /* * This is the "rock" thing that is setup by abs_dump and abs_restore; * It is passed to UV_DumpVolume/UV_RestoreVolume and then provided as * a parameter to the transaction handler routines AB_DumpFunc and ABS_RestoreFunc * when AFS is ready to receive/send data from and to the Slave. * This is how AFS requires us to do things. */ struct abs_rock{ dev_handle_t *dh; job_pt jp; int data_written; int data_read; int status; abs_label_t *labelp; unsigned int volsize; media_pt media; abs_volheader_t vh; }; /* * Global variables which keep track of our state with * respect to AFS, RX, etc. These should have locks around * them if the slave is ever threaded. */ short rx_inited; char realm[REALM_SZ]; /* * Data structure for connection management for AFS fileservers. * */ typedef struct afs_conn{ int server_addr; int rx_sec_index; struct abs_rock *rockp; struct rx_securityClass *rxsec; CREDENTIALS cred; KTEXT_ST auth; struct rx_connection *vldb_conns[VLDB_MAXSERVERS]; }afs_conn; static afs_conn dummy; int ABS_RestoreFunc(struct rx_call *call, char *restore_rock); int ABS_DumpFunc(struct rx_call *call, char *dump_rock); int setup_auth_vldb_connection(afs_conn *handlep, char *cellname); int GetServer(char *aname); /* * Note the security index which is passed to UV_SetSecurity is all * hard coded in the AFS sources, so code maintainers must check * that the meaning of the indeces have not changed or our connection * management may cease to work. * */ void * afs_connect(char *host, char *cell, char *id, int *code, int op) { int index, i; struct timeval now; char buf[512]; gettimeofday(&now); /* * Get a tgt for us so that we can run authenticated. * It would be better if there were a refresh thread which * could refresh our credentials for us when they are about * to expire. That way we wouldn't have to litter the code * with "get_tgt" calls every time we need to use a service * which requires us to have credentials. */ if (get_slave_tgt()){ /* * this routine has already logged the error for us */ *code = ABS_AUTH_ERROR; } *code = 0; dummy.server_addr = GetServer(host); if (dummy.server_addr == 0){ *code = ABS_SERVER_NOEXIST; return(NULL); } if (rx_inited == 0){ *code = rx_Init(0); if (*code) return(NULL); rx_inited = 1; *code = krb_get_lrealm(realm, 1); if (*code){ slave_log_error(ABS_ERROR,"afs_connect", "cannot get local realm"); return(NULL); } } if (dummy.rockp == (struct abs_rock *) NULL){ dummy.rockp = (struct abs_rock *) malloc(sizeof(struct abs_rock)); if (dummy.rockp == (struct abs_rock *) NULL){ *code = ABS_NO_MEM; return(NULL); } memset(dummy.rockp, 0, sizeof (struct abs_rock)); } /* * Get authentication information to pass to rx * We don't deal with requests for other realms. */ for(i=0; cell[i] != '\0'; i++){ cell[i] = tolower(cell[i]); } *code = krb_mk_req(&dummy.auth,"afs", cell, realm, &dummy.cred); if (*code == KDC_PR_UNKNOWN){ *code = krb_mk_req(&dummy.auth, "afs", "", realm, &dummy.cred); } if (*code){ sprintf(buf,"failed to get ticket to afs.%s@%s - Kerberos error %d\n", cell, realm, *code); slave_log_error(ABS_ERROR,"afs_connect",buf); *code = ABS_AUTH_ERROR; return(NULL); } *code = krb_get_cred("afs",cell, realm, &dummy.cred); /* * We have Kerberos tickets to the specified afs service; * now pass the info to RX so that it will send the auth info * on the authenticated RX connection. */ if (*code == 0 ){ dummy.rx_sec_index = 2; dummy.rxsec = (struct rx_securityClass *) rxkad_NewClientSecurityObject(rxkad_clear, &dummy.cred.session, dummy.cred.kvno, dummy.cred.ticket_st.length, dummy.cred.ticket_st.dat); }else{ dummy.rx_sec_index = 0; sprintf(buf,"Kerberos Error code %d while authenticating\n",*code); slave_log_error(ABS_ERROR,"afs_connect", "Could not authenticate to AFS -Running unauthenticated"); dummy.rxsec = (struct rx_securityClass *)rxnull_NewClientSecurityObject(); dummy.rx_sec_index = 0; } /* * Preliminary setup work for the UV_DumpVolume Call */ UV_SetSecurity( dummy.rxsec, dummy.rx_sec_index); if (op == ABS_RESTORE_OP){ *code = setup_auth_vldb_connection(&dummy, cell); } return((void *)&dummy); } /* * Procedure: setup_auth_vldb_connection * * Parameters: handlep - pointer to afs connection information. * cell - pointer to name of cell for which connection is requested * * Modifies: handlep->vld_conns * * Description: This function initializes an authenticated connection * to the VLDB servers for "cell". It uses the afsconf library calls * to read the afs configuration information to locate the addresses * of the VLDB servers for "cell". It then uses the Kerberos * authentication information stored in "handlep" to pass to * "rx_NewConnection" to create an authenticated connection to * each VLDB server in the cell. This setup is necessary for * any VLDB library calls. * * UGLY CODE WARNING: Because we are using the UV_RestoreVolume routines, * they expect that the caller has initialzed the AFS global variable * "cstruct" with the UBIK VLDB connection information. Thus the * external reference below to "cstruct" which does not appear in * our sources but is actually part of the AFS library. We * could avoid this by writing our own version of UV_RestoreVolume, * but that is too much work for now. * */ extern struct ubik_client *cstruct; int setup_auth_vldb_connection(afs_conn *handlep, char *cell) { int i, code; struct afsconf_dir *confdir; struct afsconf_cell info; char buf[512]; confdir = afsconf_Open(AFSCONF_CLIENTNAME); if (confdir == (struct afsconf_dir *) NULL){ slave_log_error(ABS_ERROR,"setup_auth_vldb", "Could not open afs cell conf file\n"); return(ABS_FS_ERROR); } code = afsconf_GetCellInfo(confdir, cell, AFSCONF_VLDBSERVICE, &info); if (code){ sprintf(buf,"Can't get AFS cell info for cell %s\n", cell); slave_log_error(ABS_ERROR,"setup_auth_vldb_conection", buf); } if (info.numServers > VLDB_MAXSERVERS) info.numServers = VLDB_MAXSERVERS; for(i=0; i< info.numServers; i++){ handlep->vldb_conns[i] = rx_NewConnection(info.hostAddr[i].sin_addr.s_addr, info.hostAddr[i].sin_port, USER_SERVICE_ID, handlep->rxsec, handlep->rx_sec_index); } afsconf_Close(confdir); code = ubik_ClientInit(handlep->vldb_conns, &cstruct); if (code){ sprintf(buf," ubik_ClientInit fails for cell %s\n", cell); slave_log_error(ABS_ERROR,"setup_auth_vldb_conection", buf); } return(code); } /* * Function: afs_dump * * Parameters: handle - pointer to server's network connection info * dh - pointer to device-specific state info * level - level of dump * jp - pointer to job info for this job * vp - pointer to net_volume describing volume to be dumped * data_written - flag indicating (on error) whether any data * was written to the medium. * * Description: Perform preliminary tasks preceeding the volume dump * Call UV_DumpVolume (afs library routine) to start a transaction on * the appropriate volserver. ABS_DumpFunc will take care of the * data transfer from the volserver to the media. */ int afs_dump(afs_conn *handle, dev_handle_t *dh, long dump_from, job_t *jp, net_volume_t *vp, int *data_written, abs_label_t *labelp, dump_params_t *params) { int code, partid, dumpid; struct afs_data *fsb; char buf[256]; if (vp->fs_private.fstype != voltype_afs){ sprintf(buf, "bad volume type for %s\n", vp->v_name); slave_log_error(ABS_ERROR, "afs_dump", buf); return(ABS_INVALID_SPEC); } fsb = &vp->fs_private.afs_volume_data; /* * get server partition id from partition name */ partid = afs_partname_to_id(vp->v_part); if (partid < 0){ return(ABS_NO_DEVICE_SPEC); } /* * Setup the abs_rock with data which is needed to * manage the dump operation. This includes the * device-specific info, the job parameters, and * the volume header, which our dump partner, ABS_DumpFunc * will write to the tape. */ handle->rockp->dh = dh; handle->rockp->jp = jp; netvol_to_volheader(vp, &handle->rockp->vh); handle->rockp->vh.fs_volid1 = fsb->afs_rwid; handle->rockp->vh.fs_volid2 = fsb->afs_backid; handle->rockp->data_written = handle->rockp->status = 0; handle->rockp->labelp = labelp; /* * UV_Dumpvolume initiates a transaction with the volserver * to begin the dump. "ABS_DumpFunc" will actually do the * work of reading the volume's data from the network and * writing it to tape. */ if (params->dump_flags == ABS_DUMP_CLONE){ dumpid = fsb->afs_backid; sprintf(buf, "Dump using CLONE %d\n", dumpid); slave_log_error(ABS_INFORMATIONAL, "afs_dump", buf); if (dumpid == 0){ /* * No clone exists for this volume - log an error */ sprintf(buf,"No clone for AFS volume %d %s\n", fsb->afs_rwid, vp->v_name); slave_log_error(ABS_ERROR,"afs_dump", buf); code = ABS_NO_CLONE; vp->v_status = ABS_NO_CLONE; *data_written = 0; return(code); } }else{ dumpid = fsb->afs_rwid; sprintf(buf, "Dump using RW %d\n", dumpid); slave_log_error(ABS_INFORMATIONAL, "afs_dump", buf); } code = UV_DumpVolume(dumpid, handle->server_addr, partid, dump_from, ABS_DumpFunc, handle->rockp); if (code == -1){ /* error writing to tape - the actual ABS error * is stored in the rock */ if (handle->rockp->status != 0) code = handle->rockp->status; else code = ABS_COMM_FAILURE; }else if (code == 0){ /* * success - update size for this volume */ LLSET(vp->v_size, handle->rockp->vh.size_high, handle->rockp->vh.size_low ); vp->last_backup = handle->rockp->vh.dump_date; }else { /* * Map any non-abs errors from AFS or RX to an abs error. */ code = map_afs_errors(code); } vp->v_status = code; *data_written = handle->rockp->data_written; return(code); } /* * Procedure: afs_restore * * Parameters: handlep - pointer to afs connection and other information * specific to this restore operation. * dh - pointer to device-specific information. * params - pointer to restore operation paramters. * vp - pointer to volume info for volume to be restored. * do_rewind - integer indicating whether any data from the * tape was actually read. * * Modifies: handlep, vp, do_rewind * * Description: This function initiates a restore operation with * the indicated server to restore a single volume. Upon entry * the media is positioned at the start of the volume header for * the volume to be restored. This function will read the volume * header and ensure it corresponds to the volume information indicated * by "vp". This function will also check if the volume currently * exists in the AFS VLDB and on the specified server before * initiating the restore operation with the server. If the volume * is found to exist on the server and the overwrite flag is not set, * the the operation will be aborted, otherwise, the restore operation * will be initiated with the appropriate AFS server. * * This function specifies ABS_RestoreFunc as the function for * UV_RestoreVolume to call to handle the actual reading of the * volume data from the media. UV_RestoreVolume is an AFS library * function. */ int afs_restore(afs_conn *handlep, dev_handle_t *dh, net_volume_pt vp, media_t *mp, job_pt jp, restore_pt params, int *do_rewind) { int code, partid, server_addr, noval; int volid, overwrite, len, tape_code = 0; struct afs_data *fsb; struct nvldbentry vent; struct volintInfo *volent; char *server, *part; abs_volheader_t vh; abs_volfooter_t vf; char buf[1024]; struct diskPartition diskp; *do_rewind = 0; if (vp->fs_private.fstype != voltype_afs){ sprintf(buf, "bad volume type for %s\n", vp->v_name); slave_log_error(ABS_ERROR, "afs_restore", buf); return(ABS_INVALID_SPEC); } fsb = &vp->fs_private.afs_volume_data; /* * Get the volume id, destination server, * destination partition and destination volume name. */ if (strlen(params->dest_host) > 0){ server = params->dest_host; }else server = vp->v_server; if (strlen(params->dest_dev) > 0) part = params->dest_dev; else part = vp->v_part; /* * get server AFS partition id from partition name */ partid = afs_partname_to_id(part); if (partid < 0){ return(ABS_NO_DEVICE_SPEC); } /* * get server address from server name */ server_addr = GetServer(server); if (server_addr == 0){ return(ABS_SERVER_NOEXIST); } /* * Read the volume header from the media. The media * is already positioned at the correct offset for this * volume */ code = read_volume_header(dh, &handlep->rockp->vh); *do_rewind = 1; if (code){ sprintf(buf,"Cannot read volume header volume %s\n", vp->v_name); slave_log_error(ABS_ERROR, "afs_restore",buf); return(code); } /* * Ensure that the volume id listed on the tape is the one that * the caller is really asking for */ if (handlep->rockp->vh.fs_volid1 != fsb->afs_rwid){ sprintf(buf, "Wrong volume on tape: wanted %d, got %d\n", fsb->afs_rwid, handlep->rockp->vh.fs_volid1); slave_log_error(ABS_ERROR, "afs_restore",buf); return(ABS_VOLID_MISMATCH); } /* * Check if the restore target volume name is different than * the original volume name */ if (params->suffix != (char *)NULL){ len = strlen(params->suffix); if (len + strlen(vp->v_name) +1 > ABS_MAX_VOLNAME){ /* save space for '.' and null terminator */ strncpy(vp->res->restore_target, vp->v_name, ABS_MAX_VOLNAME-(len+2)); sprintf(buf,"Truncating target name volume %s suffix: %s\n", vp->v_name, params->suffix); slave_log_error(ABS_WARNING,"afs_restore", buf); }else{ strcpy(vp->res->restore_target,vp->v_name); } strcat(vp->res->restore_target,"."); strcat(vp->res->restore_target, params->suffix); volid = 0; }else{ strcpy(vp->res->restore_target, vp->v_name); volid = fsb->afs_rwid; } overwrite = (params->restore_flags & ABS_OVERWRITE_VOLUME); /* * Setup the abs_rock */ handlep->rockp->dh = dh; handlep->rockp->jp = jp; handlep->rockp->data_read = 0; /* * AFS supports only 32-bit volume sizes */ LLGET(vp->v_size, noval, handlep->rockp->volsize); handlep->rockp->media = mp; /* * AFS does not handle very well the case where we overwrite * an existing volume. So check to see if the volume exists * in the VLDB first; if so, get its id and check with the server * to ensure that there is not really a volume with this id. */ if (overwrite == 0){ code = VLDB_GetEntryByName(vp->res->restore_target, &vent); if (code == 0){ /* * Now get its volumeid and verify with the target server * that the volume does not physically exist on the partition. */ code = UV_ListOneVolume(htonl(server_addr), partid, vent.volumeId[RWVOL], &volent); if (code == 0){ sprintf(buf,"Restore target volume %s already exists in VLDB and on server \n",vp->res->restore_target); slave_log_error(ABS_ERROR, "afs_restore",buf); vp->v_status = ABS_VOL_EXISTS; NEXT_VOLHEADER(dh); return(vp->v_status); }else if (code == ENODEV){ /* * Yes AFS returns ENODEV if the volume does not exist * * The volume exists only in the VLDB's mind; we * can reuse its id. Specifying a non-zero id * will save a step in UV_RestoreVolume where * AFS will execut a VLDB_GetEntryByName as we * just did. */ volid = vent.volumeId[RWVOL]; }else{ /* * Some other error; we can't determine if it really * exists. Play it safe and disallow the restore. */ code = map_afs_errors(code); sprintf(buf,"Error retrieving volume %s location info \n", vp->v_name, code); slave_log_error(ABS_ERROR, "afs_restore",buf); vp->v_status = code; NEXT_VOLHEADER(dh); return(code); } }else{ if (code != VL_NOENT){ /* * can't determine if the volume exists * disallow the restore. */ code = map_afs_errors(code); code = map_afs_errors(code); sprintf(buf,"Error retrieving volume %s location info \n", vp->v_name, code); slave_log_error(ABS_ERROR, "afs_restore",buf); vp->v_status = code; NEXT_VOLHEADER(dh); return(code); } } } /* * Now check to see if there is enough space on the target * partition. AFS does not behave well when the partition is * over 100% full; since we are privileged operation, AFS * will actually let us fill the filesystem beyond 100% */ server_addr = htonl(server_addr); code = UV_PartitionInfo(server_addr, part, &diskp); if (code){ sprintf(buf,"Cannot get parition information for %s %s, code %d\n", server, part, code); slave_log_error(ABS_ERROR, "afs_restore", buf); code = map_afs_errors(code); vp->v_status = code; NEXT_VOLHEADER(dh); *do_rewind = 1; return(code); } /* * Partition usage is given in units of K */ if (diskp.free < ((handlep->rockp->volsize + 1023) >> 10) ){ vp->v_status = ABS_FS_FULL; NEXT_VOLHEADER(dh); *do_rewind = 1; sprintf(buf,"Insufficient space on %s %s - free %d K volsize %d K\n", server, part, diskp.free, (handlep->rockp->volsize +1023) >> 10); slave_log_error(ABS_ERROR, "afs_restore", buf); return(ABS_FS_FULL); } sprintf(buf,"Initiate restore of volume %d to Server %s, partition %s\n", fsb->afs_rwid, server, part); slave_log_error(ABS_INFORMATIONAL, "afs_restore",buf); code = UV_RestoreVolume(server_addr, partid, volid, vp->res->restore_target, overwrite, ABS_RestoreFunc, handlep->rockp); /* * If ABS_RestoreFunc was successfully called it will leave the * tape positioned after this volume's footer. If not, the tape * is positioned after this volume's header. "data_read" indicates * whether ABS_RestoreFunc was ever called. The idea is that we * leave the tape positioned at the start of the volume header * which is closest to our current position to reduce the amount * of physical tape movement. * */ if (code && (handlep->rockp->data_read == 0)){ /* * Reverse tape so that it is positioned at the start of this * volume header. */ tape_code = PREV_VOLHEADER(dh); *do_rewind = 0; } if (code == -1){ /* error reading from tape - the actual ABS error * is stored in the rock if ABS_RestoreFunc was called. * If ABS_RestoreFunc was not called (because the transaction * could not be initiated, then there isn't any status to save. */ if (handlep->rockp->status) code = handlep->rockp->status; else code = ABS_COMM_FAILURE; /* Assume vlserver was down */ }else if ( code != 0){ code = map_afs_errors(code); } if (tape_code) code = tape_code; vp->v_status = code; return(code); } /* * Function: afs_disconnect * * Parameters: handle - address of afs-specific connection information. * * Description: This is curently a NOOP for AFS; it is provided solely * to fill the requirements of the filesystem abstraction layer for * the slave */ int afs_disconnect(void *handle) { return(0); } /* * Procedure: afs_partname_to_id * * Parameters: part - address of string represendint afs partition name * * Description: convert an AFS partition name to a numeric id. * Takes the last letter in "vicex" or "/vicex" and converts it to * a number in the range 0-25 - This is how AFS does it. */ int afs_partname_to_id(char *part) { char c; int id; if (!strncmp(part, "vicep", 5)){ c = part[5]; }else if (!strncmp(part, "/vicep", 6)){ c = part[6]; }else return(-1); id = (int)c - 'a'; return(id); } /* * Procedure: ABS_RestoreFunc * * Parameters: call - address of rx connection information used * to communicate with volserver * restore_rock - address of abs_rock structure * used to communicate information between this * routine and afs_restore * Modifies: restore_rock * * Description: This routine is called indirectly from afs_restore * as a result of invoking the AFS library call UV_RestoreVolume * to perform the restore of one volume. This function assumes * that the tape has been position at the start of the dump data * for the volume to be restored. It uses the size information * stored in restore_rock to determine the size of the dump data * for the volume. It reads fixed size tape records and transfers * them to the volserver via the rx_write call. * * Actual error codes are stored in restore_rock->status upon * return, if the return value from ABS_RestoreFunc is non-zero. * * The return of -1 for error is modeled after the afs * sources which also use UV_DumpVolume. * * Upon return, this function attempts to leave the tape positioned * at the start of the volume header of the volume which follows the * current volume being restored. */ int ABS_RestoreFunc(struct rx_call *call, char *restore_rock) { int count, bytes, code, magic; longlong_t i; char *buffer, buf[512]; struct abs_rock *rockp; abs_volfooter_t vf; rockp = (struct abs_rock *)restore_rock; buffer = rockp->dh->buf; count = rockp->dh->bufsize; /* * Here we are called by the RX after the volserver * is ready to accept data from us. The tape is * already positioned just after the volume header * so start reading the data */ bytes = rockp->dh->bufsize; /* * Read a tape record's worth of data from the tape and * transfer it to the server which is executing the restore. */ rockp->data_read = 1; for (i=rockp->volsize; i> 0; i-= count){ count = SLAVE_READ(rockp->dh, rockp->dh->buf, bytes, &code); if (count != bytes){ if ((code == ABS_EOF_DETECTED) || (code == ABS_EOM_DETECTED) || (code == ABS_INVALID_RECSIZE)){ /* * The above errors indicate a premature end-of-volume * Issue a warning and fail the restore operation */ sprintf(buf,"Premature end of data encountered for volume %s, code= %s\n", rockp->vh.name, get_abs_msg(code)); slave_log_error(ABS_ERROR,"ABS_RestoreFunc",buf); rockp->status = code; if (code == ABS_INVALID_RECSIZE){ /* * see if what we just read is a volheader or footer * Tape needs to be alinged on inter-record gap before * the next volume header following this volume when * we return. */ memcpy(&magic, rockp->dh->buf, sizeof(int)); magic = ntohl(magic); if (magic == ABS_VOLFOOTER_MAGIC){ return(-1); } else if (magic == ABS_VOLHEADER_MAGIC){ /* * It's a volume header */ SLAVE_NEXT_RECORD(rockp->dh, -1); }else{ /* * This shouldn't happen unless the tape somehow * was somehow corrupted. */ sprintf(buf,"Corrupt control record encountered while reading volume %s\n", rockp->vh.name); slave_log_error(ABS_ERROR,"ABS_RestoreFunc", buf); } } return(-1); }else{ /* * Error Reading from the device - The requirements don't state * exactly what we are supposed to do in this case, so this may * change. */ rockp->status = ABS_MEDIA_ERROR; return(-1); } } /* * Because dump data is written in fixed size records, the last * chunk of data may be less than the tape record size, so * we must check for this and send to rx the correct amount of data. */ if (i < bytes) count = i; if ( rx_Write(call,buffer,count) != count ){ /* * Error transferring the data to the Server * the assumption here is that rx tries hard enough * to do this, so we don't have to retry. */ switch(rx_Error(call)){ case RX_CALL_DEAD: rockp->status = ABS_COMM_FAILURE; case RX_CALL_TIMEOUT: rockp->status = ABS_CALL_TIMEOUT; break; default: rockp->status = ABS_FS_ERROR; break; } /* * Ensure we leave tape aligned after the footer */ code = NEXT_VOLFOOTER(rockp->dh); if (code) rockp->status = code; code = read_volume_footer(rockp->dh, &vf); if (code) rockp->status = code; return(-1); } } /* * Read the Footer for the volume. If we can't read the * footer return a -1 so that AFS will not put this volume on-line * and instead will mark for delete on salvage */ rockp->status = read_volume_footer(rockp->dh, &vf); if (rockp->status != 0 || vf.status != ABS_VS_VALID){ if (rockp->status != 0){ sprintf(buf,"Failed to read volume %s footer after restore: %s\n", rockp->vh.name, get_abs_msg(rockp->status)); }else{ sprintf(buf, "Volume footer indicates volume %s is invalid\n", rockp->vh.name); } slave_log_error(ABS_ERROR, "ABS_RestoreFunc", buf); return(-1); } rockp->status = 0; return(0); } /* * Function: ABS_DumpFunc * * Parameters: call - address of rx connection info * dump_rock - address of "rock" information which was setup by * "afs_dump" * * Modifies: dump_rock * * Returns: integer indicating whether the dump was successful * values: 0 - success * -1 - device/media errors * non-zero - RX error codes for RX errors * * Description: This function is called by UV_DumpVolume after the dump * transaction has been initiated with the appropriate volserver. Its * purpose is to read the data arriving on the rx connection from the volserver * and write it to the media. * * This function does not write the volume footer at the end of a * successful dump. * * This function will place an actual error code in dump_rock->status * if a non-zero value is returned. * * Note: we do not handle end-of-medium here; that is handled in the * high-level dump routine "do_dump". Volumes are not allowed to * span tapes, because this actually will create more problems than * it solves! */ int ABS_DumpFunc(struct rx_call *call, /* modified */ char *dump_rock) { unsigned int bytes_read, bytes_requested, bytes_written; unsigned int bytes_left, start; int code, done; longlong_t i, total; char *bp, buf[256]; struct abs_rock *rockp; struct timeval tv; /* * cast "dump_rock" to its real data type. The call * signature for the AFS dump handler declares the rock * parameter as a char pointer, and this is not what * we need */ rockp = (struct abs_rock *) dump_rock; bp = rockp->dh->buf; gettimeofday(&tv); rockp->vh.dump_date = tv.tv_sec; /* * Here we are called by the RX after our dump transaction has * been initiated with the volserver. The medium * already positioned just after the last EOF markser * so write the vol header and begin reading the data. * Our predecessor, afs_dump * has stored the volume header information in the "rock" * so we can now write it to the device. */ code = write_volume_header(rockp->dh, &(rockp->vh)); if (code){ rockp->status = code; sprintf(buf, "Received Error %d while writing volume header for volume %s: %s\n", code, &rockp->vh.name, get_abs_msg(code)); slave_log_error(ABS_ERROR,"ABS_DumpFunc",buf); return(-1); } /* * Keep track of whether any data was actually written for * this volume. The high level dump routine uses this * information to determivne whether it needs to create a * record for the volume footer should the dump of this * volume fail */ rockp->data_written = 1; /* * Now write the volume data to the medium as it comes in * from the network via RX. Total is used to produce an * accurate count of the amount of data associated with the * volume, this value will be returned as part of the dump * information for each volume and entered into the database * along with the tape information. */ total = 0; bytes_requested = rockp->dh->bufsize; /* * Keep asking for one buffer's worth of data * from the RX until we either get an RX error * or the amount of data received is less than * the amount of data requested and there is no error. */ memset(bp, 0, rockp->dh->bufsize); bytes_read = rx_Read(call, bp, bytes_requested); while (rx_Error(call) == 0){ if (bytes_read == 0) break; done = (bytes_read < bytes_requested); total+= bytes_read; if (done) bytes_read = rockp->dh->bufsize; bytes_written = SLAVE_WRITE(rockp->dh, bp, bytes_read, &code); if (bytes_written != bytes_read){ sprintf(buf,"Error while writing data for volume %s, code= %s\n", &rockp->vh.name, get_abs_msg(code)); slave_log_error(ABS_ERROR,"ABS_DumpFunc",buf); rockp->status = code; return(-1); } if (done) break; bytes_read = rx_Read(call, bp, bytes_requested); } /* end While */ /* * We are here because we either have finished reading all * of the data or we have an RX transmission error. */ if (rx_Error(call)){ rockp->status = rx_Error(call); sprintf(buf, "Received RX Error %d while writing volume data for volume %s\n", rockp->status, rockp->vh.name); slave_log_error(ABS_ERROR,"ABS_DumpFunc",buf); return(rx_Error(call)); } LLGET(total, rockp->vh.size_high, rockp->vh.size_low ); rockp->status = 0; return(0); } /* * Function: GetServer * * Parameters: aname - address of a server name * * Returens: ip address of server or 0 if can't convert. * * Description: this function takes a string server name and * converts it to an ip address. * * * UGLY CODE WARNING: We would rather call this from the AFS * library directly but it is declared static so we just copied * it. */ int GetServer(aname) char *aname; { register struct hostent *th; int addr; int b1, b2, b3, b4; register int code; struct in_addr *in; char *a; code = sscanf(aname, "%d.%d.%d.%d", &b1, &b2, &b3, &b4); if (code == 4) { /* parsed as 128.2.9.4, or similar, just use it */ addr = (b1<<24) | (b2<<16) | (b3<<8) | b4; return htonl(addr); /* convert to network order (128 in byte 0) */ } th = gethostbyname(aname); /* this may return a non-null pointer even if it * did not really retrieve the address * e.g., name = " cumin" instead of "cumin" */ if (!th) return 0; in = (struct in_addr *)(th->h_addr); return (in->s_addr); } /* * Procedure: map_afs_errors * * Parameters: code - error code value to be converted * * Description: Map AFS-specific error codes to ABS error codes */ int map_afs_errors(int code) { if (ABS_MIN_ERR < code && code < ABS_MAX_ERR) return(code); switch(code){ case 0: return(0); case VOLSERNOVOL: case VOFFLINE: case VNOSERVICE: /* volume not in service */ case VNOVOL: /* volume does not exist, is not attached,is off line */ return(ABS_NOSUCH_VOLUME); case VSALVAGE: /* volume needs to be salvaged */ return(ABS_VOLUME_DAMAGED); case VOLSERVOLBUSY: case VBUSY: return(ABS_VOLUME_BUSY); case VOLSERVOLMOVED: case VMOVED: return(ABS_VOLUME_MOVED); case VL_PERM: return(ABS_FS_PERM); case RX_CALL_DEAD: return(ABS_COMM_FAILURE); case RX_CALL_TIMEOUT: return(ABS_CALL_TIMEOUT); case RX_EOF: return(0); default: return(ABS_FS_ERROR); } } slave/basic/ 40700 6031 145 0 6126007667 12307 5ustar delgadoorawebslave/basic/RCS/ 40700 6031 145 0 6126007475 12733 5ustar delgadoorawebslave/basic/RCS/basic_mtio.c,v100400 6031 145 17355 6126007475 15602 0ustar delgadoorawebhead 3.5; branch ; access ; symbols autolabel-baseline:3.5 alpha:2.1; locks delgado:3.5; strict; comment @ * @; 3.5 date 96.03.12.12.37.17; author delgado; state Exp; branches ; next 2.1; 2.1 date 96.02.14.13.26.33; author delgado; state Exp; branches ; next 1.2; 1.2 date 96.02.02.11.21.23; author delgado; state Exp; branches ; next 1.1; 1.1 date 95.11.29.15.49.39; author delgado; state Exp; branches ; next ; desc @Support for simple mag tape operations via the mtio interface @ 3.5 log @autolabel baseline @ text @#include #include #include #include #include #include #include #include #include #include "private.h" #include "prototypes.h" #include "../master/abs_msg.h" #define MTIO_MAX 64512 #define MTIO_WAIT_INTERVAL 60*3 #define MTIO_MAX_RETRIES 4 typedef struct mtio_data{ int fileno; off_t offset; off_t position; struct mtdrivetype info; } mtio_data_t; typedef struct mtio_data *mtio_data_pt; int mtio_map_device_error(int code); extern int mtio_open_file(int *fd, mtio_data_t *mtiop, char *fname, int match); extern int mtio_reset(dev_handle_t *dh); int mtio_open(dev_table_t *dp, dev_handle_t **dh, char *name, int flags, int jobid) { dev_handle_t *dtp; mtio_data_t *mtp; struct mtget mt; char buf[512]; int docleanup=0; int code, blocksize, retries; if (*dh == (dev_handle_t *) NULL){ dtp = (dev_handle_t *)malloc(sizeof(dev_handle_t)); if (dtp == (dev_handle_t *) NULL){ return(ABS_NO_MEM); } strcpy(dtp->devname, name); dtp->dev_ops = dp; *dh = dtp; dtp->bufsize = MTIO_MAX; dtp->buf = (char *) malloc( dtp->bufsize ); if (dtp->buf == (char *) NULL){ free(dtp); return(ABS_NO_MEM); } mtp = (mtio_data_t *)malloc(sizeof(mtio_data_t)); dtp->data = (void *)mtp; memset(dtp->data, 0, sizeof(mtio_data_t)); docleanup = 1; }else dtp = *dh; /* * We try to open the device. If the tape is not inserted * Then the system will return EIO. Try a few times * to give the user time to mount the tape */ retries = 0; while( (dtp->fd = open(name, flags)) < 0){ if ((errno != EBUSY) && (errno != EIO) && (errno != EACCES) || (retries >= MTIO_MAX_RETRIES) ){ if (docleanup); free(dtp); return(mtio_map_device_error(errno)); } if (errno == EIO){ request_service( jobid , ABS_TAPE_MOUNT_REQ, NULL); }else if (flags == O_RDWR && errno == EACCES){ slave_log_error(ABS_WARNING,"mtio_open","Can't open device for write\n"); request_service(jobid, ABS_RO_DEVICE , NULL); }else{ slave_log_error(ABS_WARNING,"mtio_open","Device Busy - retrying\n"); } retries++; sleep(MTIO_WAIT_INTERVAL); } code = ioctl(dtp->fd, MTIOCGETDRIVETYPE, &mtp->info); return(0); } mtio_next_medium(dev_handle_t *dh, char *extid, media_id_pt midp) { return(0); } /* * * Description - attempt to read the requested number of bytes * from the device. 0 bytes read indicates an end-of-file marker * is encountered and two successive reads of 0 bytes indicates * an end-of-medium marker is encountered */ int mtio_read(dev_handle_t *dh, char *buf, int count, int *rcp) { int bytes; bytes = read(dh->fd, buf, count); if (bytes == 0){ bytes = read(dh->fd, buf, count); if (bytes == 0) *rcp = ABS_EOM_DETECTED; else *rcp = ABS_EOF_DETECTED; } else if (bytes < 0){ if (errno == EINVAL) *rcp = ABS_INVALID_RECSIZE; else *rcp = convert_system_error(errno); }else{ *rcp = 0; } return(bytes); } int mtio_write(dev_handle_t *dh, char *buf, int count, int *rcp) { int bytes; *rcp = 0; bytes = write(dh->fd, buf, count); if (bytes == 0){ *rcp = ABS_EOM_DETECTED; /* * The mtio man page says that the first time we get * bytes = 0 we can write one more time, but after that * all other writes will fail. */ bytes = write(dh->fd, buf, count); return(bytes); } else if (bytes < 0){ *rcp = convert_system_error(errno); } return(bytes); } mtio_rewind(dev_handle_t *dh) { struct mtop mt; int code; mt.mt_op = MTREW; mt.mt_count = 1; code = ioctl(dh->fd, MTIOCTOP, &mt); if (code){ if (errno == EIO) code = ABS_DEV_ERROR; else code = convert_system_error(errno); } return(code); } int mtio_next_record(dev_handle_t *dh, int count) { struct mtop mt; int code; int magic; /* * note MTFSR -1 is not the same as MTBSR 1 */ if (count >= 0){ mt.mt_count = count; mt.mt_op = MTFSR; } else{ mt.mt_count = 0 - count; mt.mt_op = MTBSR; } code = ioctl(dh->fd, MTIOCTOP, &mt); return(code); } int mtio_seek(dev_handle_t *dh, longlong_t offset, int filemarks, int flags) { return(ABS_NOT_SUPPORTED); } int mtio_close(dev_handle_t *dh, int full) { int code; code = close(dh->fd); if (code){ if (errno == EIO) code = ABS_DEV_ERROR; else code = convert_system_error(errno); } if (full == 0) return(0); if (dh->data){ free(dh->data); } free(dh); return(code); } void mtio_devtype(dev_handle_t *dh, char **dpp) { mtio_data_t *mtp; mtp = (mtio_data_t *)(dh->data); if (mtp == (mtio_data_t *) NULL){ *dpp = (char *)NULL; }else *dpp = mtp->info.vid; } int mtio_map_device_error(int code) { switch(code){ case EIO: return(ABS_NEEDS_MOUNT); case EBUSY: return(ABS_DEVICE_BUSY); case ENOENT: /* invalid device name */ return(ABS_NO_DEVICE_SPEC); default: return(ABS_DEV_ERROR); } } @ 2.1 log @alpha release @ text @@ 1.2 log @mtio_rewind should map errno and not code if an error is detected @ text @@ 1.1 log @Initial revision @ text @d5 1 d9 1 a10 1 #include "foot.h" d15 3 a17 1 #define MTIO_MAX 65532 d24 1 d27 2 d31 1 a32 1 d40 1 a40 1 mtio_open(dev_table_t *dp, dev_handle_t **dh, char *devname, int flags) d43 1 d46 2 a47 1 int code, blocksize; d49 45 a93 3 dtp = (dev_handle_t *)malloc(sizeof(dev_handle_t)); if (dtp == (dev_handle_t *) NULL){ return(ABS_NO_MEM); d95 1 a95 13 dtp->dev_ops = dp; dtp->fd = open(devname, flags); if (dtp->fd < 0){ } dtp->bufsize = MTIO_MAX; dtp->buf = (char *) malloc( dtp->bufsize ); if (dtp->buf == (char *) NULL){ free(dtp); return(ABS_NO_MEM); } dtp->data = (void *)malloc(sizeof(mtio_data_t)); memset(dtp->data, 0, sizeof(mtio_data_t)); *dh = dtp; d124 4 a127 1 *rcp = convert_system_error(errno); d139 2 d142 1 a142 1 if (bytes == 0) d144 9 d168 7 a174 1 code = convert_system_error(code); a179 5 int mtio_write_eof(dev_handle_t *dh) { struct mtop mt; int code; a180 9 mt.mt_op = MTWEOF; mt.mt_count = 1; code = ioctl(dh->fd, MTIOCTOP, &mt); code = convert_system_error(code); return(code); } d182 1 a182 1 mtio_next_file(dev_handle_t *dh, int position) d187 13 a200 3 mt.mt_op = MTFSF; mt.mt_count = position; a201 1 code = convert_system_error(code); d203 1 a204 1 } a206 1 d215 1 a215 1 mtio_close(dev_handle_t *dh) d217 1 a217 1 mtio_rewind(dh); d219 10 a228 1 close(dh->fd); d233 1 d236 4 d241 23 @ slave/basic/basic_mtio.c~100600 6031 145 13110 6126007474 15071 0ustar delgadooraweb#include #include #include #include #include #include #include #include #include #include "private.h" #include "prototypes.h" #include "../master/abs_msg.h" #define MTIO_MAX 64512 #define MTIO_WAIT_INTERVAL 60*3 #define MTIO_MAX_RETRIES 4 typedef struct mtio_data{ int fileno; off_t offset; off_t position; struct mtdrivetype info; } mtio_data_t; typedef struct mtio_data *mtio_data_pt; int mtio_map_device_error(int code); extern int mtio_open_file(int *fd, mtio_data_t *mtiop, char *fname, int match); extern int mtio_reset(dev_handle_t *dh); int mtio_open(dev_table_t *dp, dev_handle_t **dh, char *name, int flags, int jobid) { dev_handle_t *dtp; mtio_data_t *mtp; struct mtget mt; char buf[512]; int docleanup=0; int code, blocksize, retries; if (*dh == (dev_handle_t *) NULL){ dtp = (dev_handle_t *)malloc(sizeof(dev_handle_t)); if (dtp == (dev_handle_t *) NULL){ return(ABS_NO_MEM); } strcpy(dtp->devname, name); dtp->dev_ops = dp; *dh = dtp; dtp->bufsize = MTIO_MAX; dtp->buf = (char *) malloc( dtp->bufsize ); if (dtp->buf == (char *) NULL){ free(dtp); return(ABS_NO_MEM); } mtp = (mtio_data_t *)malloc(sizeof(mtio_data_t)); dtp->data = (void *)mtp; memset(dtp->data, 0, sizeof(mtio_data_t)); docleanup = 1; }else dtp = *dh; /* * We try to open the device. If the tape is not inserted * Then the system will return EIO. Try a few times * to give the user time to mount the tape */ retries = 0; while( (dtp->fd = open(name, flags)) < 0){ if ((errno != EBUSY) && (errno != EIO) && (errno != EACCES) || (retries >= MTIO_MAX_RETRIES) ){ if (docleanup); free(dtp); return(mtio_map_device_error(errno)); } if (errno == EIO){ request_service( jobid , ABS_TAPE_MOUNT_REQ, NULL); }else if (flags == O_RDWR && errno == EACCES){ slave_log_error(ABS_WARNING,"mtio_open","Can't open device for write\n"); request_service(jobid, ABS_RO_DEVICE , NULL); }else{ slave_log_error(ABS_WARNING,"mtio_open","Device Busy - retrying\n"); } retries++; sleep(MTIO_WAIT_INTERVAL); } code = ioctl(dtp->fd, MTIOCGETDRIVETYPE, &mtp->info); return(0); } mtio_next_medium(dev_handle_t *dh, char *extid, media_id_pt midp) { return(0); } /* * * Description - attempt to read the requested number of bytes * from the device. 0 bytes read indicates an end-of-file marker * is encountered and two successive reads of 0 bytes indicates * an end-of-medium marker is encountered */ int mtio_read(dev_handle_t *dh, char *buf, int count, int *rcp) { int bytes; bytes = read(dh->fd, buf, count); if (bytes == 0){ bytes = read(dh->fd, buf, count); if (bytes == 0) *rcp = ABS_EOM_DETECTED; else *rcp = ABS_EOF_DETECTED; } else if (bytes < 0){ if (errno == EINVAL) *rcp = ABS_INVALID_RECSIZE; else *rcp = convert_system_error(errno); }else{ *rcp = 0; } return(bytes); } int mtio_write(dev_handle_t *dh, char *buf, int count, int *rcp) { int bytes; *rcp = 0; bytes = write(dh->fd, buf, count); if (bytes == 0){ *rcp = ABS_EOM_DETECTED; /* * The mtio man page says that the first time we get * bytes = 0 we can write one more time, but after that * all other writes will fail. */ bytes = write(dh->fd, buf, count); return(bytes); } else if (bytes < 0){ *rcp = convert_system_error(errno); } return(bytes); } mtio_rewind(dev_handle_t *dh) { struct mtop mt; int code; mt.mt_op = MTREW; mt.mt_count = 1; code = ioctl(dh->fd, MTIOCTOP, &mt); if (code){ if (errno == EIO) code = ABS_DEV_ERROR; else code = convert_system_error(errno); } return(code); } int mtio_next_record(dev_handle_t *dh, int count) { struct mtop mt; int code; int magic; /* * note MTFSR -1 is not the same as MTBSR 1 */ if (count >= 0){ mt.mt_count = count; mt.mt_op = MTFSR; } else{ mt.mt_count = 0 - count; mt.mt_op = MTBSR; } code = ioctl(dh->fd, MTIOCTOP, &mt); return(code); } int mtio_seek(dev_handle_t *dh, longlong_t offset, int filemarks, int flags) { return(ABS_NOT_SUPPORTED); } int mtio_close(dev_handle_t *dh, int full) { int code; code = close(dh->fd); if (code){ if (errno == EIO) code = ABS_DEV_ERROR; else code = convert_system_error(errno); } if (full == 0) return(0); if (dh->data){ free(dh->data); } free(dh); return(code); } void mtio_devtype(dev_handle_t *dh, char **dpp) { mtio_data_t *mtp; mtp = (mtio_data_t *)(dh->data); if (mtp == (mtio_data_t *) NULL){ *dpp = (char *)NULL; }else *dpp = mtp->info.vid; } int mtio_map_device_error(int code) { switch(code){ case EIO: return(ABS_NEEDS_MOUNT); case EBUSY: return(ABS_DEVICE_BUSY); case ENOENT: /* invalid device name */ return(ABS_NO_DEVICE_SPEC); default: return(ABS_DEV_ERROR); } } slave/basic/basic_mtio.c100600 6031 145 13623 6150104751 14675 0ustar delgadooraweb#include #include #include #include #include #include #include #include #include #include "private.h" #include "prototypes.h" #include "../master/abs_msg.h" #define MTIO_MAX 64512 #define MTIO_WAIT_INTERVAL 60*3 #define MTIO_MAX_RETRIES 4 typedef struct mtio_data{ int fileno; off_t offset; off_t position; struct mtdrivetype info; } mtio_data_t; typedef struct mtio_data *mtio_data_pt; int mtio_map_device_error(int code); extern int mtio_open_file(int *fd, mtio_data_t *mtiop, char *fname, int match); extern int mtio_reset(dev_handle_t *dh); int mtio_open(dev_table_t *dp, dev_handle_t **dh, char *name, int flags, int jobid) { dev_handle_t *dtp; mtio_data_t *mtp; struct mtget mt; char buf[512]; int docleanup=0; int code, blocksize, retries; if (*dh == (dev_handle_t *) NULL){ dtp = (dev_handle_t *)malloc(sizeof(dev_handle_t)); if (dtp == (dev_handle_t *) NULL){ return(ABS_NO_MEM); } strcpy(dtp->devname, name); dtp->dev_ops = dp; *dh = dtp; dtp->bufsize = MTIO_MAX; dtp->buf = (char *) malloc( dtp->bufsize ); if (dtp->buf == (char *) NULL){ free(dtp); return(ABS_NO_MEM); } mtp = (mtio_data_t *)malloc(sizeof(mtio_data_t)); dtp->data = (void *)mtp; memset(dtp->data, 0, sizeof(mtio_data_t)); docleanup = 1; }else dtp = *dh; /* * We try to open the device. If the tape is not inserted * Then the system will return EIO. Try a few times * to give the user time to mount the tape */ retries = 0; while( (dtp->fd = open(name, flags)) < 0){ if ((errno != EBUSY) && (errno != EIO) && (errno != EACCES) || (retries >= MTIO_MAX_RETRIES) ){ if (docleanup); free(dtp); return(mtio_map_device_error(errno)); } if (errno == EIO){ request_service( jobid , ABS_TAPE_MOUNT_REQ, NULL); }else if (flags == O_RDWR && errno == EACCES){ slave_log_error(ABS_WARNING,"mtio_open","Can't open device for write\n"); request_service(jobid, ABS_RO_DEVICE , NULL); }else{ slave_log_error(ABS_WARNING,"mtio_open","Device Busy - retrying\n"); } retries++; sleep(MTIO_WAIT_INTERVAL); } code = ioctl(dtp->fd, MTIOCGETDRIVETYPE, &mtp->info); return(0); } mtio_next_medium(dev_handle_t *dh, char *extid, media_id_pt midp) { return(0); } /* * * Description - attempt to read the requested number of bytes * from the device. 0 bytes read indicates an end-of-file marker * is encountered and two successive reads of 0 bytes indicates * an end-of-medium marker is encountered */ int mtio_read(dev_handle_t *dh, char *buf, int count, int *rcp) { int bytes; bytes = read(dh->fd, buf, count); if (bytes == 0){ bytes = read(dh->fd, buf, count); if (bytes == 0) *rcp = ABS_EOM_DETECTED; else *rcp = ABS_EOF_DETECTED; } else if (bytes < 0){ if (errno == EINVAL) *rcp = ABS_INVALID_RECSIZE; else *rcp = convert_system_error(errno); }else{ *rcp = 0; } return(bytes); } int mtio_write(dev_handle_t *dh, char *buf, int count, int *rcp) { int bytes; *rcp = 0; bytes = write(dh->fd, buf, count); if (bytes == 0){ *rcp = ABS_EOM_DETECTED; /* * The mtio man page says that the first time we get * bytes = 0 we can write one more time, but after that * all other writes will fail. */ bytes = write(dh->fd, buf, count); return(bytes); } else if (bytes < 0){ *rcp = convert_system_error(errno); } return(bytes); } mtio_rewind(dev_handle_t *dh) { struct mtop mt; int code; mt.mt_op = MTREW; mt.mt_count = 1; code = ioctl(dh->fd, MTIOCTOP, &mt); if (code){ if (errno == EIO) code = ABS_DEV_ERROR; else code = convert_system_error(errno); } return(code); } mtio_offline(dev_handle_t *dh) { struct mtop mt; int code; mt.mt_op = MTOFFL; mt.mt_count = 1; code = ioctl(dh->fd, MTIOCTOP, &mt); if (code){ if (errno == EIO) code = ABS_DEV_ERROR; else code = convert_system_error(errno); } return(code); } int mtio_next_record(dev_handle_t *dh, int count) { struct mtop mt; int code; int magic; /* * note MTFSR -1 is not the same as MTBSR 1 */ if (count >= 0){ mt.mt_count = count; mt.mt_op = MTFSR; } else{ mt.mt_count = 0 - count; mt.mt_op = MTBSR; } code = ioctl(dh->fd, MTIOCTOP, &mt); return(code); } int mtio_seek(dev_handle_t *dh, longlong_t offset, int filemarks, int flags) { return(ABS_NOT_SUPPORTED); } int mtio_close(dev_handle_t *dh, int full) { int code; code = close(dh->fd); if (code){ if (errno == EIO) code = ABS_DEV_ERROR; else code = convert_system_error(errno); } if (full == 0) return(0); if (dh->data){ free(dh->data); } free(dh); return(code); } void mtio_devtype(dev_handle_t *dh, char **dpp) { mtio_data_t *mtp; mtp = (mtio_data_t *)(dh->data); if (mtp == (mtio_data_t *) NULL){ *dpp = (char *)NULL; }else *dpp = mtp->info.vid; } int mtio_map_device_error(int code) { switch(code){ case EIO: return(ABS_NEEDS_MOUNT); case EBUSY: return(ABS_DEVICE_BUSY); case ENOENT: /* invalid device name */ return(ABS_NO_DEVICE_SPEC); default: return(ABS_DEV_ERROR); } } slave/basic/bm.c100600 6031 145 11330 6063441052 13154 0ustar delgadooraweb#include #include #include #include #include #include #include #include #include "private.h" #include "foot.h" #include "prototypes.h" #include "../master/abs_msg.h" #define MTIO_MAX 65532 #define MTIO_WAIT_INTERVAL 60*3 #define MTIO_MAX_RETRIES 4 typedef struct mtio_data{ int fileno; off_t offset; off_t position; } mtio_data_t; typedef struct mtio_data *mtio_data_pt; int mtio_map_device_error(int code); extern int mtio_open_file(int *fd, mtio_data_t *mtiop, char *fname, int match); extern int mtio_reset(dev_handle_t *dh); int mtio_open(dev_table_t *dp, dev_handle_t **dh, char *name, int flags) { dev_handle_t *dtp; struct mtget mt; char buf[512]; int docleanup=0; int code, blocksize, retries; if (*dh == (dev_handle_t *) NULL){ dtp = (dev_handle_t *)malloc(sizeof(dev_handle_t)); if (dtp == (dev_handle_t *) NULL){ return(ABS_NO_MEM); } strcpy(dtp->devname, name); dtp->dev_ops = dp; *dh = dtp; dtp->bufsize = MTIO_MAX; dtp->buf = (char *) malloc( dtp->bufsize ); if (dtp->buf == (char *) NULL){ free(dtp); return(ABS_NO_MEM); } dtp->data = (void *)malloc(sizeof(mtio_data_t)); memset(dtp->data, 0, sizeof(mtio_data_t)); docleanup = 1; }else dtp = *dh; /* * We try to open the device. If the tape is not inserted * Then the system will return EIO. Try a few times * to give the user time to mount the tape */ retries = 0; while( (dtp->fd = open(name, flags)) < 0){ if ((errno != EBUSY) && (errno != EIO) || (retries >= MTIO_MAX_RETRIES) ){ if (docleanup); free(dtp); return(mtio_map_device_error(errno)); } if (errno == EIO){ slave_log_error(ABS_WARNING,"mtio_open"," Tape Not mounted - retrying\n"); }else{ slave_log_error(ABS_WARNING,"mtio_open","Device Busy - retrying\n"); } retries++; sleep(MTIO_WAIT_INTERVAL); } return(0); } mtio_next_medium(dev_handle_t *dh, char *extid, media_id_pt midp) { return(0); } /* * * Description - attempt to read the requested number of bytes * from the device. 0 bytes read indicates an end-of-file marker * is encountered and two successive reads of 0 bytes indicates * an end-of-medium marker is encountered */ int mtio_read(dev_handle_t *dh, char *buf, int count, int *rcp) { int bytes; bytes = read(dh->fd, buf, count); if (bytes == 0){ bytes = read(dh->fd, buf, count); if (bytes == 0) *rcp = ABS_EOM_DETECTED; else *rcp = ABS_EOF_DETECTED; } else if (bytes < 0){ *rcp = convert_system_error(errno); }else{ *rcp = 0; } return(bytes); } int mtio_write(dev_handle_t *dh, char *buf, int count, int *rcp) { int bytes; bytes = write(dh->fd, buf, count); if (bytes == 0){ *rcp = ABS_EOM_DETECTED; /* * The mtio man page says that the first time we get * bytes = 0 we can write one more time, but after that * all other writes will fail. */ bytes = write(dh->fd, buf, count); return(bytes); } else if (bytes < 0){ *rcp = convert_system_error(errno); } return(bytes); } mtio_rewind(dev_handle_t *dh) { struct mtop mt; int code; mt.mt_op = MTREW; mt.mt_count = 1; code = ioctl(dh->fd, MTIOCTOP, &mt); code = convert_system_error(code); return(code); } int mtio_write_eof(dev_handle_t *dh) { struct mtop mt; int code; mt.mt_op = MTWEOF; mt.mt_count = 1; code = ioctl(dh->fd, MTIOCTOP, &mt); code = convert_system_error(code); return(code); } int mtio_next_file(dev_handle_t *dh, int position) { struct mtop mt; int code; mt.mt_op = MTFSF; mt.mt_count = position; code = ioctl(dh->fd, MTIOCTOP, &mt); code = convert_system_error(code); return(code); } int mtio_seek(dev_handle_t *dh, longlong_t offset, int filemarks, int flags) { return(ABS_NOT_SUPPORTED); } int mtio_close(dev_handle_t *dh, int full) { mtio_rewind(dh); close(dh->fd); if (full == 0) return(0); if (dh->data){ free(dh->data); } free(dh); return(0); } int mtio_map_device_error(int code) { switch(code){ case EIO: return(ABS_NEEDS_MOUNT); case EBUSY: return(ABS_DEVICE_BUSY); case ENOENT: /* invalid device name */ return(ABS_NO_DEVICE_SPEC); default: return(ABS_DEV_ERROR); } } slave/slave_int.c100400 6031 145 52105 6240131026 13456 0ustar delgadooraweb#include #include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" extern int slave_state; struct dev_table *devp; /* points to the ops vector for our device */ extern char master_server[PATH_MAX]; extern char device_name[PATH_MAX]; /* name of our device */ extern struct utsname un; /* contains our hostname */ extern int online; /* * Procedure: abs_backup_1_svc (RPC service routine entry point) * * Parameters: ndp - address of dumpset information to be dumped * jp - address of job information (containing jobid) * params - address of dump parameters for dump operation * rcp - return value * * Modifies: rcp - set according to the outcome of the dump (0 - success * non-zero failure) * * Description: This function is the entry point from the RPC into the * Slave's backup service routine. This routine will verify incoming * parameters, open the media device, and invoke "do_dump" to perform * the actual dump. */ bool_t abs_backup_1_svc(net_dumpset_pt ndp, job_pt jp, dump_params_pt params, int *rcp, struct svc_req *clp) { dev_handle_t *dh = (dev_handle_t *) NULL; char buf[512]; job_done_res_t jdone; char *datep; struct timeval now; memset(&jdone, 0, sizeof(job_done_res_t)); /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) goto dump_error; /* * Validate incoming parameters */ if (ndp == (net_dumpset_pt) NULL){ slave_log_error(ABS_ERROR,"dump", "Master specifies null dumpset \n"); *rcp = ABS_NO_DUMPSET; goto dump_error; } if (jp == (job_pt) NULL){ slave_log_error(ABS_ERROR,"dump", "Master specifies null job descriptor \n"); *rcp = ABS_INVALID_JOB; goto dump_error; } /* * check for unspecified fields in the dumpset structure */ if (ndp->d_name == (char *) NULL){ sprintf(buf, "Job %d Dumpset has no name!\n",jp->jobid); slave_log_error(ABS_ERROR, "dump", buf); *rcp = ABS_INVALID_SPEC; goto dump_error; } /* * Check for dumpset with no volumes */ if (ndp->volumes == (net_volume_pt) NULL){ sprintf(buf, "Dumpset %s has no volumes \n", ndp->d_name); slave_log_error(ABS_ERROR,"dump", buf); *rcp = ABS_NO_VOLUME_SPEC; goto dump_error; } if (params == (dump_params_pt) NULL){ slave_log_error(ABS_ERROR, "dump","Null dump parameters structure"); } /* * validate client's requested device type and host name * Ensure it's really me that is requested */ if (strcmp(jp->host, un.nodename)){ *rcp = ABS_NO_SERVER_SPEC; slave_log_error(ABS_ERROR,"dump", "Received incorrect hostname from Master"); goto dump_error; } if (strcmp(jp->device, device_name)){ *rcp = ABS_NO_DEVICE_SPEC; slave_log_error(ABS_FATAL,"dump", "Received incorrect devicename from Master"); goto dump_error; } /* * open the device. On some tape devices, the open will fail if there * The call to "request_service" within this loop * is to request a mount in case the device needs something to be present * in the drive inorder for the open to succeed. */ while((*rcp = SLAVE_OPEN(devp, &dh, device_name, O_RDWR, jp->jobid)) == ABS_NEEDS_MOUNT){ /* * Send mesasges to the master periodically to request a mount. * The master will annoy the user until he mounts a tape. */ *rcp = request_service(jp->jobid, ABS_TAPE_MOUNT_REQ, (tapeid_t *)NULL); } /* * We are here because we either have successfully opened the device * or we have encountered some unrecoverable error */ if (*rcp ){ if (*rcp == ABS_JOB_CANCELED){ slave_log_error(ABS_ERROR,"abs_backup","Job canceled at user's request\n"); SLAVE_CLOSE( dh); return(RPC_SUCCESS); } sprintf(buf, "Cannot open device %s \n", device_name); slave_log_error(ABS_FATAL,"dump",buf); goto dump_error; } /* * Everything is set up, "do_dump" will now execute the * dump for us */ *rcp = do_dump(dh, ndp, jp, params, &jdone.stats); if (*rcp == ABS_JOB_CANCELED){ SLAVE_CLOSE( dh); return(RPC_SUCCESS); } jdone.jdr_type = jdr_type_dumpset; jdone.jdr_dumpset = ndp; gettimeofday(&now); jdone.stats.date = now.tv_sec; if (*rcp == 0){ *rcp = perform_media_verification(dh, ndp, params->verf_mode, &jdone.stats, jp->jobid); } dump_done: if (!online){ SLAVE_OFFLINE(dh); } SLAVE_CLOSE(dh); dump_error: /* * We have to make an actual RPC to the Master to inform * it that we are done with the job. The master only * queues requests with us; it does not wait for us to complete * our work as in a normal RPC */ *rcp = slave_notify_master(*rcp, jp->jobid, &jdone, 1); return(RPC_SUCCESS); } /* * Procedure: abs_restore_1_svc * * Parameters: mp - address of media with list of volumes to restore. * jobid - job id assigned by master * rp - address of restore parameters * rcp - address of return code from call * clp - address of client rpc info * * Description: This function is the entry point from the RPC into the * Slave's restore service routine. This routine will verify incoming * parameters, open the media device, and invoke "do_restore" to perform * the actual restore. * */ bool_t abs_restore_1_svc(media_t *mp, int jobid, restore_pt rp, int *rcp, struct svc_req *clp) { dev_handle_t *dh = (dev_handle_t *)NULL; job_done_res_t jdone; char buf[512]; char *datep; struct timeval now; /* * Validate the caller's credentails. We only accept calls from * our Master */ memset(&jdone, 0, sizeof(job_done_res_t)); *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) goto restore_error; /* * Validate incoming parameters */ if (rp == (restore_pt) NULL){ slave_log_error(ABS_ERROR, "restore", "Master specifies null restore descriptor \n"); *rcp = ABS_INVALID_JOB; goto restore_error; } /* * Check for Request with no media */ if (mp == (media_t *) NULL){ sprintf(buf,"Restore job %d has no media specified\n", jobid); slave_log_error(ABS_ERROR,"restore",buf); *rcp = ABS_NO_VOLUME_SPEC; goto restore_error; } /* * validate client's requested device type and host name * Ensure it's really me that is requested */ if (rp->media_host == (char *) NULL || rp->media_device == (char *) NULL){ sprintf(buf,"Restore job %d has no media host/devce specified\n", jobid); slave_log_error(ABS_ERROR,"restore",buf); *rcp = ABS_NO_SERVER_SPEC; } if (strcmp(rp->media_host, un.nodename)){ slave_log_error(ABS_ERROR,"restore", "Received incorrect hostname from Master"); goto restore_error; } if (strcmp(rp->media_device, device_name)){ *rcp = ABS_NO_DEVICE_SPEC; slave_log_error(ABS_FATAL,"restore", "Received incorrect devicename from Master"); goto restore_error; } /* * open the device */ *rcp = SLAVE_OPEN(devp, &dh, device_name, O_RDONLY, jobid); if (*rcp == ABS_JOB_CANCELED){ slave_log_error(ABS_ERROR,"abs_backup","Job canceled at user's request\n"); SLAVE_CLOSE( dh); return(RPC_SUCCESS); } if (*rcp){ sprintf(buf, "Cannot open device %s \n", device_name); slave_log_error(ABS_FATAL,"restore",buf); goto restore_error; } *rcp = do_restore(dh, mp, jobid, rp, &jdone.stats); if (*rcp == ABS_SLAVE_TERMINATED){ return(RPC_SUCCESS); } jdone.jdr_type = jdr_type_media; jdone.jdr_media = mp; gettimeofday(&now); jdone.stats.date = now.tv_sec; restore_done: if (!online){ SLAVE_OFFLINE(dh); } SLAVE_CLOSE( dh); restore_error: /* * We have to make an actual RPC to the Master to inform * it that we are done with the job. The master only * queues requests with us; it does not wait for us to complete * our work as in a normal RPC */ *rcp = slave_notify_master(*rcp, jobid, &jdone, 1); return(RPC_SUCCESS); } /* * Prodcedure: abs_scan_1_svc * * Parameters: full_scan - indicates whether slave should perform full * scan of media * jp - address of job-related information. * rcp - address of return value from call * clp - address of client rpc information * * Description: This function is the entry point from the RPC into the * Slave's scan_media service routine. This routine will verify incoming * parameters, open the media device, and invoke "do_scan" to perform * the actual scan. */ bool_t abs_scan_1_svc(int full_scan, job_pt jp, int *rcp, struct svc_req *clp) { int master_rc, master_code; dev_handle_t *dh=(dev_handle_t *)NULL; abs_label_t abs_label; char buf[512]; net_dumpset_pt dp = (net_dumpset_pt) NULL; struct toc_res toc; /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) goto scan_error; if (jp == (job_pt) NULL){ *rcp = ABS_INVALID_SPEC; slave_log_error(ABS_FATAL,"scan_media", "Received NULL job from Master"); goto scan_error; } /* * validate client's requested device type and host name * Ensure it's really me that is requested */ if (strcmp(jp->host, un.nodename)){ *rcp = ABS_NO_SERVER_SPEC; slave_log_error(ABS_ERROR,"scan_media", "Received incorrect hostname from Master"); goto scan_error; } if (strcmp(jp->device, device_name)){ *rcp = ABS_NO_DEVICE_SPEC; slave_log_error(ABS_FATAL,"scan_media", "Received incorrect devicename from Master"); goto scan_error; } /* * open the device */ while((*rcp = SLAVE_OPEN(devp, &dh, device_name, O_RDONLY, jp->jobid)) == ABS_NEEDS_MOUNT){ /* * Send mesasges to the master periodically to request a mount. * The master will annoy the user until he mounts a tape. * For single-cartridge tapes the open fails if there is not a tape * in the drive. */ *rcp = request_service(jp->jobid, ABS_TAPE_MOUNT_REQ, (tapeid_t *)NULL); } if (*rcp){ sprintf(buf, "Cannot open device %s \n", device_name); slave_log_error(ABS_FATAL,"scan_media",buf); goto scan_error; } /* * Get the next media item; for single cartridge systems * This is essentially a no-op; for multi-cartridge we * expect the device to cyle around until it finds a * medium in one of its slots. */ *rcp = SLAVE_NEXT_MEDIA(dh, NULL, (media_id_pt) NULL, 0); if (*rcp){ sprintf(buf, "Cannot advance device %s \n", device_name); slave_log_error(ABS_FATAL,"scan_media", buf); goto scan_done; } /* * Rewind the device just in case */ *rcp = SLAVE_REWIND(dh); if (*rcp){ sprintf(buf, "device %s Rewind failure \n", device_name); slave_log_error(ABS_FATAL,"scan_media", buf); goto scan_done; } *rcp = do_scan(dh, &toc, full_scan); scan_done: if (!online){ SLAVE_OFFLINE(dh); } SLAVE_CLOSE(dh); scan_error: /* * We have to make an actual RPC to the Master to inform * it that we are done with the job. The master only * queues requests with us; it does not wait for us to complete * our work as in a normal RPC */ if (*rcp == ABS_JOB_CANCELED){ return(RPC_SUCCESS); } *rcp = slave_scan_results(*rcp, jp->jobid, &toc); return(RPC_SUCCESS); } /* * Procedure: abs_label_media_1_svc * * Parameters: extid - external id of medium * mip - internal id of medium, generated by master * jp - job information created by master * rcp - address of return code * clp - address of client specific information. * * * Description: This function is the entry point from the RPC into the * Slave's label service routine. This routine will verify incoming * parameters, open the media device, and invoke "slave_label_medium" * to perform the actual label operation. */ bool_t abs_label_media_1_svc(char *extid, media_id_pt mip, job_pt jp, int *rcp, struct svc_req *clp) { int master_rc, master_code; dev_handle_t *dh = (dev_handle_t *)NULL; abs_label_t abs_label; char buf[512]; job_done_res_t jdone; char *datep; struct timeval now; memset(&jdone, 0, sizeof(job_done_res_t)); /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) goto label_error; /* * validate incoming parameters */ if (extid == (char *) NULL || strlen(extid) == 0){ *rcp = ABS_INVALID_MEDIA_ID; slave_log_error(ABS_FATAL,"label_media", "Received NULL extid from Master"); goto label_error; } if (mip == (media_id_pt) NULL){ *rcp = ABS_INVALID_MEDIA_ID; slave_log_error(ABS_FATAL, "label_media", "Received NULL internal id from Master"); goto label_error; } if (jp == (job_pt) NULL){ *rcp = ABS_INVALID_SPEC; slave_log_error(ABS_FATAL,"label_media", "Received NULL job from Master"); goto label_error; } /* * validate client's requested device type and host name * Ensure it's really me that is requested */ if (strcmp(jp->host, un.nodename)){ *rcp = ABS_NO_SERVER_SPEC; slave_log_error(ABS_ERROR,"label_media", "Received incorrect hostname from Master"); goto label_error; } if (strcmp(jp->device, device_name)){ *rcp = ABS_NO_DEVICE_SPEC; slave_log_error(ABS_FATAL,"label_media", "Received incorrect devicename from Master"); goto label_error; } /* * open the device */ while( (*rcp = SLAVE_OPEN(devp, &dh, device_name, O_RDWR, jp->jobid)) == ABS_NEEDS_MOUNT){ /* * Send mesasges to the master periodically to request a mount. * The master will annoy the user until he mounts a tape. * For single-cartridge tapes the open fails if there is not a tape * in the drive. */ *rcp = request_service(jp->jobid, ABS_TAPE_MOUNT_REQ, (tapeid_t *)NULL); } if (*rcp != 0){ /* * some other fatal error which we cannot handle. * Tell the master and quit */ sprintf(buf, "Cannot open device %s \n", device_name); slave_log_error(ABS_FATAL,"label_media",buf); goto label_error; } /* * Get the next media item; for single cartridge systems * This is essentially a no-op; for multi-cartridge we * expect the device to cyle around until it finds a * medium in one of its slots. If all slots are empty it will * request a mount from the master */ *rcp = SLAVE_NEXT_MEDIA(dh, extid, (media_id_pt) NULL, 0); if (*rcp){ sprintf(buf, "Cannot advance media on device %s \n", device_name); slave_log_error(ABS_FATAL,"label_media", buf); goto label_done; } /* * Rewind the tape */ *rcp = SLAVE_REWIND(dh); if (*rcp){ sprintf(buf, "device %s Rewind failure \n", device_name); slave_log_error(ABS_FATAL,"label_media", buf); goto label_done; } /* * Device is open and media is mounted, * Check for an already-existing label. If the tape * has a label, we will need to verify the label with * the master. */ *rcp = validate_label(dh, mip, ABS_NO_LABEL, &abs_label); if (*rcp == ABS_VALID_MEDIA){ /* * The medium appears to have a valid abs label. We * must verify the status of this medium with the master * before we overwrite it. */ master_rc = slave_validate(&abs_label.tapeid, jp->jobid, &master_code); if (master_rc == 0){ /* no transmission errors */ if (master_code != ABS_UNKNOWN_MEDIA){ /* * tape status is something other than unknown. * in this case we abort since the tape could * be valid, bad (media errors), or expired */ goto label_done; } } else{ /* unrecoverable transmission errors * since we have no knowledge of the medium's state, we * abort the operation */ *rcp = master_rc; goto label_done; } }else if (*rcp != 0){ /* * some other type of error occurred * either it's already labeled or a media/device error */ slave_log_error(ABS_ERROR,"abs_label_medium","can't read tape"); goto label_done; } /* * We have determined that this tape is ok to use * So let's label it */ *rcp = slave_label_medium(devp, dh, extid, mip); label_done: /* * Close the device - we are finished with the * device portion of this operation. * Now tell the master how the operation completed. * we'll need to get an rpc connection to the master first */ if (!online){ SLAVE_OFFLINE(dh); } SLAVE_CLOSE(dh); label_error: jdone.jdr_type = jdr_type_label; gettimeofday(&now); jdone.stats.date = now.tv_sec; /* * We have to make an actual RPC to the Master to inform * it that we are done with the job. The master only * queues requests with us; it does not wait for us to complete * our work as in a normal RPC */ *rcp = slave_notify_master(*rcp, jp->jobid, &jdone, 1); return(RPC_SUCCESS); } /* * Procedure: abs_abort_job_1_svc * * Description: placeholder for remote abort */ bool_t abs_abort_job_1_svc(tapehost_pt thp, job_pt jp, int *rcp, struct svc_req *clp) { /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) return(RPC_SUCCESS); *rcp = ABS_NOT_SUPPORTED; } /* * Procedure: abs_shutdown_slave_1_svc * * Parameters: rcp - address of return value from call * clp - address of client info * * Description: This function will cause the slave to * return from "svc_run" by instructing the rpc to * stop listening for requests. */ bool_t abs_shutdown_slave_1_svc(int *rcp, struct svc_req *clp) { char msgbuf[256]; /* * Validate the caller's credentails. We only accept calls from * our Master */ *rcp = SLAVE_CHECK_AUTH(clp); if (*rcp) return(RPC_SUCCESS); /* * Shutdown only works if the slave is not busy. * If we had threads, we could actually perform a remote shutdown * from this interface while the slave is busy dumping. */ *rcp = stop_listening(); /* Don't Accept any more RPC's */ if (*rcp){ /* failed - tell user */ sprintf(msgbuf," Failed to stop the RPC, error %d\n", *rcp); slave_log_error(ABS_ERROR, "abs_shutdown", msgbuf); return(RPC_SUCCESS); } sprintf(msgbuf,"Shutdown initiated by master"); slave_log_error(ABS_INFORMATIONAL, "abs_shutdown", msgbuf); return(RPC_SUCCESS); } /* * Procedure: absslave_1_freeresult * * Description: Required to interface with onc rpc. The rpc will * call this to free up any memory allocated for the results after * the results are delivered to the caller. We are not returning * any results through the slave service interfaces, so we don't * need to free up anything here. */ bool_t absslave_1_freeresult(transp, xdr_result, rp) SVCXPRT *transp; xdrproc_t xdr_result; caddr_t rp; { return(TRUE); } static int noauth=0; void set_noauth() { noauth = 1; } slave/slave_main.c100400 6031 145 24663 6240131026 13620 0ustar delgadooraweb#include #include #include /* getenv, exit */ #include /* for pmap_unset */ #include /* strcmp */ #include #include #include /* setsid */ #include #include #include #include #include /* rlimit */ #include #include #include #include #include #include #include #include "../master/abs_msg.h" #include "private.h" extern void sigterm_handler(int param); extern void sighup_handler(int param); extern char slave_princ[]; extern char master_princ[]; char usage[] = "slave -f "; /* * client handle to master process -used by all * slave service routines to deliver results or * status messages */ CLIENT *cl; /* * The following variables are actually defined in globals.c * */ extern char master_server[]; extern char abs_admin_dir[PATH_MAX]; extern char log_dir[PATH_MAX]; extern char device_name[PATH_MAX]; extern char device_type[10]; extern char config_file[PATH_MAX]; extern int online; char myhost[256]; struct utsname un; int dflag = 0; int mflag = 0; extern void absslave_1(struct svc_req *rqstp, register SVCXPRT *transp); extern void closedown(int sig); extern marshall_sockaddr(char *, int, struct sockaddr_in *, int ); #ifdef DEBUG #define RPC_SVC_FG #endif #define _RPCSVC_CLOSEDOWN 120 static void _msgout(char* msg) { (void) fprintf(stderr, "%s\n", msg); } server_thread() { pid_t pid; int i, rc, code; struct netbuf nbuf; char buf[32], *msgp; char mname[FMNAMESZ + 1]; struct netconfig *nconf = NULL; SVCXPRT *transp; slave_info_t slave; char addr_buf[512]; AUTH *auth; nbuf.buf = buf; nbuf.maxlen = 32; nbuf.len = 0; if (!ioctl(0, I_LOOK, mname) && (!strcmp(mname, "sockmod") || !strcmp(mname, "timod"))) { char *netid; int pmclose; openlog("master", LOG_PID, LOG_DAEMON); if ((netid = getenv("NLSPROVIDER")) == NULL) { /* started from inetd */ pmclose = 1; } else { if ((nconf = getnetconfigent(netid)) == NULL) _msgout("cannot get transport info"); pmclose = (t_getstate(0) != T_DATAXFER); } if (strcmp(mname, "sockmod") == 0) { if (ioctl(0, I_POP, 0) || ioctl(0, I_PUSH, "timod")) { _msgout("could not get the right module"); exit(1); } } if ((transp = svc_tli_create(0, nconf, NULL, 0, 0)) == NULL) { _msgout("cannot create server handle"); exit(1); } if (rpcb_getaddr(ABSSLAVE, ABSVERS, nconf, &nbuf, myhost) == TRUE){ fprintf(stderr,"Program already registered - exiting! \n"); exit(1); } if (nconf) freenetconfigent(nconf); /* svc_dg_enablecache(transp, 500) */ if (!svc_reg(transp, ABSSLAVE, ABSVERS, absslave_1, 0)) { _msgout("unable to register (ABSSLAVE, ABSVERS)."); exit(1); } if (pmclose) { (void) signal(SIGALRM, closedown); (void) alarm(_RPCSVC_CLOSEDOWN/2); } svc_run(); exit(1); /* NOTREACHED */ } uname(&un); if ((nconf = getnetconfigent("udp")) == NULL){ fprintf(stderr,"Cannot get transort information for udp!\n"); exit(1); } transp = svc_tli_create(RPC_ANYFD, nconf, (struct t_bind *)NULL, 0,0); if (transp == (SVCXPRT *)NULL) { _msgout("svc_tli_create for udp fails"); exit(1); } if (svc_reg(transp, ABSSLAVE, ABSVERS, absslave_1, 0) == FALSE) { _msgout("unable to create (ABSSLAVE, ABSVERS) for tcp."); exit(1); } /* Note - the return values for this call are opposite * of what the documentation states */ if (svc_dg_enablecache(transp, 50) == 0){ fprintf(stderr,"Unable to initialize duplicate request cache"); exit(1); } /* * Register the server's principal, instance and realm * with the rpc auth functions */ if (svc_kerb_reg(NULL, slave_princ, myhost, (char *) NULL, AUTH_KERB)){ fprintf(stderr,"svc_kerb_reg failed !\n"); exit(1); } #ifdef INTEGRITY /* * force use of integrity for this transport */ svc_control(transp, SVCSET_INTEGRITY, 0); freenetconfigent(nconf); #endif if ((nconf = getnetconfigent("tcp")) == NULL){ fprintf(stderr,"Cannot get transort information for tcp!\n"); exit(1); } transp = svc_tli_create(RPC_ANYFD, nconf, (struct t_bind *)NULL, 8192, 8192); if (transp == (SVCXPRT *)NULL) { _msgout("svc_tli_create for tcp fails"); exit(1); } if (svc_reg(transp, ABSSLAVE, ABSVERS, absslave_1, 0) == FALSE) { _msgout("unable to create (ABSSLAVE, ABSVERS) for tcp."); exit(1); } #ifdef INTEGRITY /* * force use of integrity for this transport */ svc_control(transp, SVCSET_INTEGRITY, 0); #endif freenetconfigent(nconf); /* * Send any leftover results back to the master. * This is the case where we had trouble sending our * results to the master and we've saved them to a * file */ recover_saved_jobs(master_server); /* * Now register the tcp interface with the Master so * it knows which port to contact us on */ cl = clnt_create(master_server, ABS_SLAVESERVICE, ABS_SLVVERS, "tcp"); if (cl == NULL){ clnt_pcreateerror(master_server); fprintf(stderr,"Can't create connection to master %s\n",master_server); exit(1); } /* * Use kerberos authentication with data integrity */ if (authkerb_create(master_princ, master_server, (char *) NULL, AUTH_KERB, &code, &auth, cl)){ fprintf(stderr,"authkerb_create fails code = %d\n", code); exit(1); } slave.hostname = myhost; slave.device = device_name; slave.s.type = sockaddr_type; slave.s.slave_addr_u.sa.sa_len = sizeof(struct sockaddr_in); slave.s.slave_addr_u.sa.sa_val = addr_buf; marshall_sockaddr(addr_buf, sizeof(struct sockaddr_in), (struct sockaddr_in *)transp->xp_ltaddr.buf, 1); rc = code = 0; code = slaveservice_register_device_1(&slave, NULL, &rc, cl); if (code ){ msgp = clnt_sperrno(code); slave_log_error(ABS_FATAL,"server_thread", msgp); exit(code); } if (rc){ fprintf(stderr,"failed to register with master %d\n",rc); exit(rc); } clnt_destroy(cl); set_slave_state(SLAVE_RUNNING); svc_run(); /* The only way we return from svc_run is if someone * calls the shutdown interface which will disable * the rpc listen */ _msgout("svc_run returned"); svc_unreg(ABSSLAVE, ABSVERS); slave_log_error(ABS_WARNING,"server", "Interfaces unregisterd"); slave_log_error(ABS_WARNING,"server", "Slave exiting"); exit(1); /* NOTREACHED */ } main(argc, argv) int argc; char *argv[]; { int retval, fflag=0; int *arg, i; char jobs_dir[] = "jobs"; int c, errflg=0; int bootstrap = 0; struct stat sb; extern char *optarg; extern int optind, opterr, optopt; while ((c = getopt(argc, argv, "f:n")) != EOF){ switch (c) { case 'f': strncpy(config_file, optarg, PATH_MAX); fflag++; break; case 'n': set_noauth(); break; case '?': errflg++; break; } } if (errflg){ fprintf(stderr,usage); exit(EINVAL); } if (fflag == 0){ fprintf(stderr,"Configuration file not specified - exiting!\n"); exit(1); } read_config_file(config_file, 0); if (strlen(device_name) == 0){ fprintf(stderr, "No device name specified - exiting\n"); exit(1); } if (strlen(device_type) == 0){ fprintf(stderr,"No device type specified - exiting\n"); exit(1); } if (set_devtype(device_type)){ fprintf(stderr,"Invalid device type %s\n", device_type); exit(EINVAL); } if (chdir(abs_admin_dir)){ fprintf(stderr,"Cannot chdir to %s\n", abs_admin_dir); exit(errno); } umask(007); /* * Create the various admin directories if necessary */ retval = stat(jobs_dir, &sb); if (retval && (errno == ENOENT)){ if (mkdir(jobs_dir, 0750)){ fprintf(stderr,"Cannot create directory - exiting! %s\n",jobs_dir); exit(errno); } }else if (retval != 0){ fprintf(stderr,"errno %d\n", retval); fprintf(stderr,"Cannot Access directory -exiting ! %s\n", jobs_dir); perror(jobs_dir); exit(errno); } retval = stat(log_dir, &sb); if (retval &&( errno == ENOENT)){ if (mkdir(log_dir, 0750)){ fprintf(stderr,"Cannot create directory %s- exiting! \n", log_dir); exit(errno); } }else if (retval != 0 ){ fprintf(stderr,"Cannot Access directory %s -exiting !\n", log_dir); perror(log_dir); exit(errno); } /* * If logs can't be initialized, then this * routine will exit */ initialize_slave_log(log_dir, device_name); retval = set_jobs_dir(jobs_dir); if (retval){ exit(retval); } uname(&un); strcpy(myhost, un.nodename); /* * Get a tgt so that we have credentials and can * request service tickets. This routine logs its * errors so we don't have to. */ if (get_slave_tgt()){ exit(1); } /* * set up handler for SIGTERM to allow * graceful termination */ retval = signal(SIGTERM, sigterm_handler); if (retval){ slave_log_error(ABS_FATAL, "main", "cant setup TERM signal handler -exiting"); exit(1); } retval = signal(SIGHUP, sighup_handler); if (retval){ slave_log_error(ABS_FATAL, "main", "cant setup HUP signal handler -exiting"); exit(1); } /* * Startup our RPC server business */ server_thread(); } slave/slave_utils.c100400 6031 145 124001 6240131026 14037 0ustar delgadooraweb#include #include #include #include #include "../master/abs_msg.h" #include "../master/os_defs.h" #include "private.h" #include "prototypes.h" extern int online; extern char master_server[256]; extern char slave_princ[]; extern char master_princ[]; int media_checkpoint(dev_handle_t *dh, job_pt jp, net_dumpset_t *dp, char *verfmode); int nodev(); void noname(dev_handle_t *dh, char **dpp); extern int devfs_next_file(), devfs_rewind(); extern int devfs_next_medium(), devfs_read(), devfs_write(), devfs_seek(); extern int devfs_open(), devfs_close(); extern int mtio_next_record(), mtio_rewind(), mtio_next_medium(); extern int mtio_read(), mtio_write(), mtio_seek(), mtio_open(), mtio_close(); extern int mtio_offline(); void mtio_devtype(); /* * This is the operations vector table for the vaiours device types. * each device type must supply its own set of routines for device * mangement. */ static struct dev_table __devices[ABS_MAX_DEVTYPES] = { {nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, noname}, {nodev, nodev, nodev, nodev, nodev, nodev, nodev, nodev, noname}, {mtio_next_record, mtio_rewind, mtio_next_medium, mtio_read, mtio_write, mtio_open, mtio_close, mtio_offline, mtio_devtype}, {0,0,0,0,0,0,0} }; struct dev_table *devp = &__devices[ABS_NO_DEV]; int nofs(), delete_job_info(int jobid); void *nofs_connect(); extern void *afs_connect(); extern int afs_dump(), afs_restore(), afs_disconnect(); /* * This is the operations vectory table for the various filesystem * types. In order for a filesystem to interact properly with an * ABS slave, it must support the operations listed in this table. */ static fs_ops fs_ops_array[MAX_FSTYPES] = { {nofs_connect, nofs, nofs, nofs}, {afs_connect, afs_dump, afs_restore, afs_disconnect}}; fs_ops *fsp; /* * Function: set_devtype * * Parameters: devtype - address of string containing device type * * Description: This function determines of "type" is a supported device * type and if so sets the global device operations vector pointer "devp" * to point to the appropriate set of operations from the __devices table. */ int set_devtype(char *type) { if (!strcmp(type, "fs")){ devp = &__devices[ABS_DEV_FS]; return(0); } if (!strcmp(type,"mt")){ devp = &__devices[ABS_DEV_MT]; return(0); } return(ABS_INVALID_SPEC); } /* * The following routine is a filler so that devp points to something * valid upon startup */ int nodev() { return(ABS_NO_DEVICE_SPEC); } void noname(dev_handle_t *dh, char **dpp) { *dpp = (char *) NULL; } /* * Dummy routines for filesystem types */ int nofs() { return(ABS_INVALID_FSTYPE); } void * nofs_connect() { return((void *) NULL); } /* * Function: get_fs_ops * * Parameters: type - pointer to string containing filesystem type * * Description: Determint if "type" represents a supported filesystem type * and if so return the address of the matching filesystems operations vector. */ fs_ops * get_fs_ops(char *type) { if (!strcmp(type, "AFS")) return(&fs_ops_array[AFS_OPS]); return((fs_ops *) NULL); } /* * Procedure: slave_label_medium * * Parameters: dtp - address of device operations vector * dh - address of device i/o specific info * eid - address of external medium label * mip - address of internal media id. * * Description: labels the medium with the id specified in "mip" * The label is written in network byte format for portability. */ int slave_label_medium(dev_table_t *dtp, dev_handle_t *dh, char *eid, media_id_pt mip) { abs_label_t label; struct timeval tv; int rc; long bytes_requested, bytes_written; memset(&label, 0, sizeof(label)); label.magic = ABS_LABEL_MAGIC; label.abs_version = ABSVERS; memcpy(&label.tapeid, mip, sizeof(media_id_t)); gettimeofday(&tv); label.label_created = tv.tv_sec; rc = SLAVE_REWIND(dh); if (rc) return(rc); /* * Write the label to the device */ rc = write_label(dh, &label); if (rc) return(rc); /* * TBD -Now Read it back and verify that this is the * same as what we wrote */ rc = SLAVE_REWIND(dh); if (rc) return(rc); } /* * Function: read_label * * Parameters: dh - address of device info for medium * labelp - addres of area to store label info * * Modifies: labelp * * Description: read_label attempts to read the abs label from * the medium associated with dh. The function will convert the * label which is stored in network byte order to host byte order. * This function assumes that the device is set to the beginning of * the medium. */ int read_label(dev_handle_t *dh, abs_label_t *labelp) { int bytes, code; char buffer[ABS_REC_SIZE]; code = SLAVE_REWIND(dh); if (code) return(code); bytes = SLAVE_READ(dh, buffer, ABS_REC_SIZE, &code); if (bytes != ABS_REC_SIZE){ return(code); } memcpy(labelp, buffer, sizeof(abs_label_t)); labelp->magic = ntohl(labelp->magic); labelp->abs_version = ntohl(labelp->abs_version); labelp->tapeid.internal1 = ntohl(labelp->tapeid.internal1); labelp->tapeid.internal2 = ntohl(labelp->tapeid.internal2); labelp->label_created = ntohl(labelp->label_created); labelp->block_size = ntohl(labelp->block_size); labelp->dump_type = ntohl(labelp->dump_type); labelp->level = ntohl(labelp->level); labelp->uses = ntohl(labelp->uses); labelp->tape_created = ntohl(labelp->tape_created); return(0); } /* * Function: write_label * * Parameters: dh - address of device info for medium * labelp - addres of area to store label info * * Description: write_label writes the information in "labelp" to * the medium associated with dh. The label information will be written * in network byte order for portability. This function assumes that * the device is set to beginning of medium. */ int write_label(dev_handle_t *dh, abs_label_t *labelp) { int bytes, code; char buffer[ABS_REC_SIZE]; char *devtype; memset(buffer, 0, ABS_REC_SIZE); labelp->magic = htonl(labelp->magic); labelp->abs_version = htonl(labelp->abs_version); labelp->tapeid.internal1 = htonl(labelp->tapeid.internal1); labelp->tapeid.internal2 = htonl(labelp->tapeid.internal2); labelp->label_created = htonl(labelp->label_created); labelp->block_size = htonl(labelp->block_size); labelp->dump_type = htonl(labelp->dump_type); labelp->level = htonl(labelp->level); labelp->uses = htonl(labelp->uses); labelp->tape_created = htonl(labelp->tape_created); SLAVE_DEVICE_TYPE(dh, &devtype); if (devtype != (char *) NULL){ strncpy(labelp->device_type, devtype, ABS_MAX_DEVICE); } memcpy(buffer, labelp, sizeof(abs_label_t)); bytes = SLAVE_WRITE(dh, buffer, ABS_REC_SIZE, &code); if (bytes != ABS_REC_SIZE){ return(code); } return(0); } /* * Function: validate_label * * Parameters: dh - address of device info for medium * mip - address of internal media id * validate_type - type of validation requested. * labelp - address to store label information. * * Description: This function reads a label from the specified medium * and determines if the label matches the caller's expectatations. * The caller's expectations are defined as follows * ABS_NO_LABEL - expect the medium has no label * ABS_VALID_LABEL - expects the medium has an abs label with * valid abs magic number. * ABS_VALID_LABELID - expects medium has an abs label with valid * abs magic number and internal media id which * matches "mip" * Returns 0 if tape label matches caller's expectations, non-zero otherwise. */ int validate_label(dev_handle_t *dh, media_id_pt mip, int validate_type, abs_label_t *labelp) { int code, bytes; dev_table_t *dtp = dh->dev_ops; if ((code = read_label(dh, labelp))){ if ((code == ABS_EOM_DETECTED || code == ABS_EOF_DETECTED || code == ABS_CANT_ENCODE) && (validate_type == ABS_NO_LABEL)){ /* * This is a blank tape */ return(0); } if (code == ABS_EOM_DETECTED || ABS_EOF_DETECTED) /* blank tape */ return(ABS_BLANK_MEDIUM); return(code); } /* * We've read one label's worth of data, let's see * if we have a valid label */ switch(validate_type){ case ABS_NO_LABEL: if (labelp->magic != ABS_LABEL_MAGIC) return(0); return(ABS_VALID_MEDIA); case ABS_VALID_LABEL: if (labelp->magic != ABS_LABEL_MAGIC) return(ABS_INVALID_MAGIC); return(0); case ABS_VALID_LABELID: if (labelp->magic != ABS_LABEL_MAGIC) return(ABS_INVALID_MAGIC); if (labelp->tapeid.internal1 != mip->internal1){ return(ABS_INVALID_MEDIA_ID); } if (labelp->tapeid.internal1 != mip->internal1){ return(ABS_INVALID_MEDIA_ID); } return(0); default: return(ABS_INVALID_SPEC); } } /* * Procedure: write_volume_footer * * Parameters: dh - address of device-specific information * vp - address of volume information * status - volume's dump status code. * * Description: write_volume_footer writes a volume footer for the * volume "vp" to the device associated with "dh". It sets the footer * "status" field to ABS_VS_VALID if status is 0, and ABS_VS_INVALID * otherwise. It copies the size and volumeid information from "vp" * Footer is written in network byte order. */ int write_volume_footer(dev_handle_t *dh, net_volume_pt vp, int status) { abs_volfooter_t vf; int bytes, code; vf.magic = ABS_VOLFOOTER_MAGIC; vf.absvolid = vp->v_id; LLGET(vp->v_size, vf.size_high, vf.size_low); if (status) vf.status = ABS_VS_INVALID; else vf.status = ABS_VS_VALID; memcpy(dh->buf, &vf, sizeof(vf)); bytes = SLAVE_WRITE(dh, dh->buf, ABS_REC_SIZE, &code); if (bytes != ABS_REC_SIZE){ return(code); } return(0); } /* * Procedure: read_volume_footer * * Parameters: dh - address of device speicific information * vf - address of area to copy footer data * * Modifies - vf * * Description: This function attempts to read a volume footer * from the device associated with "dh" and copies the information * into the area referenced by "vf". */ int read_volume_footer(dev_handle_t *dh, abs_volfooter_pt vf) { int bytes, code; bytes = SLAVE_READ(dh, dh->buf, ABS_REC_SIZE, &code); if (bytes != ABS_REC_SIZE){ return(code); } memcpy(vf, dh->buf, sizeof(abs_volfooter_t)); if (vf->magic != ABS_VOLFOOTER_MAGIC) return(ABS_INVALID_MAGIC); return(0); } /* * Procedure: find_control_rec * * Parameters: dh - address of device-specific information * count - advance forward or backward * * Description: This function move the medium to the next control * record (header or footer) on the medium by invoking the * SLAVE_READ function using a 512 byte record size. Note * that a read request for an incorrect record size (e.g. data record) * will advance us past that record to the interrecord gap preceeding * the next record. * * We move forward if the count is positive and backward if count * is negative. The medium is left positioned at the start of * the control record. */ int find_control_rec(dev_handle_t *dh, int count, int rec_type) { int bytes, code, magic; abs_volheader_t *vhp; abs_volfooter_t *vfp; vhp =(abs_volheader_t *) dh->buf; vfp = (abs_volfooter_t *)dh->buf; code = 0; if ( count < 0){ code = SLAVE_NEXT_RECORD(dh, -1); if (code) return(code); } while (1){ if ( (bytes = SLAVE_READ(dh, dh->buf, ABS_REC_SIZE, &code)) != ABS_REC_SIZE){ if (code == ABS_INVALID_RECSIZE){ /* * Record size is not the same as the control record size * so this record can't possibly be a volume header or footer */ if ( count < 0){ /* * If we are reversing, then we must backup over the record * we just read plus another record to reach the record * just before the one just read. */ code = SLAVE_NEXT_RECORD(dh, -2); if (code) return(code); } continue; }else if (code != 0){ /* some other error */ break; } } memcpy(&magic, dh->buf, sizeof(int)); magic = ntohl(magic); if (magic == rec_type){ code = SLAVE_NEXT_RECORD(dh, -1); break; } } if (code) code = convert_system_error(code); return(code); } destroy_handle( CLIENT * clnt_handle) { if (clnt_handle){ if (clnt_handle->cl_auth) auth_destroy(clnt_handle->cl_auth); clnt_destroy(clnt_handle); } } CLIENT * connect_to_master(char *protseq) { CLIENT *clnt_handle = (CLIENT *) NULL; struct timeval cv; AUTH *authp = (AUTH *) NULL; int interval = 5; int rc; do{ destroy_handle(clnt_handle); authp = (AUTH *) NULL; clnt_handle = (CLIENT *) NULL; while ((clnt_handle = clnt_create(master_server, ABS_SLAVESERVICE, ABS_SLVVERS, protseq)) == (CLIENT *) NULL){ /* * The master has disappeared completely! */ clnt_pcreateerror(master_server); slave_log_error(ABS_FATAL, "connect_to_master", "Cannot create connection to Master"); sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } /* * got a handle to the master now add the authentication * info to it */ }while(get_slave_tgt()); authkerb_create(master_princ, master_server, 0, AUTH_KERB, &rc, &authp, clnt_handle); /* * Bump up the patience factor; the default timeout value of 15 * seconds is too low */ cv.tv_sec = 180; cv.tv_usec = 0; clnt_control(clnt_handle, CLSET_TIMEOUT, (char *) &cv); return(clnt_handle); } /* * Procedure: slave_notify_master * * Parameters: status - integer containing job status code to send to master * jobid - integer representing job id for executed job * dp - address of dumpset/volume information for routines * such as dump/restore/scan to send to master * * Description: This procedure creates an RPC connection to the Master * and attempts to send the results to the master via the slaveservice_job_done * interface. The procedure will execute exponential retry on RPC failures * It keeps retrying until the data is delivered successfully to the master. */ int slave_notify_master(int status, int jobid, job_done_res_pt jdp, int save) { CLIENT *clnt_handle; int code, rc, interval = ABS_MIN_RETRY, retries; char buf[ABS_REC_SIZE], *msgp; retries = 0; /* * Save the job info to disk just in case */ if (save){ if (jdp->jdr_type == jdr_type_dumpset) code = save_job_info(jobid, status, jdp->jdr_dumpset, DUMPSET_TYPE); else if (jdp->jdr_type == jdr_type_volume){ code = save_job_info(jobid, status, jdp->jdr_volume, VOLUME_TYPE); } } while (1){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = code = 0; rc = slaveservice_job_done_1(status, jobid, jdp, &code, clnt_handle); if (rc == 0){ /* check for transport errors */ if (code == 0) /* check for call errors */ break; else{ if (ABS_MIN_ERR < code < ABS_MAX_ERR){ /* * The master had some trouble with our results. * this is fatal, however we continue to retry. */ sprintf(buf,"slaveservice_job_done_1: Errors from Master for job %d: %s\n", jobid, get_abs_msg(code)); slave_log_error(ABS_FATAL, "slave_notify_master", buf); }else{ sprintf(buf,"slaveservice_job_done_1: RPC Int Errors from Master %d\n", code); slave_log_error(ABS_ERROR, "slave_notify_master", buf); } } }else{ /* transport errors */ msgp = clnt_sperrno(rc); if (rc != RPC_TIMEDOUT || rc != RPC_INTR || rc != RPC_TLIERROR || rc != RPC_FAILED || rc != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, "slave_notify_master", msgp); } slave_log_error(ABS_ERROR, "slave_notify_master", msgp); sprintf(buf,"slaveservice_job_done_1: RPC Errors from Master %d\n",rc); } /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); /* * Exponential Backoff */ sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } /* end while(1) */ /* * We are finished calling the master - destroy the * the connection */ destroy_handle(clnt_handle); delete_job_info(jobid); return(code); } /* * Procedure: slave_validate * * Parameters: mip - address of media id to validate * jobid - integer representing job id for executed job * rcp - address of integer to contain media status upon return * * Description: This procedure creates an RPC connection to the Master * and attempts to request validation of the specified medium with the master * via the slaveservice_validate_media interface. The procedure will execute exponential * retry on RPC failures */ int slave_validate(media_id_pt mip, int jobid, int *rcp) { CLIENT *clnt_handle; int code, interval = ABS_MIN_RETRY; char buf[ABS_REC_SIZE]; while (1){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ code = slaveservice_validate_media_1(mip, jobid, rcp ,clnt_handle); if (code == 0){ break; } sprintf(buf,"slaveservice_validate_media: RPC Errors from Master %d\n", code); slave_log_error(ABS_FATAL, "slave_validate", buf); /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); /* * Exponential Backoff */ sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } /* end while(1) */ /* * We are finished calling the master - destroy the * the connection */ destroy_handle(clnt_handle); return(0); } /* * Function: request_service * * Parameters: devname - pointer to string containing name of device * jobid - integer identifiying job which requires mount * * Description: This function issues a "job_attention" call to the master * to request the initiator to mount the media on "device". * */ int request_service(int jobid, int request_type, tapeid_t *mp) { CLIENT *clnt_handle; int code, interval = ABS_MIN_RETRY; int rc; job_attn_t ja; char buf[512], *msgp; ja.jobid = jobid; ja.cond = request_type; if (mp == (tapeid_t *)NULL) memset(&ja.media_id, 0, sizeof(tapeid_t)); else memcpy(&ja.media_id, mp, sizeof(tapeid_t)); if (request_type == ABS_TAPE_MOUNT_REQ){ slave_log_error(ABS_ERROR, "request_service", "requesting media mount from master"); } else if (request_type == ABS_RO_DEVICE){ slave_log_error(ABS_ERROR, "request_service", "Device not writeable!\n"); } while (1){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = code = 0; rc = slaveservice_job_attention_1(&ja, &code, clnt_handle); if (rc == 0){ /* check for transport errors */ if (code != 0){ /* check for call errors */ sprintf(buf, "slaveservice_job_attention: RPC Errors from Master %d\n", code); slave_log_error(ABS_ERROR, "request_mount", buf); } break; }else{ msgp = clnt_sperrno(rc); if (rc != RPC_TIMEDOUT || rc != RPC_INTR || rc != RPC_TLIERROR || rc != RPC_FAILED || rc != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, "request_mount", msgp); code = rc; break; } slave_log_error(ABS_ERROR, "request_mount", msgp); sprintf(buf,"slaveservice_job_done_1: RPC Errors from Master %d\n",rc); } slave_log_error(ABS_ERROR, "request_mount", buf); /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } destroy_handle(clnt_handle); return(code); } /* * Function: read_volume_header * * Parameters: dh - address of device information. * vhp - address of volume header * * Description: read_volume_header reads data from the device associated * with dh and places it in the area pointed to by vhp. The header * on the medium is written in network-byte-order and read_volume_header * will convert the data to host byte order. */ int read_volume_header(dev_handle_t *dh, abs_volheader_pt vhp) { int bytes, code; code = 0; bytes = SLAVE_READ(dh, dh->buf, ABS_REC_SIZE, &code); if (code) return(code); memcpy(vhp, dh->buf, sizeof(abs_volheader_t)); vhp->magic = ntohl(vhp->magic); vhp->absvolid_low = ntohl(vhp->absvolid_low); vhp->absvolid_high = ntohl(vhp->absvolid_high); vhp->size_low = ntohl(vhp->size_low); vhp->size_high = ntohl(vhp->size_high); vhp->fs_volid1 = ntohl(vhp->fs_volid1); vhp->fs_volid2 = ntohl(vhp->fs_volid2); if (vhp->magic != ABS_VOLHEADER_MAGIC){ return(ABS_INVALID_MAGIC); } return(0); } /* * Function: write_volume_header * * Parameters: dh - pointer to device information containing media state * vhp - address of media volume header to be written * * Description - Write a volume header to the medea asociated with * dh in machine independent format. * */ int write_volume_header(dev_handle_t *dh, abs_volheader_pt vhp) { int code, bytes, count; memset(dh->buf, 0, ABS_REC_SIZE); vhp->magic = htonl(vhp->magic); vhp->absvolid_low = htonl(vhp->absvolid_low); vhp->absvolid_high = htonl(vhp->absvolid_high); vhp->size_low = htonl(vhp->size_low); vhp->size_high = htonl(vhp->size_high); vhp->fs_volid1 = htonl(vhp->fs_volid1); vhp->fs_volid2 = htonl(vhp->fs_volid2); memcpy(dh->buf, vhp, sizeof(abs_volheader_t)); /* * write the volume header */ count = SLAVE_WRITE(dh, dh->buf, ABS_REC_SIZE, &code); if (count != ABS_REC_SIZE ){ return(code); } return(0); } int convert_system_error(int code) { switch(code){ case 0: return(0); case EIO: return(ABS_MEDIA_ERROR); case EAGAIN: return(ABS_DEVICE_BUSY); default: return(ABS_OS_ERROR); } } /* * Function: netvol_to_volheader * * Parameters: vp - address of netvol structure to be converted * vh - address of vol header * Description: convert a net_volume_t structure to a tape volume * header structure */ void netvol_to_volheader(net_volume_t *vp, abs_volheader_t *vh) { vh->magic = ABS_VOLHEADER_MAGIC; vh->absvolid_high = 0; vh->absvolid_low = vp->v_id; LLGET(vp->v_size, vh->size_high, vh->size_low); strcpy(vh->name, vp->v_name); strcpy(vh->server, vp->v_server); strcpy(vh->device, vp->v_part); strcpy(vh->fstype, vp->v_fstype); } void suicide(char *msg) { fprintf(stderr,msg); exit(1); } /* * Procedure: send status * * parameters:jobid - integer identifying job * job_status_pt - address of job status information * job_stat - status code for job. * * Description: Send a status update to the master informing it * of which volume we are currently dumping. This function * requests a UDP connection with "no-wait" mode since we don't * care if the message actually arrives. * * It can return * 0 - success * ABS_JOB_CANCELED - A user has requested that the job be canceled. * other non-zero - transmission errors */ int send_status(int jobid, job_status_pt job_stat) { CLIENT *clnt_handle = (CLIENT *) NULL; AUTH *authp = (AUTH *) NULL; struct timeval cv; char buf[ABS_REC_SIZE], *msgp; int code, rpc_code; strcpy(buf, master_server); clnt_handle = clnt_create(buf, ABS_SLAVESERVICE, ABS_SLVVERS, "tcp"); if (clnt_handle == (CLIENT *) NULL){ slave_log_error(ABS_FATAL, "send_status", "Cannot create connection to Master"); return(ABS_COMM_FAILURE); } if (get_slave_tgt()){ destroy_handle(clnt_handle); return(ABS_AUTH_ERROR); } code = 0; authkerb_create(master_princ, master_server, 0, AUTH_KERB, &code, &authp, clnt_handle); if (code){ slave_log_error(ABS_WARNING, "send_status", "Failed to setup RPC auth information"); destroy_handle(clnt_handle); return(ABS_AUTH_ERROR); } /* */ /* * place the status information in "job_stat" and * send it off to the master */ code = 0; rpc_code = slaveservice_job_status_1(job_stat, jobid, &code, clnt_handle); if (rpc_code){ msgp = clnt_sperrno(rpc_code); slave_log_error(ABS_ERROR,"send_status", msgp); } destroy_handle(clnt_handle); return(code); } /* * Procedure: handle_eom * * Parameters: dh - pointer to device specific info * jp - pointer to job information. * info - pointer to label info for tape which is at eom * verfmode - type of tape verification to use * * Description: handle_eom will rewind the tape which is at eom * and then request a media mount for a new media from the master. * handle_eom, upon detecting a tape in the drive, will attempt to * read and validate the tape label to ensure that the state * of the tape is "FREE". handle_eom will keep asking for a new * tape if the tape which is mounted to satisfy the eom condition * has a label which is not readable or writeable due to media * errors. */ int handle_eom(dev_handle_t *dh, job_pt jp, abs_label_t *label, net_dumpset_t *dp, char *verfmode) { int code, sequence, did_checkpoint; char buf[256]; media_t *tmp, *mp; abs_label_t old; sequence = label->sequence + 1; code = ABS_EOM_DETECTED; did_checkpoint = 0; tmp = (media_t *) NULL; memcpy(&old, label, sizeof(abs_label_t)); while( code == ABS_MEDIA_ERROR || code == ABS_EOM_DETECTED){ do { /* * The inner loop tries hard to get a tape mounted. * * Send the info for this tape back to the master * If we fail, then we keep the tape/vol info around * and it will be sent with the next tape checkpoint * or when the job completes. */ if (did_checkpoint == 0) { code = media_checkpoint(dh, jp, dp, verfmode); if (code == ABS_JOB_CANCELED) return(ABS_JOB_CANCELED); if (code == 0){ did_checkpoint = 1; } }else{ code = SLAVE_REWIND(dh); if (code){ return(code); } SLAVE_CLOSE_PARTIAL(dh); } /* * Keep asking for a tape mount until the operator * mounts something we can use */ code = request_service(jp->jobid, ABS_TAPE_OVERRUN, NULL); if (code){ /* * Something really bad happened and we couldn't get the * tape mount request over to the master. */ sprintf(buf, "Request for media mount failed code = %d\n",code); slave_log_error(ABS_ERROR, "handle_eom", buf); return(code); } /* * Give the guy time to mount a new tape after we ask */ sleep(180); /* * The request is sent, so try to see if there is * something we can use in the drive. */ code = SLAVE_OPEN(dh->dev_ops, &dh, dh->devname, O_RDWR, jp->jobid); if (code) continue; /* * Now try to find a tape with a label which is * marked as FREE in the master's database */ code = cycle_through_tapes(dh, jp->jobid, (char *)NULL, (media_id_pt) NULL, ABS_FREE_MEDIA); }while(code != 0 && code != ABS_BLANK_MEDIUM); if (code == ABS_BLANK_MEDIUM){ code = label_tape_for_dump(dh, jp->jobid); if (code) continue; } /* * We now have a tape which we are able to use so * rewrite the dynamic portion of the label */ code = SLAVE_REWIND(dh); if (code){ continue; } if ((code = read_label(dh, label))){ continue; } if (!memcmp(&label->tapeid, &old.tapeid, sizeof(media_id))){ /* * The old tape is still in the drive; We need to * check this separately since it's possible that * we were unable to checkpoint and the Master's database * doesn't have any info about the tapes we used. */ code = ABS_NEEDS_MOUNT; continue; } label->block_size = dh->bufsize; label->level = old.level; label->uses++; label->sequence = sequence; label->tape_created = old.tape_created; strncpy(label->cell, old.cell, ABS_MAX_DOMAIN); strncpy(label->dumpset, old.dumpset, ABS_MAX_DNAME); /* * Write the new label to the medium */ code = SLAVE_REWIND(dh); if (code){ continue; } if ((code = write_label(dh, label))){ continue; } } /* end of big loop */ /* * Copy the internal id of the new media to the * tapeset record */ if (code == 0){ /* * if we failed to checkpoint, then we need to allocate * a new tapeset member; otherwise we just copy the * new id into the old media_t area. */ if (!(did_checkpoint)){ tmp = (media_t *) malloc(sizeof(media_t)); if (tmp == (media_t *) NULL){ return(ABS_NO_MEM); } memset(tmp, 0, sizeof(media_t)); tmp->next = dp->tape_sets->tapes; dp->tape_sets->tapes = tmp; } memcpy(&dp->tape_sets->tapes->internal, &label->tapeid, sizeof(media_id_t)); dp->tape_sets->tapes->log_tape = 1; } return(code); } /* * Procedure: slave_scan_results * * Parameters: status - integer containing job status code to send to master * jobid - integer representing job id for executed job * tocp - address of table of contents info to send * * Description: This procedure creates an RPC connection to the Master * and attempts to send the results to the master via the abs_toc_results * interface. The procedure will execute exponential retry on RPC failures */ int slave_scan_results(int status, int jobid, toc_res_pt tocp) { CLIENT *clnt_handle = (CLIENT *) NULL; int code, rc, interval = ABS_MIN_RETRY, retries, again; char buf[ABS_REC_SIZE], *msgp; /* * Save the job info to disk just in case */ code = save_job_info(jobid, status, tocp, TOC_TYPE); retries = 0; again = 1; do{ if (retries){ destroy_handle(clnt_handle); /* * Exponential Backoff */ sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = code = 0; rc = slaveservice_scan_results_1(jobid, tocp, &code, clnt_handle); again = check_call_completion(rc, code, "slave_scan_results"); retries++; }while(again == ABS_COMM_FAILURE); /* end while(1) */ /* * We are finished calling the master - destroy the * the connection. We arrive here because the call either * completed successfully or there is an unrecoverable error * which we will not retry at this time. */ destroy_handle(clnt_handle); if (again == 0) delete_job_info(jobid); return(code); } int check_call_completion(int rpc_code, int call_code, char *routine) { char buf[1024]; char *msgp; if (rpc_code == 0){ /* check for transport errors */ if (call_code == 0) /* check for call errors */ return(0); sprintf(buf,"Errors from Master Interface %d\n", call_code); slave_log_error(ABS_ERROR,routine, buf); return(call_code); }else{ msgp = clnt_sperrno(rpc_code); if (rpc_code != RPC_TIMEDOUT || rpc_code != RPC_INTR || rpc_code != RPC_TLIERROR || rpc_code != RPC_FAILED || rpc_code != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, routine, msgp); return(-1); } slave_log_error(ABS_ERROR, routine, msgp); sprintf(buf,"slaveservice_job_done_1: RPC Errors from Master %d\n",rpc_code); return(ABS_COMM_FAILURE); } } int request_internal_label(int jobid, media_id_t *mip) { CLIENT *clnt_handle; int interval = ABS_MIN_RETRY; int rc, code; internal_label_res_t res; job_attn_t ja; char buf[512], *msgp; code = 0; while (1){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = 0; rc = slaveservice_gen_label_1(jobid, &res, clnt_handle); if (rc == 0){ /* check for transport errors */ code = res.code; break; }else{ msgp = clnt_sperrno(rc); if (rc != RPC_TIMEDOUT || rc != RPC_INTR || rc != RPC_TLIERROR || rc != RPC_FAILED || rc != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, "request_internal_label", msgp); code = rc; break; } slave_log_error(ABS_ERROR, "request_internal_label", msgp); sprintf(buf,"slaveservice_gen_label_1: RPC Errors from Master %d\n",rc); } slave_log_error(ABS_ERROR, "request_mount", buf); /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } destroy_handle(clnt_handle); if (code == 0){ memcpy(mip, &res.internal_label_res_u.value, sizeof( media_id_t)); } return(code); } /* * Procedure: media_checkpoint * * Parameters: jp - address of job information for this job * dp - address of dumpset * * Description - this function attempts to send the volume/tape * information to the master as part of the media checkpoint. * It tries a maximum of 3 times. The volume/tape information * is deleted if the data was sent successfully. * * Modifies: dp->tape_sets->tapes */ int media_checkpoint(dev_handle_t *dh, job_pt jp, net_dumpset_t *dp, char *verfmode) { CLIENT *clnt_handle; int code, interval = ABS_MIN_RETRY; int rc, retries; job_done_res_t jd; char buf[512], *msgp; media_id_t *mid; media_t *mp; /* * Perform media verification */ rc = perform_media_verification(dh, dp, verfmode); SLAVE_REWIND(dh); SLAVE_CLOSE_PARTIAL(dh); if (!online){ SLAVE_OFFLINE(dh); } /* * setup the results structure */ jd.jdr_type = jdr_type_dumpset; jd.jdr_dumpset = dp; retries = 0; while (retries < 3){ clnt_handle = connect_to_master("tcp"); /* * We have a connection, now make the call */ rc = code = 0; rc = slaveservice_dump_checkpoint_1(jp->jobid, &jd, &code, clnt_handle); if (rc == 0){ /* check for transport errors */ if (code == 0) /* check for call errors */ break; else{ if (ABS_MIN_ERR < code < ABS_MAX_ERR){ /* * The master had some trouble with our results. * this is fatal and we won't retry. */ sprintf(buf,"slaveservice_dump_checkpoint_1: Errors from Master for job %d: %s\n", jp->jobid, get_abs_msg(code)); slave_log_error(ABS_FATAL, "slave_notify_master", buf); }else{ sprintf(buf,"slaveservice_dump_checkpoint_1: RPC Int Errors from Master %d\n", code); slave_log_error(ABS_ERROR, "slave_notify_master", buf); } break; } }else{ /* transport errors */ msgp = clnt_sperrno(rc); if (rc != RPC_TIMEDOUT || rc != RPC_INTR || rc != RPC_TLIERROR || rc != RPC_FAILED || rc != RPC_PROGNOTREGISTERED){ /* codes other than the above are things like * protocol version mismatch and other things * which indicate possible system configuration * problems. There isn't any point in retrying * these! */ slave_log_error(ABS_FATAL, "slave_notify_master", msgp); break; } slave_log_error(ABS_ERROR, "slave_notify_master", msgp); sprintf(buf,"slaveservice_dump_checkpoint_1: RPC Errors from Master %d\n",rc); } /* * Call failed because of a connection problem. * Destroy the connection. We must try to get a new * connection since if the Master is restarted, it may * be at a different network port. */ destroy_handle(clnt_handle); clnt_handle = (CLIENT *) NULL; /* * Exponential Backoff */ sleep(interval); if (interval < ABS_MAX_RETRY) interval *= 2; } /* end while(1) */ /* * We are finished calling the master - destroy the * the connection */ if (clnt_handle) destroy_handle(clnt_handle); /* * success - we can delete the media information for * the data we just sent */ if (code == 0){ for (mp = dp->tape_sets->tapes; mp != (media_pt) NULL; mp = mp->next){ if (mp->volumes){ abs_free_netvol(mp->volumes); mp->volumes = (net_volume_t *) NULL; } } /* * Free up any extra tape structures, keeping * only one to be reused. */ if (dp->tape_sets->tapes->next){ abs_free_media(dp->tape_sets->tapes->next); mp->next = (media_t *) NULL; } } return(code); } slave/slave_verify.c100444 6031 145 13075 6240131026 14203 0ustar delgadooraweb#include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" /* * Procedure: slave_vol_check * * Parameters: dh - address of device information * fileno - which volume we're checking * * Description: This function reads the volume header, spaces * over the data which follows and reads the volume footer. * It returns 0 if data was successfully read; non-zero otherwise. */ int slave_vol_check(dev_handle_t *dh, int fileno) { abs_volheader_t vh; abs_volfooter_t vf; int code; char buf[256]; code = read_volume_header(dh, &vh); if (code){ sprintf(buf,"Error reading header for volume, file number %d: %s\n", fileno, get_abs_msg(code)); slave_log_error(ABS_ERROR, "slave_vol_check", buf); return(code); } /* * Skip over data and read footer */ code = NEXT_VOLFOOTER(dh); if (code){ sprintf(buf,"Error spacing to footer for volume %s, file number %d: %s\n", vh.name, fileno, get_abs_msg(code)); slave_log_error(ABS_ERROR, "slave_vol_check", buf); return(code); } code = read_volume_footer(dh, &vf); if (code){ sprintf(buf,"Error reading footer for volume %s, file number %d: %s\n", vh.name, fileno, get_abs_msg(code)); slave_log_error(ABS_ERROR, "slave_volcheck", buf); return(code); } return(code); } /* * Function: long_compare * * Parameters: i - value 1 for comparison * j - value 2 for compairson * * Description: This comparison function is provided for use with * the "qsort" C library routine to compare two long values */ static int long_compare(long *i, long *j) { return(*i - *j); } /* * Procedure: generate_random_positions * * Parameters: positions - array of longs to store positions * count - number of slots in "positions" array. * max - maximum number of volumes on tape * * Description: generate_random_positions uses the "lrand48" * function to generate random numbers. We then take * random-value mod "max" to get a number which is between * 0 and "max". We call qsort to order the positions in * ascending order. * * Modifies - positions; this array will be filled in with * random numbers. */ int generate_random_positions(unsigned long *positions, int count, int max) { unsigned short xi[3]; /* for the random number generator */ double rvalue; unsigned long rnum; int i; for (i=0; i< count; i++){ rnum = (long) lrand48(); positions[i] = rnum % max; } qsort(positions, count, sizeof(long), long_compare); } /* * Procedure: slave_quick_verification * * Parameters: dh - address of device information * dp - address of dumpset information * * Description: * verify a few random headers and footers on the tape * We verify about 10% of the volheader/footer pairs on the tape. * Verification consists of reading the header, footer structures * and nothing more. */ int slave_quick_verification(dev_handle_t *dh, net_dumpset_t *dp) { unsigned long *positions; /* array of random tape positions */ int i, fileno; int nvols, code; char buf[256]; sprintf(buf,"Performing quick verification for dumpset %s\n", dp->d_name); slave_log_error(ABS_INFORMATIONAL, "slave_quick_verification", buf); nvols = (int)((dp->nvolumes+9)/10 ); if (nvols == 0) return(0); /* * Generate nvols worth of random numbers representing * which volumes we're going to check out. */ positions = (unsigned long *) memalign(sizeof(long), nvols*sizeof(long)); generate_random_positions(positions, nvols, dp->nvolumes); for (i=0, fileno=0; i< nvols; i++){ if (fileno > positions[i]){ /* * This is the rare case where consecutive randomly * generated positions might be the same */ continue; } while(fileno < positions[i]){ code = NEXT_VOLHEADER(dh); if (code){ free(positions); return(code); } fileno++; } sprintf(buf,"Checking volume at position %d\n", fileno); slave_log_error(ABS_INFORMATIONAL, "slave_quick_verification", buf); code = slave_vol_check(dh, fileno); if (code){ break; } fileno++; } /* * It is possible that the last volume on this tape did not * fit, and in this case there may not be a footer */ if (code == ABS_EOM_DETECTED || code == ABS_EOF_DETECTED && (fileno >= dp->nvolumes && dp->dumpstats.ntapes > 1)){ code = 0; } free(positions); return(code); } /* * Procedure: slave_full_verification * * Parameters: dh - address of device information * dp - address of dumpset information * * Description: * verify a all headers and footers on the tape * Verification consists of reading the header, footer structures * and nothing more. */ int slave_full_verification(dev_handle_t *dh, net_dumpset_t *dp) { int count, code; char buf[256]; sprintf(buf,"Performing full verification for dumpset %s\n", dp->d_name); slave_log_error(ABS_INFORMATIONAL, "slave_full_verification", buf); count=0; while ((code = slave_vol_check(dh, count)) == 0){ count++; } if (code == ABS_EOM_DETECTED || code == ABS_EOF_DETECTED) code = 0; return(code); } slave/.mh_profile100660 6031 1 13 6062062042 13166 0ustar delgadootherPath: Mail slave/slave_error.c100600 6031 145 3623 6256053660 14016 0ustar delgadooraweb#include #include #include #include #include #include #include #include "../master/abs_msg.h" FILE *logfile; void initialize_slave_log(char *logdir, char *devname) { char *fname; char buf[PATH_MAX]; char msg[2048]; int i; /* * syslog -related stuff */ openlog("abs_slave", LOG_PID|LOG_CONS, LOG_LOCAL2); setlogmask(LOG_UPTO(LOG_ERR)); /* * create/open the slave's private log file * The private logfile name is derived from the device * name with the '/' characters converted to '.' characters. */ if (strlen(logdir)+ strlen(devname) > PATH_MAX -6){ syslog(LOG_CRIT, "Cannot open Slave log file: name too long - Exiting\n"); closelog(); exit(1); } fname = strdup(devname); for (i = 0; i< strlen(fname); i++){ if (fname[i] == '/') fname[i] = '.'; } sprintf(buf,"%s/slave%s",logdir, fname); if ( (logfile = fopen(buf,"w")) == (FILE *) NULL){ sprintf(msg,"Can't open log file %s: %s\n", buf, strerror(errno)); syslog(LOG_CRIT,msg); fputs(stderr,msg); closelog(); exit(1); } } slave_stop_logging() { closelog(); fclose(logfile); } void timestamp(char *timebuf) { struct timeval tv; time_t tval; struct tm tm; gettimeofday(&tv); tval = (time_t)tv.tv_sec; localtime_r(&tval, &tm); sprintf(timebuf,"%.2d-%.2d-%.2d %.2d:%.2d:%.2d ", tm.tm_mday, tm.tm_mon+1, tm.tm_year, tm.tm_hour, tm.tm_min, tm.tm_sec); } int slave_log_error(int sev, char *routine, char *msg) { char timebuf[30]; if (logfile != (FILE *) NULL){ timestamp(timebuf); fprintf(logfile, "%s %s %s", timebuf, routine, msg); fflush(logfile); } if (sev == ABS_FATAL){ syslog(LOG_ALERT, msg); } } slave/restore.c100600 6031 145 26642 6242361342 13176 0ustar delgadooraweb#include #include #include #include #include #include "../master/abs_msg.h" #include "private.h" #include "prototypes.h" extern char *device; extern char *master_server; /* * Function: do_restore * * Parameters: dh - pointer to device device information for media * vp - pointer to linked list of volumes to be restored * * jobid - id of job on master * params - address of parameters affecting restore operation. * * Description: This function performs a restore operation for each * volume in the list pointed to by "vp". It invokes the filesystem * specific "connect" and "restore" functions for each volume in * the list. If the restore operation fails for a volume with a * transient error then that volume is retried up to the maximum * number of retries indicated in the restore parameters. This * function will also request a media mount if it determines that * the proper media is not inserted into the device. */ int do_restore( dev_handle_t *dh, media_t *mp, int jobid, restore_pt params, job_status_pt job_stat) { int code, retries, needs_rewind; int percent, total, fileno, last_requested=0; net_volume_t *cvp; media_t *cmp; abs_label_t label; void *handlep; char buf[1024]; fs_ops *fsp; char *datep; int restore_error; abs_volheader_t vh; abs_volfooter_t vf; struct timeval now; /* * "restore_error keeps track of whether we've encountered any * serious errors which will cause us to give up restoreing any * other volumes which are located on the medium which has the * error. If we hit this state for a medium, we mark all the remaining * volumes on that medium as having an error and move on to the next * medium. Currently, the only error which would cause restore_error * to be non-zero is exceeding the media error threshold. */ restore_error = 0; job_stat->media_errors = 0; /* * Get the operations vector for this filesystem type. * All volumes must have the same type */ fsp = get_fs_ops(params->fstype); if (fsp == (fs_ops *) NULL){ return(ABS_INVALID_FSTYPE); } memset(job_stat, 0, sizeof(job_status_t)); /* * Ensure the retry value makes sense */ if (params->retries <= 0){ params->retries = 1; } if (params->media_errors < 0){ params->media_errors = 0; } /* * count the number of volumes in this restore operation. * We are supposed to provide statistics for the restore * and the total number of volumes involved is part of this. */ job_stat->total_volumes = 0; for(cmp = mp; cmp != (media_t *) NULL; cmp = cmp->next){ for (cvp = cmp->volumes; cvp != (net_volume_t *) NULL; cvp = cvp->next){ job_stat->total_volumes++; } } /* * Walk through each media on the list. Although the code * here supports the specification of more than one medium, * the Master does not yet support this. */ for(cmp = mp; cmp != (media_t *) NULL; cmp = cmp->next){ if (cmp->volumes == (net_volume_t *) NULL){ sprintf(buf,"Media has no volumes!\n", cmp->extern_id); slave_log_error(ABS_ERROR, "do_restore", buf); cvp->v_status = ABS_INVALID_MEDIA_ID; continue; } /* * reset the restore error state for this media; * check to see if it is mounted. */ restore_error = 0; while((code = cycle_through_tapes(dh, jobid, cmp->extern_id, (media_id_pt) &cmp->internal, ABS_VALID_MEDIA)) == ABS_INVALID_MEDIA_ID){ /* * keep trying until the guy mounts something we * can actually use. We are looking for a specific tape. */ code = 0; if (last_requested == 0){ code = request_service(jobid, ABS_TAPE_MOUNT_REQ, cmp->extern_id); last_requested = 1; }else{ last_requested = 0; sleep(ABS_MOUNT_INTERVAL); } } if (code){ /* * A serious error, possibly a device error which * can't be fixed has occurred. Error has already been logged. */ return(code); } /* * Advance past the label and position at the beginning * of the first volume header on the tape. */ code = SLAVE_NEXT_RECORD(dh, 1); fileno=1; /* * Restore all of the volumes which are chained of this * media entry */ for (cvp = cmp->volumes; cvp != (net_volume_t *) NULL; cvp = cvp->next){ /* * Tape is positioned at beginning of a volume header. * Seek to the correct volume as indicated by cvp->media->position * and start reading the volume information from the tape. */ for (fileno; fileno < cvp->position; fileno++){ /* * This is executed twice, once for the volume header and * once for the corresponding volume footer */ code = read_volume_header(dh, &vh); if (code == ABS_MEDIA_ERROR) job_stat->media_errors++; if (job_stat->media_errors > params->media_errors){ restore_error = ABS_MEDIA_ERROR; break; } if (code == ABS_INVALID_MAGIC){ sprintf(buf,"Bad Media Format, Expected Volume header, file %d\n", fileno); slave_log_error(ABS_WARNING,"do_restore",buf); } /* skip volume data */ code = NEXT_VOLFOOTER(dh); if (code == ABS_MEDIA_ERROR) job_stat->media_errors++; if (job_stat->media_errors > params->media_errors){ restore_error = ABS_MEDIA_ERROR; break; } /* skip footer */ code = read_volume_footer(dh, &vf); if (code == ABS_MEDIA_ERROR) job_stat->media_errors++; if (job_stat->media_errors > params->media_errors){ restore_error = ABS_MEDIA_ERROR; break; } if (code == ABS_INVALID_MAGIC){ sprintf(buf,"Bad Media Format, Expected Volume footer, file %d\n", fileno); slave_log_error(ABS_WARNING,"do_restore",buf); } } if (restore_error != 0){ cvp->v_status = restore_error; continue; } /* * allocate space to store status information * to tell master what happened to this volume * The master uses this info to print out a report * for each volume at the end of the restore operation */ if (cvp->res == (job_status_pt) NULL){ cvp->res = (job_status_pt)malloc(sizeof(job_status_t)); if (cvp->res == (job_status_pt) NULL){ return(ABS_NO_MEM); } } for(retries = 0; retries < params->retries; retries ++){ /* * Connect to the filesystem entity which will * execute the restore */ handlep = FS_CONNECT(fsp, cvp->v_server, params->cell, (char *)NULL, &code, ABS_RESTORE_OP); if (code == ABS_SERVER_NOEXIST ){ /* * don't retry on unrecoverable errors such as * cell does not exist, server does not exist */ cvp->v_status = code; break; } if (handlep == (void *) NULL){ /* * failed to connect, so retry. */ continue; } /* * Send the master a little status report telling * which volume we're on */ strcpy(cvp->res->current_volume, cvp->v_name); gettimeofday(&now); cvp->res->date = now.tv_sec; cvp->res->vols_processed = job_stat->vols_processed; cvp->res->bytes_processed = job_stat->bytes_processed; cvp->res->failures = job_stat->failures; code = send_status(jobid, cvp->res); if (code == ABS_JOB_CANCELED ){ slave_log_error(ABS_ERROR, "do_restore", "Job canceld at user's request\n"); /* * Mark remaining volumes as "canceled" */ for(;cvp != (net_volume_t *) NULL; cvp = cvp->next){ cvp->v_status = ABS_JOB_CANCELED; } return(ABS_JOB_CANCELED); } if (get_slave_state() == SLAVE_TERMINATED){ slave_log_error(ABS_ERROR, "do_restore", "Slave termination request received \n"); return(ABS_SLAVE_TERMINATED); } /* * Initiate the restore with the filesystem */ sprintf(buf,"Initiating restore of %s\n", cvp->v_name); slave_log_error(ABS_INFORMATIONAL,"do_restore", buf); code = FS_RESTORE(fsp, handlep, dh, cvp, cmp, jobid, params, &needs_rewind); cvp->v_status = code; sprintf(buf,"Completed restore of %s, code = %d\n", cvp->v_name, code); slave_log_error(ABS_INFORMATIONAL,"do_restore", buf); /* * Check whether the call should be retried */ if (code != 0){ job_stat->failures++; } if (code == ABS_MEDIA_ERROR){ job_stat->media_errors++; if (job_stat->media_errors > params->media_errors) restore_error = ABS_MEDIA_ERROR; } if (code == 0 || (code != ABS_COMM_FAILURE) || (code != ABS_CALL_TIMEOUT) || (code != ABS_VOLUME_BUSY)) break; /* * seek back to the volume header and try again. */ if (needs_rewind) code = PREV_VOLHEADER(dh); sleep(ABS_DEFAULT_RETRY); } /* end for retries */ /* * We have either successfully restored the volume * or we have given up on restoring it. */ if (code){ if (code == ABS_MEDIA_ERROR){ job_stat->media_errors++; if (job_stat->media_errors > params->media_errors){ restore_error = ABS_MEDIA_ERROR; break; } } /* * Tape was left positioned after current volume footer; * increment the fileno to indicate we are at the start * of the next volume. */ if (needs_rewind){ fileno++; } }else{ /* * Success! Fs_restore has left us at the record following * the footer. */ job_stat->vols_processed++; job_stat->bytes_processed += cvp->v_size; fileno++; } } /* end for cvp */ } return(code); } slave/afs/ 40755 6031 145 0 6065325253 12005 5ustar delgadooraweb