|
46 | 46 | #include <sched.h>
|
47 | 47 | #endif
|
48 | 48 |
|
| 49 | +#ifdef HAVE_PIDFD_OPEN |
| 50 | +#include <sys/syscall.h> |
| 51 | +#endif |
| 52 | + |
49 | 53 | #ifdef HAVE_FORKX
|
50 | 54 | #include <sys/fork.h>
|
51 | 55 | #endif
|
@@ -1402,6 +1406,76 @@ PHP_FUNCTION(pcntl_forkx)
|
1402 | 1406 | #endif
|
1403 | 1407 | /* }}} */
|
1404 | 1408 |
|
| 1409 | +#ifdef HAVE_PIDFD_OPEN |
| 1410 | +// The `pidfd_open` syscall is available since 5.3 |
| 1411 | +// and `setns` since 3.0. |
| 1412 | +PHP_FUNCTION(pcntl_setns) |
| 1413 | +{ |
| 1414 | + zend_long pid, nstype = CLONE_NEWNET; |
| 1415 | + bool pid_is_null = 1; |
| 1416 | + int fd, ret; |
| 1417 | + |
| 1418 | + ZEND_PARSE_PARAMETERS_START(0, 2) |
| 1419 | + Z_PARAM_OPTIONAL |
| 1420 | + Z_PARAM_LONG_OR_NULL(pid, pid_is_null) |
| 1421 | + Z_PARAM_LONG(nstype) |
| 1422 | + ZEND_PARSE_PARAMETERS_END(); |
| 1423 | + |
| 1424 | + pid = pid_is_null ? getpid() : pid; |
| 1425 | + fd = syscall(SYS_pidfd_open, pid, 0); |
| 1426 | + if (errno) { |
| 1427 | + PCNTL_G(last_error) = errno; |
| 1428 | + switch (errno) { |
| 1429 | + case EINVAL: |
| 1430 | + case ESRCH: |
| 1431 | + zend_argument_value_error(1, "is not a valid process (%d)", pid); |
| 1432 | + RETURN_THROWS(); |
| 1433 | + |
| 1434 | + case ENFILE: |
| 1435 | + php_error_docref(NULL, E_WARNING, "Error %d: File descriptors per-process limit reached", errno); |
| 1436 | + break; |
| 1437 | + |
| 1438 | + case ENODEV: |
| 1439 | + php_error_docref(NULL, E_WARNING, "Error %d: Anonymous inode fs unsupported", errno); |
| 1440 | + break; |
| 1441 | + |
| 1442 | + case ENOMEM: |
| 1443 | + php_error_docref(NULL, E_WARNING, "Error %d: Insufficient memory for pidfd_open", errno); |
| 1444 | + break; |
| 1445 | + |
| 1446 | + default: |
| 1447 | + php_error_docref(NULL, E_WARNING, "Error %d", errno); |
| 1448 | + } |
| 1449 | + RETURN_FALSE; |
| 1450 | + } |
| 1451 | + ret = setns(fd, (int)nstype); |
| 1452 | + close(fd); |
| 1453 | + |
| 1454 | + if (ret == -1) { |
| 1455 | + PCNTL_G(last_error) = errno; |
| 1456 | + switch (errno) { |
| 1457 | + case ESRCH: |
| 1458 | + zend_argument_value_error(1, "process no longer available (%d)", pid); |
| 1459 | + RETURN_THROWS(); |
| 1460 | + |
| 1461 | + case EINVAL: |
| 1462 | + zend_argument_value_error(2, "is an invalid nstype (%d)", nstype); |
| 1463 | + RETURN_THROWS(); |
| 1464 | + |
| 1465 | + case EPERM: |
| 1466 | + php_error_docref(NULL, E_WARNING, "Error %d: No required capability for this process", errno); |
| 1467 | + break; |
| 1468 | + |
| 1469 | + default: |
| 1470 | + php_error_docref(NULL, E_WARNING, "Error %d", errno); |
| 1471 | + } |
| 1472 | + RETURN_FALSE; |
| 1473 | + } else { |
| 1474 | + RETURN_TRUE; |
| 1475 | + } |
| 1476 | +} |
| 1477 | +#endif |
| 1478 | + |
1405 | 1479 | static void pcntl_interrupt_function(zend_execute_data *execute_data)
|
1406 | 1480 | {
|
1407 | 1481 | pcntl_signal_dispatch();
|
|
0 commit comments