GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
start.c
Go to the documentation of this file.
1 /*!
2  * \file db/dbmi_client/start.c
3  *
4  * \brief DBMI Library (client) - open database connection
5  *
6  * (C) 1999-2008 by the GRASS Development Team
7  *
8  * This program is free software under the GNU General Public
9  * License (>=v2). Read the file COPYING that comes with GRASS
10  * for details.
11  *
12  * \author Joel Jones (CERL/UIUC), Radim Blazek
13  */
14 
15 #include <string.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 
19 #ifdef __MINGW32__
20 #include <windows.h>
21 #include <process.h>
22 #include <fcntl.h>
23 #endif
24 
25 #include <grass/spawn.h>
26 #include <grass/dbmi.h>
27 
28 #define READ 0
29 #define WRITE 1
30 
31 static void close_on_exec(int fd)
32 {
33 #ifndef __MINGW32__
34  int flags = fcntl(fd, F_GETFD);
35  fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
36 #endif
37 }
38 
39 /*!
40  \brief Initialize a new dbDriver for db transaction.
41 
42  If <i>name</i> is NULL, the db name will be assigned
43  connection.driverName.
44 
45  \param name driver name
46 
47  \return pointer to dbDriver structure
48  \return NULL on error
49 */
51 {
53  dbDbmscap *list, *cur;
54  const char *startup;
55  int p1[2], p2[2];
56  int pid;
57  int stat;
58  dbConnection connection;
59  char ebuf[5];
60 
61  /* Set some environment variables which are later read by driver.
62  * This is necessary when application is running without GISRC file and all
63  * gis variables are set by application.
64  * Even if GISRC is set, application may change some variables during runtime,
65  * if for example reads data from different gdatabase, location or mapset*/
66 
67  /* setenv() is not portable, putenv() is POSIX, putenv() in glibc 2.0-2.1.1 doesn't conform to SUSv2,
68  * G_putenv() as well, but that is what we want, makes a copy of string */
70  G_debug(3, "G_GISRC_MODE_MEMORY\n");
71  sprintf(ebuf, "%d", G_GISRC_MODE_MEMORY);
72  G_putenv("GRASS_DB_DRIVER_GISRC_MODE", ebuf); /* to tell driver that it must read variables */
73 
74  if (G_getenv_nofatal("DEBUG")) {
75  G_putenv("DEBUG", G_getenv_nofatal("DEBUG"));
76  }
77  else {
78  G_putenv("DEBUG", "0");
79  }
80 
81  G_putenv("GISDBASE", G_getenv_nofatal("GISDBASE"));
82  G_putenv("LOCATION_NAME", G_getenv_nofatal("LOCATION_NAME"));
83  G_putenv("MAPSET", G_getenv_nofatal("MAPSET"));
84  }
85  else {
86  /* Warning: GISRC_MODE_MEMORY _must_ be set to G_GISRC_MODE_FILE, because the module can be
87  * run from an application which previously set environment variable to G_GISRC_MODE_MEMORY */
88  sprintf(ebuf, "%d", G_GISRC_MODE_FILE);
89  G_putenv("GRASS_DB_DRIVER_GISRC_MODE", ebuf);
90  }
91 
92  /* read the dbmscap file */
93  if (NULL == (list = db_read_dbmscap()))
94  return (dbDriver *) NULL;
95 
96  /* if name is empty use connection.driverName, added by RB 4/2000 */
97  if (name[0] == '\0') {
98  db_get_connection(&connection);
99  if (NULL == (name = connection.driverName))
100  return (dbDriver *) NULL;
101  }
102 
103  /* find this system name */
104  for (cur = list; cur; cur = cur->next)
105  if (strcmp(cur->driverName, name) == 0)
106  break;
107  if (cur == NULL) {
108  char msg[256];
109 
110  db_free_dbmscap(list);
111  sprintf(msg, "%s: no such driver available", name);
112  db_error(msg);
113  return (dbDriver *) NULL;
114  }
115 
116  /* allocate a driver structure */
117  driver = (dbDriver *) db_malloc(sizeof(dbDriver));
118  if (driver == NULL) {
119  db_free_dbmscap(list);
120  return (dbDriver *) NULL;
121  }
122 
123  /* copy the relevant info from the dbmscap entry into the driver structure */
124  db_copy_dbmscap_entry(&driver->dbmscap, cur);
125  startup = driver->dbmscap.startup;
126 
127  /* free the dbmscap list */
128  db_free_dbmscap(list);
129 
130  /* run the driver as a child process and create pipes to its stdin, stdout */
131 
132 #ifdef __MINGW32__
133 #define pipe(fds) _pipe(fds, 250000, _O_BINARY | _O_NOINHERIT)
134 #endif
135 
136  /* open the pipes */
137  if ((pipe(p1) < 0) || (pipe(p2) < 0)) {
138  db_syserror("can't open any pipes");
139  return (dbDriver *) NULL;
140  }
141 
142  close_on_exec(p1[READ]);
143  close_on_exec(p1[WRITE]);
144  close_on_exec(p2[READ]);
145  close_on_exec(p2[WRITE]);
146 
147  pid = G_spawn_ex(startup,
149  SF_REDIRECT_DESCRIPTOR, 0, p1[READ],
150  SF_CLOSE_DESCRIPTOR, p1[WRITE],
151  SF_REDIRECT_DESCRIPTOR, 1, p2[WRITE],
152  SF_CLOSE_DESCRIPTOR, p2[READ],
153  startup, NULL);
154 
155  /* create a child */
156  if (pid < 0) {
157  db_syserror("can't create fork");
158  return (dbDriver *) NULL;
159  }
160 
161  close(p1[READ]);
162  close(p2[WRITE]);
163 
164  /* record driver process id in driver struct */
165  driver->pid = pid;
166 
167  /* convert pipes to FILE* */
168  driver->send = fdopen(p1[WRITE], "wb");
169  driver->recv = fdopen(p2[READ], "rb");
170 
171  /* most systems will have to use unbuffered io to get the send/recv to work */
172 #ifndef USE_BUFFERED_IO
173  setbuf(driver->send, NULL);
174  setbuf(driver->recv, NULL);
175 #endif
176 
177  db__set_protocol_fds(driver->send, driver->recv);
178  if (db__recv_return_code(&stat) != DB_OK || stat != DB_OK)
179  driver = NULL;
180 
181  return driver;
182 }
struct _dbmscap * next
Definition: dbmi.h:158
int db_get_connection(dbConnection *)
Get default DB connection settings for the current mapset.
void G_putenv(const char *, const char *)
Sets the UNIX environment variable name to value.
Definition: putenv.c:31
Definition: dbmi.h:153
int G_get_gisrc_mode(void)
Get info where variables are stored.
Definition: env.c:73
dbDbmscap dbmscap
Definition: dbmi.h:170
#define SF_REDIRECT_DESCRIPTOR
Definition: spawn.h:18
void db_syserror(const char *)
Report system error.
#define NULL
Definition: ccmath.h:32
#define SF_BACKGROUND
Definition: spawn.h:23
#define WRITE
Definition: start.c:29
void db_copy_dbmscap_entry(dbDbmscap *, dbDbmscap *)
Copy dbmscap entry.
Definition: dbmscap.c:81
int G_spawn_ex(const char *command,...)
Spawn new process based on command.
Definition: spawn.c:903
#define G_GISRC_MODE_FILE
Definition: gis.h:156
int db__recv_return_code(int *)
Receive return code.
Definition: ret_codes.c:51
struct list * list
Definition: read_list.c:24
char driverName[256]
Definition: dbmi.h:155
const struct driver * driver
Definition: driver/init.c:25
char * driverName
Definition: dbmi.h:295
void db_free_dbmscap(dbDbmscap *)
Free dbmscap.
Definition: dbmscap.c:259
int pid
Definition: dbmi.h:172
void db_error(const char *)
Report error message.
FILE * recv
Definition: dbmi.h:171
#define G_GISRC_MODE_MEMORY
Definition: gis.h:157
dbDbmscap * db_read_dbmscap(void)
Read dbmscap.
Definition: dbmscap.c:100
#define SF_CLOSE_DESCRIPTOR
Definition: spawn.h:19
const char * G_getenv_nofatal(const char *)
Get environment variable.
Definition: env.c:383
void * db_malloc(int)
Allocate memory.
const char * name
Definition: named_colr.c:7
void db__set_protocol_fds(FILE *, FILE *)
?
dbDriver * db_start_driver(const char *name)
Initialize a new dbDriver for db transaction.
Definition: start.c:50
FILE * send
Definition: dbmi.h:171
int G_debug(int, const char *,...) __attribute__((format(printf
char startup[256]
Definition: dbmi.h:156
#define READ
Definition: start.c:28
#define DB_OK
Definition: dbmi.h:71