GRASS Programmer's Manual
6.4.2(2012)
|
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 }