From: Kruti Pendharkar Date: Tue, 30 Sep 2025 06:03:43 +0000 (-0700) Subject: Use different command to reboot linux VM, depending on the init system type X-Git-Tag: stable-13.0.5~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7ff34bef69c7252fb0ceb628f64103b0fa4f56f2;p=thirdparty%2Fopen-vm-tools.git Use different command to reboot linux VM, depending on the init system type We currently use the "telinit 6" command to reboot linux VMs. However, the "telinit" command will be unavailable in the future as SysVinit will be deprecated on some modern linux systems. For example: In SUSE, "telinit" command is part of systemd-sysvcompat (15 SP6 and newer) or systemd-sysvinit (older than 15 SP6), whereas in some SUSE images or templates such as SUSE minimal VM has no such packages installed. See SUSE KB: https://www.suse.com/support/kb/doc/?id=000021564 This change detects the init system of a linux and uses different command to trigger reboot. If the modern init system, systemd, is available, then "systemctl reboot" command will be used to trigger reboot. Otherwise, continue using "telinit 6" command as SysVinit, the traditional init system, is still available. --- diff --git a/open-vm-tools/libDeployPkg/linuxDeployment.c b/open-vm-tools/libDeployPkg/linuxDeployment.c index 9bfb6820d..981ea10f5 100644 --- a/open-vm-tools/libDeployPkg/linuxDeployment.c +++ b/open-vm-tools/libDeployPkg/linuxDeployment.c @@ -1,5 +1,5 @@ /********************************************************* - * Copyright (c) 2006-2024 Broadcom. All Rights Reserved. + * Copyright (c) 2006-2025 Broadcom. All Rights Reserved. * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. * * This program is free software; you can redistribute it and/or modify it @@ -122,6 +122,9 @@ static const char* VARRUNDIR = "/var/run"; static const char* VARRUNIMCDIR = "/var/run/vmware-imc"; #endif static const char* TMPDIR = "/tmp"; +static const char* USRBINSYSTEMCTL = "/usr/bin/systemctl"; +static const char* BINSYSTEMCTL = "/bin/systemctl"; +static const char* SBINTELINIT = "/sbin/telinit"; // Possible return codes from perl script static const int CUST_SUCCESS = 0; @@ -197,7 +200,6 @@ static Bool CopyFileIfExist(const char* sourcePath, static void GetCloudinitVersion(const char* versionOutput, int* major, int* minor); -static Bool IsTelinitASoftlinkToSystemctl(void); /* * Globals @@ -1674,28 +1676,43 @@ Deploy(const char* packageName) sLog(log_error, "Failed to fork: '%s'.", strerror(errno)); } else if (pid == 0) { // We're in the child + char rebootCommand[1024]; int rebootCommandResult; + bool isSystemd = false; bool isRebooting = false; - // Retry reboot until telinit 6 succeeds to workaround PR 2716292 where - // telinit is a soft(symbolic) link to systemctl and it could exit - // abnormally due to systemd sends SIGTERM - bool retryReboot = IsTelinitASoftlinkToSystemctl(); + // PR 3438671, using different command to reboot modern systemd linux + // or traditional SysVinit linux + // Repeatedly try to reboot to workaround PR 2716292 on modern systemd + // linux where systemctl reboot could exit abnormally due to systemd + // sends SIGTERM + // Repeatedly try to reboot to workaround PR 530641 on traditional + // SysVinit linux where telinit 6 is overwritten by a telinit 2 + if (access(USRBINSYSTEMCTL, X_OK) == 0) { + isSystemd = true; + Str_Snprintf(rebootCommand, sizeof(rebootCommand), "%s reboot", + USRBINSYSTEMCTL); + } else if (access(BINSYSTEMCTL, X_OK) == 0) { + isSystemd = true; + Str_Snprintf(rebootCommand, sizeof(rebootCommand), "%s reboot", + BINSYSTEMCTL); + } else { + Str_Snprintf(rebootCommand, sizeof(rebootCommand), "%s 6", + SBINTELINIT); + } sLog(log_info, "Trigger reboot."); - // Repeatedly try to reboot to workaround PR 530641 where - // telinit 6 is overwritten by a telinit 2 do { if (isRebooting) { sLog(log_info, "Rebooting."); } rebootCommandResult = - ForkExecAndWaitCommand("/sbin/telinit 6", true, NULL, 0); + ForkExecAndWaitCommand(rebootCommand, true, NULL, 0); isRebooting = (rebootCommandResult == 0) ? true : isRebooting; sleep(1); - } while (rebootCommandResult == 0 || (retryReboot && !isRebooting)); + } while (rebootCommandResult == 0 || (isSystemd && !isRebooting)); if (!isRebooting) { sLog(log_error, - "Failed to reboot, reboot command returned error %d.", - rebootCommandResult); + "Failed to reboot, reboot command %s returned error %d.", + rebootCommand, rebootCommandResult); exit (127); } else { sLog(log_info, "Reboot has been triggered."); @@ -1955,8 +1972,11 @@ ForkExecAndWaitCommand(const char* command, char** args = GetFormattedCommandLine(command); const char* processStdOut; Bool isPerlCommand = (strcmp(args[0], "/usr/bin/perl") == 0) ? true : false; - Bool isTelinitCommand = - (strcmp(args[0], "/sbin/telinit") == 0) ? true : false; + Bool isRebootCommand = + (Str_Strncmp(command, "/usr/bin/systemctl reboot", strlen(command)) || + Str_Strncmp(command, "/bin/systemctl reboot", strlen(command)) || + Str_Strncmp(command, "/sbin/telinit 6", strlen(command))) ? + true : false; sLog(log_debug, "Command to exec : '%s'.", args[0]); Process_Create(&hp, args, sLog); @@ -2012,9 +2032,9 @@ ForkExecAndWaitCommand(const char* command, } } } else { - if (isTelinitCommand) { + if (isRebootCommand) { sLog(log_info, - "Telinit command failed with exitcode: %d, stderr: '%s'.", + "Reboot command failed with exitcode: %d, stderr: '%s'.", retval, Process_GetStderr(hp)); } else { @@ -2209,43 +2229,3 @@ GetCloudinitVersion(const char* version, int* major, int* minor) } sLog(log_info, "Cloud-init version major: %d, minor: %d", *major, *minor); } - -/** - * - * Check if "telinit" command is a soft(symbolic) link to "systemctl" command - * - * The fullpath of "systemctl" command could be: - * /bin/systemctl - * or - * /usr/bin/systemctl - * - * @returns TRUE if "telinit" command is a soft link to "systemctl" command - * FALSE if "telinit" command is not a soft link to "systemctl" command - * - **/ -static Bool -IsTelinitASoftlinkToSystemctl(void) -{ - static const char systemctlBinPath[] = "/bin/systemctl"; - static const char readlinkCommand[] = "/bin/readlink /sbin/telinit"; - char readlinkCommandOutput[256]; - int forkExecResult; - - forkExecResult = ForkExecAndWaitCommand(readlinkCommand, - true, - readlinkCommandOutput, - sizeof(readlinkCommandOutput)); - if (forkExecResult != 0) { - sLog(log_debug, "readlink command result = %d.", forkExecResult); - return FALSE; - } - - if (strstr(readlinkCommandOutput, systemctlBinPath) != NULL) { - sLog(log_debug, "/sbin/telinit is a soft link to systemctl"); - return TRUE; - } else { - sLog(log_debug, "/sbin/telinit is not a soft link to systemctl"); - } - - return FALSE; -}