1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2014 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP 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.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Authors: Ard Biesheuvel <a.k.biesheuvel@its.tudelft.nl>              |
16   +----------------------------------------------------------------------+
17 */
18
19#ifdef HAVE_CONFIG_H
20#include "config.h"
21#endif
22
23#include "php.h"
24
25#if HAVE_IBASE
26
27#include "php_interbase.h"
28#include "php_ibase_includes.h"
29
30typedef struct {
31    isc_svc_handle handle;
32    char *hostname;
33    char *username;
34    zend_resource *res;
35} ibase_service;
36
37static int le_service;
38
39static void _php_ibase_free_service(zend_resource *rsrc TSRMLS_DC) /* {{{ */
40{
41    ibase_service *sv = (ibase_service *) rsrc->ptr;
42
43    if (isc_service_detach(IB_STATUS, &sv->handle)) {
44        _php_ibase_error(TSRMLS_C);
45    }
46
47    if (sv->hostname) {
48        efree(sv->hostname);
49    }
50    if (sv->username) {
51        efree(sv->username);
52    }
53
54    efree(sv);
55}
56/* }}} */
57
58/* the svc api seems to get confused after an error has occurred,
59   so invalidate the handle on errors */
60#define IBASE_SVC_ERROR(svm) \
61    do { zend_list_delete(svm->res); _php_ibase_error(TSRMLS_C); } while (0)
62
63
64void php_ibase_service_minit(INIT_FUNC_ARGS) /* {{{ */
65{
66    le_service = zend_register_list_destructors_ex(_php_ibase_free_service, NULL,
67        "interbase service manager handle", module_number);
68
69    /* backup options */
70    REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_CHECKSUMS", isc_spb_bkp_ignore_checksums, CONST_PERSISTENT);
71    REGISTER_LONG_CONSTANT("IBASE_BKP_IGNORE_LIMBO", isc_spb_bkp_ignore_limbo, CONST_PERSISTENT);
72    REGISTER_LONG_CONSTANT("IBASE_BKP_METADATA_ONLY", isc_spb_bkp_metadata_only, CONST_PERSISTENT);
73    REGISTER_LONG_CONSTANT("IBASE_BKP_NO_GARBAGE_COLLECT", isc_spb_bkp_no_garbage_collect, CONST_PERSISTENT);
74    REGISTER_LONG_CONSTANT("IBASE_BKP_OLD_DESCRIPTIONS", isc_spb_bkp_old_descriptions, CONST_PERSISTENT);
75    REGISTER_LONG_CONSTANT("IBASE_BKP_NON_TRANSPORTABLE", isc_spb_bkp_non_transportable, CONST_PERSISTENT);
76    REGISTER_LONG_CONSTANT("IBASE_BKP_CONVERT", isc_spb_bkp_convert, CONST_PERSISTENT);
77
78    /* restore options */
79    REGISTER_LONG_CONSTANT("IBASE_RES_DEACTIVATE_IDX", isc_spb_res_deactivate_idx, CONST_PERSISTENT);
80    REGISTER_LONG_CONSTANT("IBASE_RES_NO_SHADOW", isc_spb_res_no_shadow, CONST_PERSISTENT);
81    REGISTER_LONG_CONSTANT("IBASE_RES_NO_VALIDITY", isc_spb_res_no_validity, CONST_PERSISTENT);
82    REGISTER_LONG_CONSTANT("IBASE_RES_ONE_AT_A_TIME", isc_spb_res_one_at_a_time, CONST_PERSISTENT);
83    REGISTER_LONG_CONSTANT("IBASE_RES_REPLACE", isc_spb_res_replace, CONST_PERSISTENT);
84    REGISTER_LONG_CONSTANT("IBASE_RES_CREATE", isc_spb_res_create, CONST_PERSISTENT);
85    REGISTER_LONG_CONSTANT("IBASE_RES_USE_ALL_SPACE", isc_spb_res_use_all_space, CONST_PERSISTENT);
86
87    /* manage options */
88    REGISTER_LONG_CONSTANT("IBASE_PRP_PAGE_BUFFERS", isc_spb_prp_page_buffers, CONST_PERSISTENT);
89    REGISTER_LONG_CONSTANT("IBASE_PRP_SWEEP_INTERVAL", isc_spb_prp_sweep_interval, CONST_PERSISTENT);
90    REGISTER_LONG_CONSTANT("IBASE_PRP_SHUTDOWN_DB", isc_spb_prp_shutdown_db, CONST_PERSISTENT);
91    REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_TRANSACTIONS", isc_spb_prp_deny_new_transactions, CONST_PERSISTENT);
92    REGISTER_LONG_CONSTANT("IBASE_PRP_DENY_NEW_ATTACHMENTS", isc_spb_prp_deny_new_attachments, CONST_PERSISTENT);
93    REGISTER_LONG_CONSTANT("IBASE_PRP_RESERVE_SPACE", isc_spb_prp_reserve_space, CONST_PERSISTENT);
94      REGISTER_LONG_CONSTANT("IBASE_PRP_RES_USE_FULL", isc_spb_prp_res_use_full, CONST_PERSISTENT);
95      REGISTER_LONG_CONSTANT("IBASE_PRP_RES", isc_spb_prp_res, CONST_PERSISTENT);
96    REGISTER_LONG_CONSTANT("IBASE_PRP_WRITE_MODE", isc_spb_prp_write_mode, CONST_PERSISTENT);
97      REGISTER_LONG_CONSTANT("IBASE_PRP_WM_ASYNC", isc_spb_prp_wm_async, CONST_PERSISTENT);
98      REGISTER_LONG_CONSTANT("IBASE_PRP_WM_SYNC", isc_spb_prp_wm_sync, CONST_PERSISTENT);
99    REGISTER_LONG_CONSTANT("IBASE_PRP_ACCESS_MODE", isc_spb_prp_access_mode, CONST_PERSISTENT);
100      REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READONLY", isc_spb_prp_am_readonly, CONST_PERSISTENT);
101      REGISTER_LONG_CONSTANT("IBASE_PRP_AM_READWRITE", isc_spb_prp_am_readwrite, CONST_PERSISTENT);
102    REGISTER_LONG_CONSTANT("IBASE_PRP_SET_SQL_DIALECT", isc_spb_prp_set_sql_dialect, CONST_PERSISTENT);
103    REGISTER_LONG_CONSTANT("IBASE_PRP_ACTIVATE", isc_spb_prp_activate, CONST_PERSISTENT);
104    REGISTER_LONG_CONSTANT("IBASE_PRP_DB_ONLINE", isc_spb_prp_db_online, CONST_PERSISTENT);
105
106    /* repair options */
107    REGISTER_LONG_CONSTANT("IBASE_RPR_CHECK_DB", isc_spb_rpr_check_db, CONST_PERSISTENT);
108    REGISTER_LONG_CONSTANT("IBASE_RPR_IGNORE_CHECKSUM", isc_spb_rpr_ignore_checksum, CONST_PERSISTENT);
109    REGISTER_LONG_CONSTANT("IBASE_RPR_KILL_SHADOWS", isc_spb_rpr_kill_shadows, CONST_PERSISTENT);
110    REGISTER_LONG_CONSTANT("IBASE_RPR_MEND_DB", isc_spb_rpr_mend_db, CONST_PERSISTENT);
111    REGISTER_LONG_CONSTANT("IBASE_RPR_VALIDATE_DB", isc_spb_rpr_validate_db, CONST_PERSISTENT);
112      REGISTER_LONG_CONSTANT("IBASE_RPR_FULL", isc_spb_rpr_full, CONST_PERSISTENT);
113    REGISTER_LONG_CONSTANT("IBASE_RPR_SWEEP_DB", isc_spb_rpr_sweep_db, CONST_PERSISTENT);
114
115    /* db info arguments */
116    REGISTER_LONG_CONSTANT("IBASE_STS_DATA_PAGES", isc_spb_sts_data_pages, CONST_PERSISTENT);
117    REGISTER_LONG_CONSTANT("IBASE_STS_DB_LOG", isc_spb_sts_db_log, CONST_PERSISTENT);
118    REGISTER_LONG_CONSTANT("IBASE_STS_HDR_PAGES", isc_spb_sts_hdr_pages, CONST_PERSISTENT);
119    REGISTER_LONG_CONSTANT("IBASE_STS_IDX_PAGES", isc_spb_sts_idx_pages, CONST_PERSISTENT);
120    REGISTER_LONG_CONSTANT("IBASE_STS_SYS_RELATIONS", isc_spb_sts_sys_relations, CONST_PERSISTENT);
121
122    /* server info arguments */
123    REGISTER_LONG_CONSTANT("IBASE_SVC_SERVER_VERSION", isc_info_svc_server_version, CONST_PERSISTENT);
124    REGISTER_LONG_CONSTANT("IBASE_SVC_IMPLEMENTATION", isc_info_svc_implementation, CONST_PERSISTENT);
125    REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV", isc_info_svc_get_env, CONST_PERSISTENT);
126    REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_LOCK", isc_info_svc_get_env_lock, CONST_PERSISTENT);
127    REGISTER_LONG_CONSTANT("IBASE_SVC_GET_ENV_MSG", isc_info_svc_get_env_msg, CONST_PERSISTENT);
128    REGISTER_LONG_CONSTANT("IBASE_SVC_USER_DBPATH", isc_info_svc_user_dbpath, CONST_PERSISTENT);
129    REGISTER_LONG_CONSTANT("IBASE_SVC_SVR_DB_INFO", isc_info_svc_svr_db_info, CONST_PERSISTENT);
130    REGISTER_LONG_CONSTANT("IBASE_SVC_GET_USERS", isc_info_svc_get_users, CONST_PERSISTENT);
131}
132/* }}} */
133
134static void _php_ibase_user(INTERNAL_FUNCTION_PARAMETERS, char operation) /* {{{ */
135{
136    /* user = 0, password = 1, first_name = 2, middle_name = 3, last_name = 4 */
137    static char const user_flags[] = { isc_spb_sec_username, isc_spb_sec_password,
138        isc_spb_sec_firstname, isc_spb_sec_middlename, isc_spb_sec_lastname };
139    char buf[128], *args[] = { NULL, NULL, NULL, NULL, NULL };
140    int i, args_len[] = { 0, 0, 0, 0, 0 };
141    unsigned short spb_len = 1;
142    zval *res;
143    ibase_service *svm;
144
145    RESET_ERRMSG;
146
147    if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
148            (operation == isc_action_svc_delete_user) ? "rs" : "rss|sss",
149            &res, &args[0], &args_len[0], &args[1], &args_len[1], &args[2], &args_len[2],
150            &args[3], &args_len[3], &args[4], &args_len[4])) {
151        RETURN_FALSE;
152    }
153
154    ZEND_FETCH_RESOURCE(svm, ibase_service *, res, -1, "Interbase service manager handle",
155        le_service);
156
157    buf[0] = operation;
158
159    for (i = 0; i < sizeof(user_flags); ++i) {
160        if (args[i] != NULL) {
161            int chunk = slprintf(&buf[spb_len], sizeof(buf) - spb_len, "%c%c%c%s",
162                user_flags[i], (char)args_len[i], (char)(args_len[i] >> 8), args[i]);
163
164            if ((spb_len + chunk) > sizeof(buf) || chunk <= 0) {
165                _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)"
166                    TSRMLS_CC, spb_len);
167                RETURN_FALSE;
168            }
169            spb_len += chunk;
170        }
171    }
172
173    /* now start the job */
174    if (isc_service_start(IB_STATUS, &svm->handle, NULL, spb_len, buf)) {
175        IBASE_SVC_ERROR(svm);
176        RETURN_FALSE;
177    }
178
179    RETURN_TRUE;
180}
181/* }}} */
182
183/* {{{ proto bool ibase_add_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]])
184   Add a user to security database */
185PHP_FUNCTION(ibase_add_user)
186{
187    _php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_add_user);
188}
189/* }}} */
190
191/* {{{ proto bool ibase_modify_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]])
192   Modify a user in security database */
193PHP_FUNCTION(ibase_modify_user)
194{
195    _php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_modify_user);
196}
197/* }}} */
198
199/* {{{ proto bool ibase_delete_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]])
200   Delete a user from security database */
201PHP_FUNCTION(ibase_delete_user)
202{
203    _php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_delete_user);
204}
205/* }}} */
206
207/* {{{ proto resource ibase_service_attach(string host, string dba_username, string dba_password)
208   Connect to the service manager */
209PHP_FUNCTION(ibase_service_attach)
210{
211    size_t hlen, ulen, plen, spb_len;
212    ibase_service *svm;
213    char buf[128], *host, *user, *pass, *loc;
214    isc_svc_handle handle = NULL;
215
216    RESET_ERRMSG;
217
218    if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sss",
219            &host, &hlen, &user, &ulen, &pass, &plen)) {
220
221        RETURN_FALSE;
222    }
223
224    /* construct the spb, hack the service name into it as well */
225    spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%s" "%s:service_mgr",
226        isc_spb_version, isc_spb_current_version, isc_spb_user_name, (char)ulen,
227        user, isc_spb_password, (char)plen, pass, host);
228
229    if (spb_len > sizeof(buf) || spb_len == -1) {
230        _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)" TSRMLS_CC, spb_len);
231        RETURN_FALSE;
232    }
233
234    spb_len -= hlen + 12;
235    loc = buf + spb_len; /* points to %s:service_mgr part */
236
237    /* attach to the service manager */
238    if (isc_service_attach(IB_STATUS, 0, loc, &handle, (unsigned short)spb_len, buf)) {
239        _php_ibase_error(TSRMLS_C);
240        RETURN_FALSE;
241    }
242
243    svm = (ibase_service*)emalloc(sizeof(ibase_service));
244    svm->handle = handle;
245    svm->hostname = estrdup(host);
246    svm->username = estrdup(user);
247
248    ZEND_REGISTER_RESOURCE(return_value, svm, le_service);
249    Z_ADDREF_P(return_value);
250    svm->res = Z_RES_P(return_value);
251}
252/* }}} */
253
254/* {{{ proto bool ibase_service_detach(resource service_handle)
255   Disconnect from the service manager */
256PHP_FUNCTION(ibase_service_detach)
257{
258    zval *res;
259
260    RESET_ERRMSG;
261
262    if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &res)) {
263        RETURN_FALSE;
264    }
265
266    zend_list_delete(Z_RES_P(res));
267
268    RETURN_TRUE;
269}
270/* }}} */
271
272static void _php_ibase_service_query(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */
273    ibase_service *svm, char info_action)
274{
275    static char spb[] = { isc_info_svc_timeout, 10, 0, 0, 0 };
276
277    char res_buf[400], *result, *heap_buf = NULL, *heap_p;
278    long heap_buf_size = 200, line_len;
279
280    /* info about users requires an action first */
281    if (info_action == isc_info_svc_get_users) {
282        static char action[] = { isc_action_svc_display_user };
283
284        if (isc_service_start(IB_STATUS, &svm->handle, NULL, sizeof(action), action)) {
285            IBASE_SVC_ERROR(svm);
286            RETURN_FALSE;
287        }
288    }
289
290query_loop:
291    result = res_buf;
292
293    if (isc_service_query(IB_STATUS, &svm->handle, NULL, sizeof(spb), spb,
294            1, &info_action, sizeof(res_buf), res_buf)) {
295
296        IBASE_SVC_ERROR(svm);
297        RETURN_FALSE;
298    }
299    while (*result != isc_info_end) {
300        switch (*result++) {
301            default:
302                RETURN_FALSE;
303
304            case isc_info_svc_line:
305                if (! (line_len = isc_vax_integer(result, 2))) {
306                    /* done */
307                    if (heap_buf) {
308                        RETVAL_STRING(heap_buf);
309                        efree(heap_buf);
310                        return;
311                    } else {
312                        RETURN_TRUE;
313                    }
314                }
315                if (!heap_buf || (heap_p - heap_buf + line_len +2) > heap_buf_size) {
316                    long res_size = heap_buf ? heap_p - heap_buf : 0;
317
318                    while (heap_buf_size < (res_size + line_len +2)) {
319                        heap_buf_size *= 2;
320                    }
321                    heap_buf = (char*) erealloc(heap_buf, heap_buf_size);
322                    heap_p = heap_buf + res_size;
323                }
324                result += 2;
325                *(result+line_len) = 0;
326                snprintf(heap_p, heap_buf_size - (heap_p - heap_buf), "%s\n", result);
327                heap_p += line_len +1;
328                goto query_loop; /* repeat until result is exhausted */
329
330            case isc_info_svc_server_version:
331            case isc_info_svc_implementation:
332            case isc_info_svc_get_env:
333            case isc_info_svc_get_env_lock:
334            case isc_info_svc_get_env_msg:
335            case isc_info_svc_user_dbpath:
336                RETURN_STRINGL(result + 2, isc_vax_integer(result, 2));
337
338            case isc_info_svc_svr_db_info:
339                array_init(return_value);
340
341                do {
342                    switch (*result++) {
343                        int len;
344
345                        case isc_spb_num_att:
346                            add_assoc_long(return_value, "attachments", isc_vax_integer(result,4));
347                            result += 4;
348                            break;
349
350                        case isc_spb_num_db:
351                            add_assoc_long(return_value, "databases", isc_vax_integer(result,4));
352                            result += 4;
353                            break;
354
355                        case isc_spb_dbname:
356                            len = isc_vax_integer(result,2);
357                            add_next_index_stringl(return_value, result +2, len);
358                            result += len+2;
359                    }
360                } while (*result != isc_info_flag_end);
361                return;
362
363            case isc_info_svc_get_users: {
364                zval user;
365                array_init(return_value);
366
367                while (*result != isc_info_end) {
368
369                    switch (*result++) {
370                        int len;
371
372                        case isc_spb_sec_username:
373                            /* it appears that the username is always first */
374                            array_init(&user);
375                            add_next_index_zval(return_value, &user);
376
377                            len = isc_vax_integer(result,2);
378                            add_assoc_stringl(&user, "user_name", result +2, len);
379                            result += len+2;
380                            break;
381
382                        case isc_spb_sec_firstname:
383                            len = isc_vax_integer(result,2);
384                            add_assoc_stringl(&user, "first_name", result +2, len);
385                            result += len+2;
386                            break;
387
388                        case isc_spb_sec_middlename:
389                            len = isc_vax_integer(result,2);
390                            add_assoc_stringl(&user, "middle_name", result +2, len);
391                            result += len+2;
392                            break;
393
394                        case isc_spb_sec_lastname:
395                            len = isc_vax_integer(result,2);
396                            add_assoc_stringl(&user, "last_name", result +2, len);
397                            result += len+2;
398                            break;
399
400                        case isc_spb_sec_userid:
401                            add_assoc_long(&user, "user_id", isc_vax_integer(result, 4));
402                            result += 4;
403                            break;
404
405                        case isc_spb_sec_groupid:
406                            add_assoc_long(&user, "group_id", isc_vax_integer(result, 4));
407                            result += 4;
408                            break;
409                    }
410                }
411                return;
412            }
413        }
414    }
415}
416/* }}} */
417
418static void _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAMETERS, char operation) /* {{{ */
419{
420    /**
421     * It appears that the service API is a little bit confused about which flag
422     * to use for the source and destination in the case of a restore operation.
423     * When passing the backup file as isc_spb_dbname and the destination db as
424     * bpk_file, things work well.
425     */
426    zval *res;
427    char *db, *bk, buf[200];
428    size_t dblen, bklen, spb_len;
429    long opts = 0;
430    zend_bool verbose = 0;
431    ibase_service *svm;
432
433    RESET_ERRMSG;
434
435    if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rss|lb",
436            &res, &db, &dblen, &bk, &bklen, &opts, &verbose)) {
437        RETURN_FALSE;
438    }
439
440    ZEND_FETCH_RESOURCE(svm, ibase_service *, res, -1,
441        "Interbase service manager handle", le_service);
442
443    /* fill the param buffer */
444    spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%s%c%c%c%c%c",
445        operation, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db,
446        isc_spb_bkp_file, (char)bklen, (char)(bklen >> 8), bk, isc_spb_options,
447        (char)opts,(char)(opts >> 8), (char)(opts >> 16), (char)(opts >> 24));
448
449    if (verbose) {
450        buf[spb_len++] = isc_spb_verbose;
451    }
452
453    if (spb_len > sizeof(buf) || spb_len <= 0) {
454        _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)" TSRMLS_CC, spb_len);
455        RETURN_FALSE;
456    }
457
458    /* now start the backup/restore job */
459    if (isc_service_start(IB_STATUS, &svm->handle, NULL, (unsigned short)spb_len, buf)) {
460        IBASE_SVC_ERROR(svm);
461        RETURN_FALSE;
462    }
463
464    if (!verbose) {
465        RETURN_TRUE;
466    } else {
467        _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, isc_info_svc_line);
468    }
469}
470/* }}} */
471
472/* {{{ proto mixed ibase_backup(resource service_handle, string source_db, string dest_file [, int options [, bool verbose]])
473   Initiates a backup task in the service manager and returns immediately */
474PHP_FUNCTION(ibase_backup)
475{
476    _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_backup);
477}
478/* }}} */
479
480/* {{{ proto mixed ibase_restore(resource service_handle, string source_file, string dest_db [, int options [, bool verbose]])
481   Initiates a restore task in the service manager and returns immediately */
482PHP_FUNCTION(ibase_restore)
483{
484    _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_restore);
485}
486/* }}} */
487
488static void _php_ibase_service_action(INTERNAL_FUNCTION_PARAMETERS, char svc_action) /* {{{ */
489{
490    zval *res;
491    char buf[128], *db;
492    int dblen, spb_len;
493    long action, argument = 0;
494    ibase_service *svm;
495
496    RESET_ERRMSG;
497
498    if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsl|l",
499            &res, &db, &dblen, &action, &argument)) {
500        RETURN_FALSE;
501    }
502
503    ZEND_FETCH_RESOURCE(svm, ibase_service *, res, -1,
504        "Interbase service manager handle", le_service);
505
506    if (svc_action == isc_action_svc_db_stats) {
507        switch (action) {
508            default:
509                goto unknown_option;
510
511            case isc_spb_sts_data_pages:
512            case isc_spb_sts_db_log:
513            case isc_spb_sts_hdr_pages:
514            case isc_spb_sts_idx_pages:
515            case isc_spb_sts_sys_relations:
516                goto options_argument;
517        }
518    } else {
519        /* these actions all expect different types of arguments */
520        switch (action) {
521            default:
522unknown_option:
523                _php_ibase_module_error("Unrecognised option (%ld)" TSRMLS_CC, action);
524                RETURN_FALSE;
525
526            case isc_spb_rpr_check_db:
527            case isc_spb_rpr_ignore_checksum:
528            case isc_spb_rpr_kill_shadows:
529            case isc_spb_rpr_mend_db:
530            case isc_spb_rpr_validate_db:
531            case isc_spb_rpr_sweep_db:
532                svc_action = isc_action_svc_repair;
533
534            case isc_spb_prp_activate:
535            case isc_spb_prp_db_online:
536options_argument:
537                argument |= action;
538                action = isc_spb_options;
539
540            case isc_spb_prp_page_buffers:
541            case isc_spb_prp_sweep_interval:
542            case isc_spb_prp_shutdown_db:
543            case isc_spb_prp_deny_new_transactions:
544            case isc_spb_prp_deny_new_attachments:
545            case isc_spb_prp_set_sql_dialect:
546                spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%c%c",
547                    svc_action, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db,
548                    (char)action, (char)argument, (char)(argument >> 8), (char)(argument >> 16),
549                    (char)(argument >> 24));
550                break;
551
552            case isc_spb_prp_reserve_space:
553            case isc_spb_prp_write_mode:
554            case isc_spb_prp_access_mode:
555                spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c",
556                    isc_action_svc_properties, isc_spb_dbname, (char)dblen, (char)(dblen >> 8),
557                    db, (char)action, (char)argument);
558        }
559    }
560
561    if (spb_len > sizeof(buf) || spb_len == -1) {
562        _php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)" TSRMLS_CC, spb_len);
563        RETURN_FALSE;
564    }
565
566    if (isc_service_start(IB_STATUS, &svm->handle, NULL, (unsigned short)spb_len, buf)) {
567        IBASE_SVC_ERROR(svm);
568        RETURN_FALSE;
569    }
570
571    if (svc_action == isc_action_svc_db_stats) {
572        _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, isc_info_svc_line);
573    } else {
574        RETURN_TRUE;
575    }
576}
577/* }}} */
578
579/* {{{ proto bool ibase_maintain_db(resource service_handle, string db, int action [, int argument])
580   Execute a maintenance command on the database server */
581PHP_FUNCTION(ibase_maintain_db)
582{
583    _php_ibase_service_action(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_properties);
584}
585/* }}} */
586
587/* {{{ proto string ibase_db_info(resource service_handle, string db, int action [, int argument])
588   Request statistics about a database */
589PHP_FUNCTION(ibase_db_info)
590{
591    _php_ibase_service_action(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_db_stats);
592}
593/* }}} */
594
595/* {{{ proto string ibase_server_info(resource service_handle, int action)
596   Request information about a database server */
597PHP_FUNCTION(ibase_server_info)
598{
599    zval *res;
600    long action;
601    ibase_service *svm;
602
603    RESET_ERRMSG;
604
605    if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &res, &action)) {
606        RETURN_FALSE;
607    }
608
609    ZEND_FETCH_RESOURCE(svm, ibase_service *, res, -1,
610        "Interbase service manager handle", le_service);
611
612    _php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, (char)action);
613}
614/* }}} */
615
616#else
617
618void php_ibase_register_service_constants(INIT_FUNC_ARGS) { /* nop */ }
619
620#endif /* HAVE_IBASE */
621
622/*
623 * Local variables:
624 * tab-width: 4
625 * c-basic-offset: 4
626 * End:
627 * vim600: sw=4 ts=4 fdm=marker
628 * vim<600: sw=4 ts=4
629 */
630