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