ltspfs-1.4/0000755000175000017500000000000012374427412012565 5ustar vagrantvagrantltspfs-1.4/ChangeLog0000644000175000017500000004640112374427412014344 0ustar vagrantvagrant 178 Vagrant Cascadian 2014-08-18 {ltspfs-1.4} ltspfs version 1.4 177 Vagrant Cascadian 2014-08-18 Add support for starting ltspfsd from systemd service file when systemd is running. 176 Vagrant Cascadian 2014-08-16 ltspfs_entry: Don't re-add when the device is already in ltspfs_fstab. 175 Alkis Georgopoulos 2014-08-15 Fix compile-time warnings introduced by patch to fix size reporting issues. https://bugs.launchpad.net/ubuntu/+source/ltspfs/+bug/1021579 174 Vagrant Cascadian 2014-08-15 Mount ltspfs filesystem directly to /media/username/mountpoint: - lbmount: Only handle creation/deletion of /media/username and /media/username/* dirs. - ltspfsmounter: Use lbmount to create dirs in /media, and mount directly to /media. https://bugs.debian.org/758090 173 Vagrant Cascadian 2014-08-14 Work around compatibility issues with systemd: - lbmount: Use "mount --bind" instead of "mount --move" - ltspfsmounter: Unmount the temporary /tmp mountpoints after bind mounting into /media. https://bugs.debian.org/758090 172 Vagrant Cascadian 2014-08-14 Remove empty ChangeLog, create in autogen.sh. 171 Vagrant Cascadian 2014-08-13 lbmount: Fix typo in setuid error: progarm -> program 170 Vagrant Cascadian 2014-08-13 Fix filesystem size calculations. Thanks to datube for the initial patch! https://bugs.launchpad.net/ubuntu/+source/ltspfs/+bug/1021579 169 Vagrant Cascadian 2013-12-29 {ltspfs-1.3} ltspfs version 1.3 168 Vagrant Cascadian 2013-12-29 Enable all udev rules. Distros may need to ship their own rules if these are incompatible. 167 Alkis Georgopoulos 2013-12-29 Simplify some code and avoid `pgrep -l -f` as it changed behavior. 166 Vagrant Cascadian 2013-12-25 ltspfs_entry: Require FSTYPE to be set for CDs as well as other media, which was only needed with cdpinger when there was no media. 165 Alkis Georgopoulos 2013-12-24 Add empty ChangeLog for launchpad daily build recipes. 164 Vagrant Cascadian 2013-12-23 configure.ac: Remove linux/cdrom.h from AC_CHECK_HEADERS, as it was only needed by cdpinger. 163 Vagrant Cascadian 2013-12-23 Remove cdpinger manpage. 162 Vagrant Cascadian 2013-12-23 {ltspfs-1.2} ltspfs version 1.2 161 Vagrant Cascadian 2013-12-23 Drop support for cdpinger, relying on udev rules instead. 160 Vagrant Cascadian 2013-11-25 Move init-ltsp.d hooks into the proper place. 159 Vagrant Cascadian 2013-11-25 Build ltspfs with -pthread to fix build failure. Patch from Matthias Klose: https://launchpadlibrarian.net/135897483/ltspfs_1.1-2build1_1.1-2ubuntu1.diff.gz 158 Vagrant Cascadian 2012-02-24 {ltspfs-1.1} version 1.1 157 Vagrant Cascadian 2012-02-24 Add symlinks for Debian/Ubuntu for ltspfsd.rules creation in init-ltsp.d. 156 Vagrant Cascadian 2012-02-24 Use init-ltsp.d hook for installing udev rules at boot. 155 Vagrant Cascadian 2012-02-24 Rename udev rules to ltspfsd.rules, and move them into /usr/share/ltspfs/udev, which allows for installing rules at boot. 154 vagrant@freegeek.org 2011-10-28 {ltspfs-1.0} version 1.0 153 vagrant@freegeek.org 2011-10-28 [merge] merge patch from Scott Balneaves to fix 64 bit issues. 152 Stéphane Graber 2011-08-11 {ltspfs-0.9} version 0.9 151 Stéphane Graber 2011-07-22 Launchpad: no change commit to trigger a test rebuild 150 Stéphane Graber 2011-07-07 ID_FS_LABEL is now usually 'safe'. Patch from gcc (LP: #690969) 149 Warren Togami 2011-06-16 {ltspfs-0.8} version 0.8 148 Vagrant Cascadian 2011-02-05 cdpinger: add support for UDF formatted CDs and DVDs. 147 Stéphane Graber 2010-08-08 {ltspfs-0.7} Release 0.7 146 Vagrant Cascadian 2010-06-25 init with "ltspfs" rather than simply "test". 145 Vagrant Cascadian 2010-06-25 Add example ltspfs mounted hook to issue notifications for desktops that do not display icons. Thanks to Petter Reinholdtsen. http://bugs.debian.org/575031 144 Gideon Romm 2010-05-11 Remove commented-out code. 143 Gideon Romm 2010-05-11 Fix cdrom handling. 142 Stéphane Graber 2010-02-17 {ltspfs-0.6} version 0.6 141 Stéphane Graber 2010-02-17 Try umounting with -l to avoid some issues 140 Scott Balneaves 2010-02-17 Change owner of dir in /media to user, with group of root 139 Scott Balneaves 2010-02-17 Top level media directory being created mode 750. Changed to 700 138 Gideon Romm 2010-02-10 Be careful to actually have a pid before executing kill 137 Gideon Romm 2010-02-10 Do not sed -i a file that we are reading in from stdin 136 Vagrant Cascadian 2010-02-10 allow CDs to have an empty filesystem, as they're likely to have a device but no disk inserted. this allows cdpinger to run again. 135 Vagrant Cascadian 2010-02-10 cdpinger: report syslog messages for "disk detected" and "tray open" messages only when the state changes so they are not reported every 3 seconds. 134 Gideon Romm 2010-02-10 Fix MODE setting to include add_disc annd remove_disc 133 Gideon Romm 2010-02-10 Pass DEVICENAME to add_cdrom_device and remove_cdrom_device functions 132 Gideon Romm 2010-02-10 Make sure ltspfsd gets launched 131 Gideon Romm 2010-02-10 Refactor ltspfs_entry and cdpinger code to better handle CDROMs 130 Gideon Romm 2010-02-10 Remove cdpinger pid file when cdrom is removed, since apparently cdpinger will commit suicide on its own upon device removal and we would like cdpinger to start up again upon reinsertion of the cdrom drive. 129 Gideon Romm 2010-02-09 Try to avoid multiple parallel calls to pgrep by writing a pid file to check first. If the pid file exists, it shell should not need to use pgrep in the conditional 128 Gideon Romm 2010-02-01 Make delayed-mounter work for LDM localapps 127 Scott Balneaves 2010-01-30 Added syslogging. 126 Gideon Romm 2010-01-29 Some more optimizations to use shell primitives where possible 125 Vagrant Cascadian 2010-01-29 fix call_cdpinger function to use exact matching so that "cdrom" doesn't match "cdrom1". thanks gadi! 124 Gideon Romm 2010-01-27 Fix up noauth stuff and make local devices work for localapps, rdesktop, and kiosk scripts. 123 Scott Balneaves 2010-01-27 Changed noauth mode: ltspfs now recognizes LTSPFS_NOAUTH env var, and if set, skips auth. ltspfsd now skips receiving auth packet if noauth set. 122 Stéphane Graber 2010-01-13 {ltspfs-0.5.14} release ltspfs 0.5.14 121 Stéphane Graber 2010-01-13 Fix cases where the user used for login doesn't match the case of the remote user 120 Scott Balneaves 2010-01-12 Files are now user-owned only 119 Marc Gariepy 2009-12-15 fixing local lowercase username (ldap ltsp-trunk -r 1265) 118 Vagrant Cascadian 2009-07-17 {ltspfs-0.5.13} release ltspfs 0.5.13 117 Vagrant Cascadian 2009-07-17 drop delayedmounter from xinitrc.d, as udev scripts should be sufficient now. 116 Vagrant Cascadian 2009-07-06 relocate delayed-mounter ldm hooks so they run after the user is added to /etc/passwd, and before the user is removed from /etc/passwd. 115 Vagrant Cascadian 2009-07-06 - always run as root, so mounts appear in /media/root - only run mount for localapps if user's home dir is mounted via sshfs 114 Vagrant Cascadian 2009-07-06 check for ldm-xauth in /var/run, and support newer ldm, with Xauthority in a sub-dir. 113 Vagrant Cascadian 2009-06-21 fix spelling of "Received" in ltspfsd 112 Stéphane Graber 2009-06-03 {ltspfs-0.5.12} version 0.5.12 111 Francis Giraldeau 2009-05-27 remove ltspfs_fstab entry before unmounting device, to prevent other processes from mounting it. https://bugs.launchpad.net/ubuntu/+source/ltspfsd/+bug/378495 110 Vagrant Cascadian 2009-04-03 {ltspfs-0.5.11} version 0.5.11 109 Vagrant Cascadian 2009-04-03 simplify code to handle when mountpoint is already mounted 108 Gideon Romm 2009-03-11 Make sure delayed_mounter sets USER=root for local ltspfsmounting 107 Gideon Romm 2009-03-10 Do not remove ltspfs mount on "already mounted" errors, as these errors may occur silently with multiple ltspfsmounters 106 Stéphane Graber 2009-03-09 {ltspfs-0.5.10} version 0.5.10 105 Stéphane Graber 2009-03-08 Whitespace and include Gadi's patch to ltspfs_entry where udev's environment contains spaces 104 Vagrant Cascadian 2009-03-06 updated copyright/license headers for src/*.c 103 Stéphane Graber 2009-03-05 Avoid exporting a variable that'll contain spaces at least in Ubuntu and make the export and ltspfs to fail 102 Gideon Romm 2009-02-26 Some more local ltspfsmounter fun 101 Gideon Romm 2009-02-26 Add support for local ltspfsmounter mounted by user for local apps. 100 Stéphane Graber 2009-02-18 {ltspfs-0.5.9} version 0.5.9 99 Stéphane Graber 2009-02-18 Fix indent in ltspfsmounter 98 Gideon Romm 2009-02-17 Do not remove the ltspfs mount on failed local mount if failure is because the mountpoint is already mounted. Want to make sure that two ltspfsmounters do not inadvertantly cause the ltspfsmount to be removed 97 Vagrant Cascadian 2009-01-23 minor typo: fix comment to match code 96 Vagrant Cascadian 2009-01-23 typo: add missing ;; to case statement when setting utf8 filesystems 95 Vagrant Cascadian 2009-01-23 get USER environment variable only once 94 Gideon Romm 2009-01-21 Explicitly exporting USER=root to make all these scripts happy. 93 Gideon Romm 2009-01-21 Fix the cleanup. 92 Gideon Romm 2009-01-21 Fix the cleanup. 91 Gideon Romm 2009-01-19 set USER=root in environment of ltspfsmounter if not set. 90 Gideon Romm 2009-01-19 And it is all cleanup, not cleanup all. 89 Gideon Romm 2009-01-19 SSH_CONNECTION should be unset 88 Gideon Romm 2009-01-19 ltspfs_fstab is a file not a directory! Thank, vagrantc 87 Vagrant Cascadian 2009-01-19 add udev rules for floppy drives and updated comments 86 Vagrant Cascadian 2009-01-19 call ltspfs_entry remove without doing a manual basename of the device, ltspfs_entry handles that itself. 85 Vagrant Cascadian 2009-01-19 use a case statement to check if it is a floppy device 84 Gideon Romm 2009-01-18 Do not remove ltspfs mount on failed mount if device is a floppy drive. 83 Gideon Romm 2009-01-18 Change filesystem mount in cdpinger from auto to iso9660. This, combined with rev78 should fix LP Bug #164508 - Non-Latin Letters in Filenames Appear As Question Marks. 82 Gideon Romm 2009-01-18 Call ltspfs_entry remove if we fail to mount the device, so we don't end up with an ltspfsmount to tmpfs. LP Bug #307174 81 Gideon Romm 2009-01-18 Handle two devices with same label (such as inserting two identically labeled USB sticks). 80 Gideon Romm 2009-01-18 Some other code need not run if ltspfsmounter is not installed locally. 79 Gideon Romm 2009-01-18 [merge] PACKAGING: Merge changes to run ltspfsmounter locally for non-LDM sessions. Make note of xinitrc.d directory and scripts for packaging 78 Gideon Romm 2008-12-20 Add LOCALDEV_MOUNT_OPTIONS parameter to adjust the default mount options from local devices. Also, add default support for utf8 (international) character filenames if the local device is vfat, iso9660, or ntfs 77 Warren Togami 2008-12-11 {ltspfs-0.5.8} version 0.5.8 76 Warren Togami 2008-12-11 Not sure why that is there... 75 Warren Togami 2008-12-11 Error out if autogen.sh fails. 74 Vagrant Cascadian 2008-12-03 ensure that the ltspfs authentication token exists even when ltspfsd hasn't started yet, so that devices plugged in later will still be able to mount. 73 Vagrant Cascadian 2008-12-03 {ltspfs-0.5.7} version 0.5.7 72 Vagrant Cascadian 2008-12-03 rename LOCALDEV_DENY_INTERNAL_DISK to LOCALDEV_DENY_INTERNAL_DISKS 71 Gideon Romm 2008-12-03 Fix bug in LOCALDEV_DENY 70 Vagrant Cascadian 2008-11-20 {ltspfs-0.5.6} version 0.5.6 69 Vagrant Cascadian 2008-11-19 explicitly specify "void" for functions that take no arguments. thanks to Petter Reinholdtsen. 68 Vagrant Cascadian 2008-11-17 default to LOCALDEV_DENY_INTERNAL_DISKS=True 67 Vagrant Cascadian 2008-11-17 [merge] merge LOCALDEV_DENY patches (thanks Gadi!) 66 Stéphane Graber 2008-10-11 {ltspfs-0.5.5} version 0.5.5 65 Stéphane Graber 2008-10-10 [merge] Merge Scott's code to fix the segfault in cdpinger 64 Warren Togami 2008-09-11 {ltspfs-0.5.4} version 0.5.4 63 Vagrant Cascadian 2008-08-25 added manpages for ltspfs_mount and ltspfs_umount 62 Vagrant Cascadian 2008-08-25 added manpage for cdpinger 61 Vagrant Cascadian 2008-06-26 {ltspfs-0.5.3} version 0.5.3 60 Vagrant Cascadian 2008-06-25 add code to start cdpinger from ltspfs_entry 59 Vagrant Cascadian 2008-06-25 - start ltspfsd if not already running - create ltspfs_token if not present 58 Vagrant Cascadian 2008-06-25 respect LOCALDEV setting: - source ltspfsd.conf - source LTSP configuration (ltsp_config) 57 Vagrant Cascadian 2008-06-16 - handle both floppy and cdroms - only use ID_FS_LABEL_SAFE if not yet set 56 Vagrant Cascadian 2008-06-16 don't mount swap partitions 55 Warren Togami 2008-04-28 {ltspfs-0.5.2} version 0.5.2 54 Warren Togami 2008-04-28 /media/$username created as 0750 instead of 0755. This is functionally equivalent because fuse was preventing other users from going in there anyway. vagrantc + warren analysis: 0700 doesn't work because the non-root user still has to access inside. 0770 is undesirable because we don't want the non-root user to be able to write arbitrary things in there. (/media/$username is owned by root and managed by lbmount, while mounts inside that are owned by the user.) 0750 is thus desirable by process of elimination. 53 Vagrant Cascadian 2008-04-28 [merge] switch *_fstab_entry to ltspfs_entry, called by udev and cdpinger 52 Vagrant Cascadian 2008-04-19 {ltspfs-0.5.1} version 0.5.1 51 Vagrant Cascadian 2008-04-19 patch from Oliver Grawert to fix local devices with ldm directx enabled http://launchpadlibrarian.net/13544575/udev-scripts-security-regression.dpatch 50 Warren Togami 2008-03-26 Remove empty Changelog and generate it automatically from bzr log. 49 Warren Togami 2008-03-26 {ltspfs-0.5.0} version 0.5.0 48 Vagrant Cascadian 2008-03-18 ensure that all devices get mounted (not just the first device) - note: not sure why this works, but it does. 47 Warren Togami 2008-03-13 .bzrignore mkdst related stuff 46 Warren Togami 2008-03-13 Remove ltspfs.spec and mkdst wrapper 45 Warren Togami 2008-03-10 Fedora: spec fixes 44 Warren Togami 2008-03-10 Fedora: Include spec fixes suggested by Fedora package review 43 Vagrant Cascadian 2008-03-02 mark kde-desktop-icons executable. 42 Vagrant Cascadian 2008-03-02 when mode is cleanup, don't bother to parse additional arguments 41 Vagrant Cascadian 2008-03-02 only call run_hooks for cleanup once 40 Vagrant Cascadian 2008-03-02 [merge] add example hook script to add icons on KDE desktops. - thanks to Klaus Ade Johnstad, http://bugs.debian.org/459369 39 Vagrant Cascadian 2008-03-02 [merge] only allow hooks with filenames that contain only alphanumeric, hypens or underscores. 38 Vagrant Cascadian 2008-03-02 [merge] merge patches to implement hook scripts for ltspfsmounter 37 Vagrant Cascadian 2008-02-26 use /sbin/udevadm if present, falling back to udevinfo for backwards compatibility 36 Warren Togami 2008-01-14 Example spec: add necessary build requires 35 Warren Togami 2008-01-14 homepage moved 34 Warren Togami 2008-01-13 Add example RPM spec file 33 Warren Togami 2008-01-13 Do not run anything as an explicit username, especially root. RPM packages build as non-root. 32 Warren Togami 2008-01-13 make release.conf better 31 Warren Togami 2008-01-13 add release.conf required by mkdst 30 Vagrant Cascadian 2008-01-09 [merge] merge otavio's ldm-hooks branch 29 Vagrant Cascadian 2008-01-07 [merge] merge patches to use "mount --move" instead of "mount --bind", so that only a single mountpoint appears. 28 Vagrant Cascadian 2007-12-13 [merge] merge python way to test if /dev/fuse is writeable 27 Vagrant Cascadian 2007-12-04 exit if /dev/fuse is not writeable 26 Vagrant Cascadian 2007-12-03 put cdpinger back in /usr/sbin 25 Vagrant Cascadian 2007-12-03 drop cdpinger from scripts Makefile (now in src Makefile) 24 Vagrant Cascadian 2007-12-03 only import call from subprocess, as other subprocess code is not used. 23 Vagrant Cascadian 2007-12-03 add new mkdst wrapper 22 Scott Balneaves 2007-11-16 Fixed localdev bug 21 Scott Balneaves 2007-11-15 New upstream layout 20 Scott Balneaves 2007-11-04 Makefile fixups 19 Scott Balneaves 2007-11-04 Fixed up makefile 18 Scott Balneaves 2007-11-04 Makefile mods 17 Scott Balneaves 2007-11-04 Added example makefile 16 Scott Balneaves 2007-11-04 Added root-level Makefile 15 Scott Balneaves 2007-11-04 Upstream version work. 14 Scott Balneaves 2007-11-04 Merged in C version of cdpinger 13 Scott Balneaves 2007-11-03 Added C version of cdpinger 12 Scott Balneaves 2007-09-17 fixed some bugs, more exception handling 11 Scott Balneaves 2007-09-17 Man, how did I loose that? 10 Scott Balneaves 2007-09-02 [merge] Work in ltspfs-nodm now considered prime-time. Merged 9 Scott Balneaves 2007-06-14 Moved fstab operations to /var/run/ltspfs_fstab, and /tmp/.ltspfs-socket to /var/run/ldm_socket 8 Scott Balneaves 2007-06-14 [merge] Merged vagrantc's changes 7 Scott Balneaves 2007-06-14 fixed up ltspfs bug where mutex wasn't being released. Thanks to Veli-Matti Lintu for the fix 6 Scott Balneaves 2006-09-18 Fixed floppy problems. 5 Scott Balneaves 2006-09-18 Bumped to 0.4.1 4 Scott Balneaves 2006-09-18 Fixed several minor pathing problems, plus a null pointer check for getenv(DISPLAY) 3 Scott Balneaves 2006-09-17 Removed install setuid (should be handled by packagers), added authors 2 Scott Balneaves 2006-09-16 Forgot ltspfsd_functions.h in the src/Makefile.am 1 Scott Balneaves 2006-09-16 Initial creation of proper 'Upstream' LtspFS package Use --include-merged or -n0 to see merged revisions. ltspfs-1.4/release.conf0000644000175000017500000000035712374427411015060 0ustar vagrantvagrantNAME=$(cat configure.ac | grep ^AC_INIT | sed -e "s/.*(//;s/\[//g;s/\]//g;s/ //g;" |awk -F, '{ print $1 }') VERSION=$(cat configure.ac | grep ^AC_INIT | sed -e "s/.*(//;s/\[//g;s/\]//g;s/ //g;" |awk -F, '{ print $2 }') EXPORTCHANGELOG=yes ltspfs-1.4/Makefile.am0000644000175000017500000000006712374427411014623 0ustar vagrantvagrantEXTRA_DIST = autogen.sh SUBDIRS = src man scripts udev ltspfs-1.4/INSTALL0000644000175000017500000002243212374427411013620 0ustar vagrantvagrantInstallation Instructions ************************* Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005 Free Software Foundation, Inc. This file is free documentation; the Free Software Foundation gives unlimited permission to copy, distribute and modify it. Basic Installation ================== These are generic installation instructions. The `configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, and a file `config.log' containing compiler output (useful mainly for debugging `configure'). It can also use an optional file (typically called `config.cache' and enabled with `--cache-file=config.cache' or simply `-C') that saves the results of its tests to speed up reconfiguring. (Caching is disabled by default to prevent problems with accidental use of stale cache files.) If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If you are using the cache, and at some point `config.cache' contains results you don't want to keep, you may remove or edit it. The file `configure.ac' (or `configure.in') is used to create `configure' by a program called `autoconf'. You only need `configure.ac' if you want to change it or regenerate `configure' using a newer version of `autoconf'. The simplest way to compile this package is: 1. `cd' to the directory containing the package's source code and type `./configure' to configure the package for your system. If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself. Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for. 2. Type `make' to compile the package. 3. Optionally, type `make check' to run any self-tests that come with the package. 4. Type `make install' to install the programs and any data files and documentation. 5. You can remove the program binaries and object files from the source code directory by typing `make clean'. To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a `make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution. Compilers and Options ===================== Some systems require unusual options for compilation or linking that the `configure' script does not know about. Run `./configure --help' for details on some of the pertinent environment variables. You can give `configure' initial values for configuration parameters by setting variables in the command line or in the environment. Here is an example: ./configure CC=c89 CFLAGS=-O2 LIBS=-lposix *Note Defining Variables::, for more details. Compiling For Multiple Architectures ==================================== You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'. If you have to use a `make' that does not support the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture. Installation Names ================== By default, `make install' installs the package's commands under `/usr/local/bin', include files under `/usr/local/include', etc. You can specify an installation prefix other than `/usr/local' by giving `configure' the option `--prefix=PREFIX'. You can specify separate installation prefixes for architecture-specific files and architecture-independent files. If you pass the option `--exec-prefix=PREFIX' to `configure', the package uses PREFIX as the prefix for installing programs and libraries. Documentation and other data files still use the regular prefix. In addition, if you use an unusual directory layout you can give options like `--bindir=DIR' to specify different values for particular kinds of files. Run `configure --help' for a list of the directories you can set and what kinds of files go in them. If the package supports it, you can cause programs to be installed with an extra prefix or suffix on their names by giving `configure' the option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. Optional Features ================= Some packages pay attention to `--enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `--with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `--enable-' and `--with-' options that the package recognizes. For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `--x-includes=DIR' and `--x-libraries=DIR' to specify their locations. Specifying the System Type ========================== There may be some features `configure' cannot figure out automatically, but needs to determine by the type of machine the package will run on. Usually, assuming the package is built to be run on the _same_ architectures, `configure' can figure that out, but if it prints a message saying it cannot guess the machine type, give it the `--build=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name which has the form: CPU-COMPANY-SYSTEM where SYSTEM can have one of these forms: OS KERNEL-OS See the file `config.sub' for the possible values of each field. If `config.sub' isn't included in this package, then this package doesn't need to know the machine type. If you are _building_ compiler tools for cross-compiling, you should use the option `--target=TYPE' to select the type of system they will produce code for. If you want to _use_ a cross compiler, that generates code for a platform different from the build platform, you should specify the "host" platform (i.e., that on which the generated programs will eventually be run) with `--host=TYPE'. Sharing Defaults ================ If you want to set default values for `configure' scripts to share, you can create a site shell script called `config.site' that gives default values for variables like `CC', `cache_file', and `prefix'. `configure' looks for `PREFIX/share/config.site' if it exists, then `PREFIX/etc/config.site' if it exists. Or, you can set the `CONFIG_SITE' environment variable to the location of the site script. A warning: not all `configure' scripts look for a site script. Defining Variables ================== Variables not defined in a site shell script can be set in the environment passed to `configure'. However, some packages may run configure again during the build, and the customized values of these variables may be lost. In order to avoid this problem, you should set them in the `configure' command line, using `VAR=value'. For example: ./configure CC=/usr/local2/bin/gcc causes the specified `gcc' to be used as the C compiler (unless it is overridden in the site shell script). Here is a another example: /bin/bash ./configure CONFIG_SHELL=/bin/bash Here the `CONFIG_SHELL=/bin/bash' operand causes subsequent configuration-related scripts to be executed by `/bin/bash'. `configure' Invocation ====================== `configure' recognizes the following options to control how it operates. `--help' `-h' Print a summary of the options to `configure', and exit. `--version' `-V' Print the version of Autoconf used to generate the `configure' script, and exit. `--cache-file=FILE' Enable the cache: use and save the results of the tests in FILE, traditionally `config.cache'. FILE defaults to `/dev/null' to disable caching. `--config-cache' `-C' Alias for `--cache-file=config.cache'. `--quiet' `--silent' `-q' Do not print messages saying which checks are being made. To suppress all normal output, redirect it to `/dev/null' (any error messages will still be shown). `--srcdir=DIR' Look for the package's source code in directory DIR. Usually `configure' can determine that directory automatically. `configure' also accepts some other, not widely useful, options. Run `configure --help' for more details. ltspfs-1.4/COPYING0000644000175000017500000004312212374427411013621 0ustar vagrantvagrant GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License. ltspfs-1.4/configure.ac0000644000175000017500000000175112374427411015056 0ustar vagrantvagrantAC_PREREQ(2.59) AC_INIT(ltspfs, [1.4], [sbalneav@ltsp.org]) AC_CONFIG_SRCDIR([src/ltspfs.c]) AM_INIT_AUTOMAKE AM_CONFIG_HEADER([config.h]) AM_MAINTAINER_MODE # Checks for programs. AC_PROG_CC AM_PROG_CC_C_O AC_PROG_INSTALL # Checks for libraries. # Thanks, Ollie! # PKG_CHECK_MODULES(LTSPFSD, [x11]) PKG_CHECK_MODULES(LTSPFS, [fuse, x11]) # Checks for header files. AC_HEADER_STDC AC_HEADER_DIRENT AC_HEADER_SYS_WAIT AC_CHECK_HEADERS([fcntl.h],,AC_MSG_ERROR(Required header missing)) dnl Check for Packages if test -z "$UDEV_RULES_PATH"; then UDEV_RULES_PATH=/etc/udev/rules.d fi AC_SUBST(UDEV_RULES_PATH) if test -z "$UDEV_LIB_PATH"; then UDEV_LIB_PATH=/lib/udev fi AC_SUBST(UDEV_LIB_PATH) PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.6.0) PKG_CHECK_MODULES(GOBJECT, gobject-2.0 >= 2.6.0) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) AC_SUBST(GOBJECT_CFLAGS) AC_SUBST(GOBJECT_LIBS) dnl Output AC_CONFIG_FILES(Makefile src/Makefile man/Makefile scripts/Makefile udev/Makefile) AC_OUTPUT ltspfs-1.4/config.h.in0000644000175000017500000000117112374427411014607 0ustar vagrantvagrant/* config.h.in. Generated from configure.ac by autoheader. */ /* Name of package */ #undef PACKAGE /* Define to the address where bug reports for this package should be sent. */ #undef PACKAGE_BUGREPORT /* Define to the full name of this package. */ #undef PACKAGE_NAME /* Define to the full name and version of this package. */ #undef PACKAGE_STRING /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME /* Define to the version of this package. */ #undef PACKAGE_VERSION /* Define to 1 if you have the ANSI C header files. */ #undef STDC_HEADERS /* Version number of package */ #undef VERSION ltspfs-1.4/autogen.sh0000755000175000017500000000007712374427411014571 0ustar vagrantvagrant#!/bin/sh set -e touch ChangeLog aclocal autoconf automake -ac ltspfs-1.4/AUTHORS0000644000175000017500000000014212374427411013631 0ustar vagrantvagrantScott Balneaves ltspfs, lbmount Martin Pitt lbmount ltspfs-1.4/README0000644000175000017500000000000012374427411013432 0ustar vagrantvagrantltspfs-1.4/NEWS0000644000175000017500000000000012374427411013251 0ustar vagrantvagrantltspfs-1.4/README-DEVELOPMENT-POLICY0000644000175000017500000000000012374427411016207 0ustar vagrantvagrantltspfs-1.4/udev/0000755000175000017500000000000012374427411013527 5ustar vagrantvagrantltspfs-1.4/udev/Makefile.am0000644000175000017500000000041612374427411015564 0ustar vagrantvagrantEXTRA_DIST = ltspfsd.rules UDEV_RULES_PATH = /usr/share/ltspfs/udev/ install-data-local: $(mkdir_p) $(DESTDIR)$(UDEV_RULES_PATH) $(INSTALL_DATA) $(srcdir)/ltspfsd.rules $(DESTDIR)$(UDEV_RULES_PATH) uninstall-local: rm -f $(DESTDIR)$(UDEV_RULES_PATH)/ltspfsd.rules ltspfs-1.4/udev/ltspfsd.rules0000644000175000017500000000205212374427411016261 0ustar vagrantvagrant# udev rules for ltspfs, usually installed into: # /etc/udev/rules.d/ or /lib/udev/rules.d (for newer versions of udev) # legacy floppy drives: ACTION=="add", KERNEL=="fd[0-9]", RUN+="ltspfs_entry add %k auto" # USB floppy drives: ACTION=="add", SUBSYSTEM=="block", KERNEL!="fd[0-9]", ENV{ID_TYPE}=="floppy", ATTRS{removable}=="1", RUN+="ltspfs_entry add %k auto" # other drives: ACTION=="add", SUBSYSTEM=="block", ENV{ID_TYPE}!="floppy", RUN+="ltspfs_entry add %k" # device removals: ACTION=="remove", SUBSYSTEM=="block", RUN+="ltspfs_entry remove %k" # CD change events: # ensure polling events happen for CD and DVD devices, may be needed if distro # doesn't already support polling or change events. ACTION=="add", ENV{ID_TYPE}=="cd", ATTR{removable}=="1", ATTR{events_poll_msecs}=="-1", ATTR{events_poll_msecs}="2000" ACTION=="change", SUBSYSTEM=="block", ENV{ID_TYPE}=="cd", ENV{ID_CDROM_MEDIA}=="1", RUN+="ltspfs_entry add %k iso9660,udf" ACTION=="change", SUBSYSTEM=="block", ENV{ID_TYPE}=="cd", ENV{ID_CDROM_MEDIA}!="1", RUN+="ltspfs_entry remove %k " ltspfs-1.4/src/0000755000175000017500000000000012374427411013353 5ustar vagrantvagrantltspfs-1.4/src/Makefile.am0000644000175000017500000000075112374427411015412 0ustar vagrantvagrant## Process this file with automake to produce Makefile.in bin_PROGRAMS = ltspfs ltspfsd lbmount ltspfs_SOURCES = ltspfs.c common.c common.h ltspfs.h ltspfsd_SOURCES = ltspfsd.c ltspfsd_functions.c ltspfsd_functions.h common.c common.h ltspfs.h lbmount_SOURCES = lbmount.c ltspfs_CFLAGS = -Wall -W -D_FILE_OFFSET_BITS=64 -DFUSE_USE_VERSION=22 -D_REENTRANT ltspfsd_CFLAGS = -Wall -W -D_FILE_OFFSET_BITS=64 -DAUTOMOUNT -D_REENTRANT ltspfs_LDADD = $(LTSPFS_LIBS) ltspfs_LDFLAGS = -pthread ltspfs-1.4/src/ltspfsd_functions.h0000644000175000017500000000236412374427411017300 0ustar vagrantvagrant/* * function prototypes */ void handle_connection(int sockfd); void sig_chld(int signo); void sig_term(int signo); void eacces (int sockfd); void handle_mount(int sockfd, XDR *in); void handle_auth(int sockfd, XDR *in); void ltspfs_dispatch (int sockfd, XDR *in); void ltspfs_getattr (int sockfd, XDR *in); void ltspfs_readlink (int sockfd, XDR *in); void ltspfs_readdir (int sockfd, XDR *in); void ltspfs_mknod (int sockfd, XDR *in); void ltspfs_mkdir (int sockfd, XDR *in); void ltspfs_symlink (int sockfd, XDR *in); void ltspfs_unlink (int sockfd, XDR *in); void ltspfs_rmdir (int sockfd, XDR *in); void ltspfs_rename (int sockfd, XDR *in); void ltspfs_link (int sockfd, XDR *in); void ltspfs_chmod (int sockfd, XDR *in); void ltspfs_chown (int sockfd, XDR *in); void ltspfs_truncate (int sockfd, XDR *in); void ltspfs_utime (int sockfd, XDR *in); void ltspfs_open (int sockfd, XDR *in); void ltspfs_read (int sockfd, XDR *in); void ltspfs_write (int sockfd, XDR *in); void ltspfs_statfs (int sockfd, XDR *in); void ltspfs_ping (int sockfd); void ltspfs_quit (int sockfd); /* * Global variables */ extern int debug; extern int readonly; extern int noauth; extern char *mountpoint; extern int authenticated; ltspfs-1.4/src/ltspfsd_functions.c0000644000175000017500000005753212374427411017302 0ustar vagrantvagrant/* * Copyright Scott Balneaves, sbalneav@ltsp.org, 2006, 2007 * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, you can find it on the World Wide * Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "ltspfs.h" #include "ltspfsd_functions.h" #include "common.h" extern int mounted; char *ltspfs_opcode_str[] = { "LTSPFS_GETATTR", "LTSPFS_READLINK", "LTSPFS_READDIR", "LTSPFS_MKNOD", "LTSPFS_MKDIR", "LTSPFS_SYMLINK", "LTSPFS_UNLINK", "LTSPFS_RMDIR", "LTSPFS_RENAME", "LTSPFS_LINK", "LTSPFS_CHMOD", "LTSPFS_CHOWN", "LTSPFS_TRUNCATE", "LTSPFS_UTIME", "LTSPFS_OPEN", "LTSPFS_READ", "LTSPFS_WRITE", "LTSPFS_STATFS", "LTSPFS_RELEASE", "LTSPFS_RSYNC", "LTSPFS_SETXATTR", "LTSPFS_GETXATTR", "LTSPFS_LISTXATTR", "LTSPFS_REMOVEXATTR", "LTSPFS_XAUTH", "LTSPFS_MOUNT", "LTSPFS_PING", "LTSPFS_QUIT" }; /* * eacces: * * This function stub is assigned to several callouts when read-only mode * is enabled. It basically just returns EACCES to the client FUSE program. */ void eacces(int sockfd) { if (debug) info("eacces called\n"); errno = EACCES; status_return(sockfd, FAIL); } /* * Helper routine to do get a path from the XDR stream, and do all the path * adjustment. */ int get_fn(int sockfd, XDR * in, char *path) { char *pathptr = path; int mpl; mpl = strlen(mountpoint); strncpy(path, mountpoint, mpl); pathptr += mpl; if (!xdr_string(in, &pathptr, (PATH_MAX - mpl))) { eacces(sockfd); return FAIL; } else return OK; } /* * ltspfs_dispatch: * * The callout dispatcher. Once a command's been read from the socket, * this function figures out which command it is, and dispatches the * correct handler function. */ void ltspfs_dispatch(int sockfd, XDR * in) { int packet_type; if (!xdr_int(in, &packet_type)) { if (debug) info("Packet type decode failed!\n"); close(sockfd); exit(1); } if (debug) info("Packet type: %s\n", ltspfs_opcode_str[packet_type]); if (noauth) { authenticated++; } if (!authenticated) { /* Haven't authenticated yet */ switch (packet_type) { case LTSPFS_XAUTH: handle_auth(sockfd, in); break; default: status_return(sockfd, FAIL); } } else if (!mountpoint) { switch (packet_type) { case LTSPFS_MOUNT: handle_mount(sockfd, in); /* Haven't mounted yet */ break; default: status_return(sockfd, FAIL); } } else if (packet_type == LTSPFS_PING) { ltspfs_ping(sockfd); } else { if (!mounted) am_mount(mountpoint); /* this will return */ switch (packet_type) { case LTSPFS_GETATTR: ltspfs_getattr(sockfd, in); break; case LTSPFS_READLINK: ltspfs_readlink(sockfd, in); break; case LTSPFS_READDIR: ltspfs_readdir(sockfd, in); break; case LTSPFS_MKNOD: ltspfs_mknod(sockfd, in); break; case LTSPFS_MKDIR: ltspfs_mkdir(sockfd, in); break; case LTSPFS_SYMLINK: ltspfs_symlink(sockfd, in); break; case LTSPFS_UNLINK: ltspfs_unlink(sockfd, in); break; case LTSPFS_RMDIR: ltspfs_rmdir(sockfd, in); break; case LTSPFS_RENAME: ltspfs_rename(sockfd, in); break; case LTSPFS_LINK: ltspfs_link(sockfd, in); break; case LTSPFS_CHMOD: ltspfs_chmod(sockfd, in); break; case LTSPFS_CHOWN: ltspfs_chown(sockfd, in); break; case LTSPFS_TRUNCATE: ltspfs_truncate(sockfd, in); break; case LTSPFS_UTIME: ltspfs_utime(sockfd, in); break; case LTSPFS_OPEN: ltspfs_open(sockfd, in); break; case LTSPFS_READ: ltspfs_read(sockfd, in); break; case LTSPFS_WRITE: ltspfs_write(sockfd, in); break; case LTSPFS_STATFS: ltspfs_statfs(sockfd, in); break; case LTSPFS_RELEASE: case LTSPFS_RSYNC: case LTSPFS_SETXATTR: case LTSPFS_GETXATTR: case LTSPFS_LISTXATTR: case LTSPFS_REMOVEXATTR: break; case LTSPFS_QUIT: ltspfs_quit(sockfd); break; default: status_return(sockfd, FAIL); if (debug) info("Invalid command: %d\n", packet_type); } } } /* * ltspfs_getattr: * * sends the output of the lstat() system call back to the client FUSE program */ void ltspfs_getattr(int sockfd, XDR * in) { XDR out; char path[PATH_MAX]; char output[LTSP_MAXBUF]; int i; struct stat stbuf; unsigned int nlink; if (get_fn(sockfd, in, path)) { if (debug) info("get_fn failed\n"); eacces(sockfd); return; } if (lstat(path, &stbuf) == -1) { status_return(sockfd, FAIL); return; } xdrmem_create(&out, output, LTSP_MAXBUF, XDR_ENCODE); i = 0; xdr_int(&out, &i); /* First, the dummy length */ xdr_int(&out, &i); /* Then the 0 status return */ xdr_u_longlong_t(&out, &(stbuf.st_dev)); /* device */ xdr_u_longlong_t(&out, &(stbuf.st_ino)); /* inode */ xdr_u_int(&out, &(stbuf.st_mode)); /* protection */ xdr_u_int(&out, &nlink); stbuf.st_nlink = (nlink_t) nlink; xdr_u_int(&out, &(stbuf.st_uid)); /* user ID of owner */ xdr_u_int(&out, &(stbuf.st_gid)); /* group ID of owner */ xdr_u_longlong_t(&out, &(stbuf.st_rdev)); /* device type */ xdr_longlong_t(&out, &(stbuf.st_size)); /* total size, in bytes */ xdr_long(&out, &(stbuf.st_blksize)); /* blocksize for fs I/O */ xdr_longlong_t(&out, &(stbuf.st_blocks)); /* num of blocks allocated */ xdr_long(&out, &(stbuf.st_atime)); /* time of last access */ xdr_long(&out, &(stbuf.st_mtime)); /* time of last modification */ xdr_long(&out, &(stbuf.st_ctime)); /* time of last status chng */ i = xdr_getpos(&out); /* Get our position */ xdr_setpos(&out, 0); /* Rewind to the beginning */ xdr_int(&out, &i); /* Rewrite w/ proper length */ xdr_destroy(&out); if (debug) info("returning OK"); writen(sockfd, output, i); } /* * ltspfs_readlink: * * sends the link target returned by readlink() to the client FUSE program */ void ltspfs_readlink(int sockfd, XDR * in) { XDR out; char path[PATH_MAX]; char buf[PATH_MAX]; /* linkname */ char output[LTSP_MAXBUF]; char *bufptr = buf; int i; /* readlink doesn't terminate with a null */ memset(buf, 0, PATH_MAX); if (get_fn(sockfd, in, path)) { /* Get the link source */ eacces(sockfd); return; } if (readlink(path, buf, PATH_MAX) == -1) { status_return(sockfd, FAIL); return; } if (!strncmp(buf, mountpoint, strlen(mountpoint))) /* adjust link target */ bufptr += strlen(mountpoint); xdrmem_create(&out, output, LTSP_MAXBUF, XDR_ENCODE); i = 0; xdr_int(&out, &i); /* First, the dummy length */ xdr_int(&out, &i); /* Then the 0 status return */ xdr_string(&out, &bufptr, PATH_MAX); /* Link target */ i = xdr_getpos(&out); /* Get our position */ xdr_setpos(&out, 0); /* Rewind to the beginning */ xdr_int(&out, &i); /* Rewrite with proper length */ xdr_destroy(&out); if (debug) info("returning ok", output); writen(sockfd, output, i); } /* * ltspfs_readdir: * * Returns the directory listing to the client FUSE program. Output looks * like: * * 100||| * 100||| * ... * 100||| * 001 */ void ltspfs_readdir(int sockfd, XDR * in) { XDR out; char path[PATH_MAX]; char output[LTSP_MAXBUF]; DIR *dp; char *nameptr; struct dirent *de; int i; if (get_fn(sockfd, in, path)) { /* Get the dir name */ eacces(sockfd); return; } dp = opendir(path); if (dp == NULL) { status_return(sockfd, FAIL); /* opendir failed */ return; } while ((de = readdir(dp)) != NULL) { xdrmem_create(&out, output, LTSP_MAXBUF, XDR_ENCODE); i = 0; xdr_int(&out, &i); /* First, the dummy length */ i = LTSP_STATUS_CONT; xdr_int(&out, &i); /* Then the 2 status return */ xdr_u_longlong_t(&out, &(de->d_ino)); /* Inode */ xdr_u_char(&out, &(de->d_type)); /* type */ nameptr = de->d_name; xdr_string(&out, &nameptr, PATH_MAX); /* filename */ i = xdr_getpos(&out); /* Get our position */ xdr_setpos(&out, 0); /* Rewind to the beginning */ xdr_int(&out, &i); /* Rewrite w/ proper length */ xdr_destroy(&out); if (debug) info("returning %s", de->d_name); writen(sockfd, output, i); } closedir(dp); status_return(sockfd, OK); } /* * ltspfs_mknod: * * Makes filesystem nodes (regular files, pipes, device nodes, etc). */ void ltspfs_mknod(int sockfd, XDR * in) { char path[PATH_MAX]; mode_t mode; dev_t rdev; if (!xdr_u_int(in, &mode)) { /* Get the mode */ eacces(sockfd); return; } if (!xdr_u_longlong_t(in, &rdev)) { /* Get the device type */ eacces(sockfd); return; } if (get_fn(sockfd, in, path)) { /* Get the dir name */ eacces(sockfd); return; } status_return(sockfd, mknod(path, mode, rdev)); } /* * ltspfs_mkdir: * * Makes directories */ void ltspfs_mkdir(int sockfd, XDR * in) { char path[PATH_MAX]; mode_t mode; if (!xdr_u_int(in, &mode)) { /* Get the mode */ eacces(sockfd); return; } if (get_fn(sockfd, in, path)) { /* Get the dir name */ eacces(sockfd); return; } status_return(sockfd, mkdir(path, mode)); } /* * ltspfs_symlink: * * Makes symlinks */ void ltspfs_symlink(int sockfd, XDR * in) { char from[PATH_MAX]; char to[PATH_MAX]; if (get_fn(sockfd, in, from)) { /* Get the source link */ eacces(sockfd); return; } if (get_fn(sockfd, in, to)) { /* Get the destination link */ eacces(sockfd); return; } status_return(sockfd, symlink(from, to)); } /* * ltspfs_unlink: * * Deletes (unlinks) files. */ void ltspfs_unlink(int sockfd, XDR * in) { char path[PATH_MAX]; if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } status_return(sockfd, unlink(path)); } /* * ltspfs_rmdir: * * Removes directories. */ void ltspfs_rmdir(int sockfd, XDR * in) { char path[PATH_MAX]; if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } status_return(sockfd, rmdir(path)); } /* * ltspfs_rename: * * Renames files. */ void ltspfs_rename(int sockfd, XDR * in) { char from[PATH_MAX]; char to[PATH_MAX]; if (get_fn(sockfd, in, from)) { /* Get the source name */ eacces(sockfd); return; } if (get_fn(sockfd, in, to)) { /* Get the destination name */ eacces(sockfd); return; } status_return(sockfd, rename(from, to)); } /* * ltspfs_link: * * Creates hard links. */ void ltspfs_link(int sockfd, XDR * in) { char from[PATH_MAX]; char to[PATH_MAX]; if (get_fn(sockfd, in, from)) { /* Get the source link */ eacces(sockfd); return; } if (get_fn(sockfd, in, to)) { /* Get the destination link */ eacces(sockfd); return; } status_return(sockfd, link(from, to)); } /* * ltspfs_chmod: * * Changes permisions on files. */ void ltspfs_chmod(int sockfd, XDR * in) { char path[PATH_MAX]; mode_t mode; if (!xdr_u_int(in, &mode)) { /* Get the mode */ eacces(sockfd); return; } if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } status_return(sockfd, chmod(path, mode)); } /* * ltspfs_chown: * * Changes owners/groups on files. */ void ltspfs_chown(int sockfd, XDR * in) { char path[PATH_MAX]; uid_t uid; gid_t gid; if (!xdr_u_int(in, &uid)) { /* Get the mode */ eacces(sockfd); return; } if (!xdr_u_int(in, &gid)) { /* Get the mode */ eacces(sockfd); return; } if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } status_return(sockfd, chown(path, uid, gid)); } /* * ltspfs_truncate: * * Truncates a file at offset bytes. */ void ltspfs_truncate(int sockfd, XDR * in) { char path[PATH_MAX]; off_t offset; if (!xdr_longlong_t(in, &offset)) { /* Get the mode */ eacces(sockfd); return; } if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } status_return(sockfd, truncate(path, offset)); } /* * ltspfs_utime: * * Updates the access time and modification time of a file */ void ltspfs_utime(int sockfd, XDR * in) { char path[PATH_MAX]; struct utimbuf timbuf; if (!xdr_long(in, &timbuf.actime)) { /* Get the actime */ eacces(sockfd); return; } if (!xdr_long(in, &timbuf.modtime)) { /* Get the modtime */ eacces(sockfd); return; } if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } status_return(sockfd, utime(path, &timbuf)); } /* * ltspfs_open: * * Tests whether or not a file may be opened dependant on the flags. */ void ltspfs_open(int sockfd, XDR * in) { char path[PATH_MAX]; int result; int flags; if (!xdr_int(in, &flags)) { /* Get the flags */ eacces(sockfd); return; } if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } /* * If we're a read-only filesystem, and we've been asked to open * O_WRONLY or O_RDWR, then return EACCES */ if (readonly) if ((flags & O_WRONLY) || (flags & O_RDWR)) { eacces(sockfd); return; } /* * Otherwise, check the permissions with a test open, and return the * results if an error occurred. */ result = open(path, flags); status_return(sockfd, result); if (result != -1) close(result); } /* * ltspfs_read: * * Reads blocks from a file. Atomic: open-seek-read-close */ void ltspfs_read(int sockfd, XDR * in) { XDR out; char path[PATH_MAX]; char output[LTSP_MAXBUF]; int i; int fd; int result; unsigned int usize; size_t size; off_t offset; char *buf; if (!xdr_u_int(in, &usize)) { /* Get the size */ eacces(sockfd); return; } size = (size_t) usize; if (!xdr_longlong_t(in, &offset)) { /* Get the offset */ eacces(sockfd); return; } if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } buf = malloc(size); /* * Check result of malloc */ if (!buf) { status_return(sockfd, FAIL); return; } fd = open(path, O_RDONLY); if (fd == -1) { status_return(sockfd, FAIL); free(buf); return; } lseek(fd, offset, SEEK_SET); result = read(fd, buf, size); if (result < 0) status_return(sockfd, FAIL); else { xdrmem_create(&out, output, LTSP_MAXBUF, XDR_ENCODE); i = 0; xdr_int(&out, &i); /* dummy length */ i = LTSP_STATUS_OK; /* OK status */ xdr_int(&out, &i); xdr_int(&out, &result); /* Write out the result */ i = xdr_getpos(&out); /* Get current position */ xdr_setpos(&out, 0); /* rewind to the beginning */ xdr_int(&out, &i); /* re-write proper length */ xdr_destroy(&out); /* Clean up the XDR structs */ if (debug) info("read returning %d bytes", result); writen(sockfd, output, i); /* Write out status */ writen(sockfd, buf, result); /* Write out data payload */ } close(fd); free(buf); } void ltspfs_write(int sockfd, XDR * in) { XDR out; char path[PATH_MAX]; char output[LTSP_MAXBUF]; int i; int fd; int result; size_t size; unsigned int usize; off_t offset; char *buf; if (!xdr_u_int(in, &usize)) { /* Get the size */ eacces(sockfd); return; } size = (size_t) usize; if (!xdr_longlong_t(in, &offset)) { /* Get the offset */ eacces(sockfd); return; } if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } buf = malloc(size); /* * Check result of malloc */ if (!buf) { status_return(sockfd, FAIL); return; } fd = open(path, O_WRONLY); if (fd == -1) { status_return(sockfd, FAIL); free(buf); return; } readn(sockfd, buf, size); lseek(fd, offset, SEEK_SET); result = write(fd, buf, size); if (result < 0) status_return(sockfd, FAIL); else { xdrmem_create(&out, output, LTSP_MAXBUF, XDR_ENCODE); i = 0; xdr_int(&out, &i); /* dummy length */ i = LTSP_STATUS_OK; /* OK status */ xdr_int(&out, &i); xdr_int(&out, &result); /* Write out the result */ i = xdr_getpos(&out); /* Get current position */ xdr_setpos(&out, 0); /* rewind to the beginning */ xdr_int(&out, &i); /* re-write proper length */ xdr_destroy(&out); /* Clean up the XDR structs */ if (debug) info("returning %s", output); writen(sockfd, output, i); } close(fd); free(buf); } void ltspfs_statfs(int sockfd, XDR * in) { XDR out; char path[PATH_MAX]; char output[LTSP_MAXBUF]; struct statfs stbuf; int i; int f_type, f_bsize, f_namelen; if (get_fn(sockfd, in, path)) { /* Get the path */ eacces(sockfd); return; } if (statfs(path, &stbuf) == -1) { status_return(sockfd, FAIL); return; } xdrmem_create(&out, output, LTSP_MAXBUF, XDR_ENCODE); i = 0; xdr_int(&out, &i); /* dummy length */ i = LTSP_STATUS_OK; /* OK status */ xdr_int(&out, &i); f_type = (int) stbuf.f_type; xdr_int(&out, &f_type); /* type of fs */ f_bsize = (int) stbuf.f_bsize; xdr_int(&out, &f_bsize); /* optimal transfer block sz */ xdr_u_longlong_t(&out, &stbuf.f_blocks); /* total data blocks in fs */ xdr_u_longlong_t(&out, &stbuf.f_bfree); /* free blks in fs */ xdr_u_longlong_t(&out, &stbuf.f_bavail); /* free blks avail to non-su */ xdr_u_longlong_t(&out, &stbuf.f_files); /* total file nodes in fs */ xdr_u_longlong_t(&out, &stbuf.f_ffree); /* free file nodes in fs */ f_namelen = (int) stbuf.f_namelen; xdr_int(&out, &f_namelen); /* max length of filenames */ i = xdr_getpos(&out); /* Get current position */ xdr_setpos(&out, 0); /* rewind to the beginning */ xdr_int(&out, &i); /* re-write proper length */ xdr_destroy(&out); /* Clean up the XDR structs */ if (debug) info("returning OK"); writen(sockfd, output, i); } /* * ltspfs_ping: * * Transmit a simple "000" status return to a ping request. */ void ltspfs_ping(int sockfd) { status_return(sockfd, OK); if (debug) info("received ping packet\n"); } void ltspfs_quit(int sockfd) { /* * Close up shop and bail. */ close(sockfd); exit(OK); } void handle_mount(int sockfd, XDR * in) { char path[PATH_MAX]; char *pathptr = path; /* * Get our mount point */ if (!xdr_string(in, &pathptr, PATH_MAX)) { /* Get the path */ eacces(sockfd); return; } /* * Here's where you'd do sanity checking on the dir, checking an exports * file, etc. For now, we'll assume it's correct. */ mountpoint = strdup(path); if (debug) info("mount: %s\n", mountpoint); status_return(sockfd, OK); } /* * handle_auth * * Read our secret code (generated with mcookie), and compare it to what the * client sent us. */ void handle_auth(int sockfd, XDR * in) { char recdtoken[64]; int auth_size; char authtoken[64]; int authtokensize; int authfile, i; /* * Get our auth size. */ if (!xdr_int(in, &auth_size)) { /* Get the size */ eacces(sockfd); return; } if (auth_size >= (int) sizeof recdtoken) { eacces(sockfd); return; } readn(sockfd, recdtoken, auth_size); /* read packet */ recdtoken[auth_size] = '\0'; /* * Test our authentication. * our XAUTHORITY environment variable is pointing to the xauth record, * so if we've got a match, we the open should succeed. */ authfile = open("/var/run/ltspfs_token", O_RDONLY); if (authfile < 0) { eacces(sockfd); return; } authtokensize = read(authfile, authtoken, sizeof authtoken); close(authfile); for (i = 0; i < authtokensize; i++) if (authtoken[i] == '\n') authtoken[i] = '\0'; if (strncmp(authtoken, recdtoken, auth_size)) { eacces(sockfd); return; } status_return(sockfd, OK); /* Acknowledge auth */ authenticated++; /* Set auth state */ } ltspfs-1.4/src/ltspfsd.c0000644000175000017500000001726012374427411015204 0ustar vagrantvagrant/* * ltspfsd.c * Mainline handling for the Linux Terminal Server Project File Server Daemon. * Copyright Scott Balneaves, sbalneav@ltsp.org, 2005, 2006, 2007 * Gideon Romm, gadi@ltsp.org, 2009 * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, you can find it on the World Wide * Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ltspfs.h" #include "ltspfsd_functions.h" #include "common.h" /* * Globals. */ int debug; /* Debug level. 0 = no debug */ int readonly; /* If true, make filesystem "read only" */ int noauth; /* If true, skip authentication */ int syslogopen; /* If true, then log to syslog, else stderr */ char *mountpoint; /* Point we're "mounted" to */ int authenticated; /* Mountpoint length */ int mounted; /* Automounter status */ /* * Signal handler function for SIGCHLD */ void sig_chld(int signo) { pid_t pid; int stat; (void) signo; pid = wait(&stat); /* reap our child process */ (void) pid; } /* * Signal handler function for SIGTERM */ void sig_term(int signo) { (void) signo; info("Received SIGTERM, shutting down\n"); exit(OK); } void timeout(void) { exit(0); } /* * mainline */ int main(int argc, char *argv[]) { int sockfd, newsockfd, childpid; struct sockaddr_in cli_addr; socklen_t clilen; int c; authenticated = 0; mounted = 0; mountpoint = NULL; /* * We can begin to parse command line options. */ debug = readonly = opterr = noauth = 0; while ((c = getopt(argc, argv, "rad")) != -1) { switch (c) { case 'r': readonly++; break; case 'a': noauth++; break; case 'd': debug++; break; case '?': fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); return 1; default: break; } } /* * Some initialization work. We call daemon(), which will chdir to / * so that the daemon won't lock any filesystems. The daemon() call also * closes STDIN, STDOUT, and STDERR, and forks. Then, set up our umask, * and redirect the SIGCHLD and SIGTERM signals to handlers. */ if (!debug) { /* if !debug, background */ if (!daemon(0, 0)) { signal(SIGCHLD, sig_chld); signal(SIGTERM, sig_term); } } umask(0); /* * open our logging. */ if (!debug) { openlog(argv[0], LOG_PID, LOG_USER); syslogopen++; } else setbuf(stderr, NULL); /* * Open our socket */ sockfd = bindsocket(SERVER_PORT); /* * Log informational message to indicate program starting */ info("Program started\n"); /* * Calculate the length of the cli_addr structure (needed for the accept) */ clilen = sizeof(cli_addr); for (;;) { /* * Accept incoming connection */ newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); if (newsockfd < 0) error_die("Can't accept connection"); /* * Added this part to make local connections ignore authentication */ char destination_buffer[INET_ADDRSTRLEN]; inet_ntop(AF_INET, (void *)&cli_addr.sin_addr, destination_buffer, sizeof(destination_buffer)); if (!strcmp("127.0.0.1", destination_buffer)) { noauth=1; } else { noauth=0; } if (!debug) /* In debug mode, don't fork */ childpid = fork(); else childpid = 0; if (childpid < 0) error_die("fork error"); /* If fork fails, die */ else if (childpid == 0) { close(sockfd); /* Pass work off to child */ handle_connection(newsockfd); exit(OK); /* exit child, SIGCHLD sent */ } close(newsockfd); /* parent */ } return OK; /* return 0 from main */ } /* * handle_connection is where the "work" gets done. Anything you want to "do" * as a network daemon should be done here. * * Dispatch ltspfs calls to ltspfs_dispatch. */ void handle_connection(int sockfd) { XDR in; int n; int i, q; char line[LTSP_MAXBUF]; char *lineptr; fd_set set; /* For select */ struct timeval automount_timeout; /* Timeout */ int nleft, nread; int r; for (;;) { FD_ZERO(&set); FD_SET(sockfd, &set); xdrmem_create(&in, line, LTSP_MAXBUF, XDR_DECODE); lineptr = line; /* * Sigh. I really hate to have to re-duplicate most of the readn * functionality here, but it's simply cleaner to not butcher the _readn * and _writen primitives just to handle automount timeouts. Soooo.... */ automount_timeout.tv_sec = AUTOMOUNT_TIMEOUT; automount_timeout.tv_usec = 0; r = select(FD_SETSIZE, &set, NULL, NULL, &automount_timeout); if (r < 0) error_die("handle_connection: select error\n"); else if (r == 0) { if (mounted) am_umount(mountpoint); /* this will return */ continue; /* Back to the top of loop */ } nleft = BYTES_PER_XDR_UNIT; while (nleft > 0) { nread = read(sockfd, lineptr, nleft); if (nread < 0) error_die("handle_connection: readline error\n"); else if (nread == 0) return; /* EOF, connection closed */ nleft -= nread; lineptr += nread; } xdr_int(&in, &i); if (debug) info("Packet length: %d\n", i); n = readn(sockfd, lineptr, (i - BYTES_PER_XDR_UNIT)); if (n == 0) return; /* connection closed */ else if (n < 0) error_die("handle_connection: readline error\n"); /* * OK We've got our command line, pass this off to ltspfs_dispatch */ if (debug) { info("Packet buffer: "); for (q = 0; q < i; q++) info("%x", line[q]); info("\n"); } ltspfs_dispatch(sockfd, &in); /* * Well, we're back. Reset our position to the beginning. */ xdr_destroy(&in); } } ltspfs-1.4/src/ltspfs.h0000644000175000017500000000312212374427411015035 0ustar vagrantvagrant/* * Defines */ /* * The maximum sized command we have is the symlink command. * We'll need: 1 BYTES_PER_XDR_UNIT for the packet length. * 1 BYTES_PER_XDR_UNIT for the packet type * 2 * (BYTES_PER_XDR_UNIT + PATH_MAX) for the paths. * So: * * ((4 * BYTES_PER_XDR_UNIT) + (2 * PATH_MAX)) */ #define SERVER_PORT 9220 #define LTSP_MAXBUF ((4 * BYTES_PER_XDR_UNIT) + (2 * PATH_MAX)) #define LTSPFS_TIMEOUT 120 #define AUTOMOUNT_TIMEOUT 5 #define LTSP_STATUS_OK 0 #define LTSP_STATUS_FAIL 1 #define LTSP_STATUS_CONT 2 #define PING_INTERVAL 30 /* * Packet types */ #define LTSPFS_GETATTR 0 #define LTSPFS_READLINK 1 #define LTSPFS_READDIR 2 #define LTSPFS_MKNOD 3 #define LTSPFS_MKDIR 4 #define LTSPFS_SYMLINK 5 #define LTSPFS_UNLINK 6 #define LTSPFS_RMDIR 7 #define LTSPFS_RENAME 8 #define LTSPFS_LINK 9 #define LTSPFS_CHMOD 10 #define LTSPFS_CHOWN 11 #define LTSPFS_TRUNCATE 12 #define LTSPFS_UTIME 13 #define LTSPFS_OPEN 14 #define LTSPFS_READ 15 #define LTSPFS_WRITE 16 #define LTSPFS_STATFS 17 #define LTSPFS_RELEASE 18 /* Not currently used */ #define LTSPFS_RSYNC 19 /* Not currently used */ #define LTSPFS_SETXATTR 20 /* Not currently used */ #define LTSPFS_GETXATTR 21 /* Not currently used */ #define LTSPFS_LISTXATTR 22 /* Not currently used */ #define LTSPFS_REMOVEXATTR 23 /* Not currently used */ #define LTSPFS_XAUTH 24 #define LTSPFS_MOUNT 25 #define LTSPFS_PING 26 #define LTSPFS_QUIT 27 ltspfs-1.4/src/ltspfs.c0000644000175000017500000007617212374427411015047 0ustar vagrantvagrant/* * ltspfs: a FUSE module for implementing a diskless thin client filesysem * to be used for local device access. * * Copyright Scott Balneaves, sbalneav@ltsp.org, 2005, 2006, 2007 * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, you can find it on the World Wide * Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ltspfs.h" #include "common.h" /* * Globals. */ static pthread_mutex_t lock; /* mutex needed for Fuse */ static int sockfd; /* Global socket */ static char *fuse_mount_point; /* Local mount point */ static struct fuse_context *fc = NULL; /* Fuse context for uid */ int debug = 0; int syslogopen = 0; /* * init_pkt() * * Sets up an input and output packets. */ void init_pkt(XDR * in, XDR * out, char *inbuf, char *outbuf) { int i = 0; xdrmem_create(in, inbuf, LTSP_MAXBUF, XDR_DECODE); xdrmem_create(out, outbuf, LTSP_MAXBUF, XDR_ENCODE); xdr_int(out, &i); /* reserve length field */ } /* * timeout(): * This handles a timeout on a read or write operation. * Close the socket, unmount the fuse mount, and exit the program. * This will improve over time, retry's are a possibility, etc. */ void timeout(void) { close(sockfd); fuse_unmount(fuse_mount_point); exit(0); } /* * readpacket(): * Helper command to read packets in, since we first have to read the packet * length, then the rest of the packet. */ int readpacket(XDR * in, char *packetbuffer) { char *pktptr = packetbuffer; int len; /* * First, read in the first BYTES_PER_XDR_UNIT bytes, which should * have the packet length in them. */ readn(sockfd, pktptr, BYTES_PER_XDR_UNIT); /* Read length */ xdr_int(in, &len); /* decode it */ len -= BYTES_PER_XDR_UNIT; /* reduce count */ pktptr += BYTES_PER_XDR_UNIT; /* skip over count */ return readn(sockfd, pktptr, len); /* and read the rest */ } /* * packetlen(): * Fixes up the length of the packet. Returns the packet length. */ int writepacket(XDR * out, char *packetbuffer) { int i; i = xdr_getpos(out); /* Grab current streampos */ xdr_setpos(out, 0); /* rewind to beginning */ /* * Since the first thing we do when initializing a packet is leave a space * for an int at the beginning, this is the space for the packet length. * Now, write out the proper length back at the beginning. */ xdr_int(out, &i); /* Write proper length */ i = writen(sockfd, packetbuffer, i); /* Write packet to socket */ /* * since we've finished sending, destroy the output stream */ xdr_destroy(out); return i; } /* * send_recv(): * * For most of the functions, this will handle the communications. Mutexes * handle the locking and unlocking of the communication stream. */ void send_recv(XDR * in, XDR * out, char *inbuf, char *outbuf) { pthread_mutex_lock(&lock); /* Lock mutex */ writepacket(out, outbuf); /* Send out packet */ readpacket(in, inbuf); /* Read response */ pthread_mutex_unlock(&lock); /* Unlock mutex */ } /* * ping_timeout: * * This function will handle sendig a "PING" packet to the server once every * x minutes. If it doesn't get a response back, then it will exit the * timeout function will unmount the ltspfs filesystem and exit. */ void ping_timeout(void *nothing) { XDR in, out; int i; char pingin[LTSP_MAXBUF]; char pingout[LTSP_MAXBUF]; struct timespec ping_interval; (void) nothing; init_pkt(&in, &out, pingin, pingout); /* Initialize packets */ i = LTSPFS_PING; xdr_int(&out, &i); i = xdr_getpos(&out); xdr_setpos(&out, 0); xdr_int(&out, &i); ping_interval.tv_sec = PING_INTERVAL; ping_interval.tv_nsec = 0; while (TRUE) { nanosleep(&ping_interval, NULL); pthread_mutex_lock(&lock); /* Lock mutex */ writen(sockfd, pingout, i); /* Send command */ readpacket(&in, pingin); /* Read response */ xdr_setpos(&in, 0); pthread_mutex_unlock(&lock); /* Unlock mutex */ } } /* * parse_return: * Simplifies several functions by handling simple "000" or 001|errno returns. */ static int parse_return(XDR * xdr) { int res, retcode; /* * rewind to the beginning. */ xdr_setpos(xdr, 0); /* rewind to beginning */ xdr_int(xdr, &res); /* read over the length */ if (!xdr_int(xdr, &res)) /* try to grab return code */ retcode = EACCES; /* Couldnt grab, so return */ else if (!res) /* If OK, goto out */ retcode = OK; else if (!xdr_int(xdr, &retcode)) /* If fail, then grab code */ retcode = EACCES; xdr_destroy(xdr); /* Done, so destroy stream */ return -retcode; } /* * ltspfs_sendauth: * * Grabs our $DISPLAY, and sends our XAUTH info for verification on the other * side. */ int ltspfs_sendauth(void) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int size; int opcode = LTSPFS_XAUTH; Atom comm_atom; /* Our communication atom */ Display *dpy; /* Display */ Window root; /* root window */ char *buf; Atom type; int format, res; unsigned long nitems, nleft; /* * Get the auth token from the root window of our display */ if (!(dpy = XOpenDisplay(NULL))) { fprintf(stderr, "Cannot open X display.\n"); exit(1); } root = RootWindow(dpy, DefaultScreen(dpy)); comm_atom = XInternAtom(dpy, "LTSPFS_TOKEN", False); if (comm_atom == None) { printf("Couldn't allocate atom\n"); exit(1); } res = XGetWindowProperty(dpy, root, comm_atom, 0, 512, 0, XA_STRING, &type, &format, &nitems, &nleft, (unsigned char **)&buf); if (res != Success || type != XA_STRING) { fprintf(stderr, "Couldn't read LTSPFS_TOKEN atom.\n"); exit(1); } size = strlen(buf); /* * Now, send the authorization. */ init_pkt(&in, &out, inbuf, outbuf); xdr_int(&out, &opcode); /* build opcode */ xdr_int(&out, &size); /* build auth packet size */ writepacket(&out, outbuf); /* Send command */ writen(sockfd, buf, size); /* Send authfile */ fprintf(stderr, "Wrote %s size %d, waiting\n", buf, size); readpacket(&in, inbuf); /* Read response */ XFree(buf); /* free up returned data */ XCloseDisplay(dpy); return parse_return(&in); } /* * ltspfs_getattr: * * Handles the getattr filesystem call. */ static int ltspfs_getattr(const char *path, struct stat *stbuf) { XDR out, in; char outbuf[LTSP_MAXBUF]; char inbuf[LTSP_MAXBUF]; char *ptr = (char *) path; int opcode = LTSPFS_GETATTR; unsigned int nlink = (unsigned int) stbuf->st_nlink; int res; uid_t uid; gid_t gid; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ if (!xdr_int(&in, &res)) /* Did we get error? */ return -EACCES; /* bad arg */ if (res) return parse_return(&in); /* bad result */ /* * Parse the return and populate the structure */ if (!fc) /* Initialized fc? */ fc = fuse_get_context(); /* Grab the context */ if (!xdr_u_longlong_t(&in, &stbuf->st_dev)) return -EACCES; if (!xdr_u_longlong_t(&in, &stbuf->st_ino)) return -EACCES; if (!xdr_u_int(&in, &stbuf->st_mode)) return -EACCES; if (!xdr_u_int(&in, &nlink)) return -EACCES; if (!xdr_u_int(&in, &uid)) return -EACCES; if (!xdr_u_int(&in, &gid)) return -EACCES; /* * We get back the uid and gid from the remote filesystem, but we don't * use it. Basically, we use the fuse context, which tells us who * mounted the filesystem. This way, the user always "owns" the files * on the remote media. This should probably by an overridable option, * just on the off chance that someone DOES have a "real" filesystem * (i.e. one that knows about userids) on the remote side. */ stbuf->st_uid = fc->uid; stbuf->st_gid = fc->gid; /* * Also, in order to make sure that all files are umask 700, we'll * manipulate the st_mode at this point. */ stbuf->st_mode = stbuf->st_mode & (S_IFDIR | S_IFREG | 0700); if (!xdr_u_longlong_t(&in, &stbuf->st_rdev)) return -EACCES; if (!xdr_longlong_t(&in, &stbuf->st_size)) return -EACCES; if (!xdr_long(&in, &stbuf->st_blksize)) return -EACCES; if (!xdr_longlong_t(&in, &stbuf->st_blocks)) return -EACCES; if (!xdr_long(&in, &stbuf->st_atime)) return -EACCES; if (!xdr_long(&in, &stbuf->st_mtime)) return -EACCES; if (!xdr_long(&in, &stbuf->st_ctime)) return -EACCES; xdr_destroy(&in); return OK; } /* * ltspfs_readlink: * * Handles the readlink filesystem call. */ static int ltspfs_readlink(const char *path, char *buf, size_t size) { XDR out, in; char outbuf[LTSP_MAXBUF]; char inbuf[LTSP_MAXBUF]; int opcode = LTSPFS_READLINK; int ret, retcode; char *ptr = (char *) path; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ /* * Parse the return and populate returning link name buffer. */ if (!xdr_int(&in, &ret)) return -EACCES; if (ret) { if (!xdr_int(&in, &retcode)) { retcode = EACCES; } xdr_destroy(&in); return -retcode; } ptr = buf; if (!xdr_string(&in, &ptr, size)) /* return link target */ return -EACCES; xdr_destroy(&in); return OK; } /* * ltspfs_readdir: * * Handles the readdir filesystem call. * The logic's a little complicated on this one. You've got a few different * scenarios here: * 1) filler returns nonzero, server's still sending direntries. You want * to stop calling the filler command, but keep reading from the server * so you don't have "leftovers" next function call. * 2) filler's ok, but the server on the remote end sends us a "001" error. * 3) (hopefully 99.99% of the time) everything's a-ok. */ static int ltspfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *fi) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_READDIR; int r = 0; int statcode; char *ptr = (char *) path; (void) offset; (void) fi; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ pthread_mutex_lock(&lock); /* Lock mutex */ writepacket(&out, outbuf); readpacket(&in, inbuf); /* Read response */ xdr_int(&in, &statcode); while (statcode == LTSP_STATUS_CONT) { /* Continue? */ if (!r) { /* filler ok? */ struct stat st; unsigned char type; char dirpath[PATH_MAX]; ptr = dirpath; memset(&st, 0, sizeof(st)); xdr_u_longlong_t(&in, &st.st_ino); /* grab returned inode */ xdr_u_char(&in, &type); /* grab returned type */ xdr_string(&in, &ptr, PATH_MAX); /* grab dirent name */ st.st_mode = type << 12; /* More magic */ r = filler(buf, dirpath, &st, 0); /* Call the filler function */ } /* endif !r */ xdr_setpos(&in, 0); /* reset our input buffer */ readpacket(&in, inbuf); /* Read the next line */ xdr_int(&in, &statcode); /* And grab the statcode */ } pthread_mutex_unlock(&lock); /* Unlock mutex */ if (r) /* if filler died */ return r; /* return it first */ else return parse_return(&in); /* Return result */ } /* * ltspfs_mknod: * * Handles the mknod filesystem call. */ static int ltspfs_mknod(const char *path, mode_t mode, dev_t rdev) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_MKNOD; char *ptr = (char *) path; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_u_int(&out, &mode); /* build mode */ xdr_u_longlong_t(&out, &rdev); /* build rdev */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ return parse_return(&in); } /* * ltspfs_mkdir: * * Handles the mkdir filesystem call. */ static int ltspfs_mkdir(const char *path, mode_t mode) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_MKDIR; char *ptr = (char *) path; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_u_int(&out, &mode); /* build mode */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ return parse_return(&in); } /* * ltspfs_onepath: * * Handles single path filesystem calls. */ static int ltspfs_onepath(int opcode, const char *path) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; char *ptr = (char *) path; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ return parse_return(&in); } /* * ltspfs_unlink: * * Handles the unlink filesystem call. */ static int ltspfs_unlink(const char *path) { return ltspfs_onepath(LTSPFS_UNLINK, path); } /* * ltspfs_rmdir: * * Handles the rmdir filesystem call. */ static int ltspfs_rmdir(const char *path) { return ltspfs_onepath(LTSPFS_RMDIR, path); } /* * ltspfs_twopath: * * Handles generic path filesystem calls. */ static int ltspfs_twopath(int opcode, const char *from, const char *to) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; char *ptr; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ ptr = (char *) from; xdr_string(&out, &ptr, PATH_MAX); /* build from */ ptr = (char *) to; xdr_string(&out, &ptr, PATH_MAX); /* build to */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ return parse_return(&in); } /* * ltspfs_symlink: * * Handles the symlink filesystem call. */ static int ltspfs_symlink(const char *from, const char *to) { return ltspfs_twopath(LTSPFS_SYMLINK, from, to); } /* * ltspfs_rename: * * Handles the rename filesystem call. */ static int ltspfs_rename(const char *from, const char *to) { return ltspfs_twopath(LTSPFS_RENAME, from, to); } /* * ltspfs_link: * * Handles the link filesystem call. */ static int ltspfs_link(const char *from, const char *to) { return ltspfs_twopath(LTSPFS_LINK, from, to); } /* * ltspfs_chmod: * * Handles the chmod filesystem call. */ static int ltspfs_chmod(const char *path, mode_t mode) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_CHMOD; char *ptr = (char *) path; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_u_int(&out, &mode); /* build mode */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ return parse_return(&in); } /* * ltspfs_chown: * * Handles the chown filesystem call. */ static int ltspfs_chown(const char *path, uid_t uid, gid_t gid) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_CHOWN; char *ptr = (char *) path; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_u_int(&out, &uid); /* build uid */ xdr_u_int(&out, &gid); /* build gid */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ return parse_return(&in); } /* * ltspfs_truncate: * * Handles the truncate filesystem call. */ static int ltspfs_truncate(const char *path, off_t size) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_TRUNCATE; char *ptr = (char *) path; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_longlong_t(&out, &size); /* build size */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ return parse_return(&in); } /* * ltspfs_utime: * * Handles the utime filesystem call. */ static int ltspfs_utime(const char *path, struct utimbuf *buf) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_UTIME; char *ptr = (char *) path; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_long(&out, &buf->actime); /* build accesstime */ xdr_long(&out, &buf->modtime); /* build modtime */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ return parse_return(&in); } /* * ltspfs_open: * * Handles the open filesystem call. */ static int ltspfs_open(const char *path, struct fuse_file_info *fi) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_OPEN; char *ptr = (char *) path; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_int(&out, &fi->flags); /* build open flags */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ return parse_return(&in); } /* * ltspfs_read: * * Handles the read filesystem call. */ static int ltspfs_read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_READ; char *ptr = (char *) path; int res, returned; unsigned int usize = (unsigned int) size; (void) fi; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_u_int(&out, &usize); /* build packet size */ xdr_longlong_t(&out, &offset); /* build file offset size */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ pthread_mutex_lock(&lock); /* Lock mutex */ writepacket(&out, outbuf); readpacket(&in, inbuf); /* Read response */ /* * Parse the return and populate the read buffer passed to us. */ if (!xdr_int(&in, &res)) { pthread_mutex_unlock(&lock); /* Unlock mutex */ return -EACCES; } if (!xdr_int(&in, &returned)) { pthread_mutex_unlock(&lock); /* Unlock mutex */ return -EACCES; } xdr_destroy(&in); if (res) { /* Error, return error code */ pthread_mutex_unlock(&lock); /* Unlock mutex */ return -returned; } readn(sockfd, buf, returned); /* read data payload */ pthread_mutex_unlock(&lock); /* Unlock mutex */ return returned; /* Return bytes read */ } /* * ltspfs_write: * * Handles the write filesystem call. */ static int ltspfs_write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *fi) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_WRITE; char *ptr = (char *) path; int res, returned; unsigned int usize = (unsigned int) size; (void) fi; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_u_int(&out, &usize); /* build packet size */ xdr_longlong_t(&out, &offset); /* build file offset */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ pthread_mutex_lock(&lock); /* Lock mutex */ writepacket(&out, outbuf); writen(sockfd, (char *) buf, size); /* Send data buffer */ readpacket(&in, inbuf); /* Read response */ pthread_mutex_unlock(&lock); /* Unlock mutex */ /* * Parse the return. */ if (!xdr_int(&in, &res)) return -EACCES; if (!xdr_int(&in, &returned)) return -EACCES; xdr_destroy(&in); if (res) /* Error, return error code */ return -returned; return returned; /* Return bytes written */ } /* * ltspfs_statfs: * * Handles the statfs filesystem call. */ static int ltspfs_statfs(const char *path, struct statfs *stbuf) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_STATFS; char *ptr = (char *) path; int ret; int f_type, f_bsize, f_namelen; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ send_recv(&in, &out, inbuf, outbuf); /* send output, recv response */ /* * Parse the return and populate the stbuf structure */ if (!xdr_int(&in, &ret)) return -EACCES; if (ret) return parse_return(&in); xdr_int(&in, &f_type); /* type of fs */ stbuf->f_type = (__SWORD_TYPE) f_type; xdr_int(&in, &f_bsize); /* optimal transfer block sz */ stbuf->f_bsize = (__SWORD_TYPE) f_bsize; xdr_u_longlong_t(&in, &stbuf->f_blocks); /* total data blocks in fs */ xdr_u_longlong_t(&in, &stbuf->f_bfree); /* free blks in fs */ xdr_u_longlong_t(&in, &stbuf->f_bavail); /* free blks avail to non-su */ xdr_u_longlong_t(&in, &stbuf->f_files); /* total file nodes in fs */ xdr_u_longlong_t(&in, &stbuf->f_ffree); /* free file nodes in fs */ xdr_int(&in, &f_namelen); stbuf->f_namelen = (__SWORD_TYPE) f_namelen; return OK; } /* * ltspfs_release: * * Handles the release filesystem call. * Since filesystem is stateless, this is a null function. */ static int ltspfs_release(const char *path, struct fuse_file_info *fi) { (void) path; (void) fi; return OK; } /* * ltspfs_fsync: * * Handles the fsync filesystem call. * Since filesystem is stateless, this is a null function. */ static int ltspfs_fsync(const char *path, int isdatasync, struct fuse_file_info *fi) { (void) path; (void) isdatasync; (void) fi; return OK; } /* * ltspfs_init: * * Called after the mainline's forked and daemonized. Create a pinger * thread that will sit in the background and ping the server every * PING_INTERVAL seconds. In the event that the LTSP terminal is shut off * without a proper fusermount -u being executed, this will unmount * the filesystem automatically, so that dead mounts aren't hanging around. */ static void *ltspfs_init(void) { pthread_t ping_thread; /* * Kick off our pinger thread. */ if (pthread_create(&ping_thread, NULL, (void *) &ping_timeout, (void *) NULL) < 0) { close(sockfd); exit(1); } pthread_detach(ping_thread); return NULL; } void handle_mount(char *mp) { XDR in, out; char inbuf[LTSP_MAXBUF]; char outbuf[LTSP_MAXBUF]; int opcode = LTSPFS_MOUNT; char *ptr = mp; int res; init_pkt(&in, &out, inbuf, outbuf); /* Initialize packets */ xdr_int(&out, &opcode); /* build opcode */ xdr_string(&out, &ptr, PATH_MAX); /* build path */ writepacket(&out, outbuf); readpacket(&in, inbuf); /* Read response */ xdr_int(&in, &res); if (res) { fprintf(stderr, "Couldn't mount %s\n", mp); close(sockfd); exit(1); } } /* * Populate our FUSE function callout table. */ static struct fuse_operations ltspfs_oper = { .getattr = ltspfs_getattr, .readlink = ltspfs_readlink, .readdir = ltspfs_readdir, /* newer readdir() interface */ .mknod = ltspfs_mknod, .mkdir = ltspfs_mkdir, .symlink = ltspfs_symlink, .unlink = ltspfs_unlink, .rmdir = ltspfs_rmdir, .rename = ltspfs_rename, .link = ltspfs_link, .chmod = ltspfs_chmod, .chown = ltspfs_chown, .truncate = ltspfs_truncate, .utime = ltspfs_utime, .open = ltspfs_open, .read = ltspfs_read, .write = ltspfs_write, .statfs = ltspfs_statfs, .release = ltspfs_release, .fsync = ltspfs_fsync, .init = ltspfs_init, /* no init pre 2.3 */ }; /* * MAINLINE */ int main(int argc, char *argv[]) { int i, myargc = 0; char *host = NULL, *mountpoint = NULL, *hostmount = NULL; char **myargv; /* * Argument handling. * * This seems really perverse. Fuse wants certain arguments. My program * wants certain arguments. Fuse doesn't want my arguments. Solution? * build a new argc and argv (appropriately titled "myargc" and "myargv"), * passing along only the arguments that fuse wants. In this case, that's * pretty much just the mount directory where the fuse mount will be. * * In keeping with the ever-so-popular nfs mount style, the overall command * line will look like: * * ltspfs host:/dir/to/mount /mountpoint * * We'll strip off the command line option that looks like: * somehost:somedir, and construct a new argc and argv that looks like: * ltspfs /mountpoint * * We also want to grab a copy of the local mountpoint, as we need it for * handling timeouts. When we get a timeout, we want to execute a * fuse_unmount command, so we'll assume that something that looks like * "/..." is the local directory mount point. */ setbuf(stderr, NULL); if (argc < 3) { fprintf(stderr, "Usage: %s host:/dir/to/mount /mountpoint \n", argv[0]); exit(1); } myargv = calloc(argc, sizeof(char *)); /* allocate same size */ if (!myargv) { fprintf(stderr, "calloc() failed to allocate memory\n"); exit(1); } myargv[myargc++] = argv[0]; /* program name */ for (i = 1; i < argc; i++) /* rest of arguments */ if (strchr(argv[i], ':')) hostmount = strdup(argv[i]); /* duplicate our parameter */ else { if (*argv[i] == '/') fuse_mount_point = argv[i]; /* point to the local mount */ myargv[myargc++] = argv[i]; /* copy the rest */ } /* * Now hostmount contains the string for the host, and the directory. */ if (!hostmount) { fprintf(stderr, "Remote dir must be specified as host:/dir.\n"); exit(0); } host = hostmount; mountpoint = strchr(hostmount, ':'); *mountpoint = '\0'; mountpoint++; if (!host) { fprintf(stderr, "No host specified!\n"); exit(0); } if (*mountpoint != '/') { fprintf(stderr, "No mountpoint specified!\n"); exit(0); } /* * Open up our socket */ sockfd = opensocket(host, SERVER_PORT); /* * Initialize our mutex. */ pthread_mutex_init(&lock, NULL); /* * The connection's plumbed. Issue our mount command. */ if (getenv("LTSPFS_NOAUTH") == NULL) { if (ltspfs_sendauth() != 0) { fprintf(stderr, "Authentication failed.\n"); exit(1); } } handle_mount(mountpoint); /* * We're mounted. Fire up fuse. */ return fuse_main(myargc, myargv, <spfs_oper); } ltspfs-1.4/src/lbmount.c0000644000175000017500000001551212374427411015203 0ustar vagrantvagrant/* * lbmount.c: - setuid wrapper around a bindmount to allow ltsp localdevices * to appear under /media * * Copyright Scott Balneaves, sbalneav@ltsp.org, 2006, 2007 * Martin Pitt, 2006 * Vagrant Cascadian, vagrant@freegeek.org, 2008 * Warren Togami, wtogami@redhat.com, 2008 * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, you can find it on the World Wide * Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include static uid_t uidReal; /* Users real userid */ /* * Static definitions of some parts of the mount. The program only gets passed * the name of the mounted device (i.e. the variable "mountpoint", and won't * accept any pathing on this variable. Then, the path is built dynamically. * So, a bindmount from /tmp/.username-ltspfs/devicename to * /media/username/devicename is made. Below are the "static" pieces of the * mount strings, used later to dynamically build the full paths based on * the username and mountpoint supplied. */ static char *mediadir = "/media"; void usage(char *progname) { fprintf(stderr, "usage: %s [--umount] mediadir\n", progname); exit(0); } /* * is_mounted: checks a path to see if it exists as a mountpoint in /proc/mounts */ int is_mounted(char *path) { FILE *f; struct mntent *entry; if (!(f = fopen("/proc/mounts", "r"))) { perror("Error: could not open /proc/mounts"); exit(1); } while ((entry = getmntent(f)) != NULL) { if (!strcmp(path, entry->mnt_dir)) { /* OK, here's where things get a little odd. We want to make sure * that the mount is owned by the user. Normally, we'd do a stat * call here, but because we're a setuid program, and fuse by * default doesn't even allow ROOT to access users mounts, a stat * call will fail. So, what we'll do is look at the "user_id=xxxx" * option in the mount tab, and see if it's the same as our own. * Clever.... veeeeery clever */ char *pos; pos = strstr(entry->mnt_opts, "user_id"); if (pos) { uid_t mounted_uid; pos += 8; /* skip over user_id= */ sscanf(pos, "%d", &mounted_uid); if (mounted_uid == uidReal) { endmntent(f); return 1; } } else { fprintf(stderr, "Error: mountpoint doesn't have user_id= in options\n"); } } } fprintf(stderr, "Error: %s is not mounted\n", path); endmntent(f); return 0; } void mkdir_safe(char *dir) { if (mkdir(dir, 0700)) { if (errno == EEXIST) { /* OK, we've been told that this already exists. Make sure * nothing's mounted on top of it, so we aren't doing something * nasty */ if (is_mounted(dir)) { fprintf(stderr, "Error: can't bindmount under %s: already mounted\n", dir); exit(1); } } else { perror("Unable to mkdir() in /media"); exit(1); } } if (chown (dir, uidReal, 0)) { perror ("Unable to change owner of directory"); rmdir (dir); exit (1); } } /* * mainline */ int main(int argc, char **argv) { int umount = 0; struct passwd *pwent; char *mountpoint = NULL; /* command line supplied media name */ char mediamount[PATH_MAX]; /* fully pathed mountpoint in /media */ int option; static struct option long_opts[] = { {"help", 0, NULL, 'h'}, {"umount", 0, NULL, 'u'}, {NULL, 0, NULL, 0} }; /* Save our real userid */ uidReal = getuid(); /* Is the setuid bit set? */ if (geteuid()) { perror("Error: program not installed setuid root"); exit(1); } pwent = getpwuid(uidReal); if (!pwent) { perror("uid doesn't appear to have a valid passwd entry"); exit(1); } /* Command line handling */ do { option = getopt_long(argc, argv, "hu", long_opts, NULL); switch (option) { case -1: break; case 'h': usage(argv[0]); return 0; case 'u': umount = 1; break; default: fprintf(stderr, "%c: unknown option\n", option); exit(1); } } while (option != -1); /* get the optional mountpoint */ if (optind < argc) { mountpoint = strdup(argv[optind]); if (!mountpoint) { fprintf(stderr, "Error: couldn't get mountpoint"); exit(1); } } else { fprintf(stderr, "Error: no mountpoint supplied\n"); exit(1); } /* security: mountpoint cannot have any /'s in it, or be too long */ if (strlen(mountpoint) > 80 || index(mountpoint, '/')) { fprintf(stderr, "mountpoint name invalid.\n"); exit(1); } /* security: make sure pwd->pw_name doesn't have a '/' in it */ if (index(pwent->pw_name, '/')) { fprintf(stderr, "username invalid.\n"); exit(1); } if (!umount) { /* OK, name's a normal size, and looks valid. Begin creating the media * mount point. First, we need to create /media/uid */ snprintf(mediamount, sizeof(mediamount), "%s/%s", mediadir, pwent->pw_name); mkdir_safe(mediamount); } else { /* umount */ snprintf(mediamount, sizeof(mediamount), "%s/%s", mediadir, pwent->pw_name); if (rmdir(mediamount)) { /* If we get an ENOTEMPTY, we can pass it by, as there's other * mounts still there. */ if (errno != ENOTEMPTY) { perror("Unable to rmdir() users dir in /media"); exit(1); } } exit(0); } } ltspfs-1.4/src/common.h0000644000175000017500000000174212374427411015020 0ustar vagrantvagrant/* * defines */ #define OK 0 #define ERROR 1 #define FAIL -1 #define SEP 1 #define NOSEP 0 #define BACKLOG 5 /* We can be backlogged up to 5 connections */ /* * External variables */ extern int syslogopen; extern int debug; /* * function prototypes */ int bindsocket(int port); int opensocket(char *hostname, int port); int readn(register int fd, register char *ptr, register int nbytes); int writen(register int fd, register char *ptr, register int nbytes); int _readn(register int fd, register char *ptr, register int nbytes, int timeout_secs, void (*timeout_function)(), int doselect); int _writen(register int fd, register char *ptr, register int nbytes, int timeout_secs, void (*timeout_function)(), int doselect); int streq (char *s1, char *s2); void timeout(); int status_return(int sockfd, int result); void error_die(char *err); void info(const char *format, ...); void am_mount(char *mountpoint); void am_umount(char *mountpoint); ltspfs-1.4/src/common.c0000644000175000017500000002063612374427411015016 0ustar vagrantvagrant/* * common.c: support routines for ltspfs. * * Copyright Scott Balneaves, sbalneav@ltsp.org, 2005, 2006, 2007 * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, you can find it on the World Wide * Web at http://www.gnu.org/copyleft/gpl.html, or write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, * MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "ltspfs.h" #include "common.h" /* * Open up a server socket. */ extern int mounted; int bindsocket(int port) { struct sockaddr_in serv_addr; int s; /* * Open up our socket */ s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) error_die("Can't open socket"); /* * bind server port */ memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); serv_addr.sin_port = htons(port); if (bind(s, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) error_die("Can't bind port"); /* * Listen for connections */ if (listen(s, BACKLOG) < 0) error_die("Listen failed"); return s; } /* * Open up a client socket. */ int opensocket(char *hostname, int port) { struct sockaddr_in serv_addr; struct hostent *server; int s; /* * Open up our socket */ s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) { fprintf(stderr, "ERROR opening socket\n"); exit(1); } server = gethostbyname(hostname); if (server == NULL) { fprintf(stderr, "ERROR, no such host\n"); exit(1); } memset((char *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; bcopy((char *) server->h_addr, (char *) &serv_addr.sin_addr.s_addr, server->h_length); serv_addr.sin_port = htons(port); if (connect(s, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) { fprintf(stderr, "ERROR connecting\n"); exit(1); } return s; } /* * _readn: read n bytes from the socket * The select() function is used to handle timeouts. On a timeout, the * timeout_function is called. */ int _readn(register int fd, register char *ptr, register int nbytes, int timeout_secs, void (*timeout_function) (), int doselect) { int nleft, nread; int r; fd_set set; /* For select */ struct timeval ltspfs_timeout; /* Timeout */ struct timeval *timeout_ptr = <spfs_timeout; FD_ZERO(&set); FD_SET(fd, &set); if (!doselect) timeout_ptr = NULL; nleft = nbytes; while (nleft > 0) { ltspfs_timeout.tv_sec = timeout_secs; ltspfs_timeout.tv_usec = 0; r = select(FD_SETSIZE, &set, NULL, NULL, timeout_ptr); if (r < 0) return r; else if (r == 0) timeout_function(); /* this should never return */ else { nread = read(fd, ptr, nleft); if (nread < 0) return (nread); /* error, return < 0 */ else if (nread == 0) break; /* EOF */ nleft -= nread; ptr += nread; } } return (nbytes - nleft); /* return >= 0 */ } /* * writen: write n bytes to the socket */ int _writen(register int fd, register char *ptr, register int nbytes, int timeout_secs, void (*timeout_function) (), int doselect) { int nleft, nwritten; int r; fd_set set; /* For select */ struct timeval ltspfs_timeout; /* Timeout */ struct timeval *timeout_ptr = <spfs_timeout; FD_ZERO(&set); FD_SET(fd, &set); if (!doselect) timeout_ptr = NULL; nleft = nbytes; while (nleft > 0) { ltspfs_timeout.tv_sec = timeout_secs; ltspfs_timeout.tv_usec = 0; r = select(FD_SETSIZE, NULL, &set, NULL, timeout_ptr); if (r < 0) return r; else if (r == 0) timeout_function(); /* it's expected that this will never return */ else { nwritten = write(fd, ptr, nleft); if (nwritten <= 0) return (nwritten); /* error, return < 0 */ nleft -= nwritten; ptr += nwritten; } } return (nbytes - nleft); /* return >= 0 */ } /* * These are the user functions. They handle some things with less parameters. */ int readn(register int fd, register char *ptr, register int maxlen) { return _readn(fd, ptr, maxlen, LTSPFS_TIMEOUT, &timeout, TRUE); } int writen(register int fd, register char *ptr, register int nbytes) { return _writen(fd, ptr, nbytes, LTSPFS_TIMEOUT, &timeout, TRUE); } #ifdef AUTOMOUNT /* * Automounter. */ void am_mount(char *mountpoint) { struct stat buf; char *path[] = { "/usr/sbin/ltspfs_mount", mountpoint, NULL }; pid_t pid; int status; if (debug) info("am_mount called\n"); if (mounted) /* buh? */ return; /* * Check if the mount script exists before calling */ if (!stat(path[0], &buf)) { pid = fork(); if (pid == 0) { execv(path[0], path); perror("execv"); exit(1); } else if (pid < 0) { perror("fork"); exit(1); } wait(&status); } mounted = 1; } void am_umount(char *mountpoint) { struct stat buf; char *path[] = { "/usr/sbin/ltspfs_umount", mountpoint, NULL }; pid_t pid; int status; if (debug) info("am_umount called\n"); if (!mounted) /* buh? */ return; /* * Check if the umount script exists before calling */ if (!stat(path[0], &buf)) { pid = fork(); if (pid == 0) { execv(path[0], path); perror("execv"); exit(1); } else if (pid < 0) { perror("fork"); exit(1); } wait(&status); } mounted = 0; } #endif /* * status_return is used to simplify a bunch of functions that either * return a simple error, or an all clear error code. */ int status_return(int sockfd, int result) { XDR out; char output[BUFSIZ]; int i = 0; xdrmem_create(&out, output, BUFSIZ, XDR_ENCODE); xdr_int(&out, &i); /* bogus length */ if (result == FAIL) { i = LTSP_STATUS_FAIL; xdr_int(&out, &i); if (debug) info("status_return STATUS_FAIL\n"); xdr_int(&out, &errno); } else { i = LTSP_STATUS_OK; if (debug) info("status_return STATUS_OK\n"); xdr_int(&out, &i); } i = xdr_getpos(&out); /* get current position */ xdr_setpos(&out, 0); /* rewind to the beginning */ xdr_int(&out, &i); /* Write the correct length */ writen(sockfd, output, i); return 0; } /* * error_die: * Issue an error to syslog and die. */ void error_die(char *err) { info("%s (errno = %d : %s): Shutting down\n", err, errno, strerror(errno)); exit(ERROR); } /* * info: logs messages to syslog and/or stderr. * * Thanks to Petter Reinholdtsen for the heads up on the v... functions. */ void info(const char *format, ...) { va_list ap; va_start(ap, format); if (syslogopen) vsyslog(LOG_INFO, format, ap); if (debug) vfprintf(stderr, format, ap); va_end(ap); } ltspfs-1.4/scripts/0000755000175000017500000000000012374427411014253 5ustar vagrantvagrantltspfs-1.4/scripts/ltspfs_entry0000644000175000017500000001743012374427411016737 0ustar vagrantvagrant#!/bin/sh # ltspfs_entry # place in /lib/udev # $1 = mode (add/remove) # $2 = devicename # $3 = fstype (optional) ROOT=/var/run/drives FSTAB=/var/run/ltspfs_fstab # get default configuration: if [ -f /etc/ltspfs/ltspfsd.conf ]; then . /etc/ltspfs/ltspfsd.conf fi # get ltsp configuration: if [ -f /usr/share/ltsp/ltsp_config ]; then # Need to make sure lts.conf is rechecked if changed (eg ltsp-cluster) export LTSP_CONFIG=False . /usr/share/ltsp/ltsp_config fi boolean_is_true(){ case $1 in # match all cases of true|y|yes [Tt][Rr][Uu][Ee]|[Yy]|[Yy][Ee][Ss]) return 0 ;; *) return 1 ;; esac } if ! boolean_is_true "$LOCALDEV" ; then exit 0 fi call_ltspfsmounter() { action="$1" MOUNTPOINT=$2 for LDM_SOCKET in /var/run/ldm_socket_*; do if [ -S ${LDM_SOCKET} ]; then SERVER=${LDM_SOCKET##*_} /usr/bin/ssh -X -S ${LDM_SOCKET} ${SERVER} \ "/usr/sbin/ltspfsmounter ${MOUNTPOINT} $action" fi done if [ -x "/usr/sbin/ltspfsmounter" ]; then # Also call local ltspfsmounter if installed # Don't use xauth for local mounts export LTSPFS_NOAUTH=True # always run as root, so mounts appear in /media/root USER=root /usr/sbin/ltspfsmounter ${MOUNTPOINT} $action # Add kiosk support unset KIOSK_FOUND for i in 01 02 03 04 05 06 07 08 09 10 11 12; do eval SCREEN=\${SCREEN_$i} case "$SCREEN" in kiosk*) KIOSK_FOUND=True esac done [ -n "${KIOSK_FOUND}" ] && su - ltspkiosk -c "LTSPFS_NOAUTH=True /usr/sbin/ltspfsmounter ${MOUNTPOINT} $action" # if user's home directory is mounted via sshfs, assume we want a local # mount for localapps while read dev home fstype rest; do case "$fstype" in *sshfs*) export USER=${home##*/} if [ -n "${USER}" ]; then su ${USER} -c "LTSPFS_NOAUTH=True /usr/sbin/ltspfsmounter ${MOUNTPOINT} $action" fi ;; esac done /var/run/ltspfs_token fi if [ -d /run/systemd/system ] && [ -x /bin/systemctl ]; then # attempt to start ltspfsd the systemd way. systemctl start ltspfsd else # start up the ltspfsd daemon /usr/bin/ltspfsd fi echo $! >/var/run/ltspfsd.pid fi } verify_device() { DEVICENAME="$1" if [ -z "$ID_TYPE" ]; then # set an ID type for known devices case $DEVICENAME in fd?) # internal floppy drives don't set any information ID_TYPE=floppy ;; esac fi # set devices to be denied based on simple booleans: if boolean_is_true "$LOCALDEV_DENY_FLOPPY" ; then LOCALDEV_DENY="ID_TYPE:floppy,$LOCALDEV_DENY" fi if boolean_is_true "$LOCALDEV_DENY_USB" ; then LOCALDEV_DENY="ID_BUS:usb,$LOCALDEV_DENY" fi if boolean_is_true "$LOCALDEV_DENY_CD" ; then LOCALDEV_DENY="ID_TYPE:cd,$LOCALDEV_DENY" fi # default to not allowing internal disks, as it gives write access to root # filesystems: test -z "$LOCALDEV_DENY_INTERNAL_DISKS" && LOCALDEV_DENY_INTERNAL_DISKS=True if boolean_is_true "$LOCALDEV_DENY_INTERNAL_DISKS" ; then # IDE, SCSI (which should catch sata) LOCALDEV_DENY="ID_BUS:ata+ID_TYPE:disk,ID_BUS:scsi+ID_TYPE:disk,$LOCALDEV_DENY" fi # Deny mounting by sysfs attribute from udevinfo (in environment) # LOCALDEV_DENY is a comma-separated list of var=val pairs if [ -n "${LOCALDEV_DENY}" ]; then oldifs=$IFS IFS=, for deny_ruleset in ${LOCALDEV_DENY}; do count=0 IFS=+ for deny_rule in $deny_ruleset; do var=$(echo $deny_rule|cut -d: -f1) val=$(echo $deny_rule|cut -d: -f2) eval test="\${$var}" 2>/dev/null # If $test (the value of the udevinfo var) equals $val # (the value from LOCALDEV_DENY), then increment count of # matches if [ "$test" = "$val" ]; then count=$(($count+1)) else count=0 break fi done [ $count -gt 0 ] && exit 1 done unset IFS if [ -n "$oldifs" ]; then IFS=$oldifs fi fi # Make sure we have a valid FSTYPE [ -z "${FSTYPE}" ] && FSTYPE="${ID_FS_TYPE}" # Use udevinfo ID_FS_TYPE [ "${FSTYPE}" = "swap" ] && exit 1 # Don't mount swap partitions [ -z "${FSTYPE}" ] && exit 1 # That's empty too, die. } add_device() { DEVICENAME="$1" for link in $($udevinfo -q symlink -n ${DEVICENAME}) ; do case $link in cdrom*) LABEL="$link" break ;; esac done case $DEVICENAME in fd*) LABEL="floppy${DEVICENAME##fd}" ;; cdrom*) LABEL="${DEVICENAME}" ;; esac [ -z "${LABEL}" ] && LABEL=${ID_FS_LABEL} [ -z "${LABEL}" ] && LABEL="${ID_BUS}${ID_TYPE}-${DEVICENAME}" # Check for existing label with same name if [ -r ${FSTAB} ]; then while read DEV MOUNTPOINT TYPE OPTIONS DUMP PASS; do if [ "${DEV##*/}" = "$DEVICENAME" ]; then # Duplicate entry, don't bother to re-add. exit 0 elif [ "${MOUNTPOINT##*/}" = "${LABEL}" ]; then # Seems we already have a mountpoint with this name # Let's change the label LABEL="${LABEL}-${DEVICENAME}" fi done < ${FSTAB} fi # Invent $MOUNTPOINT MOUNTPOINT=$ROOT/$LABEL mkdir -p ${MOUNTPOINT} # Set "utf8" option if volume is vfat, iso9660, or ntfs (which support it) # This fixes filenames with international characters case ${FSTYPE} in vfat|iso9660|ntfs) LOCALDEV_MOUNT_OPTIONS=${LOCALDEV_MOUNT_OPTIONS:-"defaults,utf8"} ;; esac echo "/dev/${DEVICENAME} ${MOUNTPOINT} ${FSTYPE} ${LOCALDEV_MOUNT_OPTIONS:-defaults} 0 0" >> ${FSTAB} call_ltspfsmounter add ${MOUNTPOINT} } case "$1" in add|remove|add_disc|remove_disc) MODE=$1 shift ;; *) # backwards compatibility: # called as add_fstab_entry or remove_fstab_entry # Get basename of $0 MODE=${0##*/} ;; esac # Get basename of $1 DEVICENAME=${1##*/} FSTYPE=$2 if [ -x /sbin/udevadm ]; then udevinfo="/sbin/udevadm info" else udevinfo=udevinfo fi eval "export $($udevinfo -qenv -n ${DEVICENAME}|sed -e 's/=/="/' -e 's/$/"/')" case $MODE in add*) verify_device $DEVICENAME start_ltspfsd add_device $DEVICENAME ;; remove*) remove_device $DEVICENAME ;; *) exit 1 ;; esac ltspfs-1.4/scripts/Makefile.am0000644000175000017500000000070512374427411016311 0ustar vagrantvagrantdist_sbin_SCRIPTS = ltspfs_mount ltspfsmounter ltspfs_umount EXTRA_DIST = ltspfs_entry $(ldm_DATA) UDEV_LIB_PATH = @UDEV_LIB_PATH@ ldmdir = $(datadir)/ldm/rc.d ldm_DATA = ldm/X10-delayed-mounter \ ldm/X98-delayed-mounter ltspdir = $(datadir)/ltsp/xinitrc.d ltsp_DATA = xinitrc.d/I05-set-ltspfs_token install-data-local: $(mkdir_p) $(DESTDIR)$(UDEV_LIB_PATH) $(INSTALL_DATA) -m 0755 -D $(srcdir)/ltspfs_entry $(DESTDIR)$(UDEV_LIB_PATH) ltspfs-1.4/scripts/ltspfsmounter0000644000175000017500000000634512374427411017133 0ustar vagrantvagrant#!/usr/bin/python import os import sys from subprocess import call import re hook_dirs=list() def run_hooks(mode, mountpoint): executed_hooks=list() valid_filename=re.compile('^[a-zA-Z0-9\-_]*$') for dir in hook_dirs: if os.path.isdir(dir): # get a unique list of hook scripts hook_scripts=list(set(os.listdir(dir))) hook_scripts.sort() for script in hook_scripts: # only run the first script of a given name if executed_hooks.count(script) == 0 and valid_filename.match(script): executed_hooks.append(script) try: call([os.path.join(dir, script), mode, mountpoint]) except: # be very tolerant of failures with hook scripts pass def get_var(name): return os.environ.get(name) def add_ltspfsmount(conn, path, dev, mediaroot): lbmount_command = ['lbmount', dev] ltspfs_mount = ['ltspfs', conn+':'+path, mediaroot+'/'+dev] env = os.environ.copy() try: call(lbmount_command) os.mkdir(mediaroot+'/'+dev, 0700) run_hooks('add', os.path.join(mediaroot, dev)) except OSError, e: print >>sys.stderr, "suid mount failed:", e try: call(ltspfs_mount, env=env) except OSError, e: print >>sys.stderr, "mount failed:", e def remove_ltspfsmount(root, dev): lbumount_command=['lbmount', '--umount', dev] ltspfs_umount=['fusermount', '-uzq', root+'/'+dev] try: call(ltspfs_umount) run_hooks('remove', os.path.join(root, dev)) except OSError, e: print >>sys.stderr, "umount failed:", e try: os.rmdir(root+'/'+dev) call(lbumount_command) except OSError, e: print >>sys.stderr, "suid umount failed:", e def cleanup(user, mediaroot): known_mounts = open( '/proc/mounts', 'r' ).readlines() for mount in known_mounts: if mount.startswith('ltspfs') and user in mount: mountpoint=mount.split()[1] device=mountpoint.split('/')[-1] remove_ltspfsmount(mediaroot, device) run_hooks('cleanup', '') sys.exit(0) def main(): if len(sys.argv) < 3: print 'usage: %s mountpoint add|remove|cleanup' % sys.argv[0] sys.exit(1) if not os.access('/dev/fuse', 2): sys.stderr.write('/dev/fuse not writeable\n') sys.exit(1) # check if hook dirs are present for dir in ['/etc', '/usr/share', '/usr/lib']: dir=os.path.join(dir, 'ltspfs/mounter.d') if os.path.isdir(dir): hook_dirs.append(dir) path = sys.argv[1] command = sys.argv[2] username = get_var('USER') mediaroot = "/media/%s" % username if not get_var('SSH_CONNECTION'): conn = "127.0.0.1" os.putenv('SSH_CONNECTION', '127.0.0.1') else: conn = get_var('SSH_CONNECTION').split()[0] dev = path.split('/')[-1] if command=='add': add_ltspfsmount(conn, path, dev, mediaroot) elif command=='remove': remove_ltspfsmount(mediaroot, dev) elif command=='cleanup': cleanup(username, mediaroot) else: print 'unknown command' if __name__ == "__main__": main() ltspfs-1.4/scripts/ltspfs_umount0000644000175000017500000000030012374427411017111 0ustar vagrantvagrant#!/bin/sh [ -n "$1" ] || { echo "Usage: $0 " exit 1 } grep $1 /var/run/ltspfs_fstab | while read DEV MOUNTPOINT TYPE OPTIONS DUMP PASS; do umount ${MOUNTPOINT} done ltspfs-1.4/scripts/ltspfs_mount0000644000175000017500000000126612374427411016740 0ustar vagrantvagrant#!/bin/sh [ -n "$1" ] || { echo "Usage: $0 " exit 1 } # ltspfs_mount, passed a directory name, used in /var/run/ltspfs_fstab. grep "$1" /var/run/ltspfs_fstab | while read DEV MOUNTPOINT TYPE OPTIONS DUMP PASS; do [ -d ${MOUNTPOINT} ] || mkdir ${MOUNTPOINT} # Check if it's already mounted, if not try to mount if ! mountpoint -q ${MOUNTPOINT} && ! mount -t ${TYPE} -o ${OPTIONS} ${DEV} ${MOUNTPOINT} ; then # Call ltspfs_entry remove if the mount fails and is not a floppy drive case $MOUNTPOINT in *floppy*) ;; *) [ -z "$(grep ${MOUNTPOINT} /proc/mounts)" ] && /lib/udev/ltspfs_entry remove ${DEV} ;; esac fi done ltspfs-1.4/scripts/xinitrc.d/0000755000175000017500000000000012374427411016155 5ustar vagrantvagrantltspfs-1.4/scripts/xinitrc.d/I05-set-ltspfs_token0000644000175000017500000000064712374427411021746 0ustar vagrantvagrant# # sourced with . # # Set authentication token for ltspfs in the session # if boolean_is_true "$LOCALDEV" ; then ltspfs_token=/var/run/ltspfs_token if [ ! -f "$ltspfs_token" ]; then # ltspfsd may not have been started yet if no devices are plugged in, # so create the token now. mcookie > "$ltspfs_token" fi xprop -root -f LTSPFS_TOKEN 8s -set LTSPFS_TOKEN $(cat $ltspfs_token) fi ltspfs-1.4/scripts/ldm/0000755000175000017500000000000012374427411015027 5ustar vagrantvagrantltspfs-1.4/scripts/ldm/X10-delayed-mounter0000644000175000017500000000107312374427411020417 0ustar vagrantvagrant# # sourced with . # # Script to automatically add what's in the ltspfs_fstab on login. # if [ -f /var/run/ltspfs_fstab ]; then while read DEV DIR TYPE OPTIONS DUMP PASS; do LTSPFS_MOUNTS="$LTSPFS_MOUNTS $DIR" done < /var/run/ltspfs_fstab for DIR in $LTSPFS_MOUNTS ; do ssh -X -S ${LDM_SOCKET} ${LDM_SERVER} "/usr/sbin/ltspfsmounter ${DIR} add" if [ -x /usr/sbin/ltspfsmounter ]; then unset SSH_CONNECTION su ${LDM_USERNAME} -c "LTSPFS_NOAUTH=True /usr/sbin/ltspfsmounter ${DIR} add" fi done fi ltspfs-1.4/scripts/ldm/X98-delayed-mounter0000644000175000017500000000037012374427411020436 0ustar vagrantvagrant# # sourced with . # # Script to cleanup local ltspfsmounter # if [ -f /var/run/ltspfs_fstab ] && [ -x /usr/sbin/ltspfsmounter ]; then unset SSH_CONNECTION su ${LDM_USERNAME} -c "LTSPFS_NOAUTH=True /usr/sbin/ltspfsmounter all cleanup" fi ltspfs-1.4/man/0000755000175000017500000000000012374427411013337 5ustar vagrantvagrantltspfs-1.4/man/Makefile.am0000644000175000017500000000013412374427411015371 0ustar vagrantvagrantdist_man_MANS = lbmount.1 ltspfs.1 ltspfsd.1 ltspfsmounter.1 ltspfs_mount.1 ltspfs_umount.1 ltspfs-1.4/man/ltspfsmounter.10000644000175000017500000000227412374427411016353 0ustar vagrantvagrant.TH "ltspfsmounter" "1" .SH "NAME" ltspfsmounter \(em mount fuse based filesystems .SH "SYNOPSIS" .PP \fBltspfsmounter\fR .SH "DESCRIPTION" .PP This manual page documents briefly the \fBltspfsmounter\fR command. .PP \fBltspfsmounter\fR is a program that mounts fuse based filesystems that got exported by \fBltspfsd\fR from a thin client it uses ltspfs and the lbmount suid wrapper to bind mount them to /media. This program is not intended to be run manually, but by udev scripts from the ltspfsd package installed on a thin client. .SH "OPTIONS" .PP Usage: ltspfsmounter mountpoint [add|remove|cleanup] .SH "SEE ALSO" .PP ltspfs (1). lbmount (1). .SH "AUTHOR" .PP This manual page was written by Oliver Grawert ogra@ubuntu.com for the \fBDebian\fP system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. .\" created by instant / docbook-to-man, Tue 29 Aug 2006, 11:56 ltspfs-1.4/man/ltspfsd.10000644000175000017500000000252112374427411015100 0ustar vagrantvagrant.TH "LTSPFSD" "1" .SH "NAME" ltspfsd \(em daemon to serve fuse based filesystems over the network .SH "SYNOPSIS" .PP \fBltspfsd\fR [\fB-a \fP] [\fB-r \fP] [\fB-d \fP] .SH "DESCRIPTION" .PP This manual page documents briefly the \fBltspfsd\fR command. .PP \fBltspfsd\fR is a program that provides access to local devices over the network from a ltspfs client .SH "OPTIONS" .IP "\fB-a\fP " 10 for no authentication. The server will simply accept the XAUTH packet sent down, and always return OK. .IP "\fB-r\fP " 10 for read only. Specifying this causes the ltspfsd to behave as a readonly server, and won't allow any modification to the media. .IP "\fB-d\fP " 10 for debug. Server won't fork into the background, and will print messages to stderr. .SH "SEE ALSO" .PP ltspfs (1). .SH "AUTHOR" .PP This manual page was written by Oliver Grawert ogra@ubuntu.com for the \fBDebian\fP system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. .\" created by instant / docbook-to-man, Fri 25 Aug 2006, 21:38 ltspfs-1.4/man/ltspfs_umount.10000644000175000017500000000155012374427411016344 0ustar vagrantvagrant.TH "ltspfs_umount" "1" "20080825" .SH "NAME" ltspfs_umount \(em unmounts local filesystem exported over ltspfs .SH "SYNOPSIS" .PP \fBltspfs_umount\fR .SH "DESCRIPTION" .PP \fBltspfs_umount\fR is called by ltspfsd(1) when an ltspfs filesystem is no longer used or idle. This program is not intended to be run manually. .SH "SEE ALSO" .PP ltspfs(1), ltspfsd(1), ltspfs_mount(1) .SH "AUTHOR" .PP This manual page was written by Vagrant Cascadian vagrant@freegeek.org for the \fBDebian\fP system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. ltspfs-1.4/man/ltspfs_mount.10000644000175000017500000000160712374427411016162 0ustar vagrantvagrant.TH "ltspfs_mount" "1" "20080825" .SH "NAME" ltspfs_mount \(em mounts local filesystem exported over ltspfs .SH "SYNOPSIS" .PP \fBltspfs_mount\fR .SH "DESCRIPTION" .PP \fBltspfs_mount\fR is called by ltspfsd(1) when an ltspfs filesystem needs access to the local mount and it is not already mounted. This program is not intended to be run manually. .SH "SEE ALSO" .PP ltspfs(1), ltspfsd(1), ltspfs_umount(1) .SH "AUTHOR" .PP This manual page was written by Vagrant Cascadian vagrant@freegeek.org for the \fBDebian\fP system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. ltspfs-1.4/man/ltspfs.10000644000175000017500000000167512374427411014745 0ustar vagrantvagrant.TH "LTSPFS" "1" .SH "NAME" ltspfs \(em mount fuse based filesystems .SH "SYNOPSIS" .PP \fBltspfs\fR .SH "DESCRIPTION" .PP This manual page documents briefly the \fBltspfs\fR command. .PP \fBltspfs\fR is a program that mounts fuse based filesystems that got exported by \fBltspfsd\fR .SH "OPTIONS" .PP Usage: ltspfs host:/dir/to/mount /mountpoint [fuse options] .SH "SEE ALSO" .PP ltspfsd (1). .SH "AUTHOR" .PP This manual page was written by Oliver Grawert ogra@ubuntu.com for the \fBDebian\fP system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. .\" created by instant / docbook-to-man, Tue 29 Aug 2006, 11:56 ltspfs-1.4/man/lbmount.10000644000175000017500000000177712374427411015115 0ustar vagrantvagrant.TH "lbmount" "1" .SH "NAME" lbmount \(em mount ltspfs based filesystems to a user owned subdir in /media .SH "SYNOPSIS" .PP \fBlbmount\fR .SH "DESCRIPTION" .PP This manual page documents briefly the \fBlbmount\fR command. .PP \fBlbmount\fR is a suid wrapper that creates mountpoints in /media and bind mounts ltspfs mounted devices to there \fBlbmount\fR .SH "OPTIONS" .PP Usage: lbmount [\-\-umount] mediadir .SH "SEE ALSO" .PP ltspfs (1). ltspfsmounter (1). .SH "AUTHOR" .PP This manual page was written by Oliver Grawert ogra@ubuntu.com for the \fBDebian\fP system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the GNU General Public License, Version 2 any later version published by the Free Software Foundation. .PP On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. .\" created by instant / docbook-to-man, Tue 29 Aug 2006, 11:56 ltspfs-1.4/init-ltsp.d/0000755000175000017500000000000012374427411014731 5ustar vagrantvagrantltspfs-1.4/init-ltsp.d/50-ltspfsd-udev-rules0000644000175000017500000000037712374427411020655 0ustar vagrantvagrant# configure ltspfs udev rules. if boolean_is_true "$LOCALDEV" ; then if [ -f /usr/share/ltspfs/udev/ltspfsd.rules ]; then mkdir -p /etc/udev/rules.d/ ln -s /usr/share/ltspfs/udev/ltspfsd.rules /etc/udev/rules.d/ltspfsd.rules fi fi ltspfs-1.4/doc/0000755000175000017500000000000012374427411013331 5ustar vagrantvagrantltspfs-1.4/doc/examples/0000755000175000017500000000000012374427411015147 5ustar vagrantvagrantltspfs-1.4/doc/examples/notify0000755000175000017500000000074312374427411016411 0ustar vagrantvagrant#!/usr/bin/python # Issue notification on device insertion or removal. Useful for desktops such # as KDE or LXDE which do not automatically display icons for ltspfs mounts. # # Requires python-notify to be installed. import sys mode=sys.argv[1] ltspfs_mount=sys.argv[2] if mode == 'cleanup': # do nothing in cleanup mode. sys.exit(0) import pynotify if not pynotify.init("ltspfs"): sys.exit(1) n = pynotify.Notification("ltspfs","%s" % mode+' '+ltspfs_mount) n.show() ltspfs-1.4/doc/examples/kde-desktop-icons0000755000175000017500000000314712374427411020425 0ustar vagrantvagrant#!/usr/bin/python # example ltspfs hook to add icons on the KDE Desktop. # based on a patch by Klaus Ade Johnstad: http://bugs.debian.org/459369 # to use this hook, install this in /etc/ltspfs/mounter.d/ and mark it as # executable. import sys import os mode=sys.argv[1] if mode != 'cleanup': mountpoint=sys.argv[2] dev=mountpoint.split('/')[-1] def get_desktop_file_path(dev): # FIXME: respect XDG settings when Desktop is localized return os.path.expanduser("~/Desktop/ltspfsmounter--%s.desktop" % (dev)) if mode == 'add': desktop_file_s = get_desktop_file_path(dev) if os.path.exists(desktop_file_s): print >>sys.stderr, ".desktop file already exists, skipping" sys.exit(1) if dev.startswith('usb'): icon = 'usbpendrive_mount' elif dev.startswith('ata'): icon = 'hdd_mount' elif dev.startswith('floppy'): icon = '3floppy_mount' elif dev.startswith('cdrom'): icon = 'cdrom_mount' else: icon = 'usbpendrive_mount' try: desktop_file = open(desktop_file_s, 'w') desktop_file.write('[Desktop Entry]\nEncoding=UTF-8\nName=%s\nIcon=%s\nType=Link\nURL=%s\n' % (dev, icon, mountpoint)) desktop_file.close() except IOError, e: print >>sys.stderr, 'unable to create desktop file:', e elif mode == 'remove': desktop_file_s = get_desktop_file_path(dev) if os.path.exists(desktop_file_s): os.unlink(desktop_file_s) elif mode == 'cleanup': import glob for filename in glob.glob(os.path.expanduser('~/Desktop/') + 'ltspfsmounter--*.desktop'): os.unlink(filename) ltspfs-1.4/doc/examples/ltspfsd.service0000644000175000017500000000013512374427411020207 0ustar vagrantvagrant[Unit] Description=LTSP Filesystem Daemon [Service] Type=forking ExecStart=/usr/bin/ltspfsd