GRASS Programmer's Manual  6.4.2(2012)
gem/main.c
Go to the documentation of this file.
00001 
00002 /***************************************************************************
00003  *            main.c
00004  *
00005  *  Mon Apr 18 15:19:04 2005
00006  *  Copyright  2005  Benjamin Ducke
00007  ****************************************************************************/
00008 
00009 /*
00010  *  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with this program; if not, write to the Free Software
00022  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
00023  */
00024 
00025 
00026 /* TODO:
00027 
00028    for 1.04:                    
00029 
00030    EASY STUFF:
00031 
00032 
00033    - tried to install GeneralStatistics w/o first installing RasterTools or anything else: attempts to install, fails because
00034    of missing raster tools headers! Even though line 379 in reg_deps.c should check for this case !!!
00035 
00036    - include $GISBASE/lib in linker path for compilation of extensions [NOT FIXED: see lines preceeding INSTALL action case: 693
00037    -L is added to command line, but problems still exist]
00038    MAYBE EXPORT LD_LIBRARY_PATH ??? (only add $GISBASE/lib if it does not already exist)
00039 
00040    - version number in HTML documentation index seems to not get updated when installing a newer version of an extension
00041 
00042    - remember to update version number in globals.h
00043 
00044 
00045    for 1.2 (GRASS 6.4 ?):
00046    - make GRASS store its ./configure command line options in a file in the GISBASE/etc directory, so that
00047    it will be possible for GEM to automatically configure extensions according to the system setup
00048    [this means that configure file needs to be kept in sync with GEM; --configure option can be used
00049    to overwrite this behaviour]
00050    - configure script should not fail but disable options and create config.msgs the
00051    contents of this should be displayed and deleted afterwards
00052    - check if it works with this Mac version of GRASS, as well: http://openosx.com/grass/
00053    - before release: any problems expected with native Win32-Kompilation?:
00054    - location for tmp-files?
00055    - a simple wrapper g.install with GRASS style parameters. Should start an xterm and ask for su pwd,
00056    if necessary
00057    - action to check dependencies of installed extensions
00058    - instead of aborting on each failed dependency: build list of all failed
00059    dependencies before aborting
00060    - mechanism to recursively download and install missing deps from a
00061    provided list of URLs
00062    - instead of calling external tar, switch to tarlib and zlib
00063    - action --validate for checking an extension archive/dir
00064    - add link to HTML help index into each extension's submenu in GIS Manager
00065    - g.install with a real custom-made GUI
00066    [VARIABLE GUI must be set appropriately in run_post() for post script]        
00067    this should be an independent Tcl/Tk GUI: install/uninstall/query extensions
00068    - extension database on the internet that can be queried and used with either gem
00069    or g.install
00070    - entries for QGIS
00071    - simplified scheme for installing just a single module
00072    - new scheme for registering menu entries in GIS Manager with stable hooks in menu.tcl
00073 
00074 
00075    NEED HELP
00076    - GRASS' make install installs all files BENEATH top level dir with UID
00077    set to benni !!! Is this intentional?
00078    - provide gem6x as link in /usr/local/bin as part of grass 6.x base install
00079    - description.html should not contain </body> or </html> as Rules.Make seems
00080    to append those ?
00081    - source install copies files COPYING README REQUIREMENTS.html to somewhere (but where?)
00082    -> into <extension>/src but where else ?     
00083    - menu.tcl in GRASS 6.0.0 has "all options 1", but 6.1 will have "all options $tmenu".
00084    How to cater for such things? Maybe in the future there should always be an
00085    Xtns menu provided by GIS Manager and always delimited by reliable tags
00086    - d.m window is a bit to small horizontally
00087 
00088    CAVEATS:
00089    - does not allow installation of different versions of the same extension within
00090    the same GRASS bin tree
00091    - does not have a real upgrading mechanism: option --upgrade has been disabled for now
00092    - restore cannot fix partially corrupted entries in HTML and TCL files
00093    - Links to other extension's modules will only work if those extensions are installed
00094 
00095    DOCS:
00096 
00097    - skeleton contains GPL as default license. Creators of new extensions
00098    need to be aware of this!
00099 
00100    - menu.tcl will be backed up as menu.tcl.gem.bak
00101 
00102    - HTML docs: users must prefix references to GRASS modules outside the Extension with
00103    "../../html/" !!!    
00104    - description files: things inside "<" and ">" will be filtered out as HTML tags, even
00105    if they are none!
00106    - make clear that there are some files which will be rendered both as text and HTML
00107    and therefore need things like <br> while others DO NOT (which ones?)!
00108 
00109    - configure script should not fail but disable options and create 'config.msgs'
00110    - deletes config.msg after display
00111 
00112    - State clearly that it is recommended to uninstall an older
00113    extension version before installing a new one. STATE CLEARLY that --upgrade is rather
00114    another version of --force than a real updating mechanism (RENAME to --newer)
00115    - document all env vars that gem sets
00116    - STATE CLEARLY, that users should not meddle with stuff in index.html, menu.tcl,
00117    gem-entries/ and docs/extensions/ !!!
00118    - provide a unix man page, ASCII and HTML documentation (write HTML and convert)
00119    - files in the skeleton should always be present, even if they do not containing
00120    information
00121    - make it clear, that uninstall and postinstall are run with su privileges! thus,
00122    author must make sure, that only objects in the GRASS install tree are affected
00123    - user may specify either file name or extension name for uninstall action
00124    - user may list installed extensions by using -q w/o filename. Explain
00125    what is meant by type (e.g. 'src')
00126    - uninstallation works only by extension name, NOT file name !
00127    - compiling extensions on a GRASS install with all but the most basic options
00128    disabled should give very portable binaries! (statically linked binaries?)
00129 
00130    BUGS:
00131    - remove cva, install again: WARNING: list item 'cva' exists in index.html (?)
00132    - superfluous warning upon uninstall of extension w/o "entries-gisman"
00133    - due to bad command line parsing, listing installed extensions only works like this:
00134    ./gem64 --grass=/usr/local/grass-6.4.svn -q
00135    NOT like this:
00136    ./gem64 -q --grass=/usr/local/grass-6.4.svn
00137 
00138 
00139  */
00140 
00141 #include <getopt.h>
00142 #include <fcntl.h>
00143 
00144 #define LOCAL
00145 #include "globals.h"
00146 
00147 
00148 void show_help(void)
00149 {
00150     fprintf(stdout, "Usage: gem64 [OPTION] [ACTION] [FILE|DIR]\n");
00151     fprintf(stdout, "Install a GRASS extension from FILE or DIR.\n");
00152     fprintf(stdout, "Manage (installed) GRASS extension(s).\n");
00153     fprintf(stdout, "\nPossible ACTIONs are:\n");
00154     fprintf(stdout, "  -i, --install=EXT\tinstall a GRASS extension\n");
00155     fprintf(stdout,
00156             "  -u, --uninstall=EXT\tremove an extension from GRASS\n");
00157     fprintf(stdout,
00158             "  -q, --query=EXT\tdisplay information about extension/list installed\n");
00159     fprintf(stdout,
00160             "  -d, --details=EXT\tdisplay additional details about an extension\n");
00161     fprintf(stdout,
00162             "  -c, --clean=EXT\tclean extension's source code directories\n");
00163     fprintf(stdout,
00164             "  -t, --test=EXT\tconfigure and compile extension, but don't install\n");
00165     fprintf(stdout,
00166             "  -l, --license=EXT\tshow copyright information for an extension\n");
00167     fprintf(stdout,
00168             "  -r, --restore\t\trecreate HTML links and GIS Manager entries\n");
00169     fprintf(stdout, "  -h, --help\t\tdisplay this help and exit\n");
00170     fprintf(stdout,
00171             "  -V, --version\t\toutput version information and exit\n\n");
00172     fprintf(stdout, "\nPossible OPTIONs are:\n");
00173     fprintf(stdout, "  -g, --grass=PATH\tpath to GRASS installation dir\n");
00174     fprintf(stdout,
00175             "  -b, --binary=NAME\tno compilation: use binary files for system NAME\n");
00176     fprintf(stdout,
00177             "  -f, --force\t\tforce action, regardless of dependencies\n");
00178     fprintf(stdout,
00179             "  -v, --verbose\t\tdisplay detailed status information\n");
00180     fprintf(stdout, "  -s, --skip-config\tskip configure script\n");
00181     fprintf(stdout,
00182             "  -x, --config-opts=OPTS\tpass OPTS to configure script\n");
00183     fprintf(stdout,
00184             "  -o, --options=OPTS\toptions to pass to the C compiler/linker\n");
00185     fprintf(stdout,
00186             "  -C, --config-cmd=CMD\tDefine custom 'configure' command (default=configure)\n");
00187     fprintf(stdout,
00188             "  -m, --make-cmd=CMD\tDefine custom 'make' command (default=make)\n");
00189     fprintf(stdout,
00190             "\nWhen run from within a GRASS session, locations of libs, header files\n");
00191     fprintf(stdout,
00192             "and installation target dir will be assumed to match those of the active\n");
00193     fprintf(stdout, "GRASS version. ");
00194     fprintf(stdout,
00195             "Option -g can be used to override these or install extensions\nfrom outside");
00196     fprintf(stdout, "of a GRASS session.\n");
00197     fprintf(stdout,
00198             "Per default, extensions will be compiled from source and then installed.\n");
00199     fprintf(stdout,
00200             "If the exension package contains binaries for the user's platform, they can\n");
00201     fprintf(stdout, "be installed instead using the -b option. ");
00202     fprintf(stdout,
00203             "For installation from source code, a C compiler and make tools are needed.\n");
00204     fprintf(stdout, "\nExample:\n");
00205     fprintf(stdout,
00206             "\tgem64 -b macosx --grass=/usr/local/grass-6.4.0 -i myExtension\n");
00207     fprintf(stdout,
00208             "Installs the MacOS X binaries for 'myExtension' in /usr/local/grass-6.4.0.\n");
00209     exit(0);
00210 }
00211 
00212 
00213 void show_details(char *package)
00214 {
00215     int error;
00216     char tmp[MAXSTR];
00217 
00218     sprintf(tmp, "%s", basename(package));
00219     error = chdir(tmp);
00220     if (error < 0) {
00221         print_error(ERR_NO_ACCESS_EXT,
00222                     "extension '%s' not accessible: (%s)\n", package,
00223                     strerror(errno));
00224     }
00225 
00226     dump_ascii("info", "Detailed information");
00227 
00228 
00229     /* run post action script */
00230     system("sh post");
00231 
00232     exit(0);
00233 }
00234 
00235 
00236 void show_license(char *package)
00237 {
00238     int error;
00239     char tmp[MAXSTR];
00240 
00241     sprintf(tmp, "%s", basename(package));
00242     error = chdir(tmp);
00243     if (error < 0) {
00244         print_error(ERR_NO_ACCESS_EXT,
00245                     "extension '%s' not accessible: (%s)\n", package,
00246                     strerror(errno));
00247     }
00248 
00249     dump_ascii("license", "Detailed information");
00250 
00251     /* run post action script */
00252     system("sh post");
00253 
00254     exit(0);
00255 }
00256 
00257 
00258 void show_version(void)
00259 {
00260     fprintf(stdout, "gem64 (GRASS extensions manager) %.2f\n", PROGVERSION);
00261     fprintf(stdout, "Written by Benjamin Ducke\n");
00262     fprintf(stdout, "\nCopyright (C) 2005 Benjamin Ducke\n");
00263     fprintf(stdout,
00264             "This is free software; see the source for copying conditions.  There is NO\n");
00265     fprintf(stdout,
00266             "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
00267     exit(0);
00268 }
00269 
00270 
00271 /* determine options to pass to extension's configure script */
00272 /* TODO: check, if system configuration meets a set of requirements */
00273 /* THIS FUNCTION IS CURRENTLY NOT USED */
00274 void get_configure_options(char *gisbase)
00275 {
00276 
00277     FILE *fp;
00278     char str[MAXSTR];
00279 
00280     if (strcmp(CONFIG_OPTS, "")) {
00281         /* if user has specified config options on the GEM command line: override anything else */
00282         return;
00283     }
00284 
00285     /* check if GISBASE/etc/config.system exists and if so, read options from it */
00286     sprintf(str, "%s/etc/config.system", gisbase);
00287     fp = fopen(str, "r");
00288     if (fp == NULL) {
00289         print_warning
00290             ("could not open %s for read access. Using default configure options.\n",
00291              str);
00292         return;
00293     }
00294 
00295     /* config.system may also contain nothing, only comments and/or whitespace */
00296     if (nc_fgets_nb(str, MAXSTR, fp) != NULL) {
00297         strcpy(CONFIG_OPTS, str);
00298     }
00299 }
00300 
00301 
00302 int main(int argc, char *argv[])
00303 {
00304     char *gisbase;
00305     char *grass_version;
00306     char *grass_major;
00307     char *grass_minor;
00308     char *grass_revision;
00309     char *tmp;
00310     char *url;
00311     char *filepart;
00312     char version_file[MAXSTR];
00313     char package[MAXSTR];
00314     char orgname[MAXSTR];
00315     char pkg_name[MAXSTR];
00316     char *bins;
00317     int pkg_major, pkg_minor, pkg_revision;
00318     FILE *f;
00319     int fd;
00320 
00321     char pkg_short_name[MAXSTR];
00322     char invocation[MAXSTR];
00323 
00324     char coptions[MAXSTR];
00325 
00326     int major, minor, revision;
00327     int option;
00328     int action;
00329     int valid;
00330 
00331     struct stat buf;
00332     struct stat buf2;
00333     int error;
00334     int is_directory = 0;
00335     DIR *dir;
00336     struct dirent *dir_entry;
00337     int dir_found;
00338 
00339     int option_index = 0;
00340     static struct option long_options[] = {
00341         {"install", 1, NULL, 'i'},
00342         {"uninstall", 1, NULL, 'u'},
00343         {"query", 2, NULL, 'q'},
00344         {"details", 1, NULL, 'd'},
00345         {"clean", 1, NULL, 'c'},
00346         {"test", 1, NULL, 't'},
00347         {"license", 1, NULL, 'l'},
00348         {"restore", 0, NULL, 'r'},
00349         {"help", 0, NULL, 'h'},
00350         {"version", 0, NULL, 'V'},
00351 
00352         {"grass", 1, NULL, 'g'},
00353         {"options", 1, NULL, 'o'},
00354         {"binary", 1, NULL, 'b'},
00355         {"force", 0, NULL, 'f'},
00356         {"verbose", 0, NULL, 'v'},
00357         {"skip-config", 0, NULL, 's'},
00358         {"config-opts", 1, NULL, 'x'},
00359 
00360         {"config-cmd", 1, NULL, 'C'},
00361         {"make-cmd", 1, NULL, 'm'},
00362 
00363         {0, 0, 0, 0}
00364     };
00365 
00366 
00367     /* set global variables to defaults */
00368     VERBOSE = 0;
00369     TMPCLEAN = 0;
00370     TMPDBCLEAN = 0;
00371     FORCE = 0;
00372     UPGRADE = 0;
00373     ERROR = 0;
00374     WARNINGS = 0;
00375     SKIP_CFG = 0;
00376 
00377     strcpy(GISMAN_CMD, "");
00378     strcpy(GISMAN2_CMD, "");
00379     strcpy(QGIS_CMD, "");
00380     strcpy(UNINSTALL_CMD, "");
00381     strcpy(HTML_CMD, "");
00382 
00383     strcpy(TMPDIR, "");
00384     strcpy(TMPDB, "");
00385     strcpy(TMP_GISMAN, "");
00386     strcpy(TMP_DESCR, "");
00387     strcpy(TMP_INFO, "");
00388     strcpy(TMP_DEPS, "");
00389     strcpy(TMP_BUGS, "");
00390     strcpy(TMP_AUTHORS, "");
00391     strcpy(TMP_HTML, "");
00392     strcpy(TMP_NULL, "");
00393 
00394     strcpy(CONFIG_OPTS, "");
00395 
00396     strcpy(CONFIG_CMD, "configure");
00397     strcpy(MAKE_CMD, "make");
00398 
00399     getcwd(CWD, MAXSTR);
00400 
00401     /* reset terminal colors */
00402     fprintf(stdout, "\033[0m");
00403 
00404     tmp = malloc(sizeof(char) * MAXSTR);
00405     strcpy(invocation, argv[0]);
00406 
00407     /* all output should be unbuffered */
00408     setvbuf(stdout, (char *)NULL, _IONBF, 0);
00409 
00410     /* if run with no arguments: show help */
00411     if (argc == 1) {
00412         /* show usage info and exit */
00413         show_help();
00414         exit(0);
00415     }
00416 
00417     atexit(&exit_msg);          /* show a message after program termination */
00418 
00419     valid = 0;
00420     bins = NULL;
00421     gisbase = NULL;
00422 
00423     opterr = 0;
00424     option =
00425         getopt_long(argc, argv, ":i:u:q:d:c:C:t:l:m:o:x:rhVg:b:fvs",
00426                     long_options, &option_index);
00427     while (option != -1) {
00428 
00429         if (option == '?') {
00430             print_error(ERR_INVOCATION,
00431                         "unknown option or action specified.\n");
00432         }
00433 
00434 
00435         /* check for missing arguments */
00436         if (option == ':') {
00437             if ((optopt == 'i') || (optopt == 'u') || (optopt == 'd') ||
00438                 (optopt == 'c') || (optopt == 't') || (optopt == 'l') ||
00439                 (optopt == 'r')) {
00440                 print_error(ERR_INVOCATION,
00441                             "missing file or directory name.\n");
00442             }
00443             if (optopt == 'g') {
00444                 print_error(ERR_INVOCATION, "missing path to GRASS 6.\n");
00445             }
00446             if (optopt == 'b') {
00447                 print_error(ERR_INVOCATION,
00448                             "missing name of binary architecture.\n");
00449             }
00450             if (optopt == 'b') {
00451                 print_error(ERR_INVOCATION, "missing configure options.\n");
00452             }
00453             if (optopt == 'q') {
00454                 /* '-q' w/o filename is list action */
00455                 action = LIST;
00456                 valid++;
00457                 break;
00458             }
00459         }
00460 
00461         if ((option == 'i') || (option == 'u') || (option == 'q') ||
00462             (option == 'd') || (option == 'c') || (option == 't') ||
00463             (option == 'l') || (option == 'r') || (option == 'h') ||
00464             (option == 'V')) {
00465             /* got a valid action specifier */
00466             valid++;
00467             /* set action accordingly */
00468             switch (option) {
00469             case 'i':
00470                 if (action != BIN_INSTALL) {
00471                     action = INSTALL;
00472                 }
00473                 break;
00474             case 'u':
00475                 action = UNINSTALL;
00476                 break;
00477             case 'q':
00478                 action = QUERY;
00479                 break;
00480             case 'd':
00481                 action = DETAILS;
00482                 break;
00483             case 'c':
00484                 action = CLEAN;
00485                 break;
00486             case 't':
00487                 action = TEST_INSTALL;
00488                 break;
00489             case 'l':
00490                 action = LICENSE;
00491                 break;
00492             case 'r':
00493                 action = RESTORE;
00494                 break;
00495             case 'h':
00496                 action = HELP;
00497                 break;
00498             case 'V':
00499                 action = VERSION;
00500                 break;
00501             }
00502             if (optarg != NULL) {
00503                 /* save package name as given on command line */
00504                 strcpy(package, optarg);
00505                 /* orgname will always preserve the commandline option */
00506                 strcpy(orgname, optarg);
00507             }
00508         }
00509 
00510         /* set options */
00511         if (option == 'g') {
00512             gisbase = malloc(sizeof(char) * (strlen(optarg) + 1));
00513             strcpy(gisbase, optarg);
00514         }
00515         if (option == 'b') {
00516             bins = malloc(sizeof(char) * (strlen(optarg) + 1));
00517             strcpy(bins, optarg);
00518             action = BIN_INSTALL;
00519         }
00520         if (option == 'x') {
00521             /* configure script options */
00522             strcpy(&CONFIG_OPTS[0], optarg);
00523         }
00524 
00525         if (option == 'f') {
00526             FORCE = 1;
00527         }
00528         if (option == 'v') {
00529             VERBOSE = 1;
00530         }
00531 
00532         if (option == 's') {
00533             SKIP_CFG = 1;
00534         }
00535         if (option == 'o') {
00536             /* GEM_C_OPTS gets passed to the C compiler via the GRASS/GEM Makefiles:
00537                <EXT>/src/include/Make/Grass.make.in:
00538                CFLAGS      =  $(INC) $(COMPILE_FLAGS) $(USE_TERMIO) $(GEM_C_OPTS)
00539              */
00540             strcat(coptions, optarg);
00541         }
00542         /* define a custom configure command */
00543         if (option == 'C') {
00544             strcpy(CONFIG_CMD, optarg);
00545         }
00546         /* define a custom make command */
00547         if (option == 'm') {
00548             strcpy(MAKE_CMD, optarg);
00549         }
00550         /* get next option from command line */
00551         option =
00552             getopt_long(argc, argv, ":i:u:q:d:c:t:l:o:x:rhVg:b:fvs",
00553                         long_options, &option_index);
00554     }
00555 
00556 
00557     if (valid < 1) {
00558         print_error(ERR_INVOCATION, "please specify a valid action.\n");
00559     }
00560     if (valid > 1) {
00561         print_error(ERR_INVOCATION, "please specify only one action.\n");
00562     }
00563 
00564     /* export compiler options for use by Makefiles */
00565     sprintf(GEM_C_OPTS, "GEM_C_OPTS=%s", coptions);
00566     putenv(GEM_C_OPTS);
00567 
00568     /* these actions can be done without any extension checking */
00569     if (action == HELP) {
00570         /* show usage info and exit */
00571         show_help();
00572         exit(0);
00573     }
00574 
00575     if (action == VERSION) {
00576         /* show version info and exit */
00577         show_version();
00578         exit(0);
00579     }
00580 
00581     if (!VERBOSE) {
00582         /* set temp file to pipe output to for silent operation */
00583         /* TODO: Do not hardcode temp paths */
00584         strcpy(TMP_NULL, "/tmp/grass.extension.log.XXXXXX");    /* TMP_NULL is a global variable */
00585         mkstemp(TMP_NULL);
00586         fd = open(TMP_NULL, O_CREAT, 0777);
00587         if (fd == -1) {
00588             print_error(ERR_TMPFILE, "could not create temp file: %s",
00589                         strerror(errno));
00590             exit(ERR_TMPFILE);
00591         }
00592     }
00593 
00594 
00595     /* these actions need a valid GRASS path but no extensions */
00596     if (action == RESTORE) {
00597         /* figure out path to GRASS installation */
00598         /* GIS base not given? */
00599         if (gisbase == NULL) {
00600             /* try to read from GRASS environment */
00601             gisbase = getenv("GISBASE");
00602             if (gisbase == NULL) {
00603                 /* still NULL? Abort! */
00604                 print_error(ERR_INVOCATION,
00605                             "GISBASE environment variable not set and path to GRASS not given.\n");
00606             }
00607         }
00608 
00609         if (VERBOSE) {
00610             fprintf(stdout, "Path to GRASS is %s.\n", gisbase);
00611         }
00612 
00613         restore(gisbase, grass_version);
00614         exit(0);
00615     }
00616 
00617     if (action == LIST) {
00618         /* figure out path to GRASS installation */
00619         /* GIS base not given? */
00620         if (gisbase == NULL) {
00621             /* try to read from GRASS environment */
00622             gisbase = getenv("GISBASE");
00623             if (gisbase == NULL) {
00624                 /* still NULL? Abort! */
00625                 print_error(ERR_INVOCATION,
00626                             "GISBASE environment variable not set and path to GRASS not given.\n");
00627             }
00628         }
00629 
00630         if (VERBOSE) {
00631             fprintf(stdout, "Path to GRASS is %s.\n", gisbase);
00632         }
00633         list_extensions(gisbase);
00634         exit(0);
00635     }
00636 
00637     /* check if extension is stored in a remote URL */
00638     if ((strstr(package, "http://")) || (strstr(package, "ftp://"))) {
00639         wget_extension(package);        /* download into current dir using wget */
00640         /* cut off the path specification */
00641         url = malloc(sizeof(char) * MAXSTR);
00642         strcpy(url, package);
00643         filepart = strrchr(url, '/');
00644         filepart++;
00645         strcpy(package, filepart);
00646         free(url);
00647     }
00648 
00649     if (VERBOSE) {
00650         fprintf(stdout, "Extension location is '%s'.\n", package);
00651     }
00652 
00653     if (action != UNINSTALL) {
00654         error = stat(package, &buf);
00655         if (error < 0) {
00656             print_error(ERR_NO_ACCESS_EXT,
00657                         "extension FILE or DIR '%s' invalid: %s\n", package,
00658                         strerror(errno));
00659         }
00660         if (S_ISDIR(buf.st_mode)) {
00661             is_directory = 1;
00662             if (VERBOSE) {
00663                 fprintf(stdout, "Extension files stored in a directory.\n");
00664             }
00665         }
00666         else {
00667             if (VERBOSE) {
00668                 fprintf(stdout,
00669                         "Extension files stored in a package file.\n");
00670             }
00671             /* DECOMPRESS INTO TEMP DIR, CHANGE NAME OF package TO THAT DIR */
00672             unpack_extension(package);
00673             /* find name of directory containing extension files */
00674             /* very primitive: just picks the first directory */
00675             dir = opendir(TMPDIR);
00676             dir_entry = readdir(dir);
00677             dir_found = 0;
00678             while (dir_entry != NULL) {
00679                 if ((strcmp(dir_entry->d_name, ".")) &&
00680                     (strcmp(dir_entry->d_name, ".."))
00681                     ) {
00682                     /* check if it is a directory */
00683                     sprintf(tmp, "%s/%s", TMPDIR, dir_entry->d_name);
00684                     stat(tmp, &buf2);
00685                     if (S_ISDIR(buf2.st_mode)) {
00686                         dir_found = 1;
00687                         break;
00688                     }
00689                 }
00690                 dir_entry = readdir(dir);
00691             }
00692             strcpy(package, tmp);
00693 
00694             if (dir_found == 0) {
00695                 print_error(ERR_UNPACK_EXT,
00696                             "no top-level directory found in extension package.\n");
00697             }
00698         }
00699     }
00700 
00701     /* copy package name into this maliciously named variable */
00702     /* (sorry about the mess ...) */
00703     /* This name will be used for all registration actions and */
00704     /* for creating files and directories that store extension */
00705     /* information for uninstall and restore actions */
00706     /* For uninstall, we take the last argument as package, NOT */
00707     /* file name */
00708     if (action == UNINSTALL) {
00709         strcpy(pkg_short_name, package);
00710     }
00711     else {
00712         get_package_name(package, pkg_short_name);
00713     }
00714 
00715     /* export relevant VARS for use by post script */
00716     if (valid > 0) {
00717         /* export all relevant env vars for the post script */
00718         if (gisbase == NULL) {
00719             /* try to read from GRASS environment */
00720             gisbase = getenv("GISBASE");
00721         }
00722         run_post(package, action, bins, gisbase);
00723     }
00724 
00725     if (VERBOSE) {
00726         fprintf(stdout, "Extension will be installed from '%s'\n", package);
00727     }
00728 
00729     /* CHECK PACKAGE FOR VALIDITY */
00730     if (action != UNINSTALL) {
00731         check_extension(package, pkg_name, &pkg_major, &pkg_minor,
00732                         &pkg_revision);
00733     }
00734 
00735     /* these actions can be done without GRASS checking */
00736     if (action == QUERY) {
00737         query_extension(package, pkg_name, pkg_major, pkg_minor, pkg_revision,
00738                         pkg_short_name, invocation, orgname);
00739         exit(0);
00740     }
00741 
00742     if (action == DETAILS) {
00743         show_details(package);
00744         exit(0);
00745     }
00746 
00747     if (action == LICENSE) {
00748         show_license(package);
00749         exit(0);
00750     }
00751 
00752     if (action == CLEAN) {
00753         source_clean(package);
00754         exit(0);
00755     }
00756 
00757 
00758     /* The following checks need to be done for all other actions! */
00759 
00760     /* figure out path to GRASS installation */
00761     /* GIS base not given? */
00762     if (gisbase == NULL) {
00763         /* try to read from GRASS environment */
00764         gisbase = getenv("GISBASE");
00765         if (gisbase == NULL) {
00766             /* still NULL? Abort! */
00767             print_error(ERR_INVOCATION,
00768                         "GISBASE environment variable not set and path to GRASS not given.\n");
00769         }
00770     }
00771 
00772     if (VERBOSE) {
00773         fprintf(stdout, "Path to GRASS is %s.\n", gisbase);
00774     }
00775 
00776     /* figure out GRASS version */
00777     grass_version = getenv("GRASS_VERSION");
00778     if (grass_version == NULL) {
00779         /* GRASS version can be read from gisbase/etc/VERSIONNUMBER */
00780         sprintf(version_file, "%s/etc/VERSIONNUMBER", gisbase);
00781         f = fopen(version_file, "r");
00782         if (f == NULL) {
00783             /* still NULL? Abort! */
00784             print_error(ERR_VERSION,
00785                         "Could not read GRASS version. Did you specify the right path?\n");
00786         }
00787         else {
00788             grass_version = malloc(sizeof(char) * 16);
00789             error = fscanf(f, "%s", grass_version);
00790             fclose(f);
00791             if (error < 1) {
00792                 print_error(ERR_VERSION,
00793                             "Could not read GRASS version. Did you specify the right path?\n");
00794             }
00795         }
00796     }
00797 
00798     if (grass_version != NULL) {
00799         /* extract major and minor version numbers */
00800         tmp = strdup(grass_version);
00801 
00802         grass_major = strtok(tmp, ".");
00803         grass_minor = strtok(NULL, ".");
00804         grass_revision = strtok(NULL, ".");
00805 
00806         major = strtol(grass_major, NULL, 10);
00807         minor = strtol(grass_minor, NULL, 10);
00808         revision = strtol(grass_revision, NULL, 10);
00809 
00810         grass_version = malloc(sizeof(char) * MAXSTR);
00811         sprintf(grass_version, "%i.%i.%i", major, minor, revision);
00812         if (VERBOSE) {
00813             fprintf(stdout, "GRASS version is %s.\n", grass_version);
00814         }
00815 
00816         if (major < 6) {
00817             print_error(ERR_VERSION,
00818                         "extensions only work with GRASS version 6 and above.\n");
00819         }
00820     }
00821 
00822     /* for GDAL compatibility and           
00823        for the sake of people using Lorenzo Moretti's GRASS for MacOS, we always export the following
00824        compiler options */
00825     sprintf(coptions, "-L%s/lib -I/usr/local/grasslib/include/ ", gisbase);
00826 
00827     /* these actions can only be done after everything has been checked */
00828     if (action == INSTALL) {
00829         source_install(package, gisbase, pkg_short_name, pkg_major, pkg_minor,
00830                        pkg_revision, grass_version);
00831         exit(0);
00832     }
00833 
00834     if (action == UNINSTALL) {
00835         uninstall(package, pkg_short_name, gisbase, grass_version);
00836         exit(0);
00837     }
00838 
00839     if (action == TEST_INSTALL) {
00840         test_install(package, gisbase, pkg_short_name, pkg_major, pkg_minor,
00841                      pkg_revision, grass_version);
00842         exit(0);
00843     }
00844 
00845     if (action == BIN_INSTALL) {
00846         if (binaries_exist(package, bins)) {
00847             bin_install(package, gisbase, bins, pkg_short_name, pkg_major,
00848                         pkg_minor, pkg_revision, grass_version);
00849             exit(0);
00850         }
00851         else {
00852             print_error(ERR_MISSING_BINS, "no binaries for system '%s'\n",
00853                         bins);
00854         }
00855     }
00856 
00857     exit(0);
00858 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines