Source file src/os/exec/read3.go

     1  // Copyright 2020 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build ignore
     6  
     7  // This is a test program that verifies that it can read from
     8  // descriptor 3 and that no other descriptors are open.
     9  // This is not done via TestHelperProcess and GO_EXEC_TEST_PID
    10  // because we want to ensure that this program does not use cgo,
    11  // because C libraries can open file descriptors behind our backs
    12  // and confuse the test. See issue 25628.
    13  package main
    14  
    15  import (
    16  	"fmt"
    17  	"internal/poll"
    18  	"io"
    19  	"os"
    20  	"os/exec"
    21  	"os/exec/internal/fdtest"
    22  	"runtime"
    23  	"strings"
    24  )
    25  
    26  func main() {
    27  	fd3 := os.NewFile(3, "fd3")
    28  	defer fd3.Close()
    29  
    30  	bs, err := io.ReadAll(fd3)
    31  	if err != nil {
    32  		fmt.Printf("ReadAll from fd 3: %v\n", err)
    33  		os.Exit(1)
    34  	}
    35  
    36  	// Now verify that there are no other open fds.
    37  	// stdin == 0
    38  	// stdout == 1
    39  	// stderr == 2
    40  	// descriptor from parent == 3
    41  	// All descriptors 4 and up should be available,
    42  	// except for any used by the network poller.
    43  	for fd := uintptr(4); fd <= 100; fd++ {
    44  		if poll.IsPollDescriptor(fd) {
    45  			continue
    46  		}
    47  
    48  		if !fdtest.Exists(fd) {
    49  			continue
    50  		}
    51  
    52  		fmt.Printf("leaked parent file. fdtest.Exists(%d) got true want false\n", fd)
    53  
    54  		fdfile := fmt.Sprintf("/proc/self/fd/%d", fd)
    55  		link, err := os.Readlink(fdfile)
    56  		fmt.Printf("readlink(%q) = %q, %v\n", fdfile, link, err)
    57  
    58  		var args []string
    59  		switch runtime.GOOS {
    60  		case "plan9":
    61  			args = []string{fmt.Sprintf("/proc/%d/fd", os.Getpid())}
    62  		case "aix", "solaris", "illumos":
    63  			args = []string{fmt.Sprint(os.Getpid())}
    64  		default:
    65  			args = []string{"-p", fmt.Sprint(os.Getpid())}
    66  		}
    67  
    68  		// Determine which command to use to display open files.
    69  		ofcmd := "lsof"
    70  		switch runtime.GOOS {
    71  		case "dragonfly", "freebsd", "netbsd", "openbsd":
    72  			ofcmd = "fstat"
    73  		case "plan9":
    74  			ofcmd = "/bin/cat"
    75  		case "aix":
    76  			ofcmd = "procfiles"
    77  		case "solaris", "illumos":
    78  			ofcmd = "pfiles"
    79  		}
    80  
    81  		cmd := exec.Command(ofcmd, args...)
    82  		out, err := cmd.CombinedOutput()
    83  		if err != nil {
    84  			fmt.Fprintf(os.Stderr, "%s failed: %v\n", strings.Join(cmd.Args, " "), err)
    85  		}
    86  		fmt.Printf("%s", out)
    87  		os.Exit(1)
    88  	}
    89  
    90  	os.Stdout.Write(bs)
    91  }
    92  

View as plain text