gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

mountpoint.go (4867B)


      1 // Copyright (c) 2017 Uber Technologies, Inc.
      2 //
      3 // Permission is hereby granted, free of charge, to any person obtaining a copy
      4 // of this software and associated documentation files (the "Software"), to deal
      5 // in the Software without restriction, including without limitation the rights
      6 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      7 // copies of the Software, and to permit persons to whom the Software is
      8 // furnished to do so, subject to the following conditions:
      9 //
     10 // The above copyright notice and this permission notice shall be included in
     11 // all copies or substantial portions of the Software.
     12 //
     13 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     18 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     19 // THE SOFTWARE.
     20 
     21 //go:build linux
     22 // +build linux
     23 
     24 package cgroups
     25 
     26 import (
     27 	"bufio"
     28 	"os"
     29 	"path/filepath"
     30 	"strconv"
     31 	"strings"
     32 )
     33 
     34 const (
     35 	_mountInfoSep               = " "
     36 	_mountInfoOptsSep           = ","
     37 	_mountInfoOptionalFieldsSep = "-"
     38 )
     39 
     40 const (
     41 	_miFieldIDMountID = iota
     42 	_miFieldIDParentID
     43 	_miFieldIDDeviceID
     44 	_miFieldIDRoot
     45 	_miFieldIDMountPoint
     46 	_miFieldIDOptions
     47 	_miFieldIDOptionalFields
     48 
     49 	_miFieldCountFirstHalf
     50 )
     51 
     52 const (
     53 	_miFieldOffsetFSType = iota
     54 	_miFieldOffsetMountSource
     55 	_miFieldOffsetSuperOptions
     56 
     57 	_miFieldCountSecondHalf
     58 )
     59 
     60 const _miFieldCountMin = _miFieldCountFirstHalf + _miFieldCountSecondHalf
     61 
     62 // MountPoint is the data structure for the mount points in
     63 // `/proc/$PID/mountinfo`. See also proc(5) for more information.
     64 type MountPoint struct {
     65 	MountID        int
     66 	ParentID       int
     67 	DeviceID       string
     68 	Root           string
     69 	MountPoint     string
     70 	Options        []string
     71 	OptionalFields []string
     72 	FSType         string
     73 	MountSource    string
     74 	SuperOptions   []string
     75 }
     76 
     77 // NewMountPointFromLine parses a line read from `/proc/$PID/mountinfo` and
     78 // returns a new *MountPoint.
     79 func NewMountPointFromLine(line string) (*MountPoint, error) {
     80 	fields := strings.Split(line, _mountInfoSep)
     81 
     82 	if len(fields) < _miFieldCountMin {
     83 		return nil, mountPointFormatInvalidError{line}
     84 	}
     85 
     86 	mountID, err := strconv.Atoi(fields[_miFieldIDMountID])
     87 	if err != nil {
     88 		return nil, err
     89 	}
     90 
     91 	parentID, err := strconv.Atoi(fields[_miFieldIDParentID])
     92 	if err != nil {
     93 		return nil, err
     94 	}
     95 
     96 	for i, field := range fields[_miFieldIDOptionalFields:] {
     97 		if field == _mountInfoOptionalFieldsSep {
     98 			fsTypeStart := _miFieldIDOptionalFields + i + 1
     99 
    100 			if len(fields) != fsTypeStart+_miFieldCountSecondHalf {
    101 				return nil, mountPointFormatInvalidError{line}
    102 			}
    103 
    104 			miFieldIDFSType := _miFieldOffsetFSType + fsTypeStart
    105 			miFieldIDMountSource := _miFieldOffsetMountSource + fsTypeStart
    106 			miFieldIDSuperOptions := _miFieldOffsetSuperOptions + fsTypeStart
    107 
    108 			return &MountPoint{
    109 				MountID:        mountID,
    110 				ParentID:       parentID,
    111 				DeviceID:       fields[_miFieldIDDeviceID],
    112 				Root:           fields[_miFieldIDRoot],
    113 				MountPoint:     fields[_miFieldIDMountPoint],
    114 				Options:        strings.Split(fields[_miFieldIDOptions], _mountInfoOptsSep),
    115 				OptionalFields: fields[_miFieldIDOptionalFields:(fsTypeStart - 1)],
    116 				FSType:         fields[miFieldIDFSType],
    117 				MountSource:    fields[miFieldIDMountSource],
    118 				SuperOptions:   strings.Split(fields[miFieldIDSuperOptions], _mountInfoOptsSep),
    119 			}, nil
    120 		}
    121 	}
    122 
    123 	return nil, mountPointFormatInvalidError{line}
    124 }
    125 
    126 // Translate converts an absolute path inside the *MountPoint's file system to
    127 // the host file system path in the mount namespace the *MountPoint belongs to.
    128 func (mp *MountPoint) Translate(absPath string) (string, error) {
    129 	relPath, err := filepath.Rel(mp.Root, absPath)
    130 
    131 	if err != nil {
    132 		return "", err
    133 	}
    134 	if relPath == ".." || strings.HasPrefix(relPath, "../") {
    135 		return "", pathNotExposedFromMountPointError{
    136 			mountPoint: mp.MountPoint,
    137 			root:       mp.Root,
    138 			path:       absPath,
    139 		}
    140 	}
    141 
    142 	return filepath.Join(mp.MountPoint, relPath), nil
    143 }
    144 
    145 // parseMountInfo parses procPathMountInfo (usually at `/proc/$PID/mountinfo`)
    146 // and yields parsed *MountPoint into newMountPoint.
    147 func parseMountInfo(procPathMountInfo string, newMountPoint func(*MountPoint) error) error {
    148 	mountInfoFile, err := os.Open(procPathMountInfo)
    149 	if err != nil {
    150 		return err
    151 	}
    152 	defer mountInfoFile.Close()
    153 
    154 	scanner := bufio.NewScanner(mountInfoFile)
    155 
    156 	for scanner.Scan() {
    157 		mountPoint, err := NewMountPointFromLine(scanner.Text())
    158 		if err != nil {
    159 			return err
    160 		}
    161 		if err := newMountPoint(mountPoint); err != nil {
    162 			return err
    163 		}
    164 	}
    165 
    166 	return scanner.Err()
    167 }