portlist: fix "readdirent: no such file or directory" errors on Linux.

This could happen when a process disappeared while we were reading its
file descriptor list.

I was able to replicate the problem by running this in another
terminal:

    while :; do for i in $(seq 10); do
      /bin/true & done >&/dev/null; wait >&/dev/null;
    done

And then running the portlist tests thousands of times.

Fixes #339.

Signed-off-by: Avery Pennarun <apenwarr@tailscale.com>
pull/395/head
Avery Pennarun 4 years ago
parent c97c45f268
commit 806de4ac94

@ -110,6 +110,12 @@ func addProcesses(pl []Port) ([]Port, error) {
if err == io.EOF {
return nil
}
if os.IsNotExist(err) {
// This can happen if the directory we're
// reading disappears during the run. No big
// deal.
return nil
}
if err != nil {
return fmt.Errorf("addProcesses.readDir: %w", err)
}
@ -155,6 +161,12 @@ func foreachPID(fn func(pidStr string) error) error {
if err == io.EOF {
return nil
}
if os.IsNotExist(err) {
// This can happen if the directory we're
// reading disappears during the run. No big
// deal.
return nil
}
if err != nil {
return fmt.Errorf("foreachPID.readdir: %w", err)
}

@ -7,9 +7,14 @@ package portlist
import (
"net"
"testing"
"tailscale.com/tstest"
)
func TestGetList(t *testing.T) {
rc := tstest.NewResourceCheck()
defer rc.Assert(t)
pl, err := GetList(nil)
if err != nil {
t.Fatal(err)
@ -21,6 +26,9 @@ func TestGetList(t *testing.T) {
}
func TestIgnoreLocallyBoundPorts(t *testing.T) {
rc := tstest.NewResourceCheck()
defer rc.Assert(t)
ln, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Skipf("failed to bind: %v", err)

Loading…
Cancel
Save