Files
Ertuğrul Erata 8e13c775be core updated.
2015-05-17 16:28:10 +03:00

493 lines
15 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/python
# -*- coding: utf-8 -*-
import glob
import os
import sys
import subprocess
FSTAB = '/etc/fstab'
"""
Quick list is used for improving efficiency of the script.
Stores device names and uuids pairs for partitions so prevents multiple
communication with subprocesses.
"""
quickList = {}
FAIL_FSTAB = {
"en": "Unable to read '%s'.",
"tr": "'%s' okunamadı.",
"fr": "Impossible de lire '%s' .",
"es": "No posible leer '%s'.",
"de": "'%s' konnte nicht gelesen werden.",
"nl": "Kan '%s' niet lezen.",
}
FAIL_PATH = {
"en": "'%s' is not a valid mount point.",
"tr": "'%s' geçerli bir bağlama noktası değil.",
"fr": "'%s' n'est pas un point de montage valide.",
"es": "'%s' no es un punto de montaje válido.",
"de": "'%s' ist kein gültiger Mount-Punkt.",
"nl": "'%s' is geen geldig aankoppelpunt.",
}
FAIL_PATH_ALREADY_EXIST = {
"en": "'%s' is already being used by an entry.",
"tr": "'%s' zaten bir kayıt tarafından kullanılıyor.",
"fr": "'%s' est déjà utilisé par une entrée.",
"es": "Ya '%s' siendo utilizado por una entrada.",
"de": "'%s' wird bereits durch einen Eintrag verwendet.",
"nl": "'%s' bruges allerede af en post.",
}
FAIL_ENTRY = {
"en": "Device '%s' not found in entry list.",
"tr": "'%s' aygıtı listede bulunamadı.",
"fr": "Le matériel '%s' n'a pas été trouvé dans la liste.",
"es": "Dispositivo '%s' no encontrado en lista de entrada.",
"de": "Gerät '%s' ist nicht in der Liste eingetragen.",
"nl": "Apparaat '%s' is niet in invoerlijst gevonden.",
}
FAIL_ROOT = {
"en": "'%s' is mounted to root directory, operation cancelled.",
"tr": "'%s' diski kök dizine bağlı, işlem iptal edildi.",
"fr": "'%s' est monté sur le répertoire racine, opération annulée.",
"es": "'%s' está montado com root, operación cancelada.",
"de": "'%s' ist als Root gemounted, Vorgang abgebrochen.",
"nl": "'%s' is in root-map aangekoppeld, bewerking geannuleerd.",
}
FAIL_MOUNTED = {
"en": "'%s' is mounted to another directory, operation cancelled.",
"tr": "'%s' başka bir dizine bağlı, işlem iptal edildi.",
"fr": "'%s' est monté sur un autre répertoire, opération annulée.",
"es": "'%s' está montado en otro directorio, operación cancelada.",
"de": "'%s' ist schon auf einem anderen Mount-Punkt gemounted, Vorgang abgebrochen.",
"nl": "'%s' is in een andere map aangekoppeld, bewerking geannuleerd.",
}
FAIL_OPERATION = {
"en": "Operation failed:\n\n %s",
"tr": "İşlem başarısız:\n\n %s",
"fr": "L'opération a échoué : \n\n %s",
"es": "Operación fallada:\n\n %s",
"de": "Vorgang fehlerhaft:\n\n %s",
"nl": "Mislukte bewerking:\n\n %s",
}
class DMException(Exception):
pass
def parseFstab(fstab):
if not os.access(fstab, os.R_OK):
raise DMException, _(FAIL_FSTAB) % fstab
entries = []
for line in open(fstab):
line = line.strip()
# Check len(line) for empty lines.
if line.startswith('#') or len(line) == 0:
continue
line = line.replace('\t', ' ').split()
# Replace UUID value with device name after reading it from fstab
if line[0].startswith('UUID='):
line[0] = getPartitionNameByUUID(line[0])
entries.append(line)
elif line[0].startswith('LABEL='):
line[0] = getDeviceByLabel(line[0].replace('LABEL=', ''))
entries.append(line)
elif line[0].startswith('/dev/'):
entries.append(line)
return entries
def createPath(device, path):
real_path = path
if not os.path.exists(path) and os.path.exists(os.path.dirname(path)):
# Mount point does not exist, but parent directory does.
path = os.path.dirname(path)
if not os.path.ismount(path) and not os.path.islink(path) and os.path.isdir(path):
os.mkdir(real_path, 0755)
return True
else:
if os.path.ismount(path):
# Path is already mounted, allow user to use that mount point if it's already mounted
for _device, _path in getMounted():
if device == _device and _path == path:
return True
else:
if not os.path.islink(path) and os.path.isdir(path) and os.listdir(path) == []:
return True
return False
def getMounted():
parts = []
for line in open('/proc/mounts'):
if line.startswith('/dev/'):
device, path, other = line.split(" ", 2)
parts.append((device, path, ))
return parts
def getFSType(device):
if device.startswith('UUID='):
device = getPartitionNameByUUID(device)
cmd = "/sbin/blkid -s TYPE -o value %s" % device
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
return proc.communicate()[0].strip()
def getUUID(part):
"""
Finds UUID for the given partition.
"""
global quickList
if len(quickList) == 0:
fillQuickList()
return quickList[part]
def getPartitionNameByUUID(part):
"""
Finds name of the partition for the given UUId.
"""
global quickList
part = part.replace('UUID=', '')
if len(quickList) == 0:
fillQuickList()
for devName, uuid in quickList.items():
if uuid == part:
return devName
return ''
def fillQuickList():
"""
Fills the quick list.
"""
global quickList
cmd = "/sbin/blkid"
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
for line in proc.stdout:
line = line.replace(':', '').strip()
propList = line.split()
devName = label = uuid = fsType = ''
devName = propList[0]
for property in propList:
if property.startswith('UUID'):
uuid = property.replace('UUID=', '').replace('"', '')
quickList[devName] = uuid
def runCommand(cmd):
proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
err = proc.communicate()[1].strip()
if len(err):
fail(_(FAIL_OPERATION) % err)
# Disk.Manager methods
def isMounted(device):
"""
Searches the given partition in mounted devices. If partition is
mounted, returns mount point else returns none.
"""
for _device, _path in getMounted():
if device == _device:
return _path
return ''
def getDevices():
from pardus.diskutils import EDD
return EDD().blockDevices()
def getDeviceByLabel(label):
root = '/dev/disk/by-label'
path = os.path.join(root, label)
if os.access(path, os.R_OK):
return os.path.realpath(os.path.join(root, os.readlink(path)))
else:
return ''
def getDeviceParts(device):
if not os.path.exists(device):
return []
parts = []
for part in glob.glob("%s*" % device):
if not part == device and not getFSType(part) == "":
parts.append(part)
return parts
def getLabel(device):
"""
Finds label for the given partition.
"""
cmd = "/sbin/blkid -s LABEL -o value %s" % device
proc = subprocess.Popen(cmd.split(), stdout=subprocess.PIPE)
return proc.communicate()[0].strip()
def getPath(device):
"""
Gets partition name and determine a path for that partition.
"""
# If there is a entry record for this partition in fstab
# use path in there.
if device in listEntries():
path_, fsType_, options_ = getEntry(device)
return path_
path = '/media/'
label = getLabel(device)
# There may be partitions without a label
if not label:
if not os.path.exists(path+'disk'):
path = path+'disk'
elif not os.path.ismount(path+'disk'):
path = path+'disk'
else:
for i in range(1, len(getMounted())):
if not os.path.exists(path+'disk-'+str(i)):
path = path+'disk-'+str(i)
break
elif not os.path.ismount(path+'disk-'+str(i)):
path = path+'disk-'+str(i)
break
# Labels may be same
else:
if not os.path.exists(path+label):
path = path+label
elif not os.path.ismount(path+label):
path = path+label
else:
for i in range(1, len(getMounted())):
if not os.path.exists(path+label+'-'+str(i)):
path = path+label+'-'+str(i)
break
elif not os.path.ismount(path+label+'-'+str(i)):
path = path+label+'-'+str(i)
break
return path
def mount(device, path):
if not path:
path = getPath(device)
if not createPath(device, path):
# Can't create new path
fail(_(FAIL_PATH) % path)
elif device in [x[0] for x in getMounted()]:
# Device is mounted
fail(_(FAIL_MOUNTED) % device)
runCommand(['/bin/mount', device, path])
def umount(device):
for dev, path in getMounted():
if dev == device and path == "/":
fail(_(FAIL_ROOT) % device)
runCommand(['/bin/umount', device])
def listEntries():
try:
devices = [x[0] for x in parseFstab(FSTAB)]
return devices
except DMException:
return []
def listPaths():
"""
Return paths of the entries in fstab.
"""
try:
paths = [x[1] for x in parseFstab(FSTAB)]
return paths
except DMException:
return []
def isLabelRecord(device):
for line in open(FSTAB):
line = line.strip().replace('\t', ' ').split()
if line:
if line[0] == 'LABEL=' + getLabel(device):
return True
def addEntry(device, path, fsType, options):
path_own = False
if device in listEntries():
old_path, old_fsType, old_options = getEntry(device)
# Do not change root
if old_path == "/" and not old_path == path:
fail(_(FAIL_ROOT) % device)
# Who has that mount point? me?
if old_path == path:
path_own = True
else:
# If the path value already exist in fstab, cut the operation
if path in listPaths():
fail(_(FAIL_PATH_ALREADY_EXIST) % path)
old_path = None
if not createPath(device, path):
# Can't create new path
fail(_(FAIL_PATH) % path)
#elif device in [x[0] for x in getMounted()]:
# Device is mounted
#fail(_(FAIL_MOUNTED) % device)
partText = ''
# Before removing the entry check if it is a label record or uuid record
# Remove previous one to prevent duplicates
if old_path:
if isLabelRecord(device):
partText = 'LABEL='+getLabel(device)
else:
partText = 'UUID='+getUUID(device)
else:
partText = 'UUID='+getUUID(device)
# Add new entry
_options = []
for key, value in options.iteritems():
if value:
_options.append('%s=%s' % (key, value))
else:
_options.append(key)
if not file(FSTAB).read()[-1] == '\n':
file(FSTAB, 'a').write('\n')
_options = ','.join(_options)
addit = True
# If the partition is not already mounted the given path and,
# if the partition is not mounted anywhere, try to create a path
# and mount there.
if not path_own:
if not createPath(device, path):
addit = False
# Can't create new path
fail(_(FAIL_PATH) % path)
if not device in [x[0] for x in getMounted()]:
# Mount device
try:
mount(device, path)
except:
addit = False
raise
if addit:
# try to remove old entry before
if old_path:
removeEntry(device, silent=True)
if _options:
file(FSTAB, 'a').write('%s %s %s %s 0 0\n' % (partText, path, fsType, _options))
else:
file(FSTAB, 'a').write('%s %s %s defaults 0 0\n' % (partText, path, fsType))
# Notify clients
notify("Disk.Manager", "changed", ())
def getEntry(device):
entries = parseFstab(FSTAB)
for entry in entries:
if entry[0] == device:
_path, _fsType, _options, _dump, _pass = entry[1:]
options = {}
for part in _options.split(','):
if "=" in part:
key, value = part.split('=', 1)
options[key] = value
else:
options[part] = ""
return _path, _fsType, options
fail(_(FAIL_ENTRY) % device)
def removeEntry(device, silent=False):
if isMounted(device) == '/':
fail(_(FAIL_ROOT) % device)
if device not in listEntries():
return
newlines = []
for line in open(FSTAB):
line = line.strip()
if not len(line) == 0 and not (line.replace('\t', ' ').split()[0] == 'UUID='+getUUID(device) or line.replace('\t', ' ').split()[0] == 'LABEL='+getLabel(device) or line.replace('\t', ' ').split()[0] == device):
newlines.append(line)
file(FSTAB, 'w').write('\n'.join(newlines))
if not file(FSTAB).read()[-1] == '\n':
file(FSTAB, 'a').write('\n')
# Notify clients
if not silent:
notify("Disk.Manager", "changed", ())
import errno
from time import sleep
from fcntl import ioctl
# Path to sync executable
PATH_SYNC = '/bin/sync'
# Emulate required asm-generic/ioctl.h macros
_IOC_NRBITS = 8
_IOC_TYPEBITS = 8
_IOC_SIZEBITS = 14
_IOC_DIRBITS = 2
_IOC_NRMASK = ((1 << _IOC_NRBITS) - 1)
_IOC_TYPEMASK = ((1 << _IOC_TYPEBITS) - 1)
_IOC_SIZEMASK = ((1 << _IOC_SIZEBITS) - 1)
_IOC_DIRMASK = ((1 << _IOC_DIRBITS) - 1)
_IOC_NRSHIFT = 0
_IOC_TYPESHIFT = (_IOC_NRSHIFT + _IOC_NRBITS)
_IOC_SIZESHIFT = (_IOC_TYPESHIFT + _IOC_TYPEBITS)
_IOC_DIRSHIFT = (_IOC_SIZESHIFT + _IOC_SIZEBITS)
# Direction bits.
_IOC_NONE = 0
_IOC_WRITE = 1
_IOC_READ = 2
def _IOC(dir,type,nr,size):
return (((dir) << _IOC_DIRSHIFT) | \
(type << _IOC_TYPESHIFT) | \
((nr) << _IOC_NRSHIFT) | \
((size) << _IOC_SIZESHIFT))
def _IO(type, nr):
"""Note: type is specified in hex and nr in decimal."""
return _IOC(_IOC_NONE,(type),(nr),0)
def BLKRRPART():
"""Returns ioctl number for re-reading partition table."""
# Kernels >2.6.17 have BLKRRPART defined in include/linux/fs.h.
return _IO(0x12, 95)
# -------------------------------------------
def refreshPartitionTable(device):
"""Re-Read partition table on device."""
try:
fd = os.open(device, os.O_RDONLY)
except EnvironmentError, (error, strerror):
print 'Could not open device %s. Reason: %s.'%(device, strerror)
sys.exit(-1)
# Sync and wait for Sync to complete
os.system(PATH_SYNC)
sleep(2)
# Call required ioctl to re-read partition table
try:
ioctl(fd, BLKRRPART())
except EnvironmentError, (error, message):
# Attempt ioctl call twice in case an older kernel (1.2.x) is being used
os.system(PATH_SYNC)
sleep(2)
try:
ioctl(fd, BLKRRPART())
except EnvironmentError, (error, strerror):
print 'IOCTL Error: %s for device %s.'%(strerror, device)
sys.exit(-1)
print 'Successfully re-read partition table on device %s.'%(device)
# Sync file buffers
os.fsync(fd)
os.close(fd)
# Final sync
print "Syncing %s ... " % (device),
os.system(PATH_SYNC)
sleep(4) # for sync()
print "Done."