You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							153 lines
						
					
					
						
							4.0 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							153 lines
						
					
					
						
							4.0 KiB
						
					
					
				| package command | |
| 
 | |
| import ( | |
| 	"bufio" | |
| 	"fmt" | |
| 	"github.com/seaweedfs/seaweedfs/weed/glog" | |
| 	"io" | |
| 	"os" | |
| 	"strings" | |
| ) | |
| 
 | |
| const ( | |
| 	/* 36 35 98:0 /mnt1 /mnt2 rw,noatime master:1 - ext3 /dev/root rw,errors=continue | |
| 	   (1)(2)(3)   (4)   (5)      (6)      (7)   (8) (9)   (10)         (11) | |
|  | |
| 	   (1) mount ID:  unique identifier of the mount (may be reused after umount) | |
| 	   (2) parent ID:  ID of parent (or of self for the top of the mount tree) | |
| 	   (3) major:minor:  value of st_dev for files on filesystem | |
| 	   (4) root:  root of the mount within the filesystem | |
| 	   (5) mount point:  mount point relative to the process's root | |
| 	   (6) mount options:  per mount options | |
| 	   (7) optional fields:  zero or more fields of the form "tag[:value]" | |
| 	   (8) separator:  marks the end of the optional fields | |
| 	   (9) filesystem type:  name of filesystem of the form "type[.subtype]" | |
| 	   (10) mount source:  filesystem specific information or "none" | |
| 	   (11) super options:  per super block options*/ | |
| 	mountinfoFormat = "%d %d %d:%d %s %s %s %s" | |
| ) | |
| 
 | |
| // Info reveals information about a particular mounted filesystem. This | |
| // struct is populated from the content in the /proc/<pid>/mountinfo file. | |
| type Info struct { | |
| 	// ID is a unique identifier of the mount (may be reused after umount). | |
| 	ID int | |
| 
 | |
| 	// Parent indicates the ID of the mount parent (or of self for the top of the | |
| 	// mount tree). | |
| 	Parent int | |
| 
 | |
| 	// Major indicates one half of the device ID which identifies the device class. | |
| 	Major int | |
| 
 | |
| 	// Minor indicates one half of the device ID which identifies a specific | |
| 	// instance of device. | |
| 	Minor int | |
| 
 | |
| 	// Root of the mount within the filesystem. | |
| 	Root string | |
| 
 | |
| 	// Mountpoint indicates the mount point relative to the process's root. | |
| 	Mountpoint string | |
| 
 | |
| 	// Opts represents mount-specific options. | |
| 	Opts string | |
| 
 | |
| 	// Optional represents optional fields. | |
| 	Optional string | |
| 
 | |
| 	// Fstype indicates the type of filesystem, such as EXT3. | |
| 	Fstype string | |
| 
 | |
| 	// Source indicates filesystem specific information or "none". | |
| 	Source string | |
| 
 | |
| 	// VfsOpts represents per super block options. | |
| 	VfsOpts string | |
| } | |
| 
 | |
| // Mounted determines if a specified mountpoint has been mounted. | |
| // On Linux it looks at /proc/self/mountinfo and on Solaris at mnttab. | |
| func mounted(mountPoint string) (bool, error) { | |
| 	entries, err := parseMountTable() | |
| 	if err != nil { | |
| 		return false, err | |
| 	} | |
| 
 | |
| 	// Search the table for the mountPoint | |
| 	for _, e := range entries { | |
| 		if e.Mountpoint == mountPoint { | |
| 			return true, nil | |
| 		} | |
| 	} | |
| 	return false, nil | |
| } | |
| 
 | |
| // Parse /proc/self/mountinfo because comparing Dev and ino does not work from | |
| // bind mounts | |
| func parseMountTable() ([]*Info, error) { | |
| 	f, err := os.Open("/proc/self/mountinfo") | |
| 	if err != nil { | |
| 		return nil, err | |
| 	} | |
| 	defer f.Close() | |
| 
 | |
| 	return parseInfoFile(f) | |
| } | |
| 
 | |
| func parseInfoFile(r io.Reader) ([]*Info, error) { | |
| 	var ( | |
| 		s   = bufio.NewScanner(r) | |
| 		out []*Info | |
| 	) | |
| 
 | |
| 	for s.Scan() { | |
| 		if err := s.Err(); err != nil { | |
| 			return nil, err | |
| 		} | |
| 
 | |
| 		var ( | |
| 			p              = &Info{} | |
| 			text           = s.Text() | |
| 			optionalFields string | |
| 		) | |
| 
 | |
| 		if _, err := fmt.Sscanf(text, mountinfoFormat, | |
| 			&p.ID, &p.Parent, &p.Major, &p.Minor, | |
| 			&p.Root, &p.Mountpoint, &p.Opts, &optionalFields); err != nil { | |
| 			return nil, fmt.Errorf("Scanning '%s' failed: %s", text, err) | |
| 		} | |
| 		// Safe as mountinfo encodes mountpoints with spaces as \040. | |
| 		index := strings.Index(text, " - ") | |
| 		postSeparatorFields := strings.Fields(text[index+3:]) | |
| 		if len(postSeparatorFields) < 3 { | |
| 			return nil, fmt.Errorf("Error found less than 3 fields post '-' in %q", text) | |
| 		} | |
| 
 | |
| 		if optionalFields != "-" { | |
| 			p.Optional = optionalFields | |
| 		} | |
| 
 | |
| 		p.Fstype = postSeparatorFields[0] | |
| 		p.Source = postSeparatorFields[1] | |
| 		p.VfsOpts = strings.Join(postSeparatorFields[2:], " ") | |
| 		out = append(out, p) | |
| 	} | |
| 	return out, nil | |
| } | |
| 
 | |
| func checkMountPointAvailable(dir string) bool { | |
| 	mountPoint := dir | |
| 	if mountPoint != "/" && strings.HasSuffix(mountPoint, "/") { | |
| 		mountPoint = mountPoint[0 : len(mountPoint)-1] | |
| 	} | |
| 
 | |
| 	if mounted, err := mounted(mountPoint); err != nil || mounted { | |
| 		if err != nil { | |
| 			glog.Errorf("check %s: %v", mountPoint, err) | |
| 		} | |
| 		return false | |
| 	} | |
| 
 | |
| 	return true | |
| }
 |