~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2005 MySQL AB
2
3
   This program is free software; you can redistribute it and/or modify
4
   it under the terms of the GNU General Public License as published by
5
   the Free Software Foundation; version 2 of the License.
6
7
   This program is distributed in the hope that it will be useful,
8
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
   GNU General Public License for more details.
11
12
   You should have received a copy of the GNU General Public License
13
   along with this program; if not, write to the Free Software
14
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
16
#include "my_global.h"
17
#include "mysys_priv.h"
18
#include "m_string.h"
19
#include <my_dir.h>
20
21
#define BUFF_SIZE 1024
22
#define RESERVE 1024                   /* Extend buffer with this extent */
23
24
#define NEWLINE "\n"
25
#define NEWLINE_LEN 1
26
27
static char *add_option(char *dst, const char *option_value,
28
			const char *option, int remove_option);
29
30
31
/*
32
  Add/remove option to the option file section.
33
34
  SYNOPSYS
35
    modify_defaults_file()
36
    file_location     The location of configuration file to edit
37
    option            The name of the option to look for (can be NULL)
38
    option value      The value of the option we would like to set (can be NULL)
39
    section_name      The name of the section (must be NOT NULL)
40
    remove_option     This defines what we want to remove:
41
                        - MY_REMOVE_NONE -- nothing to remove;
42
                        - MY_REMOVE_OPTION -- remove the specified option;
43
                        - MY_REMOVE_SECTION -- remove the specified section;
44
  IMPLEMENTATION
45
    We open the option file first, then read the file line-by-line,
46
    looking for the section we need. At the same time we put these lines
47
    into a buffer. Then we look for the option within this section and
48
    change/remove it. In the end we get a buffer with modified version of the
49
    file. Then we write it to the file, truncate it if needed and close it.
50
    Note that there is a small time gap, when the file is incomplete,
51
    and this theoretically might introduce a problem.
52
53
  RETURN
54
    0 - ok
55
    1 - some error has occured. Probably due to the lack of resourses
56
    2 - cannot open the file
57
*/
58
59
int modify_defaults_file(const char *file_location, const char *option,
60
                         const char *option_value,
61
                         const char *section_name, int remove_option)
62
{
63
  FILE *cnf_file;
15 by brian
Fix for stat, NETWARE removal
64
  struct stat file_stat;
1 by brian
clean slate
65
  char linebuff[BUFF_SIZE], *src_ptr, *dst_ptr, *file_buffer;
66
  size_t opt_len= 0, optval_len= 0, sect_len;
67
  uint nr_newlines= 0, buffer_size;
68
  my_bool in_section= FALSE, opt_applied= 0;
69
  uint reserve_extended;
70
  uint new_opt_len;
71
  int reserve_occupied= 0;
72
  DBUG_ENTER("modify_defaults_file");
73
74
  if (!(cnf_file= my_fopen(file_location, O_RDWR | O_BINARY, MYF(0))))
75
    DBUG_RETURN(2);
76
15 by brian
Fix for stat, NETWARE removal
77
  if (fstat(fileno(cnf_file), &file_stat))
1 by brian
clean slate
78
    goto malloc_err;
79
80
  if (option && option_value)
81
  {
82
    opt_len= strlen(option);
83
    optval_len= strlen(option_value);
84
  }
85
86
  new_opt_len= opt_len + 1 + optval_len + NEWLINE_LEN;
87
88
  /* calculate the size of the buffer we need */
89
  reserve_extended= (opt_len +
90
                     1 +                        /* For '=' char */
91
                     optval_len +               /* Option value len */
92
                     NEWLINE_LEN +              /* Space for newline */
93
                     RESERVE);                  /* Some additional space */
94
95
  buffer_size= (file_stat.st_size +
96
                1);                             /* The ending zero */
97
98
  /*
99
    Reserve space to read the contents of the file and some more
100
    for the option we want to add.
101
  */
102
  if (!(file_buffer= (char*) my_malloc(buffer_size + reserve_extended,
103
                                       MYF(MY_WME))))
104
    goto malloc_err;
105
106
  sect_len= strlen(section_name);
107
108
  for (dst_ptr= file_buffer; fgets(linebuff, BUFF_SIZE, cnf_file); )
109
  {
110
    /* Skip over whitespaces */
111
    for (src_ptr= linebuff; my_isspace(&my_charset_latin1, *src_ptr);
112
	 src_ptr++)
113
    {}
114
115
    if (!*src_ptr) /* Empty line */
116
    {
117
      nr_newlines++;
118
      continue;
119
    }
120
121
    /* correct the option (if requested) */
122
    if (option && in_section && !strncmp(src_ptr, option, opt_len) &&
123
        (*(src_ptr + opt_len) == '=' ||
124
         my_isspace(&my_charset_latin1, *(src_ptr + opt_len)) ||
125
         *(src_ptr + opt_len) == '\0'))
126
    {
127
      char *old_src_ptr= src_ptr;
128
      src_ptr= strend(src_ptr+ opt_len);        /* Find the end of the line */
129
130
      /* could be negative */
131
      reserve_occupied+= (int) new_opt_len - (int) (src_ptr - old_src_ptr);
132
      if (reserve_occupied >= (int) reserve_extended)
133
      {
134
        reserve_extended= (uint) reserve_occupied + RESERVE;
135
        if (!(file_buffer= (char*) my_realloc(file_buffer, buffer_size +
136
                                              reserve_extended,
137
                                              MYF(MY_WME|MY_FREE_ON_ERROR))))
138
          goto malloc_err;
139
      }
140
      opt_applied= 1;
141
      dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
142
    }
143
    else
144
    {
145
      /*
146
        If we are going to the new group and have an option to apply, do
147
        it now. If we are removing a single option or the whole section
148
        this will only trigger opt_applied flag.
149
      */
150
151
      if (in_section && !opt_applied && *src_ptr == '[')
152
      {
153
        dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
154
        opt_applied= 1;           /* set the flag to do write() later */
155
        reserve_occupied= new_opt_len+ opt_len + 1 + NEWLINE_LEN;
156
      }
157
158
      for (; nr_newlines; nr_newlines--)
159
        dst_ptr= strmov(dst_ptr, NEWLINE);
160
161
      /* Skip the section if MY_REMOVE_SECTION was given */
162
      if (!in_section || remove_option != MY_REMOVE_SECTION)
163
        dst_ptr= strmov(dst_ptr, linebuff);
164
    }
165
    /* Look for a section */
166
    if (*src_ptr == '[')
167
    {
168
      /* Copy the line to the buffer */
169
      if (!strncmp(++src_ptr, section_name, sect_len))
170
      {
171
        src_ptr+= sect_len;
172
        /* Skip over whitespaces. They are allowed after section name */
173
        for (; my_isspace(&my_charset_latin1, *src_ptr); src_ptr++)
174
        {}
175
176
        if (*src_ptr != ']')
177
        {
178
          in_section= FALSE;
179
          continue; /* Missing closing parenthesis. Assume this was no group */
180
        }
181
182
        if (remove_option == MY_REMOVE_SECTION)
183
          dst_ptr= dst_ptr - strlen(linebuff);
184
185
        in_section= TRUE;
186
      }
187
      else
188
        in_section= FALSE; /* mark that this section is of no interest to us */
189
    }
190
  }
191
192
  /*
193
    File ended. Apply an option or set opt_applied flag (in case of
194
    MY_REMOVE_SECTION) so that the changes are saved. Do not do anything
195
    if we are removing non-existent option.
196
  */
197
198
  if (!opt_applied && in_section && (remove_option != MY_REMOVE_OPTION))
199
  {
200
    /* New option still remains to apply at the end */
201
    if (!remove_option && *(dst_ptr - 1) != '\n')
202
      dst_ptr= strmov(dst_ptr, NEWLINE);
203
    dst_ptr= add_option(dst_ptr, option_value, option, remove_option);
204
    opt_applied= 1;
205
  }
206
  for (; nr_newlines; nr_newlines--)
207
    dst_ptr= strmov(dst_ptr, NEWLINE);
208
209
  if (opt_applied)
210
  {
211
    /* Don't write the file if there are no changes to be made */
30 by Brian Aker
Large file and ftruncate() support
212
    if (ftruncate(fileno(cnf_file), (my_off_t) (dst_ptr - file_buffer)) ||
1 by brian
clean slate
213
        my_fseek(cnf_file, 0, MY_SEEK_SET, MYF(0)) ||
214
        my_fwrite(cnf_file, (uchar*) file_buffer, (size_t) (dst_ptr - file_buffer),
215
                  MYF(MY_NABP)))
216
      goto err;
217
  }
218
  if (my_fclose(cnf_file, MYF(MY_WME)))
219
    DBUG_RETURN(1);
220
221
  my_free(file_buffer, MYF(0));
222
  DBUG_RETURN(0);
223
224
err:
225
  my_free(file_buffer, MYF(0));
226
malloc_err:
227
  my_fclose(cnf_file, MYF(0));
228
  DBUG_RETURN(1); /* out of resources */
229
}
230
231
232
static char *add_option(char *dst, const char *option_value,
233
			const char *option, int remove_option)
234
{
235
  if (!remove_option)
236
  {
237
    dst= strmov(dst, option);
238
    if (*option_value)
239
    {
240
      *dst++= '=';
241
      dst= strmov(dst, option_value);
242
    }
243
    /* add a newline */
244
    dst= strmov(dst, NEWLINE);
245
  }
246
  return dst;
247
}