~ubuntu-branches/ubuntu/hardy/php5/hardy-updates

« back to all changes in this revision

Viewing changes to ext/pcntl/pcntl.c

  • Committer: Bazaar Package Importer
  • Author(s): Adam Conrad
  • Date: 2005-10-09 03:14:32 UTC
  • Revision ID: james.westby@ubuntu.com-20051009031432-kspik3lobxstafv9
Tags: upstream-5.0.5
ImportĀ upstreamĀ versionĀ 5.0.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   +----------------------------------------------------------------------+
 
3
   | PHP Version 5                                                        |
 
4
   +----------------------------------------------------------------------+
 
5
   | Copyright (c) 1997-2004 The PHP Group                                |
 
6
   +----------------------------------------------------------------------+
 
7
   | This source file is subject to version 3.0 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_0.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
   | Author: Jason Greene <jason@inetgurus.net>                           |
 
16
   +----------------------------------------------------------------------+
 
17
 */
 
18
 
 
19
/* $Id: pcntl.c,v 1.44.2.3 2005/05/07 14:58:02 wez Exp $ */
 
20
 
 
21
#define PCNTL_DEBUG 0
 
22
 
 
23
#if PCNTL_DEBUG
 
24
#define DEBUG_OUT printf("DEBUG: ");printf
 
25
#define IF_DEBUG(z) z
 
26
#else
 
27
#define IF_DEBUG(z)
 
28
#endif
 
29
 
 
30
#ifdef HAVE_CONFIG_H
 
31
#include "config.h"
 
32
#endif
 
33
 
 
34
#include "php.h"
 
35
#include "php_ini.h"
 
36
#include "ext/standard/info.h"
 
37
#include "php_pcntl.h"
 
38
 
 
39
#if HAVE_GETPRIORITY || HAVE_SETPRIORITY || HAVE_WAIT3
 
40
#include <sys/time.h>
 
41
#include <sys/resource.h>
 
42
#endif
 
43
 
 
44
ZEND_DECLARE_MODULE_GLOBALS(pcntl)
 
45
 
 
46
function_entry pcntl_functions[] = {
 
47
        PHP_FE(pcntl_fork,                      NULL)
 
48
        PHP_FE(pcntl_waitpid,           second_arg_force_ref)
 
49
        PHP_FE(pcntl_wait,              first_arg_force_ref)
 
50
        PHP_FE(pcntl_signal,            NULL)
 
51
        PHP_FE(pcntl_wifexited,         NULL)
 
52
        PHP_FE(pcntl_wifstopped,        NULL)
 
53
        PHP_FE(pcntl_wifsignaled,       NULL)
 
54
        PHP_FE(pcntl_wexitstatus,       NULL)
 
55
        PHP_FE(pcntl_wtermsig,          NULL)
 
56
        PHP_FE(pcntl_wstopsig,          NULL)
 
57
        PHP_FE(pcntl_exec,                      NULL)
 
58
        PHP_FE(pcntl_alarm,                     NULL)
 
59
#ifdef HAVE_GETPRIORITY
 
60
        PHP_FE(pcntl_getpriority,       NULL)
 
61
#endif
 
62
#ifdef HAVE_SETPRIORITY
 
63
        PHP_FE(pcntl_setpriority,       NULL)
 
64
#endif
 
65
        {NULL, NULL, NULL}      
 
66
};
 
67
 
 
68
zend_module_entry pcntl_module_entry = {
 
69
        STANDARD_MODULE_HEADER,
 
70
        "pcntl",
 
71
        pcntl_functions,
 
72
        PHP_MINIT(pcntl),
 
73
        PHP_MSHUTDOWN(pcntl),
 
74
        PHP_RINIT(pcntl),
 
75
        PHP_RSHUTDOWN(pcntl),
 
76
        PHP_MINFO(pcntl),
 
77
        NO_VERSION_YET,
 
78
        STANDARD_MODULE_PROPERTIES
 
79
};
 
80
 
 
81
#ifdef COMPILE_DL_PCNTL
 
82
ZEND_GET_MODULE(pcntl)
 
83
# ifdef PHP_WIN32
 
84
# include "zend_arg_defs.c"
 
85
# endif
 
86
#endif
 
87
 
 
88
static void pcntl_signal_handler(int);
 
89
static void pcntl_tick_handler();
 
90
  
 
91
void php_register_signal_constants(INIT_FUNC_ARGS)
 
92
{
 
93
 
 
94
        /* Wait Constants */
 
95
#ifdef WNOHANG
 
96
        REGISTER_LONG_CONSTANT("WNOHANG",  (long) WNOHANG, CONST_CS | CONST_PERSISTENT);
 
97
#endif
 
98
#ifdef WUNTRACED
 
99
        REGISTER_LONG_CONSTANT("WUNTRACED",  (long) WUNTRACED, CONST_CS | CONST_PERSISTENT);
 
100
#endif
 
101
 
 
102
        /* Signal Constants */
 
103
        REGISTER_LONG_CONSTANT("SIG_IGN",  (long) SIG_IGN, CONST_CS | CONST_PERSISTENT);
 
104
        REGISTER_LONG_CONSTANT("SIG_DFL",  (long) SIG_DFL, CONST_CS | CONST_PERSISTENT);
 
105
        REGISTER_LONG_CONSTANT("SIG_ERR",  (long) SIG_ERR, CONST_CS | CONST_PERSISTENT);
 
106
        REGISTER_LONG_CONSTANT("SIGHUP",   (long) SIGHUP,  CONST_CS | CONST_PERSISTENT);
 
107
        REGISTER_LONG_CONSTANT("SIGINT",   (long) SIGINT,  CONST_CS | CONST_PERSISTENT);
 
108
        REGISTER_LONG_CONSTANT("SIGQUIT",  (long) SIGQUIT, CONST_CS | CONST_PERSISTENT);
 
109
        REGISTER_LONG_CONSTANT("SIGILL",   (long) SIGILL,  CONST_CS | CONST_PERSISTENT);
 
110
        REGISTER_LONG_CONSTANT("SIGTRAP",  (long) SIGTRAP, CONST_CS | CONST_PERSISTENT);
 
111
        REGISTER_LONG_CONSTANT("SIGABRT",  (long) SIGABRT, CONST_CS | CONST_PERSISTENT);
 
112
#ifdef SIGIOT
 
113
        REGISTER_LONG_CONSTANT("SIGIOT",   (long) SIGIOT,  CONST_CS | CONST_PERSISTENT);
 
114
#endif
 
115
        REGISTER_LONG_CONSTANT("SIGBUS",   (long) SIGBUS,  CONST_CS | CONST_PERSISTENT);
 
116
        REGISTER_LONG_CONSTANT("SIGFPE",   (long) SIGFPE,  CONST_CS | CONST_PERSISTENT);
 
117
        REGISTER_LONG_CONSTANT("SIGKILL",  (long) SIGKILL, CONST_CS | CONST_PERSISTENT);
 
118
        REGISTER_LONG_CONSTANT("SIGUSR1",  (long) SIGUSR1, CONST_CS | CONST_PERSISTENT);
 
119
        REGISTER_LONG_CONSTANT("SIGSEGV",  (long) SIGSEGV, CONST_CS | CONST_PERSISTENT);
 
120
        REGISTER_LONG_CONSTANT("SIGUSR2",  (long) SIGUSR2, CONST_CS | CONST_PERSISTENT);
 
121
        REGISTER_LONG_CONSTANT("SIGPIPE",  (long) SIGPIPE, CONST_CS | CONST_PERSISTENT);
 
122
        REGISTER_LONG_CONSTANT("SIGALRM",  (long) SIGALRM, CONST_CS | CONST_PERSISTENT);
 
123
        REGISTER_LONG_CONSTANT("SIGTERM",  (long) SIGTERM, CONST_CS | CONST_PERSISTENT);
 
124
#ifdef SIGSTKFLT
 
125
        REGISTER_LONG_CONSTANT("SIGSTKFLT",(long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT);
 
126
#endif 
 
127
#ifdef SIGCLD
 
128
        REGISTER_LONG_CONSTANT("SIGCLD",   (long) SIGCLD, CONST_CS | CONST_PERSISTENT);
 
129
#endif
 
130
#ifdef SIGCHLD
 
131
        REGISTER_LONG_CONSTANT("SIGCHLD",  (long) SIGCHLD, CONST_CS | CONST_PERSISTENT);
 
132
#endif
 
133
        REGISTER_LONG_CONSTANT("SIGCONT",  (long) SIGCONT, CONST_CS | CONST_PERSISTENT);
 
134
        REGISTER_LONG_CONSTANT("SIGSTOP",  (long) SIGSTOP, CONST_CS | CONST_PERSISTENT);
 
135
        REGISTER_LONG_CONSTANT("SIGTSTP",  (long) SIGTSTP, CONST_CS | CONST_PERSISTENT);
 
136
        REGISTER_LONG_CONSTANT("SIGTTIN",  (long) SIGTTIN, CONST_CS | CONST_PERSISTENT);
 
137
        REGISTER_LONG_CONSTANT("SIGTTOU",  (long) SIGTTOU, CONST_CS | CONST_PERSISTENT);
 
138
        REGISTER_LONG_CONSTANT("SIGURG",   (long) SIGURG , CONST_CS | CONST_PERSISTENT);
 
139
        REGISTER_LONG_CONSTANT("SIGXCPU",  (long) SIGXCPU, CONST_CS | CONST_PERSISTENT);
 
140
        REGISTER_LONG_CONSTANT("SIGXFSZ",  (long) SIGXFSZ, CONST_CS | CONST_PERSISTENT);
 
141
        REGISTER_LONG_CONSTANT("SIGVTALRM",(long) SIGVTALRM, CONST_CS | CONST_PERSISTENT);
 
142
        REGISTER_LONG_CONSTANT("SIGPROF",  (long) SIGPROF, CONST_CS | CONST_PERSISTENT);
 
143
        REGISTER_LONG_CONSTANT("SIGWINCH", (long) SIGWINCH, CONST_CS | CONST_PERSISTENT);
 
144
#ifdef SIGPOLL
 
145
        REGISTER_LONG_CONSTANT("SIGPOLL",  (long) SIGPOLL, CONST_CS | CONST_PERSISTENT);
 
146
#endif
 
147
        REGISTER_LONG_CONSTANT("SIGIO",    (long) SIGIO, CONST_CS | CONST_PERSISTENT);
 
148
#ifdef SIGPWR
 
149
        REGISTER_LONG_CONSTANT("SIGPWR",   (long) SIGPWR, CONST_CS | CONST_PERSISTENT);
 
150
#endif
 
151
#ifdef SIGSYS
 
152
        REGISTER_LONG_CONSTANT("SIGSYS",   (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
 
153
        REGISTER_LONG_CONSTANT("SIGBABY",  (long) SIGSYS, CONST_CS | CONST_PERSISTENT);
 
154
#endif
 
155
 
 
156
#if HAVE_GETPRIORITY || HAVE_SETPRIORITY
 
157
        REGISTER_LONG_CONSTANT("PRIO_PGRP", PRIO_PGRP, CONST_CS | CONST_PERSISTENT);
 
158
        REGISTER_LONG_CONSTANT("PRIO_USER", PRIO_USER, CONST_CS | CONST_PERSISTENT);
 
159
        REGISTER_LONG_CONSTANT("PRIO_PROCESS", PRIO_PROCESS, CONST_CS | CONST_PERSISTENT);
 
160
#endif
 
161
}
 
162
 
 
163
static void php_pcntl_init_globals(zend_pcntl_globals *pcntl_globals)
 
164
 
165
        memset(pcntl_globals, 0, sizeof(*pcntl_globals));
 
166
}
 
167
 
 
168
PHP_RINIT_FUNCTION(pcntl)
 
169
{
 
170
        zend_hash_init(&PCNTL_G(php_signal_table), 16, NULL, ZVAL_PTR_DTOR, 0);
 
171
        PCNTL_G(head) = PCNTL_G(tail) = PCNTL_G(spares) = NULL;
 
172
        return SUCCESS;
 
173
}
 
174
 
 
175
PHP_MINIT_FUNCTION(pcntl)
 
176
{
 
177
        php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
 
178
        ZEND_INIT_MODULE_GLOBALS(pcntl, php_pcntl_init_globals, NULL);
 
179
        php_add_tick_function(pcntl_tick_handler);
 
180
 
 
181
        return SUCCESS;
 
182
}
 
183
 
 
184
PHP_MSHUTDOWN_FUNCTION(pcntl)
 
185
{
 
186
        return SUCCESS;
 
187
}
 
188
 
 
189
PHP_RSHUTDOWN_FUNCTION(pcntl)
 
190
{
 
191
        struct php_pcntl_pending_signal *sig;
 
192
 
 
193
        /* FIXME: if a signal is delivered after this point, things will go pear shaped;
 
194
         * need to remove signal handlers */
 
195
        zend_hash_destroy(&PCNTL_G(php_signal_table));
 
196
        while (PCNTL_G(head)) {
 
197
                sig = PCNTL_G(head);
 
198
                PCNTL_G(head) = sig->next;
 
199
                efree(sig);
 
200
        }
 
201
        while (PCNTL_G(spares)) {
 
202
                sig = PCNTL_G(spares);
 
203
                PCNTL_G(spares) = sig->next;
 
204
                efree(sig);
 
205
        }
 
206
        return SUCCESS;
 
207
}
 
208
 
 
209
PHP_MINFO_FUNCTION(pcntl)
 
210
{
 
211
        php_info_print_table_start();
 
212
        php_info_print_table_header(2, "pcntl support", "enabled");
 
213
        php_info_print_table_end();
 
214
}
 
215
 
 
216
/* {{{ proto int pcntl_fork(void)
 
217
   Forks the currently running process following the same behavior as the UNIX fork() system call*/
 
218
PHP_FUNCTION(pcntl_fork)
 
219
{
 
220
        pid_t id;
 
221
 
 
222
        id = fork();
 
223
        if (id == -1) {
 
224
                php_error_docref(NULL TSRMLS_CC, E_ERROR, "Error %d", errno);
 
225
        }
 
226
        
 
227
        RETURN_LONG((long) id);
 
228
}
 
229
/* }}} */
 
230
 
 
231
/* {{{ proto int pcntl_alarm(int seconds)
 
232
   Set an alarm clock for delivery of a signal*/
 
233
PHP_FUNCTION(pcntl_alarm)
 
234
{
 
235
        long seconds;
 
236
 
 
237
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &seconds) == FAILURE)
 
238
                return;
 
239
        
 
240
        RETURN_LONG ((long) alarm(seconds));
 
241
}
 
242
/* }}} */
 
243
 
 
244
/* {{{ proto int pcntl_waitpid(int pid, int &status, int options)
 
245
   Waits on or returns the status of a forked child as defined by the waitpid() system call */
 
246
PHP_FUNCTION(pcntl_waitpid)
 
247
{
 
248
        long pid, options = 0;
 
249
        zval *z_status = NULL;
 
250
        int status;
 
251
        pid_t child_id;
 
252
 
 
253
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|l", &pid, &z_status, &options) == FAILURE)
 
254
                return;
 
255
        
 
256
        convert_to_long_ex(&z_status);
 
257
 
 
258
        status = Z_LVAL_P(z_status);
 
259
 
 
260
        child_id = waitpid((pid_t) pid, &status, options);
 
261
 
 
262
        Z_LVAL_P(z_status) = status;
 
263
 
 
264
        RETURN_LONG((long) child_id);
 
265
}
 
266
/* }}} */
 
267
 
 
268
/* {{{ proto int pcntl_wait(int &status)
 
269
   Waits on or returns the status of a forked child as defined by the waitpid() system call */
 
270
PHP_FUNCTION(pcntl_wait)
 
271
{
 
272
        long options = 0;
 
273
        zval *z_status = NULL;
 
274
        int status;
 
275
        pid_t child_id;
 
276
 
 
277
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &z_status, &options) == FAILURE)
 
278
                return;
 
279
        
 
280
        convert_to_long_ex(&z_status);
 
281
 
 
282
        status = Z_LVAL_P(z_status);
 
283
#ifdef HAVE_WAIT3
 
284
        if(options) {
 
285
                child_id = wait3(&status, options, NULL);
 
286
        }
 
287
        else {
 
288
                child_id = wait(&status);
 
289
        }
 
290
#else
 
291
        child_id = wait(&status);
 
292
#endif
 
293
        Z_LVAL_P(z_status) = status;
 
294
 
 
295
        RETURN_LONG((long) child_id);
 
296
}
 
297
/* }}} */
 
298
 
 
299
/* {{{ proto bool pcntl_wifexited(int status) 
 
300
   Returns true if the child status code represents a successful exit */
 
301
PHP_FUNCTION(pcntl_wifexited)
 
302
{
 
303
#ifdef WIFEXITED
 
304
        zval **status;
 
305
        int status_word;
 
306
        
 
307
        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
 
308
                WRONG_PARAM_COUNT;
 
309
        }
 
310
        
 
311
        status_word = (int) Z_LVAL_PP(status);
 
312
        
 
313
        if (WIFEXITED(status_word)) RETURN_TRUE;
 
314
#endif
 
315
        RETURN_FALSE;
 
316
}
 
317
/* }}} */
 
318
 
 
319
/* {{{ proto bool pcntl_wifstopped(int status) 
 
320
   Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
 
321
PHP_FUNCTION(pcntl_wifstopped)
 
322
{
 
323
#ifdef WIFSTOPPED
 
324
        zval **status;
 
325
        int status_word;
 
326
        
 
327
        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
 
328
                WRONG_PARAM_COUNT;
 
329
        }
 
330
        
 
331
        status_word = (int) Z_LVAL_PP(status);
 
332
        
 
333
        if (WIFSTOPPED(status_word)) RETURN_TRUE;
 
334
#endif
 
335
        RETURN_FALSE;
 
336
}
 
337
/* }}} */
 
338
 
 
339
/* {{{ proto bool pcntl_wifsignaled(int status) 
 
340
   Returns true if the child status code represents a process that was terminated due to a signal */
 
341
PHP_FUNCTION(pcntl_wifsignaled)
 
342
{
 
343
#ifdef WIFSIGNALED
 
344
        zval **status;
 
345
        int status_word;
 
346
        
 
347
        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
 
348
                WRONG_PARAM_COUNT;
 
349
        }
 
350
        
 
351
        status_word = (int) Z_LVAL_PP(status);
 
352
        
 
353
        if (WIFSIGNALED(status_word)) RETURN_TRUE;
 
354
#endif
 
355
        RETURN_FALSE;
 
356
}
 
357
/* }}} */
 
358
 
 
359
/* {{{ proto int pcntl_wexitstatus(int status) 
 
360
   Returns the status code of a child's exit */
 
361
PHP_FUNCTION(pcntl_wexitstatus)
 
362
{
 
363
#ifdef WEXITSTATUS
 
364
        zval **status;
 
365
        int status_word;
 
366
        
 
367
        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
 
368
                WRONG_PARAM_COUNT;
 
369
        }
 
370
        
 
371
        status_word = (int) Z_LVAL_PP(status);
 
372
 
 
373
        /* WEXITSTATUS only returns 8 bits so we *MUST* cast this to signed char
 
374
           if you want to have valid negative exit codes */
 
375
        RETURN_LONG((signed char) WEXITSTATUS(status_word));
 
376
#else
 
377
        RETURN_FALSE;
 
378
#endif
 
379
}
 
380
/* }}} */
 
381
 
 
382
/* {{{ proto int pcntl_wtermsig(int status) 
 
383
   Returns the number of the signal that terminated the process who's status code is passed  */
 
384
PHP_FUNCTION(pcntl_wtermsig)
 
385
{
 
386
#ifdef WTERMSIG
 
387
        zval **status;
 
388
        int status_word;
 
389
        
 
390
        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
 
391
                WRONG_PARAM_COUNT;
 
392
        }
 
393
        
 
394
        status_word = (int) Z_LVAL_PP(status);
 
395
        
 
396
        RETURN_LONG(WTERMSIG(status_word));
 
397
#else
 
398
        RETURN_FALSE;
 
399
#endif
 
400
}
 
401
/* }}} */
 
402
 
 
403
/* {{{ proto int pcntl_wstopsig(int status) 
 
404
   Returns the number of the signal that caused the process to stop who's status code is passed */
 
405
PHP_FUNCTION(pcntl_wstopsig)
 
406
{
 
407
#ifdef WSTOPSIG
 
408
        zval **status;
 
409
        int status_word;
 
410
   
 
411
        if (ZEND_NUM_ARGS() != 1 || zend_get_parameters_ex(ZEND_NUM_ARGS(), &status) == FAILURE) {
 
412
                WRONG_PARAM_COUNT;
 
413
        }
 
414
   
 
415
        status_word = (int) Z_LVAL_PP(status);
 
416
 
 
417
        RETURN_LONG(WSTOPSIG(status_word));
 
418
#else
 
419
        RETURN_FALSE;
 
420
#endif
 
421
}
 
422
/* }}} */
 
423
 
 
424
/* {{{ proto bool pcntl_exec(string path [, array args [, array envs]])
 
425
   Executes specified program in current process space as defined by exec(2) */
 
426
PHP_FUNCTION(pcntl_exec)
 
427
{
 
428
        zval *args, *envs;
 
429
        zval **element;
 
430
        HashTable *args_hash, *envs_hash;
 
431
        int argc = 0, argi = 0;
 
432
        int envc = 0, envi = 0;
 
433
        int return_val = 0;
 
434
        char **argv = NULL, **envp = NULL;
 
435
        char **current_arg, **pair;
 
436
        int pair_length;
 
437
        char *key;
 
438
        int key_length;
 
439
        char *path;
 
440
        int path_len;
 
441
        long key_num;
 
442
                
 
443
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|aa", &path, &path_len, &args, &envs) == FAILURE) {
 
444
                return;
 
445
        }
 
446
        
 
447
        if (ZEND_NUM_ARGS() > 1) {
 
448
                /* Build argumnent list */
 
449
                args_hash = HASH_OF(args);
 
450
                argc = zend_hash_num_elements(args_hash);
 
451
                
 
452
                argv = safe_emalloc((argc + 2), sizeof(char *), 0);
 
453
                *argv = path;
 
454
                for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1; 
 
455
                        (argi < argc && (zend_hash_get_current_data(args_hash, (void **) &element) == SUCCESS));
 
456
                        (argi++, current_arg++, zend_hash_move_forward(args_hash)) ) {
 
457
 
 
458
                        convert_to_string_ex(element);
 
459
                        *current_arg = Z_STRVAL_PP(element);
 
460
                }
 
461
                *(current_arg) = NULL;
 
462
        } else {
 
463
                argv = emalloc(2 * sizeof(char *));
 
464
                *argv = path;
 
465
                *(argv+1) = NULL;
 
466
        }
 
467
 
 
468
        if ( ZEND_NUM_ARGS() == 3 ) {
 
469
                /* Build environment pair list */
 
470
                envs_hash = HASH_OF(envs);
 
471
                envc = zend_hash_num_elements(envs_hash);
 
472
                
 
473
                envp = safe_emalloc((envc + 1), sizeof(char *), 0);
 
474
                for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp; 
 
475
                        (envi < envc && (zend_hash_get_current_data(envs_hash, (void **) &element) == SUCCESS));
 
476
                        (envi++, pair++, zend_hash_move_forward(envs_hash)) ) {
 
477
                        switch (return_val = zend_hash_get_current_key_ex(envs_hash, &key, &key_length, &key_num, 0, NULL)) {
 
478
                                case HASH_KEY_IS_LONG:
 
479
                                        key = emalloc(101);
 
480
                                        snprintf(key, 100, "%ld", key_num);
 
481
                                        key_length = strlen(key);
 
482
                                        break;
 
483
                                case HASH_KEY_NON_EXISTANT:
 
484
                                        pair--;
 
485
                                        continue;
 
486
                        }
 
487
 
 
488
                        convert_to_string_ex(element);
 
489
 
 
490
                        /* Length of element + equal sign + length of key + null */ 
 
491
                        pair_length = Z_STRLEN_PP(element) + key_length + 2;
 
492
                        *pair = emalloc(pair_length);
 
493
                        strlcpy(*pair, key, key_length); 
 
494
                        strlcat(*pair, "=", pair_length);
 
495
                        strlcat(*pair, Z_STRVAL_PP(element), pair_length);
 
496
                        
 
497
                        /* Cleanup */
 
498
                        if (return_val == HASH_KEY_IS_LONG) efree(key);
 
499
                }
 
500
                *(pair) = NULL;
 
501
        }
 
502
        
 
503
        if (execve(path, argv, envp) == -1) {
 
504
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occured: (errno %d) %s", errno, strerror(errno));
 
505
        }
 
506
        
 
507
        /* Cleanup */
 
508
        if (envp != NULL) {
 
509
                for (pair = envp; *pair != NULL; pair++) efree(*pair);
 
510
                efree(envp);
 
511
        }
 
512
 
 
513
        efree(argv);
 
514
        
 
515
        RETURN_FALSE;
 
516
}
 
517
/* }}} */
 
518
 
 
519
/* {{{ proto bool pcntl_signal(int signo, callback handle [, bool restart_syscalls])
 
520
   Assigns a system signal handler to a PHP function */
 
521
PHP_FUNCTION(pcntl_signal)
 
522
{
 
523
        zval *handle, **dest_handle = NULL;
 
524
        char *func_name;
 
525
        long signo;
 
526
        zend_bool restart_syscalls = 1;
 
527
 
 
528
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|b", &signo, &handle, &restart_syscalls) == FAILURE) {
 
529
                return;
 
530
        }
 
531
 
 
532
        if (!PCNTL_G(spares)) {
 
533
                /* since calling malloc() from within a signal handler is not portable,
 
534
                 * pre-allocate a few records for recording signals */
 
535
                int i;
 
536
                for (i = 0; i < 32; i++) {
 
537
                        struct php_pcntl_pending_signal *psig;
 
538
 
 
539
                        psig = emalloc(sizeof(*psig));
 
540
                        psig->next = PCNTL_G(spares);
 
541
                        PCNTL_G(spares) = psig;
 
542
                }
 
543
        }
 
544
 
 
545
        /* Special long value case for SIG_DFL and SIG_IGN */
 
546
        if (Z_TYPE_P(handle)==IS_LONG) {
 
547
                if (Z_LVAL_P(handle)!= (long) SIG_DFL && Z_LVAL_P(handle) != (long) SIG_IGN) {
 
548
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specifEied");
 
549
                }
 
550
                if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
 
551
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
 
552
                        RETURN_FALSE;
 
553
                }
 
554
                RETURN_TRUE;
 
555
        }
 
556
        
 
557
        if (!zend_is_callable(handle, 0, &func_name)) {
 
558
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name);
 
559
                efree(func_name);
 
560
                RETURN_FALSE;
 
561
        }
 
562
        efree(func_name);
 
563
        
 
564
        /* Add the function name to our signal table */
 
565
        zend_hash_index_update(&PCNTL_G(php_signal_table), signo, (void **) &handle, sizeof(zval *), (void **) &dest_handle);
 
566
        if (dest_handle) zval_add_ref(dest_handle);
 
567
        
 
568
        if (php_signal(signo, pcntl_signal_handler, (int) restart_syscalls) == SIG_ERR) {
 
569
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
 
570
                RETURN_FALSE;
 
571
        }
 
572
        RETURN_TRUE;
 
573
}
 
574
/* }}} */
 
575
 
 
576
#ifdef HAVE_GETPRIORITY
 
577
/* {{{ proto int pcntl_getpriority([int pid [, int process_identifier]])
 
578
   Get the priority of any process */
 
579
PHP_FUNCTION(pcntl_getpriority)
 
580
{
 
581
        long who = PRIO_PROCESS;
 
582
        long pid = getpid();
 
583
        int pri;
 
584
        
 
585
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &pid, &who) == FAILURE) {
 
586
                RETURN_FALSE;
 
587
        }
 
588
 
 
589
        /* needs to be cleared, since any returned value is valid */ 
 
590
        errno = 0;
 
591
 
 
592
        pri = getpriority(who, pid);
 
593
 
 
594
        if (errno) {
 
595
                switch (errno) {
 
596
                        case ESRCH:
 
597
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
 
598
                                break;
 
599
                        case EINVAL:
 
600
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
 
601
                                break;
 
602
                        default:
 
603
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occured", errno);
 
604
                                break;
 
605
                }
 
606
                RETURN_FALSE;
 
607
        }
 
608
 
 
609
        RETURN_LONG(pri);
 
610
}
 
611
/* }}} */
 
612
#endif
 
613
 
 
614
#ifdef HAVE_SETPRIORITY
 
615
/* {{{ proto bool pcntl_setpriority(int priority [, int pid [, int process_identifier]])
 
616
   Change the priority of any process */
 
617
PHP_FUNCTION(pcntl_setpriority)
 
618
{
 
619
        long who = PRIO_PROCESS;
 
620
        long pid = getpid();
 
621
        long pri;
 
622
 
 
623
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ll", &pri, &pid, &who) == FAILURE) {
 
624
                RETURN_FALSE;
 
625
        }
 
626
 
 
627
        if (setpriority(who, pid, pri)) {
 
628
                switch (errno) {
 
629
                        case ESRCH:
 
630
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
 
631
                                break;
 
632
                        case EINVAL:
 
633
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Invalid identifier flag", errno);
 
634
                                break;
 
635
                        case EPERM:
 
636
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: A process was located, but neither its effective nor real user ID matched the effective user ID of the caller", errno);
 
637
                                break;
 
638
                        case EACCES:
 
639
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: Only a super user may attempt to increase the process priority", errno);
 
640
                                break;
 
641
                        default:
 
642
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown error %d has occured", errno);
 
643
                                break;
 
644
                }
 
645
                RETURN_FALSE;
 
646
        }
 
647
        
 
648
        RETURN_TRUE;
 
649
}
 
650
/* }}} */
 
651
#endif
 
652
 
 
653
/* Our custom signal handler that calls the appropriate php_function */
 
654
static void pcntl_signal_handler(int signo)
 
655
{
 
656
        struct php_pcntl_pending_signal *psig;
 
657
        TSRMLS_FETCH();
 
658
        
 
659
        psig = PCNTL_G(spares);
 
660
        if (!psig) {
 
661
                /* oops, too many signals for us to track, so we'll forget about this one */
 
662
                return;
 
663
        }
 
664
        PCNTL_G(spares) = psig->next;
 
665
 
 
666
        psig->signo = signo;
 
667
        psig->next = NULL;
 
668
 
 
669
        /* the head check is important, as the tick handler cannot atomically clear both
 
670
         * the head and tail */
 
671
        if (PCNTL_G(head) && PCNTL_G(tail)) {
 
672
                PCNTL_G(tail)->next = psig;
 
673
        } else {
 
674
                PCNTL_G(head) = psig;
 
675
        }
 
676
        PCNTL_G(tail) = psig;
 
677
}
 
678
 
 
679
void pcntl_tick_handler()
 
680
{
 
681
        zval *param, **handle, *retval;
 
682
        struct php_pcntl_pending_signal *queue, *next;
 
683
        TSRMLS_FETCH();
 
684
 
 
685
        /* Bail if the queue is empty or if we are already playing the queue*/
 
686
        if (! PCNTL_G(head) || PCNTL_G(processing_signal_queue))
 
687
                return;
 
688
 
 
689
        /* Prevent reentrant handler calls */
 
690
        PCNTL_G(processing_signal_queue) = 1;
 
691
 
 
692
        queue = PCNTL_G(head);
 
693
        PCNTL_G(head) = NULL; /* simple stores are atomic */
 
694
        
 
695
        /* Allocate */
 
696
        MAKE_STD_ZVAL(param);
 
697
        MAKE_STD_ZVAL(retval);
 
698
 
 
699
        while (queue) {
 
700
                if (zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo, (void **) &handle)==SUCCESS) {
 
701
                        ZVAL_LONG(param, queue->signo);
 
702
 
 
703
                        /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
 
704
                        /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
 
705
                        call_user_function(EG(function_table), NULL, *handle, retval, 1, &param TSRMLS_CC);
 
706
                }
 
707
 
 
708
                next = queue->next;
 
709
                queue->next = PCNTL_G(spares);
 
710
                PCNTL_G(spares) = queue;
 
711
                queue = next;
 
712
        }
 
713
 
 
714
        /* Re-enable queue */
 
715
        PCNTL_G(processing_signal_queue) = 0;
 
716
 
 
717
        /* Clean up */
 
718
        efree(param);
 
719
        efree(retval);
 
720
}
 
721
 
 
722
 
 
723
 
 
724
/*
 
725
 * Local variables:
 
726
 * tab-width: 4
 
727
 * c-basic-offset: 4
 
728
 * indent-tabs-mode: t
 
729
 * End:
 
730
 */