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 = [
'/usr/bin/pdftohtml',
'/usr/bin/calibre-mount-helper',
'/usr/lib/libunrar.so',
'/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']],
}
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__':
from setuptools import setup, find_packages
from pyqtdistutils import PyQtExtension, build_ext, Extension
@ -68,7 +86,11 @@ if __name__ == '__main__':
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 = 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:
optional.append(Extension('calibre.plugins.winutil',
sources=['src/calibre/utils/windows/winutil.c'],
@ -90,7 +112,8 @@ if __name__ == '__main__':
poppler_inc = '/Volumes/sw/build/poppler-0.10.7/qt4/src'
poppler_lib = '/Users/kovid/poppler/lib'
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',
sources=['src/calibre/utils/poppler/poppler.cpp'],
libraries=(['poppler', 'poppler-qt4']+poppler_libs),
@ -253,6 +276,7 @@ if __name__ == '__main__':
if 'develop' in ' '.join(sys.argv) and islinux:
subprocess.check_call('calibre_postinstall --do-not-reload-udev-hal', shell=True)
setup_mount_helper()
if 'install' in sys.argv and islinux:
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 sys
import glob
import shutil
from itertools import repeat
from math import ceil
@ -489,7 +488,7 @@ class Device(DeviceConfig, DevicePlugin):
label = self.STORAGE_CARD_VOLUME_LABEL
if type == 'cardb':
label = self.STORAGE_CARD2_VOLUME_LABEL
if label is None:
if not label:
label = self.STORAGE_CARD_VOLUME_LABEL + ' 2'
extra = 0
while True:
@ -501,11 +500,15 @@ class Device(DeviceConfig, DevicePlugin):
label += ' (%d)'%extra
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:
p = subprocess.Popen(cmd + [node, label])
p = subprocess.Popen(cmd + [node, '/media/'+label])
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:
time.sleep(0.1)
return p.returncode
@ -520,11 +523,13 @@ class Device(DeviceConfig, DevicePlugin):
raise DeviceError(_('Unable to detect the %s disk drive.')
%self.__class__.__name__)
self._linux_mount_map = {}
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._linux_mount_map[main] = mp
self._main_prefix = mp
cards = [(carda, '_card_a_prefix', 'carda'),
(cardb, '_card_b_prefix', 'cardb')]
@ -536,6 +541,7 @@ class Device(DeviceConfig, DevicePlugin):
else:
if not mp.endswith('/'): mp += '/'
setattr(self, prefix, mp)
self._linux_mount_map[card] = mp
def open(self):
time.sleep(5)
@ -595,27 +601,16 @@ class Device(DeviceConfig, DevicePlugin):
success = False
for drive in drives:
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:
p = subprocess.Popen(cmd + [drive])
subprocess.Popen(cmd + [drive, mp]).wait()
except:
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):
if islinux:

View File

@ -153,7 +153,7 @@ def do_list(db, fields, sort_by, ascending, search_text, line_width, separator,
break
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
wrappers = map(lambda x: TextWrapper(x-1), widths)

View File

@ -21,7 +21,6 @@ DEPENDENCIES = [
('dnspython', '1.6.0', 'dnspython', 'dnspython', 'dnspython', 'dnspython'),
('poppler-qt4', '0.10.6', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4', 'poppler-qt4'),
('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
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')
subprocess.call(pi, shell=True)
return 0