execve(2)

الاسم
execve - تنفيذ برنامج

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

موجز
#include <unistd.h>

int execve(const char *path, char *const _Nullable argv[],
           char *const _Nullable envp[]);

الوصف
ينفذ execve() البرنامج المشار إليه بواسطة path. يتسبب هذا في استبدال البرنامج المُشغل حاليًا بواسطة العملية المستدعية ببرنامج جديد، مع مكدس، وكومة، وقطاعات بيانات (مهيأة وغير مهيأة) معاد تهيئتها.

يجب أن يكون path إما ملفًا ثنائيًا قابلًا للتنفيذ، أو نصًا برمجيًا يبدأ بسطر بالشكل:

    #!interpreter
    [optional-arg]

للحصول على تفاصيل الحالة الأخيرة، راجع "النصوص البرمجية للمفسر" أدناه.

argv هو مصفوفة من المؤشرات إلى سلاسل تُمرر إلى البرنامج الجديد كوسائط سطر الأوامر الخاصة به. وفقًا للاتفاقية، يجب أن تحتوي أول هذه السلاسل (أي argv[0]) على اسم الملف المرتبط بالملف الذي يُنفذ. يجب إنهاء مصفوفة argv بمؤشر فارغ. (وبالتالي، في البرنامج الجديد، سيكون argv[argc] مؤشرًا فارغًا.)

envp هو مصفوفة من المؤشرات إلى سلاسل، تقليديًا بالشكل key=value، والتي تُمرر كبيئة للبرنامج الجديد. يجب إنهاء مصفوفة envp بمؤشر فارغ.

تصف صفحة الدليل هذه استدعاء نظام Linux بالتفصيل؛ للحصول على نظرة عامة على التسمية والعديد من المتغيرات الموحدة، التي غالبًا ما تكون مفضلة، لهذه الوظيفة التي توفرها libc، بما في ذلك تلك التي تبحث في متغير البيئة PATH، راجع exec(3).

يمكن الوصول إلى متجه الوسائط والبيئة بواسطة الدالة main للبرنامج الجديد، عندما تُعرف على النحو التالي:

    int main(int argc, char *argv[], char *envp[])

لاحظ، مع ذلك، أن استخدام وسيطة ثالثة للدالة main غير محدد في POSIX.1؛ وفقًا لـ POSIX.1، يجب الوصول إلى البيئة عبر المتغير الخارجي environ(7).

لا يعيد execve() القيمة عند النجاح، ويُستبدل النص، والبيانات المهيأة، والبيانات غير المهيأة (bss)، والمكدس للعملية المستدعية وفقًا لمحتويات البرنامج المحمل حديثًا.

إذا كان البرنامج الحالي قيد التتبع (ptraced)، تُرسل إشارة SIGTRAP إليه بعد نجاح execve().

إذا عُيين بت set-user-ID على ملف البرنامج المشار إليه بواسطة path، فسيُغير معرف المستخدم الفعال للعملية المستدعية إلى معرف مالك ملف البرنامج. وبالمثل، إذا عُيين بت set-group-ID على ملف البرنامج، فسعُيين معرف المجموعة الفعال للعملية المستدعية إلى مجموعة ملف البرنامج.

لا تُجرى التحويلات المذكورة أعلاه للمعرفات الفعالة (أي تُجاهل بتات set-user-ID و set-group-ID) إذا كان أي مما يلي صحيحًا:

•   عُيين السمة no_new_privs للخيط المستدعي (راجع prctl(2));

•   نظام الملفات الأساسي موصول (mounted) بـ nosuid (علامة MS_NOSUID لـ mount(2)); أو

•   العملية المستدعية قيد التتبع (ptraced).

تُتجاهل أيضًا قدرات ملف البرنامج (راجع capabilities(7)) إذا كان أي مما سبق صحيحًا.

يُنسخ معرف المستخدم الفعال للعملية إلى set-user-ID المحفوظ؛ وبالمثل، يُنسخ معرف المجموعة الفعال إلى set-group-ID المحفوظ. يحدث هذا النسخ بعد أي تغييرات في المعرف الفعال تحدث بسبب بتات الوضع set-user-ID و set-group-ID.

لا تتغير معرفات UID الحقيقية و GID الحقيقية للعملية، بالإضافة إلى معرفات مجموعاتها الإضافية، باستدعاء execve().

إذا كان الملف القابل للتنفيذ هو ملف ثنائي a.out مرتبط ديناميكيًا يحتوي على كعب مكتبات مشتركة، يُستدعى الرابط الديناميكي للينكس ld.so(8) في بداية التنفيذ لإحضار الكائنات المشتركة المطلوبة إلى الذاكرة وربط الملف القابل للتنفيذ بها.

إذا كان الملف القابل للتنفيذ هو ملف ELF مرتبط ديناميكيًا، يُستخدم المفسر المسمى في مقطع PT_INTERP لتحميل الكائنات المشتركة المطلوبة. هذا المفسر هو عادةً /lib/ld-linux.so.2 للملفات الثنائية المرتبطة بـ glibc (راجع ld-linux.so(8)).

  التأثير على سمات العملية
يُحفاظ على جميع سمات العملية أثناء execve()، باستثناء ما يلي:

•   يُعاد تعيين ترتيبات أي إشارات تُلتقط إلى المبدئي (signal(7)).

•   لا يُحافظ على أي مكدس إشارة بديل (sigaltstack(2)).

•   لا يُحافظ على تعيينات الذاكرة (mmap(2)).

•   تُفصل مقاطع الذاكرة المشتركة System V المرفقة (shmat(2)).

•   يُلغى تعيين مناطق الذاكرة المشتركة POSIX (shm_open(3)).

•   تُغلق واصفات قائمة انتظار الرسائل POSIX المفتوحة (mq_overview(7)).

•   تُغلق أي إشارات مسماة POSIX مفتوحة (sem_overview(7)).

•   المؤقتات الزمنية لـ POSIX لا تُحفظ (timer_create(2)).

•   أي تيارات دليل مفتوحة تُغلق (opendir(3)).

•   أقفال الذاكرة لا تُحفظ (mlock(2), mlockall(2)).

•   معالجات الخروج لا تُحفظ (atexit(3), on_exit(3)).

•   بيئة الفاصلة العائمة تُعاد ضبطها إلى المبدئي (انظر fenv(3)).

جميع سمات العملية في القائمة السابقة محددة في POSIX.1. سمات العملية الخاصة بلينكس التالية أيضًا لا تُحفظ أثناء execve():

•   سمة "dumpable" للعملية تُضبط إلى القيمة 1، ما لم يكن برنامج set-user-ID أو set-group-ID أو برنامج ذو قدرات يُنفذ، وفي هذه الحالة قد تُعاد ضبط علامة dumpable بدلاً من ذلك إلى القيمة في /proc/sys/fs/suid_dumpable، في الظروف الموصوفة تحت PR_SET_DUMPABLE في prctl(2). لاحظ أن التغييرات في سمة "dumpable" قد تسبب تغيير ملكية الملفات في دليل /proc/pid للعملية إلى root:root، كما هو موصوف في proc(5).

•   علامة prctl(2) PR_SET_KEEPCAPS تُمسح.

•   (منذ لينكس 2.4.36 / 2.6.23) إذا كان برنامج set-user-ID أو set-group-ID يُنفذ، فإن إشارة موت الأب المضبوطة بواسطة علامة prctl(2) PR_SET_PDEATHSIG تُمسح.

•   اسم العملية، كما ضُبط بواسطة prctl(2) PR_SET_NAME (ويُعرض بواسطة ps -o comm)، يُعاد ضبطه إلى اسم الملف القابل للتنفيذ الجديد.

•   علامة SECBIT_KEEP_CAPS securebits تُمسح. انظر capabilities(7).

•   إشارة الإنهاء تُعاد ضبطها إلى SIGCHLD (انظر clone(2)).

•   جدول واصف الملف يُلغى مشاركته، مما يلغي تأثير علامة CLONE_FILES لـ clone(2).

لاحظ النقاط الإضافية التالية:

•   جميع الخيوط غير الخيط المستدعي تُدمر أثناء execve(). كائنات المزامنة ومتغيرات الشرط وكائنات pthreads الأخرى لا تُحفظ.

•   ما يعادل setlocale(LC_ALL, "C") يُنفذ عند بدء تشغيل البرنامج.

•   يحدد POSIX.1 أن ترتيبات أي إشارات تُهمل أو تُضبط إلى المبدئي تُترك دون تغيير. يحدد POSIX.1 استثناءً واحدًا: إذا كانت SIGCHLD تُهمل، فقد يترك التنفيذ الترتيب دون تغيير أو يعيد ضبطه إلى المبدئي؛ لينكس يفعل الأول.

•   أي عمليات إدخال/إخراج غير متزامنة معلقة تُلغى (aio_read(3), aio_write(3)).

•   لمعالجة القدرات أثناء execve()، انظر capabilities(7).

•   بشكل مبدئي، تبقى واصفات الملفات مفتوحة عبر execve(). واصفات الملفات الموسومة بـ close-on-exec تُغلق؛ انظر وصف FD_CLOEXEC في fcntl(2). (إذا أُغلق واصف ملف، سيؤدي ذلك إلى تحرير جميع أقفال السجلات التي حصلت عليها هذه العملية على الملف الأساسي. انظر fcntl(2) للتفاصيل.) يقول POSIX.1 أنه إذا كانت واصفات الملفات 0 و1 و2 ستُغلق لولا ذلك بعد execve() ناجح، وستكتسب العملية امتيازًا لأن بت وضع set-user-ID أو set-group-ID ضُبط على الملف المنفذ، فقد يفتح النظام ملفًا غير محدد لكل من واصفات الملفات هذه. كمبدأ عام، لا يمكن لأي برنامج محمول، سواء كان مميزًا أم لا، أن يفترض أن واصفات الملفات الثلاثة هذه ستبقى مغلقة عبر execve().

  نصوص المفسر
نص المفسر هو ملف نصي لديه إذن تنفيذ مفعل وسطره الأول من الشكل:

#!interpreter [optional-arg]

يجب أن يكون interpreter مسارًا صالحًا لملف قابل للتنفيذ.

سيُستدعى interpreter بالوسائط التالية:

interpreter [optional-arg] path arg...

حيث arg... هي سلسلة الكلمات المشار إليها بواسطة وسيطة argv لـ execve()، بدءًا من argv[1]. لاحظ أنه لا توجد طريقة للحصول على argv[0] الذي مُرر إلى استدعاء execve().

للاستخدام المحمول، يجب أن يكون optional-arg إما غائبًا، أو محددًا ككلمة واحدة (أي لا يجب أن يحتوي على مسافة بيضاء)؛ انظر الإصدارات أدناه.

منذ لينكس 2.6.28، يسمح النواة لمفسر النص أن يكون هو نفسه نصًا. هذا الإذن متكرر، حتى حد أربع تكرارات، بحيث يمكن أن يكون المفسر نصًا يُفسر بواسطة نص، وهكذا.

  حدود حجم الوسائط والبيئة
تفرض معظم تطبيقات UNIX حدًا ما على الحجم الإجمالي لسلاسل وسائط سطر الأوامر (argv) والبيئة (envp) التي قد تُمرر إلى برنامج جديد. يسمح POSIX.1 للتنفيذ بالإعلان عن هذا الحد باستخدام الثابت ARG_MAX (إما معرف في <limits.h> أو متاح في وقت التشغيل باستخدام الاستدعاء sysconf(_SC_ARG_MAX)).

قبل لينكس 2.6.23، كانت الذاكرة المستخدمة لتخزين سلاسل البيئة والوسائط محدودة بـ 32 صفحة (محددة بواسطة ثابت النواة MAX_ARG_PAGES). على معماريات بحجم صفحة 4 كيلوبايت، ينتج عن هذا حجم أقصى قدره 128 كيلوبايت.

على لينكس 2.6.23 والإصدارات الأحدث، تدعم معظم المعماريات حدًا للحجم مشتقًا من حد المورد الناعم RLIMIT_STACK (انظر getrlimit(2)) الساري في وقت استدعاء execve(). (تُستثنى المعماريات التي لا تحتوي على وحدة إدارة ذاكرة: فهي تحافظ على الحد الذي كان ساريًا قبل لينكس 2.6.23.) يسمح هذا التغيير للبرامج بالحصول على قائمة وسائط و/أو بيئة أكبر بكثير. بالنسبة لهذه المعماريات، يُحد الحجم الإجمالي إلى 1/4 من حجم المكدس المسموح به. (فرض حد 1/4 يضمن أن البرنامج الجديد لديه دائمًا بعض مساحة المكدس.) بالإضافة إلى ذلك، يُحد الحجم الإجمالي إلى 3/4 من قيمة ثابت النواة _STK_LIM (8 ميجابايت). منذ لينكس 2.6.25، تضع النواة أيضًا حدًا أدنى قدره 32 صفحة على هذا الحد الحجمي، بحيث، حتى عندما يُضبط RLIMIT_STACK منخفضًا جدًا، تُضمن التطبيقات الحصول على مساحة وسائط وبيئة على الأقل بقدر ما وفرته لينكس 2.6.22 والإصدارات الأقدم. (لم يُقدم هذا الضمان في لينكس 2.6.23 و2.6.24.) بالإضافة إلى ذلك، الحد لكل سلسلة هو 32 صفحة (ثابت النواة MAX_ARG_STRLEN)، والحد الأقصى لعدد السلاسل هو 0x7FFFFFFF.

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

الأخطاء

E2BIG
    إجمالي عدد البايتات في البيئة (envp) وقائمة الوسائط (argv) كبير جدًا، أو وسيط أو سلسلة بيئة طويلة جدًا، أو المسار الكامل path للملف القابل للتنفيذ طويل جدًا. يُحتسب البايت الصفري الختامي كجزء من طول السلسلة.

EACCES
    يُرفض إذن البحث على مكون من بادئة المسار لـ path أو اسم مفسر النص البرمجي. (انظر أيضًا path_resolution(7).)

EACCES
    الملف أو مفسر النص البرمجي ليس ملفًا عاديًا.

EACCES
    يُرفض إذن التنفيذ للملف أو النص البرمجي أو مفسر ELF.

EACCES
    نظام الملفات موصول بخيار noexec.

EAGAIN (منذ لينكس 3.1)
    بعد تغيير UID الحقيقي باستخدام إحدى استدعاءات set*uid()، كان المتصل—ولا يزال—فوق حد موارده RLIMIT_NPROC (انظر setrlimit(2)). للحصول على شرح أكثر تفصيلاً لهذا الخطأ، انظر الملاحظات.

EFAULT
    يشير path أو أحد المؤشرات في المتجهات argv أو envp إلى خارج مساحة العنوان القابلة للوصول.

EINVAL
    يحتوي ملف ELF قابل للتنفيذ على أكثر من مقطع PT_INTERP واحد (أي حاول تسمية أكثر من مفسر واحد).

EIO حدث خطأ إدخال/إخراج.

EISDIR
    كان مفسر ELF دليلاً.

ELIBBAD
    لم يكن مفسر ELF بتنسيق معروف.

ELOOP
    تمت مصادفة عدد كبير جدًا من الروابط الرمزية أثناء حل path أو اسم نص برمجي أو مفسر ELF.

ELOOP
    وصلَ إلى حد التكرار الأقصى أثناء تفسير النص البرمجي التكراري (انظر "النصوص البرمجية المفسرة"، أعلاه). قبل لينكس 3.8، كان الخطأ الناتج لهذه الحالة هو ENOEXEC.

EMFILE
    وُصل إلى الحد الأقصى لواصفات الملفات المفتوحة لكل عملية.

ENAMETOOLONG
    المسار path طويل جداً.

ENFILE
    وُصل إلى الحد الأقصى لإجمالي عدد الملفات المفتوحة على مستوى النظام.

ENOENT
    path أو نص برمجي أو مفسر ELF غير موجود.

ENOEXEC
    الملف القابل للتنفيذ ليس بتنسيق معروف، أو مخصص لبنية خاطئة، أو به خطأ تنسيق آخر يعني أنه لا يمكن تنفيذه.

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

ENOTDIR
    مكون من بادئة المسار لـ path أو نص برمجي أو مفسر ELF ليس دليلاً.

EPERM
    نظام الملفات موصول بخيار nosuid، والمستخدم ليس المستخدم الفائق، والملف يحتوي على بت set-user-ID أو set-group-ID مضبوطًا.

EPERM
    العملية قيد التتبع، والمستخدم ليس المستخدم الفائق، والملف يحتوي على بت set-user-ID أو set-group-ID مضبوطًا.

EPERM
    تطبيقات "capability-dumb" لن تحصل على المجموعة الكاملة من الصلاحيات المسموح بها الممنوحة بواسطة الملف القابل للتنفيذ. انظر capabilities(7).

ETXTBSY
    الملف القابل للتنفيذ المحدد كان مفتوحًا للكتابة بواسطة عملية واحدة أو أكثر.

الإصدارات
لا يوثق POSIX سلوك #!، لكنه موجود (مع بعض الاختلافات) على أنظمة UNIX الأخرى.

على لينكس، يمكن تحديد argv و envp كـ NULL. في كلتا الحالتين، هذا له نفس تأثير تحديد الوسيطة كمؤشر لقائمة تحتوي على مؤشر صفري واحد. لا تستغل هذه الميزة غير القياسية وغير القابلة للنقل! على العديد من أنظمة UNIX الأخرى، سيؤدي تحديد argv كـ NULL إلى خطأ (EFAULT). تعالج بعض أنظمة UNIX الأخرى حالة envp==NULL مثل لينكس.

ينص POSIX.1 على أن القيم التي ترجعها sysconf(3) يجب أن تكون ثابتة طوال عمر العملية. ومع ذلك، منذ لينكس 2.6.23، إذا تغير حد المورد RLIMIT_STACK، فإن القيمة المبلغ عنها بواسطة _SC_ARG_MAX ستتغير أيضًا، لتعكس حقيقة أن الحد الأقصى للمساحة لحفظ وسائط سطر الأوامر ومتغيرات البيئة قد تغير.

  نصوص المفسر
يفرض النواة حدًا أقصى للطول على النص الذي يتبع الأحرف "#!" في بداية النص البرمجي؛ تُتجاهل الأحرف التي تتجاوز الحد. قبل لينكس 5.1، الحد هو 127 حرفًا. منذ لينكس 5.1، الحد هو 255 حرفًا.

تختلف دلالات وسيطة optional-arg للنص البرمجي المفسر عبر التطبيقات. على لينكس، تُمرر السلسلة الكاملة التي تلي اسم interpreter كوسيطة واحدة إلى المفسر، ويمكن أن تتضمن هذه السلسلة مسافات بيضاء. ومع ذلك، يختلف السلوك على بعض الأنظمة الأخرى. تستخدم بعض الأنظمة المسافة البيضاء الأولى لإنهاء optional-arg. على بعض الأنظمة، يمكن أن يحتوي النص البرمجي المفسر على وسائط متعددة، وتُستخدم المسافات البيضاء في optional-arg لفصل الوسائط.

يتجاهل لينكس (مثل معظم أنظمة UNIX الحديثة الأخرى) بتات set-user-ID و set-group-ID على النصوص البرمجية.

المعايير
POSIX.1-2024.

التاريخ
4.3BSD، SVr4، POSIX.1-1988.

مع UNIX V6، كانت قائمة وسائط استدعاء exec() تنتهي بـ 0، بينما كانت قائمة وسائط main تنتهي بـ -1. وبالتالي، لم تكن قائمة الوسائط هذه قابلة للاستخدام مباشرة في استدعاء exec() آخر. منذ UNIX V7، كلاهما NULL.

ملاحظات
يرى المرء أحيانًا execve() (والدوال ذات الصلة الموصوفة في exec(3)) موصوفة بأنها "تنفذ عملية جديدة" (أو ما شابه). هذا وصف مضلل للغاية: لا توجد عملية جديدة؛ تظل العديد من سمات العملية المستدعية دون تغيير (على وجه الخصوص، PID الخاص بها). كل ما تفعله execve() هو ترتيب لعملية موجودة (العملية المستدعية) لتنفيذ برنامج جديد.

لا يمكن تتبع العمليات ذات set-user-ID و set-group-ID باستخدام ptrace(2).

تختلف نتيجة وصل نظام ملفات nosuid عبر إصدارات نواة لينكس: بعضها سيرفض تنفيذ البرامج القابلة للتنفيذ ذات معرف المستخدم المحدد ومعرف المجموعة المحدد عندما يمنح ذلك المستخدم صلاحيات لم تكن لديه مسبقًا (وتعيد EPERM)، وبعضها سيتجاهل بتات معرف المستخدم المحدد ومعرف المجموعة المحدد وينفذ exec() بنجاح.

في معظم حالات فشل execve()، تعود السيطرة إلى صورة البرنامج القابلة للتنفيذ الأصلية، ويمكن لمستدعي execve() معالجة الخطأ. ومع ذلك، في حالات (نادرة) (تحدث عادةً بسبب استنزاف الموارد)، قد يحدث الفشل بعد نقطة اللاعودة: تُفكك صورة البرنامج القابلة للتنفيذ الأصلية، لكن لم يمكن بناء الصورة الجديدة بالكامل. في مثل هذه الحالات، تقتل النواة العملية بإشارة SIGSEGV (SIGKILL حتى لينكس 3.17).

  execve() و EAGAIN
فيما يلي شرح أكثر تفصيلاً لخطأ EAGAIN الذي يمكن أن يحدث (منذ لينكس 3.1) عند استدعاء execve().

يمكن أن يحدث خطأ EAGAIN عندما تسبب استدعاء سابق لـ setuid(2) أو setreuid(2) أو setresuid(2) في تغيير معرف المستخدم الحقيقي للعملية، وتسبب هذا التغيير في تجاوز العملية لحد مواردها RLIMIT_NPROC (أي أن عدد العمليات التابعة لمعرف المستخدم الحقيقي الجديد يتجاوز حد المورد). من لينكس 2.6.0 إلى لينكس 3.0، تسبب هذا في فشل استدعاء set*uid(). (قبل لينكس 2.6، لم يُفرض حد المورد على العمليات التي غيرت معرفات المستخدمين الخاصة بها.)

منذ لينكس 3.1، لم يعد السيناريو الموصوف للتو يتسبب في فشل استدعاء set*uid()، لأنه أدى في كثير من الأحيان إلى ثغرات أمنية حيث لم تتحقق التطبيقات المعيبة من حالة الإرجاع وافترضت أن—إذا كان لدى المستدعي صلاحيات الجذر—فإن الاستدعاء سينجح دائمًا. بدلاً من ذلك، تقوم استدعاءات set*uid() الآن بتغيير معرف المستخدم الحقيقي بنجاح، لكن النواة تضع علامة داخلية، تسمى PF_NPROC_EXCEEDED، للإشارة إلى أنه تُجوز حد المورد RLIMIT_NPROC. إذا عُيين علامة PF_NPROC_EXCEEDED وكان حد المورد لا يزال متجاوزًا في وقت استدعاء execve() لاحق، فإن هذا الاستدعاء يفشل مع الخطأ EAGAIN. يضمن منطق النواة هذا أن حد المورد RLIMIT_NPROC لا يزال مفروضًا على سير عمل الخفي المميز الشائع—أي fork(2) + set*uid() + execve().

إذا لم يكن حد المورد لا يزال متجاوزًا في وقت استدعاء execve() (لأن عمليات أخرى تابعة لمعرف المستخدم الحقيقي هذا أنهت بين استدعاء set*uid() واستدعاء execve())، فإن استدعاء execve() ينجح وتقوم النواة بمسح علامة العملية PF_NPROC_EXCEEDED. تُمسح أيضًا العلامة إذا نجح استدعاء لاحق لـ fork(2) بواسطة هذه العملية.

أمثلة
البرنامج التالي مصمم ليُنفذ بواسطة البرنامج الثاني أدناه. إنه فقط يردد وسائط سطر الأوامر الخاصة به، واحدًا لكل سطر.

    /* myecho.c */

    #include <stdio.h>
    #include <stdlib.h>

    int
    main(int argc, char *argv[])
    {
        for (size_t j = 0; j < argc; j++)
            printf("argv[%zu]: %s\n", j, argv[j]);

        exit(EXIT_SUCCESS);
    }

يمكن استخدام هذا البرنامج لتنفيذ البرنامج المسمى في وسيطة سطر الأوامر الخاصة به:

    /* execve.c */

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    int
    main(int argc, char *argv[])
    {
        static char *newargv[] = { NULL, "hello", "world", NULL };
        static char *newenviron[] = { NULL };

        if (argc != 2) {
            fprintf(stderr, "Usage: %s <file-to-exec>\n", argv[0]);
            exit(EXIT_FAILURE);
        }

        newargv[0] = argv[1];

        execve(argv[1], newargv, newenviron);
        perror("execve");   /* execve() returns only on error */
        exit(EXIT_FAILURE);
    }

يمكننا استخدام البرنامج الثاني لتنفيذ الأول كما يلي:

    $ cc myecho.c -o myecho
    $ cc execve.c -o execve
    $ ./execve ./myecho
    argv[0]: ./myecho
    argv[1]: hello
    argv[2]: world

يمكننا أيضًا استخدام هذه البرامج لتوضيح استخدام مفسر النص البرمجي. للقيام بذلك، نقوم بإنشاء نص برمجي يكون "مفسره" هو برنامجنا myecho:

    $ cat > script
    #!./myecho script-arg
    ^D
    $ chmod +x script

يمكننا بعد ذلك استخدام برنامجنا لتنفيذ النص البرمجي:

    $ ./execve ./script
    argv[0]: ./myecho
    argv[1]: script-arg
    argv[2]: ./script
    argv[3]: hello
    argv[4]: world

انظر أيضًا
chmod(2), execveat(2), fork(2), get_robust_list(2), ptrace(2), exec(3), fexecve(3), getauxval(3), getopt(3), system(3), capabilities(7), credentials(7), environ(7), path_resolution(7), ld.so(8)

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

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

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