'\" t .TH "SYSTEMD\-SOFT\-REBOOT\&.SERVICE" "8" "" "systemd 261.2" "systemd-soft-reboot.service" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "نام (NAME)" systemd-soft-reboot.service \- سرویس راه‌اندازی مجدد نرم لایه کاربری در systemd .SH "خلاصه دستور (SYNOPSIS)" .PP systemd\-soft\-reboot\&.service .SH "توضیحات (DESCRIPTION)" .PP systemd\-soft\-reboot\&.service یک سرویس سیستمی است که توسط soft\-reboot\&.target فراخوانی می‌شود و مسئول انجام یک عملیات راه‌اندازی مجدد صرفاً در فضای کاربری (userspace-only) است\&. هنگام فراخوانی، این سرویس سیگنال \fBSIGTERM\fR را به هر فرایند در حال اجرای باقیمانده ارسال می‌کند (اما منتظر خروج فرایندها نمی‌ماند) و سپس آن را با \fBSIGKILL\fR دنبال می‌کند\&. اگر دایرکتوری /run/nextroot/ وجود داشته باشد (که می‌تواند یک دایرکتوری معمولی، یک نقطه مانت دایرکتوری یا یک پیوند نمادین به هر یک از آن‌ها باشد)، ریشه سیستم فایل را به آن تغییر می‌دهد\&. سپس مدیر سرویس را از روی سیستم فایل ریشه (که احتمالاً اکنون جدید است) مجدداً اجرا می‌کند، که همانند یک راه‌اندازی مجدد عادی یک تراکنش بوت جدید را در صف قرار می‌دهد\&. .PP چنین عملیات راه‌اندازی مجدد صرفاً در فضای کاربری امکان به‌روزرسانی یا بازنشانی کل فضای کاربری را با کمترین زمان خرابی (downtime) فراهم می‌کند، زیرا عملیات راه‌اندازی مجدد از مراحل زیر گذر \fIنمی‌کند\fR: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} فاز دوم خاموش‌سازی عادی، همان‌طور که توسط \fBsystemd-shutdown\fR(8) پیاده‌سازی شده است\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} فاز سوم خاموش‌سازی عادی، یعنی بازگشت به بافتار initrd\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} عملیات راه‌اندازی مجدد سخت‌افزاری\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} مقداردهی اولیه سفت‌افزار (firmware)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} مقداردهی اولیه بارگذار بوت (boot loader)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} مقداردهی اولیه هسته (kernel)\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} مقداردهی اولیه initrd\&. .RE .PP با این حال، این نوع راه‌اندازی مجدد معایبی نیز به همراه دارد: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} به‌روزرسانی سیستم‌عامل ناقص می‌ماند، زیرا هسته بازنشانی نمی‌شود و به اجرای خود ادامه می‌دهد\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} تنظیمات هسته (مانند تنظیمات /proc/sys/، معروف به "sysctl"، یا تنظیمات /sys/) بازنشانی نمی‌شوند\&. .RE .PP این محدودیت‌ها ممکن است از روش‌های گوناگونی برطرف شوند که خارج از حوصلهٔ این مستندات است، مانند وصله زدن زندهٔ هسته (kernel live-patching) و فایل‌های /etc/sysctl\&.d/ به‌اندازهٔ کافی جامع\&. .SH "انتقال منابع (RESOURCE PASS\-THROUGH)" .PP منابع گوناگون زمان اجرای سیستم‌عامل می‌توانند از یک زمان اجرای سیستم به زمان اجرای بعدی از طریق عملیات راه‌اندازی مجدد در فضای کاربری انتقال یابند\&. به‌طور مشخص: .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} توصیف‌کننده‌های فایل قرار گرفته در مخزن توصیف‌کننده فایل سرویس‌هایی که تا پایان فعال می‌مانند، به بوت بعدی منتقل می‌شوند و در آنجا در مخزن توصیف‌کننده فایل همان واحد قرار می‌گیرند\&. برای این کار، واحدها باید \fIDefaultDependencies=no\fR را اعلان کنند (و از تعریف دستی \fIConflicts=shutdown\&.target\fR یا مشابه آن خودداری کنند) تا اطمینان حاصل شود که طبق معمول در طول عملیات خاموش‌سازی سیستم خاتمه نمی‌یابند\&. یا از \fIFileDescriptorStorePreserve=\fR استفاده کنید تا مخزن توصیف‌کننده فایل حتی در زمان غیرفعال بودن واحد، محفوظ (pinned) باقی بماند\&. برای جزئیات درباره مخزن توصیف‌کننده فایل به \fBsystemd.service\fR(5) مراجعه کنید\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} مشابه این، توصیف‌کننده‌های فایل مرتبط با واحدهای \&.socket در صورتی که واحدها در طول انتقال متوقف نشوند، باز (و قابل اتصال) باقی می‌مانند\&. (با تنظیم \fIDefaultDependencies=no\fR حاصل می‌شود\&.) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} سیستم فایل /run/ سوارشده (mounted) و پرشده باقی می‌ماند و می‌تواند برای انتقال اطلاعات وضعیت بین این چرخه‌های راه‌اندازی مجدد فضای کاربری استفاده شود\&. .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} فرایندهای سرویس در صورتی که در سرویس‌هایی قرار گیرند که تا پایان مرحله خاموش‌سازی فعال می‌مانند (که این نیز از طریق \fIDefaultDependencies=no\fR به دست می‌آید)، ممکن است در طول انتقال، پس از soft-reboot و درون نشست بعدی به اجرای خود ادامه دهند\&. آن‌ها همچنین باید با استفاده از \fISurviveFinalKillSignal=yes\fR پیکربندی شوند تا از خاتمه یافتن توسط \fBSIGTERM\fR و \fBSIGKILL\fR مذکور جلوگیری شود، و همچنین از طریق \fIIgnoreOnIsolate=yes\fR تنظیم شوند تا از متوقف شدن در هنگام جداسازی (isolate) جلوگیری شود\&. آن‌ها همچنین باید پیکربندی شوند تا در خاموش‌سازی عادی، راه‌اندازی مجدد و حالت تعمیر و نگهداری متوقف شوند\&. در نهایت، آن‌ها باید پس از \fBbasic\&.target\fR مرتب شوند تا از ترتیب درست در زمان بوت اطمینان حاصل شود\&. توجه داشته باشید در صورتی که از هرگونه واحد جدید یا سفارشی برای جداسازی استفاده شود، یا عملکرد خاموش‌سازی معادلی را پیاده‌سازی کند، آن‌ها نیز باید به‌صورت دستی برای ترتیب و تداخل (conflicting) صحیح پیکربندی شوند\&. برای مثال: .sp .if n \{\ .RS 4 .\} .nf [Unit] Description=My Surviving Service SurviveFinalKillSignal=yes IgnoreOnIsolate=yes DefaultDependencies=no After=basic\&.target Conflicts=reboot\&.target kexec\&.target poweroff\&.target halt\&.target rescue\&.target emergency\&.target Before=shutdown\&.target rescue\&.target emergency\&.target [Service] Type=oneshot ExecStart=sleep infinity .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} علاوه بر موارد فوق، واحدهای قالب‌بندی‌شده (templated units) به یک فایل پیکربندی برای slice خود نیز نیاز دارند، زیرا آن‌ها به‌طور پیش‌فرض از sliceای استفاده می‌کنند که نام آن بر اساس بخش غیرقالب‌بندی‌شده واحد نام‌گذاری شده است\&. برای مثال، برای یک نمونهٔ foo@test\&.service، یک واحد system\-foo\&.slice می‌تواند با محتوای زیر اضافه شود: .sp .if n \{\ .RS 4 .\} .nf [Unit] SurviveFinalKillSignal=yes IgnoreOnIsolate=yes DefaultDependencies=no .fi .if n \{\ .RE .\} .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} مانت‌های سیستم فایل و حافظه‌های ذخیره‌سازی پیچیدهٔ متصل می‌توانند در طول انتقال متصل باقی بمانند، در صورتی که پیکربندی شده باشند تا پایان فرایند خاموش‌سازی باقی بمانند\&. (این نیز از طریق \fIDefaultDependencies=no\fR و با اجتناب از \fIConflicts=umount\&.target\fR حاصل می‌شود\&.) .RE .sp .RS 4 .ie n \{\ \h'-04'\(bu\h'+03'\c .\} .el \{\ .sp -1 .IP \(bu 2.3 .\} اگر واحد سرویسی را روی D\-Bus منتشر می‌کند، اتصال باید پس از soft\-reboot مجدداً برقرار شود زیرا کارگزار D\-Bus متوقف شده و سپس دوباره راه‌اندازی می‌شود\&. هنگام استفاده از کتابخانهٔ \fBsd-bus\fR(3) این امر را می‌توان با تطبیق مثال زیر به دست آورد\&. .sp .if n \{\ .RS 4 .\} .nf /* SPDX\-License\-Identifier: MIT\-0 */ /* A D\-Bus service that automatically reconnects when the system bus is * restarted\&. * * Compile with \*(Aqcc sd_bus_service_reconnect\&.c $(pkg\-config \-\-libs \-\-cflags libsystemd)\*(Aq * * To allow the program to take ownership of the name \*(Aqorg\&.freedesktop\&.ReconnectExample\*(Aq, * add the following as /etc/dbus\-1/system\&.d/org\&.freedesktop\&.ReconnectExample\&.conf * and then reload the broker with \*(Aqsystemctl reload dbus\*(Aq: * * To get the property via busctl: * * $ busctl \-\-user get\-property org\&.freedesktop\&.ReconnectExample \e * /org/freedesktop/ReconnectExample \e * org\&.freedesktop\&.ReconnectExample \e * Example * s "example" */ #include #include #include #include #define _cleanup_(f) __attribute__((cleanup(f))) static int log_error(int r, const char *str) { fprintf(stderr, "%s failed: %s\en", str, strerror(\-r)); return r; } typedef struct object { const char *example; sd_bus **bus; sd_event **event; } object; static int property_get( sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error) { object *o = userdata; if (strcmp(property, "Example") == 0) return sd_bus_message_append(reply, "s", o\->example); return sd_bus_error_setf(error, SD_BUS_ERROR_UNKNOWN_PROPERTY, "Unknown property \*(Aq%s\*(Aq", property); } /* https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_add_object\&.html */ static const sd_bus_vtable vtable[] = { SD_BUS_VTABLE_START(0), SD_BUS_PROPERTY( "Example", "s", property_get, 0, SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_VTABLE_END }; static int setup(object *o); static int on_disconnect(sd_bus_message *message, void *userdata, sd_bus_error *ret_error) { int r; r = setup((object *)userdata); if (r < 0) { object *o = userdata; r = sd_event_exit(*o\->event, r); if (r < 0) return log_error(r, "sd_event_exit()"); } return 1; } /* Ensure the event loop exits with a clear error if acquiring the well\-known * service name fails */ static int request_name_callback(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { int r; if (!sd_bus_message_is_method_error(m, NULL)) return 1; const sd_bus_error *error = sd_bus_message_get_error(m); if (sd_bus_error_has_names(error, SD_BUS_ERROR_TIMEOUT, SD_BUS_ERROR_NO_REPLY)) return 1; /* The bus is not available, try again later */ fprintf(stderr, "Failed to request name: %s\en", error\->message); object *o = userdata; r = sd_event_exit(*o\->event, \-sd_bus_error_get_errno(error)); if (r < 0) return log_error(r, "sd_event_exit()"); return 1; } static int setup(object *o) { int r; /* If we are reconnecting, then the bus object needs to be closed, detached * from the event loop and recreated\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_detach_event\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_close_unref\&.html */ if (*o\->bus) { r = sd_bus_detach_event(*o\->bus); if (r < 0) return log_error(r, "sd_bus_detach_event()"); *o\->bus = sd_bus_close_unref(*o\->bus); } /* Set up a new bus object for the system bus, configure it to wait for D\-Bus * to be available instead of failing if it is not, and start it\&. All the * following operations are asynchronous and will not block waiting for D\-Bus * to be available\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_new\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_set_address\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_set_bus_client\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_negotiate_creds\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_set_watch_bind\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_set_connected_signal\&.html * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_start\&.html */ r = sd_bus_new(o\->bus); if (r < 0) return log_error(r, "sd_bus_new()"); r = sd_bus_set_address(*o\->bus, "unix:path=/run/dbus/system_bus_socket"); if (r < 0) return log_error(r, "sd_bus_set_address()"); r = sd_bus_set_bus_client(*o\->bus, 1); if (r < 0) return log_error(r, "sd_bus_set_bus_client()"); r = sd_bus_negotiate_creds(*o\->bus, 1, SD_BUS_CREDS_UID|SD_BUS_CREDS_EUID|SD_BUS_CREDS_EFFECTIVE_CAPS); if (r < 0) return log_error(r, "sd_bus_negotiate_creds()"); r = sd_bus_set_watch_bind(*o\->bus, 1); if (r < 0) return log_error(r, "sd_bus_set_watch_bind()"); r = sd_bus_start(*o\->bus); if (r < 0) return log_error(r, "sd_bus_start()"); /* Publish an interface on the bus, specifying our well\-known object access * path and public interface name\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_add_object\&.html * https://dbus\&.freedesktop\&.org/doc/dbus\-tutorial\&.html */ r = sd_bus_add_object_vtable(*o\->bus, NULL, "/org/freedesktop/ReconnectExample", "org\&.freedesktop\&.ReconnectExample", vtable, o); if (r < 0) return log_error(r, "sd_bus_add_object_vtable()"); /* By default, the service is only assigned an ephemeral name\&. Also add a * well\-known one, so that clients know whom to call\&. This needs to be * asynchronous, as D\-Bus might not be yet available\&. The callback will check * whether the error is expected or not, in case it fails\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_request_name\&.html */ r = sd_bus_request_name_async(*o\->bus, NULL, "org\&.freedesktop\&.ReconnectExample", 0, request_name_callback, o); if (r < 0) return log_error(r, "sd_bus_request_name_async()"); /* When D\-Bus is disconnected this callback will be invoked, which will set up * the connection again\&. This needs to be asynchronous, as D\-Bus might not yet * be available\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_match_signal_async\&.html */ r = sd_bus_match_signal_async(*o\->bus, NULL, "org\&.freedesktop\&.DBus\&.Local", NULL, "org\&.freedesktop\&.DBus\&.Local", "Disconnected", on_disconnect, NULL, o); if (r < 0) return log_error(r, "sd_bus_match_signal_async()"); /* Attach the bus object to the event loop so that calls and signals are * processed\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_attach_event\&.html */ r = sd_bus_attach_event(*o\->bus, *o\->event, 0); if (r < 0) return log_error(r, "sd_bus_attach_event()"); return 0; } int main(int argc, char **argv) { /* The bus should be relinquished before the program terminates\&. The cleanup * attribute allows us to do it nicely and cleanly whenever we exit the block\&. */ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL; _cleanup_(sd_event_unrefp) sd_event *event = NULL; object o = { \&.example = "example", \&.bus = &bus, \&.event = &event, }; int r; /* Create an event loop data structure, with default parameters\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_event_default\&.html */ r = sd_event_default(&event); if (r < 0) return log_error(r, "sd_event_default()"); /* By default, the event loop will terminate when all sources have disappeared, * so we have to keep it \*(Aqoccupied\*(Aq\&. Register signal handling to do so\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_event_add_signal\&.html */ r = sd_event_add_signal(event, NULL, SIGINT|SD_EVENT_SIGNAL_PROCMASK, NULL, NULL); if (r < 0) return log_error(r, "sd_event_add_signal(SIGINT)"); r = sd_event_add_signal(event, NULL, SIGTERM|SD_EVENT_SIGNAL_PROCMASK, NULL, NULL); if (r < 0) return log_error(r, "sd_event_add_signal(SIGTERM)"); r = setup(&o); if (r < 0) return EXIT_FAILURE; /* Enter the main loop, it will exit only on sigint/sigterm\&. * https://www\&.freedesktop\&.org/software/systemd/man/sd_event_loop\&.html */ r = sd_event_loop(event); if (r < 0) return log_error(r, "sd_event_loop()"); /* https://www\&.freedesktop\&.org/software/systemd/man/sd_bus_release_name\&.html */ r = sd_bus_release_name(bus, "org\&.freedesktop\&.ReconnectExample"); if (r < 0) return log_error(r, "sd_bus_release_name()"); return 0; } .fi .if n \{\ .RE .\} .sp .RE .PP اگرچه انتقال منابع از یک چرخهٔ راه‌اندازی مجدد نرم به چرخهٔ بعدی از این طریق امکان‌پذیر است، اما اکیداً پیشنهاد می‌کنیم از این قابلیت تنها به‌ندرت و با احتیاط استفاده شود، زیرا موجب ایجاد سیستمی شکننده‌تر می‌شود چرا که منابع نسخه‌های مختلف سیستم‌عامل و برنامه‌ها ممکن است با پیامدهای پیش‌بینی‌نشده مخلوط شوند\&. به‌ویژه توصیه می‌شود از مجاز دانستن بقای فرایندها در طول عملیات راه‌اندازی مجدد نرم \fIخودداری شود\fR، زیرا این امر بدان معناست که به‌روزرسانی‌های کد لزوماً ناقص خواهند ماند و فرایندها معمولاً منابع مختلف دیگری را (مانند سیستم فایلی که بر آن متکی هستند) سنجاق (pin) می‌کنند، و در نتیجه مصرف حافظه را افزایش می‌دهند (چرا که ممکن است دو نسخه از سیستم‌عامل/برنامه/سیستم فایل در حافظه نگه‌داری شوند)\&. در حال اجرا باقی گذاشتن فرایندها در طول یک عملیات راه‌اندازی مجدد نرم مستلزم قطع اتصال جامع و همه‌جانبهٔ سرویس از بقیهٔ سیستم‌عامل است، یعنی به حداقل رساندن IPC و کاهش اشتراک‌گذاری منابع با بقیهٔ سیستم‌عامل\&. یک سازوکار احتمالی برای دستیابی به این هدف، مفهوم \m[blue]\fBPortable Services\fR\m[]\&\s-2\u[1]\d\s+2 است، اما اطمینان حاصل کنید که هیچ منبعی از سیستم‌های فایل سیستم‌عامل میزبان از طریق \fIBindPaths=\fR یا تنظیمات مشابه واحد سنجاق نشده باشد، در غیر این صورت سیستم فایل قدیمی و مبدأ تا زمانی که واحد در حال اجرا باشد سوارشده باقی خواهد ماند\&. .SH "نکات (NOTES)" .PP توجه داشته باشید که از آنجا که \fBsystemd-shutdown\fR(8) اجرا نمی‌شود، فایل‌های اجرایی موجود در /usr/lib/systemd/system\-shutdown/ نیز اجرا نخواهند شد\&. .PP توجه داشته باشید که systemd\-soft\-reboot\&.service (و واحدهای مرتبط) هرگز نباید به‌صورت مستقیم اجرا شوند\&. در عوض، خاموش‌سازی سیستم را با دستوری مانند \fBsystemctl soft\-reboot\fR آغاز کنید\&. .PP توجه داشته باشید که اگر یک سیستم فایل ریشهٔ جدید در "/run/nextroot/" راه‌اندازی شده باشد، با فراخوانی دستور \fBreboot\fR یک عملیات \fBsoft\-reboot\fR انجام خواهد شد\&. .SH "همچنین ببینید (SEE ALSO)" .PP \fBsystemd\fR(1), \fBsystemctl\fR(1), \fBsystemd.special\fR(7), \fBsystemd-poweroff.service\fR(8), \fBsystemd-suspend.service\fR(8), \fBbootup\fR(7) .SH "نکات (NOTES)" .IP " 1." 4 Portable Services .RS 4 \%https://systemd.io/PORTABLE_SERVICES .RE