Linux automounting: Remove dependency on pmount. Instead use custom mount helper. Linux distributors: Make sure calibre-mount-helper is installed setuid and setgid root

This commit is contained in:
Kovid Goyal 2009-08-09 09:40:38 -06:00
parent d668f536d6
commit fbaa321738
6 changed files with 197 additions and 28 deletions

View File

@ -28,6 +28,7 @@ def freeze():
binary_includes = [ binary_includes = [
'/usr/bin/pdftohtml', '/usr/bin/pdftohtml',
'/usr/bin/calibre-mount-helper',
'/usr/lib/libunrar.so', '/usr/lib/libunrar.so',
'/usr/lib/libsqlite3.so.0', '/usr/lib/libsqlite3.so.0',
'/usr/lib/libsqlite3.so.0', '/usr/lib/libsqlite3.so.0',

View File

@ -45,6 +45,24 @@ main_functions = {
'gui' : [_ep_to_function(i) for i in entry_points['gui_scripts']], 'gui' : [_ep_to_function(i) for i in entry_points['gui_scripts']],
} }
def setup_mount_helper():
def warn():
print 'WARNING: Failed to compile mount helper. Auto mounting of',
print 'devices will not work'
if os.geteuid() != 0:
return warn()
import stat
src = os.path.join('src', 'calibre', 'devices', 'linux_mount_helper.c')
dest = '/usr/bin/calibre-mount-helper'
p = subprocess.Popen(['gcc', '-Wall', src, '-o', dest])
ret = p.wait()
if ret != 0:
return warn()
os.chown(dest, 0, 0)
os.chmod(dest,
stat.S_ISUID|stat.S_ISGID|stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
if __name__ == '__main__': if __name__ == '__main__':
from setuptools import setup, find_packages from setuptools import setup, find_packages
from pyqtdistutils import PyQtExtension, build_ext, Extension from pyqtdistutils import PyQtExtension, build_ext, Extension
@ -68,6 +86,10 @@ if __name__ == '__main__':
qt_inc = qt_inc if qt_inc not in ('', '**Unknown**') and os.path.isdir(qt_inc) else None qt_inc = qt_inc if qt_inc not in ('', '**Unknown**') and os.path.isdir(qt_inc) else None
qt_lib = qmake_query('QT_INSTALL_LIBS').splitlines()[0] qt_lib = qmake_query('QT_INSTALL_LIBS').splitlines()[0]
qt_lib = qt_lib if qt_lib not in ('', '**Unknown**') and os.path.isdir(qt_lib) else None qt_lib = qt_lib if qt_lib not in ('', '**Unknown**') and os.path.isdir(qt_lib) else None
if qt_lib is None or qt_inc is None:
print 'WARNING: Could not find QT librariers and headers.',
print 'Is qmake in your PATH?'
if iswindows: if iswindows:
optional.append(Extension('calibre.plugins.winutil', optional.append(Extension('calibre.plugins.winutil',
@ -90,7 +112,8 @@ if __name__ == '__main__':
poppler_inc = '/Volumes/sw/build/poppler-0.10.7/qt4/src' poppler_inc = '/Volumes/sw/build/poppler-0.10.7/qt4/src'
poppler_lib = '/Users/kovid/poppler/lib' poppler_lib = '/Users/kovid/poppler/lib'
poppler_inc = os.environ.get('POPPLER_INC_DIR', poppler_inc) poppler_inc = os.environ.get('POPPLER_INC_DIR', poppler_inc)
if os.path.exists(os.path.join(poppler_inc, 'poppler-qt4.h')): if os.path.exists(os.path.join(poppler_inc, 'poppler-qt4.h'))\
and qt_lib is not None and qt_inc is not None:
optional.append(Extension('calibre.plugins.calibre_poppler', optional.append(Extension('calibre.plugins.calibre_poppler',
sources=['src/calibre/utils/poppler/poppler.cpp'], sources=['src/calibre/utils/poppler/poppler.cpp'],
libraries=(['poppler', 'poppler-qt4']+poppler_libs), libraries=(['poppler', 'poppler-qt4']+poppler_libs),
@ -253,6 +276,7 @@ if __name__ == '__main__':
if 'develop' in ' '.join(sys.argv) and islinux: if 'develop' in ' '.join(sys.argv) and islinux:
subprocess.check_call('calibre_postinstall --do-not-reload-udev-hal', shell=True) subprocess.check_call('calibre_postinstall --do-not-reload-udev-hal', shell=True)
setup_mount_helper()
if 'install' in sys.argv and islinux: if 'install' in sys.argv and islinux:
subprocess.check_call('calibre_postinstall', shell=True) subprocess.check_call('calibre_postinstall', shell=True)
setup_mount_helper()

View File

@ -0,0 +1,141 @@
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <fcntl.h>
#define MARKER ".created_by_calibre_mount_helper"
int exists(char *path) {
struct stat file_info;
if (stat(path, &file_info) == 0) return 1;
return 0;
}
int get_root() {
int res;
res = setreuid(0, 0);
if (res != 0) return 1;
if (setregid(0, 0) != 0) return 1;
return 0;
}
int do_mount(char *dev, char *mp) {
char options[1000];
char marker[2000];
if (exists(dev) == 0) {
fprintf(stderr, "Specified device node does not exist\n");
return EXIT_FAILURE;
}
if (exists(mp) == 0) {
if (mkdir(mp, S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH) != 0) {
int errsv = errno;
fprintf(stderr, "Failed to create mount point with error: %s\n", strerror(errsv));
}
}
strncat(marker, mp, strlen(mp));
strncat(marker, "/", 1);
strncat(marker, MARKER, strlen(MARKER));
if (exists(marker) == 0) {
int fd = creat(marker, S_IRUSR|S_IWUSR);
if (fd == -1) {
int errsv = errno;
fprintf(stderr, "Failed to create marker with error: %s\n", strerror(errsv));
return EXIT_FAILURE;
}
close(fd);
}
snprintf(options, 1000, "rw,noexec,nosuid,sync,nodev,quiet,shortname=mixed,uid=%d,gid=%d,umask=077,fmask=0177,dmask=0077,utf8,iocharset=iso8859-1", getuid(), getgid());
if (get_root() != 0) {
fprintf(stderr, "Failed to elevate to root privileges\n");
return EXIT_FAILURE;
}
execlp("mount", "mount", "-t", "vfat", "-o", options, dev, mp, NULL);
int errsv = errno;
fprintf(stderr, "Failed to mount with error: %s\n", strerror(errsv));
return EXIT_FAILURE;
}
int do_eject(char *dev, char*mp) {
char marker[2000];
int status = EXIT_FAILURE, ret;
if (get_root() != 0) {
fprintf(stderr, "Failed to elevate to root privileges\n");
return EXIT_FAILURE;
}
int pid = fork();
if (pid == -1) {
fprintf(stderr, "Failed to fork\n");
return EXIT_FAILURE;
}
if (pid == 0) {
if (get_root() != 0) {
fprintf(stderr, "Failed to elevate to root privileges\n");
return EXIT_FAILURE;
}
execlp("eject", "eject", "-s", dev, NULL);
int errsv = errno;
fprintf(stderr, "Failed to eject with error: %s\n", strerror(errsv));
return EXIT_FAILURE;
} else {
int i;
for (i =0; i < 7; i++) {
sleep(1);
ret = waitpid(pid, &status, WNOHANG);
if (ret == -1) return EXIT_FAILURE;
if (ret > 0) break;
}
if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
strncat(marker, mp, strlen(mp));
strncat(marker, "/", 1);
strncat(marker, MARKER, strlen(MARKER));
if (exists(marker)) {
int urt = unlink(marker);
if (urt == -1) {
fprintf(stderr, "Failed to unlink marker: %s\n", strerror(errno));
return EXIT_FAILURE;
}
int rmd = rmdir(mp);
if (rmd == -1) {
fprintf(stderr, "Failed to remove mount point: %s\n", strerror(errno));
return EXIT_FAILURE;
}
}
}
}
return EXIT_SUCCESS;
}
int main(int argc, char** argv)
{
char *action, *dev, *mp;
/*printf("Real UID\t= %d\n", getuid());
printf("Effective UID\t= %d\n", geteuid());
printf("Real GID\t= %d\n", getgid());
printf("Effective GID\t= %d\n", getegid());*/
if (argc != 4) {
fprintf(stderr, "Needs 3 arguments: action, device node and mount point\n");
return EXIT_FAILURE;
}
action = argv[1]; dev = argv[2]; mp = argv[3];
if (strncmp(action, "mount", 5) == 0) {
return do_mount(dev, mp);
}
else if (strncmp(action, "eject", 7) == 0) {
return do_eject(dev, mp);
} else {
fprintf(stderr, "Unrecognized action: must be mount or eject\n");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}

View File

@ -17,7 +17,6 @@ import time
import re import re
import sys import sys
import glob import glob
import shutil
from itertools import repeat from itertools import repeat
from math import ceil from math import ceil
@ -489,7 +488,7 @@ class Device(DeviceConfig, DevicePlugin):
label = self.STORAGE_CARD_VOLUME_LABEL label = self.STORAGE_CARD_VOLUME_LABEL
if type == 'cardb': if type == 'cardb':
label = self.STORAGE_CARD2_VOLUME_LABEL label = self.STORAGE_CARD2_VOLUME_LABEL
if label is None: if not label:
label = self.STORAGE_CARD_VOLUME_LABEL + ' 2' label = self.STORAGE_CARD_VOLUME_LABEL + ' 2'
extra = 0 extra = 0
while True: while True:
@ -501,11 +500,15 @@ class Device(DeviceConfig, DevicePlugin):
label += ' (%d)'%extra label += ' (%d)'%extra
def do_mount(node, label): def do_mount(node, label):
cmd = ['pmount', '-w', '-s'] cmd = 'calibre-mount-helper'
if getattr(sys, 'frozen_path', False):
cmd = os.path.join(sys.frozen_path, cmd)
cmd = [cmd, 'mount']
try: try:
p = subprocess.Popen(cmd + [node, label]) p = subprocess.Popen(cmd + [node, '/media/'+label])
except OSError: except OSError:
raise DeviceError(_('You must install the pmount package.')) raise DeviceError(
_('Could not find mount helper: %s.')%cmd[0])
while p.poll() is None: while p.poll() is None:
time.sleep(0.1) time.sleep(0.1)
return p.returncode return p.returncode
@ -520,11 +523,13 @@ 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__)
self._linux_mount_map = {}
mp, ret = mount(main, 'main') mp, ret = mount(main, 'main')
if mp is None: if mp is None:
raise DeviceError( raise DeviceError(
_('Unable to mount main memory (Error code: %d)')%ret) _('Unable to mount main memory (Error code: %d)')%ret)
if not mp.endswith('/'): mp += '/' if not mp.endswith('/'): mp += '/'
self._linux_mount_map[main] = mp
self._main_prefix = mp self._main_prefix = mp
cards = [(carda, '_card_a_prefix', 'carda'), cards = [(carda, '_card_a_prefix', 'carda'),
(cardb, '_card_b_prefix', 'cardb')] (cardb, '_card_b_prefix', 'cardb')]
@ -536,6 +541,7 @@ class Device(DeviceConfig, DevicePlugin):
else: else:
if not mp.endswith('/'): mp += '/' if not mp.endswith('/'): mp += '/'
setattr(self, prefix, mp) setattr(self, prefix, mp)
self._linux_mount_map[card] = mp
def open(self): def open(self):
time.sleep(5) time.sleep(5)
@ -595,27 +601,16 @@ class Device(DeviceConfig, DevicePlugin):
success = False success = False
for drive in drives: for drive in drives:
if drive: if drive:
cmd = ['pumount', '-l'] cmd = 'calibre-mount-helper'
if getattr(sys, 'frozen_path', False):
cmd = os.path.join(sys.frozen_path, cmd)
cmd = [cmd, 'eject']
mp = getattr(self, "_linux_mount_map", {}).get(drive,
'dummy/')[:-1]
try: try:
p = subprocess.Popen(cmd + [drive]) subprocess.Popen(cmd + [drive, mp]).wait()
except: except:
pass pass
while p.poll() is None:
time.sleep(0.1)
success = success or p.returncode == 0
try:
subprocess.Popen(['sudo', 'eject', drive])
except:
pass
for x in ('_main_prefix', '_card_a_prefix', '_card_b_prefix'):
x = getattr(self, x, None)
if x is not None:
if x.startswith('/media/') and os.path.exists(x) \
and not os.listdir(x):
try:
shutil.rmtree(x)
except:
pass
def eject(self): def eject(self):
if islinux: if islinux:

View File

@ -153,7 +153,7 @@ def do_list(db, fields, sort_by, ascending, search_text, line_width, separator,
break break
widths = list(base_widths) widths = list(base_widths)
titles = map(lambda x, y: '%-*s'%(x, y), widths, fields) titles = map(lambda x, y: '%-*s%s'%(x-len(separator), y, separator), widths, fields)
print terminal_controller.GREEN + ''.join(titles)+terminal_controller.NORMAL print terminal_controller.GREEN + ''.join(titles)+terminal_controller.NORMAL
wrappers = map(lambda x: TextWrapper(x-1), widths) wrappers = map(lambda x: TextWrapper(x-1), widths)

View File

@ -21,7 +21,6 @@ DEPENDENCIES = [
('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'), ('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'),
('poppler-qt4', '0.10.6', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4'), ('poppler-qt4', '0.10.6', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4'),
('podofo', '0.7', 'podofo', 'podofo', 'podofo', 'podofo'), ('podofo', '0.7', 'podofo', 'podofo', 'podofo', 'podofo'),
('pmount', '0.9.19', 'pmount', 'pmount', 'pmount', 'pmount'),
] ]
@ -385,6 +384,15 @@ else:
print 'Extracting files to %s ...'%destdir print 'Extracting files to %s ...'%destdir
extract_tarball(f, destdir) extract_tarball(f, destdir)
mh = os.path.join(destdir, 'calibre-mount-helper')
if os.geteuid() == 0:
os.chown(mh, 0, 0)
os.chmod(mh,
stat.S_ISUID|stat.S_ISGID|stat.S_IRUSR|stat.S_IWUSR|stat.S_IXUSR|stat.S_IXGRP|stat.S_IXOTH)
else:
print 'WARNING: Not running as root. Cannot install mount helper.',
print 'Device automounting may not work.'
pi = os.path.join(destdir, 'calibre_postinstall') pi = os.path.join(destdir, 'calibre_postinstall')
subprocess.call(pi, shell=True) subprocess.call(pi, shell=True)
return 0 return 0