1/*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2016 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) /* {{{ */
40{
41	ibase_service *sv = (ibase_service *) rsrc->ptr;
42
43	if (isc_service_detach(IB_STATUS, &sv->handle)) {
44		_php_ibase_error();
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(); } 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(),
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	svm = (ibase_service *)zend_fetch_resource_ex(res, "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)", spb_len);
166				RETURN_FALSE;
167			}
168			spb_len += chunk;
169		}
170	}
171
172	/* now start the job */
173	if (isc_service_start(IB_STATUS, &svm->handle, NULL, spb_len, buf)) {
174		IBASE_SVC_ERROR(svm);
175		RETURN_FALSE;
176	}
177
178	RETURN_TRUE;
179}
180/* }}} */
181
182/* {{{ proto bool ibase_add_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]])
183   Add a user to security database */
184PHP_FUNCTION(ibase_add_user)
185{
186	_php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_add_user);
187}
188/* }}} */
189
190/* {{{ proto bool ibase_modify_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]])
191   Modify a user in security database */
192PHP_FUNCTION(ibase_modify_user)
193{
194	_php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_modify_user);
195}
196/* }}} */
197
198/* {{{ proto bool ibase_delete_user(resource service_handle, string user_name, string password [, string first_name [, string middle_name [, string last_name]]])
199   Delete a user from security database */
200PHP_FUNCTION(ibase_delete_user)
201{
202	_php_ibase_user(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_delete_user);
203}
204/* }}} */
205
206/* {{{ proto resource ibase_service_attach(string host, string dba_username, string dba_password)
207   Connect to the service manager */
208PHP_FUNCTION(ibase_service_attach)
209{
210	size_t hlen, ulen, plen, spb_len;
211	ibase_service *svm;
212	char buf[128], *host, *user, *pass, *loc;
213	isc_svc_handle handle = 0;
214
215	RESET_ERRMSG;
216
217	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "sss",
218			&host, &hlen, &user, &ulen, &pass, &plen)) {
219
220		RETURN_FALSE;
221	}
222
223	/* construct the spb, hack the service name into it as well */
224	spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%s" "%s:service_mgr",
225		isc_spb_version, isc_spb_current_version, isc_spb_user_name, (char)ulen,
226		user, isc_spb_password, (char)plen, pass, host);
227
228	if (spb_len > sizeof(buf) || spb_len == -1) {
229		_php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)", spb_len);
230		RETURN_FALSE;
231	}
232
233	spb_len -= hlen + 12;
234	loc = buf + spb_len; /* points to %s:service_mgr part */
235
236	/* attach to the service manager */
237	if (isc_service_attach(IB_STATUS, 0, loc, &handle, (unsigned short)spb_len, buf)) {
238		_php_ibase_error();
239		RETURN_FALSE;
240	}
241
242	svm = (ibase_service*)emalloc(sizeof(ibase_service));
243	svm->handle = handle;
244	svm->hostname = estrdup(host);
245	svm->username = estrdup(user);
246
247	RETVAL_RES(zend_register_resource(svm, le_service));
248	Z_TRY_ADDREF_P(return_value);
249	svm->res = Z_RES_P(return_value);
250}
251/* }}} */
252
253/* {{{ proto bool ibase_service_detach(resource service_handle)
254   Disconnect from the service manager */
255PHP_FUNCTION(ibase_service_detach)
256{
257	zval *res;
258
259	RESET_ERRMSG;
260
261	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "r", &res)) {
262		RETURN_FALSE;
263	}
264
265	zend_list_delete(Z_RES_P(res));
266
267	RETURN_TRUE;
268}
269/* }}} */
270
271static void _php_ibase_service_query(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */
272	ibase_service *svm, char info_action)
273{
274	static char spb[] = { isc_info_svc_timeout, 10, 0, 0, 0 };
275
276	char res_buf[400], *result, *heap_buf = NULL, *heap_p;
277	zend_long heap_buf_size = 200, line_len;
278
279	/* info about users requires an action first */
280	if (info_action == isc_info_svc_get_users) {
281		static char action[] = { isc_action_svc_display_user };
282
283		if (isc_service_start(IB_STATUS, &svm->handle, NULL, sizeof(action), action)) {
284			IBASE_SVC_ERROR(svm);
285			RETURN_FALSE;
286		}
287	}
288
289query_loop:
290	result = res_buf;
291
292	if (isc_service_query(IB_STATUS, &svm->handle, NULL, sizeof(spb), spb,
293			1, &info_action, sizeof(res_buf), res_buf)) {
294
295		IBASE_SVC_ERROR(svm);
296		RETURN_FALSE;
297	}
298	while (*result != isc_info_end) {
299		switch (*result++) {
300			default:
301				RETURN_FALSE;
302
303			case isc_info_svc_line:
304				if (! (line_len = isc_vax_integer(result, 2))) {
305					/* done */
306					if (heap_buf) {
307						RETVAL_STRING(heap_buf);
308						efree(heap_buf);
309						return;
310					} else {
311						RETURN_TRUE;
312					}
313				}
314				if (!heap_buf || (heap_p - heap_buf + line_len +2) > heap_buf_size) {
315					zend_long res_size = heap_buf ? heap_p - heap_buf : 0;
316
317					while (heap_buf_size < (res_size + line_len +2)) {
318						heap_buf_size *= 2;
319					}
320					heap_buf = (char*) erealloc(heap_buf, heap_buf_size);
321					heap_p = heap_buf + res_size;
322				}
323				result += 2;
324				*(result+line_len) = 0;
325				snprintf(heap_p, heap_buf_size - (heap_p - heap_buf), "%s\n", result);
326				heap_p += line_len +1;
327				goto query_loop; /* repeat until result is exhausted */
328
329			case isc_info_svc_server_version:
330			case isc_info_svc_implementation:
331			case isc_info_svc_get_env:
332			case isc_info_svc_get_env_lock:
333			case isc_info_svc_get_env_msg:
334			case isc_info_svc_user_dbpath:
335				RETURN_STRINGL(result + 2, isc_vax_integer(result, 2));
336
337			case isc_info_svc_svr_db_info:
338				array_init(return_value);
339
340				do {
341					switch (*result++) {
342						int len;
343
344						case isc_spb_num_att:
345							add_assoc_long(return_value, "attachments", isc_vax_integer(result,4));
346							result += 4;
347							break;
348
349						case isc_spb_num_db:
350							add_assoc_long(return_value, "databases", isc_vax_integer(result,4));
351							result += 4;
352							break;
353
354						case isc_spb_dbname:
355							len = isc_vax_integer(result,2);
356							add_next_index_stringl(return_value, result +2, len);
357							result += len+2;
358					}
359				} while (*result != isc_info_flag_end);
360				return;
361
362			case isc_info_svc_get_users: {
363				zval user;
364				array_init(return_value);
365
366				while (*result != isc_info_end) {
367
368					switch (*result++) {
369						int len;
370
371						case isc_spb_sec_username:
372							/* it appears that the username is always first */
373							array_init(&user);
374							add_next_index_zval(return_value, &user);
375
376							len = isc_vax_integer(result,2);
377							add_assoc_stringl(&user, "user_name", result +2, len);
378							result += len+2;
379							break;
380
381						case isc_spb_sec_firstname:
382							len = isc_vax_integer(result,2);
383							add_assoc_stringl(&user, "first_name", result +2, len);
384							result += len+2;
385							break;
386
387						case isc_spb_sec_middlename:
388							len = isc_vax_integer(result,2);
389							add_assoc_stringl(&user, "middle_name", result +2, len);
390							result += len+2;
391							break;
392
393						case isc_spb_sec_lastname:
394							len = isc_vax_integer(result,2);
395							add_assoc_stringl(&user, "last_name", result +2, len);
396							result += len+2;
397							break;
398
399						case isc_spb_sec_userid:
400							add_assoc_long(&user, "user_id", isc_vax_integer(result, 4));
401							result += 4;
402							break;
403
404						case isc_spb_sec_groupid:
405							add_assoc_long(&user, "group_id", isc_vax_integer(result, 4));
406							result += 4;
407							break;
408					}
409				}
410				return;
411			}
412		}
413	}
414}
415/* }}} */
416
417static void _php_ibase_backup_restore(INTERNAL_FUNCTION_PARAMETERS, char operation) /* {{{ */
418{
419	/**
420	 * It appears that the service API is a little bit confused about which flag
421	 * to use for the source and destination in the case of a restore operation.
422	 * When passing the backup file as isc_spb_dbname and the destination db as
423	 * bpk_file, things work well.
424	 */
425	zval *res;
426	char *db, *bk, buf[200];
427	size_t dblen, bklen, spb_len;
428	zend_long opts = 0;
429	zend_bool verbose = 0;
430	ibase_service *svm;
431
432	RESET_ERRMSG;
433
434	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rss|lb",
435			&res, &db, &dblen, &bk, &bklen, &opts, &verbose)) {
436		RETURN_FALSE;
437	}
438
439	svm = (ibase_service *)zend_fetch_resource_ex(res,
440		"Interbase service manager handle", le_service);
441
442	/* fill the param buffer */
443	spb_len = slprintf(buf, sizeof(buf), "%c%c%c%c%s%c%c%c%s%c%c%c%c%c",
444		operation, isc_spb_dbname, (char)dblen, (char)(dblen >> 8), db,
445		isc_spb_bkp_file, (char)bklen, (char)(bklen >> 8), bk, isc_spb_options,
446		(char)opts,(char)(opts >> 8), (char)(opts >> 16), (char)(opts >> 24));
447
448	if (verbose) {
449		buf[spb_len++] = isc_spb_verbose;
450	}
451
452	if (spb_len > sizeof(buf) || spb_len <= 0) {
453		_php_ibase_module_error("Internal error: insufficient buffer space for SPB (%d)", spb_len);
454		RETURN_FALSE;
455	}
456
457	/* now start the backup/restore job */
458	if (isc_service_start(IB_STATUS, &svm->handle, NULL, (unsigned short)spb_len, buf)) {
459		IBASE_SVC_ERROR(svm);
460		RETURN_FALSE;
461	}
462
463	if (!verbose) {
464		RETURN_TRUE;
465	} else {
466		_php_ibase_service_query(INTERNAL_FUNCTION_PARAM_PASSTHRU, svm, isc_info_svc_line);
467	}
468}
469/* }}} */
470
471/* {{{ proto mixed ibase_backup(resource service_handle, string source_db, string dest_file [, int options [, bool verbose]])
472   Initiates a backup task in the service manager and returns immediately */
473PHP_FUNCTION(ibase_backup)
474{
475	_php_ibase_backup_restore(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_backup);
476}
477/* }}} */
478
479/* {{{ proto mixed ibase_restore(resource service_handle, string source_file, string dest_db [, int options [, bool verbose]])
480   Initiates a restore task in the service manager and returns immediately */
481PHP_FUNCTION(ibase_restore)
482{
483	_php_ibase_backup_restore(INTERNAL_FUNCTION_PARAM_PASSTHRU, isc_action_svc_restore);
484}
485/* }}} */
486
487static void _php_ibase_service_action(INTERNAL_FUNCTION_PARAMETERS, char svc_action) /* {{{ */
488{
489	zval *res;
490	char buf[128], *db;
491	size_t dblen;
492	int spb_len;
493	zend_long action, argument = 0;
494	ibase_service *svm;
495
496	RESET_ERRMSG;
497
498	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rsl|l",
499			&res, &db, &dblen, &action, &argument)) {
500		RETURN_FALSE;
501	}
502
503	svm = (ibase_service *)zend_fetch_resource_ex(res,
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 (" ZEND_LONG_FMT ")", 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)", 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	zend_long action;
601	ibase_service *svm;
602
603	RESET_ERRMSG;
604
605	if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS(), "rl", &res, &action)) {
606		RETURN_FALSE;
607	}
608
609	svm = (ibase_service *)zend_fetch_resource_ex(res,
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