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
							 | 
						|
								}
							 |