github.com/rkt/rkt@v1.30.1-0.20200224141603-171c416fac02/tests/inspect/inspect.go (about)

     1  // Copyright 2015 The rkt Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package main
    16  
    17  import (
    18  	"bufio"
    19  	"bytes"
    20  	"crypto/sha1"
    21  	"flag"
    22  	"fmt"
    23  	"io/ioutil"
    24  	"os"
    25  	"os/signal"
    26  	"path/filepath"
    27  	"sort"
    28  	"strconv"
    29  	"strings"
    30  	"syscall"
    31  	"time"
    32  	"unsafe"
    33  
    34  	"golang.org/x/sys/unix"
    35  
    36  	"github.com/appc/spec/pkg/device"
    37  	"github.com/rkt/rkt/common/cgroup"
    38  	"github.com/rkt/rkt/common/cgroup/v1"
    39  	"github.com/rkt/rkt/common/cgroup/v2"
    40  	"github.com/rkt/rkt/tests/testutils"
    41  	"github.com/syndtr/gocapability/capability"
    42  )
    43  
    44  var (
    45  	globalFlagset = flag.NewFlagSet("inspect", flag.ExitOnError)
    46  	globalFlags   = struct {
    47  		ReadStdin          bool
    48  		CheckTty           bool
    49  		CheckPath          bool
    50  		PrintExec          bool
    51  		PrintMsg           string
    52  		SuffixMsg          string
    53  		PrintEnv           string
    54  		PrintCapsPid       int
    55  		PrintUser          bool
    56  		PrintGroups        bool
    57  		PrintCwd           bool
    58  		ExitCode           int
    59  		ReadFile           bool
    60  		WriteFile          bool
    61  		StatFile           bool
    62  		HashFile           bool
    63  		FileSymlinkTarget  bool
    64  		Sleep              int
    65  		PreSleep           int
    66  		PrintMemoryLimit   bool
    67  		PrintCPUQuota      bool
    68  		PrintCPUShares     bool
    69  		FileName           string
    70  		Content            string
    71  		CheckCgroupMounts  bool
    72  		PrintNetNS         bool
    73  		PrintIpcNS         bool
    74  		PrintIPv4          string
    75  		PrintIPv6          string
    76  		PrintDefaultGWv4   bool
    77  		PrintDefaultGWv6   bool
    78  		PrintGWv4          string
    79  		PrintGWv6          string
    80  		PrintHostname      bool
    81  		GetHTTP            string
    82  		ServeHTTP          string
    83  		ServeHTTPTimeout   int
    84  		PrintIfaceCount    bool
    85  		PrintAppAnnotation string
    86  		SilentSigterm      bool
    87  		CheckMountNS       bool
    88  		PrintNoNewPrivs    bool
    89  		CheckMknod         string
    90  	}{}
    91  )
    92  
    93  func init() {
    94  	globalFlagset.BoolVar(&globalFlags.ReadStdin, "read-stdin", false, "Read a line from stdin")
    95  	globalFlagset.BoolVar(&globalFlags.CheckTty, "check-tty", false, "Check if stdin is a terminal")
    96  	globalFlagset.BoolVar(&globalFlags.CheckPath, "check-path", false, "Check if environment variable PATH does not contain \\n")
    97  	globalFlagset.BoolVar(&globalFlags.PrintExec, "print-exec", false, "Print the command we were exceed as (i.e. argv[0])")
    98  	globalFlagset.StringVar(&globalFlags.PrintMsg, "print-msg", "", "Print the message given as parameter")
    99  	globalFlagset.StringVar(&globalFlags.SuffixMsg, "suffix-msg", "", "Print this suffix after some commands")
   100  	globalFlagset.BoolVar(&globalFlags.PrintCwd, "print-cwd", false, "Print the current working directory")
   101  	globalFlagset.StringVar(&globalFlags.PrintEnv, "print-env", "", "Print the specified environment variable")
   102  	globalFlagset.IntVar(&globalFlags.PrintCapsPid, "print-caps-pid", -1, "Print capabilities of the specified pid (or current process if pid=0)")
   103  	globalFlagset.BoolVar(&globalFlags.PrintUser, "print-user", false, "Print uid and gid")
   104  	globalFlagset.BoolVar(&globalFlags.PrintGroups, "print-groups", false, "Print all gids")
   105  	globalFlagset.IntVar(&globalFlags.ExitCode, "exit-code", 0, "Return this exit code")
   106  	globalFlagset.BoolVar(&globalFlags.ReadFile, "read-file", false, "Print the content of the file $FILE")
   107  	globalFlagset.BoolVar(&globalFlags.WriteFile, "write-file", false, "Write $CONTENT in the file $FILE")
   108  	globalFlagset.BoolVar(&globalFlags.StatFile, "stat-file", false, "Print the ownership and mode of the file $FILE")
   109  	globalFlagset.BoolVar(&globalFlags.HashFile, "hash-file", false, "Print the SHA1SUM of the file $FILE")
   110  	globalFlagset.BoolVar(&globalFlags.FileSymlinkTarget, "file-symlink-target", false, "Print the symlink target of $FILE")
   111  	globalFlagset.IntVar(&globalFlags.Sleep, "sleep", -1, "Sleep before exiting (in seconds)")
   112  	globalFlagset.IntVar(&globalFlags.PreSleep, "pre-sleep", -1, "Sleep before executing (in seconds)")
   113  	globalFlagset.BoolVar(&globalFlags.PrintMemoryLimit, "print-memorylimit", false, "Print cgroup memory limit")
   114  	globalFlagset.BoolVar(&globalFlags.PrintCPUQuota, "print-cpuquota", false, "Print cgroup cpu quota in milli-cores")
   115  	globalFlagset.BoolVar(&globalFlags.PrintCPUShares, "print-cpushares", false, "Print cgroup cpu shares")
   116  	globalFlagset.StringVar(&globalFlags.FileName, "file-name", "", "The file to read/write, $FILE will be ignored if this is specified")
   117  	globalFlagset.StringVar(&globalFlags.Content, "content", "", "The content to write, $CONTENT will be ignored if this is specified")
   118  	globalFlagset.BoolVar(&globalFlags.CheckCgroupMounts, "check-cgroups", false, "Try to write to the cgroup filesystem. Everything should be RO except some well-known files")
   119  	globalFlagset.BoolVar(&globalFlags.PrintNetNS, "print-netns", false, "Print the network namespace")
   120  	globalFlagset.BoolVar(&globalFlags.PrintIpcNS, "print-ipcns", false, "Print the IPC namespace")
   121  	globalFlagset.StringVar(&globalFlags.PrintIPv4, "print-ipv4", "", "Takes an interface name and prints its IPv4")
   122  	globalFlagset.StringVar(&globalFlags.PrintIPv6, "print-ipv6", "", "Takes an interface name and prints its IPv6")
   123  	globalFlagset.BoolVar(&globalFlags.PrintDefaultGWv4, "print-defaultgwv4", false, "Print the default IPv4 gateway")
   124  	globalFlagset.BoolVar(&globalFlags.PrintDefaultGWv6, "print-defaultgwv6", false, "Print the default IPv6 gateway")
   125  	globalFlagset.StringVar(&globalFlags.PrintGWv4, "print-gwv4", "", "Takes an interface name and prints its gateway's IPv4")
   126  	globalFlagset.StringVar(&globalFlags.PrintGWv6, "print-gwv6", "", "Takes an interface name and prints its gateway's IPv6")
   127  	globalFlagset.BoolVar(&globalFlags.PrintHostname, "print-hostname", false, "Prints the pod hostname")
   128  	globalFlagset.StringVar(&globalFlags.GetHTTP, "get-http", "", "HTTP-Get from the given address")
   129  	globalFlagset.StringVar(&globalFlags.ServeHTTP, "serve-http", "", "Serve the hostname via HTTP on the given address:port")
   130  	globalFlagset.IntVar(&globalFlags.ServeHTTPTimeout, "serve-http-timeout", 30, "HTTP Timeout to wait for a client connection")
   131  	globalFlagset.BoolVar(&globalFlags.PrintIfaceCount, "print-iface-count", false, "Print the interface count")
   132  	globalFlagset.StringVar(&globalFlags.PrintAppAnnotation, "print-app-annotation", "", "Take an annotation name of the app, and prints its value")
   133  	globalFlagset.BoolVar(&globalFlags.SilentSigterm, "silent-sigterm", false, "Exit with a success exit status if we receive SIGTERM")
   134  	globalFlagset.BoolVar(&globalFlags.CheckMountNS, "check-mountns", false, "Check if app's mount ns is different than stage1's. Requires CAP_SYS_PTRACE")
   135  	globalFlagset.BoolVar(&globalFlags.PrintNoNewPrivs, "print-no-new-privs", false, "print the prctl PR_GET_NO_NEW_PRIVS value")
   136  	globalFlagset.StringVar(&globalFlags.CheckMknod, "check-mknod", "", "check whether mknod on restricted devices is allowed")
   137  }
   138  
   139  func in(list []int, el int) bool {
   140  	for _, x := range list {
   141  		if el == x {
   142  			return true
   143  		}
   144  	}
   145  	return false
   146  }
   147  
   148  func main() {
   149  	globalFlagset.Parse(os.Args[1:])
   150  	args := globalFlagset.Args()
   151  	if len(args) > 0 {
   152  		fmt.Fprintln(os.Stderr, "Wrong parameters")
   153  		os.Exit(254)
   154  	}
   155  
   156  	if globalFlags.SilentSigterm {
   157  		terminateCh := make(chan os.Signal, 1)
   158  		signal.Notify(terminateCh, syscall.SIGTERM)
   159  		go func() {
   160  			<-terminateCh
   161  			os.Exit(0)
   162  		}()
   163  	}
   164  
   165  	if globalFlags.PreSleep >= 0 {
   166  		time.Sleep(time.Duration(globalFlags.PreSleep) * time.Second)
   167  	}
   168  
   169  	if globalFlags.ReadStdin {
   170  		reader := bufio.NewReader(os.Stdin)
   171  		fmt.Printf("Enter text:\n")
   172  		text, _ := reader.ReadString('\n')
   173  		fmt.Printf("Received text: %s\n", text)
   174  	}
   175  
   176  	if globalFlags.PrintNoNewPrivs {
   177  		r1, _, err := syscall.Syscall(
   178  			syscall.SYS_PRCTL,
   179  			uintptr(unix.PR_GET_NO_NEW_PRIVS),
   180  			uintptr(0), uintptr(0),
   181  		)
   182  
   183  		fmt.Printf("no_new_privs: %v err: %v\n", r1, err)
   184  	}
   185  
   186  	if globalFlags.CheckMknod != "" {
   187  		/* format: c:5:2:name */
   188  		dev := strings.SplitN(globalFlags.CheckMknod, ":", 4)
   189  		if len(dev) < 4 {
   190  			fmt.Fprintln(os.Stderr, "Not enough parameters for mknod")
   191  			os.Exit(254)
   192  		}
   193  		typ := dev[0]
   194  		major, err := strconv.Atoi(dev[1])
   195  		if err != nil {
   196  			fmt.Fprintln(os.Stderr, "Wrong major")
   197  			os.Exit(254)
   198  		}
   199  		minor, err := strconv.Atoi(dev[2])
   200  		if err != nil {
   201  			fmt.Fprintln(os.Stderr, "Wrong minor")
   202  			os.Exit(254)
   203  		}
   204  		nodeName := dev[3]
   205  
   206  		majorMinor := device.Makedev(uint(major), uint(minor))
   207  		mode := uint32(0777)
   208  		switch typ {
   209  		case "c":
   210  			mode |= syscall.S_IFCHR
   211  		case "b":
   212  			mode |= syscall.S_IFBLK
   213  		default:
   214  			fmt.Fprintln(os.Stderr, "Wrong device node type")
   215  			os.Exit(254)
   216  		}
   217  
   218  		if err := syscall.Mknod(nodeName, mode, int(majorMinor)); err != nil {
   219  			fmt.Fprintf(os.Stderr, "mknod %s: fail: %v\n", nodeName, err)
   220  			os.Exit(254)
   221  		} else {
   222  			fmt.Printf("mknod %s: succeed\n", nodeName)
   223  			os.Exit(0)
   224  		}
   225  	}
   226  
   227  	if globalFlags.CheckTty {
   228  		fd := int(os.Stdin.Fd())
   229  		var termios syscall.Termios
   230  		_, _, err := syscall.Syscall6(syscall.SYS_IOCTL, uintptr(fd), syscall.TCGETS, uintptr(unsafe.Pointer(&termios)), 0, 0, 0)
   231  		if err == 0 {
   232  			fmt.Printf("stdin is a terminal\n")
   233  		} else {
   234  			fmt.Printf("stdin is not a terminal\n")
   235  		}
   236  	}
   237  
   238  	if globalFlags.CheckPath {
   239  		envBytes, err := ioutil.ReadFile("/proc/self/environ")
   240  		if err != nil {
   241  			fmt.Fprintf(os.Stderr, "Error reading environment from \"/proc/self/environ\": %v\n", err)
   242  			os.Exit(254)
   243  		}
   244  		for _, v := range bytes.Split(envBytes, []byte{0}) {
   245  			if len(v) == 0 {
   246  				continue
   247  			}
   248  			if strings.HasPrefix(string(v), "PATH=") {
   249  				if strings.Contains(string(v), "\n") {
   250  					fmt.Fprintf(os.Stderr, "Malformed PATH: found new line")
   251  					os.Exit(254)
   252  				} else {
   253  					fmt.Printf("PATH is good\n")
   254  					os.Exit(0)
   255  				}
   256  			} else {
   257  				continue
   258  			}
   259  		}
   260  		fmt.Fprintf(os.Stderr, "PATH not found")
   261  		os.Exit(254)
   262  	}
   263  
   264  	if globalFlags.PrintExec {
   265  		fmt.Fprintf(os.Stdout, "inspect exceed as: %s\n", os.Args[0])
   266  	}
   267  
   268  	if globalFlags.PrintMsg != "" {
   269  		fmt.Fprintf(os.Stdout, "%s\n", globalFlags.PrintMsg)
   270  		messageLoopStr := os.Getenv("MESSAGE_LOOP")
   271  		messageLoop, err := strconv.Atoi(messageLoopStr)
   272  		if err == nil {
   273  			for i := 0; i < messageLoop; i++ {
   274  				time.Sleep(time.Second)
   275  				fmt.Fprintf(os.Stdout, "%s\n", globalFlags.PrintMsg)
   276  			}
   277  		}
   278  	}
   279  
   280  	if globalFlags.PrintEnv != "" {
   281  		fmt.Fprintf(os.Stdout, "%s=%s\n", globalFlags.PrintEnv, os.Getenv(globalFlags.PrintEnv))
   282  	}
   283  
   284  	if globalFlags.PrintCapsPid >= 0 {
   285  		caps, err := capability.NewPid(globalFlags.PrintCapsPid)
   286  		if err != nil {
   287  			fmt.Fprintf(os.Stderr, "Cannot get caps: %v\n", err)
   288  			os.Exit(254)
   289  		}
   290  		fmt.Printf("Capability set: effective: %s (%s)\n", caps.StringCap(capability.EFFECTIVE), globalFlags.SuffixMsg)
   291  		fmt.Printf("Capability set: permitted: %s (%s)\n", caps.StringCap(capability.PERMITTED), globalFlags.SuffixMsg)
   292  		fmt.Printf("Capability set: inheritable: %s (%s)\n", caps.StringCap(capability.INHERITABLE), globalFlags.SuffixMsg)
   293  		fmt.Printf("Capability set: bounding: %s (%s)\n", caps.StringCap(capability.BOUNDING), globalFlags.SuffixMsg)
   294  
   295  		if capStr := os.Getenv("CAPABILITY"); capStr != "" {
   296  			capInt, err := strconv.Atoi(capStr)
   297  			if err != nil {
   298  				fmt.Fprintf(os.Stderr, "Environment variable $CAPABILITY is not a valid capability number: %v\n", err)
   299  				os.Exit(254)
   300  			}
   301  			c := capability.Cap(capInt)
   302  			if caps.Get(capability.BOUNDING, c) {
   303  				fmt.Printf("%v=enabled (%s)\n", c.String(), globalFlags.SuffixMsg)
   304  			} else {
   305  				fmt.Printf("%v=disabled (%s)\n", c.String(), globalFlags.SuffixMsg)
   306  			}
   307  		}
   308  	}
   309  
   310  	if globalFlags.PrintUser {
   311  		fmt.Printf("User: uid=%d euid=%d gid=%d egid=%d\n", os.Getuid(), os.Geteuid(), os.Getgid(), os.Getegid())
   312  	}
   313  
   314  	if globalFlags.PrintGroups {
   315  		gids, err := os.Getgroups()
   316  		if err != nil {
   317  			fmt.Fprintf(os.Stderr, "Error getting groups: %v\n", err)
   318  			os.Exit(254)
   319  		}
   320  		// getgroups(2): It is unspecified whether the effective group ID of
   321  		// the calling process is included in the returned list. (Thus, an
   322  		// application should also call getegid(2) and add or remove the
   323  		// resulting value.)
   324  		egid := os.Getegid()
   325  		if !in(gids, egid) {
   326  			gids = append(gids, egid)
   327  			sort.Ints(gids)
   328  		}
   329  		var b bytes.Buffer
   330  		for _, gid := range gids {
   331  			b.WriteString(fmt.Sprintf("%d ", gid))
   332  		}
   333  		fmt.Printf("Groups: %s\n", b.String())
   334  	}
   335  
   336  	if globalFlags.WriteFile {
   337  		fileName := os.Getenv("FILE")
   338  		if globalFlags.FileName != "" {
   339  			fileName = globalFlags.FileName
   340  		}
   341  		content := os.Getenv("CONTENT")
   342  		if globalFlags.Content != "" {
   343  			content = globalFlags.Content
   344  		}
   345  
   346  		err := ioutil.WriteFile(fileName, []byte(content), 0600)
   347  		if err != nil {
   348  			fmt.Fprintf(os.Stderr, "Cannot write to file %q: %v\n", fileName, err)
   349  			os.Exit(254)
   350  		}
   351  	}
   352  
   353  	if globalFlags.ReadFile {
   354  		fileName := os.Getenv("FILE")
   355  		if globalFlags.FileName != "" {
   356  			fileName = globalFlags.FileName
   357  		}
   358  
   359  		dat, err := ioutil.ReadFile(fileName)
   360  		if err != nil {
   361  			fmt.Fprintf(os.Stderr, "Cannot read file %q: %v\n", fileName, err)
   362  			os.Exit(254)
   363  		}
   364  		fmt.Print("<<<")
   365  		fmt.Print(string(dat))
   366  		fmt.Print(">>>\n")
   367  	}
   368  
   369  	if globalFlags.StatFile {
   370  		fileName := os.Getenv("FILE")
   371  		if globalFlags.FileName != "" {
   372  			fileName = globalFlags.FileName
   373  		}
   374  
   375  		fi, err := os.Stat(fileName)
   376  		if err != nil {
   377  			fmt.Fprintf(os.Stderr, "Cannot stat file %q: %v\n", fileName, err)
   378  			os.Exit(254)
   379  		}
   380  		fmt.Printf("%s: mode: %s\n", fileName, fi.Mode().String())
   381  		fmt.Printf("%s: user: %v\n", fileName, fi.Sys().(*syscall.Stat_t).Uid)
   382  		fmt.Printf("%s: group: %v\n", fileName, fi.Sys().(*syscall.Stat_t).Gid)
   383  	}
   384  
   385  	if globalFlags.HashFile {
   386  		fileName := os.Getenv("FILE")
   387  		if globalFlags.FileName != "" {
   388  			fileName = globalFlags.FileName
   389  		}
   390  
   391  		dat, err := ioutil.ReadFile(fileName)
   392  		if err != nil {
   393  			fmt.Fprintf(os.Stderr, "Cannot read file %q: %v\n", fileName, err)
   394  			os.Exit(254)
   395  		}
   396  
   397  		fmt.Printf("sha1sum: %x\n", sha1.Sum(dat))
   398  	}
   399  
   400  	if globalFlags.FileSymlinkTarget {
   401  		fileName := os.Getenv("FILE")
   402  		if globalFlags.FileName != "" {
   403  			fileName = globalFlags.FileName
   404  		}
   405  
   406  		dst, err := os.Readlink(fileName)
   407  		if err != nil {
   408  			fmt.Fprintf(os.Stderr, "Cannot read file target %q: %v\n", fileName, err)
   409  			os.Exit(1)
   410  		}
   411  
   412  		fmt.Printf("symlink: %q -> %q\n", fileName, dst)
   413  	}
   414  
   415  	if globalFlags.PrintCwd {
   416  		wd, err := os.Getwd()
   417  		if err != nil {
   418  			fmt.Fprintf(os.Stderr, "Cannot get working directory: %v\n", err)
   419  			os.Exit(254)
   420  		}
   421  		fmt.Printf("cwd: %s\n", wd)
   422  	}
   423  
   424  	if globalFlags.PrintMemoryLimit {
   425  		// we use /proc/1/root to escape the chroot we're in and read the file
   426  		isUnified, err := cgroup.IsCgroupUnified("/proc/1/root/")
   427  		if err != nil {
   428  			fmt.Fprintf(os.Stderr, "Error getting cgroup type: %v\n", err)
   429  			os.Exit(254)
   430  		}
   431  
   432  		var limitPath string
   433  		if isUnified {
   434  			cgroupPath, err := v2.GetOwnCgroupPath()
   435  			if err != nil {
   436  				fmt.Fprintf(os.Stderr, "Error getting own memory cgroup path: %v\n", err)
   437  				os.Exit(254)
   438  			}
   439  			limitPath = filepath.Join("/proc/1/root/sys/fs/cgroup/", cgroupPath, "memory.max")
   440  			fmt.Fprintln(os.Stderr, "limitPath:", limitPath)
   441  		} else {
   442  			memCgroupPath, err := v1.GetOwnCgroupPath("memory")
   443  			if err != nil {
   444  				fmt.Fprintf(os.Stderr, "Error getting own memory cgroup path: %v\n", err)
   445  				os.Exit(254)
   446  			}
   447  			limitPath = filepath.Join("/proc/1/root/sys/fs/cgroup/memory", memCgroupPath, "memory.limit_in_bytes")
   448  			fmt.Fprintln(os.Stderr, limitPath)
   449  		}
   450  		limit, err := ioutil.ReadFile(limitPath)
   451  		if err != nil {
   452  			fmt.Fprintf(os.Stderr, "Can't read %s\n", limitPath)
   453  			os.Exit(254)
   454  		}
   455  
   456  		fmt.Printf("Memory Limit: %s\n", string(limit))
   457  	}
   458  
   459  	if globalFlags.PrintCPUQuota {
   460  		cpuCgroupPath, err := v1.GetOwnCgroupPath("cpu")
   461  		if err != nil {
   462  			fmt.Fprintf(os.Stderr, "Error getting own cpu cgroup path: %v\n", err)
   463  			os.Exit(254)
   464  		}
   465  		// we use /proc/1/root to escape the chroot we're in and read our
   466  		// cpu quota
   467  		periodPath := filepath.Join("/proc/1/root/sys/fs/cgroup/cpu", cpuCgroupPath, "cpu.cfs_period_us")
   468  		periodBytes, err := ioutil.ReadFile(periodPath)
   469  		if err != nil {
   470  			fmt.Fprintf(os.Stderr, "Can't read cpu.cpu_period_us\n")
   471  			os.Exit(254)
   472  		}
   473  		quotaPath := filepath.Join("/proc/1/root/sys/fs/cgroup/cpu", cpuCgroupPath, "cpu.cfs_quota_us")
   474  		quotaBytes, err := ioutil.ReadFile(quotaPath)
   475  		if err != nil {
   476  			fmt.Fprintf(os.Stderr, "Can't read cpu.cpu_quota_us\n")
   477  			os.Exit(254)
   478  		}
   479  
   480  		period, err := strconv.Atoi(strings.Trim(string(periodBytes), "\n"))
   481  		if err != nil {
   482  			fmt.Fprintf(os.Stderr, "%v\n", err)
   483  			os.Exit(254)
   484  		}
   485  		quota, err := strconv.Atoi(strings.Trim(string(quotaBytes), "\n"))
   486  		if err != nil {
   487  			fmt.Fprintf(os.Stderr, "%v\n", err)
   488  			os.Exit(254)
   489  		}
   490  
   491  		quotaMilliCores := quota * 1000 / period
   492  		fmt.Printf("CPU Quota: %s\n", strconv.Itoa(quotaMilliCores))
   493  	}
   494  
   495  	if globalFlags.PrintCPUShares {
   496  		cpuCgroupPath, err := v1.GetOwnCgroupPath("cpu")
   497  		if err != nil {
   498  			fmt.Fprintf(os.Stderr, "Error getting own cpu cgroup path: %v\n", err)
   499  			os.Exit(1)
   500  		}
   501  		// we use /proc/1/root to escape the chroot we're in and read our
   502  		// cpu quota
   503  		sharesPath := filepath.Join("/proc/1/root/sys/fs/cgroup/cpu", cpuCgroupPath, "cpu.shares")
   504  		sharesBytes, err := ioutil.ReadFile(sharesPath)
   505  		if err != nil {
   506  			fmt.Fprintf(os.Stderr, "Can't read cpu.shares\n")
   507  			os.Exit(1)
   508  		}
   509  
   510  		fmt.Printf("CPU Shares: %s", string(sharesBytes))
   511  	}
   512  
   513  	if globalFlags.CheckCgroupMounts {
   514  		rootCgroupPath := "/proc/1/root/sys/fs/cgroup"
   515  		testPaths := []string{rootCgroupPath}
   516  
   517  		// test a couple of controllers if they're available
   518  		if _, err := os.Stat(filepath.Join(rootCgroupPath, "memory")); err == nil {
   519  			testPaths = append(testPaths, filepath.Join(rootCgroupPath, "memory"))
   520  		}
   521  		if _, err := os.Stat(filepath.Join(rootCgroupPath, "cpu")); err == nil {
   522  			testPaths = append(testPaths, filepath.Join(rootCgroupPath, "cpu"))
   523  		}
   524  
   525  		for _, p := range testPaths {
   526  			if err := syscall.Mkdir(filepath.Join(p, "test"), 0600); err == nil || err != syscall.EROFS {
   527  				fmt.Fprintf(os.Stderr, "check-cgroups: FAIL (%v)", err)
   528  				os.Exit(254)
   529  			}
   530  		}
   531  
   532  		fmt.Println("check-cgroups: SUCCESS")
   533  	}
   534  
   535  	if globalFlags.PrintNetNS {
   536  		ns, err := os.Readlink("/proc/self/ns/net")
   537  		if err != nil {
   538  			fmt.Fprintf(os.Stderr, "%v\n", err)
   539  			os.Exit(1)
   540  		}
   541  		fmt.Printf("NetNS: %s\n", ns)
   542  	}
   543  
   544  	if globalFlags.PrintIpcNS {
   545  		ns, err := os.Readlink("/proc/self/ns/ipc")
   546  		if err != nil {
   547  			fmt.Fprintf(os.Stderr, "%v\n", err)
   548  			os.Exit(1)
   549  		}
   550  		fmt.Printf("IPCNS: %s\n", ns)
   551  	}
   552  
   553  	if globalFlags.PrintIPv4 != "" {
   554  		iface := globalFlags.PrintIPv4
   555  		ips, err := testutils.GetIPsv4(iface)
   556  		if err != nil {
   557  			fmt.Fprintf(os.Stderr, "%v\n", err)
   558  			os.Exit(254)
   559  		}
   560  		if len(ips) == 0 {
   561  			fmt.Fprintf(os.Stderr, "No IPv4 found for interface %+v:\n", iface)
   562  			os.Exit(254)
   563  		}
   564  		fmt.Printf("%v IPv4: %s\n", iface, ips[0])
   565  	}
   566  
   567  	if globalFlags.PrintDefaultGWv4 {
   568  		gw, err := testutils.GetDefaultGWv4()
   569  		if err != nil {
   570  			fmt.Fprintf(os.Stderr, "%v\n", err)
   571  			os.Exit(254)
   572  		}
   573  		fmt.Printf("DefaultGWv4: %s\n", gw)
   574  	}
   575  
   576  	if globalFlags.PrintDefaultGWv6 {
   577  		gw, err := testutils.GetDefaultGWv6()
   578  		if err != nil {
   579  			fmt.Fprintf(os.Stderr, "%v\n", err)
   580  			os.Exit(254)
   581  		}
   582  		fmt.Printf("DefaultGWv6: %s\n", gw)
   583  	}
   584  
   585  	if globalFlags.PrintGWv4 != "" {
   586  		// TODO: GetGW not implemented yet
   587  		iface := globalFlags.PrintGWv4
   588  		gw, err := testutils.GetGWv4(iface)
   589  		if err != nil {
   590  			fmt.Fprintf(os.Stderr, "%v\n", err)
   591  			os.Exit(254)
   592  		}
   593  		fmt.Printf("%v GWv4: %s\n", iface, gw)
   594  	}
   595  
   596  	if globalFlags.PrintIPv6 != "" {
   597  		// TODO
   598  	}
   599  
   600  	if globalFlags.PrintGWv6 != "" {
   601  		// TODO
   602  	}
   603  
   604  	if globalFlags.PrintHostname {
   605  		hostname, err := os.Hostname()
   606  		if err != nil {
   607  			fmt.Fprintf(os.Stderr, "%v\n", err)
   608  			os.Exit(254)
   609  		}
   610  		fmt.Printf("Hostname: %s\n", hostname)
   611  	}
   612  
   613  	if globalFlags.ServeHTTP != "" {
   614  		err := testutils.HTTPServe(globalFlags.ServeHTTP, globalFlags.ServeHTTPTimeout)
   615  		if err != nil {
   616  			fmt.Fprintf(os.Stderr, "%v\n", err)
   617  			os.Exit(254)
   618  		}
   619  	}
   620  
   621  	if globalFlags.GetHTTP != "" {
   622  		body, err := testutils.HTTPGet(globalFlags.GetHTTP)
   623  		if err != nil {
   624  			fmt.Fprintf(os.Stderr, "%v\n", err)
   625  			os.Exit(254)
   626  		}
   627  		fmt.Printf("HTTP-Get received: %s\n", body)
   628  	}
   629  
   630  	if globalFlags.PrintIfaceCount {
   631  		ifaceCount, err := testutils.GetIfaceCount()
   632  		if err != nil {
   633  			fmt.Fprintf(os.Stderr, "%v\n", err)
   634  			os.Exit(254)
   635  		}
   636  		fmt.Printf("Interface count: %d\n", ifaceCount)
   637  	}
   638  
   639  	if globalFlags.PrintAppAnnotation != "" {
   640  		mdsUrl, appName := os.Getenv("AC_METADATA_URL"), os.Getenv("AC_APP_NAME")
   641  		body, err := testutils.HTTPGet(fmt.Sprintf("%s/acMetadata/v1/apps/%s/annotations/%s", mdsUrl, appName, globalFlags.PrintAppAnnotation))
   642  		if err != nil {
   643  			fmt.Fprintf(os.Stderr, "%v\n", err)
   644  			os.Exit(254)
   645  		}
   646  		fmt.Printf("Annotation %s=%s\n", globalFlags.PrintAppAnnotation, body)
   647  	}
   648  
   649  	if globalFlags.CheckMountNS {
   650  		appMountNS, err := os.Readlink("/proc/self/ns/mnt")
   651  		if err != nil {
   652  			fmt.Fprintf(os.Stderr, "%v\n", err)
   653  			os.Exit(254)
   654  		}
   655  		s1MountNS, err := os.Readlink("/proc/1/ns/mnt")
   656  		if err != nil {
   657  			fmt.Fprintf(os.Stderr, "%v\n", err)
   658  			os.Exit(254)
   659  		}
   660  		if appMountNS != s1MountNS {
   661  			fmt.Println("check-mountns: DIFFERENT")
   662  		} else {
   663  			fmt.Println("check-mountns: IDENTICAL")
   664  			os.Exit(254)
   665  		}
   666  	}
   667  
   668  	if globalFlags.Sleep >= 0 {
   669  		time.Sleep(time.Duration(globalFlags.Sleep) * time.Second)
   670  	}
   671  
   672  	os.Exit(globalFlags.ExitCode)
   673  }