mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-07 18:24:30 -04:00
Switch to using sysfs+pmount for device mounting in linux. Should allow for the device to be disconnected without unmounting and subsequently re-connected and still detected in calibre.
This commit is contained in:
parent
45ed449af1
commit
2815d05ccc
@ -3,14 +3,14 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
"""
|
"""
|
||||||
Provides a command-line and optional graphical interface to the SONY Reader PRS-500.
|
Provides a command-line and optional graphical interface to the SONY Reader PRS-500.
|
||||||
|
|
||||||
For usage information run the script.
|
For usage information run the script.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import StringIO, sys, time, os
|
import StringIO, sys, time, os
|
||||||
from optparse import OptionParser
|
from optparse import OptionParser
|
||||||
|
|
||||||
from calibre import __version__, iswindows, __appname__
|
from calibre import __version__, iswindows, __appname__
|
||||||
from calibre.devices.errors import PathError
|
from calibre.devices.errors import PathError
|
||||||
from calibre.utils.terminfo import TerminalController
|
from calibre.utils.terminfo import TerminalController
|
||||||
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
|
from calibre.devices.errors import ArgumentError, DeviceError, DeviceLocked
|
||||||
from calibre.customize.ui import device_plugins
|
from calibre.customize.ui import device_plugins
|
||||||
@ -29,7 +29,7 @@ def human_readable(size):
|
|||||||
return size + suffix
|
return size + suffix
|
||||||
|
|
||||||
class FileFormatter(object):
|
class FileFormatter(object):
|
||||||
def __init__(self, file, term):
|
def __init__(self, file, term):
|
||||||
self.term = term
|
self.term = term
|
||||||
self.is_dir = file.is_dir
|
self.is_dir = file.is_dir
|
||||||
self.is_readonly = file.is_readonly
|
self.is_readonly = file.is_readonly
|
||||||
@ -38,18 +38,18 @@ class FileFormatter(object):
|
|||||||
self.wtime = file.wtime
|
self.wtime = file.wtime
|
||||||
self.name = file.name
|
self.name = file.name
|
||||||
self.path = file.path
|
self.path = file.path
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
def mode_string(self):
|
def mode_string(self):
|
||||||
doc=""" The mode string for this file. There are only two modes read-only and read-write """
|
doc=""" The mode string for this file. There are only two modes read-only and read-write """
|
||||||
def fget(self):
|
def fget(self):
|
||||||
mode, x = "-", "-"
|
mode, x = "-", "-"
|
||||||
if self.is_dir: mode, x = "d", "x"
|
if self.is_dir: mode, x = "d", "x"
|
||||||
if self.is_readonly: mode += "r-"+x+"r-"+x+"r-"+x
|
if self.is_readonly: mode += "r-"+x+"r-"+x+"r-"+x
|
||||||
else: mode += "rw"+x+"rw"+x+"rw"+x
|
else: mode += "rw"+x+"rw"+x+"rw"+x
|
||||||
return mode
|
return mode
|
||||||
return property(doc=doc, fget=fget)
|
return property(doc=doc, fget=fget)
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
def isdir_name(self):
|
def isdir_name(self):
|
||||||
doc='''Return self.name + '/' if self is a directory'''
|
doc='''Return self.name + '/' if self is a directory'''
|
||||||
@ -59,8 +59,8 @@ class FileFormatter(object):
|
|||||||
name += '/'
|
name += '/'
|
||||||
return name
|
return name
|
||||||
return property(doc=doc, fget=fget)
|
return property(doc=doc, fget=fget)
|
||||||
|
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
def name_in_color(self):
|
def name_in_color(self):
|
||||||
doc=""" The name in ANSI text. Directories are blue, ebooks are green """
|
doc=""" The name in ANSI text. Directories are blue, ebooks are green """
|
||||||
@ -71,24 +71,24 @@ class FileFormatter(object):
|
|||||||
if self.is_dir: cname = blue + self.name + normal
|
if self.is_dir: cname = blue + self.name + normal
|
||||||
else:
|
else:
|
||||||
ext = self.name[self.name.rfind("."):]
|
ext = self.name[self.name.rfind("."):]
|
||||||
if ext in (".pdf", ".rtf", ".lrf", ".lrx", ".txt"): cname = green + self.name + normal
|
if ext in (".pdf", ".rtf", ".lrf", ".lrx", ".txt"): cname = green + self.name + normal
|
||||||
return cname
|
return cname
|
||||||
return property(doc=doc, fget=fget)
|
return property(doc=doc, fget=fget)
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
def human_readable_size(self):
|
def human_readable_size(self):
|
||||||
doc=""" File size in human readable form """
|
doc=""" File size in human readable form """
|
||||||
def fget(self):
|
def fget(self):
|
||||||
return human_readable(self.size)
|
return human_readable(self.size)
|
||||||
return property(doc=doc, fget=fget)
|
return property(doc=doc, fget=fget)
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
def modification_time(self):
|
def modification_time(self):
|
||||||
doc=""" Last modified time in the Linux ls -l format """
|
doc=""" Last modified time in the Linux ls -l format """
|
||||||
def fget(self):
|
def fget(self):
|
||||||
return time.strftime("%Y-%m-%d %H:%M", time.localtime(self.wtime))
|
return time.strftime("%Y-%m-%d %H:%M", time.localtime(self.wtime))
|
||||||
return property(doc=doc, fget=fget)
|
return property(doc=doc, fget=fget)
|
||||||
|
|
||||||
@dynamic_property
|
@dynamic_property
|
||||||
def creation_time(self):
|
def creation_time(self):
|
||||||
doc=""" Last modified time in the Linux ls -l format """
|
doc=""" Last modified time in the Linux ls -l format """
|
||||||
@ -104,7 +104,7 @@ def info(dev):
|
|||||||
print "Mime type: ", info[3]
|
print "Mime type: ", info[3]
|
||||||
|
|
||||||
def ls(dev, path, term, recurse=False, color=False, human_readable_size=False, ll=False, cols=0):
|
def ls(dev, path, term, recurse=False, color=False, human_readable_size=False, ll=False, cols=0):
|
||||||
def col_split(l, cols): # split list l into columns
|
def col_split(l, cols): # split list l into columns
|
||||||
rows = len(l) / cols
|
rows = len(l) / cols
|
||||||
if len(l) % cols:
|
if len(l) % cols:
|
||||||
rows += 1
|
rows += 1
|
||||||
@ -112,8 +112,8 @@ def ls(dev, path, term, recurse=False, color=False, human_readable_size=False, l
|
|||||||
for i in range(rows):
|
for i in range(rows):
|
||||||
m.append(l[i::rows])
|
m.append(l[i::rows])
|
||||||
return m
|
return m
|
||||||
|
|
||||||
def row_widths(table): # Calculate widths for each column in the row-wise table
|
def row_widths(table): # Calculate widths for each column in the row-wise table
|
||||||
tcols = len(table[0])
|
tcols = len(table[0])
|
||||||
rowwidths = [ 0 for i in range(tcols) ]
|
rowwidths = [ 0 for i in range(tcols) ]
|
||||||
for row in table:
|
for row in table:
|
||||||
@ -122,19 +122,19 @@ def ls(dev, path, term, recurse=False, color=False, human_readable_size=False, l
|
|||||||
rowwidths[c] = len(item) if len(item) > rowwidths[c] else rowwidths[c]
|
rowwidths[c] = len(item) if len(item) > rowwidths[c] else rowwidths[c]
|
||||||
c += 1
|
c += 1
|
||||||
return rowwidths
|
return rowwidths
|
||||||
|
|
||||||
output = StringIO.StringIO()
|
output = StringIO.StringIO()
|
||||||
if path.endswith("/") and len(path) > 1: path = path[:-1]
|
if path.endswith("/") and len(path) > 1: path = path[:-1]
|
||||||
dirs = dev.list(path, recurse)
|
dirs = dev.list(path, recurse)
|
||||||
for dir in dirs:
|
for dir in dirs:
|
||||||
if recurse: print >>output, dir[0] + ":"
|
if recurse: print >>output, dir[0] + ":"
|
||||||
lsoutput, lscoloutput = [], []
|
lsoutput, lscoloutput = [], []
|
||||||
files = dir[1]
|
files = dir[1]
|
||||||
maxlen = 0
|
maxlen = 0
|
||||||
if ll: # Calculate column width for size column
|
if ll: # Calculate column width for size column
|
||||||
for file in files:
|
for file in files:
|
||||||
size = len(str(file.size))
|
size = len(str(file.size))
|
||||||
if human_readable_size:
|
if human_readable_size:
|
||||||
file = FileFormatter(file, term)
|
file = FileFormatter(file, term)
|
||||||
size = len(file.human_readable_size)
|
size = len(file.human_readable_size)
|
||||||
if size > maxlen: maxlen = size
|
if size > maxlen: maxlen = size
|
||||||
@ -148,29 +148,29 @@ def ls(dev, path, term, recurse=False, color=False, human_readable_size=False, l
|
|||||||
size = str(file.size)
|
size = str(file.size)
|
||||||
if human_readable_size: size = file.human_readable_size
|
if human_readable_size: size = file.human_readable_size
|
||||||
print >>output, file.mode_string, ("%"+str(maxlen)+"s")%size, file.modification_time, name
|
print >>output, file.mode_string, ("%"+str(maxlen)+"s")%size, file.modification_time, name
|
||||||
if not ll and len(lsoutput) > 0:
|
if not ll and len(lsoutput) > 0:
|
||||||
trytable = []
|
trytable = []
|
||||||
for colwidth in range(MINIMUM_COL_WIDTH, cols):
|
for colwidth in range(MINIMUM_COL_WIDTH, cols):
|
||||||
trycols = int(cols/colwidth)
|
trycols = int(cols/colwidth)
|
||||||
trytable = col_split(lsoutput, trycols)
|
trytable = col_split(lsoutput, trycols)
|
||||||
works = True
|
works = True
|
||||||
for row in trytable:
|
for row in trytable:
|
||||||
row_break = False
|
row_break = False
|
||||||
for item in row:
|
for item in row:
|
||||||
if len(item) > colwidth - 1:
|
if len(item) > colwidth - 1:
|
||||||
works, row_break = False, True
|
works, row_break = False, True
|
||||||
break
|
break
|
||||||
if row_break: break
|
if row_break: break
|
||||||
if works: break
|
if works: break
|
||||||
rowwidths = row_widths(trytable)
|
rowwidths = row_widths(trytable)
|
||||||
trytablecol = col_split(lscoloutput, len(trytable[0]))
|
trytablecol = col_split(lscoloutput, len(trytable[0]))
|
||||||
for r in range(len(trytable)):
|
for r in range(len(trytable)):
|
||||||
for c in range(len(trytable[r])):
|
for c in range(len(trytable[r])):
|
||||||
padding = rowwidths[c] - len(trytable[r][c])
|
padding = rowwidths[c] - len(trytable[r][c])
|
||||||
print >>output, trytablecol[r][c], "".ljust(padding),
|
print >>output, trytablecol[r][c], "".ljust(padding),
|
||||||
print >>output
|
print >>output
|
||||||
print >>output
|
print >>output
|
||||||
listing = output.getvalue().rstrip()+ "\n"
|
listing = output.getvalue().rstrip()+ "\n"
|
||||||
output.close()
|
output.close()
|
||||||
return listing
|
return listing
|
||||||
|
|
||||||
@ -179,20 +179,20 @@ def main():
|
|||||||
cols = term.COLS
|
cols = term.COLS
|
||||||
if not cols: # On windows terminal width is unknown
|
if not cols: # On windows terminal width is unknown
|
||||||
cols = 80
|
cols = 80
|
||||||
|
|
||||||
parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand is one of: info, books, df, ls, cp, mkdir, touch, cat, rm\n\n"+
|
parser = OptionParser(usage="usage: %prog [options] command args\n\ncommand is one of: info, books, df, ls, cp, mkdir, touch, cat, rm\n\n"+
|
||||||
"For help on a particular command: %prog command", version=__appname__+" version: " + __version__)
|
"For help on a particular command: %prog command", version=__appname__+" version: " + __version__)
|
||||||
parser.add_option("--log-packets", help="print out packet stream to stdout. "+\
|
parser.add_option("--log-packets", help="print out packet stream to stdout. "+\
|
||||||
"The numbers in the left column are byte offsets that allow the packet size to be read off easily.",
|
"The numbers in the left column are byte offsets that allow the packet size to be read off easily.",
|
||||||
dest="log_packets", action="store_true", default=False)
|
dest="log_packets", action="store_true", default=False)
|
||||||
parser.remove_option("-h")
|
parser.remove_option("-h")
|
||||||
parser.disable_interspersed_args() # Allow unrecognized options
|
parser.disable_interspersed_args() # Allow unrecognized options
|
||||||
options, args = parser.parse_args()
|
options, args = parser.parse_args()
|
||||||
|
|
||||||
if len(args) < 1:
|
if len(args) < 1:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
command = args[0]
|
command = args[0]
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
dev = None
|
dev = None
|
||||||
@ -207,27 +207,27 @@ def main():
|
|||||||
if scanner.is_device_connected(d):
|
if scanner.is_device_connected(d):
|
||||||
dev = d
|
dev = d
|
||||||
dev.reset(log_packets=options.log_packets)
|
dev.reset(log_packets=options.log_packets)
|
||||||
|
|
||||||
if dev is None:
|
if dev is None:
|
||||||
print >>sys.stderr, 'Unable to find a connected ebook reader.'
|
print >>sys.stderr, 'Unable to find a connected ebook reader.'
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
try:
|
try:
|
||||||
dev.open()
|
dev.open()
|
||||||
if command == "df":
|
if command == "df":
|
||||||
total = dev.total_space(end_session=False)
|
total = dev.total_space(end_session=False)
|
||||||
free = dev.free_space()
|
free = dev.free_space()
|
||||||
where = ("Memory", "Stick", "Card")
|
where = ("Memory", "Stick", "Card")
|
||||||
print "Filesystem\tSize \tUsed \tAvail \tUse%"
|
print "Filesystem\tSize \tUsed \tAvail \tUse%"
|
||||||
for i in range(3):
|
for i in range(3):
|
||||||
print "%-10s\t%s\t%s\t%s\t%s"%(where[i], human_readable(total[i]), human_readable(total[i]-free[i]), human_readable(free[i]),\
|
print "%-10s\t%s\t%s\t%s\t%s"%(where[i], human_readable(total[i]), human_readable(total[i]-free[i]), human_readable(free[i]),\
|
||||||
str(0 if total[i]==0 else int(100*(total[i]-free[i])/(total[i]*1.)))+"%")
|
str(0 if total[i]==0 else int(100*(total[i]-free[i])/(total[i]*1.)))+"%")
|
||||||
elif command == "books":
|
elif command == "books":
|
||||||
print "Books in main memory:"
|
print "Books in main memory:"
|
||||||
for book in dev.books():
|
for book in dev.books():
|
||||||
print book
|
print book
|
||||||
print "\nBooks on storage card:"
|
print "\nBooks on storage card:"
|
||||||
for book in dev.books(oncard=True): print book
|
for book in dev.books(oncard=True): print book
|
||||||
elif command == "mkdir":
|
elif command == "mkdir":
|
||||||
parser = OptionParser(usage="usage: %prog mkdir [options] path\nCreate a directory on the device\n\npath must begin with / or card:/")
|
parser = OptionParser(usage="usage: %prog mkdir [options] path\nCreate a directory on the device\n\npath must begin with / or card:/")
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
@ -245,7 +245,7 @@ def main():
|
|||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
print ls(dev, args[0], term, color=options.color, recurse=options.recurse, ll=options.ll, human_readable_size=options.hrs, cols=cols),
|
print ls(dev, args[0], term, color=options.color, recurse=options.recurse, ll=options.ll, human_readable_size=options.hrs, cols=cols),
|
||||||
elif command == "info":
|
elif command == "info":
|
||||||
info(dev)
|
info(dev)
|
||||||
elif command == "cp":
|
elif command == "cp":
|
||||||
@ -259,22 +259,22 @@ def main():
|
|||||||
parser.add_option('-f', '--force', dest='force', action='store_true', default=False,
|
parser.add_option('-f', '--force', dest='force', action='store_true', default=False,
|
||||||
help='Overwrite the destination file if it exists already.')
|
help='Overwrite the destination file if it exists already.')
|
||||||
options, args = parser.parse_args(args)
|
options, args = parser.parse_args(args)
|
||||||
if len(args) != 2:
|
if len(args) != 2:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
if args[0].startswith("prs500:"):
|
if args[0].startswith("prs500:"):
|
||||||
outfile = args[1]
|
outfile = args[1]
|
||||||
path = args[0][7:]
|
path = args[0][7:]
|
||||||
if path.endswith("/"): path = path[:-1]
|
if path.endswith("/"): path = path[:-1]
|
||||||
if os.path.isdir(outfile):
|
if os.path.isdir(outfile):
|
||||||
outfile = os.path.join(outfile, path[path.rfind("/")+1:])
|
outfile = os.path.join(outfile, path[path.rfind("/")+1:])
|
||||||
try:
|
try:
|
||||||
outfile = open(outfile, "wb")
|
outfile = open(outfile, "wb")
|
||||||
except IOError, e:
|
except IOError, e:
|
||||||
print >> sys.stderr, e
|
print >> sys.stderr, e
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
dev.get_file(path, outfile)
|
dev.get_file(path, outfile)
|
||||||
outfile.close()
|
outfile.close()
|
||||||
elif args[1].startswith("prs500:"):
|
elif args[1].startswith("prs500:"):
|
||||||
try:
|
try:
|
||||||
@ -299,7 +299,7 @@ def main():
|
|||||||
outfile = sys.stdout
|
outfile = sys.stdout
|
||||||
parser = OptionParser(usage="usage: %prog cat path\nShow file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/")
|
parser = OptionParser(usage="usage: %prog cat path\nShow file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/")
|
||||||
options, args = parser.parse_args(args)
|
options, args = parser.parse_args(args)
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
if args[0].endswith("/"): path = args[0][:-1]
|
if args[0].endswith("/"): path = args[0][:-1]
|
||||||
@ -311,15 +311,15 @@ def main():
|
|||||||
"and must begin with / or card:/\n\n"+\
|
"and must begin with / or card:/\n\n"+\
|
||||||
"rm will DELETE the file. Be very CAREFUL")
|
"rm will DELETE the file. Be very CAREFUL")
|
||||||
options, args = parser.parse_args(args)
|
options, args = parser.parse_args(args)
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
dev.rm(args[0])
|
dev.rm(args[0])
|
||||||
elif command == "touch":
|
elif command == "touch":
|
||||||
parser = OptionParser(usage="usage: %prog touch path\nCreate an empty file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/\n\n"+
|
parser = OptionParser(usage="usage: %prog touch path\nCreate an empty file on the device\n\npath should point to a file on the device and must begin with /,a:/ or b:/\n\n"+
|
||||||
"Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing" )
|
"Unfortunately, I cant figure out how to update file times on the device, so if path already exists, touch does nothing" )
|
||||||
options, args = parser.parse_args(args)
|
options, args = parser.parse_args(args)
|
||||||
if len(args) != 1:
|
if len(args) != 1:
|
||||||
parser.print_help()
|
parser.print_help()
|
||||||
return 1
|
return 1
|
||||||
dev.touch(args[0])
|
dev.touch(args[0])
|
||||||
|
@ -60,9 +60,8 @@ class PRS505(CLI, Device):
|
|||||||
<cache xmlns="http://www.kinoma.com/FskCache/1">
|
<cache xmlns="http://www.kinoma.com/FskCache/1">
|
||||||
</cache>
|
</cache>
|
||||||
'''.encode('utf8'))
|
'''.encode('utf8'))
|
||||||
return True
|
return True
|
||||||
except:
|
except:
|
||||||
self._card_prefix = None
|
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
return False
|
return False
|
||||||
@ -226,5 +225,5 @@ class PRS505(CLI, Device):
|
|||||||
f.close()
|
f.close()
|
||||||
write_card_prefix(self._card_a_prefix, 1)
|
write_card_prefix(self._card_a_prefix, 1)
|
||||||
write_card_prefix(self._card_b_prefix, 2)
|
write_card_prefix(self._card_b_prefix, 2)
|
||||||
|
|
||||||
self.report_progress(1.0, _('Sending metadata to device...'))
|
self.report_progress(1.0, _('Sending metadata to device...'))
|
||||||
|
@ -6,7 +6,7 @@ intended to be subclassed with the relevant parts implemented for a particular
|
|||||||
device. This class handles device detection.
|
device. This class handles device detection.
|
||||||
'''
|
'''
|
||||||
|
|
||||||
import os, subprocess, time, re
|
import os, subprocess, time, re, sys, glob
|
||||||
from itertools import repeat
|
from itertools import repeat
|
||||||
|
|
||||||
from calibre.devices.interface import DevicePlugin
|
from calibre.devices.interface import DevicePlugin
|
||||||
@ -36,6 +36,7 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
|
|
||||||
MAIN_MEMORY_VOLUME_LABEL = ''
|
MAIN_MEMORY_VOLUME_LABEL = ''
|
||||||
STORAGE_CARD_VOLUME_LABEL = ''
|
STORAGE_CARD_VOLUME_LABEL = ''
|
||||||
|
STORAGE_CARD2_VOLUME_LABEL = None
|
||||||
|
|
||||||
FDI_TEMPLATE = \
|
FDI_TEMPLATE = \
|
||||||
'''
|
'''
|
||||||
@ -345,63 +346,119 @@ class Device(DeviceConfig, DevicePlugin):
|
|||||||
raise DeviceError(_('Unable to detect the %s disk drive.')
|
raise DeviceError(_('Unable to detect the %s disk drive.')
|
||||||
%self.__class__.__name__)
|
%self.__class__.__name__)
|
||||||
|
|
||||||
devnodes = []
|
devnodes, ok = [], {}
|
||||||
for x, isfile in walk(usb_dir):
|
for x, isfile in walk(usb_dir):
|
||||||
if not isfile and '/block/' in x:
|
if not isfile and '/block/' in x:
|
||||||
parts = x.split('/')
|
parts = x.split('/')
|
||||||
idx = parts.index('block')
|
idx = parts.index('block')
|
||||||
if idx == len(parts)-2:
|
if idx == len(parts)-2:
|
||||||
devnodes.append(parts[idx+1])
|
sz = j(x, 'size')
|
||||||
|
node = parts[idx+1]
|
||||||
|
try:
|
||||||
|
exists = int(open(sz).read()) > 0
|
||||||
|
if exists:
|
||||||
|
node = self.find_largest_partition(x)
|
||||||
|
ok[node] = True
|
||||||
|
else:
|
||||||
|
ok[node] = False
|
||||||
|
except:
|
||||||
|
ok[node] = False
|
||||||
|
devnodes.append(node)
|
||||||
devnodes.sort()
|
devnodes.sort()
|
||||||
devnodes += list(repeat(None, 2))
|
devnodes += list(repeat(None, 3))
|
||||||
return devnodes[:3]
|
return tuple(['/dev/'+x if ok.get(x, False) else None for x in devnodes[:3]])
|
||||||
|
|
||||||
|
def node_mountpoint(self, node):
|
||||||
|
for line in open('/proc/mounts').readlines():
|
||||||
|
line = line.split()
|
||||||
|
if line[0] == node:
|
||||||
|
return line[1]
|
||||||
|
return None
|
||||||
|
|
||||||
|
def find_largest_partition(self, path):
|
||||||
|
node = path.split('/')[-1]
|
||||||
|
nodes = []
|
||||||
|
for x in glob.glob(path+'/'+node+'*'):
|
||||||
|
sz = x + '/size'
|
||||||
|
|
||||||
|
if not os.access(sz, os.R_OK):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
sz = int(open(sz).read())
|
||||||
|
except:
|
||||||
|
continue
|
||||||
|
if sz > 0:
|
||||||
|
nodes.append((x.split('/')[-1], sz))
|
||||||
|
|
||||||
|
nodes.sort(cmp=lambda x, y: cmp(x[1], y[1]))
|
||||||
|
if not nodes:
|
||||||
|
return node
|
||||||
|
return nodes[-1][0]
|
||||||
|
|
||||||
|
|
||||||
def open_linux(self):
|
def open_linux(self):
|
||||||
import dbus
|
|
||||||
bus = dbus.SystemBus()
|
|
||||||
hm = dbus.Interface(bus.get_object("org.freedesktop.Hal", "/org/freedesktop/Hal/Manager"), "org.freedesktop.Hal.Manager")
|
|
||||||
|
|
||||||
def conditional_mount(dev):
|
def mount(node, type):
|
||||||
mmo = bus.get_object("org.freedesktop.Hal", dev)
|
mp = self.node_mountpoint(node)
|
||||||
label = mmo.GetPropertyString('volume.label', dbus_interface='org.freedesktop.Hal.Device')
|
if mp is not None:
|
||||||
is_mounted = mmo.GetPropertyString('volume.is_mounted', dbus_interface='org.freedesktop.Hal.Device')
|
return mp, 0
|
||||||
mount_point = mmo.GetPropertyString('volume.mount_point', dbus_interface='org.freedesktop.Hal.Device')
|
|
||||||
fstype = mmo.GetPropertyString('volume.fstype', dbus_interface='org.freedesktop.Hal.Device')
|
|
||||||
if is_mounted:
|
|
||||||
return str(mount_point)
|
|
||||||
mmo.Mount(label, fstype, ['umask=077', 'uid='+str(os.getuid()), 'sync'],
|
|
||||||
dbus_interface='org.freedesktop.Hal.Device.Volume')
|
|
||||||
return os.path.normpath('/media/'+label)+'/'
|
|
||||||
|
|
||||||
mm = hm.FindDeviceStringMatch(__appname__+'.mainvolume', self.__class__.__name__)
|
if type == 'main':
|
||||||
if not mm:
|
label = self.MAIN_MEMORY_VOLUME_LABEL
|
||||||
raise DeviceError(_('Unable to detect the %s disk drive. Try rebooting.')%(self.__class__.__name__,))
|
if type == 'carda':
|
||||||
self._main_prefix = None
|
label = self.STORAGE_CARD_VOLUME_LABEL
|
||||||
for dev in mm:
|
if type == 'cardb':
|
||||||
try:
|
label = self.STORAGE_CARD2_VOLUME_LABEL
|
||||||
self._main_prefix = conditional_mount(dev)+os.sep
|
if label is None:
|
||||||
break
|
label = self.STORAGE_CARD_VOLUME_LABEL + ' 2'
|
||||||
except dbus.exceptions.DBusException:
|
extra = 0
|
||||||
continue
|
while True:
|
||||||
|
q = ' (%d)'%extra if extra else ''
|
||||||
|
if not os.path.exists('/media/'+label+q):
|
||||||
|
break
|
||||||
|
extra += 1
|
||||||
|
if extra:
|
||||||
|
label += ' (%d)'%extra
|
||||||
|
|
||||||
if not self._main_prefix:
|
def do_mount(node, label):
|
||||||
raise DeviceError('Could not open device for reading. Try a reboot.')
|
cmd = ['pmount', '-w', '-s']
|
||||||
|
label = label.replace(' ', '_')
|
||||||
|
try:
|
||||||
|
p = subprocess.Popen(cmd + [node, label])
|
||||||
|
except OSError:
|
||||||
|
raise DeviceError(_('You must install the pmount package.'))
|
||||||
|
while p.poll() is None:
|
||||||
|
time.sleep(0.1)
|
||||||
|
return p.returncode
|
||||||
|
|
||||||
self._card_a_prefix = self._card_b_prefix = None
|
ret = do_mount(node, label)
|
||||||
cards = hm.FindDeviceStringMatch(__appname__+'.cardvolume', self.__class__.__name__)
|
if ret != 0:
|
||||||
|
return None, ret
|
||||||
|
return self.node_mountpoint(node)+'/', 0
|
||||||
|
|
||||||
def mount_card(dev):
|
|
||||||
try:
|
|
||||||
return conditional_mount(dev)+os.sep
|
|
||||||
except:
|
|
||||||
import traceback
|
|
||||||
print traceback
|
|
||||||
|
|
||||||
if len(cards) >= 1:
|
main, carda, cardb = self.find_device_nodes()
|
||||||
self._card_a_prefix = mount_card(cards[0])
|
if main is None:
|
||||||
if len(cards) >=2:
|
raise DeviceError(_('Unable to detect the %s disk drive.')
|
||||||
self._card_b_prefix = mount_card(cards[1])
|
%self.__class__.__name__)
|
||||||
|
|
||||||
|
mp, ret = mount(main, 'main')
|
||||||
|
if mp is None:
|
||||||
|
raise DeviceError(
|
||||||
|
_('Unable to mount main memory (Error code: %d)')%ret)
|
||||||
|
if not mp.endswith('/'): mp += '/'
|
||||||
|
self._main_prefix = mp
|
||||||
|
cards = [x for x in (carda, cardb) if x is not None]
|
||||||
|
prefix, typ = '_card_a_prefix', 'carda'
|
||||||
|
for card in cards:
|
||||||
|
mp, ret = mount(card, typ)
|
||||||
|
if mp is None:
|
||||||
|
print >>sys.stderr, 'Unable to mount card (Error code: %d)'%ret
|
||||||
|
else:
|
||||||
|
if not mp.endswith('/'): mp += '/'
|
||||||
|
setattr(self, prefix, mp)
|
||||||
|
prefix, typ = '_card_b_prefix', 'cardb'
|
||||||
|
|
||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
@ -2,7 +2,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||||
''' Post installation script for linux '''
|
''' Post installation script for linux '''
|
||||||
import sys, os, shutil
|
import sys, os, shutil
|
||||||
from subprocess import check_call, call
|
from subprocess import check_call
|
||||||
|
|
||||||
from calibre import __version__, __appname__
|
from calibre import __version__, __appname__
|
||||||
from calibre.customize.ui import device_plugins
|
from calibre.customize.ui import device_plugins
|
||||||
@ -263,49 +263,6 @@ def setup_udev_rules(group_file, reload, fatal_errors):
|
|||||||
'''BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="%s"\n'''%(group,)
|
'''BUS=="usb", SYSFS{idProduct}=="029b", SYSFS{idVendor}=="054c", MODE="660", GROUP="%s"\n'''%(group,)
|
||||||
)
|
)
|
||||||
udev.close()
|
udev.close()
|
||||||
fdi = open_file('/usr/share/hal/fdi/policy/20thirdparty/10-calibre.fdi')
|
|
||||||
manifest.append(fdi.name)
|
|
||||||
fdi.write('<?xml version="1.0" encoding="UTF-8"?>\n\n<deviceinfo version="0.2">\n')
|
|
||||||
for cls in DEVICES:
|
|
||||||
fdi.write(\
|
|
||||||
'''
|
|
||||||
<device>
|
|
||||||
<match key="usb_device.vendor_id" int="%(vendor_id)s">
|
|
||||||
<match key="usb_device.product_id" int="%(product_id)s">
|
|
||||||
<match key="usb_device.device_revision_bcd" int="%(bcd)s">
|
|
||||||
<merge key="calibre.deviceclass" type="string">%(cls)s</merge>
|
|
||||||
</match>
|
|
||||||
</match>
|
|
||||||
</match>
|
|
||||||
</device>
|
|
||||||
'''%dict(cls=cls.__class__.__name__, vendor_id=cls.VENDOR_ID, product_id=cls.PRODUCT_ID,
|
|
||||||
prog=__appname__, bcd=cls.BCD))
|
|
||||||
fdi.write('\n'+cls.get_fdi())
|
|
||||||
fdi.write('\n</deviceinfo>\n')
|
|
||||||
fdi.close()
|
|
||||||
if reload:
|
|
||||||
called = False
|
|
||||||
for hal in ('hald', 'hal', 'haldaemon'):
|
|
||||||
hal = os.path.join('/etc/init.d', hal)
|
|
||||||
if os.access(hal, os.X_OK):
|
|
||||||
call((hal, 'restart'))
|
|
||||||
called = True
|
|
||||||
break
|
|
||||||
if not called and os.access('/etc/rc.d/rc.hald', os.X_OK):
|
|
||||||
call(('/etc/rc.d/rc.hald', 'restart'))
|
|
||||||
|
|
||||||
try:
|
|
||||||
check_call('udevadm control --reload_rules', shell=True)
|
|
||||||
except:
|
|
||||||
try:
|
|
||||||
check_call('udevcontrol reload_rules', shell=True)
|
|
||||||
except:
|
|
||||||
try:
|
|
||||||
check_call('/etc/init.d/udev reload', shell=True)
|
|
||||||
except:
|
|
||||||
if fatal_errors:
|
|
||||||
raise Exception("Couldn't reload udev, you may have to reboot")
|
|
||||||
print >>sys.stderr, "Couldn't reload udev, you may have to reboot"
|
|
||||||
return manifest
|
return manifest
|
||||||
|
|
||||||
def option_parser():
|
def option_parser():
|
||||||
@ -314,7 +271,7 @@ def option_parser():
|
|||||||
parser.add_option('--use-destdir', action='store_true', default=False, dest='destdir',
|
parser.add_option('--use-destdir', action='store_true', default=False, dest='destdir',
|
||||||
help='If set, respect the environment variable DESTDIR when installing files')
|
help='If set, respect the environment variable DESTDIR when installing files')
|
||||||
parser.add_option('--do-not-reload-udev-hal', action='store_true', dest='dont_reload', default=False,
|
parser.add_option('--do-not-reload-udev-hal', action='store_true', dest='dont_reload', default=False,
|
||||||
help='If set, do not try to reload udev rules and HAL FDI files')
|
help='Does nothing. Present for legacy reasons.')
|
||||||
parser.add_option('--group-file', default='/etc/group', dest='group_file',
|
parser.add_option('--group-file', default='/etc/group', dest='group_file',
|
||||||
help='File from which to read group information. Default: %default')
|
help='File from which to read group information. Default: %default')
|
||||||
parser.add_option('--dont-check-root', action='store_true', default=False, dest='no_root',
|
parser.add_option('--dont-check-root', action='store_true', default=False, dest='no_root',
|
||||||
|
@ -21,6 +21,7 @@ DEPENDENCIES = [
|
|||||||
('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'),
|
('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'),
|
||||||
('poppler', '0.10.5', 'poppler', 'poppler', 'poppler', 'poppler'),
|
('poppler', '0.10.5', 'poppler', 'poppler', 'poppler', 'poppler'),
|
||||||
('podofo', '0.7', 'podofo', 'podofo', 'podofo', 'podofo'),
|
('podofo', '0.7', 'podofo', 'podofo', 'podofo', 'podofo'),
|
||||||
|
('pmount', '0.9.19', 'pmount', 'pmount', 'pmount', 'pmount'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user