sudo/lib/util/multiarch.c

104 lines
3.1 KiB
C

/*
* SPDX-License-Identifier: ISC
*
* Copyright (c) 2022 Todd C. Miller <Todd.Miller@sudo.ws>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* This is an open source non-commercial project. Dear PVS-Studio, please check it.
* PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
*/
#include <config.h>
#ifdef __linux__
# include <sys/stat.h>
# include <sys/utsname.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sudo_compat.h>
#include <sudo_util.h>
# if defined(__linux__)
/*
* On Linux systems that use multi-arch, the actual DSO may be in a
* machine-specific subdirectory. If the specified path contains
* /lib/ or /libexec/, insert a multi-arch directory after it.
* If sb is non-NULL, stat(2) will be called on the new path, filling in sb.
* Returns a dynamically allocated string on success and NULL on failure.
*/
char *
sudo_stat_multiarch_v1(const char * restrict path, struct stat * restrict sb)
{
# if defined(__ILP32__)
const char *libdirs[] = { "/libx32/", "/lib/", "/libexec/", NULL };
# elif defined(__LP64__)
const char *libdirs[] = { "/lib64/", "/lib/", "/libexec/", NULL };
# else
const char *libdirs[] = { "/lib32/", "/lib/", "/libexec/", NULL };
# endif
const char **lp, *lib, *slash;
struct utsname unamebuf;
char *newpath = NULL;
size_t len;
if (uname(&unamebuf) == -1)
return NULL;
for (lp = libdirs; *lp != NULL; lp++) {
/* Replace lib64, lib32, libx32 with lib in new path. */
const char *newlib = lp == libdirs ? "/lib/" : *lp;
/* Search for lib dir in path, find the trailing slash. */
lib = strstr(path, *lp);
if (lib == NULL)
continue;
slash = lib + strlen(*lp) - 1;
/* Make sure there isn't already a machine-linux-gnu dir. */
len = strcspn(slash + 1, "/-");
if (strncmp(slash + 1 + len, "-linux-gnu/", 11) == 0) {
/* Multiarch already present. */
break;
}
/* Add machine-linux-gnu dir after /lib/ or /libexec/. */
if (asprintf(&newpath, "%.*s%s%s-linux-gnu%s",
(int)(lib - path), path, newlib, unamebuf.machine, slash) == -1) {
newpath = NULL;
break;
}
/* If sb was set, use stat(2) to make sure newpath exists. */
if (sb == NULL || stat(newpath, sb) == 0)
break;
free(newpath);
newpath = NULL;
}
return newpath;
}
#else
char *
sudo_stat_multiarch_v1(const char * restrict path, struct stat * restrict sb)
{
return NULL;
}
#endif /* __linux__ */