diff --git a/install.sh b/install.sh index 4a6c3904..de226be4 100755 --- a/install.sh +++ b/install.sh @@ -178,6 +178,7 @@ sudo cp ~/.dotfiles/root/dwm.desktop /usr/share/xsessions sudo cp ~/.dotfiles/root/nancyj.flf /usr/share/figlet/fonts sudo cp ~/.dotfiles/root/quark.service /usr/lib/systemd/system sudo cp ~/.dotfiles/root/kdialog /usr/local/bin/kdialog +sudo cp ~/.dotfiles/root/udevil.conf /etc/udevil/udevil.conf sudo chmod +x /usr/local/bin/kdialog sudo systemctl daemon-reload sudo systemctl enable quark diff --git a/root/udevil.conf b/root/udevil.conf new file mode 100644 index 00000000..ae118c0b --- /dev/null +++ b/root/udevil.conf @@ -0,0 +1,335 @@ +############################################################################## +# +# udevil configuration file /etc/udevil/udevil.conf +# +# This file controls what devices, networks, and files users may mount and +# unmount via udevil (set suid). +# +# IMPORTANT: IT IS POSSIBLE TO CREATE SERIOUS SECURITY PROBLEMS IF THIS FILE +# IS MISCONFIGURED - EDIT WITH CARE +# +# Note: For greater control for specific users, including root, copy this +# file to /etc/udevil/udevil-user-USERNAME.conf replacing USERNAME with the +# desired username (eg /etc/udevil/udevil-user-jim.conf). +# +# Format: +# OPTION = VALUE[, VALUE, ...] +# +# DO NOT USE QUOTES except literally +# Lines beginning with # are ignored +# +############################################################################## + + +# To log all uses of udevil, set log_file to a file path: +# log_file = /var/log/udevil.log + +# Approximate number of days to retain log entries (0=forever, max=60): +log_keep_days = 10 + + +# allowed_types determines what fstypes can be passed by a user to the u/mount +# program, what device filesystems may be un/mounted implicitly, and what +# network filesystems may be un/mounted. +# It may also include the 'file' keyword, indicating that the user is allowed +# to mount files (eg an ISO file). The $KNOWN_FILESYSTEMS variable may +# be included to include common local filesystems as well as those listed in +# /etc/filesystems and /proc/filesystems. +# allowed_types_USERNAME, if present, is used to override allowed_types for +# the specific user 'USERNAME'. For example, to allow user 'jim' to mount +# only vfat filesystems, add: +# allowed_types_jim = vfat +# Setting allowed_types = * does NOT allow all types, as this is a security +# risk, but does allow all recognized types. +# allowed_types = $KNOWN_FILESYSTEMS, file, cifs, smbfs, nfs, curlftpfs, ftpfs, sshfs, davfs, tmpfs, ramfs +allowed_types = $KNOWN_FILESYSTEMS, file, cifs + + +# allowed_users is a list of users permitted to mount and unmount with udevil. +# Wildcards (* or ?) may be used in the usernames. To allow all users, +# specify "allowed_users=*". UIDs may be included using the form UID=1000. +# For example: allowed_users = carl, UID=1000, pre* +# Also note that permission to execute udevil may be limited to users belonging +# to the group that owns /usr/bin/udevil, such as 'plugdev' or 'storage', +# depending on installation. +# allowed_users_FSTYPE, if present, is used to override allowed_users when +# mounting or unmounting a specific fstype (eg nfs, ext3, file). +# Note that when mounting a file, fstype will always be 'file' regardless of +# the internal fstype of the file. +# For example, to allow only user 'bob' to mount nfs shares, add: +# allowed_users_nfs = bob +# The root user is NOT automatically allowed to use udevil in some cases unless +# listed here (except for unmounting anything or mounting fstab devices). +allowed_users = * + + +# allowed_groups is a list of groups permitted to mount and unmount with +# udevil. The user MUST belong to at least one of these groups. Wildcards +# or GIDs may NOT be used in group names, but a single * may be used to allow +# all groups. +# Also note that permission to execute udevil may be limited to users belonging +# to the group that owns /usr/bin/udevil, such as 'plugdev' or 'storage', +# depending on installation. +# allowed_groups_FSTYPE, if present, is used to override allowed_groups when +# mounting or unmounting a specific fstype (eg nfs, ext3, file). For example, +# to allow only members of the 'network' group to mount smb and nfs shares, +# use both of these lines: +# allowed_groups_smbfs = network +# allowed_groups_nfs = network +# The root user is NOT automatically allowed to use udevil in some cases unless +# listed here (except for unmounting anything or mounting fstab devices). +allowed_groups = * + + +# allowed_media_dirs specifies the media directories in which user mount points +# may be located. The first directory which exists and does not contain a +# wildcard will be used as the default media directory (normally /media or +# /media/$USER). +# The $USER variable, if included, will be replaced with the username of the +# user running udevil. Wildcards may also be used in any directory EXCEPT the +# default. Wildcards will not match a /, except a /** suffix for recursion. +# allowed_media_dirs_FSTYPE, if present, is used to override allowed_media_dirs +# when mounting or unmounting a specific fstype (eg ext2, nfs). For example, +# to cause /media/network to be used as the default media directory for +# nfs and ftpfs mounts, use these two lines: +# allowed_media_dirs_nfs = /media/network, /media, /media/$USER +# allowed_media_dirs_ftpfs = /media/network, /media, /media/$USER +# NOTE: If you want only the user who mounted a device to have access to it +# and be allowed to unmount it, specify /media/$USER as the first +# allowed media directory (only /media/$USER is created on demand). +# IMPORTANT: If an allowed file is mounted to a media directory, the user may +# be permitted to unmount its associated loop device even though internal. +# INCLUDING /MNT HERE IS NOT RECOMMENDED. ALL ALLOWED MEDIA DIRECTORIES +# SHOULD BE OWNED AND WRITABLE ONLY BY ROOT. +allowed_media_dirs = /media/$USER, /run/media/$USER + + +# allowed_devices is the first criteria for what block devices users may mount +# or unmount. If a device is not listed in allowed_devices, it cannot be +# un/mounted (unless in fstab). However, even if a device is listed, other +# factors may prevent its use. For example, access to system internal devices +# will be denied to normal users even if they are included in allowed_devices. +# allowed_devices_FSTYPE, if present, is used to override allowed_devices when +# mounting or unmounting a specific fstype (eg ext3, ntfs). For example, to +# prevent all block devices containing an ext4 filesystem from being +# un/mounted use: +# allowed_devices_ext4 = +# Note: Wildcards may be used, but a wildcard will never match a /, except +# for "allowed_devices=*" which allows any device. The recommended setting is +# allowed_devices = /dev/* +# WARNING: ALLOWING USERS TO MOUNT DEVICES OUTSIDE OF /dev CAN CAUSE SERIOUS +# SECURITY PROBLEMS. DO NOT ALLOW DEVICES IN /dev/shm +allowed_devices = /dev/* + + +# allowed_internal_devices causes udevil to treat any listed block devices as +# removable, thus allowing normal users to un/mount them (providing they are +# also listed in allowed_devices). +# allowed_internal_devices_FSTYPE, if present, is used to override +# allowed_internal_devices when mounting or unmounting a specific fstype +# (eg ext3, ntfs). For example, to allow block devices containing a vfat +# filesystem to be un/mounted even if they are system internal devices, use: +# allowed_internal_devices_vfat = /dev/sdb* +# Some removable esata drives look like internal drives to udevil. To avoid +# this problem, they can be treated as removable with this setting. +# WARNING: SETTING A SYSTEM DEVICE HERE CAN CAUSE SERIOUS SECURITY PROBLEMS. +# allowed_internal_devices = + + +# allowed_internal_uuids and allowed_internal_uuids_FSTYPE work similarly to +# allowed_internal_devices, except that UUIDs are specified instead of devices. +# For example, to allow un/mounting of an internal filesystem based on UUID: +# allowed_internal_uuids = cc0c4489-8def-1e5b-a304-ab87c3cb626c0 +# WARNING: SETTING A SYSTEM DEVICE HERE CAN CAUSE SERIOUS SECURITY PROBLEMS. +# allowed_internal_uuids = + + +# forbidden_devices is used to prevent block devices from being un/mounted +# even if other settings would allow them (except devices in fstab). +# forbidden_devices_FSTYPE, if present, is used to override +# forbidden_devices when mounting or unmounting a specific fstype +# (eg ext3, ntfs). For example, to prevent device /dev/sdd1 from being +# mounted when it contains an ntfs filesystem, use: +# forbidden_devices_ntfs = /dev/sdd1 +# NOTE: device node paths are canonicalized before being tested, so forbidding +# a link to a device will have no effect. +forbidden_devices = + + +# allowed_networks determines what hosts may be un/mounted by udevil users when +# using nfs, cifs, smbfs, curlftpfs, ftpfs, or sshfs. Hosts may be specified +# using a hostname (eg myserver.com) or IP address (192.168.1.100). +# Wildcards may be used in hostnames and IP addresses, but CIDR notation +# (192.168.1.0/16) is NOT supported. IP v6 is supported. For example: +# allowed_networks = 127.0.0.1, 192.168.1.*, 10.0.0.*, localmachine, *.okay.com +# Or, to prevent un/mounting of any network shares, set: +# allowed_networks = +# allowed_networks_FSTYPE, if present, is used to override allowed_networks +# when mounting or unmounting a specific network fstype (eg nfs, cifs, sshfs, +# curlftpfs). For example, to limit nfs and samba shares to only local +# networks, use these two lines: +# allowed_networks_nfs = 192.168.1.*, 10.0.0.* +# allowed_networks_cifs = 192.168.1.*, 10.0.0.* +allowed_networks = * + + +# forbidden_networks and forbidden_networks_FSTYPE are used to specify networks +# that are never allowed, even if other settings allow them (except fstab). +# NO REVERSE LOOKUP IS PERFORMED, so including bad.com will only have an effect +# if the user uses that hostname. IP lookup is always performed, so forbidding +# an IP address will also forbid all corresponding hostnames. +forbidden_networks = + + +# allowed_files is used to determine what files in what directories may be +# un/mounted. A user must also have read permission on a file to mount it. +# Note: Wildcards may be used, but a wildcard will never match a /, except +# for "allowed_files=*" which allows any file, and a /** suffix, which matches +# all files recursively. +# For example, to allow only files in the /share directory to be mounted, use: +# allowed_files = /share/* +# To allow all files in the /share directory AND all subdirectories use: +# allowed_files = /share/** +# NOTE: Specifying allowed_files_FSTYPE will NOT work because the fstype of +# files is always 'file'. +allowed_files = * + + +# forbidden_files is used to specify files that are never allowed, even if +# other settings allow them (except fstab). Specify a full path. +# Note: Wildcards may be used, but a wildcard will never match a /, except +# for "forbidden_files = *", or a /** suffix, which matches all recursively. +# NOTE: file paths are canonicalized before being tested, so forbidding +# a link to a file will have no effect. +forbidden_files = + + +# default_options specifies what options are always included when performing +# a mount, in addition to any options the user may specify. +# Note: When a device is present in /etc/fstab, and the user does not specify +# a mount point, the device is mounted with normal user permissions using +# the fstab entry, without these options. +# default_options_FSTYPE, if present, is used to override default_options +# when mounting a specific fstype (eg ext2, nfs). +# The variables $USER, $UID, and $GID are changed to the user's username, UID, +# and GID. +# FOR GOOD SECURITY, default_options SHOULD ALWAYS INCLUDE: nosuid,noexec,nodev +# WARNING: OPTIONS PRESENT OR MISSING CAN CAUSE SERIOUS SECURITY PROBLEMS. +default_options = nosuid, noexec, nodev, noatime +default_options_file = nosuid, noexec, nodev, noatime, uid=$UID, gid=$GID, ro +# mount iso9660 with 'ro' to prevent mount read-only warning +default_options_iso9660 = nosuid, noexec, nodev, noatime, uid=$UID, gid=$GID, ro, utf8 +default_options_udf = nosuid, noexec, nodev, noatime, uid=$UID, gid=$GID +default_options_vfat = nosuid, noexec, nodev, noatime, fmask=0133, dmask=0022, uid=$UID, gid=$GID, utf8 +default_options_exfat = nosuid, noexec, nodev, noatime, umask=0077, uid=$UID, gid=$GID, iocharset=utf8, namecase=0, nonempty +default_options_msdos = nosuid, noexec, nodev, noatime, fmask=0133, dmask=0022, uid=$UID, gid=$GID +default_options_umsdos = nosuid, noexec, nodev, noatime, fmask=0133, dmask=0022, uid=$UID, gid=$GID +default_options_ntfs = nosuid, noexec, nodev, noatime, fmask=0133, uid=$UID, gid=$GID, utf8 +default_options_cifs = nosuid, noexec, nodev, uid=$UID, gid=$GID +default_options_smbfs = nosuid, noexec, nodev, uid=$UID, gid=$GID +default_options_sshfs = nosuid, noexec, nodev, noatime, uid=$UID, gid=$GID, nonempty, allow_other +default_options_curlftpfs = nosuid, noexec, nodev, noatime, uid=$UID, gid=$GID, nonempty, allow_other +default_options_ftpfs = nosuid, noexec, nodev, noatime, uid=$UID, gid=$GID +default_options_davfs = nosuid, noexec, nodev, uid=$UID, gid=$GID +default_options_tmpfs = nosuid, noexec, nodev, noatime, uid=$UID, gid=$GID +default_options_ramfs = nosuid, noexec, nodev, noatime, uid=$UID, gid=$GID + + +# allowed_options determines all options that a user may specify when mounting. +# All the options used in default_options above must be included here too, or +# they will be rejected. If the user attempts to use an option not included +# here, an error will result. Wildcards may be used. +# allowed_options_FSTYPE, if present, is used to override allowed_options +# when mounting a specific fstype (eg ext2, nfs). +# The variables $USER, $UID, and $GID are changed to the user's username, UID, +# and GID. +# If you want to forbid remounts, remove 'remount' from here. +# WARNING: OPTIONS HERE CAN CAUSE SERIOUS SECURITY PROBLEMS - CHOOSE CAREFULLY +allowed_options = nosuid, noexec, nodev, noatime, fmask=0133, dmask=0022, uid=$UID, gid=$GID, ro, rw, sync, flush, iocharset=*, utf8, remount +allowed_options_nfs = nosuid, noexec, nodev, noatime, ro, rw, sync, remount, port=*, rsize=*, wsize=*, hard, proto=*, timeo=*, retrans=* +allowed_options_cifs = nosuid, noexec, nodev, ro, rw, remount, port=*, user=*, username=*, pass=*, password=*, guest, domain=*, uid=$UID, gid=$GID, credentials=* +allowed_options_smbfs = nosuid, noexec, nodev, ro, rw, remount, port=*, user=*, username=*, pass=*, password=*, guest, domain=*, uid=$UID, gid=$GID, credentials=* +allowed_options_sshfs = nosuid, noexec, nodev, noatime, ro, rw, uid=$UID, gid=$GID, nonempty, allow_other, idmap=user, BatchMode=yes, port=* +allowed_options_curlftpfs = nosuid, noexec, nodev, noatime, ro, rw, uid=$UID, gid=$GID, nonempty, allow_other, user=* +allowed_options_ftpfs = nosuid, noexec, nodev, noatime, ro, rw, port=*, user=*, pass=*, root=*, uid=$UID, gid=$GID +allowed_options_exfat = nosuid, noexec, nodev, noatime, fmask=0133, dmask=0022, uid=$UID, gid=$GID, umask=0077, namecase=*, ro, rw, sync, flush, iocharset=*, remount, nonempty + + +# mount_point_mode, if present and set to a non-empty value, will cause udevil +# to set the mode (permissions) on the moint point after mounting If not +# specified or if left empty, the mode is not changed. Mode must be octal +# starting with a zero (0755). +# mount_point_mode_FSTYPE, if present, is used to override mount_point_mode +# when mounting a specific fstype (eg ext2, nfs). +# NOT SETTING A MODE CAN HAVE SECURITY IMPLICATIONS FOR SOME FSTYPES +mount_point_mode = 0755 +# don't set a mode for some types: +mount_point_mode_sshfs = +mount_point_mode_curlftpfs = +mount_point_mode_ftpfs = + + +# Use the settings below to change the default locations of programs used by +# udevil, or (advanced topic) to redirect commands to your scripts. +# When substituting scripts, make sure they are root-owned and accept the +# options used by udevil (for example, the mount_program must accept --fake, +# -o, -v, and other options valid to mount.) +# Be sure to specify the full path and include NO OPTIONS or other arguments. +# These programs may also be specified as configure options when building +# udevil. +# THESE PROGRAMS ARE RUN AS ROOT +# mount_program = /bin/mount +# umount_program = /bin/umount +# losetup_program = /sbin/losetup +# setfacl_program = /usr/bin/setfacl + + +# validate_exec specifies a program or script which provides additional +# validation of a mount or unmount command, beyond the checks performed by +# udevil. The program is run as a normal user (if root runs udevil, +# validate_exec will NOT be run). The program is NOT run if the user is +# mounting a device without root privileges (a device in fstab). +# The program is passed the username, a printable description of what is +# happening, and the entire udevil command line as the first three arguments. +# The program must return an exit status of 0 to allow the mount or unmount +# to proceed. If it returns non-zero, the user will be denied permission. +# For example, validate_exec might specify a script which notifies you +# of the command being run, or performs additional steps to authenticate the +# user. +# Specify a full path to the program, with NO options or arguments. +# validate_exec = + + +# validate_rootexec works similarly to validate_exec, except that the program +# is run as root. validate_rootexec will also be run if the root user runs +# udevil. If both validate_exec and validate_rootexec are specified, +# validate_rootexec will run first, followed by validate_exec. +# The program must return an exit status of 0 to allow the mount or unmount +# to proceed. If it returns non-zero, the user will be denied permission. +# Unless you are familiar with writing root scripts, it is recommended that +# rootexec settings NOT be used, as it is easy to inadvertently open exploits. +# THIS PROGRAM IS ALWAYS RUN AS ROOT, even if the user running udevil is not. +# validate_rootexec = + + +# success_exec is run after a successful mount, remount, or unmount. The +# program is run as a normal user (if root runs udevil, success_exec +# will NOT be run). +# The program is passed the username, a printable description of what action +# was taken, and the entire udevil command line as the first three arguments. +# The program's exit status is ignored. +# For example, success_exec might run a script which informs you of what action +# was taken, and might perform further actions. +# Specify a full path to the program, with NO options or arguments. +# success_exec = + + +# success_rootexec works similarly to success_exec, except that the program is +# run as root. success_rootexec will also be run if the root user runs udevil. +# If both success_exec and success_rootexec are specified, success_rootexec +# will run first, followed by success_exec. +# Unless you are familiar with writing root scripts, it is recommended that +# rootexec settings NOT be used, as it is easy to inadvertently open exploits. +# THIS PROGRAM IS ALWAYS RUN AS ROOT, even if the user running udevil is not. +# success_rootexec = + diff --git a/scripts/devmon b/scripts/devmon new file mode 100755 index 00000000..1ca1d8f6 --- /dev/null +++ b/scripts/devmon @@ -0,0 +1,1266 @@ +#!/bin/bash +# Script Name: devmon http://igurublog.wordpress.com/downloads/script-devmon/ +# Requires: udevil bash>=4 Recommended: eject spacefm|zenity +# Optional: udisks v1 may be substituted for udevil +# If udevil is not set suid, udisks v1/v2 or pmount is required +# License: GNU GENERAL PUBLIC LICENSE Version 3 http://www.gnu.org/licenses/gpl-3.0.txt +# Thanks to Bernard Baeyens (berbae) for code from udisksvm script + +#========================================================================= + +defaultmountoptions="noexec,nosuid,nodev,noatime" + +#========================================================================= + +help() +{ + cat << EOF +devmon version 1.1.8 (distributed with udevil) +Automounts and unmounts optical and removable drives +Requires: udevil bash>=4 Also Recommended: eject spacefm|zenity +Optional: udisks v1 may be substituted for udevil + If udevil is not set suid, udisks v1/v2 or pmount is required +Usage: devmon [AUTOMOUNT-OPTIONS] # Run as daemon to automount + devmon [MOUNT-OPTIONS] # Or run as client to manually un/mount +AUTOMOUNT-OPTIONS: (these can be used only in daemon mode) +--exec-on-device DEVICE "COMMAND" Execute COMMAND after mounting DEVICE +--exec-on-label "LABEL" "COMMAND" Execute COMMAND after mounting LABEL +--exec-on-video "COMMAND" Execute COMMAND after video DVD mount +--exec-on-audio "COMMAND" Execute COMMAND after audio CD insertion +--exec-on-disc "COMMAND" Execute COMMAND after data CD/DVD mount +--exec-on-drive "COMMAND" Execute COMMAND after drive mount +--exec-on-unmount "COMMAND" Execute COMMAND after unmount +--exec-on-remove "COMMAND" Execute COMMAND after drive removal + Where the following in COMMAND will be replaced with: + %d mount point directory (eg /media/cd) + %f device name (eg /dev/sdd1) + %l label of mounted volume + Multiple --exec-on-XXX options may be used to execute multiple commands. + Other exec-on-XXX commands are ignored if exec-on-device or -label executed. +--mount-options "OPTIONS" Default: $defaultmountoptions +--info-on-mount Show mounted drive info in a popup dialog +--no-mount Don't mount anything, just exec (disables + --exec-on-video) +--no-unmount Don't unmount all removable drives on exit + +MOUNT-OPTIONS: (these can be used only in client mode) +--unmount-removable | -r Sync and unmount all removable drives and show + pop-up dialog (spacefm or zenity required) +--unmount-recent | -c Unmount most recently mounted removable drive +--unmount-optical | -o Unmount all optical drives (error pop-up only) +--unmount-all | -u Same as --unmount-removable --unmount-optical +--unmount DIR|DEVICE Unmount DEVICE or mount point DIR +--eject DIR|DEVICE Unmount and eject DEVICE or mount point DIR +--mount-all | -a Mount all removable and optical drives +--mount DEVICE Mount DEVICE +--mount-options|--mount-fstype|--eject-options "OPTIONS" + These options will be passed to mount or eject +--enumerate-device-files List known devices + +UNIVERSAL OPTIONS: (these can be used in both daemon and client modes) +--ignore-device DEVICE Ignore DEVICE (eg /dev/sdd1) +--ignore-label "LABEL" Ignore volume with LABEL +--sync | -s Add sync mount option for ext2-4 ntfs ufs, or + flush for fat & vfat (slower writing but safer) +--internal Also attempt to un/mount internal system drives + (this is mostly a fix for esata issues) +--no-gui | -g Do not show spacefm/zenity pop-up dialogs +Instructions and updates: + http://igurublog.wordpress.com/downloads/script-devmon/ +EOF + exit +} + +test2() +{ + if [ "${2:0:1}" = "-" ] || [ "$2" = "" ]; then + echo "devmon: Option $1 requires an argument" 1>&2 + exit 1 + fi +} + +test3() +{ + if [ "${2:0:1}" = "-" ] || [ "$2" = "" ] || \ + [ "${3:0:1}" = "-" ] || [ "$3" = "" ]; then + echo "devmon: Option $1 requires two arguments" 1>&2 + exit 1 + fi +} + +unknown() +{ + echo "devmon: Unknown option $1" 1>&2 + echo " For help use: devmon --help" 1>&2 + exit 1 +} + +# parse command line +execoix=0 +execomx=0 +execovx=0 +execoax=0 +execodx=0 +execolx=0 +execoux=0 +execorx=0 +umntx=0 +mntx=0 +ejx=0 +igdevx=0 +iglabx=0 +while [ "$1" != "" ]; do + if [ "${1:0:1}" = "-" ]; then + case "$1" in + --help ) + help + exit + ;; + # don't use eval on these to preserve command strings + --exec-on-drive ) + test2 "$1" "$2" + execoi[$execoix]="$2" + (( execoix++ )) + shift + ;; + --exec-on-disc ) + test2 "$1" "$2" + execom[$execomx]="$2" + (( execomx++ )) + shift + ;; + --exec-on-video ) + test2 "$1" "$2" + execov[$execovx]="$2" + (( execovx++ )) + shift + ;; + --exec-on-audio ) + test2 "$1" "$2" + execoa[$execoax]="$2" + (( execoax++ )) + shift + ;; + --exec-on-device ) + test3 "$1" "$2" "$3" + execod1[$execodx]="$2" + execod2[$execodx]="$3" + (( execodx++ )) + shift 2 + ;; + --exec-on-label ) + test3 "$1" "$2" "$3" + execol1[$execolx]="$2" + execol2[$execolx]="$3" + (( execolx++ )) + shift 2 + ;; + --exec-on-unmount ) + test2 "$1" "$2" + execou[$execoux]="$2" + (( execoux++ )) + shift + ;; + --exec-on-remove ) + test2 "$1" "$2" + execor[$execorx]="$2" + (( execorx++ )) + shift + ;; + --info-on-mount ) + infomount=1 + ;; + --no-mount ) + nomount=1 + ;; + --sync ) + syncopt=1 + ;; + --unmount-on-exit ) + # leave for usage compat with versions prior to 1.0.1 + ;; + --no-unmount ) + nounmount=1 + ;; + --unmount-all ) + unmountrem=1 + unmountoptical=1 + ;; + --unmount-removable ) + unmountrem=1 + ;; + --unmount-optical ) + unmountoptical=1 + ;; + --unmount-recent ) + unmountrecent=1 + ;; + --unmount ) + test2 "$1" "$2" + umnt[$umntx]="$2" + (( umntx++ )) + shift + ;; + --mount-all ) + mountall=1 + ;; + --mount ) + test2 "$1" "$2" + mnt[$mntx]="$2" + (( mntx++ )) + shift + ;; + --eject ) + test2 "$1" "$2" + ej[$ejx]="$2" + (( ejx++ )) + shift + ;; + --mount-options ) + test2 "$1" "$2" + mountoptions="$2" + shift + ;; + --mount-fstype ) + test2 "$1" "$2" + mountfstype="$2" + shift + ;; + --eject-options ) + test2 "$1" "$2" + ejectoptions="$2" + shift + ;; + --internal ) + internal=1 + ;; + --nogui | --no-gui ) + nogui=1 + ;; + --ignore-device ) + test2 "$1" "$2" + igdev[$igdevx]="$2" + (( igdevx++ )) + shift + ;; + --ignore-label ) + test2 "$1" "$2" + iglab[$iglabx]="$2" + (( iglabx++ )) + shift + ;; + --enumerate-device-files ) + all=`grep " [ms]d[a-z0-9]*$" /proc/partitions | \ + sed 's/.* \([ms]d[a-z0-9]*\)/\/dev\/\1/'` + n=$'\n' + if [ "$all" != "" ]; then + all="$all$n" + fi + for f in /dev/mapper/*; do + if [ -h "$f" ]; then + name="$(basename "$f")" + target="$(readlink "$f")" + target="$(basename "$target")" + if [ "$target" != "" ]; then + all="$all/dev/$target$n" + if [ "${name:0:4}" = "loop" ]; then + all="$all/dev/$name$n" + fi + fi + fi + done + # add mounted loop devices (attached requires losetup as root) + loop=`cat /proc/self/mountinfo 2>/dev/null | grep ' /dev/loop[0-9]* ' | cut -f9 -d ' ' 2>/dev/null` + if [ "$loop" != "" ]; then + loop="$loop$n" + fi + other=`/bin/ls -1 /dev/md[0-9]* /dev/dm-* /dev/sr* 2>/dev/null` + if [ "$other" != "" ]; then + other="$other$n" + fi + all="$all$loop$other" + echo -n "$all" | sort | uniq + exit + ;; + --* ) + unknown "$1";; + -* ) + o="${1:1}" + while [ "$o" != "" ]; do + case "${o:0:1}" in + r ) + unmountrem=1;; + o ) + unmountoptical=1;; + u ) + unmountrem=1 + unmountoptical=1 + ;; + a ) + mountall=1;; + s ) + syncopt=1;; + c ) + unmountrecent=1;; + g ) + nogui=1;; + h ) + help + exit + ;; + * ) + unknown "-${o:0:1}";; + esac + o="${o:1}" + done + ;; + esac + else + unknown "$1" + fi + shift +done +(( mountmode = umntx + mntx + ejx + unmountrem + unmountoptical + mountall + unmountrecent )) + +# Warnings +if [ "$(whoami)" = "root" ]; then + echo "WARNING: running devmon as root is usually not required or recommended" 1>&2 +fi + +if (( execoix + execomx + execovx + execoax + execodx + execolx + execoux + execorx \ + + nounmount + infomount != 0 )) && (( mountmode != 0 )); then + echo "WARNING: devmon automount options ignored in mount mode" 1>&2 +fi + +# Discovery +udevil=`which udevil 2>/dev/null` +udisks1=`which udisks 2>/dev/null` +udisks2=`which udisksctl 2>/dev/null` +pmount=`which pmount 2>/dev/null` +zenity=`which zenity 2>/dev/null` +spacefm=`which spacefm 2>/dev/null` + +if [ "$udevil" != "" ] && [ -x "$udevil" ]; then + info_cmd="$udevil" +elif [ "$udisks1" != "" ] && [ -x "$udisks1" ]; then + info_cmd="$udisks1" +else + echo "WARNING: devmon can't run udevil or udisks v1 for device monitoring" 1>&2 + info_cmd="udevil" +fi + +if [ "$udevil" != "" ] && [ -x "$udevil" ]; then + if [ -u "$udevil" ] || [ "$(whoami)" = "root" ]; then + mount_cmd="$udevil" + fi +fi + +if [ "$mount_cmd" = "" ] && [ "$pmount" != "" ] && [ -x "$pmount" ]; then + if [ -u "$pmount" ] || [ "$(whoami)" = "root" ]; then + mount_cmd="$pmount" + fi +fi + +if [ "$mount_cmd" = "" ] && [ "$udisks1" != "" ] && [ -x "$udisks1" ]; then + mount_cmd="$udisks1" +fi + +if [ "$mount_cmd" = "" ] && [ "$udisks2" != "" ] && [ -x "$udisks2" ]; then + mount_cmd="$udisks2" +fi + +if [ "$mount_cmd" = "" ]; then + echo "WARNING: devmon can't run udevil, pmount, or udisks for mounting" 1>&2 + mount_cmd="udevil" +fi + + +driveinfo() #$1=dev #Optional $2=quiet +{ + unset systeminternal usage ismounted presentationnopolicy hasmedia \ + opticaldisc numaudiotracks type partition media blank label + uinfos=`$info_cmd --show-info $1 2> /dev/null` + label=`echo "$uinfos" | grep -m 1 "^ label:" | sed 's/ *label: *\(.*\)/\1/'` + listinfos=`echo "$uinfos" | grep \ + -e "^ system internal:" \ + -e "^ usage:" \ + -e "^ type:" \ + -e "^ is mounted:" \ + -e "^ presentation nopolicy:" \ + -e "^ has media" \ + -e "^ optical disc:" \ + -e " blank:" \ + -e " num audio tracks:" \ + -e "^ partition:" \ + -e " media:"` + # The change for type= is to take only its first value in listinfos + listinfos=$(echo "$listinfos" | sed 's/ //g + s/:/=/ + s/opticaldisc=/&1/ + s/type=\(.*\)/type=${type:-\1}/ + s/[()]//g + s/partition=/&1/') + eval "$listinfos" + if (( internal == 1 )); then + systeminternal="ignored" + fi + # Take only the first character + hasmedia=${hasmedia:0:1} + # If "partition:" not find in listinfos, should mean it is not a partition + partition=${partition:-0} + nopolicy="$presentationnopolicy" + if (( mountmode == 0 )) && [ "$systeminternal" != "1" ] && [ "$2" != "quiet" ]; then + if [ "$usage" = "filesystem" ] || [ "$opticaldisc" = "1" ]; then + echo "device: [$1]" + echo " systeminternal: [$systeminternal]" + echo " usage: [$usage]" + echo " type: [$type]" + echo " label: [$label]" + echo " ismounted: [$ismounted]" + echo " nopolicy: [$nopolicy]" + echo " hasmedia: [$hasmedia]" + echo " opticaldisc: [$opticaldisc]" + echo " numaudiotracks: [$numaudiotracks]" + echo " blank: [$blank]" + echo " media: [$media]" + echo " partition: [$partition]" + fi + fi +} + +ignoredevice() +{ + idx=0 + while (( idx < igdevx )); do + if [ "$1" = "${igdev[$idx]}" ]; then + echo "devmon: ignored device $1" + return 0 + fi + (( idx++ )) + done + return 1 +} + +ignorelabel() +{ + ilx=0 + while (( ilx < iglabx )); do + if [ "$1" = "${iglab[$ilx]}" ]; then + echo "devmon: ignored label $1" + return 0 + fi + (( ilx++ )) + done + return 1 +} + +execcommands() # $exectype "${exec[@]}" +{ + exectype="$1" + shift + while [ "$1" != "" ]; do + usercmd="$1" + usercmd="${usercmd//%f/$dv}" + usercmd="${usercmd//%l/$lb}" + usercmd="${usercmd//%d/$point}" + if [ "$usercmd" != "" ]; then + echo "devmon: [$exectype] eval $usercmd &" + eval $usercmd & + fi + shift + done +} + +mountdev() # $1=device [$2=label] [$3=devtype or fstype] +{ + # set label comment + if [ "$2" = "" ]; then + lblcmt="" + else + lblcmt="# ($2)" + fi + # set mount-fstype option + if [ "$mountfstype" != "" ]; then + if [ "$mount_cmd" = "$udisks2" ] || [ "$mount_cmd" = "$pmount" ]; then + fst="-t" + else + fst="--mount-fstype" + fi + else + fst="" + fi + # set default mount options + if [ "$mountoptions" != "" ]; then + mopts="$mountoptions" + else + mopts="$defaultmountoptions" + fi + # set sync mount options + if (( syncopt == 1 )); then + case "$3" in + ext2 | ext3 | ext4 | ufs | ntfs ) + mopts="$mopts,sync";; + fat | vfat ) + mopts="$mopts,flush";; + esac + fi + + if [ "$mount_cmd" = "$udisks2" ]; then + mntmsg="devmon: $mount_cmd mount -b $1 -o \"$mopts\" $fst $mountfstype $lblcmt" + elif [ "$mount_cmd" = "$pmount" ]; then + mntmsg="devmon: $mount_cmd $fst $mountfstype $1 $lblcmt" + else + mntmsg="devmon: $mount_cmd --mount $1 --mount-options \"$mopts\" $fst $mountfstype $lblcmt" + fi + if [ "$3" != "nofs" ]; then + echo "$mntmsg" + fi + + # mount + if [ "$mount_cmd" = "$udisks2" ]; then + umsg=`$mount_cmd mount -b $1 -o "$mopts" $fst $mountfstype 2>&1` + elif [ "$mount_cmd" = "$pmount" ]; then + umsg=`$mount_cmd $fst $mountfstype $1 2>&1` + else + umsg=`$mount_cmd --mount $1 --mount-options "$mopts" $fst $mountfstype 2>&1` + fi + mounterr="$?" + # get mount point + point=`echo "$umsg" | grep "^Mounted " | sed 's/^Mounted .* at \(.*\)/\1/'` + + if [ "$mount_cmd" = "$pmount" ] && [ "$point" = "" ]; then + # pmount doesn't output the mount point - get it below + point=" " + fi + if [ "$mounterr" != "0" ] || [ "$point" = "" ]; then + # if $3=nofs then there was no apparent filesystem but we tried to mount it + # anyway in case it didn't report the filesystem accurately, so ignore the + # error + if [ "$3" != "nofs" ]; then + echo "$umsg" 1>&2 + echo "devmon: error mounting $1 ($mounterr)" 1>&2 + if [ "$mount_cmd" = "$udisks1" ] || [ "$mount_cmd" = "$udisks2" ]; then + if (( mountmode == 0 )) && (( polkiterrgiven != 1 )) && \ + [ "$(echo "$umsg" | grep 'Not *Authorized')" != "" ]; then + if (( nogui != 1 )); then + if [ "$spacefm" != "" ]; then + ( sleep 3 && $spacefm -g --title "devmon error" --window-icon error --label "udisks functions are not authorized through policykit,\nso devmon cannot automount drives.\nPlease install udevil or see devmon's consolekit installation instructions:\n\nhttp://igurublog.wordpress.com/downloads/script-devmon/#install\n\n(To silence this pop-up add --no-gui to devmon's command line.)" --button "Open Website" xdg-open "http://igurublog.wordpress.com/downloads/script-devmon/#install" --button ok &> /dev/null ) & + else + ( sleep 3 && WINDOWID="" $zenity --error --no-wrap --title="devmon error" \ + --text="udisks functions are not authorized through policykit,\nso devmon cannot automount drives.\nPlease install udevil or see devmon's consolekit installation instructions:\n\nhttp://igurublog.wordpress.com/downloads/script-devmon/#install\n\n(To silence this pop-up add --no-gui to devmon's command line.)" &> /dev/null ) & + fi + fi + echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" 1>&2 + echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" 1>&2 + echo "udisks functions are not authorized through policykit," 1>&2 + echo "so devmon cannot automount drives." 1>&2 + echo "Please see devmon's consolekit installation instructions:" 1>&2 + echo "http://igurublog.wordpress.com/downloads/script-devmon/#install" 1>&2 + echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" 1>&2 + echo "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@" 1>&2 + polkiterrgiven=1 + fi + fi + fi + uerr=3 + return 3 + elif [ "$3" = "nofs" ]; then + # no filesystem reported but successful mount + echo "$mntmsg" + fi + + # set devtag for recognizing mounted by devmon + devpath="$1" + devtag="${devpath#/dev/}" + devtag="${devtag//-/_}" + eval devmounted${devtag}=1 + + echo "$umsg" + if [ "$point" = " " ]; then + # pmount doesn't output the mount point - get it now + sleep 1 + point=`$info_cmd --show-info $1 2>/dev/null | grep "^ mount paths:" | sed 's/.*: *\(.*\)/\1/'` + point="${point%%, *}" + fi +} + +unmountdev() # $1=device +{ + if [ "$mount_cmd" = "$udisks2" ]; then + echo "devmon: $mount_cmd unmount -b $1" + uerrmsg=`$mount_cmd unmount -b $1 2>&1` + elif [ "$mount_cmd" = "$pmount" ]; then + echo "devmon: pumount $1" + uerrmsg=`pumount $1 2>&1` + else + echo "devmon: $mount_cmd --unmount $1" + uerrmsg=`$mount_cmd --unmount $1 2>&1` + fi + umounterr="$?" + if [ "$mount_cmd" = "$udisks1" ] && [ "$uerrmsg" != "" ]; then + # bug: udisks v1 returns $?==0 when unmount fails + umounterr=1 + fi + if [ "$uerrmsg" != "" ]; then + echo "$uerrmsg" + fi + if [ $umounterr -ne 0 ]; then + uerr=3 + return 3 + fi +} + +ejectdev() +{ + echo "devmon: eject $ejectoptions $1" + eject $ejectoptions $1 + if [ "$?" != "0" ]; then + uerr=3 + return 3 + fi +} + +mountdrive() # $1=device $2=label [$3=devtype or fstype] +{ + dv="$1" + lb="$2" + tp="$3" + unset point + + if ( ignoredevice "$dv" ) || ( ignorelabel "$lb" ); then + return + fi + + # mount + if [ "$tp" != "audiocd" ] && (( nomount != 1 )); then + mountdev $dv "$lb" "$tp" + if [ "$?" != "0" ]; then + return + fi + fi + + # exec on device + unset execdone + x=0 + while (( x < execodx )); do + if [ "${execod1[$x]}" = "$dv" ]; then + usercmd="${execod2[$x]}" + usercmd="${usercmd//%f/$dv}" + usercmd="${usercmd//%l/$lb}" + usercmd="${usercmd//%d/$point}" + if [ "$usercmd" != "" ]; then + echo "devmon: [exec on device] eval $usercmd" + eval $usercmd & + execdone=1 + fi + fi + (( x++ )) + done + if (( execdone == 1 )); then return; fi + + # exec on label + x=0 + while (( x < execolx )); do + if [ "${execol1[$x]}" = "$lb" ]; then + usercmd="${execol2[$x]}" + usercmd="${usercmd//%f/$dv}" + usercmd="${usercmd//%l/$lb}" + usercmd="${usercmd//%d/$point}" + if [ "$usercmd" != "" ]; then + echo "devmon: [exec on label] eval $usercmd" + eval $usercmd & + execdone=1 + fi + fi + (( x++ )) + done + if (( execdone == 1 )); then return; fi + + # exec on video + if [ "$tp" = "dvd" ] && [ "$point" != "" ] && [ -d "$point/VIDEO_TS" ]; then + echo "devmon: videodvd $dv ($lb) on $point" + if (( execovx != 0 )); then + execcommands "exec on video" "${execov[@]}" + fi + return + fi + + # exec on audio + if [ "$tp" = "audiocd" ]; then + echo "devmon: audiocd $dv ($lb)" + if (( execoax != 0 )); then + execcommands "exec on audio" "${execoa[@]}" + fi + return + fi + + # exec on disc + if [ "$tp" = "optical" ] || [ "$tp" = "dvd" ]; then + if [ "$point" != "" ] || (( nomount == 1 )); then + if (( execomx != 0 )); then + execcommands "exec on disc" "${execom[@]}" + fi + fi + return + fi + + # exec on drive + if [ "$point" != "" ] || (( nomount == 1 )); then + if (( execoix != 0 )); then + execcommands "exec on drive" "${execoi[@]}" + fi + fi + + # info on mount + if [ "$point" != "" ] && (( infomount == 1 )) && (( nomount != 1 )); then + sleep .5 + echo "devmon: [info on mount] $dv" + if (( nogui != 1 )); then + if [ "$spacefm" != "" ]; then + $spacefm -g --title "devmon mount" --window-icon drive-removable-media --label \ + "The following device has been mounted:\n\n$(df -hT "$dv" | grep "$dv" | \ + awk '{print "Device:\\t"$1"\x0AType:\\t"$2"\nSize:\\t\\t"$3"\nUsed:\\t"$4"\n""Avail:\\t"$5"\nUse%:\\t"$6"\nMount:\\t"$7,$8,$9,$10}')\nLabel:\\t$lb" \ + --button open spacefm "$point" --button ok &>/dev/null & + else + WINDOWID="" $zenity --info --text="The following device has been mounted:\n\n$(df -hT "$dv" \ + | grep "$dv" | awk '{print "Device:\\t"$1"\x0AType:\\t"$2"\nSize:\\t\\t"$3"\nUsed:\\t"$4"\n""Avail:\\t"$5"\nUse%:\\t"$6"\nMount:\\t"$7,$8,$9,$10}')\nLabel:\\t$lb" --title="devmon mount" & + fi + fi + df -hT "$dv" + fi +} + +mountalldrives() +{ + # Mount all optical drives, no exec + x=0 + while [ -e /dev/sr$x ]; do + driveinfo /dev/sr$x + if [ "$numaudiotracks" = "" ]; then + numaudiotracks=0 + fi + if [ "$systeminternal" != "1" ] && [ "$opticaldisc" = "1" ] && \ + [ "$ismounted" != "1" ] && [ "$hasmedia" != "0" ] && \ + [ "$blank" != "1" ] && (( numaudiotracks == 0 )) && \ + [ "$nopolicy" != "1" ]; then + if ( ignoredevice "/dev/sr$x" ) || ( ignorelabel "$label" ); then + (( x++ )) + continue + fi + mountdev /dev/sr$x "$label" + eval notejectedsr$x=1 + fi + (( x++ )) + done + # Mount removable drives, no exec + IFSOLD="$IFS" + IFS=$'\n' + partlist=`grep " [ms]d[a-z0-9]*$" /proc/partitions | sed 's/.* \([ms]d[a-z0-9]*\)/\1/'` + for p in $partlist; do + if ( ignoredevice "/dev/$p" ); then + continue + fi + driveinfo /dev/$p + if ( ignorelabel "$label" ); then + continue + else + if [ "$systeminternal" != "1" ] && [ "$opticaldisc" != "1" ] && \ + [ "$ismounted" = "0" ] && [ "$nopolicy" != "1" ]; then + if [ "$usage" = "filesystem" ]; then + mountdev /dev/$p "$label" "$type" + else + mountdev /dev/$p "$label" nofs + fi + fi + fi + done + IFS="$IFSOLD" +} + +trapexit() +{ + kill $COPROC_PID 2> /dev/null + + # prevent trap code from executing multiple times on different signals + if (( trapdone != 1 )); then + trapdone=1 + # Unmount All + if (( nounmount != 1 )); then + IFSOLD="$IFS" + IFS=$'\n' + uerr=0 + partlist=`grep " [ms]d[a-z0-9]*$" /proc/partitions | \ + sed 's/.* \([ms]d[a-z0-9]*\)/\1/'` + for p in $partlist; do + if ( ignoredevice "/dev/$p" ); then + continue + fi + driveinfo /dev/$p + if ( ignorelabel "$label" ); then + continue + else + if [ "$systeminternal" != "1" ] && [ "$opticaldisc" != "1" ] && \ + [ "$usage" = "filesystem" ] && [ "$ismounted" = "1" ]; then + if [ "$mount_cmd" = "$udisks2" ]; then + echo "devmon: [on exit] $mount_cmd unmount -b /dev/$p &" + $mount_cmd unmount -b /dev/$p & + elif [ "$mount_cmd" = "$pmount" ]; then + echo "devmon: [on exit] pumount /dev/$p &" + pumount /dev/$p & + else + echo "devmon: [on exit]$mount_cmd --unmount /dev/$p &" + $mount_cmd --unmount /dev/$p & + fi + if [ "$?" != "0" ]; then + uerr=3 + fi + fi + fi + done + IFS="$IFSOLD" + fi + echo 'devmon: stopped' + exit $uerr + fi +} + +# Client Mode +if (( mountmode != 0 )); then + uerr=0 + if (( unmountrem == 1 )) || (( unmountrecent == 1 )); then + y=0 + unset udrive zpid + IFSOLD="$IFS" + IFS=$'\n' + if (( unmountrem == 1 )); then + # Unmount All Removable Drives + partlist=`grep " [ms]d[a-z0-9]*$" /proc/partitions | sed 's/.* \([ms]d[a-z0-9]*\)/\1/'` + msgtitle="devmon unmount" + else + # Unmount Recent + partlist=`mount | grep "^/dev/.* on " | sed 's/^\/dev\/\(.*\) on .*/\1/' \ + | grep -v -e "null" -e "shm" -e "mapper" -e "snd" \ + -e "video" -e "random" | tac` + msgtitle="devmon unmount recent" + fi + for p in $partlist; do + if ( ignoredevice "/dev/$p" ); then + continue + fi + driveinfo /dev/$p + if ( ignorelabel "$label" ); then + continue + else + if [ "$systeminternal" != "1" ] && [ "$opticaldisc" != "1" ] \ + && [ "$ismounted" = "1" ]; then + udrive[$y]="/dev/$p" + (( y++ )) + if (( unmountrem != 1 )); then break; fi + fi + fi + done + IFS="$IFSOLD" + if (( y == 0 )); then + msg="No removable drives are mounted" + echo "$msg" + else + msg="Unmounting ${udrive[@]}...\n\n(This dialog will close when the devices are unmounted)" + echo "Preparing to unmount ${udrive[@]}" + fi + if (( nogui != 1 )); then + if [ "$spacefm" != "" ]; then + spacefm -g --title "$msgtitle" --label "$msg" --button close &> /dev/null & + else + WINDOWID="" zenity --info --title="$msgtitle" --text="$msg" &> /dev/null & + fi + zpid=$! + fi + if (( y > 0 )); then + echo "devmon: sync" + sync + for d in ${udrive[@]}; do + unmountdev $d + if [ "$?" != "0" ] && (( nogui != 1 )); then + driveinfo "$d" quiet + if [ "$label" = "" ]; then + lb="" + else + lb=" ($label)" + fi + msg="Unmount error on $d$lb:\n\n$uerrmsg" + if [ "$spacefm" != "" ]; then + spacefm -g --title "$msgtitle" --window-icon error \ + --label "$msg" --button close &> /dev/null & + else + WINDOWID="" zenity --error --title="$msgtitle" --text="$msg" &> /dev/null & + fi + fi + done + echo "devmon: sync" + sync + fi + if [ "$zpid" != "" ]; then + sleep 2 + kill $zpid 2> /dev/null + fi + fi + + # Unmount Optical + if (( unmountoptical == 1 )); then + x=0 + while [ -e "/dev/sr$x" ]; do + if ( ignoredevice "/dev/sr$x" ); then + (( x++ )) + continue + fi + driveinfo /dev/sr$x + if ( ignorelabel "$label" ); then + (( x++ )) + continue + else + if [ "$systeminternal" != "1" ] && [ "$opticaldisc" = "1" ] && \ + [ "$ismounted" = "1" ]; then + unmountdev /dev/sr$x + if [ "$?" != "0" ] && (( nogui != 1 )); then + if [ "$label" = "" ]; then + lb="" + else + lb=" ($label)" + fi + msg="Unmount error on /dev/sr$x$lb:\n\n$uerrmsg" + if [ "$spacefm" != "" ]; then + spacefm -g --title "devmon unmount optical" \ + --window-icon error \ + --label "$msg" --button close &> /dev/null & + else + WINDOWID="" zenity --error --title="devmon unmount optical" \ + --text="$msg" &> /dev/null & + fi + fi + fi + fi + (( x++ )) + done + fi + + # Unmount DIR|DEVICE + if (( umntx > 0 )); then + x=0 + while (( x < umntx )); do + d="${umnt[$x]}" + # remove trailing slash + if [ "$d" != "/" ]; then + d="${d%/}" + fi + if [ "${d:0:5}" = "/dev/" ]; then + # Unmount DEVICE + unmountdev "$d" + else + # Unmount DIR + if [ "$(dirname "$d")" = "." ]; then + if [ -d "$(pwd)/$d" ]; then + d="$(pwd)/$d" + elif [ -d "/media/$d" ]; then + d="/media/$d" + elif [ -e "/dev/$d" ] && [ "$(mount | grep "^/dev/$d on ")" != "" ]; then + unmountdev "/dev/$d" + (( x++ )) + continue + fi + fi + if [ ! -d "$d" ]; then + echo "devmon: No such directory or mounted device $d" 1>&2 + uerr=3 + else + dv=`mount | grep -m 1 " on $d type " | awk '{print $1}'` + if [ "$dv" = "" ]; then + echo "devmon: Nothing mounted on $d (mtab)" 1>&2 + uerr=3 + else + unmountdev "$dv" + fi + fi + fi + (( x++ )) + done + fi + + # Eject DIR|DEVICE + if (( ejx > 0 )); then + x=0 + while (( x < ejx )); do + d="${ej[$x]}" + # remove trailing slash + if [ "$d" != "/" ]; then + d="${d%/}" + fi + dv="" + if [ "${d:0:5}" = "/dev/" ]; then + # Eject DEVICE + dv="$d" + else + # Eject DIR + if [ "$(dirname "$d")" = "." ]; then + if [ -d "$(pwd)/$d" ]; then + d="$(pwd)/$d" + elif [ -d "/media/$d" ]; then + d="/media/$d" + elif [ -e "/dev/$d" ] && [ "$(mount | grep "^/dev/$d on ")" != "" ]; then + dv="/dev/$d" + fi + fi + if [ "$dv" = "" ]; then + if [ ! -d "$d" ]; then + echo "devmon: No such directory or mounted device $d" 1>&2 + uerr=3 + else + dv=`mount | grep -m 1 " on $d type " | awk '{print $1}'` + if [ "$dv" = "" ]; then + echo "devmon: Nothing mounted on $d (mtab)" 1>&2 + uerr=3 + fi + fi + fi + fi + if [ "$dv" != "" ]; then + driveinfo "$dv" + if [ "$systeminternal" != "1" ] && [ "$opticaldisc" = "1" ] && \ + [ "$ismounted" = "1" ]; then + unmountdev "$dv" + fi + ejectdev "$dv" + fi + (( x++ )) + done + fi + + # Mount DEVICE + if (( mntx > 0 )); then + x=0 + while (( x < mntx )); do + d="${mnt[$x]}" + # remove trailing slash + if [ "$d" != "/" ]; then + d="${d%/}" + fi + if [ "$(dirname "$d")" = "." ] && [ "${d:0:5}" != "/dev/" ]; then + d="/dev/$d" + fi + driveinfo "$d" quiet + if [ "$opticaldisc" = "1" ]; then + mountdev $d "$label" + else + mountdev $d "$label" "$type" + fi + (( x++ )) + done + fi + + # Mount All Unmounted + if (( mountall == 1 )); then + mountalldrives + fi + + exit $uerr +fi + +# Daemon Mode +if [ "$mountfstype" != "" ]; then + echo "WARNING: --mount-fstype ignored in daemon mode" 1>&2 + mountfstype="" +fi +if [ "$ejectoptions" != "" ]; then + echo "WARNING: --eject-options ignored in daemon mode" 1>&2 + ejectoptions="" +fi +pidcount=`ps h -C "${0//*\//}" -o pid | wc -l` +if (( pidcount > 2 )); then + echo + echo "WARNING: multiple instances of devmon appear to be running (my pid=$$):" + ps h -C "${0//*\//}" + echo +fi + +if [ "$mount_cmd" = "$udisks1" ] || [ "$info_cmd" = "$udisks1" ]; then + # Trigger udisks daemon start two ways + if [ -e /dev/sr0 ]; then + udisks --poll-for-media /dev/sr0 + fi + udisks --show-info /dev/sda > /dev/null +fi +sleep 2 # helps successful sr0 startup mount on reboot + + +# Startup Mounting +if (( nomount != 1 )); then + mountalldrives +fi + +# Start monitoring +coproc $info_cmd --monitor +err=$? +trap trapexit EXIT SIGINT SIGTERM SIGQUIT +trap "echo devmon: ignored HUP" SIGHUP + +if [ $err != "0" ] || [ ! ps -p $COPROC_PID &>/dev/null ]; then + echo "devmon: unable to start $info_cmd --monitor" 1>&2 + exit 2 +fi + + +# Monitoring Loop +while ps -p $COPROC_PID &>/dev/null; do + read -u ${COPROC[0]} + echo "===========================================" + echo "$REPLY" + event="${REPLY%:*}" + devpath="${REPLY#*:}" + devpath="/dev/${devpath##*/}" + devtag="${devpath#/dev/}" + devtag="${devtag//-/_}" + if [ "$event" != "" ] && [ "$devpath" != "/dev/" ] && [ -e "$devpath" ]; then + case $event in + added ) + driveinfo $devpath + if [ "$systeminternal" != "1" ] && [ "$ismounted" = "0" ] && \ + [ "$nopolicy" != "1" ]; then + if [ "$usage" = "filesystem" ]; then + mountdrive $devpath "$label" "$type" + else + mountdrive $devpath "$label" nofs + fi + fi + ;; + job-changed ) + ;; + removed ) + ;; + changed ) + driveinfo $devpath + eval notejected=\$notejected${devtag} + eval devmounted=\$devmounted${devtag} + eval devmounted${devtag}="$ismounted" + # If notejected==1 then cd has not been ejected and was probably + # manually unmounted, so don't automount it. Otherwise + # devmon will instantly mount any manual unmount. + if [ "$systeminternal" != "1" ] && [ "$opticaldisc" = "1" ] && \ + [ "$ismounted" != "1" ] && [ "$hasmedia" != "0" ] && \ + [ "$blank" != "1" ] && (( notejected != 1 )) && \ + [ "$nopolicy" != "1" ]; then + if [ "$media" = "optical_dvd" ]; then + mountdrive $devpath "$label" dvd + elif (( numaudiotracks > 0 )); then + mountdrive $devpath "$label" audiocd + else + mountdrive $devpath "$label" optical + fi + eval notejected${devtag}=1 + else + if [ "$systeminternal" != "1" ] && \ + [ "$hasmedia" = "0" ]; then + if (( notejected == 1 )) || [ "$notejected" == "" ]; then + # disc ejected + echo "devmon: $devpath eject detected" + eval notejected${devtag}=0 + fi + if [ "$ismounted" != "0" ]; then + # unmount if ejected disc still mounted + unmountdev "$devpath" + fi + fi + if [ "$systeminternal" != "1" ] && [ "$ismounted" != "1" ] && \ + [ "$nopolicy" != "1" ] && [ "$devmounted" = "1" ]; then + # exec-on-unmount + if (( execoux != 0 )); then + if ( ! ignoredevice "$devpath" ) && \ + ( ! ignorelabel "$label" ); then + unset lb point + dv="$devpath" + execcommands "exec on unmount" "${execou[@]}" + fi + fi + # remove udevil mount point in case unmounted by other + if [ "$mount_cmd" = "$udevil" ]; then + echo "devmon: $udevil clean" + $udevil clean + fi + fi + fi + ;; + esac + elif [ "$event" = "removed" ]; then + eval unset devmounted${devtag} + # unmount if removed device is still mounted + grep -qs "^${devpath} " /proc/mounts &> /dev/null + mounterr=$? + if [ $mounterr -ne 0 ]; then + grep -qs "^${devpath} " /etc/mtab &> /dev/null + mounterr=$? + fi + if [ $mounterr -eq 0 ]; then + unmountdev "${devpath}" + elif [ "$mount_cmd" = "$udevil" ]; then + # remove udevil mount point in case unmounted by other + echo "devmon: $udevil clean" + $udevil clean + fi + + # exec-on-remove + if (( execorx != 0 )); then + if ( ! ignoredevice "$devpath" ); then + unset lb point + dv="$devpath" + execcommands "exec on remove" "${execor[@]}" + fi + fi + fi +done + +exit + +# CHANGELOG +# For changes after version 1.1.0, see udevil ChangeLog +# +# 1.1.0: added support for udevil, udisks2, pmount +# 1.0.5: --exec-on-unmount now executes only once per unmount +# 1.0.4: added --exec-on-unmount, --exec-on-remove +# added multiple instance warning +# %f device spec no longer passed in quotes to commands +# 1.0.3: help updated for sync +# corrected exec-on-drive bug introduced in 1.0.1 +# 1.0.2: --sync adds sync for ntfs +# 1.0.1: added --sync +# added --no-unmount; unmount-on-exit is now default +# obey UDISKS_PRESENTATION_NOPOLICY to inhibit automount +# added unmount-all error pop-ups +# 1.0.0: added --unmount-recent +# improved udisks mount info to stdout +# improved mount/unmount without apparent filesystem +# 0.9.5: ignore trailing slash in un/mount dir/dev specs +# attempt to mount no filesystem in case there is one +# 0.9.4: polkit error more selective +# 0.9.3: corrected problems with spaces in volume labels +# corrected un/mounting of partitionless devices +# corrected --ignore-devices problem +# added not authorized pop-up error +# 0.9.2: added --internal +# 0.9.1: corrected --unmount-on-removable not recognized +# 0.9.0: changed --unmount-all to --unmount-removable +# added --unmount-all (now includes optical) +# added --unmount-optical +# added --unmount DIR|DEVICE +# added --eject DIR|DEVICE +# added --mount-all +# added --mount DEVICE +# added --info-on-mount +# added pass options to udisks +# better error msg from udisks +# individual drive eject detection +# no limit on number of optical drives +# 0.8.2: more verbose errors +# run as root changed to warning +# 0.8.1: added --unmount-on-exit +# adjusted start daemon trigger, timing +# added 'do not run as root' catcher +# added trap to ignore SIGHUP + diff --git a/scripts/dmenu-refresh b/scripts/dmenu-refresh index 9c05d2b4..5f022ea0 100755 --- a/scripts/dmenu-refresh +++ b/scripts/dmenu-refresh @@ -44,6 +44,12 @@ case $selection in kill -9 $(pidof dunst) dunst & ;; + devmon) + pkill -f devmon + ~/.scripts/devmon --exec-on-drive "/sbin/notify-send ' Drive Mounted' '%l (%f) at %d '" \ + --exec-on-remove "/sbin/notify-send ' Drive Removed' '%l (%f) from %d '" \ + --exec-on-unmount "/sbin/notify-send ' Drive Unmounted' '%l (%f) from %d '" & + ;; quark) sudo systemctl restart quark ;; diff --git a/scripts/dmenu-udevil b/scripts/dmenu-udevil index 1f8a760c..ad1c20d6 100755 --- a/scripts/dmenu-udevil +++ b/scripts/dmenu-udevil @@ -51,7 +51,8 @@ dmenu_mnt() { msg=$(cat $TMP) else udevil --verbose $udevil_cmd "$path" > "$TMP" 2>&1 - msg=$(grep "umount: " "$TMP" | cut -c '9-') + #msg=$(grep "umount: " "$TMP" | cut -c '9-') + msg="" fi exitc=$? diff --git a/scripts/dmenu-wallabag b/scripts/dmenu-wallabag index 41bb3365..430d6221 100755 --- a/scripts/dmenu-wallabag +++ b/scripts/dmenu-wallabag @@ -29,6 +29,9 @@ list_entries() { items="$(cat $itemcache)" selection=$(echo "$items" | dmenu -l 10 -p "Choose an article:") fi + if [ "$selection" = "" ]; then + exit + fi selection=$(echo "$selection" | cut -d" " -f1) wallabag update --read $selection wallabag open $selection @@ -37,6 +40,9 @@ list_entries() { add_entry() { url=$(echo -n "" | dmenu -p "Enter URL:") + if [ "$url" = "" ]; then + exit + fi wallabag add $url wallabag list | head -n -1 | tail -n +2 > $itemcache } diff --git a/scripts/dmenu_surf b/scripts/dmenu_surf index 080bd182..cff2c898 100755 --- a/scripts/dmenu_surf +++ b/scripts/dmenu_surf @@ -9,5 +9,5 @@ selection=$(echo "" | dmenu -p "Enter URL") if [ ! -z "$selection" ] then - firefox-developer-edition $selection + brave-start $selection fi diff --git a/scripts/menu-surfraw b/scripts/menu-surfraw index fdfdf96a..c1297855 100755 --- a/scripts/menu-surfraw +++ b/scripts/menu-surfraw @@ -7,7 +7,7 @@ # it in your browser of choice. # Edit here to change what browser you open links in -browser="firefox-developer-edition" +browser="brave" usage() { echo "Usage: $0 [OPTIONS] [ELVIS [SEARCHTERM]] @@ -47,5 +47,9 @@ answerB=$(echo "${@:2}") # the search in surfraw action=$(echo "" | $menu -p "$answerA ") +if [ "$action" = "" ]; then + exit +fi + surfraw -browser=$browser $answerA $action diff --git a/xorg/xinitrc b/xorg/xinitrc index a2c9d14d..11c01113 100755 --- a/xorg/xinitrc +++ b/xorg/xinitrc @@ -2,9 +2,11 @@ pkill -f clipmenud pkill -f dunst +pkill -9 devmon pkill -f "bash /sbin/clipmenud" pkill -f "/usr/bin/gnome-keyring-daemon --start --components=pkcs11,secrets,ssh" pkill -f "/usr/lib/polkit-gnome/polkit-gnome-authentication-agent-1" +pkill -f devmon rm -rf /tmp/day_cache source ~/.config.env @@ -53,6 +55,11 @@ xset dpms 600 600 600 dunst & + +~/.scripts/devmon --exec-on-drive "/sbin/notify-send ' Drive Mounted' '%l (%f) at %d '" \ + --exec-on-remove "/sbin/notify-send ' Drive Removed' '%l (%f) from %d '" \ + --exec-on-unmount "/sbin/notify-send ' Drive Unmounted' '%l (%f) from %d '" & + touch ~/.cache/dwm-restart while [ -f /home/yigit/.cache/dwm-restart ]; do