start.c 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  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. #include <string.h>
  15. #include <stdlib.h>
  16. #include <unistd.h>
  17. #ifdef __MINGW32__
  18. #include <windows.h>
  19. #include <process.h>
  20. #include <fcntl.h>
  21. #endif
  22. #include <grass/spawn.h>
  23. #include <grass/dbmi.h>
  24. #define READ 0
  25. #define WRITE 1
  26. static void close_on_exec(int fd)
  27. {
  28. #ifndef __MINGW32__
  29. int flags = fcntl(fd, F_GETFD);
  30. fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
  31. #endif
  32. }
  33. /*!
  34. \brief Initialize a new dbDriver for db transaction.
  35. If <i>name</i> is NULL, the db name will be assigned
  36. connection.driverName.
  37. \param name driver name
  38. \return pointer to dbDriver structure
  39. \return NULL on error
  40. */
  41. dbDriver *db_start_driver(const char *name)
  42. {
  43. dbDriver *driver;
  44. dbDbmscap *list, *cur;
  45. const char *startup;
  46. int p1[2], p2[2];
  47. int pid;
  48. int stat;
  49. dbConnection connection;
  50. char ebuf[5];
  51. /* Set some environment variables which are later read by driver.
  52. * This is necessary when application is running without GISRC file and all
  53. * gis variables are set by application.
  54. * Even if GISRC is set, application may change some variables during runtime,
  55. * if for example reads data from different gdatabase, location or mapset*/
  56. /* setenv() is not portable, putenv() is POSIX, putenv() in glibc 2.0-2.1.1 doesn't conform to SUSv2,
  57. * G_putenv() as well, but that is what we want, makes a copy of string */
  58. if (G_get_gisrc_mode() == G_GISRC_MODE_MEMORY) {
  59. G_debug(3, "G_GISRC_MODE_MEMORY\n");
  60. sprintf(ebuf, "%d", G_GISRC_MODE_MEMORY);
  61. G_putenv("GRASS_DB_DRIVER_GISRC_MODE", ebuf); /* to tell driver that it must read variables */
  62. if (G_getenv_nofatal("DEBUG")) {
  63. G_putenv("DEBUG", G_getenv_nofatal("DEBUG"));
  64. }
  65. else {
  66. G_putenv("DEBUG", "0");
  67. }
  68. G_putenv("GISDBASE", G_getenv_nofatal("GISDBASE"));
  69. G_putenv("LOCATION_NAME", G_getenv_nofatal("LOCATION_NAME"));
  70. G_putenv("MAPSET", G_getenv_nofatal("MAPSET"));
  71. }
  72. else {
  73. /* Warning: GISRC_MODE_MEMORY _must_ be set to G_GISRC_MODE_FILE, because the module can be
  74. * run from an application which previously set environment variable to G_GISRC_MODE_MEMORY */
  75. sprintf(ebuf, "%d", G_GISRC_MODE_FILE);
  76. G_putenv("GRASS_DB_DRIVER_GISRC_MODE", ebuf);
  77. }
  78. /* read the dbmscap file */
  79. if (NULL == (list = db_read_dbmscap()))
  80. return (dbDriver *) NULL;
  81. /* if name is empty use connection.driverName, added by RB 4/2000 */
  82. if (name[0] == '\0') {
  83. db_get_connection(&connection);
  84. if (NULL == (name = connection.driverName))
  85. return (dbDriver *) NULL;
  86. }
  87. /* find this system name */
  88. for (cur = list; cur; cur = cur->next)
  89. if (strcmp(cur->driverName, name) == 0)
  90. break;
  91. if (cur == NULL) {
  92. char msg[256];
  93. db_free_dbmscap(list);
  94. sprintf(msg, "%s: no such driver available", name);
  95. db_error(msg);
  96. return (dbDriver *) NULL;
  97. }
  98. /* allocate a driver structure */
  99. driver = (dbDriver *) db_malloc(sizeof(dbDriver));
  100. if (driver == NULL) {
  101. db_free_dbmscap(list);
  102. return (dbDriver *) NULL;
  103. }
  104. /* copy the relevant info from the dbmscap entry into the driver structure */
  105. db_copy_dbmscap_entry(&driver->dbmscap, cur);
  106. startup = driver->dbmscap.startup;
  107. /* free the dbmscap list */
  108. db_free_dbmscap(list);
  109. /* run the driver as a child process and create pipes to its stdin, stdout */
  110. #ifdef __MINGW32__
  111. #define pipe(fds) _pipe(fds, 250000, _O_BINARY | _O_NOINHERIT)
  112. #endif
  113. /* open the pipes */
  114. if ((pipe(p1) < 0) || (pipe(p2) < 0)) {
  115. db_syserror("can't open any pipes");
  116. return (dbDriver *) NULL;
  117. }
  118. close_on_exec(p1[READ]);
  119. close_on_exec(p1[WRITE]);
  120. close_on_exec(p2[READ]);
  121. close_on_exec(p2[WRITE]);
  122. pid = G_spawn_ex(startup,
  123. SF_BACKGROUND,
  124. SF_REDIRECT_DESCRIPTOR, 0, p1[READ],
  125. SF_CLOSE_DESCRIPTOR, p1[WRITE],
  126. SF_REDIRECT_DESCRIPTOR, 1, p2[WRITE],
  127. SF_CLOSE_DESCRIPTOR, p2[READ],
  128. startup, NULL);
  129. /* create a child */
  130. if (pid < 0) {
  131. db_syserror("can't create fork");
  132. return (dbDriver *) NULL;
  133. }
  134. close(p1[READ]);
  135. close(p2[WRITE]);
  136. /* record driver process id in driver struct */
  137. driver->pid = pid;
  138. /* convert pipes to FILE* */
  139. driver->send = fdopen(p1[WRITE], "wb");
  140. driver->recv = fdopen(p2[READ], "rb");
  141. /* most systems will have to use unbuffered io to get the send/recv to work */
  142. #ifndef USE_BUFFERED_IO
  143. setbuf(driver->send, NULL);
  144. setbuf(driver->recv, NULL);
  145. #endif
  146. db__set_protocol_fds(driver->send, driver->recv);
  147. if (db__recv_return_code(&stat) != DB_OK || stat != DB_OK)
  148. driver = NULL;
  149. return driver;
  150. }