CUBRID Engine  latest
databases_file.c
Go to the documentation of this file.
1 /*
2  * Copyright 2008 Search Solution Corporation
3  * Copyright 2016 CUBRID Corporation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */
18 
19 
20 /*
21  * databases_file.c - Parsing the database directory file
22  *
23  */
24 
25 #ident "$Id$"
26 
27 #include "config.h"
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <signal.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 
36 #if defined(WINDOWS)
37 #include <io.h>
38 #else /* WINDOWS */
39 #include <unistd.h>
40 #endif /* WINDOWS */
41 #include <assert.h>
42 
43 #include "porting.h"
44 
45 #include "chartype.h"
46 #include "error_manager.h"
47 #include "databases_file.h"
48 #include "boot.h"
49 #include "connection_defs.h"
50 #include "memory_alloc.h"
51 #include "environment_variable.h"
52 #include "system_parameter.h"
53 
54 #if defined(WINDOWS)
55 #include "misc_string.h"
56 #include "wintcp.h"
57 #endif /* WINDOWS */
58 
59 
60 /* conservative upper bound of a line in databases.txt */
61 #define CFG_MAX_LINE 4096
62 
63 static char CFG_HOST_SEPARATOR = ':';
64 
65 static char *cfg_next_char (char *str_p);
66 static char *cfg_next_line (char *str_p);
67 static char *cfg_pop_token (char *str_p, char **token_p);
68 static char *cfg_pop_linetoken (char *str_p, char **token_p);
69 static void cfg_get_directory_filename (char *buffer, int *local);
70 
71 static int cfg_ensure_directory_write (void);
72 static FILE *cfg_open_directory_file (bool write_flag);
73 
74 static char **cfg_copy_hosts (const char **host_array, int *num_hosts);
75 static const char *cfg_pop_host (const char *host_list, char *buffer, int *length);
76 static bool cfg_host_exists (char *host_list, char *hostname, int num_items);
77 
78 /* PARSING UTILITIES */
79 /*
80  * cfg_next_char() - Advances the given pointer until a non-whitespace character
81  * or the end of the string are encountered.
82  * return: char *
83  * str_p(in): buffer pointer
84  */
85 static char *
86 cfg_next_char (char *str_p)
87 {
88  char *p;
89 
90  p = str_p;
91  while (char_isspace ((int) *p) && *p != '\0')
92  {
93  p++;
94  }
95 
96  return (p);
97 }
98 
99 /*
100  * cfg_next_line()
101  * return: char *
102  * str_p(in): buffer pointer
103  */
104 static char *
105 cfg_next_line (char *str_p)
106 {
107  char *p;
108 
109  p = str_p;
110  while (!char_iseol ((int) *p) && *p != '\0')
111  {
112  p++;
113  }
114  while (char_iseol ((int) *p) && *p != '\0')
115  {
116  p++;
117  }
118 
119  return (p);
120 }
121 
122 /*
123  * cfg_pop_token() - This looks in the buffer for the next token which is define as
124  * a string of characters surrounded by whitespace
125  * return: char
126  * str_p(in): buffer with tokens
127  * token_p(in/out): returned next token string
128  *
129  * Note : When found the token characters are copied into a new string
130  * and returned.
131  * The pointer to the first character following the new token in
132  * the buffer is returned.
133  */
134 static char *
135 cfg_pop_token (char *str_p, char **token_p)
136 {
137  char *p, *end, *token = NULL;
138  int length;
139 
140  token = NULL;
141  p = str_p;
142  while (char_isspace ((int) *p) && *p != '\0')
143  {
144  p++;
145  }
146  end = p;
147  while (!char_isspace ((int) *end) && *end != '\0')
148  {
149  end++;
150  }
151 
152  length = (int) (end - p);
153  if (length > 0)
154  {
155  token = (char *) malloc (length + 1);
156  if (token != NULL)
157  {
158  strncpy (token, p, length);
159  token[length] = '\0';
160  }
161  }
162 
163  *token_p = token;
164  return (end);
165 }
166 
167 /*
168  * cfg_pop_linetoken()
169  * return: char *
170  * str_p(in):
171  * token_p(in/out):
172  */
173 static char *
174 cfg_pop_linetoken (char *str_p, char **token_p)
175 {
176  char *p, *end, *token = NULL;
177  int length;
178 
179  if (str_p == NULL || char_iseol ((int) *str_p))
180  {
181  *token_p = NULL;
182  return str_p;
183  }
184  token = NULL;
185  p = str_p;
186  while (char_isspace ((int) *p) && !char_iseol ((int) *p) && *p != '\0')
187  {
188  p++;
189  }
190  end = p;
191 
192  while (!char_isspace ((int) *end) && *end != '\0')
193  {
194  end++;
195  }
196 
197  length = (int) (end - p);
198  if (length > 0)
199  {
200  token = (char *) malloc (length + 1);
201  if (token != NULL)
202  {
203  strncpy (token, p, length);
204  token[length] = '\0';
205  }
206  }
207 
208  *token_p = token;
209  return (end);
210 }
211 
212 /*
213  * cfg_get_directory_filename() - Finds the full pathname of the database
214  * directory file.
215  * return: none
216  * buffer(in): character buffer to hold the full path name
217  * local(out): flag set if the file was assumed to be local
218  */
219 static void
220 cfg_get_directory_filename (char *buffer, int *local)
221 {
222 #if !defined (DO_NOT_USE_CUBRIDENV)
223  const char *env_name;
224 
225  *local = 0;
226  env_name = envvar_get (DATABASES_ENVNAME);
227  if (env_name == NULL || strlen (env_name) == 0)
228  {
229  sprintf (buffer, DATABASES_FILENAME);
230  *local = 1;
231  }
232  else
233  {
234  if (env_name[strlen (env_name) - 1] == '/')
235  {
236  sprintf (buffer, "%s%s", env_name, DATABASES_FILENAME);
237  }
238  else
239  {
240  sprintf (buffer, "%s/%s", env_name, DATABASES_FILENAME);
241  }
242  }
243 #else
244  *local = 0;
245  envvar_vardir_file (buffer, PATH_MAX, DATABASES_FILENAME);
246 #endif
247 }
248 
249 /*
250  * cfg_os_working_directory() - Returns the current working directory
251  * in a buffer.
252  * Buffer returned is static and must be
253  * copied immediately.
254  * return: char *
255  */
256 char *
258 {
259  char *return_str = NULL;
260 
261 #if defined(WINDOWS)
262  static char working_dir[PATH_MAX];
263  return_str = _fullpath (working_dir, ".", PATH_MAX);
264 #else /* WINDOWS */
265  return_str = getenv ("PWD");
266 #endif /* WINDOWS */
267 
268  return return_str;
269 }
270 
271 /*
272  * cfg_maycreate_get_directory_filename()
273  * return: char *
274  * buffer(in):
275  */
276 char *
278 {
279  int local_ignore;
280  FILE *file_p = NULL;
281 
282  cfg_get_directory_filename (buffer, &local_ignore);
283  if ((file_p = fopen (buffer, "a+")) == NULL)
284  {
285 #if !defined(CS_MODE)
287 #else /* !CS_MODE */
289 #endif /* !CS_MODE */
290  return NULL;
291  }
292  fclose (file_p);
293  return buffer;
294 }
295 
296 /*
297  * cfg_ensure_directory_write() - Make sure that we can get write access to
298  * the directory file, if not abort
299  * the operation.
300  * return: non-zero if directory file is writable
301  */
302 static int
304 {
305  char filename[PATH_MAX];
306  FILE *file_p = NULL;
307  int local, status;
308 
309  status = 0;
310 
311  cfg_get_directory_filename (filename, &local);
312  file_p = fopen (filename, "a+");
313  if (file_p == NULL)
314  {
316  }
317  else
318  {
319  status = 1;
320  fclose (file_p);
321  }
322 
323  return (status);
324 }
325 
326 /*
327  * cfg_open_directory_file()
328  * return: file pointer
329  * write_flag(in): set to open for write
330  */
331 static FILE *
332 cfg_open_directory_file (bool write_flag)
333 {
334  char filename[PATH_MAX];
335  FILE *file_p = NULL;
336  int local;
337 
338  cfg_get_directory_filename (filename, &local);
339 
340  if (write_flag)
341  {
342 #if defined(WINDOWS)
343  file_p = fopen (filename, "wbc"); /* write binary commit */
344 #else /* WINDOWS */
345  file_p = fopen (filename, "w");
346 #endif /* WINDOWS */
347  }
348  else
349  {
350  file_p = fopen (filename, "r");
351  }
352  if (file_p == NULL)
353  {
354  if (write_flag)
355  {
357  }
358  else
359  {
360  /* Only standalone and server will update the database location file */
361 #if !defined(CS_MODE)
362  /* no readable file, try to create one */
363  file_p = fopen (filename, "r+");
364  if (file_p == NULL)
365  {
367  }
368 #else /* !CS_MODE */
369  file_p = NULL;
370 #endif /* !CS_MODE */
371  }
372  }
373  return (file_p);
374 }
375 
376 /*
377  * cfg_read_directory() - This reads the database directory file and returns
378  * a list of descriptors
379  * return: non-zero for success
380  * info_p(out): pointer to returned list of descriptors
381  * write_flag(in): flag indicating write intention
382  *
383  * Note: The write_flag flag should be set if the file is to be
384  * modified. This will ensure that write access is available before some
385  * potentially expensive operation like database creation is performed.
386  * A list of hosts where the database could exist is obtained from
387  * cfg_get_hosts() and attached to the DB_INFO structure.
388  *
389  * However, cfg_read_directory() has a potential problem that
390  * the file lock is released. The file lock acquired through io_mount()
391  * is released when cfg_read_directory() opens and closes the file.
392  */
393 int
394 cfg_read_directory (DB_INFO ** info_p, bool write_flag)
395 {
396  char line[CFG_MAX_LINE];
397  FILE *file_p = NULL;
398  DB_INFO *databases, *last, *db;
399  char *str = NULL;
400  char *primary_host = NULL;
401  int error_code = ER_FAILED;
402  char *ha_node_list = NULL;
403 
404  databases = last = NULL;
405 
406 #if defined(SERVER_MODE)
408  {
409  str = strchr (prm_get_string_value (PRM_ID_HA_NODE_LIST), '@');
410  ha_node_list = (str) ? str + 1 : NULL;
411  }
412 #endif
413 
414  if (!write_flag || cfg_ensure_directory_write ())
415  {
416  file_p = cfg_open_directory_file (false);
417  if (file_p != NULL)
418  {
419  while (fgets (line, CFG_MAX_LINE - 1, file_p) != NULL)
420  {
421  str = cfg_next_char (line);
422  if (*str != '\0' && *str != '#')
423  {
424  db = (DB_INFO *) malloc (sizeof (DB_INFO));
425  if (db == NULL)
426  {
427  if (databases != NULL)
428  {
429  cfg_free_directory (databases);
430  }
431  *info_p = NULL;
434  }
435  db->next = NULL;
436  str = cfg_pop_token (str, &db->name);
437  str = cfg_pop_token (str, &db->pathname);
438  str = cfg_pop_token (str, &primary_host);
439  if (ha_node_list)
440  {
441  db->hosts = cfg_get_hosts (ha_node_list, &db->num_hosts, false);
442  }
443  else
444  {
445  db->hosts = cfg_get_hosts (primary_host, &db->num_hosts, false);
446  }
447  if (primary_host != NULL)
448  {
449  free_and_init (primary_host);
450  }
451 
452  str = cfg_pop_token (str, &db->logpath);
453  str = cfg_pop_token (str, &db->lobpath);
454 
455  if (databases == NULL)
456  {
457  databases = db;
458  }
459  else
460  {
461  last->next = db;
462  }
463  last = db;
464  if (db->name == NULL || db->pathname == NULL || db->hosts == NULL || db->logpath == NULL
465  /* skip to check above to support backward compatibility || db->lobpath == NULL */ )
466  {
468  if (databases != NULL)
469  {
470  cfg_free_directory (databases);
471  }
472  *info_p = NULL;
474  }
475  }
476  }
477  fclose (file_p);
478  error_code = NO_ERROR;
479  }
480  }
481  *info_p = databases;
482  return (error_code);
483 }
484 
485 /*
486  * cfg_read_directory_ex() - This provides same functionality of
487  * cfg_read_directory().
488  * return: non-zero for success
489  * vdes(in): file descriptor
490  * info_p(out): pointer to returned list of descriptors
491  * write_flag(in): flag indicating write intention
492  *
493  * Note: However it does not open/close the file, the file lock is
494  * preserved.
495  */
496 int
497 cfg_read_directory_ex (int vdes, DB_INFO ** info_p, bool write_flag)
498 {
499  char *line = NULL;
500  DB_INFO *databases, *last, *db;
501  char *str = NULL;
502  char *primary_host = NULL;
503  struct stat stat_buffer;
504  int error_code = ER_FAILED;
505 
506 #if defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
507  return cfg_read_directory (info_p, write_flag);
508 #endif /* DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
509 
510  databases = last = NULL;
511 
512  if (lseek (vdes, 0L, SEEK_SET) == 0L)
513  {
514  fstat (vdes, &stat_buffer);
515  line = (char *) malloc (stat_buffer.st_size + 1);
516  if (line == NULL)
517  {
518  *info_p = NULL;
519  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, (size_t) (stat_buffer.st_size + 1));
521  }
522  read (vdes, line, (unsigned int) stat_buffer.st_size);
523  line[stat_buffer.st_size] = '\0';
524  str = cfg_next_char (line);
525  while (*str != '\0')
526  {
527  if (*str != '#')
528  {
529  if ((db = (DB_INFO *) malloc (sizeof (DB_INFO))) == NULL)
530  {
531  if (databases != NULL)
532  {
533  cfg_free_directory (databases);
534  }
535  *info_p = NULL;
536  free_and_init (line);
537 
540  }
541 
542  db->next = NULL;
543  str = cfg_pop_linetoken (str, &db->name);
544  str = cfg_pop_linetoken (str, &db->pathname);
545  str = cfg_pop_linetoken (str, &primary_host);
546  db->hosts = cfg_get_hosts (primary_host, &db->num_hosts, false);
547  if (primary_host != NULL)
548  {
549  free_and_init (primary_host);
550  }
551  str = cfg_pop_linetoken (str, &db->logpath);
552  str = cfg_pop_linetoken (str, &db->lobpath);
553 
554  if (databases == NULL)
555  {
556  databases = db;
557  }
558  else
559  {
560  last->next = db;
561  }
562  last = db;
563  if (db->name == NULL || db->pathname == NULL || db->hosts == NULL || db->logpath == NULL
564  /* skip to check above to support backward compatibility || db->lobpath == NULL */ )
565 
566  {
568  if (databases != NULL)
569  {
570  cfg_free_directory (databases);
571  }
572  *info_p = NULL;
573  free_and_init (line);
575  }
576  }
577  str = cfg_next_line (str);
578  str = cfg_next_char (str);
579  }
580  error_code = NO_ERROR;
581  free_and_init (line);
582  }
583  *info_p = databases;
584  return (error_code);
585 }
586 
587 /*
588  * cfg_write_directory() - This writes a list of database descriptors to
589  * the accessible config file. only the first host,
590  * (primary host), is written to file.
591  * return: none
592  * databases(in): list of database descriptors
593  *
594  * Note: However, cfg_write_directory() has a potential problem that
595  * the file lock is released. The file lock acquired through io_mount()
596  * is released when cfg_write_directory() opens and closes the file.
597  */
598 void
599 cfg_write_directory (const DB_INFO * databases)
600 {
601  FILE *file_p;
602  const DB_INFO *db_info_p;
603 #if !defined(WINDOWS)
604  sigset_t new_mask, old_mask;
605 #endif /* !WINDOWS */
606 
607  file_p = cfg_open_directory_file (true);
608  if (file_p != NULL)
609  {
610 
611 #if !defined(WINDOWS)
612  sigfillset (&new_mask);
613  sigdelset (&new_mask, SIGINT);
614  sigdelset (&new_mask, SIGQUIT);
615  sigdelset (&new_mask, SIGTERM);
616  sigdelset (&new_mask, SIGHUP);
617  sigdelset (&new_mask, SIGABRT);
618  sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
619 #endif /* !WINDOWS */
620 
621  fprintf (file_p, "#db-name\tvol-path\t\tdb-host\t\tlog-path\t\tlob-base-path\n");
622  for (db_info_p = databases; db_info_p != NULL; db_info_p = db_info_p->next)
623  {
624  bool t = (strlen (db_info_p->name) < 8);
625 #if defined(WINDOWS)
626  char short_path[256];
627  GetShortPathName (db_info_p->pathname, short_path, 256);
628  fprintf (file_p, "%s%s\t%s\t", db_info_p->name, (t ? "\t" : ""), short_path);
629 #else /* WINDOWS */
630  fprintf (file_p, "%s%s\t%s\t", db_info_p->name, (t ? "\t" : ""), db_info_p->pathname);
631 #endif /* WINDOWS */
632 
633  if (db_info_p->hosts != NULL && *(db_info_p->hosts) != NULL)
634  {
635  char **array = db_info_p->hosts;
636  fprintf (file_p, "%s", *array++);
637  while (*array != NULL)
638  {
639  fprintf (file_p, ":%s", *array++);
640  }
641  }
642  else
643  {
644  fprintf (file_p, "localhost");
645  }
646 
647  if (db_info_p->logpath != NULL)
648  {
649 #if defined(WINDOWS)
650  GetShortPathName (db_info_p->logpath, short_path, 256);
651  fprintf (file_p, "\t%s ", short_path);
652 #else /* WINDOWS */
653  fprintf (file_p, "\t%s ", db_info_p->logpath);
654 #endif /* WINDOWS */
655  }
656 
657  if (db_info_p->lobpath != NULL)
658  {
659  fprintf (file_p, "\t%s ", db_info_p->lobpath);
660  }
661 
662  fprintf (file_p, "\n");
663  }
664  fflush (file_p);
665  fclose (file_p);
666 
667 #if !defined(WINDOWS)
668  sigprocmask (SIG_SETMASK, &old_mask, NULL);
669 #endif /* !WINDOWS */
670  }
671 }
672 
673 /*
674  * cfg_write_directory_ex() - This writes a list of database descriptors
675  * to the accessible config file.
676  * only the first host, (primary host),
677  * is written to file.
678  * return: none
679  * vdes(in): file descriptor
680  * databases(in): list of database descriptors
681  *
682  * Note : However, cfg_write_directory() has a potential problem that
683  * the file lock is released. The file lock acquired through io_mount()
684  * is released when cfg_write_directory() opens and closes the file.
685  */
686 void
687 cfg_write_directory_ex (int vdes, const DB_INFO * databases)
688 {
689  char line[LINE_MAX], *s;
690  const DB_INFO *db_info_p;
691  int n;
692 #if !defined(WINDOWS)
693  sigset_t new_mask, old_mask;
694 #endif /* !WINDOWS */
695 
696 #if defined(DONT_USE_MANDATORY_LOCK_IN_WINDOWS)
697  cfg_read_directory (info_p, true);
698  return;
699 #endif /* DONT_USE_MANDATORY_LOCK_IN_WINDOWS */
700 
701 #if !defined(WINDOWS)
702  sigfillset (&new_mask);
703  sigdelset (&new_mask, SIGINT);
704  sigdelset (&new_mask, SIGQUIT);
705  sigdelset (&new_mask, SIGTERM);
706  sigdelset (&new_mask, SIGHUP);
707  sigdelset (&new_mask, SIGABRT);
708  sigprocmask (SIG_SETMASK, &new_mask, &old_mask);
709 #endif /* !WINDOWS */
710 
711  lseek (vdes, 0L, SEEK_SET);
712  n = sprintf (line, "#db-name\tvol-path\t\tdb-host\t\tlog-path\t\tlob-base-path\n");
713  write (vdes, line, n);
714  for (db_info_p = databases; db_info_p != NULL; db_info_p = db_info_p->next)
715  {
716  bool t = (strlen (db_info_p->name) < 8);
717  s = line;
718  s += sprintf (s, "%s%s\t%s\t", db_info_p->name, (t ? "\t" : ""), db_info_p->pathname);
719 
720  if (db_info_p->hosts != NULL && *(db_info_p->hosts) != NULL)
721  {
722  char **array = db_info_p->hosts;
723  s += sprintf (s, "%s", *array++);
724  while (*array != NULL)
725  {
726  s += sprintf (s, ":%s", *array++);
727  }
728  }
729  else
730  {
731  s += sprintf (s, "localhost");
732  }
733  if (db_info_p->logpath)
734  {
735  s += sprintf (s, "\t%s", db_info_p->logpath);
736  }
737  if (db_info_p->lobpath)
738  {
739  s += sprintf (s, "\t%s", db_info_p->lobpath);
740  }
741  s += sprintf (s, "\n");
742  n = (int) (s - line);
743  write (vdes, line, n);
744  }
745 
746  ftruncate (vdes, lseek (vdes, 0L, SEEK_CUR));
747 
748 #if !defined(WINDOWS)
749  sigprocmask (SIG_SETMASK, &old_mask, NULL);
750 #endif /* !WINDOWS */
751 }
752 
753 /*
754  * cfg_free_directory() - Frees a list of database descriptors.
755  * return: none
756  * databases(in): list of databases
757  */
758 void
760 {
761  DB_INFO *db_info_p, *next_info_p;
762 
763  for (db_info_p = databases, next_info_p = NULL; db_info_p != NULL; db_info_p = next_info_p)
764  {
765 
766  next_info_p = db_info_p->next;
767 
768  if (db_info_p->name != NULL)
769  {
770  free_and_init (db_info_p->name);
771  }
772  if (db_info_p->pathname != NULL)
773  {
774  free_and_init (db_info_p->pathname);
775  }
776  if (db_info_p->hosts != NULL)
777  {
778  cfg_free_hosts (db_info_p->hosts);
779  }
780  if (db_info_p->logpath != NULL)
781  {
782  free_and_init (db_info_p->logpath);
783  }
784  if (db_info_p->lobpath != NULL)
785  {
786  free_and_init (db_info_p->lobpath);
787  }
788  free_and_init (db_info_p);
789  }
790 }
791 
792 #if defined(CUBRID_DEBUG)
793 /*
794  * cfg_dump_directory() - debug function.
795  * return: none
796  * databases(in): list of database descriptors
797  */
798 void
799 cfg_dump_directory (const DB_INFO * databases)
800 {
801  const DB_INFO *db_info_p;
802  int i = 0;
803 
804  for (db_info_p = databases; db_info_p != NULL; db_info_p = db_info_p->next)
805  {
806  fprintf (stdout, "%s %s ", db_info_p->name, db_info_p->pathname);
807  if (db_info_p->hosts != NULL)
808  {
809  i = 0;
810  while ((*((db_info_p->hosts) + i)) != NULL)
811  {
812  fprintf (stdout, "%s", (*(db_info_p->hosts + i)));
813  i++;
814  if ((*((db_info_p->hosts) + i)) != NULL)
815  {
816  fprintf (stdout, ",");
817  }
818  else
819  {
820  fprintf (stdout, " ");
821  }
822  }
823  }
824  if (db_info_p->logpath != NULL)
825  {
826  fprintf (stdout, "%s ", db_info_p->logpath);
827  }
828  if (db_info_p->lobpath != NULL)
829  {
830  fprintf (stdout, "%s", db_info_p->lobpath);
831  }
832  fprintf (stdout, "\n");
833  }
834 }
835 #endif
836 
837 /*
838  * cfg_update_db() - Updates pathname, logpath, and creates a new host list
839  * with the hostname sent in used as the primary host.
840  * return: none
841  * db_info_p(in): database descriptor
842  * path(in): directory path name
843  * logpath(in): log path name
844  * host(in): server host name
845  */
846 void
847 cfg_update_db (DB_INFO * db_info_p, const char *path, const char *logpath, const char *lobpath, const char *host)
848 {
849  char **ptr_p;
850 
851  if (db_info_p != NULL)
852  {
853  if (path != NULL)
854  {
855  if (db_info_p->pathname != NULL)
856  {
857  free_and_init (db_info_p->pathname);
858  }
859  db_info_p->pathname = strdup (path);
860  }
861 
862  if (logpath != NULL)
863  {
864  if (db_info_p->logpath != NULL)
865  {
866  free_and_init (db_info_p->logpath);
867  }
868  db_info_p->logpath = strdup (logpath);
869  }
870 
871  if (lobpath != NULL)
872  {
873  if (db_info_p->lobpath != NULL)
874  {
875  free_and_init (db_info_p->lobpath);
876  }
877  db_info_p->lobpath = strdup (lobpath);
878  }
879 
880  if (host != NULL)
881  {
882  ptr_p = cfg_get_hosts (host, &db_info_p->num_hosts, false);
883  if (db_info_p->hosts != NULL)
884  {
885  cfg_free_hosts (db_info_p->hosts);
886  }
887  db_info_p->hosts = ptr_p;
888  }
889  }
890 }
891 
892 /*
893  * cfg_new_db() - creates a new DB_INFO structure. If the hosts array sent
894  * in is NULL, an array with the local host as primary host
895  * is created.
896  * return: new database descriptor
897  * name(in): database name
898  * path(in):
899  * logpath(in): log path
900  * lobpath(in): lob path
901  * hosts(in):
902  */
903 DB_INFO *
904 cfg_new_db (const char *name, const char *path, const char *logpath, const char *lobpath, const char **hosts)
905 {
906  DB_INFO *db_info_p;
907 
908  db_info_p = (DB_INFO *) malloc (DB_SIZEOF (DB_INFO));
909  if (db_info_p == NULL)
910  {
911  goto error;
912  }
913 
914  db_info_p->pathname = NULL;
915  db_info_p->logpath = NULL;
916  db_info_p->lobpath = NULL;
917  db_info_p->hosts = NULL;
918  db_info_p->num_hosts = 0;
919 
920  db_info_p->name = strdup (name);
921  if (db_info_p->name == NULL)
922  goto error;
923 
924  if (path == NULL)
925  {
926  path = cfg_os_working_directory ();
927  }
928 
929  /*
930  * if NULL hosts is passed in, then create a new host list, with the
931  * local host as the primary.
932  */
933  if (hosts == NULL)
934  {
935  db_info_p->hosts = cfg_get_hosts (NULL, &db_info_p->num_hosts, true);
936  }
937  else
938  {
939  db_info_p->hosts = cfg_copy_hosts (hosts, &db_info_p->num_hosts);
940  }
941 
942  db_info_p->pathname = (path != NULL) ? strdup (path) : NULL;
943  if (db_info_p->pathname == NULL)
944  {
945  goto error;
946  }
947 
948  if (logpath == NULL)
949  {
950  db_info_p->logpath = strdup (db_info_p->pathname);
951  }
952  else
953  {
954  db_info_p->logpath = strdup (logpath);
955  }
956 
957  if (db_info_p->logpath == NULL)
958  {
959  goto error;
960  }
961 
962  if (lobpath != NULL)
963  {
964  db_info_p->lobpath = strdup (lobpath);
965  }
966 
967  db_info_p->next = NULL;
968 
969  return (db_info_p);
970 
971 error:
972  if (db_info_p != NULL)
973  {
974  if (db_info_p->name != NULL)
975  {
976  free_and_init (db_info_p->name);
977  }
978  if (db_info_p->pathname != NULL)
979  {
980  free_and_init (db_info_p->pathname);
981  }
982  if (db_info_p->logpath != NULL)
983  {
984  free_and_init (db_info_p->logpath);
985  }
986  if (db_info_p->lobpath != NULL)
987  {
988  free_and_init (db_info_p->lobpath);
989  }
990  if (db_info_p->hosts != NULL)
991  {
992  free_and_init (db_info_p->hosts);
993  }
994 
995  free_and_init (db_info_p);
996  }
997 
998  return NULL;
999 }
1000 
1001 /*
1002  * cfg_find_db_list()
1003  * return: database descriptor
1004  * dir(in): descriptor list
1005  * name(in): database name
1006  */
1007 DB_INFO *
1008 cfg_find_db_list (DB_INFO * db_info_list_p, const char *name)
1009 {
1010  DB_INFO *db_info_p, *found_info_p;
1011 
1012  found_info_p = NULL;
1013  for (db_info_p = db_info_list_p; db_info_p != NULL && found_info_p == NULL; db_info_p = db_info_p->next)
1014  {
1015  if (strcmp (db_info_p->name, name) == 0)
1016  {
1017  found_info_p = db_info_p;
1018  }
1019  }
1020 
1021  return (found_info_p);
1022 }
1023 
1024 /*
1025  * cfg_add_db() - Creates a new hosts array and DB_INFO structure and pops
1026  * the structure into the dir linked-list.
1027  * return: new database descriptor
1028  * dir(in/out): pointer to directory list
1029  * name(in): database name
1030  * path(in): directory path
1031  * logpath(in): log path
1032  * lobpath(in): lob path
1033  */
1034 DB_INFO *
1035 cfg_add_db (DB_INFO ** dir, const char *name, const char *path, const char *logpath, const char *lobpath,
1036  const char *host)
1037 {
1038  DB_INFO *db_info_p;
1039 
1040  if (host != NULL)
1041  {
1042  const char *hosts[2];
1043  hosts[0] = host;
1044  hosts[1] = NULL;
1045  db_info_p = cfg_new_db (name, path, logpath, lobpath, hosts);
1046  }
1047  else
1048  {
1049  db_info_p = cfg_new_db (name, path, logpath, lobpath, NULL);
1050  }
1051 
1052  if (db_info_p != NULL)
1053  {
1054  db_info_p->next = *dir;
1055  *dir = db_info_p;
1056  }
1057 
1058  return (db_info_p);
1059 }
1060 
1061 /*
1062  * cfg_find_db()
1063  * return: database descriptor
1064  * db_name(in): database name
1065  */
1066 DB_INFO *
1067 cfg_find_db (const char *db_name)
1068 {
1069  DB_INFO *dir_info_p, *db_info_p;
1070 
1071  db_info_p = NULL;
1072 
1073  if (cfg_read_directory (&dir_info_p, false) == NO_ERROR)
1074  {
1075  if (dir_info_p == NULL)
1076  {
1077 #if !defined(CS_MODE)
1079 #else /* !CS_MODE */
1081 #endif /* !CS_MODE */
1082  }
1083  else
1084  {
1085  db_info_p = cfg_find_db_list (dir_info_p, db_name);
1086  if (db_info_p == NULL)
1087  {
1088 #if !defined(CS_MODE)
1090 #else /* !CS_MODE */
1092 #endif /* !CS_MODE */
1093  }
1094  else
1095  {
1096  if (db_info_p->hosts != NULL)
1097  {
1098  db_info_p = cfg_new_db (db_info_p->name, db_info_p->pathname, db_info_p->logpath, db_info_p->lobpath,
1099  (const char **) db_info_p->hosts);
1100  }
1101  else
1102  {
1103  db_info_p = cfg_new_db (db_info_p->name, db_info_p->pathname, db_info_p->logpath, db_info_p->lobpath,
1104  NULL);
1105  }
1106  }
1107  cfg_free_directory (dir_info_p);
1108  }
1109  }
1110  else
1111  {
1112 #if !defined(CS_MODE)
1114 #else /* !CS_MODE */
1116 #endif /* !CS_MODE */
1117  }
1118  return (db_info_p);
1119 }
1120 
1121 /*
1122  * cfg_delete_db() - Deletes a database entry from a directory list.
1123  * return: if success is return true, otherwise return false
1124  * dir_info_p(in): pointer to directory list
1125  * name(in): database name
1126  */
1127 bool
1128 cfg_delete_db (DB_INFO ** dir_info_p, const char *name)
1129 {
1130  DB_INFO *db_info_p, *prev_info_p, *found_info_p;
1131  bool success = false;
1132 
1133  for (db_info_p = *dir_info_p, found_info_p = NULL, prev_info_p = NULL; db_info_p != NULL && found_info_p == NULL;
1134  db_info_p = db_info_p->next)
1135  {
1136  if (strcmp (db_info_p->name, name) == 0)
1137  {
1138  found_info_p = db_info_p;
1139  }
1140  else
1141  {
1142  prev_info_p = db_info_p;
1143  }
1144  }
1145  if (found_info_p != NULL)
1146  {
1147  if (prev_info_p == NULL)
1148  {
1149  *dir_info_p = found_info_p->next;
1150  }
1151  else
1152  {
1153  prev_info_p->next = found_info_p->next;
1154  }
1155  found_info_p->next = NULL;
1156  cfg_free_directory (found_info_p);
1157  success = true;
1158  }
1159  return (success);
1160 }
1161 
1162 /*
1163  * cfg_get_hosts() - assigns value count, to the number of hosts in array.
1164  * cfg_free_hosts should be called to free up memory used
1165  * by the array
1166  * return: pointer to an array containing the host list.
1167  * dbname(in): database name to connect to. (this is for future use)
1168  * prim_host(in): primary hostname for database.
1169  * count(in): count will contain the number of host found after processing
1170  * include_local_host(in): boolean indicating if the local host name should
1171  * be prepended to the list.
1172  */
1173 char **
1174 cfg_get_hosts (const char *prim_host, int *count, bool include_local_host)
1175 {
1176  /* pointers to array of hosts, to return */
1177  char **host_array;
1178  char *hosts_data;
1179  int i;
1180 
1181  *count = 0;
1182 
1183  /*
1184  * get a clean host list, i.e., null fields and duplicate hosts removed.
1185  * prim_host will be prepended to the list, and the local host will
1186  * will be appended if include_local_host is true.
1187  */
1188  hosts_data = cfg_create_host_list (prim_host, include_local_host, count);
1189  if (*count == 0 || hosts_data == NULL)
1190  {
1191  return NULL;
1192  }
1193 
1194  /* create a list of pointers to point to the hosts in hosts_data */
1195  host_array = (char **) calloc (*count + 1, sizeof (char **));
1196  if (host_array == NULL)
1197  {
1198  free_and_init (hosts_data);
1199  return NULL;
1200  }
1201  for (i = 0; i < *count; i++)
1202  {
1203  host_array[i] = hosts_data;
1204  hosts_data = strchr (hosts_data, CFG_HOST_SEPARATOR);
1205  if (hosts_data == NULL)
1206  {
1207  break;
1208  }
1209 
1210  *hosts_data++ = '\0';
1211  }
1212 
1213  return host_array;
1214 }
1215 
1216 /*
1217  * cfg_free_hosts() - free_and_init's host_array and *host_array if not NULL
1218  * return: none
1219  * host_array(in): array of pointers to buffer containing hostnames.
1220  */
1221 void
1222 cfg_free_hosts (char **host_array)
1223 {
1224  if (host_array != NULL)
1225  {
1226  if (*host_array != NULL)
1227  {
1228  free_and_init (*host_array);
1229  }
1230  free_and_init (host_array);
1231  }
1232 }
1233 
1234 /*
1235  * cfg_pop_host() - pointer to next character in string
1236  * return: returns pointer to next character in string
1237  * host_list(in): String containing list of hosts
1238  * buffer(in): Buffer to pop in hostname.
1239  * length(out): Returns the length of the hostname, popped.
1240  * -1 indicates that the hostname was too long > MAXHOSTLEN,
1241  * and buffer is empty
1242  *
1243  * Note : Sending in a NULL buffer will mean the function will assign length
1244  * to the length of the next host in the list only.
1245  */
1246 static const char *
1247 cfg_pop_host (const char *host_list, char *buffer, int *length)
1248 {
1249  int current_host_length = 0;
1250  const char *start, *host;
1251 
1252  host = host_list;
1253 
1254  if (buffer != NULL)
1255  {
1256  *buffer = '\0';
1257  }
1258 
1259  /* Ignore initial spaces/field separators in list */
1260 
1261  while (((char_isspace (*host)) || (*host == CFG_HOST_SEPARATOR)) && (*host != '\0'))
1262  {
1263  ++host;
1264  }
1265 
1266  /* Read in next host, and make a note of its length */
1267 
1268  start = host;
1269  current_host_length = 0;
1270 
1271  while ((*host != CFG_HOST_SEPARATOR) && (!char_isspace (*host)) && (*host != '\0'))
1272  {
1273  host++;
1274  current_host_length++;
1275  }
1276 
1277  /*
1278  * Increment count if we have a valid hostname, and we have reached,
1279  * a field separator, a space or end of line.
1280  * Copy host into buffer supplied.
1281  */
1282  if (((*host == CFG_HOST_SEPARATOR) || (char_isspace (*host)) || (*host == '\0')) && (current_host_length != 0))
1283  {
1284  /* Note buffer is empty if length of host is greater than CUB_MAXHOSTNAMELEN) */
1285  if ((buffer != NULL) && (current_host_length <= CUB_MAXHOSTNAMELEN))
1286  {
1287  strncpy (buffer, start, current_host_length);
1288  *(buffer + current_host_length) = '\0';
1289  }
1290  }
1291 
1292  if (current_host_length >= CUB_MAXHOSTNAMELEN)
1293  {
1294  *length = (-1);
1295  }
1296  else
1297  {
1298  *length = current_host_length;
1299  }
1300  return (host);
1301 }
1302 
1303 /*
1304  * cfg_host_exists() - Traverses the host_list to locate hostname.
1305  * return: true if item exists.
1306  * host_list(in): Pointer to array holding host names
1307  * hostname(in): host name to search for.
1308  * num_items(in): The number of items currently in the list
1309  */
1310 static bool
1311 cfg_host_exists (char *host_list, char *hostname, int num_items)
1312 {
1313  char *current_host;
1314  char *next_sep;
1315  int i = 0, len, hostname_len;
1316 
1317  hostname_len = (int) strlen (hostname);
1318 
1319  current_host = host_list;
1320  while ((current_host != NULL) && (i < num_items))
1321  {
1322  next_sep = strchr (current_host, CFG_HOST_SEPARATOR);
1323  if (next_sep == NULL)
1324  {
1325  if (strcmp (current_host, hostname) == 0)
1326  {
1327  return true;
1328  }
1329  else
1330  {
1331  return false;
1332  }
1333  }
1334  else
1335  {
1336  len = CAST_STRLEN (next_sep - current_host);
1337 
1338  if (len == hostname_len && strncmp (current_host, hostname, len) == 0)
1339  {
1340  return true;
1341  }
1342  }
1343 
1344  i++;
1345  current_host = next_sep + 1;
1346  }
1347  return false;
1348 } /* cfg_host_exists() */
1349 
1350 /*
1351  * cfg_copy_hosts() - a copy of the array holding hostnames.
1352  * return: returns a pointer to a copy of the array holding hostnames.
1353  * host_array(in): Pointer to array holding host names
1354  */
1355 static char **
1356 cfg_copy_hosts (const char **host_array, int *num_hosts)
1357 {
1358  char **new_array;
1359  const char *host;
1360  char *buffer;
1361  int num;
1362  size_t buffer_size;
1363 
1364  assert (host_array != NULL);
1365  assert (num_hosts != NULL);
1366 
1367  *num_hosts = 0;
1368  buffer_size = 0;
1369  /* count the number of hosts array and calculate the size of buffer */
1370  for (num = 0, host = host_array[0]; host; num++, host = host_array[num])
1371  {
1372  buffer_size += strlen (host) + 1;
1373  }
1374  if (num == 0)
1375  {
1376  return NULL;
1377  }
1378 
1379  /* copy the hosts array into the buffer and make new pointer array */
1380  buffer = (char *) malloc (buffer_size);
1381  if (buffer == NULL)
1382  {
1384  return NULL;
1385  }
1386 
1387  new_array = (char **) calloc (num + 1, sizeof (char **));
1388  if (new_array == NULL)
1389  {
1390  er_set (ER_ERROR_SEVERITY, ARG_FILE_LINE, ER_OUT_OF_VIRTUAL_MEMORY, 1, ((num + 1) * sizeof (char **)));
1391  free_and_init (buffer);
1392  return NULL;
1393  }
1394 
1395  for (num = 0, host = host_array[0]; host; num++, host = host_array[num])
1396  {
1397  strcpy (buffer, host);
1398  new_array[num] = buffer;
1399  buffer += strlen (host) + 1;
1400  }
1401 
1402  if (host_array[0] == NULL)
1403  {
1404  free_and_init (buffer);
1405  }
1406 
1407  *num_hosts = num;
1408 
1409  return new_array;
1410 }
1411 
1412 /*
1413  * cfg_create_host_lsit()
1414  * return: returns a pointer to a copy of the array holding hostnames
1415  * primary_host_name(in): String containing primary host name.
1416  * include_local_host(in): Flag indicating if the local hostname should be
1417  * included in the list.
1418  * count(out): Pointer to integer which will be assigned the number of hosts
1419  * in list.
1420  *
1421  * Note : Null or empty hostnames are ignored, and duplicates are not
1422  * included in the list.
1423  */
1424 char *
1425 cfg_create_host_list (const char *primary_host_name, bool include_local_host, int *count)
1426 {
1427  int host_list_length, host_length, host_count;
1428  const char *str_ptr;
1429  char *full_host_list, *host_ptr;
1430  char local_host[CUB_MAXHOSTNAMELEN + 1];
1431 
1432  assert (count != NULL);
1433 
1434  host_list_length = 0;
1435  /* include local host to list if required */
1436  *local_host = '\0';
1437  if (include_local_host)
1438  {
1439 #if 0 /* use Unix-domain socket for localhost */
1440  if (GETHOSTNAME (local_host, CUB_MAXHOSTNAMELEN) == 0)
1441  {
1442  local_host[CUB_MAXHOSTNAMELEN] = '\0';
1443  host_list_length += strlen (local_host) + 1;
1444  }
1445 #else
1446  strcpy (local_host, "localhost");
1447  host_list_length += (int) strlen (local_host) + 1;
1448 #endif
1449  }
1450  /* check the given primary hosts list */
1451  if (primary_host_name != NULL && *primary_host_name != '\0')
1452  {
1453  host_list_length += (int) strlen (primary_host_name) + 1;
1454  }
1455 
1456  /* get the hosts list from parameters */
1458  {
1459  host_list_length += (int) strlen (prm_get_string_value (PRM_ID_CFG_DB_HOSTS)) + 1;
1460  }
1461 
1462  /*
1463  * concatenate host lists with separator
1464  * count the number of hosts in the list
1465  * ignore null and space
1466  * removing duplicates
1467  */
1468  if (host_list_length == 0)
1469  {
1470  return NULL;
1471  }
1472  full_host_list = (char *) malloc (host_list_length + 1);
1473  if (full_host_list == NULL)
1474  {
1475  return NULL;
1476  }
1477  host_count = 0;
1478  host_ptr = full_host_list;
1479  *host_ptr = '\0';
1480  /* add the given primary hosts to the list */
1481  if (primary_host_name != NULL && *primary_host_name != '\0')
1482  {
1483  str_ptr = primary_host_name;
1484  while (*str_ptr != '\0')
1485  {
1486  str_ptr = cfg_pop_host (str_ptr, host_ptr, &host_length);
1487  if (host_length > 0)
1488  {
1489  if (!cfg_host_exists (full_host_list, host_ptr, host_count))
1490  {
1491  host_count++;
1492  host_ptr += host_length;
1493  *host_ptr++ = CFG_HOST_SEPARATOR;
1494  }
1495  *host_ptr = '\0';
1496  }
1497  }
1498  }
1499  /* append the hosts from the parameter to the list */
1501  {
1503  while (*str_ptr != '\0')
1504  {
1505  str_ptr = cfg_pop_host (str_ptr, host_ptr, &host_length);
1506  if (host_length > 0)
1507  {
1508  if (!cfg_host_exists (full_host_list, host_ptr, host_count))
1509  {
1510  host_count++;
1511  host_ptr += host_length;
1512  *host_ptr++ = CFG_HOST_SEPARATOR;
1513  }
1514  *host_ptr = '\0';
1515  }
1516  }
1517  }
1518  /* append local host if exists */
1519  if (*local_host != '\0')
1520  {
1521  if (!cfg_host_exists (full_host_list, local_host, host_count))
1522  {
1523  strcpy (host_ptr, local_host);
1524  host_ptr += strlen (local_host);
1525  host_count++;
1526  }
1527  }
1528 
1529  /* remove last separator */
1530  host_ptr--;
1531  if (*host_ptr == CFG_HOST_SEPARATOR)
1532  {
1533  *host_ptr = '\0';
1534  }
1535 
1536  /* return host list and counter */
1537  if (host_count != 0)
1538  {
1539  *count = host_count;
1540  return full_host_list;
1541  }
1542 
1543  /* no valid host name */
1544  free_and_init (full_host_list);
1545  return NULL;
1546 }
int char_isspace(int c)
Definition: chartype.c:109
char * cfg_maycreate_get_directory_filename(char *buffer)
#define NO_ERROR
Definition: error_code.h:46
DB_INFO * cfg_find_db(const char *db_name)
static FILE * cfg_open_directory_file(bool write_flag)
char ** cfg_get_hosts(const char *prim_host, int *count, bool include_local_host)
void cfg_free_hosts(char **host_array)
#define ER_FAILED
Definition: error_code.h:47
#define ER_CFG_FIND_DATABASE
Definition: error_code.h:820
void cfg_update_db(DB_INFO *db_info_p, const char *path, const char *logpath, const char *lobpath, const char *host)
static char ** cfg_copy_hosts(const char **host_array, int *num_hosts)
#define CAST_STRLEN
Definition: porting.h:470
#define DATABASES_FILENAME
static int cfg_ensure_directory_write(void)
static char * cfg_next_line(char *str_p)
static char * cfg_next_char(char *str_p)
void er_set(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
char * cfg_create_host_list(const char *primary_host_name, bool include_local_host, int *count)
#define assert(x)
static char * cfg_pop_token(char *str_p, char **token_p)
#define ER_OUT_OF_VIRTUAL_MEMORY
Definition: error_code.h:50
static char * cfg_pop_linetoken(char *str_p, char **token_p)
#define DB_SIZEOF(val)
Definition: memory_alloc.h:54
#define NULL
Definition: freelistheap.h:34
static int success()
char * cfg_os_working_directory(void)
bool cfg_delete_db(DB_INFO **dir_info_p, const char *name)
int char_iseol(int c)
Definition: chartype.c:121
static char CFG_HOST_SEPARATOR
int cfg_read_directory_ex(int vdes, DB_INFO **info_p, bool write_flag)
char * db_name
void er_set_with_oserror(int severity, const char *file_name, const int line_no, int err_id, int num_args,...)
int count(int &result, const cub_regex_object &reg, const std::string &src, const int position, const INTL_CODESET codeset)
DB_INFO * cfg_add_db(DB_INFO **dir, const char *name, const char *path, const char *logpath, const char *lobpath, const char *host)
#define DATABASES_ENVNAME
const char * envvar_get(const char *name)
static void error(const char *msg)
Definition: gencat.c:331
#define ARG_FILE_LINE
Definition: error_manager.h:44
char * envvar_vardir_file(char *path, size_t size, const char *filename)
int cfg_read_directory(DB_INFO **info_p, bool write_flag)
static bool cfg_host_exists(char *host_list, char *hostname, int num_items)
#define free_and_init(ptr)
Definition: memory_alloc.h:147
#define strlen(s1)
Definition: intl_support.c:43
char * prm_get_string_value(PARAM_ID prm_id)
static const char * cfg_pop_host(const char *host_list, char *buffer, int *length)
#define ER_CFG_INVALID_DATABASES
Definition: error_code.h:1092
int i
Definition: dynamic_load.c:954
char * strdup(const char *str)
Definition: porting.c:901
#define HA_DISABLED()
DB_INFO * next
#define ER_CFG_NO_WRITE_ACCESS
Definition: error_code.h:239
void cfg_write_directory_ex(int vdes, const DB_INFO *databases)
static void cfg_get_directory_filename(char *buffer, int *local)
#define CUB_MAXHOSTNAMELEN
Definition: porting.h:379
static char * host
void cfg_free_directory(DB_INFO *databases)
#define CFG_MAX_LINE
#define GETHOSTNAME(p, l)
Definition: porting.h:381
const char ** p
Definition: dynamic_load.c:945
DB_INFO * cfg_new_db(const char *name, const char *path, const char *logpath, const char *lobpath, const char **hosts)
#define ER_CFG_READ_DATABASES
Definition: error_code.h:819
DB_INFO * cfg_find_db_list(DB_INFO *db_info_list_p, const char *name)
void cfg_write_directory(const DB_INFO *databases)