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