systemdを使用したUSBドライブの自動マウント


27

私たちは、lightdm / xfce、もちろんsystemd(およびudisks2)を含む、非常に古いディストリビューションから最新のDebian Jessieベースのシステムにサーバーを更新しています。1つの問題点は、USBドライブの自動マウントです。以前はいくつかのudevルールでこれを達成していました。古いルールはほとんど機能します-マウントポイントが作成され、ドライブが正常にマウントされますが、数秒後にsystemdがマウントを壊す何かをしているため、その後のアクセス試行は「トランスポートエンドポイントが接続されていません」エラーになります。

コマンドラインを使用してドライブを手動でマウントすると正常に機能します。また、ファイルマネージャー(thunarおよびthunar-volman、順番にudisks2を使用)も許可します。しかし、これらは実行可能なオプションではありません-これらのシステムはほとんどヘッドレスで実行されるため、thunarは通常実行されません。cronベースの無人バックアップ用にディスクドライブを接続できる必要があります。

udevスクリプトを変更してマウントを実行する前に数秒待機するデタッチされたジョブを生成するとうまくいくかもしれないと思いましたが、systemdはこれを防ぐために邪魔にならないようです-それはどういうわけかデタッチされたジョブが完了する前に待つ続きます。

おそらく、udevスクリプトにudisks2をくすぐらせるのが正しい方法でしょうか?私は迷っているので、アドバイスは大歓迎です。


1
接線的にのみ関連していますが、...サーバーにxfceを配置していますか?
パルティアショット

ああ、私は「サーバー」という用語をかなり大まかに使用しました...システムとのユーザーの対話はすべて、通常はネットワーク経由でブラウザーを介してアクセスされるWebアプリを通じて行われます。しかし、一部のお客様は非ネットワークソリューションを好むため、コンソール上でChromeを一種のキオスクモードで実行しています。(これはネットワーク設定の問題のデバッグにも便利です。モニター/マウス/キーボードを接続して、Linuxログイン資格情報を必要とせずにWebアプリの基本的な診断ツールにアクセスできます)。そこlightdm / XFCEよりも軽量化ソリューションは、おそらくですが、これは設定するのが最も簡単だった...
マイクBlackwellの

systemd-udevdルールでスクリプトを直接実行したい場合:これがありました。しばらくは機能しましたが、udevdが自動的に開始されていた場合、ある時点でスクリプトの実行を停止しました。コマンドラインから停止して再起動すれば問題ありません。それに加えて、udevはNTFS + FUSEでうまく動作しませんでした。udevは、長時間実行される子プロセス(ntfs-3g)を検出し、60秒後にそれを強制終了したためです。結論:スクリプトを直接実行するudevルールは時間の無駄です。回答に記載されているように、代わりにudevルールとsystemdサービスを使用してください。その場合、名前空間(MountFlags = slave)を扱う必要もありません。
マーク

ネットワーク接続を確立できないudevによって開始されたスクリプトの同様の問題がありました。systemdを使用する以下の解決策もこれに有効でした-ありがとう!
クエンティンスタッフォードフレイザー

回答:


28

いくつかの誤った開始後、私はこれを理解しました。重要なのは、udevとマウントスクリプトの間にsystemdユニットサービスを追加することです。

(記録のためにudisksctl mount -b /dev/sdb1、udevルールまたはsystemdユニットファイルから直接呼び出されるudisks2を使用してこれを機能させることはできませんでした。競合状態のようで、デバイスノードの準備ができていません、Error looking up object for device /dev/sdb1残念なことに、udisks2はすべてのマウントポイントの乱雑さを処理できるため...)

面倒な作業は、マウントポイントの作成と削除、ドライブのマウントとマウント解除を行うシェルスクリプトによって行われます。

/usr/local/bin/usb-mount.sh

#!/bin/bash

# This script is called from our systemd unit file to mount or unmount
# a USB drive.

usage()
{
    echo "Usage: $0 {add|remove} device_name (e.g. sdb1)"
    exit 1
}

if [[ $# -ne 2 ]]; then
    usage
fi

ACTION=$1
DEVBASE=$2
DEVICE="/dev/${DEVBASE}"

# See if this drive is already mounted, and if so where
MOUNT_POINT=$(/bin/mount | /bin/grep ${DEVICE} | /usr/bin/awk '{ print $3 }')

do_mount()
{
    if [[ -n ${MOUNT_POINT} ]]; then
        echo "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
        exit 1
    fi

    # Get info for this drive: $ID_FS_LABEL, $ID_FS_UUID, and $ID_FS_TYPE
    eval $(/sbin/blkid -o udev ${DEVICE})

    # Figure out a mount point to use
    LABEL=${ID_FS_LABEL}
    if [[ -z "${LABEL}" ]]; then
        LABEL=${DEVBASE}
    elif /bin/grep -q " /media/${LABEL} " /etc/mtab; then
        # Already in use, make a unique one
        LABEL+="-${DEVBASE}"
    fi
    MOUNT_POINT="/media/${LABEL}"

    echo "Mount point: ${MOUNT_POINT}"

    /bin/mkdir -p ${MOUNT_POINT}

    # Global mount options
    OPTS="rw,relatime"

    # File system type specific mount options
    if [[ ${ID_FS_TYPE} == "vfat" ]]; then
        OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
    fi

    if ! /bin/mount -o ${OPTS} ${DEVICE} ${MOUNT_POINT}; then
        echo "Error mounting ${DEVICE} (status = $?)"
        /bin/rmdir ${MOUNT_POINT}
        exit 1
    fi

    echo "**** Mounted ${DEVICE} at ${MOUNT_POINT} ****"
}

do_unmount()
{
    if [[ -z ${MOUNT_POINT} ]]; then
        echo "Warning: ${DEVICE} is not mounted"
    else
        /bin/umount -l ${DEVICE}
        echo "**** Unmounted ${DEVICE}"
    fi

    # Delete all empty dirs in /media that aren't being used as mount
    # points. This is kind of overkill, but if the drive was unmounted
    # prior to removal we no longer know its mount point, and we don't
    # want to leave it orphaned...
    for f in /media/* ; do
        if [[ -n $(/usr/bin/find "$f" -maxdepth 0 -type d -empty) ]]; then
            if ! /bin/grep -q " $f " /etc/mtab; then
                echo "**** Removing mount point $f"
                /bin/rmdir "$f"
            fi
        fi
    done
}

case "${ACTION}" in
    add)
        do_mount
        ;;
    remove)
        do_unmount
        ;;
    *)
        usage
        ;;
esac

スクリプトは、systemdユニットファイルによって呼び出されます。「@」ファイル名構文を使用して、引数としてデバイス名を渡すことができます。

/etc/systemd/system/usb-mount@.service

[Unit]
Description=Mount USB Drive on %i
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/local/bin/usb-mount.sh add %i
ExecStop=/usr/local/bin/usb-mount.sh remove %i

最後に、いくつかのudevルールは、hotplug / unplugでsystemdユニットサービスを開始および停止します。

/etc/udev/rules.d/99-local.rules

KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="add", RUN+="/bin/systemctl start usb-mount@%k.service"

KERNEL=="sd[a-z][0-9]", SUBSYSTEMS=="usb", ACTION=="remove", RUN+="/bin/systemctl stop usb-mount@%k.service"

これでうまくいくようです!このようなものをデバッグするためのいくつかの便利なコマンド:

  • udevadm control -l debug詳細ログを有効にして /var/log/syslog、何が起きているのかを確認できるようにします。
  • udevadm control --reload-rules rules.d dir内のファイルを変更した後(必要ではないかもしれませんが、傷つけることはできません...)。
  • systemctl daemon-reload systemdユニットファイルを変更した後。

4
ワオ。これはすごい。複数の賛成票を投じることができますように!私は修正しなければならなかった唯一のことは、私のシステム上で、ということでしたblkid抽出していないようだID_FS_LABEL私はちょうど使用して、DEVBASEというよりもLABEL建設するMOUNT_POINT代わりに。
トラビスグリッグス

このセットアップは、ATA / SCSIデバイスで動作するように変更できますか?参照:serverfault.com/q/825779/297059
user339676

@Travis-のudevadm代わりに使用できますblkid。より詳細な情報と追加情報が得られます。(例udevadm info --query=property --name=sda1
-user339676

USBデバイスが既に接続されている場合、これは起動時にうまく機能しません。何か案は?
ミハルアルタゾフ

nullglobsが設定されていない場合、アンマウント時にクリーンアップによりのようなエラーが生成される可能性があります/usr/bin/find: '/media/*': No such file or directory。クリーンアップでは、if [ "$f" != "/media/*" ]; then実行前に追加チェックを使用できますfind
プロバックアップ

12

新しい簡潔なsystemd自動マウントオプションがあり、fstabこれを使用すると、標準化されたすべてのマウント許可オプションを使用できます。次のようになります。

  x-systemd.automount

fstab行のそれの例:

  /dev/sdd1   /mnt/hitachi-one     auto     noauto,x-systemd.automount     0 2

このnoautoオプションは、古いソフトウェアのように、起動時にマウントを試行しないことを意味しますautofs

新しいx-systemd.automount行を追加した後、fstab次を実行する必要があります。

  sudo systemctl daemon-reload

そして、次の両方または1つ:

  sudo systemctl restart remote-fs.target
  sudo systemctl restart local-fs.target

それについての詳細情報:

https://wiki.archlinux.org/index.php/Fstab#Automount_with_systemd


sudo systemctl restart local-fs.target私のためにトリックをした
フィリップガチュー

2

@MikeBlackwellのスクリプトを次のように変更しました。

  • だけで/dev/sd[a-z]なく、複数の文字にまたがるデバイス名を認識します/dev/sd[a-z]*。多くの場合、より多くのスピンドルを持つサーバーの場合です。
  • 自動マウントされたドライブのリストを追跡します /var/log/usb-mount.track
  • /var/log/messagesタグusb-mount.shでアクションのログを記録します
  • ラベルが割り当てられていないドライブで問題にして実行しないようにマウントポイント用のデバイス・ラベルを持つ接頭デバイス名(空?): /media/sdd2_usbtest/media/sdd2_
  • ファイルを適切に配置し、必要に応じて元に戻すラッパースクリプトが含まれています

@MikeBlackwellはすでにほとんどの面倒な作業を行っているため、書き直さないことにしました。必要な変更を加えました。元の回答の名前とURIを目撃した彼の作品を認めました。

https://github.com/raamsri/automount-usbで見つけてください


2

使用pmount、systemdにマイク・ブラックウェルのアプローチを、あなたは全体を簡素化することができます。

/etc/systemd/system/usb-mount@.service

[Unit]
Description=Mount USB Drive on %i
[Service]
Type=oneshot
RemainAfterExit=true
ExecStart=/usr/bin/pmount --umask 000 /dev/%i /media/%i
ExecStop=/usr/bin/pumount /dev/%i

/etc/udev/rules.d/99-usb-mount.rules

ACTION=="add",KERNEL=="sd[a-z][0-9]*",SUBSYSTEMS=="usb",RUN+="/bin/systemctl start usb-mount@%k.service"
ACTION=="remove",KERNEL=="sd[a-z][0-9]*",SUBSYSTEMS=="usb",RUN+="/bin/systemctl stop usb-mount@%k.service"

HTH、マイクありがとう。


0

私はウォーレン・ヤングの答えに行きます

ドライブの環境の評価でエラーが発生するため、スペース保護を追加しました。

usbディスクをchmodするセクションを追加して、すべてのユーザーが非ntfsまたはvfatディスクにフルアクセスできるようにしました。

/usr/local/bin/usb-mount.sh

#!/bin/bash

# This script is called from our systemd unit file to mount or unmount
# a USB drive.

usage()
{
    echo "Usage: $0 {add|remove} device_name (e.g. sdb1)"
    exit 1
}

if [[ $# -ne 2 ]]; then
    usage
fi

ACTION="$1"
DEVBASE="$2"
DEVICE="/dev/${DEVBASE}"

# See if this drive is already mounted, and if so where
MOUNT_POINT=$(/bin/mount | /bin/grep ${DEVICE} | /usr/bin/awk '{ print $3 }')

do_mount()
{
    if [[ -n "${MOUNT_POINT}" ]]; then
        echo "Warning: ${DEVICE} is already mounted at ${MOUNT_POINT}"
        exit 1
    fi

    # Get info for this drive: $ID_FS_LABEL, $ID_FS_UUID, and $ID_FS_TYPE
    # added some sed's to avoid space issues
    eval $(/sbin/blkid -o udev ${DEVICE}|sed 's/=/="/'|sed 's/$/"/')

    # Figure out a mount point to use
    LABEL="${ID_FS_LABEL}"
    if [[ -z "${LABEL}" ]]; then
        LABEL="${DEVBASE}"
    elif /bin/grep -q " /media/${LABEL} " /etc/mtab; then
        # Already in use, make a unique one
        LABEL+="-${DEVBASE}"
    fi
    MOUNT_POINT="/media/${LABEL}"

    echo "Mount point: ${MOUNT_POINT}"

    /bin/mkdir -p "${MOUNT_POINT}"

    # Global mount options
    OPTS="rw,relatime"
    #added a chmod checker for file systems that don't 
    #understand allow all to read write
    CHMOD=no
    # File system type specific mount options
    if [[ ${ID_FS_TYPE} == "vfat" ]]; then
        OPTS+=",users,gid=100,umask=000,shortname=mixed,utf8=1,flush"
    #added options I wanted on ntfs
    elif [[ ${ID_FS_TYPE} == "ntfs" ]]; then
        OPTS+=",user,users,umask=000,allow_other"
    else
       CHMOD=yes
    fi

    if ! /bin/mount -o "${OPTS}" ${DEVICE} "${MOUNT_POINT}"; then
        echo "Error mounting ${DEVICE} (status = $?)"
        /bin/rmdir "${MOUNT_POINT}"
        exit 1
    fi


    echo "**** Mounted ${DEVICE} at ${MOUNT_POINT} ****"
    if [ "${CHMOD}" = "yes" ];then
        /usr/bin/find "${MOUNT_POINT}" -type f -exec chmod 0666 {} \;
        /usr/bin/find "${MOUNT_POINT}" -type d -exec chmod 0777 {} \;
    fi
}

do_unmount()
{
    if [[ -z ${MOUNT_POINT} ]]; then
        echo "Warning: ${DEVICE} is not mounted"
    else
        /bin/umount -l ${DEVICE}
        echo "**** Unmounted ${DEVICE}"
    fi

    # Delete all empty dirs in /media that aren't being used as mount
    # points. This is kind of overkill, but if the drive was unmounted
    # prior to removal we no longer know its mount point, and we don't
    # want to leave it orphaned...
    for f in /media/* ; do
        if [[ -n $(/usr/bin/find "$f" -maxdepth 0 -type d -empty) ]]; then
            if ! /bin/grep -q " $f " /etc/mtab; then
                echo "**** Removing mount point $f"
                /bin/rmdir "$f"
            fi
        fi
    done
}

case "${ACTION}" in
    add)
        do_mount
        ;;
    remove)
        do_unmount
        ;;
    *)
        usage
        ;;
 esac

より有用なものにするために、元の回答と自分の回答の違いをいくつかの言葉で説明することができます。PS:ウォーレンヤングによる回答はありませんでした。多分あなたは編集されたマイク・ブラックウェルの答えを意味しましたか?
アミール
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.