github.com/Cloud-Foundations/Dominator@v0.3.4/lib/wsyscall/wrappers_linux.go (about)

     1  //go:build go1.11.6 || go1.12
     2  // +build go1.11.6 go1.12
     3  
     4  // Go versions prior to 1.10 would re-use a thread that was locked to a
     5  // goroutine that exited. While go1.10 prevented thread re-use, it wasn't until
     6  // go1.11.6/go1.12 that this was reliable:
     7  // https://github.com/golang/go/issues/28979
     8  
     9  package wsyscall
    10  
    11  import (
    12  	"errors"
    13  	"os"
    14  	"runtime"
    15  	"strconv"
    16  	"syscall"
    17  )
    18  
    19  const (
    20  	S_IFBLK  = syscall.S_IFBLK
    21  	S_IFCHR  = syscall.S_IFCHR
    22  	S_IFDIR  = syscall.S_IFDIR
    23  	S_IFIFO  = syscall.S_IFIFO
    24  	S_IFLNK  = syscall.S_IFLNK
    25  	S_IFMT   = syscall.S_IFMT
    26  	S_IFREG  = syscall.S_IFREG
    27  	S_IFSOCK = syscall.S_IFSOCK
    28  	S_IREAD  = syscall.S_IREAD
    29  	S_IRGRP  = syscall.S_IRGRP
    30  	S_IROTH  = syscall.S_IROTH
    31  	S_IRUSR  = syscall.S_IRUSR
    32  	S_IRWXG  = syscall.S_IRWXG
    33  	S_IRWXO  = syscall.S_IRWXO
    34  	S_IRWXU  = syscall.S_IRWXU
    35  	S_ISGID  = syscall.S_ISGID
    36  	S_ISUID  = syscall.S_ISUID
    37  	S_ISVTX  = syscall.S_ISVTX
    38  	S_IWGRP  = syscall.S_IWGRP
    39  	S_IWOTH  = syscall.S_IWOTH
    40  	S_IWRITE = syscall.S_IWRITE
    41  	S_IWUSR  = syscall.S_IWUSR
    42  	S_IXGRP  = syscall.S_IXGRP
    43  	S_IXOTH  = syscall.S_IXOTH
    44  	S_IXUSR  = syscall.S_IXUSR
    45  
    46  	sys_SETNS = 308 // 64 bit only.
    47  )
    48  
    49  func convertStat(dest *Stat_t, source *syscall.Stat_t) {
    50  	dest.Dev = source.Dev
    51  	dest.Ino = source.Ino
    52  	dest.Nlink = uint64(source.Nlink)
    53  	dest.Mode = source.Mode
    54  	dest.Uid = source.Uid
    55  	dest.Gid = source.Gid
    56  	dest.Rdev = source.Rdev
    57  	dest.Size = source.Size
    58  	dest.Blksize = int64(source.Blksize)
    59  	dest.Blocks = source.Blocks
    60  	dest.Atim = source.Atim
    61  	dest.Mtim = source.Mtim
    62  	dest.Ctim = source.Ctim
    63  }
    64  
    65  func dup(oldfd int) (int, error) {
    66  	return syscall.Dup(oldfd)
    67  }
    68  
    69  // Arm64 linux does NOT support the Dup2 syscall
    70  // https://marcin.juszkiewicz.com.pl/download/tables/syscalls.html
    71  // and dup3 is more supported so doing it here:
    72  func dup2(oldfd int, newfd int) error {
    73  	return syscall.Dup3(oldfd, newfd, 0)
    74  }
    75  
    76  func dup3(oldfd int, newfd int, flags int) error {
    77  	return syscall.Dup3(oldfd, newfd, flags)
    78  }
    79  
    80  func fallocate(fd int, mode uint32, off int64, len int64) error {
    81  	return syscall.Fallocate(fd, mode, off, len)
    82  }
    83  
    84  func getFileDescriptorLimit() (uint64, uint64, error) {
    85  	var rlim syscall.Rlimit
    86  	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil {
    87  		return 0, 0, err
    88  	}
    89  	return rlim.Cur, rlim.Max, nil
    90  }
    91  
    92  func getrusage(who int, rusage *Rusage) error {
    93  	switch who {
    94  	case RUSAGE_CHILDREN:
    95  		who = syscall.RUSAGE_CHILDREN
    96  	case RUSAGE_SELF:
    97  		who = syscall.RUSAGE_SELF
    98  	case RUSAGE_THREAD:
    99  		who = syscall.RUSAGE_THREAD
   100  	default:
   101  		return syscall.ENOTSUP
   102  	}
   103  	var syscallRusage syscall.Rusage
   104  	if err := syscall.Getrusage(who, &syscallRusage); err != nil {
   105  		return err
   106  	}
   107  	rusage.Utime.Sec = int64(syscallRusage.Utime.Sec)
   108  	rusage.Utime.Usec = int64(syscallRusage.Utime.Usec)
   109  	rusage.Stime.Sec = int64(syscallRusage.Stime.Sec)
   110  	rusage.Stime.Usec = int64(syscallRusage.Stime.Usec)
   111  	rusage.Maxrss = int64(syscallRusage.Maxrss)
   112  	rusage.Ixrss = int64(syscallRusage.Ixrss)
   113  	rusage.Idrss = int64(syscallRusage.Idrss)
   114  	rusage.Minflt = int64(syscallRusage.Minflt)
   115  	rusage.Majflt = int64(syscallRusage.Majflt)
   116  	rusage.Nswap = int64(syscallRusage.Nswap)
   117  	rusage.Inblock = int64(syscallRusage.Inblock)
   118  	rusage.Oublock = int64(syscallRusage.Oublock)
   119  	rusage.Msgsnd = int64(syscallRusage.Msgsnd)
   120  	rusage.Msgrcv = int64(syscallRusage.Msgrcv)
   121  	rusage.Nsignals = int64(syscallRusage.Nsignals)
   122  	rusage.Nvcsw = int64(syscallRusage.Nvcsw)
   123  	rusage.Nivcsw = int64(syscallRusage.Nivcsw)
   124  	return nil
   125  }
   126  
   127  func ioctl(fd int, request, argp uintptr) error {
   128  	_, _, errno := syscall.Syscall(syscall.SYS_IOCTL, uintptr(fd), request,
   129  		argp)
   130  	if errno != 0 {
   131  		return os.NewSyscallError("ioctl", errno)
   132  	}
   133  	return nil
   134  }
   135  
   136  func lstat(path string, statbuf *Stat_t) error {
   137  	var rawStatbuf syscall.Stat_t
   138  	if err := syscall.Lstat(path, &rawStatbuf); err != nil {
   139  		return err
   140  	}
   141  	convertStat(statbuf, &rawStatbuf)
   142  	return nil
   143  }
   144  
   145  func mount(source string, target string, fstype string, flags uintptr,
   146  	data string) error {
   147  	var linuxFlags uintptr
   148  	if flags&MS_BIND != 0 {
   149  		linuxFlags |= syscall.MS_BIND
   150  	}
   151  	if flags&MS_RDONLY != 0 {
   152  		linuxFlags |= syscall.MS_RDONLY
   153  	}
   154  	return syscall.Mount(source, target, fstype, linuxFlags, data)
   155  }
   156  
   157  func reboot() error {
   158  	return syscall.Reboot(syscall.LINUX_REBOOT_CMD_RESTART)
   159  }
   160  
   161  func setAllGid(gid int) error {
   162  	return syscall.Setresgid(gid, gid, gid)
   163  }
   164  
   165  func setAllUid(uid int) error {
   166  	return syscall.Setresuid(uid, uid, uid)
   167  }
   168  
   169  // setMyPriority sets the priority of the current process, for all OS threads.
   170  // It will iterate over all the threads and set the priority on each, since the
   171  // Linux implementation of setpriority(2) only applies to a thread, not the
   172  // whole process (contrary to the POSIX specification).
   173  func setMyPriority(priority int) error {
   174  	file, err := os.Open("/proc/self/task")
   175  	if err != nil {
   176  		return err
   177  	}
   178  	defer file.Close()
   179  	taskNames, err := file.Readdirnames(0)
   180  	if err != nil {
   181  		return err
   182  	}
   183  	for _, taskName := range taskNames {
   184  		taskId, err := strconv.Atoi(taskName)
   185  		if err != nil {
   186  			return err
   187  		}
   188  		err = syscall.Setpriority(syscall.PRIO_PROCESS, taskId, priority)
   189  		if err != nil {
   190  			return err
   191  		}
   192  	}
   193  	return nil
   194  }
   195  
   196  func setNetNamespace(namespaceFd int) error {
   197  	runtime.LockOSThread()
   198  	_, _, errno := syscall.Syscall(sys_SETNS, uintptr(namespaceFd),
   199  		uintptr(syscall.CLONE_NEWNET), 0)
   200  	if errno != 0 {
   201  		return os.NewSyscallError("setns", errno)
   202  	}
   203  	return nil
   204  
   205  }
   206  
   207  func stat(path string, statbuf *Stat_t) error {
   208  	var rawStatbuf syscall.Stat_t
   209  	if err := syscall.Stat(path, &rawStatbuf); err != nil {
   210  		return err
   211  	}
   212  	convertStat(statbuf, &rawStatbuf)
   213  	return nil
   214  }
   215  
   216  func unshareMountNamespace() error {
   217  	// Pin goroutine to OS thread. This hack is required because
   218  	// syscall.Unshare() operates on only one thread in the process, and Go
   219  	// switches execution between threads randomly. Thus, the namespace can be
   220  	// suddenly switched for running code. This is an aspect of Go that was not
   221  	// well thought out.
   222  	runtime.LockOSThread()
   223  	if err := syscall.Unshare(syscall.CLONE_NEWNS); err != nil {
   224  		return errors.New("error unsharing mount namespace: " + err.Error())
   225  	}
   226  	err := syscall.Mount("none", "/", "", syscall.MS_REC|syscall.MS_PRIVATE, "")
   227  	if err != nil {
   228  		return errors.New("error making mounts private: " + err.Error())
   229  	}
   230  	return nil
   231  }
   232  
   233  func sync() error {
   234  	syscall.Sync()
   235  	return nil
   236  }
   237  
   238  func unshareNetNamespace() (int, int, error) {
   239  	runtime.LockOSThread()
   240  	if err := syscall.Unshare(syscall.CLONE_NEWNET); err != nil {
   241  		return -1, -1,
   242  			errors.New("error unsharing net namespace: " + err.Error())
   243  	}
   244  	tid := syscall.Gettid()
   245  	tidString := strconv.FormatInt(int64(tid), 10)
   246  	fd, err := syscall.Open("/proc/"+tidString+"/ns/net", syscall.O_RDONLY, 0)
   247  	if err != nil {
   248  		return -1, -1,
   249  			errors.New("error getting FD for namespace: " + err.Error())
   250  	}
   251  	return fd, tid, nil
   252  }