Break out utils to separate file
This commit is contained in:
@@ -8,6 +8,8 @@ bin_PROGRAMS = build-root
|
||||
|
||||
build_root_SOURCES = \
|
||||
build-root.c \
|
||||
utils.h \
|
||||
utils.c \
|
||||
$(NULL)
|
||||
|
||||
build_root_CFLAGS = $(AM_CFLAGS)
|
||||
|
334
build-root.c
334
build-root.c
@@ -8,7 +8,7 @@
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
@@ -18,53 +18,28 @@
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <getopt.h>
|
||||
#include <grp.h>
|
||||
#include <linux/loop.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
#include <pwd.h>
|
||||
#include <sched.h>
|
||||
#include <signal.h>
|
||||
#include <poll.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/mount.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/eventfd.h>
|
||||
#include <sys/signalfd.h>
|
||||
#include <sys/capability.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <sys/utsname.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#if 0
|
||||
#define __debug__(x) printf x
|
||||
#else
|
||||
#define __debug__(x)
|
||||
#endif
|
||||
|
||||
#define N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
typedef int bool;
|
||||
|
||||
#define READ_END 0
|
||||
#define WRITE_END 1
|
||||
#include "utils.h"
|
||||
|
||||
/* Globals to avoid having to use getuid(), since the uid/gid changes during runtime */
|
||||
static uid_t uid;
|
||||
@@ -73,290 +48,6 @@ static bool is_privileged;
|
||||
static const char *argv0;
|
||||
static int proc_fd = -1;
|
||||
|
||||
static void
|
||||
strfreev (char **str_array)
|
||||
{
|
||||
if (str_array)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; str_array[i] != NULL; i++)
|
||||
free (str_array[i]);
|
||||
|
||||
free (str_array);
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
cleanup_freep (void *p)
|
||||
{
|
||||
void **pp = (void**)p;
|
||||
if (*pp)
|
||||
free (*pp);
|
||||
}
|
||||
|
||||
static inline void
|
||||
cleanup_strvp (void *p)
|
||||
{
|
||||
void **pp = (void**)p;
|
||||
strfreev (*pp);
|
||||
}
|
||||
|
||||
static inline void
|
||||
cleanup_fdp (int *fdp)
|
||||
{
|
||||
int fd;
|
||||
|
||||
assert (fdp);
|
||||
|
||||
fd = *fdp;
|
||||
if (fd != -1)
|
||||
(void) close (fd);
|
||||
}
|
||||
|
||||
#define cleanup_free __attribute__((cleanup(cleanup_freep)))
|
||||
#define cleanup_fd __attribute__((cleanup(cleanup_fdp)))
|
||||
#define cleanup_strv __attribute__((cleanup(cleanup_strvp)))
|
||||
|
||||
static inline void *
|
||||
steal_pointer (void *pp)
|
||||
{
|
||||
void **ptr = (void **) pp;
|
||||
void *ref;
|
||||
|
||||
ref = *ptr;
|
||||
*ptr = NULL;
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* type safety */
|
||||
#define steal_pointer(pp) \
|
||||
(0 ? (*(pp)) : (steal_pointer) (pp))
|
||||
|
||||
static void
|
||||
die_with_error (const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int errsv;
|
||||
|
||||
errsv = errno;
|
||||
|
||||
va_start (args, format);
|
||||
vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
|
||||
fprintf (stderr, ": %s\n", strerror (errsv));
|
||||
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static void
|
||||
die (const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static void
|
||||
die_oom (void)
|
||||
{
|
||||
die ("Out of memory");
|
||||
}
|
||||
|
||||
static void *
|
||||
xmalloc (size_t size)
|
||||
{
|
||||
void *res = malloc (size);
|
||||
if (res == NULL)
|
||||
die_oom ();
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *
|
||||
xcalloc (size_t size)
|
||||
{
|
||||
void *res = calloc (1, size);
|
||||
if (res == NULL)
|
||||
die_oom ();
|
||||
return res;
|
||||
}
|
||||
|
||||
static void *
|
||||
xrealloc (void *ptr, size_t size)
|
||||
{
|
||||
void *res = realloc (ptr, size);
|
||||
if (size != 0 && res == NULL)
|
||||
die_oom ();
|
||||
return res;
|
||||
}
|
||||
|
||||
static char *
|
||||
xstrdup (const char *str)
|
||||
{
|
||||
char *res;
|
||||
|
||||
assert (str != NULL);
|
||||
|
||||
res = strdup (str);
|
||||
if (res == NULL)
|
||||
die_oom ();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static void
|
||||
xsetenv (const char *name, const char *value, int overwrite)
|
||||
{
|
||||
if (setenv (name, value, overwrite))
|
||||
die ("setenv failed");
|
||||
}
|
||||
|
||||
static void
|
||||
xunsetenv (const char *name)
|
||||
{
|
||||
if (unsetenv(name))
|
||||
die ("unsetenv failed");
|
||||
}
|
||||
|
||||
static char *
|
||||
strconcat (const char *s1,
|
||||
const char *s2)
|
||||
{
|
||||
size_t len = 0;
|
||||
char *res;
|
||||
|
||||
if (s1)
|
||||
len += strlen (s1);
|
||||
if (s2)
|
||||
len += strlen (s2);
|
||||
|
||||
res = xmalloc (len + 1);
|
||||
*res = 0;
|
||||
if (s1)
|
||||
strcat (res, s1);
|
||||
if (s2)
|
||||
strcat (res, s2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static char *
|
||||
strconcat3 (const char *s1,
|
||||
const char *s2,
|
||||
const char *s3)
|
||||
{
|
||||
size_t len = 0;
|
||||
char *res;
|
||||
|
||||
if (s1)
|
||||
len += strlen (s1);
|
||||
if (s2)
|
||||
len += strlen (s2);
|
||||
if (s3)
|
||||
len += strlen (s3);
|
||||
|
||||
res = xmalloc (len + 1);
|
||||
*res = 0;
|
||||
if (s1)
|
||||
strcat (res, s1);
|
||||
if (s2)
|
||||
strcat (res, s2);
|
||||
if (s3)
|
||||
strcat (res, s3);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static char*
|
||||
strdup_printf (const char *format,
|
||||
...)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
vasprintf (&buffer, format, args);
|
||||
va_end (args);
|
||||
|
||||
if (buffer == NULL)
|
||||
die_oom ();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
static int
|
||||
fdwalk (int (*cb)(void *data, int fd), void *data)
|
||||
{
|
||||
int open_max;
|
||||
int fd;
|
||||
int dfd;
|
||||
int res = 0;
|
||||
DIR *d;
|
||||
|
||||
dfd = openat (proc_fd, "self/fd", O_DIRECTORY | O_PATH);
|
||||
if (dfd == -1)
|
||||
return -1;
|
||||
|
||||
if ((d = fdopendir (dfd)))
|
||||
{
|
||||
struct dirent *de;
|
||||
|
||||
while ((de = readdir (d)))
|
||||
{
|
||||
long l;
|
||||
char *e = NULL;
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
errno = 0;
|
||||
l = strtol (de->d_name, &e, 10);
|
||||
if (errno != 0 || !e || *e)
|
||||
continue;
|
||||
|
||||
fd = (int) l;
|
||||
|
||||
if ((long) fd != l)
|
||||
continue;
|
||||
|
||||
if (fd == dirfd (d))
|
||||
continue;
|
||||
|
||||
if ((res = cb (data, fd)) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
closedir (d);
|
||||
return res;
|
||||
}
|
||||
|
||||
open_max = sysconf (_SC_OPEN_MAX);
|
||||
|
||||
for (fd = 0; fd < open_max; fd++)
|
||||
if ((res = cb (data, fd)) != 0)
|
||||
break;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int raw_clone(unsigned long flags, void *child_stack) {
|
||||
#if defined(__s390__) || defined(__CRIS__)
|
||||
/* On s390 and cris the order of the first and second arguments
|
||||
* of the raw clone() system call is reversed. */
|
||||
return (int) syscall(__NR_clone, child_stack, flags);
|
||||
#else
|
||||
return (int) syscall(__NR_clone, flags, child_stack);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
usage ()
|
||||
{
|
||||
@@ -367,17 +58,6 @@ usage ()
|
||||
exit (1);
|
||||
}
|
||||
|
||||
static int
|
||||
pivot_root (const char * new_root, const char * put_old)
|
||||
{
|
||||
#ifdef __NR_pivot_root
|
||||
return syscall(__NR_pivot_root, new_root, put_old);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
BIND_READONLY = (1<<0),
|
||||
BIND_PRIVATE = (1<<1),
|
||||
@@ -1110,7 +790,7 @@ monitor_child (int event_fd)
|
||||
|
||||
/* Close all extra fds in the monitoring process.
|
||||
Any passed in fds have been passed on to the child anyway. */
|
||||
fdwalk (close_extra_fds, dont_close);
|
||||
fdwalk (proc_fd, close_extra_fds, dont_close);
|
||||
|
||||
sigemptyset (&mask);
|
||||
sigaddset (&mask, SIGCHLD);
|
||||
@@ -1654,7 +1334,7 @@ main (int argc,
|
||||
Any passed in fds have been passed on to the child anyway. */
|
||||
{
|
||||
int dont_close[] = { event_fd, sync_fd, -1 };
|
||||
fdwalk (close_extra_fds, dont_close);
|
||||
fdwalk (proc_fd, close_extra_fds, dont_close);
|
||||
}
|
||||
|
||||
return do_init (event_fd, pid);
|
||||
|
272
utils.c
Normal file
272
utils.c
Normal file
@@ -0,0 +1,272 @@
|
||||
/* build-root
|
||||
* Copyright (C) 2016 Alexander Larsson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
#include "config.h"
|
||||
|
||||
#include "utils.h"
|
||||
#include <sys/syscall.h>
|
||||
|
||||
void
|
||||
die_with_error (const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int errsv;
|
||||
|
||||
errsv = errno;
|
||||
|
||||
va_start (args, format);
|
||||
vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
|
||||
fprintf (stderr, ": %s\n", strerror (errsv));
|
||||
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void
|
||||
die (const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
|
||||
fprintf (stderr, "\n");
|
||||
|
||||
exit (1);
|
||||
}
|
||||
|
||||
void
|
||||
die_oom (void)
|
||||
{
|
||||
die ("Out of memory");
|
||||
}
|
||||
|
||||
void *
|
||||
xmalloc (size_t size)
|
||||
{
|
||||
void *res = malloc (size);
|
||||
if (res == NULL)
|
||||
die_oom ();
|
||||
return res;
|
||||
}
|
||||
|
||||
void *
|
||||
xcalloc (size_t size)
|
||||
{
|
||||
void *res = calloc (1, size);
|
||||
if (res == NULL)
|
||||
die_oom ();
|
||||
return res;
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc (void *ptr, size_t size)
|
||||
{
|
||||
void *res = realloc (ptr, size);
|
||||
if (size != 0 && res == NULL)
|
||||
die_oom ();
|
||||
return res;
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup (const char *str)
|
||||
{
|
||||
char *res;
|
||||
|
||||
assert (str != NULL);
|
||||
|
||||
res = strdup (str);
|
||||
if (res == NULL)
|
||||
die_oom ();
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void
|
||||
strfreev (char **str_array)
|
||||
{
|
||||
if (str_array)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; str_array[i] != NULL; i++)
|
||||
free (str_array[i]);
|
||||
|
||||
free (str_array);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
xsetenv (const char *name, const char *value, int overwrite)
|
||||
{
|
||||
if (setenv (name, value, overwrite))
|
||||
die ("setenv failed");
|
||||
}
|
||||
|
||||
void
|
||||
xunsetenv (const char *name)
|
||||
{
|
||||
if (unsetenv(name))
|
||||
die ("unsetenv failed");
|
||||
}
|
||||
|
||||
char *
|
||||
strconcat (const char *s1,
|
||||
const char *s2)
|
||||
{
|
||||
size_t len = 0;
|
||||
char *res;
|
||||
|
||||
if (s1)
|
||||
len += strlen (s1);
|
||||
if (s2)
|
||||
len += strlen (s2);
|
||||
|
||||
res = xmalloc (len + 1);
|
||||
*res = 0;
|
||||
if (s1)
|
||||
strcat (res, s1);
|
||||
if (s2)
|
||||
strcat (res, s2);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char *
|
||||
strconcat3 (const char *s1,
|
||||
const char *s2,
|
||||
const char *s3)
|
||||
{
|
||||
size_t len = 0;
|
||||
char *res;
|
||||
|
||||
if (s1)
|
||||
len += strlen (s1);
|
||||
if (s2)
|
||||
len += strlen (s2);
|
||||
if (s3)
|
||||
len += strlen (s3);
|
||||
|
||||
res = xmalloc (len + 1);
|
||||
*res = 0;
|
||||
if (s1)
|
||||
strcat (res, s1);
|
||||
if (s2)
|
||||
strcat (res, s2);
|
||||
if (s3)
|
||||
strcat (res, s3);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
char*
|
||||
strdup_printf (const char *format,
|
||||
...)
|
||||
{
|
||||
char *buffer = NULL;
|
||||
va_list args;
|
||||
|
||||
va_start (args, format);
|
||||
vasprintf (&buffer, format, args);
|
||||
va_end (args);
|
||||
|
||||
if (buffer == NULL)
|
||||
die_oom ();
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
int
|
||||
fdwalk (int proc_fd, int (*cb)(void *data, int fd), void *data)
|
||||
{
|
||||
int open_max;
|
||||
int fd;
|
||||
int dfd;
|
||||
int res = 0;
|
||||
DIR *d;
|
||||
|
||||
dfd = openat (proc_fd, "self/fd", O_DIRECTORY | O_PATH);
|
||||
if (dfd == -1)
|
||||
return -1;
|
||||
|
||||
if ((d = fdopendir (dfd)))
|
||||
{
|
||||
struct dirent *de;
|
||||
|
||||
while ((de = readdir (d)))
|
||||
{
|
||||
long l;
|
||||
char *e = NULL;
|
||||
|
||||
if (de->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
errno = 0;
|
||||
l = strtol (de->d_name, &e, 10);
|
||||
if (errno != 0 || !e || *e)
|
||||
continue;
|
||||
|
||||
fd = (int) l;
|
||||
|
||||
if ((long) fd != l)
|
||||
continue;
|
||||
|
||||
if (fd == dirfd (d))
|
||||
continue;
|
||||
|
||||
if ((res = cb (data, fd)) != 0)
|
||||
break;
|
||||
}
|
||||
|
||||
closedir (d);
|
||||
return res;
|
||||
}
|
||||
|
||||
open_max = sysconf (_SC_OPEN_MAX);
|
||||
|
||||
for (fd = 0; fd < open_max; fd++)
|
||||
if ((res = cb (data, fd)) != 0)
|
||||
break;
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int
|
||||
raw_clone (unsigned long flags,
|
||||
void *child_stack)
|
||||
{
|
||||
#if defined(__s390__) || defined(__CRIS__)
|
||||
/* On s390 and cris the order of the first and second arguments
|
||||
* of the raw clone() system call is reversed. */
|
||||
return (int) syscall(__NR_clone, child_stack, flags);
|
||||
#else
|
||||
return (int) syscall(__NR_clone, flags, child_stack);
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
pivot_root (const char * new_root, const char * put_old)
|
||||
{
|
||||
#ifdef __NR_pivot_root
|
||||
return syscall(__NR_pivot_root, new_root, put_old);
|
||||
#else
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
#endif
|
||||
}
|
128
utils.h
Normal file
128
utils.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/* build-root
|
||||
* Copyright (C) 2016 Alexander Larsson
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __UTILS_H__
|
||||
#define __UTILS_H__
|
||||
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if 0
|
||||
#define __debug__(x) printf x
|
||||
#else
|
||||
#define __debug__(x)
|
||||
#endif
|
||||
|
||||
#define N_ELEMENTS(arr) (sizeof (arr) / sizeof ((arr)[0]))
|
||||
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
typedef int bool;
|
||||
|
||||
#define PIPE_READ_END 0
|
||||
#define PIPE_WRITE_END 1
|
||||
|
||||
void strfreev (char **str_array);
|
||||
void die_with_error (const char *format,
|
||||
...);
|
||||
void die (const char *format,
|
||||
...);
|
||||
void die_oom (void);
|
||||
void *xmalloc (size_t size);
|
||||
void *xcalloc (size_t size);
|
||||
void *xrealloc (void *ptr,
|
||||
size_t size);
|
||||
char *xstrdup (const char *str);
|
||||
void xsetenv (const char *name,
|
||||
const char *value,
|
||||
int overwrite);
|
||||
void xunsetenv (const char *name);
|
||||
char *strconcat (const char *s1,
|
||||
const char *s2);
|
||||
char *strconcat3 (const char *s1,
|
||||
const char *s2,
|
||||
const char *s3);
|
||||
char* strdup_printf (const char *format,
|
||||
...);
|
||||
int fdwalk (int proc_fd,
|
||||
int (*cb)(void *data, int fd),
|
||||
void *data);
|
||||
|
||||
/* syscall wrappers */
|
||||
int raw_clone (unsigned long flags,
|
||||
void *child_stack);
|
||||
int pivot_root (const char *new_root,
|
||||
const char *put_old);
|
||||
|
||||
static inline void
|
||||
cleanup_freep (void *p)
|
||||
{
|
||||
void **pp = (void**)p;
|
||||
if (*pp)
|
||||
free (*pp);
|
||||
}
|
||||
|
||||
static inline void
|
||||
cleanup_strvp (void *p)
|
||||
{
|
||||
void **pp = (void**)p;
|
||||
strfreev (*pp);
|
||||
}
|
||||
|
||||
static inline void
|
||||
cleanup_fdp (int *fdp)
|
||||
{
|
||||
int fd;
|
||||
|
||||
assert (fdp);
|
||||
|
||||
fd = *fdp;
|
||||
if (fd != -1)
|
||||
(void) close (fd);
|
||||
}
|
||||
|
||||
#define cleanup_free __attribute__((cleanup(cleanup_freep)))
|
||||
#define cleanup_fd __attribute__((cleanup(cleanup_fdp)))
|
||||
#define cleanup_strv __attribute__((cleanup(cleanup_strvp)))
|
||||
|
||||
static inline void *
|
||||
steal_pointer (void *pp)
|
||||
{
|
||||
void **ptr = (void **) pp;
|
||||
void *ref;
|
||||
|
||||
ref = *ptr;
|
||||
*ptr = NULL;
|
||||
|
||||
return ref;
|
||||
}
|
||||
|
||||
/* type safety */
|
||||
#define steal_pointer(pp) \
|
||||
(0 ? (*(pp)) : (steal_pointer) (pp))
|
||||
|
||||
#endif /* __UTILS_H__ */
|
Reference in New Issue
Block a user