GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
reg_deps.c
Go to the documentation of this file.
1 
2 /***************************************************************************
3  * reg_deps.c
4  *
5  * Mon Apr 18 15:19:04 2005
6  * Copyright 2005 Benjamin Ducke
7  ****************************************************************************/
8 
9 /*
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23  */
24 
25 #include "globals.h"
26 
27 
28 /*
29  Reads in the "depends" file and returns a string of comma-separated
30  extensions, on which this one depends.
31  */
32 char *depstr(char *package, char *gisbase)
33 {
34  char file[MAXSTR];
35  char line[MAXSTR];
36  char *str;
37  int first;
38  int error;
39  FILE *f_deps;
40 
41  char short_name[MAXSTR];
42 
43  /* check if 'depends' exists and is readable */
44  sprintf(file, "../depends");
45  f_deps = fopen(file, "r");
46  if (f_deps == NULL) {
47  if (errno == ENOENT) {
48  /* file does not exist, return an empty string */
49  return ("");
50  }
51  else {
52  /* sth. strange happened */
53  print_error(ERR_CHECK_DEPS, "checking for file '%s': %s\n", file,
54  strerror(errno));
55  }
56  }
57 
58  first = 1;
59  str = malloc(sizeof(char) * MAXSTR);
60  while (nc_fgets_nb(line, MAXSTR, f_deps) != NULL) {
61  if (strlen(line) > 0) {
62  error = sscanf(line, "%s", short_name);
63  if ((error > 0) && (strcmp("GRASS", short_name))) {
64  if (first) {
65  strcat(str, "\t");
66  strcat(str, short_name);
67  first = 0;
68  }
69  else {
70  strcat(str, ",");
71  strcat(str, short_name);
72  }
73  }
74  }
75  }
76 
77  fclose(f_deps);
78  return (str);
79 }
80 
81 /*
82  Reads in GISBASE/etc/extensions.db
83  Adds a line to the file GISBASE/etc/extensions.db that contains:
84  extension name and version, 'src' or name of binary files.
85  Adds extension name to the end of every entry mentioned in 'depends'
86  */
87 void register_extension(char *gisbase, char *bins, char *pkg_short_name,
88  int pkg_major, int pkg_minor, int pkg_revision)
89 {
90  char file[MAXSTR];
91  char str[MAXSTR];
92  int n_lines;
93  int error;
94  int db_exists;
95  int must_register;
96  int copy_thru;
97  int ext_exists;
98  FILE *f_in, *f_out;
99 
100  char short_name[MAXSTR];
101  char inst_bins[MAXSTR];
102  char deps[MAXSTR];
103  int major, minor, revision;
104 
105 
106  /* check, if extensions.db exists and is readable */
107  db_exists = 1;
108  sprintf(file, "%s/etc/extensions.db", gisbase);
109  f_in = fopen(file, "r");
110  if (f_in == NULL) {
111  if (errno == ENOENT) {
112  /* file does not yet exist */
113  db_exists = 0;
114  }
115  else {
116  /* sth. strange happened */
117  fclose(f_in);
118  print_error(ERR_REGISTER_EXT, "checking for file '%s': %s\n",
119  file, strerror(errno));
120  }
121  }
122 
123  if (db_exists) {
124  /* create a temporary extensions.db file for write access */
125  /* TODO: Do not hardcode temp paths */
126  strcpy(TMPDB, "/tmp/grass.extensions.db.XXXXXX"); /* TMPDB is a global variable */
127  mkstemp(TMPDB);
128 
129  f_out = fopen(TMPDB, "w+");
130  if (f_out == NULL) {
132  "could not create temp file '%s': %s\n \
133  Make sure that directory /tmp exists on your system and you have write permission.\n", TMPDB, strerror(errno));
134  }
135 
136  atexit(&exit_db); /* now need to register an at exit func to remove tmpdb automatically! */
137 
138  /* count number of extensions.db registry entries */
139  n_lines = 0;
140  must_register = 1;
141  ext_exists = 0;
142  while (nc_fgets_nb(str, MAXSTR, f_in) != NULL) {
143  n_lines++;
144  copy_thru = 1;
145  /* read in name and version of registered item */
146  sscanf(str, "%s\t%i.%i.%i\t%s\t%s", short_name, &major, &minor,
147  &revision, inst_bins, deps);
148  /* check, if extension with same name already exists */
149  if (!strcmp(short_name, pkg_short_name)) {
150  /* an extension with this name is already installed */
151  ext_exists = 1;
152  /* check if it's version is lower, same or higher */
153  error =
154  vercmp(major, minor, revision, pkg_major, pkg_minor,
155  pkg_revision);
156  if ((!FORCE)) {
157  /* error, if another version is present! */
158  if (error < 0) {
160  "Extension '%s' with lower version (%i.%i.%i) already installed. You can use -f to overwrite this version, if you know what you are doing.\n",
161  pkg_short_name, major, minor, revision);
162  }
163  else {
165  "Extension '%s' with same or higher version (%i.%i.%i) already installed. You can use -f to overwrite this version, if you know what you are doing.\n",
166  pkg_short_name, major, minor, revision);
167  }
168  }
169  if (FORCE) { /* this overrides/implies UPGRADE! */
170  if (error == 0) {
171  /* if same version installed: just leave everything untouched */
172  must_register = 0;
173  }
174  else {
175  /* otherwise, work needs be done! */
176  must_register = 1;
177  copy_thru = 0;
178  }
179  }
180  }
181 
182  /* write line to temporary extension file */
183  if (copy_thru) { /* just copy thru */
184  fprintf(f_out, str);
185  fflush(f_out);
186  }
187  }
188 
189  if (must_register) {
190  if (!ext_exists) {
191  /* register brand new extension */
192  sprintf(deps, "%s", depstr(pkg_short_name, gisbase));
193  fprintf(f_out, "%s\t%i.%i.%i\t%s\t%s\n", pkg_short_name,
194  pkg_major, pkg_minor, pkg_revision, bins, deps);
195  }
196  else {
197  /* register only new version number and binary source, if appropriate */
198  sprintf(deps, "%s", depstr(pkg_short_name, gisbase));
199  fprintf(f_out, "%s\t%i.%i.%i\t%s\t%s\n", short_name,
200  pkg_major, pkg_minor, pkg_revision, inst_bins, deps);
201  }
202  }
203 
204  fclose(f_out);
205  fclose(f_in);
206  }
207 
208  if ((n_lines == 0) || (!db_exists)) {
209  /* extensions.db file does not yet exist or is empty: just create a new one */
210  /* TODO: Do not hardcode temp paths */
211  strcpy(TMPDB, "/tmp/grass.extensions.db.XXXXXX"); /* tmpdir is a global variable */
212  mkstemp(TMPDB);
213 
214  f_out = fopen(TMPDB, "w+");
215  if (f_out == NULL) {
217  "could not create temp db '%s': %s\n \
218  Make sure that directory /tmp exists on your system and you have write permission.\n", file, strerror(errno));
219  }
220  atexit(&exit_db); /* now need to register an at exit func to remove tmpdb automatically! */
221 
222  /* register brand new extension */
223  sprintf(deps, "%s", depstr(pkg_short_name, gisbase));
224  fprintf(f_out, "%s\t%i.%i.%i\t%s\t%s\n", pkg_short_name, pkg_major,
225  pkg_minor, pkg_revision, bins, deps);
226  fclose(f_out);
227  return;
228  }
229 }
230 
231 
232 /*
233  Removes an entry from GISBASE/etc/extensions.db
234  */
235 void deregister_extension(char *package, char *pkg_short_name, char *gisbase)
236 {
237  char file[MAXSTR];
238  char str[MAXSTR];
239  int error;
240  int db_exists;
241  int copy_thru;
242  FILE *f_in, *f_out;
243  int found_ext;
244 
245  char short_name[MAXSTR];
246  char inst_bins[MAXSTR];
247  char deps[MAXSTR];
248  int major, minor, revision;
249 
250 
251  db_exists = 0;
252  /* check, if extensions.db exists and is readable */
253  sprintf(file, "%s/etc/extensions.db", gisbase);
254  f_in = fopen(file, "r");
255  if (f_in == NULL) {
256  if ((errno == ENOENT) && (!FORCE)) {
257  /* file does not yet exist */
258  fclose(f_in);
260  "could not deregister: no extensions installed\n");
261  }
262  else {
263  /* sth. strange happened */
264  if (!FORCE) {
265  fclose(f_in);
267  "checking for file '%s': %s\n", file,
268  strerror(errno));
269  }
270  }
271  }
272  else {
273  db_exists = 1;
274  }
275 
276  if (db_exists) {
277  db_exists = 0;
278  /* create a temporary extensions.db file for write access */
279  /* TODO: Do not hardcode temp paths */
280  strcpy(TMPDB, "/tmp/grass.extensions.db.XXXXXX"); /* tmpdir is a global variable */
281  mkstemp(TMPDB);
282 
283  f_out = fopen(TMPDB, "w+");
284  if ((f_out == NULL) && (!FORCE)) {
286  "could not create temp db '%s': %s\n \
287  Make sure that directory /tmp exists on your system and you have write permission.\n", file, strerror(errno));
288  }
289  else {
290  db_exists = 1;
291  atexit(&exit_db); /* now need to register an at exit func to remove tmpdb automatically! */
292  }
293  }
294 
295  /* if creation of temp db file succeeded: */
296  if (db_exists) {
297  /* read every line in extension.db */
298  found_ext = 0;
299  while (nc_fgets_nb(str, MAXSTR, f_in) != NULL) {
300  /* copy thru, if extension name different from current extension's */
301  error =
302  sscanf(str, "%s\t%i.%i.%i\t%s\t%s", short_name, &major,
303  &minor, &revision, inst_bins, deps);
304  if (error > 0) {
305  copy_thru = 1;
306  if (!strcmp(pkg_short_name, short_name)) {
307  copy_thru = 0;
308  found_ext = 1;
309  }
310  if (copy_thru) {
311  /* abort, if a dependency on current extension is found */
312  if ((strstr(deps, pkg_short_name)) && (!FORCE)) {
314  "cannot uninstall extension '%s' it is needed by '%s'.\n",
315  pkg_short_name, short_name);
316  }
317  fprintf(f_out, str);
318  }
319  }
320  }
321 
322  /* was the extension installed at all? */
323  if (found_ext == 0) {
325  "no extension '%s' registered/installed in '%s'.\n",
326  pkg_short_name, gisbase);
327  }
328  /* mind the right sequence for closing these! */
329  fclose(f_in);
330  fclose(f_out);
331  }
332 }
333 
334 
335 /*
336  checks GRASS version number and whether all extensions listed in 'depends'
337  are satisfied (by analysing GISBASE/etc/extensions.db).
338  Terminates program, if missing deps; just returns, if "--force" was given.
339  */
340 void check_dependencies(char *package, char *gisbase, char *grass_version)
341 {
342  char file[MAXSTR];
343  char str[MAXSTR];
344  char dbstr[MAXSTR];
345  int error;
346  int db_exists;
347  int satisfied;
348  FILE *f_deps, *f_db;
349 
350  char short_name[MAXSTR];
351  int major, minor, revision;
352  char dep_short_name[MAXSTR];
353  int dep_major, dep_minor, dep_revision;
354 
355  if (FORCE) {
356  return;
357  }
358 
359  /* check if 'depends' exists and is readable */
360  f_deps = fopen("../depends", "r");
361  if (f_deps == NULL) {
362  if (errno == ENOENT) {
363  /* file does not exist, no need to check for deps */
364  fprintf(stderr, "\n%s/depends ENOENT\n", package);
365  return;
366  }
367  else {
368  /* sth. strange happened */
369  fclose(f_deps);
370  print_error(ERR_CHECK_DEPS, "checking for file '%s': %s\n", file,
371  strerror(errno));
372  }
373  }
374 
375  db_exists = 1;
376  /* check if extensions.db exists and is readable */
377  sprintf(file, "%s/etc/extensions.db", gisbase);
378  f_db = fopen(file, "r");
379  if (f_db == NULL) {
380  if (errno == ENOENT) {
381  /* file does not exist */
382  db_exists = 0;
383  }
384  else {
385  /* sth. strange happened */
386  fclose(f_db);
387  print_error(ERR_CHECK_DEPS, "checking for file '%s': %s\n", file,
388  strerror(errno));
389  }
390  }
391 
392  satisfied = 0;
393  while (nc_fgets_nb(str, MAXSTR, f_deps) != NULL) {
394  /* get first line with dependencies info */
395  major = 0;
396  minor = 0;
397  revision = 0;
398  dep_major = 0;
399  dep_minor = 0;
400  dep_revision = 0;
401  error =
402  sscanf(str, "%s\t%i.%i.%i", dep_short_name, &dep_major,
403  &dep_minor, &dep_revision);
404  if (error > 0) {
405  if (!strcmp(dep_short_name, "GRASS")) {
406  /* a GRASS version dependency has been specified */
407  sscanf(grass_version, "%i.%i.%i", &major, &minor, &revision);
408  if (vercmp
409  (major, minor, revision, dep_major, dep_minor,
410  dep_revision) < 0) {
412  "installed version (%s) of GRASS is too low. Required version is %i.%i.%i\n",
413  grass_version, dep_major, dep_minor,
414  dep_revision);
415  }
416  satisfied = 1; /* let's be tolerant */
417  }
418  else {
419  /* a dependency on some other extension has been specified ... */
420  if (db_exists) { /* ... if no extensions installed yet, it must be unsatisfied! */
421  satisfied = 0;
422  rewind(f_db);
423  while (nc_fgets_nb(dbstr, MAXSTR, f_db) != NULL) {
424  major = 0;
425  minor = 0;
426  revision = 0;
427  error =
428  sscanf(dbstr, "%s\t%i.%i.%i", short_name, &major,
429  &minor, &revision);
430  if (error > 0) {
431  if (!strcmp(short_name, dep_short_name)) {
432  /* found an installed extension that satisfies name, now check
433  for version number */
434  if (vercmp
435  (major, minor, revision, dep_major,
436  dep_minor, dep_revision) < 0) {
438  "installed version %i.%i.%i of required extension '%s' is too low.\n \
439  Required version is %i.%i.%i\n",
440  major, minor, revision, dep_short_name, dep_major, dep_minor,
441  dep_revision);
442  }
443  /* name and version dependencies satisfied */
444  satisfied = 1;
445  }
446  }
447  }
448  if (!satisfied) {
450  "required extension '%s' not found in '%s'.\n",
451  dep_short_name, gisbase);
452  }
453  }
454  }
455  }
456  }
457  if (db_exists) {
458  fclose(f_db);
459  }
460  fclose(f_deps);
461 
462 }
void register_extension(char *gisbase, char *bins, char *pkg_short_name, int pkg_major, int pkg_minor, int pkg_revision)
Definition: reg_deps.c:87
void exit_db(void)
sprintf(buf2,"%s", G3D_CATS_ELEMENT)
#define ERR_MISSING_DEPS
Definition: globals.h:94
#define MAXSTR
Definition: globals.h:59
char * depstr(char *package, char *gisbase)
Definition: reg_deps.c:32
void print_error(int err_code, char *msg,...)
Definition: gem/error.c:32
tuple gisbase
Definition: forms.py:59
void deregister_extension(char *package, char *pkg_short_name, char *gisbase)
Definition: reg_deps.c:235
#define ERR_EXISTS_EXT
Definition: globals.h:92
void * malloc(YYSIZE_T)
int vercmp(int major, int minor, int revision, int major2, int minor2, int revision2)
Definition: tools.c:832
EXTERN char TMPDB[MAXSTR]
Definition: globals.h:149
int first
Definition: form/open.c:25
EXTERN int FORCE
Definition: globals.h:161
#define ERR_REGISTER_EXT
Definition: globals.h:91
return NULL
Definition: dbfopen.c:1394
#define ERR_CHECK_DEPS
Definition: globals.h:93
fclose(fd)
#define file
#define ERR_DEREGISTER_EXT
Definition: globals.h:95
int errno
char * nc_fgets_nb(char *s, int size, FILE *stream)
Definition: tools.c:500
void check_dependencies(char *package, char *gisbase, char *grass_version)
Definition: reg_deps.c:340