|
Packit |
fc043f |
/* sysutils.c - Platform specific helper functions
|
|
Packit |
fc043f |
* Copyright (C) 2017 g10 Code GmbH
|
|
Packit |
fc043f |
*
|
|
Packit |
fc043f |
* This file is part of libgpg-error.
|
|
Packit |
fc043f |
*
|
|
Packit |
fc043f |
* libgpg-error is free software; you can redistribute it and/or
|
|
Packit |
fc043f |
* modify it under the terms of the GNU Lesser General Public License
|
|
Packit |
fc043f |
* as published by the Free Software Foundation; either version 2.1 of
|
|
Packit |
fc043f |
* the License, or (at your option) any later version.
|
|
Packit |
fc043f |
*
|
|
Packit |
fc043f |
* libgpg-error is distributed in the hope that it will be useful, but
|
|
Packit |
fc043f |
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
fc043f |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Packit |
fc043f |
* Lesser General Public License for more details.
|
|
Packit |
fc043f |
*
|
|
Packit |
fc043f |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit |
fc043f |
* License along with this program; if not, see <https://www.gnu.org/licenses/>.
|
|
Packit |
fc043f |
* SPDX-License-Identifier: LGPL-2.1+
|
|
Packit |
fc043f |
*/
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#include <config.h>
|
|
Packit |
fc043f |
#include <stdlib.h>
|
|
Packit |
fc043f |
#include <stdint.h>
|
|
Packit |
fc043f |
#include <string.h>
|
|
Packit |
fc043f |
#include <unistd.h>
|
|
Packit |
fc043f |
#include <errno.h>
|
|
Packit |
fc043f |
#ifdef HAVE_W32_SYSTEM
|
|
Packit |
fc043f |
# include <windows.h>
|
|
Packit |
fc043f |
#endif
|
|
Packit |
fc043f |
#ifdef HAVE_STAT
|
|
Packit |
fc043f |
# include <sys/stat.h>
|
|
Packit |
fc043f |
#endif
|
|
Packit |
fc043f |
#include <sys/types.h>
|
|
Packit |
fc043f |
#include <fcntl.h>
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#include "gpgrt-int.h"
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
/* Return true if FD is valid. */
|
|
Packit |
fc043f |
int
|
|
Packit |
fc043f |
_gpgrt_fd_valid_p (int fd)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
int d = dup (fd);
|
|
Packit |
fc043f |
if (d < 0)
|
|
Packit |
fc043f |
return 0;
|
|
Packit |
fc043f |
close (d);
|
|
Packit |
fc043f |
return 1;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
/* Our variant of getenv. The returned string must be freed. If the
|
|
Packit |
fc043f |
* environment variable does not exists NULL is returned and ERRNO set
|
|
Packit |
fc043f |
* to 0. */
|
|
Packit |
fc043f |
char *
|
|
Packit |
fc043f |
_gpgrt_getenv (const char *name)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
if (!name || !*name || strchr (name, '='))
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpg_err_set_errno (EINVAL);
|
|
Packit |
fc043f |
return NULL;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#ifdef HAVE_W32_SYSTEM
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
int len, size;
|
|
Packit |
fc043f |
char *result;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
len = GetEnvironmentVariable (name, NULL, 0);
|
|
Packit |
fc043f |
if (!len && GetLastError () == ERROR_ENVVAR_NOT_FOUND)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpg_err_set_errno (0);
|
|
Packit |
fc043f |
return NULL;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
again:
|
|
Packit |
fc043f |
size = len;
|
|
Packit |
fc043f |
result = _gpgrt_malloc (size);
|
|
Packit |
fc043f |
if (!result)
|
|
Packit |
fc043f |
return NULL;
|
|
Packit |
fc043f |
len = GetEnvironmentVariable (name, result, size);
|
|
Packit |
fc043f |
if (len >= size)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
/* Changed in the meantime - retry. */
|
|
Packit |
fc043f |
_gpgrt_free (result);
|
|
Packit |
fc043f |
goto again;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
if (!len && GetLastError () == ERROR_ENVVAR_NOT_FOUND)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
/* Deleted in the meantime. */
|
|
Packit |
fc043f |
_gpgrt_free (result);
|
|
Packit |
fc043f |
_gpg_err_set_errno (0);
|
|
Packit |
fc043f |
return NULL;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
if (!len)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
/* Other error. FIXME: We need mapping fucntion. */
|
|
Packit |
fc043f |
_gpgrt_free (result);
|
|
Packit |
fc043f |
_gpg_err_set_errno (EIO);
|
|
Packit |
fc043f |
return NULL;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return result;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
#else /*!HAVE_W32_SYSTEM*/
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
const char *s = getenv (name);
|
|
Packit |
fc043f |
if (!s)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
_gpg_err_set_errno (0);
|
|
Packit |
fc043f |
return NULL;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
return _gpgrt_strdup (s);
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
#endif /*!HAVE_W32_SYSTEM*/
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
/* Wrapper around setenv so that we can have the same function in
|
|
Packit |
fc043f |
* Windows and Unix. In contrast to the standard setenv passing a
|
|
Packit |
fc043f |
* VALUE as NULL and setting OVERWRITE will remove the envvar. */
|
|
Packit |
fc043f |
gpg_err_code_t
|
|
Packit |
fc043f |
_gpgrt_setenv (const char *name, const char *value, int overwrite)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
if (!name || !*name || strchr (name, '='))
|
|
Packit |
fc043f |
return GPG_ERR_EINVAL;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#ifdef HAVE_W32_SYSTEM
|
|
Packit |
fc043f |
/* Windows maintains (at least) two sets of environment variables.
|
|
Packit |
fc043f |
* One set can be accessed by GetEnvironmentVariable and
|
|
Packit |
fc043f |
* SetEnvironmentVariable. This set is inherited by the children.
|
|
Packit |
fc043f |
* The other set is maintained in the C runtime, and is accessed
|
|
Packit |
fc043f |
* using getenv and putenv. We try to keep them in sync by
|
|
Packit |
fc043f |
* modifying both sets. Note that gpgrt_getenv ignores the libc
|
|
Packit |
fc043f |
* values - however, too much existing code still uses getenv. */
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
int exists;
|
|
Packit |
fc043f |
char tmpbuf[10];
|
|
Packit |
fc043f |
char *buf;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
if (!value && overwrite)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
if (!SetEnvironmentVariable (name, NULL))
|
|
Packit |
fc043f |
return GPG_ERR_EINVAL;
|
|
Packit |
fc043f |
if (getenv (name))
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
/* Ugly: Leaking memory. */
|
|
Packit |
fc043f |
buf = _gpgrt_strdup (name);
|
|
Packit |
fc043f |
if (!buf)
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
if (putenv (buf))
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
return 0;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
exists = GetEnvironmentVariable (name, tmpbuf, sizeof tmpbuf);
|
|
Packit |
fc043f |
if ((! exists || overwrite) && !SetEnvironmentVariable (name, value))
|
|
Packit |
fc043f |
return GPG_ERR_EINVAL; /* (Might also be ENOMEM.) */
|
|
Packit |
fc043f |
if (overwrite || !getenv (name))
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
/* Ugly: Leaking memory. */
|
|
Packit |
fc043f |
buf = _gpgrt_strconcat (name, "=", value, NULL);
|
|
Packit |
fc043f |
if (!buf)
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
if (putenv (buf))
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
return 0;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#else /*!HAVE_W32_SYSTEM*/
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
# ifdef HAVE_SETENV
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
if (!value && overwrite)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
if (unsetenv (name))
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
else
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
if (setenv (name, value, overwrite))
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return 0;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
# else /*!HAVE_SETENV*/
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
# if __GNUC__
|
|
Packit |
fc043f |
# warning no setenv - using putenv but leaking memory.
|
|
Packit |
fc043f |
# endif
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
char *buf;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
if (!value && overwrite)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
if (getenv (name))
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
buf = _gpgrt_strdup (name);
|
|
Packit |
fc043f |
if (!buf)
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
if (putenv (buf))
|
|
Packit |
fc043f |
return -1;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
else if (overwrite || !getenv (name))
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
buf = _gpgrt_strconcat (name, "=", value, NULL);
|
|
Packit |
fc043f |
if (!buf)
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
if (putenv (buf))
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return 0;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
# endif /*!HAVE_SETENV*/
|
|
Packit |
fc043f |
#endif /*!HAVE_W32_SYSTEM*/
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
#ifndef HAVE_W32_SYSTEM
|
|
Packit |
fc043f |
static mode_t
|
|
Packit |
fc043f |
modestr_to_mode (const char *modestr)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
mode_t mode = 0;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
if (modestr && *modestr)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
modestr++;
|
|
Packit |
fc043f |
if (*modestr && *modestr++ == 'r')
|
|
Packit |
fc043f |
mode |= S_IRUSR;
|
|
Packit |
fc043f |
if (*modestr && *modestr++ == 'w')
|
|
Packit |
fc043f |
mode |= S_IWUSR;
|
|
Packit |
fc043f |
if (*modestr && *modestr++ == 'x')
|
|
Packit |
fc043f |
mode |= S_IXUSR;
|
|
Packit |
fc043f |
if (*modestr && *modestr++ == 'r')
|
|
Packit |
fc043f |
mode |= S_IRGRP;
|
|
Packit |
fc043f |
if (*modestr && *modestr++ == 'w')
|
|
Packit |
fc043f |
mode |= S_IWGRP;
|
|
Packit |
fc043f |
if (*modestr && *modestr++ == 'x')
|
|
Packit |
fc043f |
mode |= S_IXGRP;
|
|
Packit |
fc043f |
if (*modestr && *modestr++ == 'r')
|
|
Packit |
fc043f |
mode |= S_IROTH;
|
|
Packit |
fc043f |
if (*modestr && *modestr++ == 'w')
|
|
Packit |
fc043f |
mode |= S_IWOTH;
|
|
Packit |
fc043f |
if (*modestr && *modestr++ == 'x')
|
|
Packit |
fc043f |
mode |= S_IXOTH;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
return mode;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
#endif
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
/* A wrapper around mkdir which takes a string for the mode argument.
|
|
Packit |
fc043f |
* This makes it easier to handle the mode argument which is not
|
|
Packit |
fc043f |
* defined on all systems. The format of the modestring is
|
|
Packit |
fc043f |
*
|
|
Packit |
fc043f |
* "-rwxrwxrwx"
|
|
Packit |
fc043f |
*
|
|
Packit |
fc043f |
* '-' is a don't care or not set. 'r', 'w', 'x' are read allowed,
|
|
Packit |
fc043f |
* write allowed, execution allowed with the first group for the user,
|
|
Packit |
fc043f |
* the second for the group and the third for all others. If the
|
|
Packit |
fc043f |
* string is shorter than above the missing mode characters are meant
|
|
Packit |
fc043f |
* to be not set. */
|
|
Packit |
fc043f |
gpg_err_code_t
|
|
Packit |
fc043f |
_gpgrt_mkdir (const char *name, const char *modestr)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
#ifdef HAVE_W32CE_SYSTEM
|
|
Packit |
fc043f |
wchar_t *wname;
|
|
Packit |
fc043f |
(void)modestr;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
wname = utf8_to_wchar (name);
|
|
Packit |
fc043f |
if (!wname)
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
if (!CreateDirectoryW (wname, NULL))
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
xfree (wname);
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
xfree (wname);
|
|
Packit |
fc043f |
return 0;
|
|
Packit |
fc043f |
#elif MKDIR_TAKES_ONE_ARG
|
|
Packit |
fc043f |
(void)modestr;
|
|
Packit |
fc043f |
/* Note: In the case of W32 we better use CreateDirectory and try to
|
|
Packit |
fc043f |
set appropriate permissions. However using mkdir is easier
|
|
Packit |
fc043f |
because this sets ERRNO. */
|
|
Packit |
fc043f |
if (mkdir (name))
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
return 0;
|
|
Packit |
fc043f |
#else
|
|
Packit |
fc043f |
if (mkdir (name, modestr_to_mode (modestr)))
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
return 0;
|
|
Packit |
fc043f |
#endif
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
/* A simple wrapper around chdir. NAME is expected to be utf8
|
|
Packit |
fc043f |
* encoded. */
|
|
Packit |
fc043f |
gpg_err_code_t
|
|
Packit |
fc043f |
_gpgrt_chdir (const char *name)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
if (chdir (name))
|
|
Packit |
fc043f |
return _gpg_err_code_from_syserror ();
|
|
Packit |
fc043f |
return 0;
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
/* Return the current working directory as a malloced string. Return
|
|
Packit |
fc043f |
* NULL and sets ERRNO on error. */
|
|
Packit |
fc043f |
char *
|
|
Packit |
fc043f |
_gpgrt_getcwd (void)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
char *buffer;
|
|
Packit |
fc043f |
size_t size = 100;
|
|
Packit |
fc043f |
|
|
Packit |
fc043f |
for (;;)
|
|
Packit |
fc043f |
{
|
|
Packit |
fc043f |
buffer = xtrymalloc (size+1);
|
|
Packit |
fc043f |
if (!buffer)
|
|
Packit |
fc043f |
return NULL;
|
|
Packit |
fc043f |
#ifdef HAVE_W32CE_SYSTEM
|
|
Packit |
fc043f |
strcpy (buffer, "/"); /* Always "/". */
|
|
Packit |
fc043f |
return buffer;
|
|
Packit |
fc043f |
#else
|
|
Packit |
fc043f |
if (getcwd (buffer, size) == buffer)
|
|
Packit |
fc043f |
return buffer;
|
|
Packit |
fc043f |
xfree (buffer);
|
|
Packit |
fc043f |
if (errno != ERANGE)
|
|
Packit |
fc043f |
return NULL;
|
|
Packit |
fc043f |
size *= 2;
|
|
Packit |
fc043f |
#endif
|
|
Packit |
fc043f |
}
|
|
Packit |
fc043f |
}
|