github.com/apptainer/singularity@v3.1.1+incompatible/pkg/util/unix/socket.go (about)

     1  // Copyright (c) 2018, Sylabs Inc. All rights reserved.
     2  // This software is licensed under a 3-clause BSD license. Please consult the
     3  // LICENSE.md file distributed with the sources of this project regarding your
     4  // rights to use or distribute this software.
     5  
     6  package unix
     7  
     8  import (
     9  	"fmt"
    10  	"net"
    11  	"os"
    12  	"path/filepath"
    13  	"runtime"
    14  	"syscall"
    15  )
    16  
    17  // Listen wraps net.Listen to handle 108 characters issue
    18  func Listen(path string) (net.Listener, error) {
    19  	socket := path
    20  
    21  	if len(path) >= 108 {
    22  		runtime.LockOSThread()
    23  		defer runtime.UnlockOSThread()
    24  
    25  		cwd, err := os.Getwd()
    26  		if err != nil {
    27  			return nil, fmt.Errorf("failed to get current working directory: %s", err)
    28  		}
    29  		defer os.Chdir(cwd)
    30  
    31  		dir := filepath.Dir(path)
    32  		socket = filepath.Base(path)
    33  
    34  		if err := os.Chdir(dir); err != nil {
    35  			return nil, fmt.Errorf("failed to go into %s: %s", dir, err)
    36  		}
    37  	}
    38  
    39  	return net.Listen("unix", socket)
    40  }
    41  
    42  // Dial wraps net.Dial to handle 108 characters issue
    43  func Dial(path string) (net.Conn, error) {
    44  	socket := path
    45  
    46  	if len(path) >= 108 {
    47  		runtime.LockOSThread()
    48  		defer runtime.UnlockOSThread()
    49  
    50  		cwd, err := os.Getwd()
    51  		if err != nil {
    52  			return nil, fmt.Errorf("failed to get current working directory: %s", err)
    53  		}
    54  		defer os.Chdir(cwd)
    55  
    56  		dir := filepath.Dir(path)
    57  		socket = filepath.Base(path)
    58  
    59  		if err := os.Chdir(dir); err != nil {
    60  			return nil, fmt.Errorf("failed to go into %s: %s", dir, err)
    61  		}
    62  	}
    63  
    64  	return net.Dial("unix", socket)
    65  }
    66  
    67  // CreateSocket creates an unix socket and returns connection listener.
    68  func CreateSocket(path string) (net.Listener, error) {
    69  	oldmask := syscall.Umask(0177)
    70  	defer syscall.Umask(oldmask)
    71  	return Listen(path)
    72  }
    73  
    74  // WriteSocket writes data over unix socket
    75  func WriteSocket(path string, data []byte) error {
    76  	c, err := Dial(path)
    77  
    78  	if err != nil {
    79  		return fmt.Errorf("failed to connect to %s socket: %s", path, err)
    80  	}
    81  	defer c.Close()
    82  
    83  	if _, err := c.Write(data); err != nil {
    84  		return fmt.Errorf("failed to send data over socket: %s", err)
    85  	}
    86  
    87  	return nil
    88  }