1--TEST--
2FPM: Set CLOEXEC on the listen and connection socket
3--SKIPIF--
4<?php
5require_once "skipif.inc";
6FPM\Tester::skipIfShellCommandFails('lsof -v', 'lsof-org/lsof');
7?>
8--FILE--
9<?php
10
11require_once "tester.inc";
12
13$cfg = <<<'EOT'
14[global]
15error_log = {{FILE:LOG}}
16[unconfined]
17listen = {{ADDR}}
18pm = static
19pm.max_children = 1
20pm.status_listen = {{ADDR[status]}}
21pm.status_path = /status
22env[PATH] = $PATH
23EOT;
24
25$code = <<<'EOT'
26<?php
27
28$fpmPort = $_GET['fpm_port'];
29
30echo "My sockets (expect to see 2 of them - one ESTABLISHED and one LISTEN):\n";
31
32$mypid = getmypid();
33$ph = popen("/bin/sh -c 'lsof -Pn -p$mypid' 2>&1 | grep TCP | grep '127.0.0.1:$fpmPort'", 'r');
34echo stream_get_contents($ph);
35pclose($ph);
36
37echo "\n";
38
39/*
40We expect that both LISTEN (inherited from the master process) and ACCEPTED (ESTABLISHED)
41have F_CLOEXEC and should not appear in the created process.
42
43We grep out sockets from non-FPM port, because they may appear in the environment,
44e.g. PHP-FPM can inherit them from the test-runner. We cannot control the runner,
45but we can test how the FPM behaves.
46*/
47
48echo "Sockets after exec(), expected to be empty:\n";
49$ph = popen("/bin/sh -c 'lsof -Pn -p\$\$' 2>&1 | grep TCP | grep '127.0.0.1:$fpmPort'", 'r');
50var_dump(stream_get_contents($ph));
51pclose($ph);
52
53EOT;
54
55$tester = new FPM\Tester($cfg, $code);
56$tester->start();
57$tester->expectLogStartNotices();
58$tester->request(query: 'fpm_port='.$tester->getPort())->printBody();
59$tester->terminate();
60$tester->expectLogTerminatingNotices();
61$tester->close();
62
63?>
64Done
65--EXPECTF--
66My sockets (expect to see 2 of them - one ESTABLISHED and one LISTEN):
67%S 127.0.0.1:%d->127.0.0.1:%d (ESTABLISHED)
68%S 127.0.0.1:%d (LISTEN)
69
70Sockets after exec(), expected to be empty:
71string(0) ""
72Done
73--CLEAN--
74<?php
75require_once "tester.inc";
76FPM\Tester::clean();
77?>
78