123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183 |
- /*!
- * \file db/dbmi_client/start.c
- *
- * \brief DBMI Library (client) - open database connection
- *
- * (C) 1999-2008 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (>=v2). Read the file COPYING that comes with GRASS
- * for details.
- *
- * \author Joel Jones (CERL/UIUC), Radim Blazek
- */
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #ifdef __MINGW32__
- #include <windows.h>
- #include <process.h>
- #include <fcntl.h>
- #endif
- #include <grass/spawn.h>
- #include <grass/dbmi.h>
- #define READ 0
- #define WRITE 1
- static void close_on_exec(int fd)
- {
- #ifndef __MINGW32__
- int flags = fcntl(fd, F_GETFD);
- fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
- #endif
- }
- /*!
- \brief Initialize a new dbDriver for db transaction.
-
- If <i>name</i> is NULL, the db name will be assigned
- connection.driverName.
-
- \param name driver name
-
- \return pointer to dbDriver structure
- \return NULL on error
- */
- dbDriver *db_start_driver(const char *name)
- {
- dbDriver *driver;
- dbDbmscap *list, *cur;
- const char *startup;
- int p1[2], p2[2];
- int pid;
- int stat;
- dbConnection connection;
- char ebuf[5];
- /* Set some environment variables which are later read by driver.
- * This is necessary when application is running without GISRC file and all
- * gis variables are set by application.
- * Even if GISRC is set, application may change some variables during runtime,
- * if for example reads data from different gdatabase, location or mapset*/
- /* setenv() is not portable, putenv() is POSIX, putenv() in glibc 2.0-2.1.1 doesn't conform to SUSv2,
- * G_putenv() as well, but that is what we want, makes a copy of string */
- if (G_get_gisrc_mode() == G_GISRC_MODE_MEMORY) {
- G_debug(3, "G_GISRC_MODE_MEMORY\n");
- sprintf(ebuf, "%d", G_GISRC_MODE_MEMORY);
- G_putenv("GRASS_DB_DRIVER_GISRC_MODE", ebuf); /* to tell driver that it must read variables */
- if (G_getenv_nofatal("DEBUG")) {
- G_putenv("DEBUG", G_getenv_nofatal("DEBUG"));
- }
- else {
- G_putenv("DEBUG", "0");
- }
- G_putenv("GISDBASE", G_getenv_nofatal("GISDBASE"));
- G_putenv("LOCATION_NAME", G_getenv_nofatal("LOCATION_NAME"));
- G_putenv("MAPSET", G_getenv_nofatal("MAPSET"));
- }
- else {
- /* Warning: GISRC_MODE_MEMORY _must_ be set to G_GISRC_MODE_FILE, because the module can be
- * run from an application which previously set environment variable to G_GISRC_MODE_MEMORY */
- sprintf(ebuf, "%d", G_GISRC_MODE_FILE);
- G_putenv("GRASS_DB_DRIVER_GISRC_MODE", ebuf);
- }
- /* read the dbmscap file */
- if (NULL == (list = db_read_dbmscap()))
- return (dbDriver *) NULL;
- /* if name is empty use connection.driverName, added by RB 4/2000 */
- if (name[0] == '\0') {
- db_get_connection(&connection);
- if (NULL == (name = connection.driverName))
- return (dbDriver *) NULL;
- }
- /* find this system name */
- for (cur = list; cur; cur = cur->next)
- if (strcmp(cur->driverName, name) == 0)
- break;
- if (cur == NULL) {
- char msg[256];
- db_free_dbmscap(list);
- sprintf(msg, "%s: no such driver available", name);
- db_error(msg);
- return (dbDriver *) NULL;
- }
- /* allocate a driver structure */
- driver = (dbDriver *) db_malloc(sizeof(dbDriver));
- if (driver == NULL) {
- db_free_dbmscap(list);
- return (dbDriver *) NULL;
- }
- /* copy the relevant info from the dbmscap entry into the driver structure */
- db_copy_dbmscap_entry(&driver->dbmscap, cur);
- startup = driver->dbmscap.startup;
- /* free the dbmscap list */
- db_free_dbmscap(list);
- /* run the driver as a child process and create pipes to its stdin, stdout */
- #ifdef __MINGW32__
- #define pipe(fds) _pipe(fds, 250000, _O_BINARY | _O_NOINHERIT)
- #endif
- /* open the pipes */
- if ((pipe(p1) < 0) || (pipe(p2) < 0)) {
- db_syserror("can't open any pipes");
- return (dbDriver *) NULL;
- }
- close_on_exec(p1[READ]);
- close_on_exec(p1[WRITE]);
- close_on_exec(p2[READ]);
- close_on_exec(p2[WRITE]);
- pid = G_spawn_ex(startup,
- SF_BACKGROUND,
- SF_REDIRECT_DESCRIPTOR, 0, p1[READ],
- SF_CLOSE_DESCRIPTOR, p1[WRITE],
- SF_REDIRECT_DESCRIPTOR, 1, p2[WRITE],
- SF_CLOSE_DESCRIPTOR, p2[READ],
- startup, NULL);
- /* create a child */
- if (pid < 0) {
- db_syserror("can't create fork");
- return (dbDriver *) NULL;
- }
- close(p1[READ]);
- close(p2[WRITE]);
- /* record driver process id in driver struct */
- driver->pid = pid;
- /* convert pipes to FILE* */
- driver->send = fdopen(p1[WRITE], "wb");
- driver->recv = fdopen(p2[READ], "rb");
- /* most systems will have to use unbuffered io to get the send/recv to work */
- #ifndef USE_BUFFERED_IO
- setbuf(driver->send, NULL);
- setbuf(driver->recv, NULL);
- #endif
- db__set_protocol_fds(driver->send, driver->recv);
- if (db__recv_return_code(&stat) != DB_OK || stat != DB_OK)
- driver = NULL;
- return driver;
- }
|