On Sat Nov 1, 2025 at 2:14 PM CET, Michael Tokarev wrote:

> The code checks existance of a command (halt/poweroff/reboot) by using

> stat(2) and immediately checking for S_ISLNK() on the returned stat

> struct.  This check will never be true, because stat(2) always follows

> symbolic links and hence will either return ENOENT (in case of dangling

> symlink) or the properties for the final target file.  It is lstat(2)

> which might return information about the symlink itself.  However, even

> there, we want to check the final file properties, not the first symlink.

>

> This check - S_ISLNK - is harmful but useless in this case.  However, it

> is confusing and it helps the wrong usage of stat(2) to spread, so it is

> better to remove it.

>

> Additionally, the code would better to check for the executable bits

> of the final file, not check if it's a regular file - it's sort of

> dubious to have anything but regular files in /sbin/.

>

> But a POSIX system provides another command which suits the purpose

> perfectly: it is access(2).  And it is so simple that it's not

> necessary to create a separate function when usin it.

>

> Replace stat(2) with access(X_OK) to check for file existance in

> qga/commands-posix.c

>

> Fixes: c5b4afd4d56e "qga: Support guest shutdown of BusyBox-based systems"

> Signed-off-by: Michael Tokarev <[email protected]>


Reviewed-by: Rodrigo Dias Correa <[email protected]>

Thanks for fixing it.
Rodrigo
> ---

> v3: and actually don't forget to commit the changes.

>     I'm sorry for the noize.

> v2: fix reverse logic of the access() tests.

>     I should write code more often :)

>

>  qga/commands-posix.c | 12 +++---------

>  1 file changed, 3 insertions(+), 9 deletions(-)

>

> diff --git a/qga/commands-posix.c b/qga/commands-posix.c

> index c7059857e4..7785150fe4 100644

> --- a/qga/commands-posix.c

> +++ b/qga/commands-posix.c

> @@ -213,12 +213,6 @@ out:

>      return retcode;

>  }

>  

> -static bool file_exists(const char *path)

> -{

> -    struct stat st;

> -    return stat(path, &st) == 0 && (S_ISREG(st.st_mode) || 
> S_ISLNK(st.st_mode));

> -}

> -

>  #define POWEROFF_CMD_PATH "/sbin/poweroff"

>  #define HALT_CMD_PATH "/sbin/halt"

>  #define REBOOT_CMD_PATH "/sbin/reboot"

> @@ -245,17 +239,17 @@ void qmp_guest_shutdown(const char *mode, Error **errp)

>  

>      slog("guest-shutdown called, mode: %s", mode);

>      if (!mode || strcmp(mode, "powerdown") == 0) {

> -        if (file_exists(POWEROFF_CMD_PATH)) {

> +        if (access(POWEROFF_CMD_PATH, X_OK) == 0) {

>              shutdown_cmd = POWEROFF_CMD_PATH;

>          }

>          shutdown_flag = powerdown_flag;

>      } else if (strcmp(mode, "halt") == 0) {

> -        if (file_exists(HALT_CMD_PATH)) {

> +        if (access(HALT_CMD_PATH, X_OK) == 0) {

>              shutdown_cmd = HALT_CMD_PATH;

>          }

>          shutdown_flag = halt_flag;

>      } else if (strcmp(mode, "reboot") == 0) {

> -        if (file_exists(REBOOT_CMD_PATH)) {

> +        if (access(REBOOT_CMD_PATH, X_OK) == 0) {

>              shutdown_cmd = REBOOT_CMD_PATH;

>          }

>          shutdown_flag = reboot_flag;




Reply via email to