mount_setattr(2)

الاسم
mount_setattr - يغير خصائص الوصل أو شجرة الوصل

المكتبة
مكتبة سي المعيارية (libc، -lc)

موجز
#include <fcntl.h>       /* تعريف ثوابت AT_* */
#include <sys/mount.h>

int mount_setattr(int dirfd, const char *path, unsigned int flags,
                  struct mount_attr *attr, size_t size);

الوصف
نداء النظام mount_setattr() هو جزء من مجموعة مرافق الوصل المعتمدة على واصفات الملفات في لينكس.

يغير mount_setattr() خصائص الوصل لوصلة ما أو لشجرة وصل كاملة. إذا كان path نسبياً، فسيُفسر بالنسبة إلى الدليل الذي يشير إليه واصف الملف dirfd. وإذا كان dirfd هو القيمة الخاصة AT_FDCWD، فسيُفسر path بالنسبة إلى دليل العمل الحالي للعملية المستدعِية. وإذا كان path سلسلة فارغة وحُدد AT_EMPTY_PATH في flags، فستُغير خصائص الوصل للوصلة المحددة بواسطة dirfd. (انظر openat(2) لشرح سبب فائدة المعامل dirfd.)

يستخدم نداء النظام mount_setattr() بنية قابلة للتوسيع (struct mount_attr) للسماح بالتوسعات المستقبلية. أي توسعات لـ mount_setattr() ليست من نوع الأعلام ستُنفذ كحقول جديدة تُلحق بهذه البنية، وتؤدي القيمة الصفرية في الحقل الجديد إلى تعامل النواة كما لو أن حقل التوسعة هذا غير موجود. لذلك، يجب على المستدعِي ملء هذه البنية بالأصفار عند التهيئة. انظر القسم الفرعي "القابلية للتوسع" تحت NOTES لمزيد من التفاصيل.

عادة ما يُحدد المعامل size كـ sizeof(struct mount_attr). ومع ذلك، إذا كان المستدعِي يستخدم نواة تدعم struct mount_attr ممتدة، ولكنه لا ينوي استخدام هذه الميزات، فمن الممكن تمرير حجم نسخة سابقة من البنية مع البنية الممتدة. وهذا يسمح للنواة بعدم نسخ الأجزاء اللاحقة من البنية التي لا تُستخدم على أي حال. مع كل توسعة تغير حجم struct mount_attr، ستكشف النواة عن تعريف على الشكل MOUNT_ATTR_SIZE_VERnumber . على سبيل المثال، الماكرو الخاص بحجم النسخة الأولية من struct mount_attr هو MOUNT_ATTR_SIZE_VER0.

يمكن استخدام المعامل flags لتعديل سلوك تحليل اسم المسار. القيم المدعومة هي:

AT_EMPTY_PATH
    إذا كان path سلسلة فارغة، فستُغير خصائص الوصل في dirfd نفسه.

AT_RECURSIVE
    يغير خصائص الوصل لشجرة الوصل كاملة.

AT_SYMLINK_NOFOLLOW
    لا يتبع الروابط الرمزية اللاحقة.

AT_NO_AUTOMOUNT
    لا يطلق عمليات الوصل الآلي.

المعامل attr لـ mount_setattr() هو مؤشر إلى بنية mount_attr، الموصوفة في mount_attr(2type).

تُستخدم العضوان attr_set و attr_clr لتحديد خصائص الوصل التي يُفترض ضبطها أو مسحها لوصلة ما أو لشجرة وصل. الأعلام المضبوطة في attr_set تُفعل خاصية في الوصل أو شجرة الوصل، والأعلام المضبوطة في attr_clr تزيل خاصية من الوصل أو شجرة الوصل.

عند تغيير خصائص الوصل، ستقوم النواة أولاً بمسح الأعلام المحددة في حقل attr_clr، ثم تضبط الأعلام المحددة في حقل attr_set. على سبيل المثال، هذه الإعدادات:

    struct mount_attr attr = {
        .attr_clr = MOUNT_ATTR_NOEXEC | MOUNT_ATTR_NODEV,
        .attr_set = MOUNT_ATTR_RDONLY | MOUNT_ATTR_NOSUID,
    };

تكافئ الخطوات التالية:

    unsigned int current_mnt_flags = mnt->mnt_flags;

    /*
     * مسح كل الأعلام المضبوطة في .attr_clr،
     * مسح MOUNT_ATTR_NOEXEC و MOUNT_ATTR_NODEV.
     */
    current_mnt_flags &= ~attr->attr_clr;

    /*
     * الآن ضبط كل الأعلام المضبوطة في .attr_set،
     * تطبيق MOUNT_ATTR_RDONLY و MOUNT_ATTR_NOSUID.
     */
    current_mnt_flags |= attr->attr_set;

    mnt->mnt_flags = current_mnt_flags;

نتيجة لهذا التغيير، تصبح الوصلة أو شجرة الوصل (أ) للقراءة فقط؛ (ب) تمنع تنفيذ برامج set-user-ID و set-group-ID؛ (ج) تسمح بتنفيذ البرامج؛ و (د) تسمح بالوصول إلى الأجهزة.

تغييرات متعددة بنفس مجموعة الأعلام المطلوبة في attr_clr و attr_set مضمونة بأنها متساوية القوى (idempotent) بعد تطبيق التغييرات.

سمات الوصل التالية يمكن تحديدها في حقلي attr_set أو attr_clr:

MOUNT_ATTR_RDONLY
    إذا ضُبط في attr_set، فإنه يجعل الوصلة للقراءة فقط. وإذا ضُبط في attr_clr، فإنه يزيل إعداد القراءة فقط إذا كان مضبوطاً على الوصلة.

MOUNT_ATTR_NOSUID
    إذا ضُبط في attr_set، فإنه يجعل الوصلة لا تحترم بتات وضع set-user-ID و set-group-ID وقدرات الملفات عند تنفيذ البرامج. وإذا ضُبط في attr_clr، فإنه يمسح قيود set-user-ID و set-group-ID وقدرات الملفات إذا كانت مضبوطة على هذه الوصلة.

MOUNT_ATTR_NODEV
    إذا ضُبط في attr_set، فإنه يمنع الوصول إلى الأجهزة في هذه الوصلة. وإذا ضُبط في attr_clr، فإنه يزيل القيد الذي كان يمنع الوصول إلى الأجهزة في هذه الوصلة.

MOUNT_ATTR_NOEXEC
    إذا ضُبط في attr_set، فإنه يمنع تنفيذ البرامج في هذه الوصلة. وإذا ضُبط في attr_clr، فإنه يزيل القيد الذي كان يمنع تنفيذ البرامج في هذه الوصلة.

MOUNT_ATTR_NOSYMFOLLOW
    إذا ضُبط في attr_set، فإنه يمنع تتبع الروابط الرمزية في هذه الوصلة. وإذا ضُبط في attr_clr، فإنه يزيل القيد الذي كان يمنع تتبع الروابط الرمزية في هذه الوصلة.

MOUNT_ATTR_NODIRATIME
    إذا ضُبط في attr_set، فإنه يمنع تحديث وقت الوصول للأدلة في هذه الوصلة. وإذا ضُبط في attr_clr، فإنه يزيل القيد الذي كان يمنع تحديث وقت الوصول للأدلة. لاحظ أن MOUNT_ATTR_NODIRATIME يمكن دمجه مع إعدادات وقت الوصول الأخرى، وهو متضمن في إعداد noatime. جميع إعدادات وقت الوصول الأخرى حصرية تبادلياً.

MOUNT_ATTR__ATIME - تغيير إعدادات وقت الوصول
    قيم وقت الوصول المدرجة أدناه هي تعداد يتضمن القيمة صفر، وتُعبر عنها البتات المحددة بواسطة القناع MOUNT_ATTR__ATIME. ورغم أن هذه البتات هي تعداد (على عكس أعلام الوصل الأخرى مثل MOUNT_ATTR_NOEXEC)، إلا أنها تُمرر مع ذلك في attr_set و attr_clr للاتساق مع fsmount(2)، الذي أدخل هذا السلوك.

    لاحظ أنه نظراً لأن قيم وقت الوصول هي تعداد وليست قيم بتات، فإن المستدعِي الذي يرغب في الانتقال إلى إعداد وقت وصول مختلف لا يمكنه ببساطة تحديد إعداد وقت الوصول في attr_set، بل يجب عليه أيضًا تضمين MOUNT_ATTR__ATIME في حقل attr_clr. ستتحقق النواة من أن MOUNT_ATTR__ATIME ليس مضبوطاً بشكل جزئي في attr_clr (أي أن جميع البتات في حقل بت MOUNT_ATTR__ATIME إما مضبوطة أو ممسوحة)، ومن أن attr_set لا يحتوي على أي بتات لوقت الوصول مضبوطة إذا لم يكن MOUNT_ATTR__ATIME مضبوطاً في attr_clr.

    MOUNT_ATTR_RELATIME
        عند الوصول إلى ملف عبر هذه الوصلة، يُحدث آخر وقت وصول للملف (atime) فقط إذا كانت القيمة الحالية لـ atime أقل من أو تساوي آخر وقت تعديل للملف (mtime) أو آخر وقت لتغيير الحالة (ctime).

        لتفعيل إعداد وقت الوصول هذا على وصلة أو شجرة وصل، يجب ضبط MOUNT_ATTR_RELATIME في attr_set وضبط MOUNT_ATTR__ATIME في حقل attr_clr.

    MOUNT_ATTR_NOATIME
        لا يُحدث أوقات الوصول (لجميع أنواع) الملفات في هذه الوصلة.

        لتفعيل إعداد وقت الوصول هذا على وصلة أو شجرة وصل، يجب ضبط MOUNT_ATTR_NOATIME في attr_set وضبط MOUNT_ATTR__ATIME في حقل attr_clr.

    MOUNT_ATTR_STRICTATIME
        يُحدث دائماً وقت الوصول الأخير (atime) عند الوصول إلى الملفات في هذه الوصلة.

        لتفعيل إعداد وقت الوصول هذا على وصلة أو شجرة وصل، يجب ضبط MOUNT_ATTR_STRICTATIME في attr_set وضبط MOUNT_ATTR__ATIME في حقل attr_clr.

MOUNT_ATTR_IDMAP
    إذا ضُبط في attr_set، فإنه ينشئ وصلة معنونة بالمعرفات (ID-mapped mount). يؤخذ تعيين المعرف من مساحة اسم المستخدم المحددة في userns_fd ويُربط بالوصلة.

    بما أنه لا يُدعم تغيير تعيين معرف الوصلة بعد تعيينه، فإنه من غير الصالح تحديد MOUNT_ATTR_IDMAP في attr_clr.

    لمزيد من التفاصيل، انظر القسم الفرعي "الوصلات المعنونة بالمعرفات" تحت NOTES.

يُستخدم حقل propagation لتحديد نوع انتشار الوصل أو شجرة الوصل. هذا الحقل إما أن يحتوي على القيمة صفر، مما يعني ترك نوع الانتشار دون تغيير، أو يحتوي على إحدى القيم التالية:

MS_PRIVATE
    يحول جميع الوصلات إلى وصلات خاصة.

MS_SHARED
    يحول جميع الوصلات إلى وصلات مشتركة.

MS_SLAVE
    يحول جميع الوصلات إلى وصلات تابعة.

MS_UNBINDABLE
    يحول جميع الوصلات إلى وصلات غير قابلة للربط.

لمزيد من التفاصيل حول أنواع الانتشار المذكورة أعلاه، انظر mount_namespaces(7).

قيمة الإرجاع
عند النجاح، يرجع mount_setattr() صفراً. وعند حدوث خطأ، يرجع -1 ويُضبط errno للإشارة إلى الخطأ.

الأخطاء

EBADF
    المسار path نسبي ولكن dirfd ليس AT_FDCWD ولا واصف ملف صالح.

EBADF
    userns_fd ليس واصف ملف صالح.

EBUSY
    حاول المستدعِي تغيير الوصلة إلى MOUNT_ATTR_RDONLY، لكن الوصلة لا تزال تحتوي على ملفات مفتوحة للكتابة.

EBUSY
    حاول المستدعِي إنشاء وصلة معنونة بالمعرفات عبر رفع MOUNT_ATTR_IDMAP وتحديد userns_fd لكن الوصلة لا تزال تحتوي على ملفات مفتوحة للكتابة.

EINVAL
    اسم المسار المحدد عبر المعاملين dirfd و path لـ mount_setattr() ليس نقطة وصل.

EINVAL
    ضُبطت قيمة غير مدعومة في flags.

EINVAL
    حُددت قيمة غير مدعومة في حقل attr_set لـ mount_attr.

EINVAL
    حُددت قيمة غير مدعومة في حقل attr_clr لـ mount_attr.

EINVAL
    حُددت قيمة غير مدعومة في حقل propagation لـ mount_attr.

EINVAL
    ضُبط أكثر من واحد من MS_SHARED أو MS_SLAVE أو MS_PRIVATE أو MS_UNBINDABLE في حقل propagation لـ mount_attr.

EINVAL
    حُدد إعداد وقت الوصول في حقل attr_set دون ضبط MOUNT_ATTR__ATIME في حقل attr_clr.

EINVAL
    حُدد MOUNT_ATTR_IDMAP في attr_clr.

EINVAL
    حُددت قيمة واصف ملف في userns_fd تتجاوز INT_MAX.

EINVAL
    حُددت قيمة واصف ملف صالحة في userns_fd، لكن واصف الملف لا يشير إلى مساحة اسم مستخدم.

EINVAL
    نظام الملفات الأساسي لا يدعم الوصلات المعنونة بالمعرفات.

EINVAL
    الوصلة المراد عنونتها بالمعرف ليست وصلة منفصلة؛ أي أن الوصلة لم تكن مرئية مسبقاً في مساحة اسم وصل.

EINVAL
    حُدد إعداد وقت وصول جزئي في attr_clr بدلاً من ضبط MOUNT_ATTR__ATIME.

EINVAL
    تقع الوصلة خارج مساحة اسم الوصل الخاصة بالمستدعِي.

EINVAL
    نُظم نظام الملفات الأساسي في مساحة اسم وصل مملوكة لمساحة اسم مستخدم غير أولية

ENOENT
    كان اسم المسار فارغاً أو احتوى على مكون غير موجود.

ENOMEM
    عند تغيير انتشار الوصل إلى MS_SHARED، تجب تخصيص معرف مجموعة أقران جديد لكل عمليات الوصل التي لا تملك معرف مجموعة أقران مضبوطًا. فشل هذا التخصيص بسبب عدم توفر ذاكرة كافية لتخصيص الهياكل الداخلية ذات الصلة.

ENOSPC
    عند تغيير انتشار الوصل إلى MS_SHARED، تجب تخصيص معرف مجموعة أقران جديد لكل عمليات الوصل التي لا تملك معرف مجموعة أقران مضبوطًا. فشل هذا التخصيص لأن النواة استنفدت جميع المعرفات المتاحة.

EPERM
    كانت إحدى عمليات الوصل تملك وسمًا واحدًا على الأقل من MOUNT_ATTR_NOATIME أو MOUNT_ATTR_NODEV أو MOUNT_ATTR_NODIRATIME أو MOUNT_ATTR_NOEXEC أو MOUNT_ATTR_NOSUID أو MOUNT_ATTR_RDONLY مضبوطًا وكان العلم مقفلًا. تُقفل سمات الوصل في حالات الوصل التالية:

    •   أُنشئ وصل جديد أو شجرة وصل تسببت في انتشار الوصل عبر مساحات أسماء المستخدمين (أي الانتشار إلى مساحة أسماء وصل يملكها مساحة أسماء مستخدم مختلفة). ستقفل النواة الأعلام المذكورة أعلاه لمنع تغيير هذه الخصائص الحساسة.

    •   أُنشئ زوج جديد من مساحة أسماء الوصل والمستخدم. يحدث هذا على سبيل المثال عند تحديد CLONE_NEWUSER | CLONE_NEWNS في unshare(2) أو clone(2) أو clone3(2). تُقفل الأعلام المذكورة أعلاه في مساحة أسماء الوصل الجديدة لمنع تغيير خصائص الوصل الحساسة. نظرًا لأن مساحة أسماء الوصل المنشأة حديثًا ستكون مملوكة لمساحة أسماء المستخدم المنشأة حديثًا، فإن المستدعِي الذي يملك امتيازات في مساحة أسماء المستخدم الجديدة سيكون قادرًا — في غياب هذا القفل — على تغيير خصائص الوصل الحساسة (مثل إعادة وصل وصلة كانت للقراءة فقط لتصبح للقراءة والكتابة في مساحة أسماء الوصل الجديدة).

EPERM
    حُددت قيمة واصف ملف صالحة في userns_fd، ولكن واصف الملف يشير إلى مساحة أسماء المستخدم المبدئية.

EPERM
    جرت محاولة لإضافة تخطيط معرف (ID mapping) لوصلة تملك بالفعل تخطيط معرف.

EPERM
    لا يملك المستدعِي صلاحية CAP_SYS_ADMIN في مساحة أسماء المستخدم المبدئية.

المعايير
لينكس.

التاريخ
لينكس 5.12، glibc 2.36.

ملاحظات

  عمليات الوصل المخططة بالمعرف (ID-mapped)
يتيح إنشاء وصلة مخططة بالمعرف إمكانية تغيير ملكية جميع الملفات الموجودة تحت هذا الوصل. وبالتالي، تسمح عمليات الوصل المخططة بالمعرف بتغيير الملكية بشكل مؤقت ومحلي. هو تغيير محلي لأن تغييرات الملكية لا تظهر إلا من خلال وصلة محددة؛ ولا يتأثر جميع المستخدمين والمواقع الأخرى التي يُعرض فيها نظام الملفات. وهو تغيير مؤقت لأن تغييرات الملكية مرتبطة بعمر الوصلة.

كلما تفاعل المستدعِي مع نظام الملفات من خلال وصلة مخططة بالمعرف، سيُطبق تخطيط معرف الوصلة على معرفات المستخدم والمجموعة المرتبطة بكائنات نظام الملفات. يشمل ذلك معرفات المستخدم والمجموعة المرتبطة بـ inodes وأيضًا مفاتيح xattr(7) التالية:

•   security.capability، كلما خُزنت صلاحيات نظام الملفات أو أُرجعت بتنسيق VFS_CAP_REVISION_3، الذي يخزن معرف مستخدم جذر بجانب الصلاحيات (انظر capabilities(7)).

•   system.posix_acl_access و system.posix_acl_default، كلما خُزنت معرفات المستخدم أو معرفات المجموعة في مدخلات ACL_USER أو ACL_GROUP.

يجب استيفاء الشروط التالية لإنشاء وصلة مخططة بالمعرف:

•   يجب أن يملك المستدعِي صلاحية CAP_SYS_ADMIN في مساحة أسماء المستخدم التي وُصل فيها نظام الملفات.

•   يجب أن يدعم نظام الملفات الأساسي عمليات الوصل المخططة بالمعرف. حاليًا، تدعم أنظمة الملفات التالية هذه الميزة:

    •   xfs(5) (منذ لينكس 5.12)
    •   ext4(5) (منذ لينكس 5.12)
    •   FAT (منذ لينكس 5.12)
    •   btrfs(5) (منذ لينكس 5.15)
    •   ntfs3 (منذ لينكس 5.15)
    •   f2fs (منذ لينكس 5.18)
    •   erofs (منذ لينكس 5.19)
    •   overlayfs (دُعمت الطبقات السفلى والعليا المخططة بالمعرف منذ لينكس 5.19)
    •   squashfs (منذ لينكس 6.2)
    •   tmpfs (منذ لينكس 6.3)
    •   cephfs (منذ لينكس 6.7)
    •   hugetlbfs (منذ لينكس 6.9)

•   يجب ألا تكون الوصلة مخططة بالمعرف بالفعل. وهذا يعني أيضًا أنه لا يمكن تغيير تخطيط المعرف لوصلة ما.

•   يجب ألا تحتوي الوصلة على أي كُتّاب (writers).

•   يجب أن تكون الوصلة وصلة منفصلة؛ أي يجب أن تكون قد أُنشئت باستدعاء open_tree(2) مع العلم OPEN_TREE_CLONE ويجب ألا تكون مرئية بالفعل في مساحة أسماء وصل. (وبعبارة أخرى: يجب ألا تكون الوصلة قد رُبطت بالتسلسل الهرمي لنظام الملفات باستدعاء نظام مثل move_mount(2).)

يمكن إنشاء تخطيطات المعرف لمعرفات المستخدم والمجموعة والمشروع. تخطيط المعرف هو في الأساس تخطيط لنطاق من معرفات المستخدم أو المجموعة إلى نطاق آخر أو نفس النطاق من المعرفات. تُكتب تخطيطات المعرف في ملفات التخطيط كأربعة أرقام مفصولة بمسافات بيضاء. يحدد الرقمان الأولان معرف المستخدم أو المجموعة البادئ في كل من مساحتي أسماء المستخدمين. ويحدد الرقم الثالث نطاق تخطيط المعرف. على سبيل المثال، التخطيط لمعرفات المستخدم مثل "1000 1001 1" يشير إلى أن معرف المستخدم 1000 في مساحة أسماء المستخدم للمستدعِي يُخطط إلى معرف المستخدم 1001 في مساحة أسماء المستخدم السلف. وبما أن نطاق الخريطة هو 1، يُخطط المعرف 1000 فقط.

من الممكن تحديد ما يصل إلى 340 تخطيط معرف لكل نوع من أنواع التخطيط. إذا لم تُخطط أي معرفات مستخدم أو مجموعة، فإن جميع الملفات المملوكة لهذا المعرف غير المخطط ستظهر كما لو كانت مملوكة لمعرف مستخدم الفائض (overflow) أو معرف مجموعة الفائض على التوالي.

يمكن العثور على مزيد من التفاصيل حول إعداد تخطيطات المعرف في user_namespaces(7).

في الحالة الشائعة، تكون مساحة أسماء المستخدم الممرة في userns_fd (مع MOUNT_ATTR_IDMAP في attr_set) لإنشاء وصلة مخططة بالمعرف هي مساحة أسماء المستخدم الخاصة بحاوية (container). وفي سيناريوهات أخرى ستكون مساحة أسماء مستخدم مخصصة مرتبطة بجلسة تسجيل دخول المستخدم كما هو الحال في الأدلة المنزلية المحمولة في systemd-homed.service(8). ومن الجيد أيضًا إنشاء مساحة أسماء مستخدم مخصصة لغرض تخطيط معرف وصلة ما.

يمكن أن تكون عمليات الوصل المخططة بالمعرف مفيدة في السيناريوهات التالية وغيرها الكثير:

•   مشاركة الملفات أو أنظمة الملفات بين مستخدمين متعددين أو أجهزة متعددة، خاصة في السيناريوهات المعقدة. على سبيل المثال، تُستخدم عمليات الوصل المخططة بالمعرف لتنفيذ الأدلة المنزلية المحمولة في systemd-homed.service(8)، حيث تسمح للمستخدمين بنقل دليلهم المنزلي إلى جهاز تخزين خارجي واستخدامه على حواسيب متعددة حيث يتم تعيين معرفات مستخدم ومجموعة مختلفة لهم. يجعل هذا من الممكن فعليًا تعيين معرفات مستخدم ومجموعة عشوائية وقت تسجيل الدخول.

•   مشاركة الملفات أو أنظمة الملفات من المضيف مع حاويات غير مميزة. يسمح هذا للمستخدم بتجنب الاضطرار إلى تغيير الملكية بشكل دائم عبر chown(2).

•   تخطيط معرف نظام الملفات الجذر للحاوية. لا يحتاج المستخدمون لتغيير الملكية دائمًا عبر chown(2). خاصة بالنسبة لأنظمة الملفات الجذرية الكبيرة، يمكن أن يكون استخدام chown(2) مكلفًا للغاية من حيث الوقت والموارد.

•   مشاركة الملفات أو أنظمة الملفات بين الحاويات ذات تخطيطات المعرف غير المتداخلة.

•   تنفيذ فحص أذونات الوصول الاختياري (DAC) لأنظمة الملفات التي تفتقر لمفهوم الملكية.

•   تغيير الملكية بكفاءة على أساس كل وصلة. على عكس chown(2)، فإن تغيير ملكية مجموعات كبيرة من الملفات يتم بلحظة واحدة مع عمليات الوصل المخططة بالمعرف. يفيد هذا بشكل خاص عند الرغبة في تغيير ملكية نظام ملفات جذر كامل لآلة افتراضية أو حاوية كما ذُكر أعلاه. مع الوصلات المخططة بالمعرف، يكفي استدعاء نظام mount_setattr() واحد لتغيير ملكية جميع الملفات.

•   مراعاة الملكية الحالية. تحدد تخطيطات المعرف بدقة ما الذي يجب أن يُخطط إليه معرف المستخدم أو المجموعة. وهذا يتناقض مع استدعاء النظام chown(2) الذي لا يمكنه تلقائيًا مراعاة الملكية الحالية للملفات التي يغيرها؛ بل يكتفي بتغيير الملكية إلى معرف المستخدم والمجموعة المحددين.

•   تغييرات الملكية المقيدة محليًا ومؤقتًا. تجعل عمليات الوصل المخططة بالمعرف من الممكن تغيير الملكية محليًا، وقصر تغييرات الملكية على وصلات محددة، ومؤقتًا حيث لا تنطبق تغييرات الملكية إلا طالما أن الوصلة موجودة. في المقابل، يؤدي تغيير الملكية عبر استدعاء النظام chown(2) إلى تغيير الملكية عالميًا وبشكل دائم.

  سمات الوصل ومعاملات نظام الملفات
تمتلك بعض سمات الوصل (المرتبطة تقليديًا بخيارات نمط mount(8)) معامل نظام ملفات نظير بسلوك مشابه ظاهريًا للمستخدم. على سبيل المثال، الخيار -o ro في mount(8) قد يشير إلى معامل نظام الملفات "للقراءة فقط"، أو سمة الوصل "للقراءة فقط". كلاهما يؤدي إلى جعل كائنات الوصل للقراءة فقط، لكنهما يملكان سلوكًا مختلفًا.

الفرق بين هذين النوعين من الخيارات هو أن سمات كائن الوصل تُطبق لكل كائن وصل على حدة (مما يسمح لكائنات وصل مختلفة مشتقة من نسخة نظام ملفات معينة أن تملك سمات مختلفة)، بينما تُطبق معاملات نسخة نظام الملفات ("أعلام الكتلة الفائقة - superblock flags" بلغة مطوري النواة) على جميع كائنات الوصل المشتقة من نفس نسخة نظام الملفات.

عند استخدام mount(2)، كانت الحدود بين هذين النوعين من خيارات الوصل ضبابية. ومع ذلك، مع mount_setattr() و fsconfig(2)، أصبح التمييز أكثر وضوحًا. تُضبط سمات الوصل باستخدام mount_setattr()، بينما تُضبط معاملات نظام الملفات باستخدام fsconfig(2).

  القابلية للتوسع
للسماح بالتوسع المستقبلي، يتطلب mount_setattr() من تطبيق مساحة المستخدم تحديد حجم هيكل mount_attr الذي يمرره. بتوفير هذه المعلومات، يمكن لـ mount_setattr() توفير توافق مع الإصدارات اللاحقة والسابقة، حيث يعمل size كرقم إصدار ضمني. (نظرًا لأن حقول التوسعة الجديدة ستُلحق دائمًا في النهاية، فإن حجم الهيكل سيزداد دائمًا). هذا التصميم لقابلية التوسع مشابه جدًا لاستدعاءات نظام أخرى مثل perf_setattr(2) و perf_event_open(2) و clone3(2) و openat2(2).

ليكن usize هو حجم الهيكل كما حدده تطبيق مساحة المستخدم، و ksize هو حجم الهيكل الذي تدعمه النواة، وعندها توجد ثلاث حالات للنظر فيها:

•   إذا كان ksize يساوي usize، فلا يوجد تعارض في الإصدار ويمكن استخدام attr كما هو.

•   إذا كان ksize أكبر من usize، فهذا يعني وجود بعض حقول التوسعة التي تدعمها النواة ولكن تطبيق مساحة المستخدم لا يدركها. ولأن القيمة الصفرية في أي حقل توسعة مضاف تعني عدم التنفيذ (no-op)، تعامل النواة جميع حقول التوسعة التي لم يوفرها تطبيق مساحة المستخدم على أنها ذات قيم صفرية. يوفر هذا توافقا مع الإصدارات السابقة.

•   إذا كان ksize أصغر من usize، فهذا يعني وجود بعض حقول التوسعة التي يدركها تطبيق مساحة المستخدم ولكن النواة لا تدعمها. ولأن أي حقل توسعة يجب أن تعني قيمته الصفرية عدم التنفيذ، يمكن للنواة تجاهل حقول التوسعة غير المدعومة بأمان إذا كانت جميعها صفرية. وإذا كانت أي من حقول التوسعة غير المدعومة غير صفرية، فسيُرجع -1 ويُضبط errno على E2BIG. يوفر هذا توافقًا مع الإصدارات اللاحقة.

نظرًا لأن تعريف struct mount_attr قد يتغير في المستقبل (بإضافة حقول جديدة عند تحديث ترويسات النظام)، يجب على تطبيقات مساحة المستخدم ملء هيكل struct mount_attr بالأصفار لضمان أن إعادة تصريف البرنامج بترويسات جديدة لن تؤدي إلى أخطاء زائفة وقت التشغيل. أبسط طريقة هي استخدام تهيئة محددة:

    struct mount_attr attr = {
        .attr_set = MOUNT_ATTR_RDONLY,
        .attr_clr = MOUNT_ATTR_NODEV
    };

بدلًا من ذلك، يمكن ملء الهيكل بالأصفار باستخدام memset(3) أو وظائف مماثلة:

    struct mount_attr attr;
    memset(&attr, 0, sizeof(attr));
    attr.attr_set = MOUNT_ATTR_RDONLY;
    attr.attr_clr = MOUNT_ATTR_NODEV;

يمكن لتطبيق في مساحة المستخدم يرغب في تحديد الامتدادات التي تدعمها النواة العاملة القيام بذلك عن طريق إجراء بحث ثنائي على size مع هيكل يحتوي كل بايت فيه على قيمة غير صفرية (للعثور على أكبر قيمة لا تنتج خطأ E2BIG).

أمثلة
    /*
     * This program allows the caller to create a new detached mount
     * and set various properties on it.
     */
    #define _GNU_SOURCE
    #include <err.h>
    #include <fcntl.h>
    #include <getopt.h>
    #include <sys/mount.h>
    #include <sys/types.h>
    #include <stdbool.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>

    static const struct option longopts[] = {
        {"map-mount",       required_argument,  NULL,  'a'},
        {"recursive",       no_argument,        NULL,  'b'},
        {"read-only",       no_argument,        NULL,  'c'},
        {"block-setid",     no_argument,        NULL,  'd'},
        {"block-devices",   no_argument,        NULL,  'e'},
        {"block-exec",      no_argument,        NULL,  'f'},
        {"no-access-time",  no_argument,        NULL,  'g'},
        { NULL,             0,                  NULL,   0 },
    };

    int
    main(int argc, char *argv[])
    {
        int                fd_userns = -1;
        int                fd_tree;
        int                index = 0;
        int                ret;
        bool               recursive = false;
        const char         *source;
        const char         *target;
        struct mount_attr  *attr = &(struct mount_attr){};

        while ((ret = getopt_long_only(argc, argv, "",
                                       longopts, &index)) != -1) {
            switch (ret) {
            case 'a':
                fd_userns = open(optarg, O_RDONLY | O_CLOEXEC);
                if (fd_userns == -1)
                    err(EXIT_FAILURE, "open(%s)", optarg);
                break;
            case 'b':
                recursive = true;
                break;
            case 'c':
                attr->attr_set |= MOUNT_ATTR_RDONLY;
                break;
            case 'd':
                attr->attr_set |= MOUNT_ATTR_NOSUID;
                break;
            case 'e':
                attr->attr_set |= MOUNT_ATTR_NODEV;
                break;
            case 'f':
                attr->attr_set |= MOUNT_ATTR_NOEXEC;
                break;
            case 'g':
                attr->attr_set |= MOUNT_ATTR_NOATIME;
                attr->attr_clr |= MOUNT_ATTR__ATIME;
                break;
            default:
                errx(EXIT_FAILURE, "Invalid argument specified");
            }
        }

        if ((argc - optind) < 2)
            errx(EXIT_FAILURE, "Missing source or target mount point");

        source = argv[optind];
        target = argv[optind + 1];

        /* In the following, -1 as the 'dirfd' argument ensures that
           open_tree() fails if 'source' is not an absolute pathname.  */

        fd_tree = open_tree(-1, source,
                            OPEN_TREE_CLONE | OPEN_TREE_CLOEXEC |
                            AT_EMPTY_PATH | (recursive ? AT_RECURSIVE : 0));
        if (fd_tree == -1)
            err(EXIT_FAILURE, "open(%s)", source);

        if (fd_userns >= 0) {
            attr->attr_set  |= MOUNT_ATTR_IDMAP;
            attr->userns_fd = fd_userns;
        }

        ret = mount_setattr(fd_tree, "",
                            AT_EMPTY_PATH | (recursive ? AT_RECURSIVE : 0),
                            attr, sizeof(struct mount_attr));
        if (ret == -1)
            err(EXIT_FAILURE, "mount_setattr");

        close(fd_userns);

        /* In the following, -1 as the 'to_dirfd' argument ensures that
           open_tree() fails if 'target' is not an absolute pathname.  */

        ret = move_mount(fd_tree, "", -1, target,
                         MOVE_MOUNT_F_EMPTY_PATH);
        if (ret == -1)
            err(EXIT_FAILURE, "move_mount() to %s", target);

        close(fd_tree);

        exit(EXIT_SUCCESS);
    }

انظر أيضًا
newgidmap(1)، newuidmap(1)، clone(2)، mount(2)، unshare(2)، proc(5)، capabilities(7)، mount_namespaces(7)، user_namespaces(7)، xattr(7)

ترجمة
تُرجمت هذه الصفحة من الدليل بواسطة زايد السعيدي <zayed.alsaidi@gmail.com>

هذه الترجمة هي وثيقة مجانية؛ راجع رخصة جنو العامة الإصدار 3 (https://www.gnu.org/licenses/gpl-3.0.html) أو ما بعده للاطلاع على شروط حقوق النشر. لا توجد أي ضمانات.

إذا وجدت أي أخطاء في ترجمة صفحة الدليل هذه، يرجى إرسال بريد إلكتروني إلى قائمة بريد المترجمين: kde-l10n-ar@kde.org.