1 : /*
2 : +----------------------------------------------------------------------+
3 : | Zend Engine |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1998-2007 Zend Technologies Ltd. (http://www.zend.com) |
6 : +----------------------------------------------------------------------+
7 : | This source file is subject to version 2.00 of the Zend license, |
8 : | that is bundled with this package in the file LICENSE, and is |
9 : | available through the world-wide-web at the following url: |
10 : | http://www.zend.com/license/2_00.txt. |
11 : | If you did not receive a copy of the Zend license and are unable to |
12 : | obtain it through the world-wide-web, please send a note to |
13 : | license@zend.com so we can mail you a copy immediately. |
14 : +----------------------------------------------------------------------+
15 : | Author: Zeev Suraski <zeev@zend.com> |
16 : +----------------------------------------------------------------------+
17 : */
18 :
19 : /* $Id: zend_ini.c,v 1.39.2.2.2.7 2007/03/06 21:08:05 tony2001 Exp $ */
20 :
21 : #include "zend.h"
22 : #include "zend_qsort.h"
23 : #include "zend_API.h"
24 : #include "zend_ini.h"
25 : #include "zend_alloc.h"
26 : #include "zend_operators.h"
27 : #include "zend_strtod.h"
28 :
29 : static HashTable *registered_zend_ini_directives;
30 :
31 : #define NO_VALUE_PLAINTEXT "no value"
32 : #define NO_VALUE_HTML "<i>no value</i>"
33 :
34 : /*
35 : * hash_apply functions
36 : */
37 : static int zend_remove_ini_entries(zend_ini_entry *ini_entry, int *module_number TSRMLS_DC)
38 243811 : {
39 243811 : if (ini_entry->module_number == *module_number) {
40 33941 : return 1;
41 : } else {
42 209870 : return 0;
43 : }
44 : }
45 :
46 :
47 : static int zend_restore_ini_entry_cb(zend_ini_entry *ini_entry, int stage TSRMLS_DC)
48 34 : {
49 34 : if (ini_entry->modified) {
50 34 : if (ini_entry->on_modify) {
51 34 : zend_try {
52 : /* even if on_modify bails out, we have to continue on with restoring,
53 : since there can be allocated variables that would be freed on MM shutdown
54 : and would lead to memory corruption later ini entry is modified again */
55 34 : ini_entry->on_modify(ini_entry, ini_entry->orig_value, ini_entry->orig_value_length, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage TSRMLS_CC);
56 34 : } zend_end_try();
57 : }
58 34 : efree(ini_entry->value);
59 34 : ini_entry->value = ini_entry->orig_value;
60 34 : ini_entry->value_length = ini_entry->orig_value_length;
61 34 : ini_entry->modified = 0;
62 34 : ini_entry->orig_value = NULL;
63 34 : ini_entry->orig_value_length = 0;
64 : }
65 34 : return 0;
66 : }
67 :
68 : static int zend_restore_ini_entry_wrapper(zend_ini_entry **ini_entry TSRMLS_DC)
69 34 : {
70 34 : zend_restore_ini_entry_cb(*ini_entry, ZEND_INI_STAGE_DEACTIVATE TSRMLS_CC);
71 34 : return 1;
72 : }
73 :
74 : /*
75 : * Startup / shutdown
76 : */
77 : ZEND_API int zend_ini_startup(TSRMLS_D)
78 220 : {
79 220 : registered_zend_ini_directives = (HashTable *) malloc(sizeof(HashTable));
80 :
81 220 : EG(ini_directives) = registered_zend_ini_directives;
82 220 : EG(modified_ini_directives) = NULL;
83 220 : if (zend_hash_init_ex(registered_zend_ini_directives, 100, NULL, NULL, 1, 0)==FAILURE) {
84 0 : return FAILURE;
85 : }
86 220 : return SUCCESS;
87 : }
88 :
89 :
90 : ZEND_API int zend_ini_shutdown(TSRMLS_D)
91 219 : {
92 219 : zend_hash_destroy(EG(ini_directives));
93 219 : free(EG(ini_directives));
94 219 : return SUCCESS;
95 : }
96 :
97 :
98 : ZEND_API int zend_ini_global_shutdown(TSRMLS_D)
99 0 : {
100 0 : zend_hash_destroy(registered_zend_ini_directives);
101 0 : free(registered_zend_ini_directives);
102 0 : return SUCCESS;
103 : }
104 :
105 :
106 : ZEND_API int zend_ini_deactivate(TSRMLS_D)
107 219 : {
108 219 : if (EG(modified_ini_directives)) {
109 28 : zend_hash_apply(EG(modified_ini_directives), (apply_func_t) zend_restore_ini_entry_wrapper TSRMLS_CC);
110 28 : zend_hash_destroy(EG(modified_ini_directives));
111 28 : FREE_HASHTABLE(EG(modified_ini_directives));
112 28 : EG(modified_ini_directives) = NULL;
113 : }
114 219 : return SUCCESS;
115 : }
116 :
117 :
118 : #ifdef ZTS
119 : ZEND_API int zend_copy_ini_directives(TSRMLS_D)
120 : {
121 : zend_ini_entry ini_entry;
122 :
123 : EG(modified_ini_directives) = NULL;
124 : EG(ini_directives) = (HashTable *) malloc(sizeof(HashTable));
125 : if (zend_hash_init_ex(EG(ini_directives), registered_zend_ini_directives->nNumOfElements, NULL, NULL, 1, 0)==FAILURE) {
126 : return FAILURE;
127 : }
128 : zend_hash_copy(EG(ini_directives), registered_zend_ini_directives, NULL, &ini_entry, sizeof(zend_ini_entry));
129 : return SUCCESS;
130 : }
131 : #endif
132 :
133 :
134 : static int ini_key_compare(const void *a, const void *b TSRMLS_DC)
135 0 : {
136 : Bucket *f;
137 : Bucket *s;
138 :
139 0 : f = *((Bucket **) a);
140 0 : s = *((Bucket **) b);
141 :
142 0 : if (f->nKeyLength==0 && s->nKeyLength==0) { /* both numeric */
143 0 : return ZEND_NORMALIZE_BOOL(f->nKeyLength - s->nKeyLength);
144 0 : } else if (f->nKeyLength==0) { /* f is numeric, s is not */
145 0 : return -1;
146 0 : } else if (s->nKeyLength==0) { /* s is numeric, f is not */
147 0 : return 1;
148 : } else { /* both strings */
149 0 : return zend_binary_strcasecmp(f->arKey, f->nKeyLength, s->arKey, s->nKeyLength);
150 : }
151 : }
152 :
153 :
154 : ZEND_API void zend_ini_sort_entries(TSRMLS_D)
155 0 : {
156 0 : zend_hash_sort(EG(ini_directives), zend_qsort, ini_key_compare, 0 TSRMLS_CC);
157 0 : }
158 :
159 : /*
160 : * Registration / unregistration
161 : */
162 :
163 : ZEND_API int zend_register_ini_entries(zend_ini_entry *ini_entry, int module_number TSRMLS_DC)
164 2639 : {
165 2639 : zend_ini_entry *p = ini_entry;
166 : zend_ini_entry *hashed_ini_entry;
167 : zval default_value;
168 2639 : HashTable *directives = registered_zend_ini_directives;
169 2639 : zend_bool config_directive_success = 0;
170 :
171 : #ifdef ZTS
172 : /* if we are called during the request, eg: from dl(),
173 : * then we should not touch the global directives table,
174 : * and should update the per-(request|thread) version instead.
175 : * This solves two problems: one is that ini entries for dl()'d
176 : * extensions will now work, and the second is that updating the
177 : * global hash here from dl() is not mutex protected and can
178 : * lead to death.
179 : */
180 : if (directives != EG(ini_directives)) {
181 : directives = EG(ini_directives);
182 : }
183 : #endif
184 :
185 39374 : while (p->name) {
186 34096 : p->module_number = module_number;
187 34096 : config_directive_success = 0;
188 34096 : if (zend_hash_add(directives, p->name, p->name_length, p, sizeof(zend_ini_entry), (void **) &hashed_ini_entry)==FAILURE) {
189 0 : zend_unregister_ini_entries(module_number TSRMLS_CC);
190 0 : return FAILURE;
191 : }
192 34096 : if ((zend_get_configuration_directive(p->name, p->name_length, &default_value))==SUCCESS) {
193 4373 : if (!hashed_ini_entry->on_modify
194 : || hashed_ini_entry->on_modify(hashed_ini_entry, default_value.value.str.val, default_value.value.str.len, hashed_ini_entry->mh_arg1, hashed_ini_entry->mh_arg2, hashed_ini_entry->mh_arg3, ZEND_INI_STAGE_STARTUP TSRMLS_CC)==SUCCESS) {
195 4373 : hashed_ini_entry->value = default_value.value.str.val;
196 4373 : hashed_ini_entry->value_length = default_value.value.str.len;
197 4373 : config_directive_success = 1;
198 : }
199 : }
200 :
201 34096 : if (!config_directive_success && hashed_ini_entry->on_modify) {
202 25761 : hashed_ini_entry->on_modify(hashed_ini_entry, hashed_ini_entry->value, hashed_ini_entry->value_length, hashed_ini_entry->mh_arg1, hashed_ini_entry->mh_arg2, hashed_ini_entry->mh_arg3, ZEND_INI_STAGE_STARTUP TSRMLS_CC);
203 : }
204 34096 : p++;
205 : }
206 2639 : return SUCCESS;
207 : }
208 :
209 :
210 : ZEND_API void zend_unregister_ini_entries(int module_number TSRMLS_DC)
211 1970 : {
212 1970 : zend_hash_apply_with_argument(registered_zend_ini_directives, (apply_func_arg_t) zend_remove_ini_entries, (void *) &module_number TSRMLS_CC);
213 1970 : }
214 :
215 :
216 : #ifdef ZTS
217 : static int zend_ini_refresh_cache(zend_ini_entry *p, int stage TSRMLS_DC)
218 : {
219 : if (p->on_modify) {
220 : p->on_modify(p, p->value, p->value_length, p->mh_arg1, p->mh_arg2, p->mh_arg3, stage TSRMLS_CC);
221 : }
222 : return 0;
223 : }
224 :
225 :
226 : ZEND_API void zend_ini_refresh_caches(int stage TSRMLS_DC)
227 : {
228 : zend_hash_apply_with_argument(EG(ini_directives), (apply_func_arg_t) zend_ini_refresh_cache, (void *)(long) stage TSRMLS_CC);
229 : }
230 : #endif
231 :
232 :
233 : ZEND_API int zend_alter_ini_entry(char *name, uint name_length, char *new_value, uint new_value_length, int modify_type, int stage)
234 9347 : {
235 : zend_ini_entry *ini_entry;
236 : char *duplicate;
237 : TSRMLS_FETCH();
238 :
239 9347 : if (zend_hash_find(EG(ini_directives), name, name_length, (void **) &ini_entry)==FAILURE) {
240 0 : return FAILURE;
241 : }
242 :
243 9347 : if (!(ini_entry->modifiable & modify_type)) {
244 0 : return FAILURE;
245 : }
246 :
247 9347 : duplicate = estrndup(new_value, new_value_length);
248 :
249 18693 : if (!ini_entry->on_modify
250 : || ini_entry->on_modify(ini_entry, duplicate, new_value_length, ini_entry->mh_arg1, ini_entry->mh_arg2, ini_entry->mh_arg3, stage TSRMLS_CC)==SUCCESS) {
251 9346 : if (!ini_entry->modified) {
252 34 : ini_entry->orig_value = ini_entry->value;
253 34 : ini_entry->orig_value_length = ini_entry->value_length;
254 34 : ini_entry->modified = 1;
255 34 : if (!EG(modified_ini_directives)) {
256 28 : ALLOC_HASHTABLE(EG(modified_ini_directives));
257 28 : zend_hash_init(EG(modified_ini_directives), 8, NULL, NULL, 0);
258 : }
259 34 : zend_hash_add(EG(modified_ini_directives), name, name_length, &ini_entry, sizeof(zend_ini_entry*), NULL);
260 : } else { /* we already changed the value, free the changed value */
261 9312 : efree(ini_entry->value);
262 : }
263 9346 : ini_entry->value = duplicate;
264 9346 : ini_entry->value_length = new_value_length;
265 : } else {
266 0 : efree(duplicate);
267 : }
268 :
269 9346 : return SUCCESS;
270 : }
271 :
272 :
273 : ZEND_API int zend_restore_ini_entry(char *name, uint name_length, int stage)
274 0 : {
275 : zend_ini_entry *ini_entry;
276 : TSRMLS_FETCH();
277 :
278 0 : if (zend_hash_find(EG(ini_directives), name, name_length, (void **) &ini_entry)==FAILURE ||
279 : (stage == ZEND_INI_STAGE_RUNTIME && (ini_entry->modifiable & ZEND_INI_USER) == 0)) {
280 0 : return FAILURE;
281 : }
282 :
283 0 : if (EG(modified_ini_directives)) {
284 0 : zend_restore_ini_entry_cb(ini_entry, stage TSRMLS_CC);
285 0 : zend_hash_del(EG(modified_ini_directives), name, name_length);
286 : }
287 :
288 0 : return SUCCESS;
289 : }
290 :
291 :
292 : ZEND_API int zend_ini_register_displayer(char *name, uint name_length, void (*displayer)(zend_ini_entry *ini_entry, int type))
293 0 : {
294 : zend_ini_entry *ini_entry;
295 :
296 0 : if (zend_hash_find(registered_zend_ini_directives, name, name_length, (void **) &ini_entry)==FAILURE) {
297 0 : return FAILURE;
298 : }
299 :
300 0 : ini_entry->displayer = displayer;
301 0 : return SUCCESS;
302 : }
303 :
304 :
305 :
306 : /*
307 : * Data retrieval
308 : */
309 :
310 : ZEND_API long zend_ini_long(char *name, uint name_length, int orig)
311 438 : {
312 : zend_ini_entry *ini_entry;
313 : TSRMLS_FETCH();
314 :
315 438 : if (zend_hash_find(EG(ini_directives), name, name_length, (void **) &ini_entry)==SUCCESS) {
316 438 : if (orig && ini_entry->modified) {
317 0 : return (ini_entry->orig_value ? strtol(ini_entry->orig_value, NULL, 0) : 0);
318 438 : } else if (ini_entry->value) {
319 438 : return strtol(ini_entry->value, NULL, 0);
320 : }
321 : }
322 :
323 0 : return 0;
324 : }
325 :
326 :
327 : ZEND_API double zend_ini_double(char *name, uint name_length, int orig)
328 0 : {
329 : zend_ini_entry *ini_entry;
330 : TSRMLS_FETCH();
331 :
332 0 : if (zend_hash_find(EG(ini_directives), name, name_length, (void **) &ini_entry)==SUCCESS) {
333 0 : if (orig && ini_entry->modified) {
334 0 : return (double) (ini_entry->orig_value ? zend_strtod(ini_entry->orig_value, NULL) : 0.0);
335 0 : } else if (ini_entry->value) {
336 0 : return (double) zend_strtod(ini_entry->value, NULL);
337 : }
338 : }
339 :
340 0 : return 0.0;
341 : }
342 :
343 :
344 : ZEND_API char *zend_ini_string(char *name, uint name_length, int orig)
345 933 : {
346 : zend_ini_entry *ini_entry;
347 : TSRMLS_FETCH();
348 :
349 933 : if (zend_hash_find(EG(ini_directives), name, name_length, (void **) &ini_entry)==SUCCESS) {
350 933 : if (orig && ini_entry->modified) {
351 0 : return ini_entry->orig_value;
352 : } else {
353 933 : return ini_entry->value;
354 : }
355 : }
356 :
357 0 : return "";
358 : }
359 :
360 : #if TONY_20070307
361 : static void zend_ini_displayer_cb(zend_ini_entry *ini_entry, int type)
362 : {
363 : if (ini_entry->displayer) {
364 : ini_entry->displayer(ini_entry, type);
365 : } else {
366 : char *display_string;
367 : uint display_string_length;
368 :
369 : if (type==ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
370 : if (ini_entry->orig_value) {
371 : display_string = ini_entry->orig_value;
372 : display_string_length = ini_entry->orig_value_length;
373 : } else {
374 : if (zend_uv.html_errors) {
375 : display_string = NO_VALUE_HTML;
376 : display_string_length = sizeof(NO_VALUE_HTML)-1;
377 : } else {
378 : display_string = NO_VALUE_PLAINTEXT;
379 : display_string_length = sizeof(NO_VALUE_PLAINTEXT)-1;
380 : }
381 : }
382 : } else if (ini_entry->value && ini_entry->value[0]) {
383 : display_string = ini_entry->value;
384 : display_string_length = ini_entry->value_length;
385 : } else {
386 : if (zend_uv.html_errors) {
387 : display_string = NO_VALUE_HTML;
388 : display_string_length = sizeof(NO_VALUE_HTML)-1;
389 : } else {
390 : display_string = NO_VALUE_PLAINTEXT;
391 : display_string_length = sizeof(NO_VALUE_PLAINTEXT)-1;
392 : }
393 : }
394 : ZEND_WRITE(display_string, display_string_length);
395 : }
396 : }
397 : #endif
398 :
399 : ZEND_INI_DISP(zend_ini_boolean_displayer_cb)
400 0 : {
401 : int value, tmp_value_len;
402 : char *tmp_value;
403 :
404 0 : if (type==ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
405 0 : tmp_value = (ini_entry->orig_value ? ini_entry->orig_value : NULL );
406 0 : tmp_value_len = ini_entry->orig_value_length;
407 0 : } else if (ini_entry->value) {
408 0 : tmp_value = ini_entry->value;
409 0 : tmp_value_len = ini_entry->value_length;
410 : } else {
411 0 : tmp_value = NULL;
412 0 : tmp_value_len = 0;
413 : }
414 :
415 0 : if (tmp_value_len == 4 && strcasecmp(tmp_value, "true") == 0) {
416 0 : value = 1;
417 : }
418 0 : else if (tmp_value_len == 3 && strcasecmp(tmp_value, "yes") == 0) {
419 0 : value = 1;
420 : }
421 0 : else if (tmp_value_len == 2 && strcasecmp(tmp_value, "on") == 0) {
422 0 : value = 1;
423 : }
424 : else {
425 0 : value = atoi(tmp_value);
426 : }
427 :
428 0 : if (value) {
429 0 : ZEND_PUTS("On");
430 : } else {
431 0 : ZEND_PUTS("Off");
432 : }
433 0 : }
434 :
435 :
436 : ZEND_INI_DISP(zend_ini_color_displayer_cb)
437 0 : {
438 : char *value;
439 :
440 0 : if (type==ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
441 0 : value = ini_entry->orig_value;
442 0 : } else if (ini_entry->value) {
443 0 : value = ini_entry->value;
444 : } else {
445 0 : value = NULL;
446 : }
447 0 : if (value) {
448 0 : if (zend_uv.html_errors) {
449 0 : zend_printf("<font style=\"color: %s\">%s</font>", value, value);
450 : } else {
451 0 : ZEND_PUTS(value);
452 : }
453 : } else {
454 0 : if (zend_uv.html_errors) {
455 0 : ZEND_PUTS(NO_VALUE_HTML);
456 : } else {
457 0 : ZEND_PUTS(NO_VALUE_PLAINTEXT);
458 : }
459 : }
460 0 : }
461 :
462 :
463 : ZEND_INI_DISP(display_link_numbers)
464 0 : {
465 : char *value;
466 :
467 0 : if (type==ZEND_INI_DISPLAY_ORIG && ini_entry->modified) {
468 0 : value = ini_entry->orig_value;
469 0 : } else if (ini_entry->value) {
470 0 : value = ini_entry->value;
471 : } else {
472 0 : value = NULL;
473 : }
474 :
475 0 : if (value) {
476 0 : if (atoi(value)==-1) {
477 0 : ZEND_PUTS("Unlimited");
478 : } else {
479 0 : zend_printf("%s", value);
480 : }
481 : }
482 0 : }
483 :
484 :
485 : /* Standard message handlers */
486 :
487 : ZEND_API ZEND_INI_MH(OnUpdateBool)
488 11662 : {
489 : zend_bool *p;
490 : #ifndef ZTS
491 11662 : char *base = (char *) mh_arg2;
492 : #else
493 : char *base;
494 :
495 : base = (char *) ts_resource(*((int *) mh_arg2));
496 : #endif
497 :
498 11662 : p = (zend_bool *) (base+(size_t) mh_arg1);
499 :
500 11662 : if (new_value_length==2 && strcasecmp("on", new_value)==0) {
501 0 : *p = (zend_bool) 1;
502 : }
503 11662 : else if (new_value_length==3 && strcasecmp("yes", new_value)==0) {
504 0 : *p = (zend_bool) 1;
505 : }
506 11662 : else if (new_value_length==4 && strcasecmp("true", new_value)==0) {
507 0 : *p = (zend_bool) 1;
508 : }
509 : else {
510 11662 : *p = (zend_bool) atoi(new_value);
511 : }
512 11662 : return SUCCESS;
513 : }
514 :
515 :
516 : ZEND_API ZEND_INI_MH(OnUpdateLong)
517 5940 : {
518 : long *p;
519 : #ifndef ZTS
520 5940 : char *base = (char *) mh_arg2;
521 : #else
522 : char *base;
523 :
524 : base = (char *) ts_resource(*((int *) mh_arg2));
525 : #endif
526 :
527 5940 : p = (long *) (base+(size_t) mh_arg1);
528 :
529 5940 : *p = zend_atoi(new_value, new_value_length);
530 5940 : return SUCCESS;
531 : }
532 :
533 : ZEND_API ZEND_INI_MH(OnUpdateLongGEZero)
534 440 : {
535 : long *p, tmp;
536 : #ifndef ZTS
537 440 : char *base = (char *) mh_arg2;
538 : #else
539 : char *base;
540 :
541 : base = (char *) ts_resource(*((int *) mh_arg2));
542 : #endif
543 :
544 440 : tmp = zend_atoi(new_value, new_value_length);
545 440 : if (tmp < 0) {
546 0 : return FAILURE;
547 : }
548 :
549 440 : p = (long *) (base+(size_t) mh_arg1);
550 440 : *p = tmp;
551 :
552 440 : return SUCCESS;
553 : }
554 :
555 :
556 : ZEND_API ZEND_INI_MH(OnUpdateReal)
557 0 : {
558 : double *p;
559 : #ifndef ZTS
560 0 : char *base = (char *) mh_arg2;
561 : #else
562 : char *base;
563 :
564 : base = (char *) ts_resource(*((int *) mh_arg2));
565 : #endif
566 :
567 0 : p = (double *) (base+(size_t) mh_arg1);
568 :
569 0 : *p = zend_strtod(new_value, NULL);
570 0 : return SUCCESS;
571 : }
572 :
573 :
574 : ZEND_API ZEND_INI_MH(OnUpdateString)
575 7948 : {
576 : char **p;
577 : #ifndef ZTS
578 7948 : char *base = (char *) mh_arg2;
579 : #else
580 : char *base;
581 :
582 : base = (char *) ts_resource(*((int *) mh_arg2));
583 : #endif
584 :
585 7948 : p = (char **) (base+(size_t) mh_arg1);
586 :
587 7948 : *p = new_value;
588 7948 : return SUCCESS;
589 : }
590 :
591 :
592 : ZEND_API ZEND_INI_MH(OnUpdateStringUnempty)
593 1540 : {
594 : char **p;
595 : #ifndef ZTS
596 1540 : char *base = (char *) mh_arg2;
597 : #else
598 : char *base;
599 :
600 : base = (char *) ts_resource(*((int *) mh_arg2));
601 : #endif
602 :
603 1540 : if (new_value && !new_value[0]) {
604 0 : return FAILURE;
605 : }
606 :
607 1540 : p = (char **) (base+(size_t) mh_arg1);
608 :
609 1540 : *p = new_value;
610 1540 : return SUCCESS;
611 : }
612 :
613 : /*
614 : * Local variables:
615 : * tab-width: 4
616 : * c-basic-offset: 4
617 : * indent-tabs-mode: t
618 : * End:
619 : */
|