ExecStart ليس غلافًا: إصلاح وحدة مساعدة VPN
يشغّل ExecStart برنامجًا بوسائط، لا خط أنابيب في غلاف. استخدم مفسّرًا صريحًا أو سكربتًا حقيقيًا، ثم تحقّق من الوحدة واقرأ السجل.
انسخ سطر أوامر عاملًا إلى ExecStart، ثم أعد التحميل، فتفشل الوحدة أو تنتهي بصمت مع معاملة الوسائط كأسماء ملفات. لا شيء معطّل في systemd. إن ExecStart قائمة وسائط لا غلاف، لذا تفقد الأنابيب وإعادة التوجيه والشروط معناها لحظة مغادرتها الطرفية. قرّر أين ينتمي الغلاف، ثم اكتب وحدة تنصّ بدقة على ما ينبغي تنفيذه.
لماذا لا يفعل خط الأنابيب في ExecStart شيئًا
عند كتابة أمر في الطرفية، يحلّله الغلاف أولًا. يبني خط أنابيب، ويفتح الملفات لإعادة التوجيه، ويوسّع المتغيرات قبل أن يبدأ أي برنامج. لا يفعل systemd شيئًا من ذلك: فهو يقسّم ExecStart وفق قواعده الخاصة وينفّذ البرنامج الناتج بتلك الوسائط. لذا تصل > كوسيط حرفي، ويُسلَّم | إلى البرنامج بدلًا من ربط عمليتين. الوحدة لا تسيء التصرف؛ بل كانت الصياغة تعني شيئًا آخر.
هذا متعمّد لا إهمال، لأن التعامل المتوقَّع مع الوسائط هو ما يجعل الوحدات قابلة للتدقيق. وهو لا يفاجئ إلا من يفترض وجود غلاف.
اكتب وحدة تقول بدقة ما يعمل
ابدأ بوحدة صغيرة يظهر غرضها في السجل، ليبقى مشكل التحليل منفصلًا عن مشكل النفق. هذه الوحدة لا تبلغ إلا عن إصدار برنامج ثنائي.
[Unit]
Description=Report the installed OpenVPN version
[Service]
Type=oneshot
ExecStart=/usr/sbin/openvpn --version
StandardOutput=journal
StandardError=journalالمسار عنصر نائب، فاستبدله بالبرنامج الثنائي المثبّت فعليًا. Type=oneshot يناسب أمرًا يعمل حتى الاكتمال، وإعدادات السجل تضع خرجه حيث يمكنك قراءته دون طرفية. لا يوجد قسم تثبيت عن قصد، فتُستدعى الوحدة يدويًا بدلًا من تفعيلها عند الإقلاع. تحقّق من الملف قبل تشغيله، لأن خطأ مطبعيًا في اسم توجيه يفشل بشكل مختلف عن خطأ في المسار.
systemd-analyze verify /etc/systemd/system/openvpn-version.service
systemctl start openvpn-version.serviceأبقِ منطق الغلاف في سكربت
عندما يحتاج المساعد فعلًا إلى منطق شرطي، ضع ذلك المنطق في سكربت واستدعه صراحةً. يحتاج السكربت إلى سطر مفسّر وإذن تنفيذ ورموز خروج تستطيع الخدمة الإبلاغ بها. إن تشغيل /bin/sh -c مع أمر بين علامتي اقتباس يعمل فعلًا، لكنه يخفي قواعد الاقتباس داخل الوحدة ويزيد المراجعة صعوبة. ويمكن اختبار سكربت مسمّى يدويًا واستبداله لاحقًا دون تعديل الوحدة. لا تعتمد على ملف تعريف الغلاف الخاص بالمستخدم التفاعلي، لأن الخدمة تبدأ ببيئتها الخاصة.
عيّن WorkingDirectory عندما تهمّ المسارات النسبية، ومرّر البيئة عبر التوجيهات المدعومة في الوحدة بدلًا من تصديرها في طرفية. تنتمي الأسرار إلى ملفات محمية أو بيانات اعتماد، لا إلى قوائم وسائط قد يسجّلها السجل.
تحقّق من الوحدة الموجودة فعلًا
تغيّر ملفات drop-in السلوك دون لمس الملف الذي تتذكر أنك عدّلته. اقرأ ما حمّله المدير وما أبلغ عنه آخر تشغيل.
systemctl cat vpn-helper.service
journalctl -u vpn-helper.service -n 20 --no-pagerيتضمن تفريغ الوحدة ملفات drop-in بترتيب التحميل، ومن هنا يأتي عادةً ExecStart غير المتوقع. بعد أي تغيير، أعد تحميل المدير وتأكّد من أن التعريف الجديد هو ما يطبعه systemctl cat. يعرض السجل سطر الأوامر الدقيق وحالة الخروج، مما يفصل مشكلة الوسائط عن برنامج مفقود أو خطأ في الأذونات. ثم قرّر ما إذا كان المساعد ينتمي إلى دورة حياة VPN القائمة أم ينبغي أن يبقى تشخيصًا يدويًا، لأن عملية نفق خلفية ثانية تخلق مالكًا منافسًا.
الوحدة التي تطبع الخرج الصحيح عند الطلب إنجاز أول جيد. لكنها ليست نفقًا بعد، ولا ينبغي أن تدّعي ذلك.