start.c 4.6 KB

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