close_range(2)

الاسم
close_range - إغلاق كل واصفات الملفات في نطاق معين

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

موجز
#define _GNU_SOURCE         /* انظر feature_test_macros(7) */
#include <unistd.h>

#include <linux/close_range.h> /* Definition of CLOSE_RANGE_*
                                  constants */

int close_range(unsigned int first, unsigned int last, int flags);

الوصف
استدعاء النظام close_range() يغلق كل واصفات الملفات المفتوحة من first إلى last (شاملًا).

الأخطاء عند إغلاق واصف ملف معين تُتجاهل حاليًا.

flags هو قناع بت يحتوي على 0 أو أكثر مما يلي:

CLOSE_RANGE_CLOEXEC (منذ لينكس 5.11)
    يضبط علم الإغلاق عند التنفيذ على واصفات الملفات المحددة، بدلًا من إغلاقها فورًا.

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

قيمة الإرجاع
عند النجاح، تُرجع close_range() 0. عند الخطأ، تُرجع -1 ويُضبط errno للإشارة إلى الخطأ.

الأخطاء

EINVAL
    flags غير صالح، أو first أكبر من last.

ما يلي يمكن أن يحدث مع CLOSE_RANGE_UNSHARE (عند بناء جدول الواصفات الجديد):

EMFILE
    عدد واصفات الملفات المفتوحة يتجاوز الحد المحدد في /proc/sys/fs/nr_open (انظر proc(5)). هذا الخطأ يمكن أن يحدث في حالات حيث خُفض ذلك الحد قبل استدعاء close_range() حيث يُحدد علم CLOSE_RANGE_UNSHARE.

ENOMEM
    ذاكرة النواة المتوفرة غير كافية.

المعايير
لا شيء.

التاريخ
فري بي إس دي. لينكس 5.9، جليبتك 2.34.

ملاحظات

  إغلاق كل واصفات الملفات المفتوحة
لتجنب إغلاق واصفات الملفات بشكل أعمى في نطاق واصفات الملفات الممكنة، يُنفذ هذا أحيانًا (على لينكس) بسرد واصفات الملفات المفتوحة في /proc/self/fd/ واستدعاء close(2) على كل واحد. close_range() يمكنه التعامل مع هذا دون الحاجة إلى /proc وداخل استدعاء نظام واحد، مما يوفر فوائد أداء كبيرة.

  إغلاق واصفات الملفات قبل التنفيذ
يمكن إغلاق واصفات الملفات بأمان باستخدام

    /* we don't want anything past stderr here */
    close_range(3, ~0U, CLOSE_RANGE_UNSHARE);
    execve(....);

CLOSE_RANGE_UNSHARE مكافئ من الناحية المفاهيمية لـ

    unshare(CLONE_FILES);
    close_range(first, last, 0);

لكنه يمكن أن يكون أكثر كفاءة: إذا امتد النطاق المفصول إلى ما بعد الحد الأقصى الحالي لعدد واصفات الملفات المخصصة في جدول واصفات ملفات المستدعي (الحالة الشائعة عندما يكون last هو ~0U)، سيفصل النواة جدول واصفات ملفات جديد للمستدعي حتى first، ناسخًا أقل عدد ممكن من واصفات الملفات. هذا يتجنب استدعاءات close(2) اللاحقة تمامًا؛ تكتمل العملية بأكملها بمجرد فصل الجدول.

  إغلاق الملفات عند التنفيذ
هذا مفيد بشكل خاص في الحالات حيث خطوات الإعداد المتعددة قبل exec تخاطر بالتعارض مع بعضها البعض. على سبيل المثال، إعداد تشكيلة seccomp(2) يمكن أن يتعارض مع استدعاء close_range(): إذا أغلقت واصفات الملفات قبل إعداد تشكيلة seccomp(2)، لا يمكن لإعداد التشكيلة استخدامها بنفسها، أو التحكم في إغلاقها؛ إذا أغلقت واصفات الملفات بعد ذلك، لا يمكن لتشكيلة seccomp حظر استدعاء close_range() أو أي بدائل. استخدام CLOSE_RANGE_CLOEXEC يتجنب هذا: يمكن وضع علامة على الواصفات قبل إعداد تشكيلة seccomp(2)، ويمكن للتشكيلة التحكم في الوصول إلى close_range() دون التأثير على عملية الاستدعاء.

أمثلة
البرنامج الموضح أدناه يفتح الملفات المسماة في وسائط سطر الأوامر الخاصة به، يعرض قائمة الملفات التي فتحها (بالتكرار عبر الإدخالات في /proc/PID/fd)، يستخدم close_range() لإغلاق كل واصفات الملفات الأكبر من أو تساوي 3، ثم يعرض مرة أخرى قائمة الملفات المفتوحة للعملية. المثال التالي يوضح استخدام البرنامج:

    $ touch /tmp/a /tmp/b /tmp/c;
    $ ./a.out /tmp/a /tmp/b /tmp/c;
    /tmp/a opened as FD 3
    /tmp/b opened as FD 4
    /tmp/c opened as FD 5
    /proc/self/fd/0 ==> /dev/pts/1
    /proc/self/fd/1 ==> /dev/pts/1
    /proc/self/fd/2 ==> /dev/pts/1
    /proc/self/fd/3 ==> /tmp/a
    /proc/self/fd/4 ==> /tmp/b
    /proc/self/fd/5 ==> /tmp/c
    /proc/self/fd/6 ==> /proc/9005/fd
    ========= About to call close_range() =======
    /proc/self/fd/0 ==> /dev/pts/1
    /proc/self/fd/1 ==> /dev/pts/1
    /proc/self/fd/2 ==> /dev/pts/1
    /proc/self/fd/3 ==> /proc/9005/fd

لاحظ أن الأسطر التي تظهر اسم المسار /proc/9005/fd تنتج عن استدعاءات opendir(3).

  مصدر البرنامج
    #define _GNU_SOURCE
    #include <dirent.h>
    #include <fcntl.h>
    #include <limits.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <sys/types.h>
    #include <unistd.h>

    /* إظهار محتويات الروابط الرمزية في /proc/self/fd */

    static void
    show_fds(void)
    {
        DIR            *dirp;
        char           path[PATH_MAX], target[PATH_MAX];
        ssize_t        len;
        struct dirent  *dp;

        dirp = opendir("/proc/self/fd");
        if (dirp  == NULL) {
            perror("opendir");
            exit(EXIT_FAILURE);
        }

        for (;;) {
            dp = readdir(dirp);
            if (dp == NULL)
                break;

            if (dp->d_type == DT_LNK) {
                snprintf(path, sizeof(path), "/proc/self/fd/%s",
                         dp->d_name);

                len = readlink(path, target, sizeof(target));
                printf("%s ==> %.*s\n", path, (int) len, target);
            }
        }

        closedir(dirp);
    }

    int
    main(int argc, char *argv[])
    {
        int  fd;

        for (size_t j = 1; j < argc; j++) {
            fd = open(argv[j], O_RDONLY);
            if (fd == -1) {
                perror(argv[j]);
                exit(EXIT_FAILURE);
            }
            printf("%s opened as FD %d\n", argv[j], fd);
        }

        show_fds();

        printf("========= About to call close_range() =======\n");

        if (close_range(3, ~0U, 0) == -1) {
            perror("close_range");
            exit(EXIT_FAILURE);
        }

        show_fds();
        exit(EXIT_FAILURE);
    }

انظر أيضًا
close(2)

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

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

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