1/*
2 *  SQLInstallDriver.c
3 *
4 *  $Id: SQLInstallDriver.c,v 1.10 2006/01/20 15:58:35 source Exp $
5 *
6 *  Install a driver
7 *
8 *  The iODBC driver manager.
9 *
10 *  Copyright (C) 1996-2006 by OpenLink Software <iodbc@openlinksw.com>
11 *  All Rights Reserved.
12 *
13 *  This software is released under the terms of either of the following
14 *  licenses:
15 *
16 *      - GNU Library General Public License (see LICENSE.LGPL)
17 *      - The BSD License (see LICENSE.BSD).
18 *
19 *  Note that the only valid version of the LGPL license as far as this
20 *  project is concerned is the original GNU Library General Public License
21 *  Version 2, dated June 1991.
22 *
23 *  While not mandated by the BSD license, any patches you make to the
24 *  iODBC source code may be contributed back into the iODBC project
25 *  at your discretion. Contributions will benefit the Open Source and
26 *  Data Access community as a whole. Submissions may be made at:
27 *
28 *      http://www.iodbc.org
29 *
30 *
31 *  GNU Library Generic Public License Version 2
32 *  ============================================
33 *  This library is free software; you can redistribute it and/or
34 *  modify it under the terms of the GNU Library General Public
35 *  License as published by the Free Software Foundation; only
36 *  Version 2 of the License dated June 1991.
37 *
38 *  This library is distributed in the hope that it will be useful,
39 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
40 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
41 *  Library General Public License for more details.
42 *
43 *  You should have received a copy of the GNU Library General Public
44 *  License along with this library; if not, write to the Free
45 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
46 *
47 *
48 *  The BSD License
49 *  ===============
50 *  Redistribution and use in source and binary forms, with or without
51 *  modification, are permitted provided that the following conditions
52 *  are met:
53 *
54 *  1. Redistributions of source code must retain the above copyright
55 *     notice, this list of conditions and the following disclaimer.
56 *  2. Redistributions in binary form must reproduce the above copyright
57 *     notice, this list of conditions and the following disclaimer in
58 *     the documentation and/or other materials provided with the
59 *     distribution.
60 *  3. Neither the name of OpenLink Software Inc. nor the names of its
61 *     contributors may be used to endorse or promote products derived
62 *     from this software without specific prior written permission.
63 *
64 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
65 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
66 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
67 *  A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL OPENLINK OR
68 *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
69 *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
70 *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
71 *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
72 *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
73 *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
74 *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
75 */
76
77
78#include <iodbc.h>
79#include <odbcinst.h>
80#include <unicode.h>
81
82#include "misc.h"
83#include "inifile.h"
84#include "iodbc_error.h"
85
86#ifdef _MAC
87# include <getfpn.h>
88#endif
89
90#if !defined(WINDOWS) && !defined(WIN32) && !defined(OS2) && !defined(macintosh)
91# include <pwd.h>
92# include <unistd.h>
93# include <sys/types.h>
94# include <sys/stat.h>
95# define UNIX_PWD
96#endif
97
98
99BOOL
100InstallDriverPath (LPSTR lpszPath, WORD cbPathMax, WORD * pcbPathOut,
101    LPSTR envname)
102{
103#ifdef _MAC
104  OSErr result;
105  long fldrDid;
106  short fldrRef;
107#endif
108  BOOL retcode = FALSE;
109  char *ptr;
110
111  lpszPath[cbPathMax - 1] = 0;
112
113#if	!defined(UNIX_PWD)
114#ifdef _MAC
115  result = FindFolder (kOnSystemDisk, kExtensionFolderType, kDontCreateFolder,
116      &fldrRef, &fldrDid);
117  if (result != noErr)
118    {
119      PUSH_ERROR (ODBC_ERROR_GENERAL_ERR);
120      goto quit;
121    }
122
123  ptr = get_full_pathname (fldrDid, fldrRef);
124  STRNCPY (lpszPath, ptr, cbPathMax - 1);
125  free (ptr);
126
127  if (STRLEN (ptr) >= cbPathMax)
128    {
129      PUSH_ERROR (ODBC_ERROR_INVALID_BUFF_LEN);
130      goto quit;
131    }
132  else
133    goto done;
134#else
135  /*
136   *  On Windows, there is only one place to look
137   */
138  if (GetWindowsDirectory ((LPSTR) buf, cbPathMax) >= cbPathMax)
139    {
140      PUSH_ERROR (ODBC_ERROR_INVALID_BUFF_LEN);
141      goto quit;
142    }
143  else
144    goto done;
145#endif
146#else
147
148  /*
149   *  1. Check $ODBCDRIVERS environment variable
150   */
151  if ((ptr = getenv (envname)))
152    if (access (ptr, R_OK | W_OK | X_OK) == 0)
153      {
154	STRNCPY (lpszPath, ptr, cbPathMax - 1);
155	if (STRLEN (ptr) >= cbPathMax)
156	  {
157	    PUSH_ERROR (ODBC_ERROR_INVALID_BUFF_LEN);
158	    goto quit;
159	  }
160	else
161	  goto done;
162      }
163
164  /*
165   * 2. Check /usr/local/lib and /usr/lib
166   */
167#ifdef _BE
168  STRNCPY (lpszPath, "/boot/beos/system/lib", cbPathMax - 1);
169  if (STRLEN (lpszPath) != STRLEN ("/boot/beos/system/lib"))
170#else
171  STRNCPY (lpszPath, "/usr/local/lib", cbPathMax - 1);
172  if (STRLEN (lpszPath) != STRLEN ("/usr/local/lib"))
173#endif
174    {
175      PUSH_ERROR (ODBC_ERROR_INVALID_BUFF_LEN);
176      goto quit;
177    }
178  if (access (lpszPath, R_OK | W_OK | X_OK) == 0)
179    goto done;
180
181#ifdef _BE
182  STRNCPY (lpszPath, "/boot/home/config/lib", cbPathMax - 1);
183  if (STRLEN (lpszPath) != STRLEN ("/boot/home/config/lib"))
184#else
185  STRNCPY (lpszPath, "/usr/lib", cbPathMax - 1);
186  if (STRLEN (lpszPath) != STRLEN ("/usr/lib"))
187#endif
188    {
189      PUSH_ERROR (ODBC_ERROR_INVALID_BUFF_LEN);
190      goto quit;
191    }
192  if (access (lpszPath, R_OK | W_OK | X_OK) == 0)
193    goto done;
194
195  /*
196   *  3. Check either $HOME
197   */
198  if (!(ptr = getenv ("HOME")))
199    {
200      ptr = (char *) getpwuid (getuid ());
201      if (ptr)
202	ptr = ((struct passwd *) ptr)->pw_dir;
203    }
204
205  if (ptr)
206    {
207#ifdef _BE
208      sprintf (lpszPath, "%s/config/lib", ptr);
209#else
210      sprintf (lpszPath, "%s/lib", ptr);
211#endif
212      if (access (lpszPath, R_OK | W_OK | X_OK) == 0)
213	goto done;
214    }
215
216  if (!mkdir (lpszPath, 0755))
217    goto done;
218
219#endif
220
221  SQLPostInstallerError (ODBC_ERROR_GENERAL_ERR,
222      "Cannot retrieve a directory where to install the driver or translator.");
223  goto quit;
224
225done:
226  retcode = TRUE;
227
228quit:
229  if (pcbPathOut)
230    *pcbPathOut = STRLEN (lpszPath);
231  return retcode;
232}
233
234
235BOOL INSTAPI
236SQLInstallDriver (LPCSTR lpszInfFile, LPCSTR lpszDriver, LPSTR lpszPath,
237    WORD cbPathMax, WORD * pcbPathOut)
238{
239  PCONFIG pCfg = NULL, pOdbcCfg = NULL;
240  BOOL retcode = FALSE;
241
242  /* Check input parameters */
243  CLEAR_ERROR ();
244  if (!lpszDriver || !STRLEN (lpszDriver))
245    {
246      PUSH_ERROR (ODBC_ERROR_INVALID_PARAM_SEQUENCE);
247      goto quit;
248    }
249
250  if (!lpszPath || !cbPathMax)
251    {
252      PUSH_ERROR (ODBC_ERROR_INVALID_BUFF_LEN);
253      goto quit;
254    }
255
256  /* Write the out path */
257  if (!InstallDriverPath (lpszPath, cbPathMax, pcbPathOut, "ODBCDRIVERS"))
258    goto quit;
259
260  /* Else go through user/system odbcinst.ini */
261  switch (configMode)
262    {
263    case ODBC_BOTH_DSN:
264    case ODBC_USER_DSN:
265      wSystemDSN = USERDSN_ONLY;
266      break;
267
268    case ODBC_SYSTEM_DSN:
269      wSystemDSN = SYSTEMDSN_ONLY;
270      break;
271    }
272
273  if (_iodbcdm_cfg_search_init (&pCfg, "odbcinst.ini", TRUE))
274    {
275      PUSH_ERROR (ODBC_ERROR_GENERAL_ERR);
276      goto quit;
277    }
278
279  if (_iodbcdm_cfg_search_init (&pOdbcCfg, "odbc.ini", TRUE))
280    {
281      PUSH_ERROR (ODBC_ERROR_GENERAL_ERR);
282      pOdbcCfg = NULL;
283      goto done;
284    }
285
286  if (lpszInfFile)
287    {
288      if (!install_from_ini (pCfg, pOdbcCfg, (char *) lpszInfFile,
289	      (char *) lpszDriver, TRUE))
290	{
291	  PUSH_ERROR (ODBC_ERROR_INVALID_INF);
292	  goto done;
293	}
294    }
295  else if (!install_from_string (pCfg, pOdbcCfg, (char *) lpszDriver, TRUE))
296    {
297      PUSH_ERROR (ODBC_ERROR_INVALID_KEYWORD_VALUE);
298      goto done;
299    }
300
301  if (_iodbcdm_cfg_commit (pCfg) || _iodbcdm_cfg_commit (pOdbcCfg))
302    {
303      PUSH_ERROR (ODBC_ERROR_GENERAL_ERR);
304      goto done;
305    }
306
307  retcode = TRUE;
308
309done:
310  _iodbcdm_cfg_done (pCfg);
311  if (pOdbcCfg)
312    _iodbcdm_cfg_done (pOdbcCfg);
313
314quit:
315  wSystemDSN = USERDSN_ONLY;
316  configMode = ODBC_BOTH_DSN;
317
318  return retcode;
319}
320
321BOOL INSTAPI
322SQLInstallDriverW (LPCWSTR lpszInfFile, LPCWSTR lpszDriver, LPWSTR lpszPath,
323    WORD cbPathMax, WORD FAR * pcbPathOut)
324{
325  char *_inf_u8 = NULL;
326  char *_driver_u8 = NULL;
327  char *_path_u8 = NULL;
328  BOOL retcode = FALSE;
329
330  _inf_u8 = (char *) dm_SQL_WtoU8 ((SQLWCHAR *) lpszInfFile, SQL_NTS);
331  if (_inf_u8 == NULL && lpszInfFile)
332    {
333      PUSH_ERROR (ODBC_ERROR_OUT_OF_MEM);
334      goto done;
335    }
336
337  _driver_u8 = (char *) dm_SQL_WtoU8 ((SQLWCHAR *) lpszDriver, SQL_NTS);
338  if (_driver_u8 == NULL && lpszDriver)
339    {
340      PUSH_ERROR (ODBC_ERROR_OUT_OF_MEM);
341      goto done;
342    }
343
344  if (cbPathMax > 0)
345    {
346      if ((_path_u8 = malloc (cbPathMax * UTF8_MAX_CHAR_LEN + 1)) == NULL)
347	{
348	  PUSH_ERROR (ODBC_ERROR_OUT_OF_MEM);
349	  goto done;
350	}
351    }
352
353  retcode =
354      SQLInstallDriver (_inf_u8, _driver_u8, _path_u8,
355      cbPathMax * UTF8_MAX_CHAR_LEN, pcbPathOut);
356
357  if (retcode == TRUE)
358    {
359      dm_StrCopyOut2_U8toW (_path_u8, lpszPath, cbPathMax, pcbPathOut);
360    }
361
362done:
363  MEM_FREE (_inf_u8);
364  MEM_FREE (_driver_u8);
365  MEM_FREE (_path_u8);
366
367  return retcode;
368}
369