/* EXAREAD Read standard FITS files from Exabyte Modifications: 06-Aug-96 JRV Begin port from FORTRAN. 30-Sep-96 JRV First working version (list files not tested yet). 25-Nov-96 JRV Modfications to make file skip actually work. 12-Feb-98 JRV Start version for Linux. 16-Oct-98 JRV Fix problem with changing clusters. 20-Oct-98 JRV Check for successful FITS write to disk. 11-Jan-99 JRV Minor fixes to list file mode. --version for RedHat Linux, kernel 2.0.30 13-May-02 JRV Changes for RH Linux kernel 2.4.9 22-Aug-03 JRV Changes to read old WPIX tapes. 03-Sep-03 JRV Changes to make file names for some old Eyecom images */ #include #include #include #include #include #include #include #include #include #include "fitsio.h" #include "exaread.h" /* Realloc fix */ #define xalloc(Loc, Bytes) \ ((Loc) == NULL ? malloc (Bytes) : realloc ((Loc), (Bytes))) static void strip_return(char *string_to_strip) { int len; len = strlen(string_to_strip); if (string_to_strip[len - 1] == '\n') string_to_strip[len - 1] = '\0'; } /* try to guess filename for Eyecom files */ void GFnam(char (*header)[81], int maxln, char *filename, int *istat) { int bitpix, nax, naxes[2], nend, ierr, i, id, im, iy, result; char obstype[8], obsdate[8]; char obscomm[72], datecomm[72]; char months; *istat = 1; result = freads(header, maxln, "TYPE-OBS", obstype, obscomm); if (result == -1) { *istat = 0; } else { result = freads(header, maxln, "DATE-OBS", obsdate, datecomm); if (result >= 0) { /* both TYPE-OBS and DATE-OBS exist */ if (obsdate[0] == ' ') obsdate[0] = '0'; if (obsdate[3] == ' ') obsdate[3] = '0'; sscanf(obsdate, "%2d%*1c%2d%*1c%2d", &id, &im, &iy); if (id == 0 && im == 0 && iy == 0) *istat = 0; /* there are a few tapes with bad date values */ if (*istat == 1) { switch (im) { case 1: sprintf(filename, "%1cJAN%02d001.FTS", obstype[0], id); break; case 2: sprintf(filename, "%1cFEB%02d001.FTS", obstype[0], id); break; case 3: sprintf(filename, "%1cMAR%02d001.FTS", obstype[0], id); break; case 4: sprintf(filename, "%1cAPR%02d001.FTS", obstype[0], id); break; case 5: sprintf(filename, "%1cMAY%02d001.FTS", obstype[0], id); break; case 6: sprintf(filename, "%1cJUN%02d001.FTS", obstype[0], id); break; case 7: sprintf(filename, "%1cJUL%02d001.FTS", obstype[0], id); break; case 8: sprintf(filename, "%1cAUG%02d001.FTS", obstype[0], id); break; case 9: sprintf(filename, "%1cSEP%02d001.FTS", obstype[0], id); break; case 10: sprintf(filename, "%1cOCT%02d001.FTS", obstype[0], id); break; case 11: sprintf(filename, "%1cNOV%02d001.FTS", obstype[0], id); break; case 12: sprintf(filename, "%1cDEC%02d001.FTS", obstype[0], id); break; } } } else { *istat = -1; } } } int tapehdrd(int tapefildes, unsigned char *tapebuff, char (**header)[81], int *maxln, int *bitpix, int *naxes) { char (*headbuf)[81] = NULL; int nbytesread, bytesread, i; /* Exabyte tape blocks are always 8192 bytes */ nbytesread = read(tapefildes, tapebuff, 8192); if (nbytesread != 8192) { if (nbytesread == 0) return -1; /* EOF read, end of cluster */ else { printf("tapehdrd: error reading header from tape, read %d bytes\n", nbytesread); return -2; } } /* copy header into FITS line array */ *maxln = 0; do { if (*maxln % 36 == 0) { headbuf = (char (*)[81]) xalloc(headbuf, (*maxln + 36) * 81); if (headbuf == NULL) { printf("tapehdrd: error allocating memory for FITS header\n"); return -3; } } memcpy (headbuf[*maxln], tapebuff + (*maxln * 80), 80); headbuf[*maxln][80] = '\0'; } while (strncmp(headbuf[(*maxln)++], "END ", 8) != 0); *header = headbuf; bytesread = fits_head_decode (headbuf, *maxln, bitpix, naxes); if (bytesread < 0) { switch(bytesread) { case -11: printf("FITS error -- not SIMPLE\n"); break; case -12: printf("FITS error -- BITPIX error\n"); break; case -13: printf("FITS error -- NAXES error\n"); break; case -14: printf("FITS error -- NAXIS1\n"); break; case -15: printf("FITS error -- NAXIS2\n"); break; default: printf("Error decoding FITS header\n"); break; } return -2; } return 0; } int main(int argc, char *argv[]) { int interflg, rmode, tapefp, maxln, bitpix; int naxes[4], result, xresult; int clustart, cluend, filstart, filend, ldblank, lfblank, istat; int flen, j, lset; int imm, ind2; int ltype; int lrfdisp = FALSE; int leof = FALSE; int lname; int cnew, fnew; int iclust, ifile, nfskip, nskip, n2read, i, ndblke; int ndbyte, bytesleft, unitnum; char string[81], uinput[81]; char lfil[81]; char tapdevnam[81]; unsigned char tapebuff[8192]; char (*header)[81]; FILE *fp; char filename[81], file[81], fillin[81]; char odir[81]; char *dptr; char junk[80] = "junk"; char tfile[81]; char ffnam[81]; char space = ' ', brack = ']', dot = '.'; char nfstr[6]; char *diskfile = "ORIGIN FILE WAS NAMED "; char *diskfil2 = "ORIGIN FILE NAME "; char sub[4]; char keyword[9]; char *comment = "COMMENT "; unsigned char *fitspict; long tapeid, nimage; struct mtop mt_command; struct mtget mt_status; printf("EXAREAD 03 Sep 2003 version for Linux\n"); printf(" Reads std. FITS files from Exabyte tape\n"); /* Process command line */ lfil[0] = '\0'; odir[0] = '\0'; interflg = TRUE; if (argc > 1) { unitnum = (int) strtol(argv[1], NULL, 10); if (unitnum == 0) { strcpy(tapdevnam, "/dev/nst0"); } else if (unitnum == 1) { strcpy(tapdevnam, "/dev/nst1"); } else { printf("Usage: EXAREAD unitnum [listfile]\n"); exit(0); } } else { printf("Usage: EXAREAD unitnum [listfile]\n"); exit(0); } if (argc > 2) { interflg = FALSE; rmode = 1; strcpy(lfil,argv[2]); } if (argc == 4) strcpy(odir,argv[3]); if (argc > 4) { printf("EXAREAD: Too many arguments.\n"); exit(0); } /* Set read mode */ if (interflg) { printf("Read using list file (Y/N)? "); fgets(string, 80, stdin); strip_return(string); if (string[0] == 'Y' || string[0] == 'y') { rmode = 1; } else { rmode = 0; } if (rmode == 1) { printf("Enter list file name: "); fgets(string, 80, stdin); strip_return(string); strcpy(lfil, string); } } /* Attempt to access Exabyte drive */ if((tapefp = open(tapdevnam, O_RDONLY)) == -1) { printf("cannot open tape\n"); exit(0); } else { printf("Exabyte drive %s successfully accessed.\n", tapdevnam); } /* Set tape density */ mt_command.mt_op = MTSETDENSITY; mt_command.mt_count = 0x14; /* EXB-8200 density */ result = ioctl(tapefp, MTIOCTOP, &mt_command); if (result == -1) { printf("cannot set tape density\n"); exit(0); } mt_command.mt_op = MTSETBLK; mt_command.mt_count = 0; result = ioctl(tapefp, MTIOCTOP, &mt_command); if (result == -1) { printf("could not set variable tape block size\n"); exit(0); } /* Request output filename */ if (interflg) { printf("Enter filename for restored images or \n"); fgets(filename, 80, stdin); strip_return(filename); if (filename[0] == '\n') filename[0] = '\0'; if (strlen(filename) != 0) { lname = TRUE; } else { lname = FALSE; } /* get output directory */ printf("Enter output directory: "); fgets(uinput, 80, stdin); strip_return(uinput); if (uinput[0] == '\n') uinput[0] = '\0'; if (strlen(uinput) != 0) strcpy(odir, uinput); } else { lname = FALSE; } /* Request starting and ending file numbers */ if (rmode == 0) { printf("Enter starting cluster and file number: "); scanf("%d %d", &clustart, &filstart); if (clustart <= 0 || filstart <= 0) goto error_stop; printf("\nEnter ending cluster and file number: "); scanf("%d %d", &cluend, &filend); if (cluend < clustart || (cluend == clustart && filend < filstart)) { printf("cannot understand which files you want!\n"); goto error_stop; } } else if (rmode == 1) { /* read list file if needed */ fp = fopen(lfil,"r"); if (fp == NULL) { printf("error opening list file\n"); goto error_stop; } for (i = 0; i < 5; i++) { /* skip header lines */ fgets(fillin, 80, fp); strip_return(fillin); } if(fgets(fillin, 80, fp) != NULL) { strip_return(fillin); sscanf(fillin,"%d %d", &clustart, &filstart); } else { printf("End of file reached in list file prematurely.\n"); goto error_stop; } } /* printf("rmode = %d, lname = %d, lfil = %s\n", rmode, lname, lfil); printf("filename = %s, odir = %s\n", filename, odir); */ /* Position Exabyte tape at first file */ nimage = 0; iclust = 1; ifile = 0; cnew = clustart; fnew = filstart; nfskip = fnew - 1; nskip = cnew - 1; skip_clusters: ifile++; /* skip over clusters */ if (nskip > 0) { lrfdisp = TRUE; printf("now skipping over file clusters ...\n"); mt_command.mt_op = MTFSF; mt_command.mt_count = nskip; result = ioctl(tapefp, MTIOCTOP, &mt_command); if (result == -1) { printf("tape skip error\n"); goto error_stop; } iclust = iclust + nskip; if (lrfdisp) printf("%d file marks skipped over\n", nskip); } else { if (lrfdisp) printf("No file marks skipped over\n"); } /* skip over images in cluster */ if (lrfdisp) printf("iclust now: %d\n", iclust); skip_files: n2read = 8192; if (nfskip > 0) { lrfdisp = TRUE; printf("now skipping over files within the cluster ...\n"); for (i = 0; i < nfskip; i++) { xresult = tapehdrd(tapefp, tapebuff, &header, &maxln, &bitpix, naxes); if (xresult == -1) goto cluster_change; /* determine size of data, skip over it */ ndbyte = naxes[0] * naxes[1]; if (bitpix == 16) ndbyte = ndbyte * 2; ndblke = (ndbyte + 8191) / 8192; mt_command.mt_count = ndblke; for (j = 0; j < ndblke; j++) { result = read(tapefp, tapebuff, 8192); if (result != 8192) { if (result == 0) { /* EOF read */ goto cluster_change; } else if (result > 0) { printf("read incorrect number of bytes: %d\n", result); goto error_stop; } else { printf("tape file skip error\n"); perror("read call from file skip:"); goto error_stop; } } } ifile++; } if (lrfdisp) printf("%d files skipped over within the cluster\n", nfskip); } else { if (lrfdisp) printf("No data files skipped over within the cluster\n"); } /* Set up to start copying */ /* printf("ifile now %d\n", ifile); */ read_file: if (lrfdisp) { printf("Reading files...\n"); lrfdisp = FALSE; } /* Read and decode header */ result = tapehdrd(tapefp, tapebuff, &header, &maxln, &bitpix, naxes); /* printf("maxln = %d\n", maxln); printf("bitpix = %d\n", bitpix); printf("naxes: %d %d\n", naxes[0], naxes[1]); */ /* determine output filename */ if (result == 0) { leof = FALSE; if (lname) { /* use filename given in command line or by user */ lset = TRUE; flen = strlen(filename); if (flen == 0) { printf("Could not make suitable filename\n"); goto error_stop; } sprintf(nfstr,"%2.2d%4.4d", iclust, ifile); file[0] = '\0'; strcat(file, filename); strcat(file, nfstr); strcat(file, ".fts"); } else { /* use filename in FITS header */ lset = FALSE; i = 0; do { strncpy(keyword, header[i], 8); if (!(strcmp(keyword, comment))) { /* printf("header [%d]: %s\n", i, header[i]); */ dptr = NULL; if ((dptr = strstr(header[i], diskfile)) != NULL) { dptr = dptr + 22; /* printf("%s\n", dptr); */ strcpy(filename,dptr); } if (dptr == NULL) { if ((dptr = strstr(header[i], diskfil2)) != NULL) { dptr = dptr + 17; /* printf("%s\n", dptr); */ strcpy(filename,dptr); } } if (dptr != NULL) { /* printf("Removing VMS directory stuff\n"); */ /* remove VMS directory stuff */ dptr = strchr(filename,brack); if (dptr != NULL) strcpy(file, (dptr+1)); else strcpy(file, filename); /* check for ; and remove if present */ dptr = strchr(file, ';'); if (dptr != NULL) *dptr = '\0'; dptr = strchr(file, space); if (dptr != NULL) *dptr = '\0'; flen = strlen(file); for (j = 0; j < flen; j++) file[j] = tolower(file[j]); lset = TRUE; } } i++; } while (!lset && (i < maxln)); } if (!lset) { GFnam(header, maxln, filename, &istat); if (istat == 1) { strcpy(file, filename); } else { sprintf(nfstr,"%2.2d%4.4d", iclust, ifile); file[0] = '\0'; strcat(file, junk); strcat(file, nfstr); strcat(file, ".fts"); } lset = TRUE; } /* printf("filename selected: %s\n", file); */ if (lset) { if (strlen(odir) != 0) { ffnam[0] = '\0'; strcpy(ffnam,odir); strcat(ffnam,file); } else { strcpy(ffnam,file); } } /* printf("full filename = %s\n", ffnam); */ /* Now copy the data to the data buffer */ /* Determine size of data buffer, allocate it */ ndbyte = naxes[0] * naxes[1]; ndbyte = ndbyte * (bitpix / 8); /* printf("ndbyte = %d\n", ndbyte); */ fitspict = (unsigned char *) malloc(ndbyte); if (fitspict == NULL) { printf("error allocating memory for copy\n"); goto error_stop; } ndblke = (ndbyte + 8191) / 8192; /* printf("ndblke = %d\n", ndblke); */ bytesleft = ndbyte; for (i = 0; i < ndblke; i++) { result = read(tapefp, tapebuff, n2read); if (bytesleft >= 8192) { memcpy(fitspict + (i * 8192),tapebuff, n2read); bytesleft -= 8192; } else { memcpy(fitspict + (i * 8192), tapebuff, bytesleft); } } /* printf("FITS data read from tape\n"); */ /* write FITS file to disk */ if (lset) { istat = fits_write(ffnam, header, maxln, (void *) fitspict, naxes, bitpix); if (istat == 0) { printf("File %s written to disk.\n", ffnam); nimage++; } else { printf("Writing %s to disk failed. Disk may be full. Stopping.\n"); goto error_stop; } } else { printf("File name not set up. File not written to disk.\n"); goto error_stop; } free(fitspict); } else { if (result != -1) { printf("Error during interpretation of header\n"); printf("in cluster %d and file %d.\n", iclust, ifile); printf("tapehdrd returns: %d.\n", result); printf("Program stops.\n"); goto error_stop; } else { if (leof == FALSE) printf("End of cluster reached.\n"); iclust++; } } /* Get next file from list */ if (rmode == 0) { /* printf("Now comparing file numbers\n"); */ /* printf("iclust = %d ifile = %d\n", iclust, ifile); */ if ((iclust < cluend) || ((iclust == cluend) && (ifile < filend))) { nfskip = 0; nskip = 0; goto skip_clusters; } else goto normal_stop; } else { /* read next cluster and file numbers from list file */ if(fgets(fillin, 80, fp) != NULL) { strip_return(fillin); sscanf(fillin,"%d %d", &cnew, &fnew); nskip = cnew - iclust; if (cnew != iclust) { nfskip = fnew - 1; ifile = 0; } else { nfskip = fnew - ifile - 1; } if (nfskip < 0) nfskip = 0; goto skip_clusters; } else { if (feof(fp)) goto normal_stop; else { printf("error reading list file\n"); goto error_stop; } } /* then go to skip_clusters */ } /* Come here if cluster changes */ cluster_change: if (leof == TRUE) { printf("End of tape reached.\n"); goto normal_stop; } /* We read two EOFs in a row; stop. */ if (rmode == 1 && cnew == iclust && fnew == ifile) { lrfdisp = TRUE; leof = TRUE; goto read_file; } else if (rmode == 0) { lrfdisp = TRUE; leof = TRUE; goto read_file; } else { printf("Unexpected cluster change -- Stopping\n"); } normal_stop: printf("%d images read from tape\n", nimage); printf("Done.\n"); close(tapefp); exit(0); error_stop: printf("%d images read from tape\n", nimage); printf("Exabyte Cluster and File numbers: %d %d\n", iclust, ifile); printf("Program exits.\n"); close(tapefp); exit(0); }