diff options
Diffstat (limited to 'vendor/voclient/voapps/votget.c')
-rw-r--r-- | vendor/voclient/voapps/votget.c | 1089 |
1 files changed, 1089 insertions, 0 deletions
diff --git a/vendor/voclient/voapps/votget.c b/vendor/voclient/voapps/votget.c new file mode 100644 index 00000000..87bef50c --- /dev/null +++ b/vendor/voclient/voapps/votget.c @@ -0,0 +1,1089 @@ +/** + * VOTGET -- Download select/all access references in a VOTable. + * + * Usage: + * + * votget [<opts>] <votable.xml> + * votget [<opts>] --samp # to listen for SMAP messages + * + * Where + * -b,--base <base> Base output filename + * -e,--extn [<extn>] Extension to add to filename (or auto) + * -f,--fmt <fmt> Download only specified <type> + * -s,--sum Use checksum as file number + * -t,--tmp Input file is temporary, delete when done + * -u,--ucd <ucd> Use ucd to identify acref column + * + * -o,--output <fname> Output filename (single download) + * -v,--verbose Verbose output + * -x,--extract Extract access references + * + * -A,--acref <colnum> Col number for acref column (0-indexed) + * -B,--bkg Background, i.e. run in forked child process + * -C,--cache Cache the downloaded file + * -D,--download Set download directory + * -F,--fmtcol <colnum> Col number for format column (0-indexed) + * -N,--num <N> Number of simultaneous downloads + * -S,--samp start as SAMP listener + * -m,--mtype <mtype> mtype to wait for + * + * -h,--help Print help summary + * -d,--debug Debug output + * --test Run unit tests + * + * <votable> VOTable to process + * + * @file votget.c + * @author Mike Fitzpatrick + * @date 6/03/12 + * + * @brief Download select/all access references in a VOTable. + */ + + +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <fcntl.h> +#include <signal.h> +#include <sys/errno.h> +#include <sys/types.h> +#include <sys/uio.h> +#include <sys/stat.h> +#include <sys/wait.h> +#include <pthread.h> + +#include <curl/curl.h> +#include <curl/types.h> +#include <curl/easy.h> + +#include "samp.h" +#include "votParse.h" +#include "voApps.h" + + +#define MIN_THREADS 4 /* min no. simultaneous thread */ +#define MAX_THREADS 64 /* max no. simultaneous threads */ +#define MAX_DOWNLOADS 4096 /* max no. files to download */ +#define MAX_TRYS 3 /* max download attempts */ + +#define NAXIS_UCD "VOX:Image_Naxis" +#define NAXES_UCD "VOX:Image_Naxes" +#define SCALE_UCD "VOX:Image_Scale" +#define ACREF_UCD "VOX:Image_AccessReference" +#define FORMAT_UCD "VOX:Image_Format" + + +static int vot = 0; /* VOTable handle */ +static int verbose = 0; /* verbose parameter */ +static int debug = 0; /* debug flag */ +static int extract = 0; /* extract references only */ +static int detach = 0; /* run as detached process */ +static int nfiles = 0; /* number of download files */ +static int ngot = 0; /* number of files downloaded */ +static int seq = 1; /* use sequential file numbers */ +static int isCache = 0; /* is this a cache file? */ +static int isTemp = 0; /* is this a temp file? */ +static int force = 0; /* overwrite existing file */ +static int acol = -1; /* access reference column */ +static int tcol = -1; /* image type column */ +static int filenum = 0; /* running download file number */ + +static int nthreads = MIN_THREADS; /* number of download threads */ +static int maxTrys = MAX_TRYS; /* download attempts */ + +static char *base = NULL; /* output base filename */ +static char *extn = NULL; /* output filename extension */ +static char *dir = NULL; /* download directory */ +static char *afname = NULL; /* output acref filename */ + +static char *acref = NULL; /* acref url */ +static char *acref_ucd = NULL; /* acref UCD */ +static char *fmt = NULL; /* image format */ +static char *fmt_ucd = NULL; /* image format UCD */ + +static FILE *afd = (FILE *) NULL; /* acref file descriptor */ + +static pthread_mutex_t counter_mut = PTHREAD_MUTEX_INITIALIZER; + +typedef void (*SIGFUNC)(); /* signal handler type */ + +typedef struct { + char url[SZ_URL]; /* access URL */ + char fname[SZ_URL]; /* local filename */ + int tnum; /* worker thread number */ +} Acref, *AcrefP; + +Acref aclist[MAX_DOWNLOADS]; /* access list */ + + +/* Task specific option declarations. + */ +int votget (int argc, char **argv, size_t *len, void **result); + +static Task self = { "votget", votget, 0, 0, 0 }; +static char *opts = "%:hb:e:f:dstu:o:vxA:BCD:F:N:Sm:"; +static struct option long_opts[] = { + { "base", 1, 0, 'b'}, /* task option */ + { "extn", 1, 0, 'e'}, /* task option */ + { "fmt", 1, 0, 'f'}, /* task option */ + { "sum", 2, 0, 's'}, /* task option */ + { "tmp", 2, 0, 't'}, /* task option */ + { "ucd", 1, 0, 'u'}, /* task option */ + { "output", 1, 0, 'o'}, /* task option */ + { "verbose", 2, 0, 'v'}, /* task option */ + { "extract", 2, 0, 'x'}, /* task option */ + { "acref", 1, 0, 'A'}, /* task option */ + { "bkg", 2, 0, 'B'}, /* task option */ + { "cache", 2, 0, 'C'}, /* task option */ + { "download", 1, 0, 'D'}, /* task option */ + { "fmtcol", 1, 0, 'F'}, /* task option */ + { "num", 1, 0, 'N'}, /* task option */ + { "force", 2, 0, 'O'}, /* task option */ + { "samp", 2, 0, 'S'}, /* task option */ + { "mtype", 1, 0, 'm'}, /* task option */ + + { "help", 2, 0, 'h'}, /* required */ + { "debug", 2, 0, 'd'}, /* required */ + { "test", 1, 0, '%'}, /* required */ + { NULL, 0, 0, 0 } +}; + +static int do_return = 0; /* NOT USED */ +static int do_samp = 0; /* samp listener? */ +static char *mtype = NULL; /* samp mtype */ + + +static void Usage (void); +static void Tests (char *input); + + +/* Public methods. + */ +extern int vot_isValidFormat (char *fmt); +extern int vot_atoi (char *val); +extern int vot_sum32 (char *str); +extern char *strcasestr (); + + +/* Private methods. + */ +static void votableHandler (char *url, char *tblId, char *name); + +static int vot_procFile (char *iname); +static int vot_isVOTable (char *infile); +static int vot_acrefColumn (handle_t tab); +static int vot_typeColumn (handle_t tab); +static int vot_loadText (char *infile); +static int vot_loadVOTable (char *infile); +static int vot_getData (char *url, char *ofname); + +static void vot_saveAcref (char *acref, int num, int fnum); +static void *vot_getAclist (void *arg); +static void vot_printAclist (); +static void vot_reaper (int sig, int *arg1, int *arg2); + + + + +/** + * Program entry point. + */ +int +votget (int argc, char **argv, size_t *reslen, void **result) +{ + char **pargv, optval[SZ_FNAME]; + char *iname = NULL, ch; + int samp = 0, pos = 0, stat = OK; + + + /* Initialize. + */ + *reslen = 0; + *result = NULL; + + + /* Parse the argument list. + */ + pargv = vo_paramInit (argc, argv, opts, long_opts); + while ((ch = vo_paramNext (opts,long_opts,argc,pargv,optval,&pos)) != 0) { + if (ch > 0) { + + switch (ch) { + case '%': Tests (optval); return (self.nfail); + case 'h': Usage (); return (OK); + + case 'b': base = strdup (optval); break; + case 'e': extn = strdup (optval); break; + case 'f': if (!vot_isValidFormat ((fmt = strdup (optval)))) { + fprintf (stderr, "Error: invalid format '%s'\n", + fmt); + return (ERR); + } + break; + case 'd': debug++; break; + case 's': seq=0; break; + case 't': isTemp++; break; + case 'u': acref_ucd = strdup (optval); break; + + case 'o': afname = strdup (optval); break; + case 'v': verbose++; break; + case 'x': extract++; break; + + case 'A': acol = vot_atoi (optval); break; + case 'B': detach++; break; + case 'C': isCache++; break; + case 'D': dir = strdup (optval); break; + case 'F': tcol = vot_atoi (optval); break; + case 'N': nthreads = vot_atoi (optval); break; + case 'O': force++; break; + case 'S': do_samp++; break; + case 'm': mtype = strdup (optval);; break; + + default: + fprintf (stderr, "Invalid option '%c'\n", ch); + return (1); + } + + } else if (ch == PARG_ERR) { + return (ERR); + + } else { + iname = strdup (optval); + } + } + + + /* Sanity checks + */ + if (iname == NULL) iname = strdup ("stdin"); + if (strcmp (iname, "-") == 0) { free (iname), iname = strdup ("stdin"); } + + + /* Setup defaults and initialize. + */ + do_return = 0; + memset (&aclist[0], 0, (sizeof (Acref) * MAX_DOWNLOADS)); + + if (afname && (afd = fopen (afname, "a+")) == (FILE *) NULL) { + if (verbose) + fprintf (stderr, "Error: cannot open aclist file '%s'\n", afname); + return (ERR); + } + + if (!base) base = strdup ("file"); + if (!mtype) mtype = strdup ("table.load.votable"); + if (!fmt_ucd) fmt_ucd = strdup (FORMAT_UCD); + if (!acref_ucd) acref_ucd = strdup (ACREF_UCD); + + + if (do_samp) { + /* Initialize and startup the SAMP interface. Wait for a message. + */ + if (verbose) + fprintf (stderr, "Initializing samp ....\n"); + samp = sampInit ("votget", "VOClient Task"); + samp_Subscribe (samp, mtype, votableHandler); + if (sampStartup (samp) < 0) + return (ERR); + + if (verbose) + fprintf (stderr, "Type <cr> to quit ...."); + while (fgetc(stdin) != EOF) + break; + + sampShutdown (samp); + + } else { + /* Process the file. + */ + stat = vot_procFile (iname); + } + + + /* Close the table and clean up. + */ + if (base) free (base); + if (extn) free (extn); + if (dir) free (dir); + if (afname) free (afname); + if (acref) free (acref); + if (acref_ucd) free (acref_ucd); + if (fmt) free (fmt); + if (fmt_ucd) free (fmt_ucd); + if (mtype) free (mtype); + + vo_paramFree (argc, pargv); + if (detach) + exit (OK); + else + return (stat); +} + + +/** + * VOTABLEHANDLER -- Callback for the load.table.votable message. + */ +static void +votableHandler (char *url, char *tblId, char *name) +{ + char fname[SZ_FNAME]; + + + memset (fname, 0, SZ_FNAME); + + if (verbose) + printf ("\n"); + + + if (strncmp (url, "http://", 7) == 0) { + strcpy (fname, "/tmp/votgetXXXXXX"); /* temp download name */ + mktemp (fname); + if (vot_getData (url, fname) < 0) + fprintf (stderr, "Error accessing url '%s'\n", url); + + vot_procFile (fname); + unlink (fname); + + } else if (strncmp (url, "file://", 7) == 0) { + strcpy (fname, &url[7]); + vot_procFile (fname); + + } else { + fprintf (stderr, "Error: unsupported URL type '%s'\n", url); + return; + } + + /* Clean up for the next file to process. + */ + memset (&aclist[0], 0, (sizeof (Acref) * MAX_DOWNLOADS)); + nfiles = 0; +} + + +/** + * VOT_PROCFILE -- Process a VOTable file. + */ +static int +vot_procFile (char *iname) +{ + int stat = OK; + + + /* Determine the type of input file. + */ + if (strncmp (iname, "http://", 7) == 0) { + if (vot_loadVOTable (iname) < 0) { + fprintf (stderr, "Error opening votable '%s'\n", iname); + return ( (stat = ERR) ); + } + + } else { + switch ((vot = vot_isVOTable (iname))) { + case -1: fprintf (stderr, "Error opening file '%s'\n", iname); + return ( (stat = ERR) ); + case 0: if (vot_loadText (iname) < 0) { + fprintf (stderr, "Error opening text file '%s'\n", iname); + return ( (stat = ERR) ); + } + break; + case 1: if (vot_loadVOTable (iname) < 0) { + fprintf (stderr, "Error opening votable '%s'\n", iname); + return ( (stat = ERR) ); + } + break; + } + } + + + /* If all we're doing is extracting the URLs we can quit now. + */ + if (extract) + return (OK); + + if (debug) { + fprintf (stderr, "acol = %d tcol = %d\n", acol, tcol); + fprintf (stderr, "Downloading %d files ....\n", nfiles); + vot_printAclist (); + } + + + /* If we've been asked to detach, fork off to do the downloads in + * a child, and return to the caller. + */ + if (detach) { + pid_t pid; + + signal (SIGCHLD, (SIGFUNC)vot_reaper); + switch ((pid = fork ())) { + case -1: return (ERR); /* We are an error */ + case 0: break; /* We are the child */ + default: return (OK); /* We are the parent */ + } + } + + + /* Initialize the download directory. + */ + if (dir) { + if (access (dir, F_OK) < 0) + mkdir (dir, 0755); + if (access (dir, W_OK) < 0) { + if (verbose) + fprintf (stderr, "Error: Cannot write to directory '%s'\n", dir); + return (ERR); + } + chdir (dir); + } + + /* Do the downloads. + */ + if (nfiles < MIN_THREADS) + nthreads = nfiles; + + if (nthreads == 1) { + vot_getAclist (NULL); + + } else { + /* Spawn the worker threads. + */ + int rc = 0, tc = 0, status = 0, tnum[MAX_THREADS]; + pthread_attr_t attr; /* thread attributes */ + pthread_t thread[MAX_THREADS]; + + + /* Initialize the service processing thread attributes and run 'em. + */ + pthread_attr_init (&attr); + pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_JOINABLE); + + if (verbose) + fprintf (stderr, "Starting download ....\r"); + + for (tc=0; tc < nthreads; tc++) { + tnum[tc] = tc; + if ((rc = pthread_create (&thread[tc], &attr, vot_getAclist, + (void *)&tnum[tc]))) { + fprintf (stderr, "ERROR: pthread_create() fails, code=%d\n", + rc); + return (-1); + } + } + + /* Free attribute and wait for the threads to complete. + */ + pthread_attr_destroy (&attr); + for (tc=0; tc < nthreads; tc++) { + if ((rc = pthread_join (thread[tc], (void **)&status)) ) { + if (rc != ESRCH) { + fprintf (stderr, + "ERROR: pthread_join() fails, code=%d status=%d\n", + rc, status); + return (-1); + } + } + } + + if (verbose) { + fprintf (stderr, + "Downloaded %d files -- Download complete (Total: %d)\n", + nfiles, (filenum+1)); + fflush (stderr); + } + } + + + /* Remove input file if it is temporary. + */ + if (isTemp) + unlink (iname); + + return (stat); +} + + + + +/** + * VOT_USAGE -- Print the task usage and exit. + */ +static void +Usage (void) +{ + fprintf (stderr, "\n Usage:\n\t" + "votget [<opts>] [ <votable.xml> | <urls.txt> ]\n\t" + "votget [<opts>] --samp # to listen for SMAP messages\n" + "\n" + "Where\n" + " -b,--base <base> Base output filename\n" + " -e,--extn [<extn>] Extension to add to filename (or auto)\n" + " -f,--fmt <fmt> Download only specified <type>\n" + " -s,--sum Use 32-bit checksum as file numbers\n" + " -t,--tmp Input file is temporary, delete when done\n" + " -u,--ucd <ucd> Use ucd to identify acref column\n" + "\n" + " -o,--output <fname> Output filename (single download)\n" + " -v,--verbose Verbose output\n" + " -x,--extract Extract access references\n" + "\n" + " -A,--acref <colnum> Col number for acref column (0-indexed)\n" + " -B,--bkg Background, i.e. run in forked child\n" + " -C,--cache Cache the downloaded file\n" + " -D,--download Set download directory\n" + " -F,--fmtcol <colnum> Col number for format column (0-indexed)\n" + " -N,--num <N> Number of simultaneous downloads\n" + " -S,--samp start as SAMP listener\n" + "\n" + " -h,--help Print help summary\n" + " -d,--debug Debug output\n" + " --test Run unit tests\n" + "\n" + " <votable> VOTable to process\n" + "\n" + " Examples:\n\n" + + " 1) Download all files in the VOTable 'results.xml', 3 files at\n" + " a time:\n\n" + " %% votget -N 3 results.xml\n" + "\n" + " 2) Start as a SAMP listener waiting for VOTable events to be \n" + " broadcast, saved files will begin with the string 'foo' and \n" + " contain a 'fits' filename extension:\n\n" + " %% votget -b foo -e fits -S\n" + "\n" + " To exit the task, hit the <CR>.\n" + "\n" + " 3) Download all the urls in the file 'urls.txt':\n\n" + " %% votget -b foo urls.txt\n" + "\n" + " 4) Extract all the access references in a VOTable:\n\n" + " %% votget -x results.xml\n" + "\n" + ); +} + + +/** + * Tests -- Task unit tests. + */ +static void +Tests (char *input) +{ + Task *task = &self; + char *urls = "http://iraf.noao.edu/votest/sia.xml\n"; + + + vo_taskTest (task, "--help", NULL); + + if (access (input, F_OK) != 0) { + fprintf (stderr, "Warning: cannot open file '%s'\n", input); + return; + } + + vo_taskTestFile (urls, "urls.txt"); + + vo_taskTest (task, "-N", "3", input, NULL); // Ex 1 + vo_taskTest (task, "-b", "foo", input, NULL); // Ex 3 + vo_taskTest (task, "-x", input, NULL); // Ex 4 + vo_taskTest (task, "-x", "-o", "/tmp/acref", input, NULL); + + if (access ("/tmp/acref", F_OK) == 0) unlink ("/tmp/acref"); + if (access ("urls.txt", F_OK) == 0) unlink ("urls.txt"); + + vo_taskTestReport (self); +} + + + +/********************************************************************** +** Private Procedures +**********************************************************************/ + +/** + * VOT_REAPER -- Catch a SIGCHLD signal and reap all children. + */ +static void +vot_reaper ( + int sig, /* signal which was trapped */ + int *arg1, /* not used */ + int *arg2 /* not used */ +) +{ + int status=0, pid=0; + + while ((pid = waitpid ((pid_t) 0, &status, WNOHANG)) > 0) + ; +} + + +/** + * VOT_LOADTEXT -- Load the access list from a text file. We assume the + * list is simply one url per line. + */ +static int +vot_loadText (char *infile) +{ + int i = 0, fd, nread = 0, tnum = 0, sz = 0; + char *acref, *buf, *ip; + struct stat info; + + + nfiles = 0; + memset (&aclist[0], 0, (sizeof (Acref) * MAX_DOWNLOADS)); + + if ((fd = open (infile, O_RDONLY)) < 0) + return (-1); + + if (stat (infile, &info) < 0) /* read the whole file */ + return (-1); + sz = info.st_size; + buf = calloc (sz + 1, sizeof(char)); + nread = read (fd, buf, sz); + close (fd); + + acref = buf; /* point to 1st url */ + for (i=0; *acref; i++) { + for (ip=acref; *ip && *ip != '\n'; ip++) + ; + *ip = '\0'; + + vot_saveAcref (acref, i, filenum++); + + acref = ip + 1; + nfiles++; + tnum++; + } + + if (afd) /* close the acref file */ + fclose (afd); + + return (nfiles); +} + + +/** + * VOT_LOADVOTABLE -- Load the access list from a VOTable. + */ +static int +vot_loadVOTable (char *infile) +{ + int i, tnum = 0; + int res, tab, data, tdata, tr; + char *acref; + + + nfiles = 0; + memset (&aclist[0], 0, (sizeof (Acref) * MAX_DOWNLOADS)); + + /* Open the table. This also parses it. + */ + if ( (vot = vot_openVOTABLE (infile) ) <= 0) { + if (verbose) + fprintf (stderr, "Error opening VOTable '%s'\n", infile); + return (ERR); + } + + /* Loop over all the resources in the file. In most cases there will + * only be one <RESOURCE>, if not then the selection applies to all + * valid tables. + */ + for (res = vot_getRESOURCE (vot); res; res = vot_getNext (res)) { + + /* Get the <TABLE> element. + */ + if (! (tab = vot_getTABLE (res))) { + if (verbose) fprintf (stderr, "Error: No <TABLE> in <RESOURCE>\n"); + continue; + } + if ((data = vot_getDATA (tab))) + tdata = vot_getTABLEDATA (data); + else + continue; /* empty data table */ + + /* Loop through the FIELDs to find the acref. Let the cmdline param + * override the acref column ucd. + */ + acol = (acol < 0 ? vot_acrefColumn (tab) : acol); + tcol = (tcol < 0 ? vot_typeColumn (tab) : tcol); + + /* Now scan the data table for acrefs. We got the acref column above + * so lookup the table cell directly for each row, either printing + * out the acref for a simple extract, or by adding to the access + * list to be processed below. + */ + i = 0; + for (tr=vot_getTR (tdata); tr; tr=vot_getNext(tr)) { + acref = vot_getTableCell (tdata, i, acol); + if (tcol >= 0) { + char *format = vot_getTableCell (tdata, i, tcol); + + if (format && fmt && strcasestr (format, fmt) == NULL) + continue; + } + + vot_saveAcref (acref, i, filenum++); + + nfiles++; + tnum++; + i++; + } + } + + + /* Clean up. + */ + if (afd) /* close the acref file */ + fclose (afd); + + vot_closeVOTABLE (vot); + + return (nfiles); +} + + +/** + * VOT_SAVEACREF -- Save the URL to the access list. + */ +static void +vot_saveAcref (char *acref, int num, int fnum) +{ + if (afd) + fprintf (afd, "%s\n", acref); + else if (extract) + fprintf (stderr, "%s\n", acref); + else { + /* Save to the access list. + */ + aclist[num].tnum = ((nthreads == 1) ? 0 : (num % nthreads)); + strcpy (aclist[num].url, acref); + if (seq) + sprintf (aclist[num].fname, "%s%04d", base, (int) fnum); + else + sprintf (aclist[num].fname, "%s%d", base, vot_sum32 (acref)); + } +} + + +/** + * VOT_ISVOTABLE -- Determine in the input file is a VOTable or URL @file. + * We return zero if the file cannot be parsed as a valid VOTable (i.e. + * we assume it is an @file of URLs), or else we return the root handle to + * the parsed file. + */ + +#define SZ_READ 2880 + +static int +vot_isVOTable (char *infile) +{ + FILE *fd = (FILE *) NULL; + char buf[SZ_READ], fname[SZ_READ]; + register int nread;; + + + memset (fname, 0, SZ_READ); + if (strncmp (infile, "file://", 7) == 0) + strcpy (fname, &infile[7]); + else + strcpy (fname, infile); + + /* read the first 1024 bytes and search for a 'votable' string... */ + if (access (fname, F_OK) < 0) { + if (verbose) + fprintf (stderr, "Error: Cannot open input file '%s'\n", fname); + return (-1); + + } else if ((fd = fopen (fname, "r"))) { + memset (buf, 0, SZ_READ); + nread = fread (buf, sizeof (char), SZ_READ, fd); + fclose (fd); + + return (strcasestr (buf, "votable") ? 1 : 0); + } + return ( 0 ); +} + + +/** + * VOT_ACREFCOLUMN -- Determine the access column for the given table. + */ +static int +vot_acrefColumn (handle_t tab) +{ + register int i = 0, acol = -1; + handle_t field; + char *ucd; + + + /* Loop through the FIELDs to find the acref. + */ + for (field=vot_getFIELD(tab); field; field=vot_getNext(field),i++) { + ucd = vot_getAttr (field, "ucd"); + if (ucd && strcasecmp (acref_ucd, ucd) == 0) { + acol = i; + break; + } + } + + if (acol < 0) { /* make sure we found a column */ + if (verbose) + fprintf (stderr, "Error: no acref column found (%s)\n", acref); + return (-1); + } + + return (acol); +} + + +/** + * VOT_TYPECOLUMN -- Determine the type column for the given table. + */ +static int +vot_typeColumn (handle_t tab) +{ + register int i = 0; + handle_t field; + char *ucd; + + + /* Loop through the FIELDs to find the type. Use a generous match. + */ + if (tcol < 0) { + for (field=vot_getFIELD(tab); field; field=vot_getNext(field),i++) { + ucd = vot_getAttr (field, "ucd"); + if (ucd && strcasestr (ucd, fmt_ucd)) { + tcol = i; + break; + } + } + } + + return (tcol); +} + + +/** + * VOT_GETACLIST -- Download all the files for the specified thread. + */ +static void * +vot_getAclist (void *arg) +{ + register int i, j, done = 0, ret = 0; + int threadNum = 0; + + + if (arg) + threadNum = *(int *)arg; + + for (i=0; i < nfiles; i++) { + if (aclist[i].tnum == threadNum) { + for (j=0; j < maxTrys; j++) { + if ((ret = vot_getData (aclist[i].url, aclist[i].fname))) + break; + } + done += ret; + } + } + +/* + pthread_exit (NULL); +*/ + return ((void *) NULL); +} + + +/** + * VOT_GETDATA -- Utility routine to do a simple URL download to the file. + */ +static int +vot_getData (char *url, char *ofname) +{ + int stat = 0; + char lockfile[SZ_FNAME], dot[SZ_FNAME], errBuf[CURL_ERROR_SIZE]; + char fname[SZ_FNAME], ffname[SZ_FNAME]; + FILE *fd; + CURL *curl_handle; + + + /* FIXME */ + if (extn) + sprintf (ffname, "%s.%s", ofname, extn); + else { + sprintf (ffname, "%s.fits", ofname); + } + + if (access (ofname, F_OK) == 0 || access (ffname, F_OK) == 0) { + /* file already exists */ + if (force) + unlink (ofname); + else + return (1); + } + + + /* Initialize the lock file. + */ + memset (lockfile, 0, SZ_FNAME); + memset (dot, 0, SZ_FNAME); + + sprintf (lockfile, ".%s.LOCK", ofname); + sprintf (dot, ".%s", ofname); + + if (access (lockfile, F_OK) == 0 && access (dot, F_OK) < 0) { + /* Download currently in progress, perhaps on another thread? + */ + return (0); + } else if (access (lockfile, F_OK) == 0 && access (dot, F_OK) == 0) { + /* Download complete, stray lockfile. + */ + unlink (lockfile); + } else if (access (lockfile, F_OK) < 0) { + /* No lock file, create one. + */ + creat (lockfile, O_CREAT); + } + + + /* Append filename extension if specified. + */ + if (extn) + sprintf (fname, "%s.%s", ofname, extn); + else + strcpy (fname, ofname); + + + /* For the CURL operation to download the file. + */ + curl_global_init (CURL_GLOBAL_ALL); /* init curl session */ + curl_handle = curl_easy_init (); + + /* Open the output file. + */ + if ((fd = fopen (fname, "wb")) == NULL) { + if (verbose) + fprintf (stderr, "Error: cannot open output file '%s'\n", fname); + curl_easy_cleanup (curl_handle); + return 0; + } + + /* Set cURL options + */ + curl_easy_setopt (curl_handle, CURLOPT_URL, url); + curl_easy_setopt (curl_handle, CURLOPT_NOPROGRESS, 1L); + curl_easy_setopt (curl_handle, CURLOPT_WRITEDATA, fd); + curl_easy_setopt (curl_handle, CURLOPT_ERRORBUFFER, errBuf); + curl_easy_setopt (curl_handle, CURLOPT_FOLLOWLOCATION, 1); + + /* Do the download. + */ + if ((stat = curl_easy_perform (curl_handle)) != 0) { + /* Error in download, clean up. + */ + if (verbose) + fprintf (stderr, "Error: can't download '%s' : %s\n", url, errBuf); + unlink (fname); unlink (lockfile); + fclose (fd); /* close the file */ + curl_easy_cleanup (curl_handle); /* cleanup curl stuff */ + return (0); + } + + fflush (fd); + fclose (fd); /* close the file */ + curl_easy_cleanup (curl_handle); /* cleanup curl stuff */ + + /* Save the URL to a "dotfile" is we're downloading to a cache. + */ + if (isCache) { + if ((fd = fopen (dot, "w")) == NULL) { /* open cache file */ + if (verbose) + fprintf (stderr, "Error: cannot open cache file '%s'\n", dot); + return 0; + } + fprintf (fd, "%s\n", url); + fclose (fd); + } + + /* If we didn't specify an extension, try to determin the file type + * automatically. + */ + if (!extn) { + int i = 0, dfd, maxtrys = 30; + + if ((dfd = open (fname, O_RDONLY)) > 0) { + char buf[1024], new[SZ_FNAME]; + unsigned short *s = (unsigned short *) NULL; + + (void) read (dfd, buf, 1024); + + s = (unsigned short *) buf; + memset (new, 0, SZ_FNAME); + if ((s[0] == 35615 && s[1] == 2056) || /* GZIP file */ + (s[0] == 8075 && s[1] == 2048)) { + char gz[SZ_FNAME], cmd[SZ_FNAME]; + + memset (gz, 0, SZ_FNAME); + sprintf (gz, "%s.gz", fname); + memset (cmd, 0, SZ_FNAME); + sprintf (cmd, "gunzip %s", gz); + + rename (fname, gz); /* FIXME !!! */ + system (cmd); + + close (dfd); + if ((dfd = open (fname, O_RDONLY)) > 0) { + (void) lseek (dfd, 0, SEEK_SET); + (void) read (dfd, buf, 1024); + } + } + + memset (new, 0, SZ_FNAME); + if (strncmp ("SIMPLE", buf, 6) == 0) { /* FITS */ + sprintf (new, "%s.fits", fname); + rename (fname, new); + for (i=0; i < maxtrys; i++) { + if (access (new, F_OK) != 0) + sleep (1); + } + } + + close (dfd); + } + } + + pthread_mutex_lock (&counter_mut); + ngot++; + if (verbose) { + fprintf (stderr, "Downloaded %d of %d files ....\r", ngot, nfiles); + fflush (stderr); + } + pthread_mutex_unlock (&counter_mut); + + /* Remove the lock file to indicate we are done. + */ + unlink (lockfile); + + return (1); +} + + + +/****************************************************************************** +** Debug Utilities +******************************************************************************/ + +/** + * VOT_GETACLIST -- Download all the files for the specified thread. + */ +static void +vot_printAclist () +{ + register int i; + + fprintf (stderr, "\nAccess List: nfiles = %d\n", nfiles); + for (i=0; i < nfiles; i++) { + fprintf (stderr, "%2d: url='%20.20s...' fname='%s' tnum=%d\n", + i, aclist[i].url, aclist[i].fname, aclist[i].tnum); + } +} |