|
GRASS Programmer's Manual
6.5.svn(2012)-r51648
|
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 ./gem65 --grass=/usr/local/grass-6.5.svn -q 00135 NOT like this: 00136 ./gem65 -q --grass=/usr/local/grass-6.5.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: gem65 [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 "\tgem65 -b macosx --grass=/usr/local/grass-6.5.0 -i myExtension\n"); 00207 fprintf(stdout, 00208 "Installs the MacOS X binaries for 'myExtension' in /usr/local/grass-6.5.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, "gem65 (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 strncpy(invocation, argv[0], MAXSTR); 00406 invocation[MAXSTR-1] = '\0'; 00407 00408 /* all output should be unbuffered */ 00409 setvbuf(stdout, (char *)NULL, _IONBF, 0); 00410 00411 /* if run with no arguments: show help */ 00412 if (argc == 1) { 00413 /* show usage info and exit */ 00414 show_help(); 00415 exit(0); 00416 } 00417 00418 atexit(&exit_msg); /* show a message after program termination */ 00419 00420 valid = 0; 00421 bins = NULL; 00422 gisbase = NULL; 00423 00424 opterr = 0; 00425 option = 00426 getopt_long(argc, argv, ":i:u:q:d:c:C:t:l:m:o:x:rhVg:b:fvs", 00427 long_options, &option_index); 00428 while (option != -1) { 00429 00430 if (option == '?') { 00431 print_error(ERR_INVOCATION, 00432 "unknown option or action specified.\n"); 00433 } 00434 00435 00436 /* check for missing arguments */ 00437 if (option == ':') { 00438 if ((optopt == 'i') || (optopt == 'u') || (optopt == 'd') || 00439 (optopt == 'c') || (optopt == 't') || (optopt == 'l') || 00440 (optopt == 'r')) { 00441 print_error(ERR_INVOCATION, 00442 "missing file or directory name.\n"); 00443 } 00444 if (optopt == 'g') { 00445 print_error(ERR_INVOCATION, "missing path to GRASS 6.\n"); 00446 } 00447 if (optopt == 'b') { 00448 print_error(ERR_INVOCATION, 00449 "missing name of binary architecture.\n"); 00450 } 00451 if (optopt == 'b') { 00452 print_error(ERR_INVOCATION, "missing configure options.\n"); 00453 } 00454 if (optopt == 'q') { 00455 /* '-q' w/o filename is list action */ 00456 action = LIST; 00457 valid++; 00458 break; 00459 } 00460 } 00461 00462 if ((option == 'i') || (option == 'u') || (option == 'q') || 00463 (option == 'd') || (option == 'c') || (option == 't') || 00464 (option == 'l') || (option == 'r') || (option == 'h') || 00465 (option == 'V')) { 00466 /* got a valid action specifier */ 00467 valid++; 00468 /* set action accordingly */ 00469 switch (option) { 00470 case 'i': 00471 if (action != BIN_INSTALL) { 00472 action = INSTALL; 00473 } 00474 break; 00475 case 'u': 00476 action = UNINSTALL; 00477 break; 00478 case 'q': 00479 action = QUERY; 00480 break; 00481 case 'd': 00482 action = DETAILS; 00483 break; 00484 case 'c': 00485 action = CLEAN; 00486 break; 00487 case 't': 00488 action = TEST_INSTALL; 00489 break; 00490 case 'l': 00491 action = LICENSE; 00492 break; 00493 case 'r': 00494 action = RESTORE; 00495 break; 00496 case 'h': 00497 action = HELP; 00498 break; 00499 case 'V': 00500 action = VERSION; 00501 break; 00502 } 00503 if (optarg != NULL) { 00504 /* save package name as given on command line */ 00505 strcpy(package, optarg); 00506 /* orgname will always preserve the commandline option */ 00507 strcpy(orgname, optarg); 00508 } 00509 } 00510 00511 /* set options */ 00512 if (option == 'g') { 00513 gisbase = malloc(sizeof(char) * (strlen(optarg) + 1)); 00514 strcpy(gisbase, optarg); 00515 } 00516 if (option == 'b') { 00517 bins = malloc(sizeof(char) * (strlen(optarg) + 1)); 00518 strcpy(bins, optarg); 00519 action = BIN_INSTALL; 00520 } 00521 if (option == 'x') { 00522 /* configure script options */ 00523 strcpy(&CONFIG_OPTS[0], optarg); 00524 } 00525 00526 if (option == 'f') { 00527 FORCE = 1; 00528 } 00529 if (option == 'v') { 00530 VERBOSE = 1; 00531 } 00532 00533 if (option == 's') { 00534 SKIP_CFG = 1; 00535 } 00536 if (option == 'o') { 00537 /* GEM_C_OPTS gets passed to the C compiler via the GRASS/GEM Makefiles: 00538 <EXT>/src/include/Make/Grass.make.in: 00539 CFLAGS = $(INC) $(COMPILE_FLAGS) $(USE_TERMIO) $(GEM_C_OPTS) 00540 */ 00541 strcat(coptions, optarg); 00542 } 00543 /* define a custom configure command */ 00544 if (option == 'C') { 00545 strcpy(CONFIG_CMD, optarg); 00546 } 00547 /* define a custom make command */ 00548 if (option == 'm') { 00549 strcpy(MAKE_CMD, optarg); 00550 } 00551 /* get next option from command line */ 00552 option = 00553 getopt_long(argc, argv, ":i:u:q:d:c:t:l:o:x:rhVg:b:fvs", 00554 long_options, &option_index); 00555 } 00556 00557 00558 if (valid < 1) { 00559 print_error(ERR_INVOCATION, "please specify a valid action.\n"); 00560 } 00561 if (valid > 1) { 00562 print_error(ERR_INVOCATION, "please specify only one action.\n"); 00563 } 00564 00565 /* export compiler options for use by Makefiles */ 00566 sprintf(GEM_C_OPTS, "GEM_C_OPTS=%s", coptions); 00567 putenv(GEM_C_OPTS); 00568 00569 /* these actions can be done without any extension checking */ 00570 if (action == HELP) { 00571 /* show usage info and exit */ 00572 show_help(); 00573 exit(0); 00574 } 00575 00576 if (action == VERSION) { 00577 /* show version info and exit */ 00578 show_version(); 00579 exit(0); 00580 } 00581 00582 if (!VERBOSE) { 00583 /* set temp file to pipe output to for silent operation */ 00584 /* TODO: Do not hardcode temp paths */ 00585 strcpy(TMP_NULL, "/tmp/grass.extension.log.XXXXXX"); /* TMP_NULL is a global variable */ 00586 mkstemp(TMP_NULL); 00587 fd = open(TMP_NULL, O_CREAT, 0777); 00588 if (fd == -1) { 00589 print_error(ERR_TMPFILE, "could not create temp file: %s", 00590 strerror(errno)); 00591 exit(ERR_TMPFILE); 00592 } 00593 } 00594 00595 00596 /* these actions need a valid GRASS path but no extensions */ 00597 if (action == RESTORE) { 00598 /* figure out path to GRASS installation */ 00599 /* GIS base not given? */ 00600 if (gisbase == NULL) { 00601 /* try to read from GRASS environment */ 00602 gisbase = getenv("GISBASE"); 00603 if (gisbase == NULL) { 00604 /* still NULL? Abort! */ 00605 print_error(ERR_INVOCATION, 00606 "GISBASE environment variable not set and path to GRASS not given.\n"); 00607 } 00608 } 00609 00610 if (VERBOSE) { 00611 fprintf(stdout, "Path to GRASS is %s.\n", gisbase); 00612 } 00613 00614 restore(gisbase, grass_version); 00615 exit(0); 00616 } 00617 00618 if (action == LIST) { 00619 /* figure out path to GRASS installation */ 00620 /* GIS base not given? */ 00621 if (gisbase == NULL) { 00622 /* try to read from GRASS environment */ 00623 gisbase = getenv("GISBASE"); 00624 if (gisbase == NULL) { 00625 /* still NULL? Abort! */ 00626 print_error(ERR_INVOCATION, 00627 "GISBASE environment variable not set and path to GRASS not given.\n"); 00628 } 00629 } 00630 00631 if (VERBOSE) { 00632 fprintf(stdout, "Path to GRASS is %s.\n", gisbase); 00633 } 00634 list_extensions(gisbase); 00635 exit(0); 00636 } 00637 00638 /* check if extension is stored in a remote URL */ 00639 if ((strstr(package, "http://")) || (strstr(package, "ftp://"))) { 00640 wget_extension(package); /* download into current dir using wget */ 00641 /* cut off the path specification */ 00642 url = malloc(sizeof(char) * MAXSTR); 00643 strcpy(url, package); 00644 filepart = strrchr(url, '/'); 00645 filepart++; 00646 strcpy(package, filepart); 00647 free(url); 00648 } 00649 00650 if (VERBOSE) { 00651 fprintf(stdout, "Extension location is '%s'.\n", package); 00652 } 00653 00654 if (action != UNINSTALL) { 00655 error = stat(package, &buf); 00656 if (error < 0) { 00657 print_error(ERR_NO_ACCESS_EXT, 00658 "extension FILE or DIR '%s' invalid: %s\n", package, 00659 strerror(errno)); 00660 } 00661 if (S_ISDIR(buf.st_mode)) { 00662 is_directory = 1; 00663 if (VERBOSE) { 00664 fprintf(stdout, "Extension files stored in a directory.\n"); 00665 } 00666 } 00667 else { 00668 if (VERBOSE) { 00669 fprintf(stdout, 00670 "Extension files stored in a package file.\n"); 00671 } 00672 /* DECOMPRESS INTO TEMP DIR, CHANGE NAME OF package TO THAT DIR */ 00673 unpack_extension(package); 00674 /* find name of directory containing extension files */ 00675 /* very primitive: just picks the first directory */ 00676 dir = opendir(TMPDIR); 00677 dir_entry = readdir(dir); 00678 dir_found = 0; 00679 while (dir_entry != NULL) { 00680 if ((strcmp(dir_entry->d_name, ".")) && 00681 (strcmp(dir_entry->d_name, "..")) 00682 ) { 00683 /* check if it is a directory */ 00684 sprintf(tmp, "%s/%s", TMPDIR, dir_entry->d_name); 00685 stat(tmp, &buf2); 00686 if (S_ISDIR(buf2.st_mode)) { 00687 dir_found = 1; 00688 break; 00689 } 00690 } 00691 dir_entry = readdir(dir); 00692 } 00693 strcpy(package, tmp); 00694 00695 if (dir_found == 0) { 00696 print_error(ERR_UNPACK_EXT, 00697 "no top-level directory found in extension package.\n"); 00698 } 00699 } 00700 } 00701 00702 /* copy package name into this maliciously named variable */ 00703 /* (sorry about the mess ...) */ 00704 /* This name will be used for all registration actions and */ 00705 /* for creating files and directories that store extension */ 00706 /* information for uninstall and restore actions */ 00707 /* For uninstall, we take the last argument as package, NOT */ 00708 /* file name */ 00709 if (action == UNINSTALL) { 00710 strcpy(pkg_short_name, package); 00711 } 00712 else { 00713 get_package_name(package, pkg_short_name); 00714 } 00715 00716 /* export relevant VARS for use by post script */ 00717 if (valid > 0) { 00718 /* export all relevant env vars for the post script */ 00719 if (gisbase == NULL) { 00720 /* try to read from GRASS environment */ 00721 gisbase = getenv("GISBASE"); 00722 } 00723 run_post(package, action, bins, gisbase); 00724 } 00725 00726 if (VERBOSE) { 00727 fprintf(stdout, "Extension will be installed from '%s'\n", package); 00728 } 00729 00730 /* CHECK PACKAGE FOR VALIDITY */ 00731 if (action != UNINSTALL) { 00732 check_extension(package, pkg_name, &pkg_major, &pkg_minor, 00733 &pkg_revision); 00734 } 00735 00736 /* these actions can be done without GRASS checking */ 00737 if (action == QUERY) { 00738 query_extension(package, pkg_name, pkg_major, pkg_minor, pkg_revision, 00739 pkg_short_name, invocation, orgname); 00740 exit(0); 00741 } 00742 00743 if (action == DETAILS) { 00744 show_details(package); 00745 exit(0); 00746 } 00747 00748 if (action == LICENSE) { 00749 show_license(package); 00750 exit(0); 00751 } 00752 00753 if (action == CLEAN) { 00754 source_clean(package); 00755 exit(0); 00756 } 00757 00758 00759 /* The following checks need to be done for all other actions! */ 00760 00761 /* figure out path to GRASS installation */ 00762 /* GIS base not given? */ 00763 if (gisbase == NULL) { 00764 /* try to read from GRASS environment */ 00765 gisbase = getenv("GISBASE"); 00766 if (gisbase == NULL) { 00767 /* still NULL? Abort! */ 00768 print_error(ERR_INVOCATION, 00769 "GISBASE environment variable not set and path to GRASS not given.\n"); 00770 } 00771 } 00772 00773 if (VERBOSE) { 00774 fprintf(stdout, "Path to GRASS is %s.\n", gisbase); 00775 } 00776 00777 /* figure out GRASS version */ 00778 grass_version = getenv("GRASS_VERSION"); 00779 if (grass_version == NULL) { 00780 /* GRASS version can be read from gisbase/etc/VERSIONNUMBER */ 00781 sprintf(version_file, "%s/etc/VERSIONNUMBER", gisbase); 00782 f = fopen(version_file, "r"); 00783 if (f == NULL) { 00784 /* still NULL? Abort! */ 00785 print_error(ERR_VERSION, 00786 "Could not read GRASS version. Did you specify the right path?\n"); 00787 } 00788 else { 00789 grass_version = malloc(sizeof(char) * 16); 00790 error = fscanf(f, "%s", grass_version); 00791 fclose(f); 00792 if (error < 1) { 00793 print_error(ERR_VERSION, 00794 "Could not read GRASS version. Did you specify the right path?\n"); 00795 } 00796 } 00797 } 00798 00799 if (grass_version != NULL) { 00800 /* extract major and minor version numbers */ 00801 tmp = strdup(grass_version); 00802 00803 grass_major = strtok(tmp, "."); 00804 grass_minor = strtok(NULL, "."); 00805 grass_revision = strtok(NULL, "."); 00806 00807 major = strtol(grass_major, NULL, 10); 00808 minor = strtol(grass_minor, NULL, 10); 00809 revision = strtol(grass_revision, NULL, 10); 00810 00811 grass_version = malloc(sizeof(char) * MAXSTR); 00812 sprintf(grass_version, "%i.%i.%i", major, minor, revision); 00813 if (VERBOSE) { 00814 fprintf(stdout, "GRASS version is %s.\n", grass_version); 00815 } 00816 00817 if (major < 6) { 00818 print_error(ERR_VERSION, 00819 "extensions only work with GRASS version 6 and above.\n"); 00820 } 00821 } 00822 00823 /* for GDAL compatibility and 00824 for the sake of people using Lorenzo Moretti's GRASS for MacOS, we always export the following 00825 compiler options */ 00826 sprintf(coptions, "-L%s/lib -I/usr/local/grasslib/include/ ", gisbase); 00827 00828 /* these actions can only be done after everything has been checked */ 00829 if (action == INSTALL) { 00830 source_install(package, gisbase, pkg_short_name, pkg_major, pkg_minor, 00831 pkg_revision, grass_version); 00832 exit(0); 00833 } 00834 00835 if (action == UNINSTALL) { 00836 uninstall(package, pkg_short_name, gisbase, grass_version); 00837 exit(0); 00838 } 00839 00840 if (action == TEST_INSTALL) { 00841 test_install(package, gisbase, pkg_short_name, pkg_major, pkg_minor, 00842 pkg_revision, grass_version); 00843 exit(0); 00844 } 00845 00846 if (action == BIN_INSTALL) { 00847 if (binaries_exist(package, bins)) { 00848 bin_install(package, gisbase, bins, pkg_short_name, pkg_major, 00849 pkg_minor, pkg_revision, grass_version); 00850 exit(0); 00851 } 00852 else { 00853 print_error(ERR_MISSING_BINS, "no binaries for system '%s'\n", 00854 bins); 00855 } 00856 } 00857 00858 exit(0); 00859 }