diff options
Diffstat (limited to 'REORG.TODO/sysdeps/posix')
95 files changed, 11340 insertions, 0 deletions
diff --git a/REORG.TODO/sysdeps/posix/Makefile b/REORG.TODO/sysdeps/posix/Makefile new file mode 100644 index 0000000000..52f20f5d97 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/Makefile @@ -0,0 +1,11 @@ +# These affect the generated bits/stdio_lim.h file. +L_tmpnam = 20 +TMP_MAX = 238328 +L_ctermid = 9 +L_cuserid = 9 + +ifeq ($(subdir)|$(have-thread-library),rt|no) +# With NPTL, this lives in libpthread so it can be used for sem_open too. +# Without NPTL, it's just private in librt. +librt-routines += shm-directory +endif diff --git a/REORG.TODO/sysdeps/posix/Subdirs b/REORG.TODO/sysdeps/posix/Subdirs new file mode 100644 index 0000000000..a46884d4f8 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/Subdirs @@ -0,0 +1 @@ +login diff --git a/REORG.TODO/sysdeps/posix/alarm.c b/REORG.TODO/sysdeps/posix/alarm.c new file mode 100644 index 0000000000..c1a50129ba --- /dev/null +++ b/REORG.TODO/sysdeps/posix/alarm.c @@ -0,0 +1,49 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <sys/time.h> + +/* Schedule an alarm. In SECONDS seconds, the process will get a SIGALRM. + If SECONDS is zero, any currently scheduled alarm will be cancelled. + The function returns the number of seconds remaining until the last + alarm scheduled would have signaled, or zero if there wasn't one. + There is no return value to indicate an error, but you can set `errno' + to 0 and check its value after calling `alarm', and this might tell you. + The signal may come late due to processor scheduling. */ +unsigned int +alarm (unsigned int seconds) +{ + struct itimerval old, new; + unsigned int retval; + + new.it_interval.tv_usec = 0; + new.it_interval.tv_sec = 0; + new.it_value.tv_usec = 0; + new.it_value.tv_sec = (long int) seconds; + if (__setitimer (ITIMER_REAL, &new, &old) < 0) + return 0; + + retval = old.it_value.tv_sec; + /* Round to the nearest second, but never report zero seconds when + the alarm is still set. */ + if (old.it_value.tv_usec >= 500000 + || (retval == 0 && old.it_value.tv_usec > 0)) + ++retval; + return retval; +} +libc_hidden_def (alarm) diff --git a/REORG.TODO/sysdeps/posix/clock.c b/REORG.TODO/sysdeps/posix/clock.c new file mode 100644 index 0000000000..2985f0bf5e --- /dev/null +++ b/REORG.TODO/sysdeps/posix/clock.c @@ -0,0 +1,31 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/times.h> +#include <time.h> + +/* Return the time used by the program so far (user time + system time). */ +clock_t +clock (void) +{ + struct tms buf; + + if (__times (&buf) < 0) + return (clock_t) -1; + + return buf.tms_utime + buf.tms_stime; +} diff --git a/REORG.TODO/sysdeps/posix/clock_getres.c b/REORG.TODO/sysdeps/posix/clock_getres.c new file mode 100644 index 0000000000..b6248bef2c --- /dev/null +++ b/REORG.TODO/sysdeps/posix/clock_getres.c @@ -0,0 +1,118 @@ +/* clock_getres -- Get the resolution of a POSIX clockid_t. + Copyright (C) 1999-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdint.h> +#include <time.h> +#include <unistd.h> +#include <sys/param.h> +#include <libc-internal.h> + + +#if HP_TIMING_AVAIL +static long int nsec; /* Clock frequency of the processor. */ + +static int +hp_timing_getres (struct timespec *res) +{ + if (__glibc_unlikely (nsec == 0)) + { + hp_timing_t freq; + + /* This can only happen if we haven't initialized the `nsec' + variable yet. Do this now. We don't have to protect this + code against multiple execution since all of them should + lead to the same result. */ + freq = __get_clockfreq (); + if (__glibc_unlikely (freq == 0)) + /* Something went wrong. */ + return -1; + + nsec = MAX (UINT64_C (1000000000) / freq, 1); + } + + /* Fill in the values. + The seconds are always zero (unless we have a 1Hz machine). */ + res->tv_sec = 0; + res->tv_nsec = nsec; + + return 0; +} +#endif + +static inline int +realtime_getres (struct timespec *res) +{ + long int clk_tck = sysconf (_SC_CLK_TCK); + + if (__glibc_likely (clk_tck != -1)) + { + /* This implementation assumes that the realtime clock has a + resolution higher than 1 second. This is the case for any + reasonable implementation. */ + res->tv_sec = 0; + res->tv_nsec = 1000000000 / clk_tck; + return 0; + } + + return -1; +} + + +/* Get resolution of clock. */ +int +__clock_getres (clockid_t clock_id, struct timespec *res) +{ + int retval = -1; + + switch (clock_id) + { +#ifdef SYSDEP_GETRES + SYSDEP_GETRES; +#endif + +#ifndef HANDLED_REALTIME + case CLOCK_REALTIME: + retval = realtime_getres (res); + break; +#endif /* handled REALTIME */ + + default: +#ifdef SYSDEP_GETRES_CPU + SYSDEP_GETRES_CPU; +#endif +#if HP_TIMING_AVAIL + if ((clock_id & ((1 << CLOCK_IDFIELD_SIZE) - 1)) + == CLOCK_THREAD_CPUTIME_ID) + retval = hp_timing_getres (res); + else +#endif + __set_errno (EINVAL); + break; + +#if HP_TIMING_AVAIL && !defined HANDLED_CPUTIME + case CLOCK_PROCESS_CPUTIME_ID: + case CLOCK_THREAD_CPUTIME_ID: + retval = hp_timing_getres (res); + break; +#endif + } + + return retval; +} +weak_alias (__clock_getres, clock_getres) diff --git a/REORG.TODO/sysdeps/posix/closedir.c b/REORG.TODO/sysdeps/posix/closedir.c new file mode 100644 index 0000000000..e7b7d77fde --- /dev/null +++ b/REORG.TODO/sysdeps/posix/closedir.c @@ -0,0 +1,54 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stddef.h> +#include <stdlib.h> +#include <dirent.h> +#include <unistd.h> +#include <dirstream.h> +#include <not-cancel.h> + + +/* Close the directory stream DIRP. + Return 0 if successful, -1 if not. */ +int +__closedir (DIR *dirp) +{ + int fd; + + if (dirp == NULL) + { + __set_errno (EINVAL); + return -1; + } + + /* We do not try to synchronize access here. If some other thread + still uses this handle it is a big mistake and that thread + deserves all the bad data it gets. */ + + fd = dirp->fd; + +#if IS_IN (libc) + __libc_lock_fini (dirp->lock); +#endif + + free ((void *) dirp); + + return close_not_cancel (fd); +} +weak_alias (__closedir, closedir) diff --git a/REORG.TODO/sysdeps/posix/ctermid.c b/REORG.TODO/sysdeps/posix/ctermid.c new file mode 100644 index 0000000000..253a89f0ab --- /dev/null +++ b/REORG.TODO/sysdeps/posix/ctermid.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <string.h> + + +/* Return the name of the controlling terminal. If S is not NULL, the + name is copied into it (it should be at least L_ctermid bytes + long), otherwise we return a pointer to a non-const but read-only + string literal, that POSIX states the caller must not modify. */ +char * +ctermid (char *s) +{ + char *name = (char /*drop const*/ *) "/dev/tty"; + + if (s == NULL) + return name; + + return strcpy (s, name); +} diff --git a/REORG.TODO/sysdeps/posix/cuserid.c b/REORG.TODO/sysdeps/posix/cuserid.c new file mode 100644 index 0000000000..bee9734793 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/cuserid.c @@ -0,0 +1,47 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <pwd.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <sys/types.h> + +/* Return the username of the caller. + If S is not NULL, it points to a buffer of at least L_cuserid bytes + into which the name is copied; otherwise, a static buffer is used. */ +char * +cuserid (char *s) +{ + static char name[L_cuserid]; + char buf[NSS_BUFLEN_PASSWD]; + struct passwd pwent; + struct passwd *pwptr; + + if (__getpwuid_r (__geteuid (), &pwent, buf, sizeof (buf), &pwptr) + || pwptr == NULL) + { + if (s != NULL) + s[0] = '\0'; + return s; + } + + if (s == NULL) + s = name; + s[L_cuserid - 1] = '\0'; + return strncpy (s, pwptr->pw_name, L_cuserid - 1); +} diff --git a/REORG.TODO/sysdeps/posix/dirfd.c b/REORG.TODO/sysdeps/posix/dirfd.c new file mode 100644 index 0000000000..fee8326d93 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/dirfd.c @@ -0,0 +1,28 @@ +/* Return the file descriptor used by a DIR stream. Unix version. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <dirent.h> +#include <dirstream.h> + +#undef dirfd + +int +dirfd (DIR *dirp) +{ + return dirp->fd; +} diff --git a/REORG.TODO/sysdeps/posix/dirstream.h b/REORG.TODO/sysdeps/posix/dirstream.h new file mode 100644 index 0000000000..521db348a6 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/dirstream.h @@ -0,0 +1,55 @@ +/* Copyright (C) 1993-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _DIRSTREAM_H +#define _DIRSTREAM_H 1 + +#include <sys/types.h> + +#include <libc-lock.h> + +/* Directory stream type. + + The miscellaneous Unix `readdir' implementations read directory data + into a buffer and return `struct dirent *' pointers into it. */ + +struct __dirstream + { + int fd; /* File descriptor. */ + + __libc_lock_define (, lock) /* Mutex lock for this structure. */ + + size_t allocation; /* Space allocated for the block. */ + size_t size; /* Total valid data in the block. */ + size_t offset; /* Current offset into the block. */ + + off_t filepos; /* Position of next entry to read. */ + + int errcode; /* Delayed error code. */ + + /* Directory block. We must make sure that this block starts + at an address that is aligned adequately enough to store + dirent entries. Using the alignment of "void *" is not + sufficient because dirents on 32-bit platforms can require + 64-bit alignment. We use "long double" here to be consistent + with what malloc uses. */ + char data[0] __attribute__ ((aligned (__alignof__ (long double)))); + }; + +#define _DIR_dirfd(dirp) ((dirp)->fd) + +#endif /* dirstream.h */ diff --git a/REORG.TODO/sysdeps/posix/dl-fileid.h b/REORG.TODO/sysdeps/posix/dl-fileid.h new file mode 100644 index 0000000000..0ab98272ba --- /dev/null +++ b/REORG.TODO/sysdeps/posix/dl-fileid.h @@ -0,0 +1,50 @@ +/* File identity for the dynamic linker. Generic POSIX.1 version. + Copyright (C) 2015-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdbool.h> +#include <sys/stat.h> + +/* For POSIX.1 systems, the pair of st_dev and st_ino constitute + a unique identifier for a file. */ +struct r_file_id + { + dev_t dev; + ino64_t ino; + }; + +/* Sample FD to fill in *ID. Returns true on success. + On error, returns false, with errno set. */ +static inline bool +_dl_get_file_id (int fd, struct r_file_id *id) +{ + struct stat64 st; + + if (__glibc_unlikely (__fxstat64 (_STAT_VER, fd, &st) < 0)) + return false; + + id->dev = st.st_dev; + id->ino = st.st_ino; + return true; +} + +/* Compare two results from _dl_get_file_id for equality. */ +static inline bool +_dl_file_id_match_p (const struct r_file_id *a, const struct r_file_id *b) +{ + return a->dev == b->dev && a->ino == b->ino; +} diff --git a/REORG.TODO/sysdeps/posix/dup.c b/REORG.TODO/sysdeps/posix/dup.c new file mode 100644 index 0000000000..82c0081111 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/dup.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + + +/* Duplicate FD, returning a new file descriptor open on the same file. */ +int +__dup (int fd) +{ + return __fcntl (fd, F_DUPFD, 0); +} +libc_hidden_def (__dup) +weak_alias (__dup, dup) diff --git a/REORG.TODO/sysdeps/posix/dup2.c b/REORG.TODO/sysdeps/posix/dup2.c new file mode 100644 index 0000000000..3c8e1bcac4 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/dup2.c @@ -0,0 +1,56 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <unistd.h> + +/* Duplicate FD to FD2, closing the old FD2 and making FD2 be + open the same file as FD is. Return FD2 or -1. */ +int +__dup2 (int fd, int fd2) +{ + int save; + + if (fd2 < 0 +#ifdef OPEN_MAX + || fd2 >= OPEN_MAX +#endif +) + { + __set_errno (EBADF); + return -1; + } + + /* Check if FD is kosher. */ + if (fcntl (fd, F_GETFL) < 0) + return -1; + + if (fd == fd2) + return fd2; + + /* This is not atomic. */ + + save = errno; + (void) close (fd2); + __set_errno (save); + + return fcntl (fd, F_DUPFD, fd2); +} +libc_hidden_def (__dup2) +weak_alias (__dup2, dup2) diff --git a/REORG.TODO/sysdeps/posix/euidaccess.c b/REORG.TODO/sysdeps/posix/euidaccess.c new file mode 100644 index 0000000000..0c6f4d0c54 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/euidaccess.c @@ -0,0 +1,215 @@ +/* Check if effective user id can access file + Copyright (C) 1990-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* Written by David MacKenzie and Torbjorn Granlund. + Adapted for GNU C library by Roland McGrath. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef S_IEXEC +# ifndef S_IXUSR +# define S_IXUSR S_IEXEC +# endif +# ifndef S_IXGRP +# define S_IXGRP (S_IEXEC >> 3) +# endif +# ifndef S_IXOTH +# define S_IXOTH (S_IEXEC >> 6) +# endif +#endif /* S_IEXEC */ + +#if defined HAVE_UNISTD_H || defined _LIBC +# include <unistd.h> +#endif + +#ifndef _POSIX_VERSION +uid_t getuid (); +gid_t getgid (); +uid_t geteuid (); +gid_t getegid (); +#endif /* not POSIX_VERSION */ + +#include <errno.h> +#ifndef errno +extern int errno; +#endif +#ifndef __set_errno +# define __set_errno(val) errno = (val) +#endif + +#if defined EACCES && !defined EACCESS +# define EACCESS EACCES +#endif + +#ifndef F_OK +# define F_OK 0 +# define X_OK 1 +# define W_OK 2 +# define R_OK 4 +#endif + +#if !defined S_IROTH && defined R_OK +# define S_IROTH R_OK +#endif +#if !defined S_IWOTH && defined W_OK +# define S_IWOTH W_OK +#endif +#if !defined S_IXOTH && defined X_OK +# define S_IXOTH X_OK +#endif + + +#ifdef _LIBC + +# define group_member __group_member +# define euidaccess __euidaccess + +#else + +/* The user's real user id. */ +static uid_t uid; + +/* The user's real group id. */ +static gid_t gid; + +/* The user's effective user id. */ +static uid_t euid; + +/* The user's effective group id. */ +static gid_t egid; + +/* Nonzero if UID, GID, EUID, and EGID have valid values. */ +static int have_ids; + +# ifdef HAVE_GETGROUPS +int group_member (); +# else +# define group_member(gid) 0 +# endif + +#endif + + +/* Return 0 if the user has permission of type MODE on file PATH; + otherwise, return -1 and set `errno' to EACCESS. + Like access, except that it uses the effective user and group + id's instead of the real ones, and it does not check for read-only + filesystem, text busy, etc. */ + +int +euidaccess (const char *path, int mode) +{ + struct stat64 stats; + int granted; + +#ifdef _LIBC + uid_t euid; + gid_t egid; +#else + if (have_ids == 0) + { + have_ids = 1; + uid = getuid (); + gid = getgid (); + euid = geteuid (); + egid = getegid (); + } + + if (uid == euid && gid == egid) + /* If we are not set-uid or set-gid, access does the same. */ + return access (path, mode); +#endif + + if (stat64 (path, &stats)) + return -1; + + mode &= (X_OK | W_OK | R_OK); /* Clear any bogus bits. */ +#if R_OK != S_IROTH || W_OK != S_IWOTH || X_OK != S_IXOTH + ?error Oops, portability assumptions incorrect. +#endif + + if (mode == F_OK) + return 0; /* The file exists. */ + +#ifdef _LIBC + /* Now we need the IDs. */ + euid = __geteuid (); + egid = __getegid (); + + if (__getuid () == euid && __getgid () == egid) + /* If we are not set-uid or set-gid, access does the same. */ + return __access (path, mode); +#endif + + /* The super-user can read and write any file, and execute any file + that anyone can execute. */ + if (euid == 0 && ((mode & X_OK) == 0 + || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))) + return 0; + + if (euid == stats.st_uid) + granted = (unsigned int) (stats.st_mode & (mode << 6)) >> 6; + else if (egid == stats.st_gid || group_member (stats.st_gid)) + granted = (unsigned int) (stats.st_mode & (mode << 3)) >> 3; + else + granted = (stats.st_mode & mode); + /* XXX Add support for ACLs. */ + if (granted == mode) + return 0; + __set_errno (EACCESS); + return -1; +} +#undef euidaccess +#undef eaccess +#ifdef weak_alias +weak_alias (__euidaccess, euidaccess) +weak_alias (__euidaccess, eaccess) +#endif + +#ifdef TEST +# include <stdio.h> +# include <errno.h> +# include "error.h" + +char *program_name; + +int +main (int argc, char **argv) +{ + char *file; + int mode; + int err; + + program_name = argv[0]; + if (argc < 3) + abort (); + file = argv[1]; + mode = atoi (argv[2]); + + err = euidaccess (file, mode); + printf ("%d\n", err); + if (err != 0) + error (0, errno, "%s", file); + exit (0); +} +#endif diff --git a/REORG.TODO/sysdeps/posix/fdopendir.c b/REORG.TODO/sysdeps/posix/fdopendir.c new file mode 100644 index 0000000000..6e772f26ff --- /dev/null +++ b/REORG.TODO/sysdeps/posix/fdopendir.c @@ -0,0 +1,52 @@ +/* Copyright (C) 2005-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <sys/stat.h> + +#include <not-cancel.h> + + +DIR * +__fdopendir (int fd) +{ + struct stat64 statbuf; + + if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &statbuf), 0) < 0) + return NULL; + if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode))) + { + __set_errno (ENOTDIR); + return NULL; + } + + /* Make sure the descriptor allows for reading. */ + int flags = __fcntl (fd, F_GETFL); + if (__glibc_unlikely (flags == -1)) + return NULL; + if (__glibc_unlikely ((flags & O_ACCMODE) == O_WRONLY)) + { + __set_errno (EINVAL); + return NULL; + } + + return __alloc_dir (fd, false, flags, &statbuf); +} +weak_alias (__fdopendir, fdopendir) diff --git a/REORG.TODO/sysdeps/posix/flock.c b/REORG.TODO/sysdeps/posix/flock.c new file mode 100644 index 0000000000..5aeba7d1b8 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/flock.c @@ -0,0 +1,56 @@ +/* Copyright (C) 1992-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* This file implements the `flock' function in terms of the POSIX.1 `fcntl' + locking mechanism. In 4BSD, these are two incompatible locking mechanisms, + perhaps with different semantics? */ + +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/file.h> + +/* Apply or remove an advisory lock, according to OPERATION, + on the file FD refers to. */ +int +__flock (int fd, int operation) +{ + struct flock lbuf; + + switch (operation & ~LOCK_NB) + { + case LOCK_SH: + lbuf.l_type = F_RDLCK; + break; + case LOCK_EX: + lbuf.l_type = F_WRLCK; + break; + case LOCK_UN: + lbuf.l_type = F_UNLCK; + break; + default: + __set_errno (EINVAL); + return -1; + } + + lbuf.l_whence = SEEK_SET; + lbuf.l_start = lbuf.l_len = 0L; /* Lock the whole file. */ + + return __fcntl (fd, (operation & LOCK_NB) ? F_SETLK : F_SETLKW, &lbuf); +} + +weak_alias (__flock, flock) diff --git a/REORG.TODO/sysdeps/posix/fpathconf.c b/REORG.TODO/sysdeps/posix/fpathconf.c new file mode 100644 index 0000000000..a363a59659 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/fpathconf.c @@ -0,0 +1,229 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> +#include <limits.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <sys/statvfs.h> + + +/* Get file-specific information about descriptor FD. */ +long int +__fpathconf (int fd, int name) +{ + if (fd < 0) + { + __set_errno (EBADF); + return -1; + } + + switch (name) + { + default: + __set_errno (EINVAL); + return -1; + + case _PC_LINK_MAX: +#ifdef LINK_MAX + return LINK_MAX; +#else + return -1; +#endif + + case _PC_MAX_CANON: +#ifdef MAX_CANON + return MAX_CANON; +#else + return -1; +#endif + + case _PC_MAX_INPUT: +#ifdef MAX_INPUT + return MAX_INPUT; +#else + return -1; +#endif + + case _PC_NAME_MAX: +#ifdef NAME_MAX + { + struct statvfs64 sv; + int save_errno = errno; + + if (__fstatvfs64 (fd, &sv) < 0) + { + if (errno == ENOSYS) + { + __set_errno (save_errno); + return NAME_MAX; + } + else if (errno == ENODEV) + __set_errno (EINVAL); + + return -1; + } + else + { + return sv.f_namemax; + } + } +#else + return -1; +#endif + + case _PC_PATH_MAX: +#ifdef PATH_MAX + return PATH_MAX; +#else + return -1; +#endif + + case _PC_PIPE_BUF: +#ifdef PIPE_BUF + return PIPE_BUF; +#else + return -1; +#endif + + case _PC_CHOWN_RESTRICTED: +#ifdef _POSIX_CHOWN_RESTRICTED + return _POSIX_CHOWN_RESTRICTED; +#else + return -1; +#endif + + case _PC_NO_TRUNC: +#ifdef _POSIX_NO_TRUNC + return _POSIX_NO_TRUNC; +#else + return -1; +#endif + + case _PC_VDISABLE: +#ifdef _POSIX_VDISABLE + return _POSIX_VDISABLE; +#else + return -1; +#endif + + case _PC_SYNC_IO: +#ifdef _POSIX_SYNC_IO + return _POSIX_SYNC_IO; +#else + return -1; +#endif + + case _PC_ASYNC_IO: +#ifdef _POSIX_ASYNC_IO + { + /* AIO is only allowed on regular files and block devices. */ + struct stat64 st; + + if (__fxstat64 (_STAT_VER, fd, &st) < 0 + || (! S_ISREG (st.st_mode) && ! S_ISBLK (st.st_mode))) + return -1; + else + return 1; + } +#else + return -1; +#endif + + case _PC_PRIO_IO: +#ifdef _POSIX_PRIO_IO + return _POSIX_PRIO_IO; +#else + return -1; +#endif + + case _PC_SOCK_MAXBUF: +#ifdef SOCK_MAXBUF + return SOCK_MAXBUF; +#else + return -1; +#endif + + case _PC_FILESIZEBITS: +#ifdef FILESIZEBITS + return FILESIZEBITS; +#else + /* We let platforms with larger file sizes overwrite this value. */ + return 32; +#endif + + case _PC_REC_INCR_XFER_SIZE: + /* XXX It is not entirely clear what the limit is supposed to do. + What is incremented? */ + return -1; + + case _PC_REC_MAX_XFER_SIZE: + /* XXX It is not entirely clear what the limit is supposed to do. + In general there is no top limit of the number of bytes which + case be transported at once. */ + return -1; + + case _PC_REC_MIN_XFER_SIZE: + { + /* XXX It is not entirely clear what the limit is supposed to do. + I assume this is the block size of the filesystem. */ + struct statvfs64 sv; + + if (__fstatvfs64 (fd, &sv) < 0) + return -1; + return sv.f_bsize; + } + + case _PC_REC_XFER_ALIGN: + { + /* XXX It is not entirely clear what the limit is supposed to do. + I assume that the number should reflect the minimal block + alignment. */ + struct statvfs64 sv; + + if (__fstatvfs64 (fd, &sv) < 0) + return -1; + return sv.f_frsize; + } + + case _PC_ALLOC_SIZE_MIN: + { + /* XXX It is not entirely clear what the limit is supposed to do. + I assume that the number should reflect the minimal block + alignment. */ + struct statvfs64 sv; + + if (__fstatvfs64 (fd, &sv) < 0) + return -1; + return sv.f_frsize; + } + + case _PC_SYMLINK_MAX: + /* In general there are no limits. If a system has one it should + overwrite this case. */ + return -1; + + case _PC_2_SYMLINKS: + /* Unix systems generally have symlinks. */ + return 1; + } +} + +#undef __fpathconf +weak_alias (__fpathconf, fpathconf) diff --git a/REORG.TODO/sysdeps/posix/gai_strerror-strs.h b/REORG.TODO/sysdeps/posix/gai_strerror-strs.h new file mode 100644 index 0000000000..19040a5138 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/gai_strerror-strs.h @@ -0,0 +1,17 @@ +_S(EAI_ADDRFAMILY, N_("Address family for hostname not supported")) +_S(EAI_AGAIN, N_("Temporary failure in name resolution")) +_S(EAI_BADFLAGS, N_("Bad value for ai_flags")) +_S(EAI_FAIL, N_("Non-recoverable failure in name resolution")) +_S(EAI_FAMILY, N_("ai_family not supported")) +_S(EAI_MEMORY, N_("Memory allocation failure")) +_S(EAI_NODATA, N_("No address associated with hostname")) +_S(EAI_NONAME, N_("Name or service not known")) +_S(EAI_SERVICE, N_("Servname not supported for ai_socktype")) +_S(EAI_SOCKTYPE, N_("ai_socktype not supported")) +_S(EAI_SYSTEM, N_("System error")) +_S(EAI_INPROGRESS, N_("Processing request in progress")) +_S(EAI_CANCELED, N_("Request canceled")) +_S(EAI_NOTCANCELED, N_("Request not canceled")) +_S(EAI_ALLDONE, N_("All requests done")) +_S(EAI_INTR, N_("Interrupted by a signal")) +_S(EAI_IDN_ENCODE, N_("Parameter string not correctly encoded")) diff --git a/REORG.TODO/sysdeps/posix/gai_strerror.c b/REORG.TODO/sysdeps/posix/gai_strerror.c new file mode 100644 index 0000000000..e47e14688f --- /dev/null +++ b/REORG.TODO/sysdeps/posix/gai_strerror.c @@ -0,0 +1,69 @@ +/* Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Philip Blundell <pjb27@cam.ac.uk>, 1997. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <libintl.h> +#include <netdb.h> +#include <stdint.h> +#include <stdio.h> + + +#define MSGSTRFIELD(line) MSGSTRFIELD1 (line) +#define MSGSTRFIELD1(line) str##line +static const union msgstr_t +{ + struct + { +#define _S(n, s) char MSGSTRFIELD(__LINE__)[sizeof (s)]; +#include "gai_strerror-strs.h" +#undef _S + }; + char str[0]; +} msgstr = + { + { +#define _S(n, s) s, +#include "gai_strerror-strs.h" +#undef _S + } + }; +static const struct +{ + int16_t code; + uint16_t idx; +} msgidx[] = + { +#define _S(n, s) { n, offsetof (union msgstr_t, MSGSTRFIELD (__LINE__)) }, +#include "gai_strerror-strs.h" +#undef _S + }; + + +const char * +gai_strerror (int code) +{ + const char *result = "Unknown error"; + for (size_t i = 0; i < sizeof (msgidx) / sizeof (msgidx[0]); ++i) + if (msgidx[i].code == code) + { + result = msgstr.str + msgidx[i].idx; + break; + } + + return _(result); +} +libc_hidden_def (gai_strerror) diff --git a/REORG.TODO/sysdeps/posix/getaddrinfo.c b/REORG.TODO/sysdeps/posix/getaddrinfo.c new file mode 100644 index 0000000000..a8bdd9a182 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/getaddrinfo.c @@ -0,0 +1,2598 @@ +/* Host and service name lookups using Name Service Switch modules. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* The Inner Net License, Version 2.00 + + The author(s) grant permission for redistribution and use in source and +binary forms, with or without modification, of the software and documentation +provided that the following conditions are met: + +0. If you receive a version of the software that is specifically labelled + as not being for redistribution (check the version message and/or README), + you are not permitted to redistribute that version of the software in any + way or form. +1. All terms of the all other applicable copyrights and licenses must be + followed. +2. Redistributions of source code must retain the authors' copyright + notice(s), this list of conditions, and the following disclaimer. +3. Redistributions in binary form must reproduce the authors' copyright + notice(s), this list of conditions, and the following disclaimer in the + documentation and/or other materials provided with the distribution. +4. [The copyright holder has authorized the removal of this clause.] +5. Neither the name(s) of the author(s) nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + If these license terms cause you a real problem, contact the author. */ + +/* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */ + +#include <assert.h> +#include <ctype.h> +#include <errno.h> +#include <ifaddrs.h> +#include <netdb.h> +#include <nss.h> +#include <resolv/resolv-internal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <stdlib.h> +#include <string.h> +#include <stdint.h> +#include <arpa/inet.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/un.h> +#include <sys/utsname.h> +#include <unistd.h> +#include <nsswitch.h> +#include <libc-lock.h> +#include <not-cancel.h> +#include <nscd/nscd-client.h> +#include <nscd/nscd_proto.h> +#include <resolv/res_hconf.h> +#include <scratch_buffer.h> +#include <inet/net-internal.h> + +#ifdef HAVE_LIBIDN +extern int __idna_to_ascii_lz (const char *input, char **output, int flags); +extern int __idna_to_unicode_lzlz (const char *input, char **output, + int flags); +# include <libidn/idna.h> +#endif + +struct gaih_service + { + const char *name; + int num; + }; + +struct gaih_servtuple + { + struct gaih_servtuple *next; + int socktype; + int protocol; + int port; + }; + +static const struct gaih_servtuple nullserv; + + +struct gaih_typeproto + { + int socktype; + int protocol; + uint8_t protoflag; + bool defaultflag; + char name[8]; + }; + +/* Values for `protoflag'. */ +#define GAI_PROTO_NOSERVICE 1 +#define GAI_PROTO_PROTOANY 2 + +static const struct gaih_typeproto gaih_inet_typeproto[] = +{ + { 0, 0, 0, false, "" }, + { SOCK_STREAM, IPPROTO_TCP, 0, true, "tcp" }, + { SOCK_DGRAM, IPPROTO_UDP, 0, true, "udp" }, +#if defined SOCK_DCCP && defined IPPROTO_DCCP + { SOCK_DCCP, IPPROTO_DCCP, 0, false, "dccp" }, +#endif +#ifdef IPPROTO_UDPLITE + { SOCK_DGRAM, IPPROTO_UDPLITE, 0, false, "udplite" }, +#endif +#ifdef IPPROTO_SCTP + { SOCK_STREAM, IPPROTO_SCTP, 0, false, "sctp" }, + { SOCK_SEQPACKET, IPPROTO_SCTP, 0, false, "sctp" }, +#endif + { SOCK_RAW, 0, GAI_PROTO_PROTOANY|GAI_PROTO_NOSERVICE, true, "raw" }, + { 0, 0, 0, false, "" } +}; + +static const struct addrinfo default_hints = + { + .ai_flags = AI_DEFAULT, + .ai_family = PF_UNSPEC, + .ai_socktype = 0, + .ai_protocol = 0, + .ai_addrlen = 0, + .ai_addr = NULL, + .ai_canonname = NULL, + .ai_next = NULL + }; + + +static int +gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, + const struct addrinfo *req, struct gaih_servtuple *st, + struct scratch_buffer *tmpbuf) +{ + struct servent *s; + struct servent ts; + int r; + + do + { + r = __getservbyname_r (servicename, tp->name, &ts, + tmpbuf->data, tmpbuf->length, &s); + if (r != 0 || s == NULL) + { + if (r == ERANGE) + { + if (!scratch_buffer_grow (tmpbuf)) + return -EAI_MEMORY; + } + else + return -EAI_SERVICE; + } + } + while (r); + + st->next = NULL; + st->socktype = tp->socktype; + st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) + ? req->ai_protocol : tp->protocol); + st->port = s->s_port; + + return 0; +} + +/* Convert struct hostent to a list of struct gaih_addrtuple objects. + h_name is not copied, and the struct hostent object must not be + deallocated prematurely. *RESULT must be NULL or a pointer to an + object allocated using malloc, which is freed. */ +static bool +convert_hostent_to_gaih_addrtuple (const struct addrinfo *req, + int family, + struct hostent *h, + struct gaih_addrtuple **result) +{ + free (*result); + *result = NULL; + + /* Count the number of addresses in h->h_addr_list. */ + size_t count = 0; + for (char **p = h->h_addr_list; *p != NULL; ++p) + ++count; + + /* Report no data if no addresses are available, or if the incoming + address size is larger than what we can store. */ + if (count == 0 || h->h_length > sizeof (((struct gaih_addrtuple) {}).addr)) + return true; + + struct gaih_addrtuple *array = calloc (count, sizeof (*array)); + if (array == NULL) + return false; + + for (size_t i = 0; i < count; ++i) + { + if (family == AF_INET && req->ai_family == AF_INET6) + { + /* Perform address mapping. */ + array[i].family = AF_INET6; + memcpy(array[i].addr + 3, h->h_addr_list[i], sizeof (uint32_t)); + array[i].addr[2] = htonl (0xffff); + } + else + { + array[i].family = family; + memcpy (array[i].addr, h->h_addr_list[i], h->h_length); + } + array[i].next = array + i + 1; + } + array[0].name = h->h_name; + array[count - 1].next = NULL; + + *result = array; + return true; +} + +#define gethosts(_family, _type) \ + { \ + int herrno; \ + struct hostent th; \ + struct hostent *h; \ + char *localcanon = NULL; \ + no_data = 0; \ + while (1) { \ + rc = 0; \ + status = DL_CALL_FCT (fct, (name, _family, &th, \ + tmpbuf->data, tmpbuf->length, \ + &rc, &herrno, NULL, &localcanon)); \ + if (rc != ERANGE || herrno != NETDB_INTERNAL) \ + break; \ + if (!scratch_buffer_grow (tmpbuf)) \ + { \ + result = -EAI_MEMORY; \ + goto free_and_return; \ + } \ + } \ + if (status == NSS_STATUS_SUCCESS && rc == 0) \ + h = &th; \ + else \ + h = NULL; \ + if (rc != 0) \ + { \ + if (herrno == NETDB_INTERNAL) \ + { \ + __set_h_errno (herrno); \ + _res.options |= old_res_options & DEPRECATED_RES_USE_INET6; \ + result = -EAI_SYSTEM; \ + goto free_and_return; \ + } \ + if (herrno == TRY_AGAIN) \ + no_data = EAI_AGAIN; \ + else \ + no_data = herrno == NO_DATA; \ + } \ + else if (h != NULL) \ + { \ + if (!convert_hostent_to_gaih_addrtuple (req, _family,h, &addrmem)) \ + { \ + _res.options |= old_res_options & DEPRECATED_RES_USE_INET6; \ + result = -EAI_SYSTEM; \ + goto free_and_return; \ + } \ + *pat = addrmem; \ + \ + if (localcanon != NULL && canon == NULL) \ + { \ + canonbuf = __strdup (localcanon); \ + if (canonbuf == NULL) \ + { \ + result = -EAI_SYSTEM; \ + goto free_and_return; \ + } \ + canon = canonbuf; \ + } \ + if (_family == AF_INET6 && *pat != NULL) \ + got_ipv6 = true; \ + } \ + } + + +typedef enum nss_status (*nss_gethostbyname4_r) + (const char *name, struct gaih_addrtuple **pat, + char *buffer, size_t buflen, int *errnop, + int *h_errnop, int32_t *ttlp); +typedef enum nss_status (*nss_gethostbyname3_r) + (const char *name, int af, struct hostent *host, + char *buffer, size_t buflen, int *errnop, + int *h_errnop, int32_t *ttlp, char **canonp); +typedef enum nss_status (*nss_getcanonname_r) + (const char *name, char *buffer, size_t buflen, char **result, + int *errnop, int *h_errnop); +extern service_user *__nss_hosts_database attribute_hidden; + +/* This function is called if a canonical name is requested, but if + the service function did not provide it. It tries to obtain the + name using getcanonname_r from the same service NIP. If the name + cannot be canonicalized, return a copy of NAME. Return NULL on + memory allocation failure. The returned string is allocated on the + heap; the caller has to free it. */ +static char * +getcanonname (service_user *nip, struct gaih_addrtuple *at, const char *name) +{ + nss_getcanonname_r cfct = __nss_lookup_function (nip, "getcanonname_r"); + char *s = (char *) name; + if (cfct != NULL) + { + char buf[256]; + int herrno; + int rc; + if (DL_CALL_FCT (cfct, (at->name ?: name, buf, sizeof (buf), + &s, &rc, &herrno)) != NSS_STATUS_SUCCESS) + /* If the canonical name cannot be determined, use the passed + string. */ + s = (char *) name; + } + return __strdup (name); +} + +static int +gaih_inet (const char *name, const struct gaih_service *service, + const struct addrinfo *req, struct addrinfo **pai, + unsigned int *naddrs, struct scratch_buffer *tmpbuf) +{ + const struct gaih_typeproto *tp = gaih_inet_typeproto; + struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv; + struct gaih_addrtuple *at = NULL; + int rc; + bool got_ipv6 = false; + const char *canon = NULL; + const char *orig_name = name; + + /* Reserve stack memory for the scratch buffer in the getaddrinfo + function. */ + size_t alloca_used = sizeof (struct scratch_buffer); + + if (req->ai_protocol || req->ai_socktype) + { + ++tp; + + while (tp->name[0] + && ((req->ai_socktype != 0 && req->ai_socktype != tp->socktype) + || (req->ai_protocol != 0 + && !(tp->protoflag & GAI_PROTO_PROTOANY) + && req->ai_protocol != tp->protocol))) + ++tp; + + if (! tp->name[0]) + { + if (req->ai_socktype) + return -EAI_SOCKTYPE; + else + return -EAI_SERVICE; + } + } + + int port = 0; + if (service != NULL) + { + if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) + return -EAI_SERVICE; + + if (service->num < 0) + { + if (tp->name[0]) + { + st = (struct gaih_servtuple *) + alloca_account (sizeof (struct gaih_servtuple), alloca_used); + + if ((rc = gaih_inet_serv (service->name, tp, req, st, tmpbuf))) + return rc; + } + else + { + struct gaih_servtuple **pst = &st; + for (tp++; tp->name[0]; tp++) + { + struct gaih_servtuple *newp; + + if ((tp->protoflag & GAI_PROTO_NOSERVICE) != 0) + continue; + + if (req->ai_socktype != 0 + && req->ai_socktype != tp->socktype) + continue; + if (req->ai_protocol != 0 + && !(tp->protoflag & GAI_PROTO_PROTOANY) + && req->ai_protocol != tp->protocol) + continue; + + newp = (struct gaih_servtuple *) + alloca_account (sizeof (struct gaih_servtuple), + alloca_used); + + if ((rc = gaih_inet_serv (service->name, + tp, req, newp, tmpbuf))) + { + if (rc) + continue; + return rc; + } + + *pst = newp; + pst = &(newp->next); + } + if (st == (struct gaih_servtuple *) &nullserv) + return -EAI_SERVICE; + } + } + else + { + port = htons (service->num); + goto got_port; + } + } + else + { + got_port: + + if (req->ai_socktype || req->ai_protocol) + { + st = alloca_account (sizeof (struct gaih_servtuple), alloca_used); + st->next = NULL; + st->socktype = tp->socktype; + st->protocol = ((tp->protoflag & GAI_PROTO_PROTOANY) + ? req->ai_protocol : tp->protocol); + st->port = port; + } + else + { + /* Neither socket type nor protocol is set. Return all socket types + we know about. */ + struct gaih_servtuple **lastp = &st; + for (++tp; tp->name[0]; ++tp) + if (tp->defaultflag) + { + struct gaih_servtuple *newp; + + newp = alloca_account (sizeof (struct gaih_servtuple), + alloca_used); + newp->next = NULL; + newp->socktype = tp->socktype; + newp->protocol = tp->protocol; + newp->port = port; + + *lastp = newp; + lastp = &newp->next; + } + } + } + + bool malloc_name = false; + struct gaih_addrtuple *addrmem = NULL; + char *canonbuf = NULL; + int result = 0; + + if (name != NULL) + { + at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); + at->family = AF_UNSPEC; + at->scopeid = 0; + at->next = NULL; + +#ifdef HAVE_LIBIDN + if (req->ai_flags & AI_IDN) + { + int idn_flags = 0; + if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED) + idn_flags |= IDNA_ALLOW_UNASSIGNED; + if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES) + idn_flags |= IDNA_USE_STD3_ASCII_RULES; + + char *p = NULL; + rc = __idna_to_ascii_lz (name, &p, idn_flags); + if (rc != IDNA_SUCCESS) + { + /* No need to jump to free_and_return here. */ + if (rc == IDNA_MALLOC_ERROR) + return -EAI_MEMORY; + if (rc == IDNA_DLOPEN_ERROR) + return -EAI_SYSTEM; + return -EAI_IDN_ENCODE; + } + /* In case the output string is the same as the input string + no new string has been allocated. */ + if (p != name) + { + name = p; + malloc_name = true; + } + } +#endif + + if (__inet_aton (name, (struct in_addr *) at->addr) != 0) + { + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) + at->family = AF_INET; + else if (req->ai_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) + { + at->addr[3] = at->addr[0]; + at->addr[2] = htonl (0xffff); + at->addr[1] = 0; + at->addr[0] = 0; + at->family = AF_INET6; + } + else + { + result = -EAI_ADDRFAMILY; + goto free_and_return; + } + + if (req->ai_flags & AI_CANONNAME) + canon = name; + } + else if (at->family == AF_UNSPEC) + { + char *scope_delim = strchr (name, SCOPE_DELIMITER); + int e; + + { + bool malloc_namebuf = false; + char *namebuf = (char *) name; + + if (__glibc_unlikely (scope_delim != NULL)) + { + if (malloc_name) + *scope_delim = '\0'; + else + { + if (__libc_use_alloca (alloca_used + + scope_delim - name + 1)) + { + namebuf = alloca_account (scope_delim - name + 1, + alloca_used); + *((char *) __mempcpy (namebuf, name, + scope_delim - name)) = '\0'; + } + else + { + namebuf = __strndup (name, scope_delim - name); + if (namebuf == NULL) + { + assert (!malloc_name); + return -EAI_MEMORY; + } + malloc_namebuf = true; + } + } + } + + e = inet_pton (AF_INET6, namebuf, at->addr); + + if (malloc_namebuf) + free (namebuf); + else if (scope_delim != NULL && malloc_name) + /* Undo what we did above. */ + *scope_delim = SCOPE_DELIMITER; + } + if (e > 0) + { + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) + at->family = AF_INET6; + else if (req->ai_family == AF_INET + && IN6_IS_ADDR_V4MAPPED (at->addr)) + { + at->addr[0] = at->addr[3]; + at->family = AF_INET; + } + else + { + result = -EAI_ADDRFAMILY; + goto free_and_return; + } + + if (scope_delim != NULL + && __inet6_scopeid_pton ((struct in6_addr *) at->addr, + scope_delim + 1, + &at->scopeid) != 0) + { + result = -EAI_NONAME; + goto free_and_return; + } + + if (req->ai_flags & AI_CANONNAME) + canon = name; + } + } + + if (at->family == AF_UNSPEC && (req->ai_flags & AI_NUMERICHOST) == 0) + { + struct gaih_addrtuple **pat = &at; + int no_data = 0; + int no_inet6_data = 0; + service_user *nip; + enum nss_status inet6_status = NSS_STATUS_UNAVAIL; + enum nss_status status = NSS_STATUS_UNAVAIL; + int no_more; + int old_res_options; + + /* If we do not have to look for IPv6 addresses or the canonical + name, use the simple, old functions, which do not support + IPv6 scope ids, nor retrieving the canonical name. */ + if (req->ai_family == AF_INET + && (req->ai_flags & AI_CANONNAME) == 0) + { + int rc; + struct hostent th; + struct hostent *h; + int herrno; + + while (1) + { + rc = __gethostbyname2_r (name, AF_INET, &th, + tmpbuf->data, tmpbuf->length, + &h, &herrno); + if (rc != ERANGE || herrno != NETDB_INTERNAL) + break; + if (!scratch_buffer_grow (tmpbuf)) + { + result = -EAI_MEMORY; + goto free_and_return; + } + } + + if (rc == 0) + { + if (h != NULL) + { + /* We found data, convert it. */ + if (!convert_hostent_to_gaih_addrtuple + (req, AF_INET, h, &addrmem)) + { + result = -EAI_MEMORY; + goto free_and_return; + } + *pat = addrmem; + } + } + else + { + if (herrno == NETDB_INTERNAL) + { + __set_h_errno (herrno); + result = -EAI_SYSTEM; + } + else if (herrno == TRY_AGAIN) + result = -EAI_AGAIN; + else + /* We made requests but they turned out no data. + The name is known, though. */ + result = -EAI_NODATA; + + goto free_and_return; + } + + goto process_list; + } + +#ifdef USE_NSCD + if (__nss_not_use_nscd_hosts > 0 + && ++__nss_not_use_nscd_hosts > NSS_NSCD_RETRY) + __nss_not_use_nscd_hosts = 0; + + if (!__nss_not_use_nscd_hosts + && !__nss_database_custom[NSS_DBSIDX_hosts]) + { + /* Try to use nscd. */ + struct nscd_ai_result *air = NULL; + int herrno; + int err = __nscd_getai (name, &air, &herrno); + if (air != NULL) + { + /* Transform into gaih_addrtuple list. */ + bool added_canon = (req->ai_flags & AI_CANONNAME) == 0; + char *addrs = air->addrs; + + addrmem = calloc (air->naddrs, sizeof (*addrmem)); + if (addrmem == NULL) + { + result = -EAI_MEMORY; + goto free_and_return; + } + + struct gaih_addrtuple *addrfree = addrmem; + for (int i = 0; i < air->naddrs; ++i) + { + socklen_t size = (air->family[i] == AF_INET + ? INADDRSZ : IN6ADDRSZ); + + if (!((air->family[i] == AF_INET + && req->ai_family == AF_INET6 + && (req->ai_flags & AI_V4MAPPED) != 0) + || req->ai_family == AF_UNSPEC + || air->family[i] == req->ai_family)) + { + /* Skip over non-matching result. */ + addrs += size; + continue; + } + + if (*pat == NULL) + { + *pat = addrfree++; + (*pat)->scopeid = 0; + } + uint32_t *pataddr = (*pat)->addr; + (*pat)->next = NULL; + if (added_canon || air->canon == NULL) + (*pat)->name = NULL; + else if (canonbuf == NULL) + { + canonbuf = __strdup (air->canon); + if (canonbuf == NULL) + { + result = -EAI_MEMORY; + goto free_and_return; + } + canon = (*pat)->name = canonbuf; + } + + if (air->family[i] == AF_INET + && req->ai_family == AF_INET6 + && (req->ai_flags & AI_V4MAPPED)) + { + (*pat)->family = AF_INET6; + pataddr[3] = *(uint32_t *) addrs; + pataddr[2] = htonl (0xffff); + pataddr[1] = 0; + pataddr[0] = 0; + pat = &((*pat)->next); + added_canon = true; + } + else if (req->ai_family == AF_UNSPEC + || air->family[i] == req->ai_family) + { + (*pat)->family = air->family[i]; + memcpy (pataddr, addrs, size); + pat = &((*pat)->next); + added_canon = true; + if (air->family[i] == AF_INET6) + got_ipv6 = true; + } + addrs += size; + } + + free (air); + + if (at->family == AF_UNSPEC) + { + result = -EAI_NONAME; + goto free_and_return; + } + + goto process_list; + } + else if (err == 0) + /* The database contains a negative entry. */ + goto free_and_return; + else if (__nss_not_use_nscd_hosts == 0) + { + if (herrno == NETDB_INTERNAL && errno == ENOMEM) + result = -EAI_MEMORY; + else if (herrno == TRY_AGAIN) + result = -EAI_AGAIN; + else + result = -EAI_SYSTEM; + + goto free_and_return; + } + } +#endif + + if (__nss_hosts_database == NULL) + no_more = __nss_database_lookup ("hosts", NULL, + "dns [!UNAVAIL=return] files", + &__nss_hosts_database); + else + no_more = 0; + nip = __nss_hosts_database; + + /* Initialize configurations. */ + _res_hconf_init (); + if (__res_maybe_init (&_res, 0) == -1) + no_more = 1; + + /* If we are looking for both IPv4 and IPv6 address we don't + want the lookup functions to automatically promote IPv4 + addresses to IPv6 addresses. Currently this is decided + by setting the RES_USE_INET6 bit in _res.options. */ + old_res_options = _res.options; + _res.options &= ~DEPRECATED_RES_USE_INET6; + + while (!no_more) + { + no_data = 0; + nss_gethostbyname4_r fct4 = NULL; + + /* gethostbyname4_r sends out parallel A and AAAA queries and + is thus only suitable for PF_UNSPEC. */ + if (req->ai_family == PF_UNSPEC) + fct4 = __nss_lookup_function (nip, "gethostbyname4_r"); + + if (fct4 != NULL) + { + int herrno; + + while (1) + { + rc = 0; + status = DL_CALL_FCT (fct4, (name, pat, + tmpbuf->data, tmpbuf->length, + &rc, &herrno, + NULL)); + if (status == NSS_STATUS_SUCCESS) + break; + if (status != NSS_STATUS_TRYAGAIN + || rc != ERANGE || herrno != NETDB_INTERNAL) + { + if (herrno == TRY_AGAIN) + no_data = EAI_AGAIN; + else + no_data = herrno == NO_DATA; + break; + } + + if (!scratch_buffer_grow (tmpbuf)) + { + _res.options + |= old_res_options & DEPRECATED_RES_USE_INET6; + result = -EAI_MEMORY; + goto free_and_return; + } + } + + if (status == NSS_STATUS_SUCCESS) + { + assert (!no_data); + no_data = 1; + + if ((req->ai_flags & AI_CANONNAME) != 0 && canon == NULL) + canon = (*pat)->name; + + while (*pat != NULL) + { + if ((*pat)->family == AF_INET + && req->ai_family == AF_INET6 + && (req->ai_flags & AI_V4MAPPED) != 0) + { + uint32_t *pataddr = (*pat)->addr; + (*pat)->family = AF_INET6; + pataddr[3] = pataddr[0]; + pataddr[2] = htonl (0xffff); + pataddr[1] = 0; + pataddr[0] = 0; + pat = &((*pat)->next); + no_data = 0; + } + else if (req->ai_family == AF_UNSPEC + || (*pat)->family == req->ai_family) + { + pat = &((*pat)->next); + + no_data = 0; + if (req->ai_family == AF_INET6) + got_ipv6 = true; + } + else + *pat = ((*pat)->next); + } + } + + no_inet6_data = no_data; + } + else + { + nss_gethostbyname3_r fct = NULL; + if (req->ai_flags & AI_CANONNAME) + /* No need to use this function if we do not look for + the canonical name. The function does not exist in + all NSS modules and therefore the lookup would + often fail. */ + fct = __nss_lookup_function (nip, "gethostbyname3_r"); + if (fct == NULL) + /* We are cheating here. The gethostbyname2_r + function does not have the same interface as + gethostbyname3_r but the extra arguments the + latter takes are added at the end. So the + gethostbyname2_r code will just ignore them. */ + fct = __nss_lookup_function (nip, "gethostbyname2_r"); + + if (fct != NULL) + { + if (req->ai_family == AF_INET6 + || req->ai_family == AF_UNSPEC) + { + gethosts (AF_INET6, struct in6_addr); + no_inet6_data = no_data; + inet6_status = status; + } + if (req->ai_family == AF_INET + || req->ai_family == AF_UNSPEC + || (req->ai_family == AF_INET6 + && (req->ai_flags & AI_V4MAPPED) + /* Avoid generating the mapped addresses if we + know we are not going to need them. */ + && ((req->ai_flags & AI_ALL) || !got_ipv6))) + { + gethosts (AF_INET, struct in_addr); + + if (req->ai_family == AF_INET) + { + no_inet6_data = no_data; + inet6_status = status; + } + } + + /* If we found one address for AF_INET or AF_INET6, + don't continue the search. */ + if (inet6_status == NSS_STATUS_SUCCESS + || status == NSS_STATUS_SUCCESS) + { + if ((req->ai_flags & AI_CANONNAME) != 0 + && canon == NULL) + { + canonbuf = getcanonname (nip, at, name); + if (canonbuf == NULL) + { + _res.options + |= old_res_options + & DEPRECATED_RES_USE_INET6; + result = -EAI_MEMORY; + goto free_and_return; + } + canon = canonbuf; + } + status = NSS_STATUS_SUCCESS; + } + else + { + /* We can have different states for AF_INET and + AF_INET6. Try to find a useful one for both. */ + if (inet6_status == NSS_STATUS_TRYAGAIN) + status = NSS_STATUS_TRYAGAIN; + else if (status == NSS_STATUS_UNAVAIL + && inet6_status != NSS_STATUS_UNAVAIL) + status = inet6_status; + } + } + else + { + status = NSS_STATUS_UNAVAIL; + /* Could not load any of the lookup functions. Indicate + an internal error if the failure was due to a system + error other than the file not being found. We use the + errno from the last failed callback. */ + if (errno != 0 && errno != ENOENT) + __set_h_errno (NETDB_INTERNAL); + } + } + + if (nss_next_action (nip, status) == NSS_ACTION_RETURN) + break; + + if (nip->next == NULL) + no_more = -1; + else + nip = nip->next; + } + + _res.options |= old_res_options & DEPRECATED_RES_USE_INET6; + + if (h_errno == NETDB_INTERNAL) + { + result = -EAI_SYSTEM; + goto free_and_return; + } + + if (no_data != 0 && no_inet6_data != 0) + { + /* If both requests timed out report this. */ + if (no_data == EAI_AGAIN && no_inet6_data == EAI_AGAIN) + result = -EAI_AGAIN; + else + /* We made requests but they turned out no data. The name + is known, though. */ + result = -EAI_NODATA; + + goto free_and_return; + } + } + + process_list: + if (at->family == AF_UNSPEC) + { + result = -EAI_NONAME; + goto free_and_return; + } + } + else + { + struct gaih_addrtuple *atr; + atr = at = alloca_account (sizeof (struct gaih_addrtuple), alloca_used); + memset (at, '\0', sizeof (struct gaih_addrtuple)); + + if (req->ai_family == AF_UNSPEC) + { + at->next = __alloca (sizeof (struct gaih_addrtuple)); + memset (at->next, '\0', sizeof (struct gaih_addrtuple)); + } + + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) + { + at->family = AF_INET6; + if ((req->ai_flags & AI_PASSIVE) == 0) + memcpy (at->addr, &in6addr_loopback, sizeof (struct in6_addr)); + atr = at->next; + } + + if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) + { + atr->family = AF_INET; + if ((req->ai_flags & AI_PASSIVE) == 0) + atr->addr[0] = htonl (INADDR_LOOPBACK); + } + } + + { + struct gaih_servtuple *st2; + struct gaih_addrtuple *at2 = at; + size_t socklen; + sa_family_t family; + + /* + buffer is the size of an unformatted IPv6 address in printable format. + */ + while (at2 != NULL) + { + /* Only the first entry gets the canonical name. */ + if (at2 == at && (req->ai_flags & AI_CANONNAME) != 0) + { + if (canon == NULL) + /* If the canonical name cannot be determined, use + the passed in string. */ + canon = orig_name; + +#ifdef HAVE_LIBIDN + if (req->ai_flags & AI_CANONIDN) + { + int idn_flags = 0; + if (req->ai_flags & AI_IDN_ALLOW_UNASSIGNED) + idn_flags |= IDNA_ALLOW_UNASSIGNED; + if (req->ai_flags & AI_IDN_USE_STD3_ASCII_RULES) + idn_flags |= IDNA_USE_STD3_ASCII_RULES; + + char *out; + int rc = __idna_to_unicode_lzlz (canon, &out, idn_flags); + if (rc != IDNA_SUCCESS) + { + if (rc == IDNA_MALLOC_ERROR) + result = -EAI_MEMORY; + else if (rc == IDNA_DLOPEN_ERROR) + result = -EAI_SYSTEM; + else + result = -EAI_IDN_ENCODE; + goto free_and_return; + } + /* In case the output string is the same as the input + string no new string has been allocated and we + make a copy. */ + if (out == canon) + goto make_copy; + canon = out; + } + else +#endif + { +#ifdef HAVE_LIBIDN + make_copy: +#endif + if (canonbuf != NULL) + /* We already allocated the string using malloc, but + the buffer is now owned by canon. */ + canonbuf = NULL; + else + { + canon = __strdup (canon); + if (canon == NULL) + { + result = -EAI_MEMORY; + goto free_and_return; + } + } + } + } + + family = at2->family; + if (family == AF_INET6) + { + socklen = sizeof (struct sockaddr_in6); + + /* If we looked up IPv4 mapped address discard them here if + the caller isn't interested in all address and we have + found at least one IPv6 address. */ + if (got_ipv6 + && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED + && IN6_IS_ADDR_V4MAPPED (at2->addr)) + goto ignore; + } + else + socklen = sizeof (struct sockaddr_in); + + for (st2 = st; st2 != NULL; st2 = st2->next) + { + struct addrinfo *ai; + ai = *pai = malloc (sizeof (struct addrinfo) + socklen); + if (ai == NULL) + { + free ((char *) canon); + result = -EAI_MEMORY; + goto free_and_return; + } + + ai->ai_flags = req->ai_flags; + ai->ai_family = family; + ai->ai_socktype = st2->socktype; + ai->ai_protocol = st2->protocol; + ai->ai_addrlen = socklen; + ai->ai_addr = (void *) (ai + 1); + + /* We only add the canonical name once. */ + ai->ai_canonname = (char *) canon; + canon = NULL; + +#ifdef _HAVE_SA_LEN + ai->ai_addr->sa_len = socklen; +#endif /* _HAVE_SA_LEN */ + ai->ai_addr->sa_family = family; + + /* In case of an allocation error the list must be NULL + terminated. */ + ai->ai_next = NULL; + + if (family == AF_INET6) + { + struct sockaddr_in6 *sin6p = + (struct sockaddr_in6 *) ai->ai_addr; + + sin6p->sin6_port = st2->port; + sin6p->sin6_flowinfo = 0; + memcpy (&sin6p->sin6_addr, + at2->addr, sizeof (struct in6_addr)); + sin6p->sin6_scope_id = at2->scopeid; + } + else + { + struct sockaddr_in *sinp = + (struct sockaddr_in *) ai->ai_addr; + sinp->sin_port = st2->port; + memcpy (&sinp->sin_addr, + at2->addr, sizeof (struct in_addr)); + memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero)); + } + + pai = &(ai->ai_next); + } + + ++*naddrs; + + ignore: + at2 = at2->next; + } + } + + free_and_return: + if (malloc_name) + free ((char *) name); + free (addrmem); + free (canonbuf); + + return result; +} + + +struct sort_result +{ + struct addrinfo *dest_addr; + /* Using sockaddr_storage is for now overkill. We only support IPv4 + and IPv6 so far. If this changes at some point we can adjust the + type here. */ + struct sockaddr_in6 source_addr; + uint8_t source_addr_len; + bool got_source_addr; + uint8_t source_addr_flags; + uint8_t prefixlen; + uint32_t index; + int32_t native; +}; + +struct sort_result_combo +{ + struct sort_result *results; + int nresults; +}; + + +#if __BYTE_ORDER == __BIG_ENDIAN +# define htonl_c(n) n +#else +# define htonl_c(n) __bswap_constant_32 (n) +#endif + +static const struct scopeentry +{ + union + { + char addr[4]; + uint32_t addr32; + }; + uint32_t netmask; + int32_t scope; +} default_scopes[] = + { + /* Link-local addresses: scope 2. */ + { { { 169, 254, 0, 0 } }, htonl_c (0xffff0000), 2 }, + { { { 127, 0, 0, 0 } }, htonl_c (0xff000000), 2 }, + /* Default: scope 14. */ + { { { 0, 0, 0, 0 } }, htonl_c (0x00000000), 14 } + }; + +/* The label table. */ +static const struct scopeentry *scopes; + + +static int +get_scope (const struct sockaddr_in6 *in6) +{ + int scope; + if (in6->sin6_family == PF_INET6) + { + if (! IN6_IS_ADDR_MULTICAST (&in6->sin6_addr)) + { + if (IN6_IS_ADDR_LINKLOCAL (&in6->sin6_addr) + /* RFC 4291 2.5.3 says that the loopback address is to be + treated like a link-local address. */ + || IN6_IS_ADDR_LOOPBACK (&in6->sin6_addr)) + scope = 2; + else if (IN6_IS_ADDR_SITELOCAL (&in6->sin6_addr)) + scope = 5; + else + /* XXX Is this the correct default behavior? */ + scope = 14; + } + else + scope = in6->sin6_addr.s6_addr[1] & 0xf; + } + else if (in6->sin6_family == PF_INET) + { + const struct sockaddr_in *in = (const struct sockaddr_in *) in6; + + size_t cnt = 0; + while (1) + { + if ((in->sin_addr.s_addr & scopes[cnt].netmask) + == scopes[cnt].addr32) + return scopes[cnt].scope; + + ++cnt; + } + /* NOTREACHED */ + } + else + /* XXX What is a good default? */ + scope = 15; + + return scope; +} + + +struct prefixentry +{ + struct in6_addr prefix; + unsigned int bits; + int val; +}; + + +/* The label table. */ +static const struct prefixentry *labels; + +/* Default labels. */ +static const struct prefixentry default_labels[] = + { + /* See RFC 3484 for the details. */ + { { .__in6_u + = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } + }, 128, 0 }, + { { .__in6_u + = { .__u6_addr8 = { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } + }, 16, 2 }, + { { .__in6_u + = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } + }, 96, 3 }, + { { .__in6_u + = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } + }, 96, 4 }, + /* The next two entries differ from RFC 3484. We need to treat + IPv6 site-local addresses special because they are never NATed, + unlike site-locale IPv4 addresses. If this would not happen, on + machines which have only IPv4 and IPv6 site-local addresses, the + sorting would prefer the IPv6 site-local addresses, causing + unnecessary delays when trying to connect to a global IPv6 address + through a site-local IPv6 address. */ + { { .__in6_u + = { .__u6_addr8 = { 0xfe, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } + }, 10, 5 }, + { { .__in6_u + = { .__u6_addr8 = { 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } + }, 7, 6 }, + /* Additional rule for Teredo tunnels. */ + { { .__in6_u + = { .__u6_addr8 = { 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } + }, 32, 7 }, + { { .__in6_u + = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } + }, 0, 1 } + }; + + +/* The precedence table. */ +static const struct prefixentry *precedence; + +/* The default precedences. */ +static const struct prefixentry default_precedence[] = + { + /* See RFC 3484 for the details. */ + { { .__in6_u + = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } } + }, 128, 50 }, + { { .__in6_u + = { .__u6_addr8 = { 0x20, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } + }, 16, 30 }, + { { .__in6_u + = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } + }, 96, 20 }, + { { .__in6_u + = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 } } + }, 96, 10 }, + { { .__in6_u + = { .__u6_addr8 = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } } + }, 0, 40 } + }; + + +static int +match_prefix (const struct sockaddr_in6 *in6, + const struct prefixentry *list, int default_val) +{ + int idx; + struct sockaddr_in6 in6_mem; + + if (in6->sin6_family == PF_INET) + { + const struct sockaddr_in *in = (const struct sockaddr_in *) in6; + + /* Construct a V4-to-6 mapped address. */ + in6_mem.sin6_family = PF_INET6; + in6_mem.sin6_port = in->sin_port; + in6_mem.sin6_flowinfo = 0; + memset (&in6_mem.sin6_addr, '\0', sizeof (in6_mem.sin6_addr)); + in6_mem.sin6_addr.s6_addr16[5] = 0xffff; + in6_mem.sin6_addr.s6_addr32[3] = in->sin_addr.s_addr; + in6_mem.sin6_scope_id = 0; + + in6 = &in6_mem; + } + else if (in6->sin6_family != PF_INET6) + return default_val; + + for (idx = 0; ; ++idx) + { + unsigned int bits = list[idx].bits; + const uint8_t *mask = list[idx].prefix.s6_addr; + const uint8_t *val = in6->sin6_addr.s6_addr; + + while (bits >= 8) + { + if (*mask != *val) + break; + + ++mask; + ++val; + bits -= 8; + } + + if (bits < 8) + { + if ((*mask & (0xff00 >> bits)) == (*val & (0xff00 >> bits))) + /* Match! */ + break; + } + } + + return list[idx].val; +} + + +static int +get_label (const struct sockaddr_in6 *in6) +{ + /* XXX What is a good default value? */ + return match_prefix (in6, labels, INT_MAX); +} + + +static int +get_precedence (const struct sockaddr_in6 *in6) +{ + /* XXX What is a good default value? */ + return match_prefix (in6, precedence, 0); +} + + +/* Find last bit set in a word. */ +static int +fls (uint32_t a) +{ + uint32_t mask; + int n; + for (n = 0, mask = 1 << 31; n < 32; mask >>= 1, ++n) + if ((a & mask) != 0) + break; + return n; +} + + +static int +rfc3484_sort (const void *p1, const void *p2, void *arg) +{ + const size_t idx1 = *(const size_t *) p1; + const size_t idx2 = *(const size_t *) p2; + struct sort_result_combo *src = (struct sort_result_combo *) arg; + struct sort_result *a1 = &src->results[idx1]; + struct sort_result *a2 = &src->results[idx2]; + + /* Rule 1: Avoid unusable destinations. + We have the got_source_addr flag set if the destination is reachable. */ + if (a1->got_source_addr && ! a2->got_source_addr) + return -1; + if (! a1->got_source_addr && a2->got_source_addr) + return 1; + + + /* Rule 2: Prefer matching scope. Only interesting if both + destination addresses are IPv6. */ + int a1_dst_scope + = get_scope ((struct sockaddr_in6 *) a1->dest_addr->ai_addr); + + int a2_dst_scope + = get_scope ((struct sockaddr_in6 *) a2->dest_addr->ai_addr); + + if (a1->got_source_addr) + { + int a1_src_scope = get_scope (&a1->source_addr); + int a2_src_scope = get_scope (&a2->source_addr); + + if (a1_dst_scope == a1_src_scope && a2_dst_scope != a2_src_scope) + return -1; + if (a1_dst_scope != a1_src_scope && a2_dst_scope == a2_src_scope) + return 1; + } + + + /* Rule 3: Avoid deprecated addresses. */ + if (a1->got_source_addr) + { + if (!(a1->source_addr_flags & in6ai_deprecated) + && (a2->source_addr_flags & in6ai_deprecated)) + return -1; + if ((a1->source_addr_flags & in6ai_deprecated) + && !(a2->source_addr_flags & in6ai_deprecated)) + return 1; + } + + /* Rule 4: Prefer home addresses. */ + if (a1->got_source_addr) + { + if (!(a1->source_addr_flags & in6ai_homeaddress) + && (a2->source_addr_flags & in6ai_homeaddress)) + return 1; + if ((a1->source_addr_flags & in6ai_homeaddress) + && !(a2->source_addr_flags & in6ai_homeaddress)) + return -1; + } + + /* Rule 5: Prefer matching label. */ + if (a1->got_source_addr) + { + int a1_dst_label + = get_label ((struct sockaddr_in6 *) a1->dest_addr->ai_addr); + int a1_src_label = get_label (&a1->source_addr); + + int a2_dst_label + = get_label ((struct sockaddr_in6 *) a2->dest_addr->ai_addr); + int a2_src_label = get_label (&a2->source_addr); + + if (a1_dst_label == a1_src_label && a2_dst_label != a2_src_label) + return -1; + if (a1_dst_label != a1_src_label && a2_dst_label == a2_src_label) + return 1; + } + + + /* Rule 6: Prefer higher precedence. */ + int a1_prec + = get_precedence ((struct sockaddr_in6 *) a1->dest_addr->ai_addr); + int a2_prec + = get_precedence ((struct sockaddr_in6 *) a2->dest_addr->ai_addr); + + if (a1_prec > a2_prec) + return -1; + if (a1_prec < a2_prec) + return 1; + + + /* Rule 7: Prefer native transport. */ + if (a1->got_source_addr) + { + /* The same interface index means the same interface which means + there is no difference in transport. This should catch many + (most?) cases. */ + if (a1->index != a2->index) + { + int a1_native = a1->native; + int a2_native = a2->native; + + if (a1_native == -1 || a2_native == -1) + { + uint32_t a1_index; + if (a1_native == -1) + { + /* If we do not have the information use 'native' as + the default. */ + a1_native = 0; + a1_index = a1->index; + } + else + a1_index = 0xffffffffu; + + uint32_t a2_index; + if (a2_native == -1) + { + /* If we do not have the information use 'native' as + the default. */ + a2_native = 0; + a2_index = a2->index; + } + else + a2_index = 0xffffffffu; + + __check_native (a1_index, &a1_native, a2_index, &a2_native); + + /* Fill in the results in all the records. */ + for (int i = 0; i < src->nresults; ++i) + if (a1_index != -1 && src->results[i].index == a1_index) + { + assert (src->results[i].native == -1 + || src->results[i].native == a1_native); + src->results[i].native = a1_native; + } + else if (a2_index != -1 && src->results[i].index == a2_index) + { + assert (src->results[i].native == -1 + || src->results[i].native == a2_native); + src->results[i].native = a2_native; + } + } + + if (a1_native && !a2_native) + return -1; + if (!a1_native && a2_native) + return 1; + } + } + + + /* Rule 8: Prefer smaller scope. */ + if (a1_dst_scope < a2_dst_scope) + return -1; + if (a1_dst_scope > a2_dst_scope) + return 1; + + + /* Rule 9: Use longest matching prefix. */ + if (a1->got_source_addr + && a1->dest_addr->ai_family == a2->dest_addr->ai_family) + { + int bit1 = 0; + int bit2 = 0; + + if (a1->dest_addr->ai_family == PF_INET) + { + assert (a1->source_addr.sin6_family == PF_INET); + assert (a2->source_addr.sin6_family == PF_INET); + + /* Outside of subnets, as defined by the network masks, + common address prefixes for IPv4 addresses make no sense. + So, define a non-zero value only if source and + destination address are on the same subnet. */ + struct sockaddr_in *in1_dst + = (struct sockaddr_in *) a1->dest_addr->ai_addr; + in_addr_t in1_dst_addr = ntohl (in1_dst->sin_addr.s_addr); + struct sockaddr_in *in1_src + = (struct sockaddr_in *) &a1->source_addr; + in_addr_t in1_src_addr = ntohl (in1_src->sin_addr.s_addr); + in_addr_t netmask1 = 0xffffffffu << (32 - a1->prefixlen); + + if ((in1_src_addr & netmask1) == (in1_dst_addr & netmask1)) + bit1 = fls (in1_dst_addr ^ in1_src_addr); + + struct sockaddr_in *in2_dst + = (struct sockaddr_in *) a2->dest_addr->ai_addr; + in_addr_t in2_dst_addr = ntohl (in2_dst->sin_addr.s_addr); + struct sockaddr_in *in2_src + = (struct sockaddr_in *) &a2->source_addr; + in_addr_t in2_src_addr = ntohl (in2_src->sin_addr.s_addr); + in_addr_t netmask2 = 0xffffffffu << (32 - a2->prefixlen); + + if ((in2_src_addr & netmask2) == (in2_dst_addr & netmask2)) + bit2 = fls (in2_dst_addr ^ in2_src_addr); + } + else if (a1->dest_addr->ai_family == PF_INET6) + { + assert (a1->source_addr.sin6_family == PF_INET6); + assert (a2->source_addr.sin6_family == PF_INET6); + + struct sockaddr_in6 *in1_dst; + struct sockaddr_in6 *in1_src; + struct sockaddr_in6 *in2_dst; + struct sockaddr_in6 *in2_src; + + in1_dst = (struct sockaddr_in6 *) a1->dest_addr->ai_addr; + in1_src = (struct sockaddr_in6 *) &a1->source_addr; + in2_dst = (struct sockaddr_in6 *) a2->dest_addr->ai_addr; + in2_src = (struct sockaddr_in6 *) &a2->source_addr; + + int i; + for (i = 0; i < 4; ++i) + if (in1_dst->sin6_addr.s6_addr32[i] + != in1_src->sin6_addr.s6_addr32[i] + || (in2_dst->sin6_addr.s6_addr32[i] + != in2_src->sin6_addr.s6_addr32[i])) + break; + + if (i < 4) + { + bit1 = fls (ntohl (in1_dst->sin6_addr.s6_addr32[i] + ^ in1_src->sin6_addr.s6_addr32[i])); + bit2 = fls (ntohl (in2_dst->sin6_addr.s6_addr32[i] + ^ in2_src->sin6_addr.s6_addr32[i])); + } + } + + if (bit1 > bit2) + return -1; + if (bit1 < bit2) + return 1; + } + + + /* Rule 10: Otherwise, leave the order unchanged. To ensure this + compare with the value indicating the order in which the entries + have been received from the services. NB: no two entries can have + the same order so the test will never return zero. */ + return idx1 < idx2 ? -1 : 1; +} + + +static int +in6aicmp (const void *p1, const void *p2) +{ + struct in6addrinfo *a1 = (struct in6addrinfo *) p1; + struct in6addrinfo *a2 = (struct in6addrinfo *) p2; + + return memcmp (a1->addr, a2->addr, sizeof (a1->addr)); +} + + +/* Name of the config file for RFC 3484 sorting (for now). */ +#define GAICONF_FNAME "/etc/gai.conf" + + +/* Non-zero if we are supposed to reload the config file automatically + whenever it changed. */ +static int gaiconf_reload_flag; + +/* Non-zero if gaiconf_reload_flag was ever set to true. */ +static int gaiconf_reload_flag_ever_set; + +/* Last modification time. */ +#ifdef _STATBUF_ST_NSEC + +static struct timespec gaiconf_mtime; + +static inline void +save_gaiconf_mtime (const struct stat64 *st) +{ + gaiconf_mtime = st->st_mtim; +} + +static inline bool +check_gaiconf_mtime (const struct stat64 *st) +{ + return (st->st_mtim.tv_sec == gaiconf_mtime.tv_sec + && st->st_mtim.tv_nsec == gaiconf_mtime.tv_nsec); +} + +#else + +static time_t gaiconf_mtime; + +static inline void +save_gaiconf_mtime (const struct stat64 *st) +{ + gaiconf_mtime = st->st_mtime; +} + +static inline bool +check_gaiconf_mtime (const struct stat64 *st) +{ + return st->st_mtime == gaiconf_mtime; +} + +#endif + + +libc_freeres_fn(fini) +{ + if (labels != default_labels) + { + const struct prefixentry *old = labels; + labels = default_labels; + free ((void *) old); + } + + if (precedence != default_precedence) + { + const struct prefixentry *old = precedence; + precedence = default_precedence; + free ((void *) old); + } + + if (scopes != default_scopes) + { + const struct scopeentry *old = scopes; + scopes = default_scopes; + free ((void *) old); + } +} + + +struct prefixlist +{ + struct prefixentry entry; + struct prefixlist *next; +}; + + +struct scopelist +{ + struct scopeentry entry; + struct scopelist *next; +}; + + +static void +free_prefixlist (struct prefixlist *list) +{ + while (list != NULL) + { + struct prefixlist *oldp = list; + list = list->next; + free (oldp); + } +} + + +static void +free_scopelist (struct scopelist *list) +{ + while (list != NULL) + { + struct scopelist *oldp = list; + list = list->next; + free (oldp); + } +} + + +static int +prefixcmp (const void *p1, const void *p2) +{ + const struct prefixentry *e1 = (const struct prefixentry *) p1; + const struct prefixentry *e2 = (const struct prefixentry *) p2; + + if (e1->bits < e2->bits) + return 1; + if (e1->bits == e2->bits) + return 0; + return -1; +} + + +static int +scopecmp (const void *p1, const void *p2) +{ + const struct scopeentry *e1 = (const struct scopeentry *) p1; + const struct scopeentry *e2 = (const struct scopeentry *) p2; + + if (e1->netmask > e2->netmask) + return -1; + if (e1->netmask == e2->netmask) + return 0; + return 1; +} + + +static void +gaiconf_init (void) +{ + struct prefixlist *labellist = NULL; + size_t nlabellist = 0; + bool labellist_nullbits = false; + struct prefixlist *precedencelist = NULL; + size_t nprecedencelist = 0; + bool precedencelist_nullbits = false; + struct scopelist *scopelist = NULL; + size_t nscopelist = 0; + bool scopelist_nullbits = false; + + FILE *fp = fopen (GAICONF_FNAME, "rce"); + if (fp != NULL) + { + struct stat64 st; + if (__fxstat64 (_STAT_VER, fileno (fp), &st) != 0) + { + fclose (fp); + goto no_file; + } + + char *line = NULL; + size_t linelen = 0; + + __fsetlocking (fp, FSETLOCKING_BYCALLER); + + while (!feof_unlocked (fp)) + { + ssize_t n = __getline (&line, &linelen, fp); + if (n <= 0) + break; + + /* Handle comments. No escaping possible so this is easy. */ + char *cp = strchr (line, '#'); + if (cp != NULL) + *cp = '\0'; + + cp = line; + while (isspace (*cp)) + ++cp; + + char *cmd = cp; + while (*cp != '\0' && !isspace (*cp)) + ++cp; + size_t cmdlen = cp - cmd; + + if (*cp != '\0') + *cp++ = '\0'; + while (isspace (*cp)) + ++cp; + + char *val1 = cp; + while (*cp != '\0' && !isspace (*cp)) + ++cp; + size_t val1len = cp - cmd; + + /* We always need at least two values. */ + if (val1len == 0) + continue; + + if (*cp != '\0') + *cp++ = '\0'; + while (isspace (*cp)) + ++cp; + + char *val2 = cp; + while (*cp != '\0' && !isspace (*cp)) + ++cp; + + /* Ignore the rest of the line. */ + *cp = '\0'; + + struct prefixlist **listp; + size_t *lenp; + bool *nullbitsp; + switch (cmdlen) + { + case 5: + if (strcmp (cmd, "label") == 0) + { + struct in6_addr prefix; + unsigned long int bits; + unsigned long int val; + char *endp; + + listp = &labellist; + lenp = &nlabellist; + nullbitsp = &labellist_nullbits; + + new_elem: + bits = 128; + __set_errno (0); + cp = strchr (val1, '/'); + if (cp != NULL) + *cp++ = '\0'; + if (inet_pton (AF_INET6, val1, &prefix) + && (cp == NULL + || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX + || errno != ERANGE) + && *endp == '\0' + && bits <= 128 + && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX + || errno != ERANGE) + && *endp == '\0' + && val <= INT_MAX) + { + struct prefixlist *newp = malloc (sizeof (*newp)); + if (newp == NULL) + { + free (line); + fclose (fp); + goto no_file; + } + + memcpy (&newp->entry.prefix, &prefix, sizeof (prefix)); + newp->entry.bits = bits; + newp->entry.val = val; + newp->next = *listp; + *listp = newp; + ++*lenp; + *nullbitsp |= bits == 0; + } + } + break; + + case 6: + if (strcmp (cmd, "reload") == 0) + { + gaiconf_reload_flag = strcmp (val1, "yes") == 0; + if (gaiconf_reload_flag) + gaiconf_reload_flag_ever_set = 1; + } + break; + + case 7: + if (strcmp (cmd, "scopev4") == 0) + { + struct in6_addr prefix; + unsigned long int bits; + unsigned long int val; + char *endp; + + bits = 32; + __set_errno (0); + cp = strchr (val1, '/'); + if (cp != NULL) + *cp++ = '\0'; + if (inet_pton (AF_INET6, val1, &prefix)) + { + bits = 128; + if (IN6_IS_ADDR_V4MAPPED (&prefix) + && (cp == NULL + || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX + || errno != ERANGE) + && *endp == '\0' + && bits >= 96 + && bits <= 128 + && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX + || errno != ERANGE) + && *endp == '\0' + && val <= INT_MAX) + { + struct scopelist *newp; + new_scope: + newp = malloc (sizeof (*newp)); + if (newp == NULL) + { + free (line); + fclose (fp); + goto no_file; + } + + newp->entry.netmask = htonl (bits != 96 + ? (0xffffffff + << (128 - bits)) + : 0); + newp->entry.addr32 = (prefix.s6_addr32[3] + & newp->entry.netmask); + newp->entry.scope = val; + newp->next = scopelist; + scopelist = newp; + ++nscopelist; + scopelist_nullbits |= bits == 96; + } + } + else if (inet_pton (AF_INET, val1, &prefix.s6_addr32[3]) + && (cp == NULL + || (bits = strtoul (cp, &endp, 10)) != ULONG_MAX + || errno != ERANGE) + && *endp == '\0' + && bits <= 32 + && ((val = strtoul (val2, &endp, 10)) != ULONG_MAX + || errno != ERANGE) + && *endp == '\0' + && val <= INT_MAX) + { + bits += 96; + goto new_scope; + } + } + break; + + case 10: + if (strcmp (cmd, "precedence") == 0) + { + listp = &precedencelist; + lenp = &nprecedencelist; + nullbitsp = &precedencelist_nullbits; + goto new_elem; + } + break; + } + } + + free (line); + + fclose (fp); + + /* Create the array for the labels. */ + struct prefixentry *new_labels; + if (nlabellist > 0) + { + if (!labellist_nullbits) + ++nlabellist; + new_labels = malloc (nlabellist * sizeof (*new_labels)); + if (new_labels == NULL) + goto no_file; + + int i = nlabellist; + if (!labellist_nullbits) + { + --i; + memset (&new_labels[i].prefix, '\0', sizeof (struct in6_addr)); + new_labels[i].bits = 0; + new_labels[i].val = 1; + } + + struct prefixlist *l = labellist; + while (i-- > 0) + { + new_labels[i] = l->entry; + l = l->next; + } + free_prefixlist (labellist); + + /* Sort the entries so that the most specific ones are at + the beginning. */ + qsort (new_labels, nlabellist, sizeof (*new_labels), prefixcmp); + } + else + new_labels = (struct prefixentry *) default_labels; + + struct prefixentry *new_precedence; + if (nprecedencelist > 0) + { + if (!precedencelist_nullbits) + ++nprecedencelist; + new_precedence = malloc (nprecedencelist * sizeof (*new_precedence)); + if (new_precedence == NULL) + { + if (new_labels != default_labels) + free (new_labels); + goto no_file; + } + + int i = nprecedencelist; + if (!precedencelist_nullbits) + { + --i; + memset (&new_precedence[i].prefix, '\0', + sizeof (struct in6_addr)); + new_precedence[i].bits = 0; + new_precedence[i].val = 40; + } + + struct prefixlist *l = precedencelist; + while (i-- > 0) + { + new_precedence[i] = l->entry; + l = l->next; + } + free_prefixlist (precedencelist); + + /* Sort the entries so that the most specific ones are at + the beginning. */ + qsort (new_precedence, nprecedencelist, sizeof (*new_precedence), + prefixcmp); + } + else + new_precedence = (struct prefixentry *) default_precedence; + + struct scopeentry *new_scopes; + if (nscopelist > 0) + { + if (!scopelist_nullbits) + ++nscopelist; + new_scopes = malloc (nscopelist * sizeof (*new_scopes)); + if (new_scopes == NULL) + { + if (new_labels != default_labels) + free (new_labels); + if (new_precedence != default_precedence) + free (new_precedence); + goto no_file; + } + + int i = nscopelist; + if (!scopelist_nullbits) + { + --i; + new_scopes[i].addr32 = 0; + new_scopes[i].netmask = 0; + new_scopes[i].scope = 14; + } + + struct scopelist *l = scopelist; + while (i-- > 0) + { + new_scopes[i] = l->entry; + l = l->next; + } + free_scopelist (scopelist); + + /* Sort the entries so that the most specific ones are at + the beginning. */ + qsort (new_scopes, nscopelist, sizeof (*new_scopes), + scopecmp); + } + else + new_scopes = (struct scopeentry *) default_scopes; + + /* Now we are ready to replace the values. */ + const struct prefixentry *old = labels; + labels = new_labels; + if (old != default_labels) + free ((void *) old); + + old = precedence; + precedence = new_precedence; + if (old != default_precedence) + free ((void *) old); + + const struct scopeentry *oldscope = scopes; + scopes = new_scopes; + if (oldscope != default_scopes) + free ((void *) oldscope); + + save_gaiconf_mtime (&st); + } + else + { + no_file: + free_prefixlist (labellist); + free_prefixlist (precedencelist); + free_scopelist (scopelist); + + /* If we previously read the file but it is gone now, free the + old data and use the builtin one. Leave the reload flag + alone. */ + fini (); + } +} + + +static void +gaiconf_reload (void) +{ + struct stat64 st; + if (__xstat64 (_STAT_VER, GAICONF_FNAME, &st) != 0 + || !check_gaiconf_mtime (&st)) + gaiconf_init (); +} + + +int +getaddrinfo (const char *name, const char *service, + const struct addrinfo *hints, struct addrinfo **pai) +{ + int i = 0, last_i = 0; + int nresults = 0; + struct addrinfo *p = NULL; + struct gaih_service gaih_service, *pservice; + struct addrinfo local_hints; + + if (name != NULL && name[0] == '*' && name[1] == 0) + name = NULL; + + if (service != NULL && service[0] == '*' && service[1] == 0) + service = NULL; + + if (name == NULL && service == NULL) + return EAI_NONAME; + + if (hints == NULL) + hints = &default_hints; + + if (hints->ai_flags + & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED +#ifdef HAVE_LIBIDN + |AI_IDN|AI_CANONIDN|AI_IDN_ALLOW_UNASSIGNED + |AI_IDN_USE_STD3_ASCII_RULES +#endif + |AI_NUMERICSERV|AI_ALL)) + return EAI_BADFLAGS; + + if ((hints->ai_flags & AI_CANONNAME) && name == NULL) + return EAI_BADFLAGS; + + struct in6addrinfo *in6ai = NULL; + size_t in6ailen = 0; + bool seen_ipv4 = false; + bool seen_ipv6 = false; + bool check_pf_called = false; + + if (hints->ai_flags & AI_ADDRCONFIG) + { + /* We might need information about what interfaces are available. + Also determine whether we have IPv4 or IPv6 interfaces or both. We + cannot cache the results since new interfaces could be added at + any time. */ + __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen); + check_pf_called = true; + + /* Now make a decision on what we return, if anything. */ + if (hints->ai_family == PF_UNSPEC && (seen_ipv4 || seen_ipv6)) + { + /* If we haven't seen both IPv4 and IPv6 interfaces we can + narrow down the search. */ + if ((! seen_ipv4 || ! seen_ipv6) && (seen_ipv4 || seen_ipv6)) + { + local_hints = *hints; + local_hints.ai_family = seen_ipv4 ? PF_INET : PF_INET6; + hints = &local_hints; + } + } + else if ((hints->ai_family == PF_INET && ! seen_ipv4) + || (hints->ai_family == PF_INET6 && ! seen_ipv6)) + { + /* We cannot possibly return a valid answer. */ + __free_in6ai (in6ai); + return EAI_NONAME; + } + } + + if (service && service[0]) + { + char *c; + gaih_service.name = service; + gaih_service.num = strtoul (gaih_service.name, &c, 10); + if (*c != '\0') + { + if (hints->ai_flags & AI_NUMERICSERV) + { + __free_in6ai (in6ai); + return EAI_NONAME; + } + + gaih_service.num = -1; + } + + pservice = &gaih_service; + } + else + pservice = NULL; + + struct addrinfo **end = &p; + + unsigned int naddrs = 0; + if (hints->ai_family == AF_UNSPEC || hints->ai_family == AF_INET + || hints->ai_family == AF_INET6) + { + struct scratch_buffer tmpbuf; + scratch_buffer_init (&tmpbuf); + last_i = gaih_inet (name, pservice, hints, end, &naddrs, &tmpbuf); + scratch_buffer_free (&tmpbuf); + + if (last_i != 0) + { + freeaddrinfo (p); + __free_in6ai (in6ai); + + return -last_i; + } + while (*end) + { + end = &((*end)->ai_next); + ++nresults; + } + } + else + { + __free_in6ai (in6ai); + return EAI_FAMILY; + } + + if (naddrs > 1) + { + /* Read the config file. */ + __libc_once_define (static, once); + __typeof (once) old_once = once; + __libc_once (once, gaiconf_init); + /* Sort results according to RFC 3484. */ + struct sort_result *results; + size_t *order; + struct addrinfo *q; + struct addrinfo *last = NULL; + char *canonname = NULL; + bool malloc_results; + size_t alloc_size = nresults * (sizeof (*results) + sizeof (size_t)); + + malloc_results + = !__libc_use_alloca (alloc_size); + if (malloc_results) + { + results = malloc (alloc_size); + if (results == NULL) + { + __free_in6ai (in6ai); + return EAI_MEMORY; + } + } + else + results = alloca (alloc_size); + order = (size_t *) (results + nresults); + + /* Now we definitely need the interface information. */ + if (! check_pf_called) + __check_pf (&seen_ipv4, &seen_ipv6, &in6ai, &in6ailen); + + /* If we have information about deprecated and temporary addresses + sort the array now. */ + if (in6ai != NULL) + qsort (in6ai, in6ailen, sizeof (*in6ai), in6aicmp); + + int fd = -1; + int af = AF_UNSPEC; + + for (i = 0, q = p; q != NULL; ++i, last = q, q = q->ai_next) + { + results[i].dest_addr = q; + results[i].native = -1; + order[i] = i; + + /* If we just looked up the address for a different + protocol, reuse the result. */ + if (last != NULL && last->ai_addrlen == q->ai_addrlen + && memcmp (last->ai_addr, q->ai_addr, q->ai_addrlen) == 0) + { + memcpy (&results[i].source_addr, &results[i - 1].source_addr, + results[i - 1].source_addr_len); + results[i].source_addr_len = results[i - 1].source_addr_len; + results[i].got_source_addr = results[i - 1].got_source_addr; + results[i].source_addr_flags = results[i - 1].source_addr_flags; + results[i].prefixlen = results[i - 1].prefixlen; + results[i].index = results[i - 1].index; + } + else + { + results[i].got_source_addr = false; + results[i].source_addr_flags = 0; + results[i].prefixlen = 0; + results[i].index = 0xffffffffu; + + /* We overwrite the type with SOCK_DGRAM since we do not + want connect() to connect to the other side. If we + cannot determine the source address remember this + fact. */ + if (fd == -1 || (af == AF_INET && q->ai_family == AF_INET6)) + { + if (fd != -1) + close_retry: + close_not_cancel_no_status (fd); + af = q->ai_family; + fd = __socket (af, SOCK_DGRAM | SOCK_CLOEXEC, IPPROTO_IP); + } + else + { + /* Reset the connection. */ + struct sockaddr sa = { .sa_family = AF_UNSPEC }; + __connect (fd, &sa, sizeof (sa)); + } + + socklen_t sl = sizeof (results[i].source_addr); + if (fd != -1 + && __connect (fd, q->ai_addr, q->ai_addrlen) == 0 + && __getsockname (fd, + (struct sockaddr *) &results[i].source_addr, + &sl) == 0) + { + results[i].source_addr_len = sl; + results[i].got_source_addr = true; + + if (in6ai != NULL) + { + /* See whether the source address is on the list of + deprecated or temporary addresses. */ + struct in6addrinfo tmp; + + if (q->ai_family == AF_INET && af == AF_INET) + { + struct sockaddr_in *sinp + = (struct sockaddr_in *) &results[i].source_addr; + tmp.addr[0] = 0; + tmp.addr[1] = 0; + tmp.addr[2] = htonl (0xffff); + /* Special case for lo interface, the source address + being possibly different than the interface + address. */ + if ((ntohl(sinp->sin_addr.s_addr) & 0xff000000) + == 0x7f000000) + tmp.addr[3] = htonl(0x7f000001); + else + tmp.addr[3] = sinp->sin_addr.s_addr; + } + else + { + struct sockaddr_in6 *sin6p + = (struct sockaddr_in6 *) &results[i].source_addr; + memcpy (tmp.addr, &sin6p->sin6_addr, IN6ADDRSZ); + } + + struct in6addrinfo *found + = bsearch (&tmp, in6ai, in6ailen, sizeof (*in6ai), + in6aicmp); + if (found != NULL) + { + results[i].source_addr_flags = found->flags; + results[i].prefixlen = found->prefixlen; + results[i].index = found->index; + } + } + + if (q->ai_family == AF_INET && af == AF_INET6) + { + /* We have to convert the address. The socket is + IPv6 and the request is for IPv4. */ + struct sockaddr_in6 *sin6 + = (struct sockaddr_in6 *) &results[i].source_addr; + struct sockaddr_in *sin + = (struct sockaddr_in *) &results[i].source_addr; + assert (IN6_IS_ADDR_V4MAPPED (sin6->sin6_addr.s6_addr32)); + sin->sin_family = AF_INET; + /* We do not have to initialize sin_port since this + fields has the same position and size in the IPv6 + structure. */ + assert (offsetof (struct sockaddr_in, sin_port) + == offsetof (struct sockaddr_in6, sin6_port)); + assert (sizeof (sin->sin_port) + == sizeof (sin6->sin6_port)); + memcpy (&sin->sin_addr, + &sin6->sin6_addr.s6_addr32[3], INADDRSZ); + results[i].source_addr_len = sizeof (struct sockaddr_in); + } + } + else if (errno == EAFNOSUPPORT && af == AF_INET6 + && q->ai_family == AF_INET) + /* This could mean IPv6 sockets are IPv6-only. */ + goto close_retry; + else + /* Just make sure that if we have to process the same + address again we do not copy any memory. */ + results[i].source_addr_len = 0; + } + + /* Remember the canonical name. */ + if (q->ai_canonname != NULL) + { + assert (canonname == NULL); + canonname = q->ai_canonname; + q->ai_canonname = NULL; + } + } + + if (fd != -1) + close_not_cancel_no_status (fd); + + /* We got all the source addresses we can get, now sort using + the information. */ + struct sort_result_combo src + = { .results = results, .nresults = nresults }; + if (__glibc_unlikely (gaiconf_reload_flag_ever_set)) + { + __libc_lock_define_initialized (static, lock); + + __libc_lock_lock (lock); + if (__libc_once_get (old_once) && gaiconf_reload_flag) + gaiconf_reload (); + __qsort_r (order, nresults, sizeof (order[0]), rfc3484_sort, &src); + __libc_lock_unlock (lock); + } + else + __qsort_r (order, nresults, sizeof (order[0]), rfc3484_sort, &src); + + /* Queue the results up as they come out of sorting. */ + q = p = results[order[0]].dest_addr; + for (i = 1; i < nresults; ++i) + q = q->ai_next = results[order[i]].dest_addr; + q->ai_next = NULL; + + /* Fill in the canonical name into the new first entry. */ + p->ai_canonname = canonname; + + if (malloc_results) + free (results); + } + + __free_in6ai (in6ai); + + if (p) + { + *pai = p; + return 0; + } + + return last_i ? -last_i : EAI_NONAME; +} +libc_hidden_def (getaddrinfo) + +nss_interface_function (getaddrinfo) + +void +freeaddrinfo (struct addrinfo *ai) +{ + struct addrinfo *p; + + while (ai != NULL) + { + p = ai; + ai = ai->ai_next; + free (p->ai_canonname); + free (p); + } +} +libc_hidden_def (freeaddrinfo) diff --git a/REORG.TODO/sysdeps/posix/getcwd.c b/REORG.TODO/sysdeps/posix/getcwd.c new file mode 100644 index 0000000000..eb1706aa5c --- /dev/null +++ b/REORG.TODO/sysdeps/posix/getcwd.c @@ -0,0 +1,535 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +/* Wants: + AC_STDC_HEADERS + AC_DIR_HEADER + AC_UNISTD_H + AC_MEMORY_H + AC_CONST + AC_ALLOCA + */ + +/* AIX requires this to be the first thing in the file. */ +#if defined _AIX && !defined __GNUC__ + #pragma alloca +#endif + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <errno.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef STDC_HEADERS +# include <stddef.h> +#endif + +#if !defined __GNU_LIBRARY__ && !defined STDC_HEADERS +extern int errno; +#endif +#ifndef __set_errno +# define __set_errno(val) errno = (val) +#endif + +#ifndef NULL +# define NULL 0 +#endif + +#if defined USGr3 && !defined DIRENT +# define DIRENT +#endif /* USGr3 */ +#if defined Xenix && !defined SYSNDIR +# define SYSNDIR +#endif /* Xenix */ + +#if defined POSIX || defined DIRENT || defined __GNU_LIBRARY__ +# include <dirent.h> +# ifndef __GNU_LIBRARY__ +# define D_NAMLEN(d) strlen((d)->d_name) +# else +# define HAVE_D_NAMLEN +# define D_NAMLEN(d) ((d)->d_namlen) +# endif +#else /* not POSIX or DIRENT */ +# define dirent direct +# define D_NAMLEN(d) ((d)->d_namlen) +# define HAVE_D_NAMLEN +# if defined USG && !defined sgi +# if defined SYSNDIR +# include <sys/ndir.h> +# else /* Not SYSNDIR */ +# include "ndir.h" +# endif /* SYSNDIR */ +# else /* not USG */ +# include <sys/dir.h> +# endif /* USG */ +#endif /* POSIX or DIRENT or __GNU_LIBRARY__ */ + +#if defined HAVE_UNISTD_H || defined __GNU_LIBRARY__ +# include <unistd.h> +#endif + +#if defined STDC_HEADERS || defined __GNU_LIBRARY__ || defined POSIX +# include <stdlib.h> +# include <string.h> +# define ANSI_STRING +#else /* No standard headers. */ + +# ifdef USG + +# include <string.h> +# ifdef NEED_MEMORY_H +# include <memory.h> +# endif +# define ANSI_STRING + +# else /* Not USG. */ + +# ifdef NeXT + +# include <string.h> + +# else /* Not NeXT. */ + +# include <strings.h> + +# ifndef bcmp +extern int bcmp (); +# endif +# ifndef bzero +extern void bzero (); +# endif +# ifndef bcopy +extern void bcopy (); +# endif + +# endif /* NeXT. */ + +# endif /* USG. */ + +extern char *malloc (), *realloc (); +extern void free (); + +#endif /* Standard headers. */ + +#ifndef ANSI_STRING +# define memcpy(d, s, n) bcopy((s), (d), (n)) +# define memmove memcpy +#endif /* Not ANSI_STRING. */ + +#ifndef MAX +# define MAX(a, b) ((a) < (b) ? (b) : (a)) +#endif + +#ifdef _LIBC +# ifndef mempcpy +# define mempcpy __mempcpy +# endif +# define HAVE_MEMPCPY 1 +#endif + +#if !defined __alloca && !defined __GNU_LIBRARY__ + +# ifdef __GNUC__ +# undef alloca +# define alloca(n) __builtin_alloca (n) +# else /* Not GCC. */ +# if defined sparc || defined HAVE_ALLOCA_H +# include <alloca.h> +# else /* Not sparc or HAVE_ALLOCA_H. */ +# ifndef _AIX +extern char *alloca (); +# endif /* Not _AIX. */ +# endif /* sparc or HAVE_ALLOCA_H. */ +# endif /* GCC. */ + +# define __alloca alloca + +#endif + +#if defined HAVE_LIMITS_H || defined STDC_HEADERS || defined __GNU_LIBRARY__ +# include <limits.h> +#else +# include <sys/param.h> +#endif + +#if defined _LIBC +# include <not-cancel.h> +# include <kernel-features.h> +#else +# define openat64_not_cancel_3(dfd, name, mode) openat64 (dfd, name, mode) +# define close_not_cancel_no_status(fd) close (fd) +#endif + +#ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN +# else +# define PATH_MAX 1024 +# endif +#endif + +#if !defined STDC_HEADERS && !defined __GNU_LIBRARY__ +# undef size_t +# define size_t unsigned int +#endif + +#ifndef __GNU_LIBRARY__ +# define __lstat64 stat64 +#endif + +#ifndef _LIBC +# define __rewinddir rewinddir +#endif + +#ifndef _LIBC +# define __getcwd getcwd +#endif + +#ifndef GETCWD_RETURN_TYPE +# define GETCWD_RETURN_TYPE char * +#endif + +#ifdef __ASSUME_ATFCTS +# define __have_atfcts 1 +#elif IS_IN (rtld) +static int __rtld_have_atfcts; +# define __have_atfcts __rtld_have_atfcts +#endif + +/* Get the pathname of the current working directory, and put it in SIZE + bytes of BUF. Returns NULL if the directory couldn't be determined or + SIZE was too small. If successful, returns BUF. In GNU, if BUF is + NULL, an array is allocated with `malloc'; the array is SIZE bytes long, + unless SIZE == 0, in which case it is as big as necessary. */ + +GETCWD_RETURN_TYPE +__getcwd (char *buf, size_t size) +{ +#ifndef __ASSUME_ATFCTS + static const char dots[] + = "../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../../\ +../../../../../../../../../../../../../../../../../../../../../../../../../.."; + const char *dotp = &dots[sizeof (dots)]; + const char *dotlist = dots; + size_t dotsize = sizeof (dots) - 1; +#endif + int prev_errno = errno; + DIR *dirstream = NULL; + bool fd_needs_closing = false; + int fd = AT_FDCWD; + + char *path; +#ifndef NO_ALLOCATION + size_t allocated = size; + if (size == 0) + { + if (buf != NULL) + { + __set_errno (EINVAL); + return NULL; + } + + allocated = PATH_MAX + 1; + } + + if (buf == NULL) + { + path = malloc (allocated); + if (path == NULL) + return NULL; + } + else +#else +# define allocated size +#endif + path = buf; + + char *pathp = path + allocated; + *--pathp = '\0'; + + struct stat64 st; + if (__lstat64 (".", &st) < 0) + goto lose; + dev_t thisdev = st.st_dev; + ino_t thisino = st.st_ino; + + if (__lstat64 ("/", &st) < 0) + goto lose; + dev_t rootdev = st.st_dev; + ino_t rootino = st.st_ino; + + while (!(thisdev == rootdev && thisino == rootino)) + { + if (__have_atfcts >= 0) + fd = openat64_not_cancel_3 (fd, "..", O_RDONLY | O_CLOEXEC); + else + fd = -1; + if (fd >= 0) + { + fd_needs_closing = true; + if (__fstat64 (fd, &st) < 0) + goto lose; + } +#ifndef __ASSUME_ATFCTS + else if (errno == ENOSYS) + { + __have_atfcts = -1; + + /* Look at the parent directory. */ + if (dotp == dotlist) + { +# ifdef NO_ALLOCATION + __set_errno (ENOMEM); + goto lose; +# else + /* My, what a deep directory tree you have, Grandma. */ + char *new; + if (dotlist == dots) + { + new = malloc (dotsize * 2 + 1); + if (new == NULL) + goto lose; +# ifdef HAVE_MEMPCPY + dotp = mempcpy (new, dots, dotsize); +# else + memcpy (new, dots, dotsize); + dotp = &new[dotsize]; +# endif + } + else + { + new = realloc ((__ptr_t) dotlist, dotsize * 2 + 1); + if (new == NULL) + goto lose; + dotp = &new[dotsize]; + } +# ifdef HAVE_MEMPCPY + *((char *) mempcpy ((char *) dotp, new, dotsize)) = '\0'; + dotsize *= 2; +# else + memcpy ((char *) dotp, new, dotsize); + dotsize *= 2; + new[dotsize] = '\0'; +# endif + dotlist = new; +# endif + } + + dotp -= 3; + + /* Figure out if this directory is a mount point. */ + if (__lstat64 (dotp, &st) < 0) + goto lose; + } +#endif + else + goto lose; + + if (dirstream && __closedir (dirstream) != 0) + { + dirstream = NULL; + goto lose; + } + + dev_t dotdev = st.st_dev; + ino_t dotino = st.st_ino; + bool mount_point = dotdev != thisdev; + + /* Search for the last directory. */ + if (__have_atfcts >= 0) + dirstream = __fdopendir (fd); +#ifndef __ASSUME_ATFCTS + else + dirstream = __opendir (dotp); +#endif + if (dirstream == NULL) + goto lose; + fd_needs_closing = false; + + struct dirent *d; + bool use_d_ino = true; + while (1) + { + /* Clear errno to distinguish EOF from error if readdir returns + NULL. */ + __set_errno (0); + d = __readdir (dirstream); + if (d == NULL) + { + if (errno == 0) + { + /* When we've iterated through all directory entries + without finding one with a matching d_ino, rewind the + stream and consider each name again, but this time, using + lstat64. This is necessary in a chroot on at least one + system. */ + if (use_d_ino) + { + use_d_ino = false; + __rewinddir (dirstream); + continue; + } + + /* EOF on dirstream, which means that the current directory + has been removed. */ + __set_errno (ENOENT); + } + goto lose; + } + +#ifdef _DIRENT_HAVE_D_TYPE + if (d->d_type != DT_DIR && d->d_type != DT_UNKNOWN) + continue; +#endif + if (d->d_name[0] == '.' + && (d->d_name[1] == '\0' + || (d->d_name[1] == '.' && d->d_name[2] == '\0'))) + continue; + if (use_d_ino && !mount_point && (ino_t) d->d_ino != thisino) + continue; + + if (__have_atfcts >= 0) + { + /* We don't fail here if we cannot stat64() a directory entry. + This can happen when (network) filesystems fail. If this + entry is in fact the one we are looking for we will find + out soon as we reach the end of the directory without + having found anything. */ + if (__fstatat64 (fd, d->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) + continue; + } +#ifndef __ASSUME_ATFCTS + else + { + char name[dotlist + dotsize - dotp + 1 + _D_ALLOC_NAMLEN (d)]; +# ifdef HAVE_MEMPCPY + char *tmp = mempcpy (name, dotp, dotlist + dotsize - dotp); + *tmp++ = '/'; + strcpy (tmp, d->d_name); +# else + memcpy (name, dotp, dotlist + dotsize - dotp); + name[dotlist + dotsize - dotp] = '/'; + strcpy (&name[dotlist + dotsize - dotp + 1], d->d_name); +# endif + /* We don't fail here if we cannot stat64() a directory entry. + This can happen when (network) filesystems fail. If this + entry is in fact the one we are looking for we will find + out soon as we reach the end of the directory without + having found anything. */ + if (__lstat64 (name, &st) < 0) + continue; + } +#endif + if (S_ISDIR (st.st_mode) + && st.st_dev == thisdev && st.st_ino == thisino) + break; + } + + size_t namlen = _D_EXACT_NAMLEN (d); + + if ((size_t) (pathp - path) <= namlen) + { +#ifndef NO_ALLOCATION + if (size == 0) + { + size_t oldsize = allocated; + + allocated = 2 * MAX (allocated, namlen); + char *tmp = realloc (path, allocated); + if (tmp == NULL) + goto lose; + + /* Move current contents up to the end of the buffer. + This is guaranteed to be non-overlapping. */ + pathp = memcpy (tmp + allocated - (path + oldsize - pathp), + tmp + (pathp - path), + path + oldsize - pathp); + path = tmp; + } + else +#endif + { + __set_errno (ERANGE); + goto lose; + } + } + pathp -= namlen; + (void) memcpy (pathp, d->d_name, namlen); + *--pathp = '/'; + + thisdev = dotdev; + thisino = dotino; + } + + if (dirstream != NULL && __closedir (dirstream) != 0) + { + dirstream = NULL; + goto lose; + } + + if (pathp == &path[allocated - 1]) + *--pathp = '/'; + +#ifndef __ASSUME_ATFCTS + if (dotlist != dots) + free ((__ptr_t) dotlist); +#endif + + size_t used = path + allocated - pathp; + memmove (path, pathp, used); + + if (size == 0) + /* Ensure that the buffer is only as large as necessary. */ + buf = realloc (path, used); + + if (buf == NULL) + /* Either buf was NULL all along, or `realloc' failed but + we still have the original string. */ + buf = path; + + /* Restore errno on successful return. */ + __set_errno (prev_errno); + + return buf; + + lose:; + int save_errno = errno; +#ifndef __ASSUME_ATFCTS + if (dotlist != dots) + free ((__ptr_t) dotlist); +#endif + if (dirstream != NULL) + __closedir (dirstream); + if (fd_needs_closing) + close_not_cancel_no_status (fd); +#ifndef NO_ALLOCATION + if (buf == NULL) + free (path); +#endif + __set_errno (save_errno); + return NULL; +} + +#if defined _LIBC && !defined __getcwd +weak_alias (__getcwd, getcwd) +#endif diff --git a/REORG.TODO/sysdeps/posix/getdtsz.c b/REORG.TODO/sysdeps/posix/getdtsz.c new file mode 100644 index 0000000000..0f468cf498 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/getdtsz.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <limits.h> +#include <unistd.h> +#include <sys/resource.h> + +/* Return the maximum number of file descriptors + the current process could possibly have. */ +int +__getdtablesize (void) +{ + struct rlimit ru; + + /* This should even work if `getrlimit' is not implemented. POSIX.1 + does not define this function but we will generate a stub which + returns -1. */ + return __getrlimit (RLIMIT_NOFILE, &ru) < 0 ? OPEN_MAX : ru.rlim_cur; +} + +weak_alias (__getdtablesize, getdtablesize) diff --git a/REORG.TODO/sysdeps/posix/gethostname.c b/REORG.TODO/sysdeps/posix/gethostname.c new file mode 100644 index 0000000000..03a5d3f409 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/gethostname.c @@ -0,0 +1,46 @@ +/* Copyright (C) 1992-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <sys/utsname.h> + +/* Put the name of the current host in no more than LEN bytes of NAME. + The result is null-terminated if LEN is large enough for the full + name and the terminator. */ +int +__gethostname (char *name, size_t len) +{ + struct utsname buf; + size_t node_len; + + if (uname (&buf)) + return -1; + + node_len = strlen (buf.nodename) + 1; + memcpy (name, buf.nodename, len < node_len ? len : node_len); + + if (node_len > len) + { + __set_errno (ENAMETOOLONG); + return -1; + } + return 0; +} + +weak_alias (__gethostname, gethostname) diff --git a/REORG.TODO/sysdeps/posix/getpagesize.c b/REORG.TODO/sysdeps/posix/getpagesize.c new file mode 100644 index 0000000000..de7b52e284 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/getpagesize.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1993-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Brendan Kehoe (brendan@cygnus.com). + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + +/* Return the system page size. */ +int +__getpagesize (void) +{ + return __sysconf (_SC_PAGESIZE); +} +libc_hidden_def (__getpagesize) +weak_alias (__getpagesize, getpagesize) diff --git a/REORG.TODO/sysdeps/posix/gettimeofday.c b/REORG.TODO/sysdeps/posix/gettimeofday.c new file mode 100644 index 0000000000..41a8217fd1 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/gettimeofday.c @@ -0,0 +1,67 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <time.h> +#include <sys/time.h> + +/* Get the current time of day and timezone information, + putting it into *TV and *TZ. If TZ is NULL, *TZ is not filled. + Returns 0 on success, -1 on errors. */ +int +__gettimeofday (struct timeval *tv, struct timezone *tz) +{ + if (tv == NULL) + { + __set_errno (EINVAL); + return -1; + } + + tv->tv_sec = (long int) time ((time_t *) NULL); + tv->tv_usec = 0L; + + if (tz != NULL) + { + const time_t timer = tv->tv_sec; + struct tm tm; + const struct tm *tmp; + + const long int save_timezone = __timezone; + const long int save_daylight = __daylight; + char *save_tzname[2]; + save_tzname[0] = __tzname[0]; + save_tzname[1] = __tzname[1]; + + tmp = localtime_r (&timer, &tm); + + tz->tz_minuteswest = __timezone / 60; + tz->tz_dsttime = __daylight; + + __timezone = save_timezone; + __daylight = save_daylight; + __tzname[0] = save_tzname[0]; + __tzname[1] = save_tzname[1]; + + if (tmp == NULL) + return -1; + } + + return 0; +} +libc_hidden_def (__gettimeofday) +weak_alias (__gettimeofday, gettimeofday) +libc_hidden_weak (gettimeofday) diff --git a/REORG.TODO/sysdeps/posix/isatty.c b/REORG.TODO/sysdeps/posix/isatty.c new file mode 100644 index 0000000000..150a0134d7 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/isatty.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <termios.h> + +/* Return 1 if FD is a terminal, 0 if not. */ +int +__isatty (int fd) +{ + struct termios term; + + return __tcgetattr (fd, &term) == 0; +} + +weak_alias (__isatty, isatty) diff --git a/REORG.TODO/sysdeps/posix/isfdtype.c b/REORG.TODO/sysdeps/posix/isfdtype.c new file mode 100644 index 0000000000..4a825e7e5d --- /dev/null +++ b/REORG.TODO/sysdeps/posix/isfdtype.c @@ -0,0 +1,37 @@ +/* Determine whether descriptor has given property. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <sys/types.h> + +int +isfdtype (int fildes, int fdtype) +{ + struct stat64 st; + int result; + + { + int save_error = errno; + result = fstat64 (fildes, &st); + __set_errno (save_error); + } + + return result ?: (st.st_mode & S_IFMT) == (mode_t) fdtype; +} diff --git a/REORG.TODO/sysdeps/posix/killpg.c b/REORG.TODO/sysdeps/posix/killpg.c new file mode 100644 index 0000000000..5b9df19c76 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/killpg.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> + + +/* Send SIG to all processes in process group PGRP. + If PGRP is zero, send SIG to all processes in + the current process's process group. */ +int +killpg (__pid_t pgrp, int sig) +{ + if (pgrp < 0) + { + __set_errno (EINVAL); + return -1; + } + + return __kill (- pgrp, sig); +} diff --git a/REORG.TODO/sysdeps/posix/libc_fatal.c b/REORG.TODO/sysdeps/posix/libc_fatal.c new file mode 100644 index 0000000000..b261963679 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/libc_fatal.c @@ -0,0 +1,187 @@ +/* Catastrophic failure reports. Generic POSIX.1 version. + Copyright (C) 1993-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <atomic.h> +#include <errno.h> +#include <fcntl.h> +#include <ldsodefs.h> +#include <paths.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sysdep.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/uio.h> +#include <not-cancel.h> + +#ifdef FATAL_PREPARE_INCLUDE +#include FATAL_PREPARE_INCLUDE +#endif + +#ifndef WRITEV_FOR_FATAL +# define WRITEV_FOR_FATAL writev_for_fatal +static bool +writev_for_fatal (int fd, const struct iovec *iov, size_t niov, size_t total) +{ + return TEMP_FAILURE_RETRY (__writev (fd, iov, niov)) == total; +} +#endif + +#ifndef BEFORE_ABORT +# define BEFORE_ABORT before_abort +static void +before_abort (int do_abort __attribute__ ((unused)), + bool written __attribute__ ((unused)), + int fd __attribute__ ((unused))) +{ +} +#endif + +struct str_list +{ + const char *str; + size_t len; + struct str_list *next; +}; + +/* Abort with an error message. */ +void +__libc_message (int do_abort, const char *fmt, ...) +{ + va_list ap; + int fd = -1; + + va_start (ap, fmt); + +#ifdef FATAL_PREPARE + FATAL_PREPARE; +#endif + + /* Open a descriptor for /dev/tty unless the user explicitly + requests errors on standard error. */ + const char *on_2 = __libc_secure_getenv ("LIBC_FATAL_STDERR_"); + if (on_2 == NULL || *on_2 == '\0') + fd = open_not_cancel_2 (_PATH_TTY, O_RDWR | O_NOCTTY | O_NDELAY); + + if (fd == -1) + fd = STDERR_FILENO; + + struct str_list *list = NULL; + int nlist = 0; + + const char *cp = fmt; + while (*cp != '\0') + { + /* Find the next "%s" or the end of the string. */ + const char *next = cp; + while (next[0] != '%' || next[1] != 's') + { + next = __strchrnul (next + 1, '%'); + + if (next[0] == '\0') + break; + } + + /* Determine what to print. */ + const char *str; + size_t len; + if (cp[0] == '%' && cp[1] == 's') + { + str = va_arg (ap, const char *); + len = strlen (str); + cp += 2; + } + else + { + str = cp; + len = next - cp; + cp = next; + } + + struct str_list *newp = alloca (sizeof (struct str_list)); + newp->str = str; + newp->len = len; + newp->next = list; + list = newp; + ++nlist; + } + + bool written = false; + if (nlist > 0) + { + struct iovec *iov = alloca (nlist * sizeof (struct iovec)); + ssize_t total = 0; + + for (int cnt = nlist - 1; cnt >= 0; --cnt) + { + iov[cnt].iov_base = (char *) list->str; + iov[cnt].iov_len = list->len; + total += list->len; + list = list->next; + } + + written = WRITEV_FOR_FATAL (fd, iov, nlist, total); + + if (do_abort) + { + total = ((total + 1 + GLRO(dl_pagesize) - 1) + & ~(GLRO(dl_pagesize) - 1)); + struct abort_msg_s *buf = __mmap (NULL, total, + PROT_READ | PROT_WRITE, + MAP_ANON | MAP_PRIVATE, -1, 0); + if (__glibc_likely (buf != MAP_FAILED)) + { + buf->size = total; + char *wp = buf->msg; + for (int cnt = 0; cnt < nlist; ++cnt) + wp = mempcpy (wp, iov[cnt].iov_base, iov[cnt].iov_len); + *wp = '\0'; + + /* We have to free the old buffer since the application might + catch the SIGABRT signal. */ + struct abort_msg_s *old = atomic_exchange_acq (&__abort_msg, + buf); + if (old != NULL) + __munmap (old, old->size); + } + } + } + + va_end (ap); + + if (do_abort) + { + BEFORE_ABORT (do_abort, written, fd); + + /* Kill the application. */ + abort (); + } +} + + +void +__libc_fatal (const char *message) +{ + /* The loop is added only to keep gcc happy. */ + while (1) + __libc_message (1, "%s", message); +} +libc_hidden_def (__libc_fatal) diff --git a/REORG.TODO/sysdeps/posix/mkfifo.c b/REORG.TODO/sysdeps/posix/mkfifo.c new file mode 100644 index 0000000000..4d7fa58675 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/mkfifo.c @@ -0,0 +1,29 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stddef.h> +#include <sys/stat.h> +#include <sys/types.h> + +/* Create a named pipe (FIFO) named PATH with protections MODE. */ +int +mkfifo (const char *path, mode_t mode) +{ + dev_t dev = 0; + return __xmknod (_MKNOD_VER, path, mode | S_IFIFO, &dev); +} diff --git a/REORG.TODO/sysdeps/posix/mkfifoat.c b/REORG.TODO/sysdeps/posix/mkfifoat.c new file mode 100644 index 0000000000..598c1e25ca --- /dev/null +++ b/REORG.TODO/sysdeps/posix/mkfifoat.c @@ -0,0 +1,28 @@ +/* Copyright (C) 2005-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/stat.h> + + +/* Create a new FIFO with permission bits MODE. But interpret + relative PATH names relative to the directory associated with FD. */ +int +mkfifoat (int fd, const char *file, mode_t mode) +{ + dev_t dev = 0; + return __xmknodat (_MKNOD_VER, fd, file, mode | S_IFIFO, &dev); +} diff --git a/REORG.TODO/sysdeps/posix/nice.c b/REORG.TODO/sysdeps/posix/nice.c new file mode 100644 index 0000000000..d13176556e --- /dev/null +++ b/REORG.TODO/sysdeps/posix/nice.c @@ -0,0 +1,51 @@ +/* Copyright (C) 1992-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> +#include <sys/resource.h> + +/* Increment the scheduling priority of the calling process by INCR. + The superuser may use a negative INCR to decrement the priority. */ +int +nice (int incr) +{ + int save; + int prio; + int result; + + /* -1 is a valid priority, so we use errno to check for an error. */ + save = errno; + __set_errno (0); + prio = __getpriority (PRIO_PROCESS, 0); + if (prio == -1) + { + if (errno != 0) + return -1; + } + + result = __setpriority (PRIO_PROCESS, 0, prio + incr); + if (result == -1) + { + if (errno == EACCES) + __set_errno (EPERM); + return -1; + } + + __set_errno (save); + return __getpriority (PRIO_PROCESS, 0); +} diff --git a/REORG.TODO/sysdeps/posix/open64.c b/REORG.TODO/sysdeps/posix/open64.c new file mode 100644 index 0000000000..dd1b4d61fe --- /dev/null +++ b/REORG.TODO/sysdeps/posix/open64.c @@ -0,0 +1,50 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <fcntl.h> +#include <stdarg.h> +#include <sysdep-cancel.h> + +/* Open FILE with access OFLAG. If O_CREAT or O_TMPFILE is in OFLAG, + a third argument is the file protection. */ +int +__libc_open64 (const char *file, int oflag, ...) +{ + int mode = 0; + + if (__OPEN_NEEDS_MODE (oflag)) + { + va_list arg; + va_start (arg, oflag); + mode = va_arg (arg, int); + va_end (arg); + } + + if (SINGLE_THREAD_P) + return __libc_open (file, oflag | O_LARGEFILE, mode); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = __libc_open (file, oflag | O_LARGEFILE, mode); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +weak_alias (__libc_open64, __open64) +libc_hidden_weak (__open64) +weak_alias (__libc_open64, open64) diff --git a/REORG.TODO/sysdeps/posix/opendir.c b/REORG.TODO/sysdeps/posix/opendir.c new file mode 100644 index 0000000000..909aa61884 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/opendir.c @@ -0,0 +1,248 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h> +#include <dirent.h> +#include <fcntl.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdio.h> +#include <string.h> + +#include <dirstream.h> +#include <not-cancel.h> +#include <kernel-features.h> + +/* The st_blksize value of the directory is used as a hint for the + size of the buffer which receives struct dirent values from the + kernel. st_blksize is limited to MAX_DIR_BUFFER_SIZE, in case the + file system provides a bogus value. */ +#define MAX_DIR_BUFFER_SIZE 1048576U + +/* opendir() must not accidentally open something other than a directory. + Some OS's have kernel support for that, some don't. In the worst + case we have to stat() before the open() AND fstat() after. + + We have to test at runtime for kernel support since libc may have + been compiled with different headers to the kernel it's running on. + This test can't be done reliably in the general case. We'll use + /dev/null, which if it's not a device lots of stuff will break, as + a guinea pig. It may be missing in chroot environments, so we + make sure to fail safe. */ +#ifdef O_DIRECTORY +# ifdef O_DIRECTORY_WORKS +# define o_directory_works 1 +# define tryopen_o_directory() while (1) /* This must not be called. */ +# else +static int o_directory_works; + +static void +tryopen_o_directory (void) +{ + int serrno = errno; + int x = open_not_cancel_2 ("/dev/null", O_RDONLY|O_NDELAY|O_DIRECTORY); + + if (x >= 0) + { + close_not_cancel_no_status (x); + o_directory_works = -1; + } + else if (errno != ENOTDIR) + o_directory_works = -1; + else + o_directory_works = 1; + + __set_errno (serrno); +} +# endif +# define EXTRA_FLAGS O_DIRECTORY +#else +# define EXTRA_FLAGS 0 +#endif + +enum { + opendir_oflags = O_RDONLY|O_NDELAY|EXTRA_FLAGS|O_LARGEFILE|O_CLOEXEC +}; + +static bool +invalid_name (const char *name) +{ + if (__glibc_unlikely (name[0] == '\0')) + { + /* POSIX.1-1990 says an empty name gets ENOENT; + but `open' might like it fine. */ + __set_errno (ENOENT); + return true; + } + return false; +} + + +static bool +need_isdir_precheck (void) +{ +#ifdef O_DIRECTORY + /* Test whether O_DIRECTORY works. */ + if (o_directory_works == 0) + tryopen_o_directory (); + + /* We can skip the expensive `stat' call if O_DIRECTORY works. */ + return o_directory_works < 0; +#endif + return true; +} + +static DIR * +opendir_tail (int fd) +{ + if (__glibc_unlikely (fd < 0)) + return NULL; + + /* Now make sure this really is a directory and nothing changed since the + `stat' call. The S_ISDIR check is superfluous if O_DIRECTORY works, + but it's cheap and we need the stat call for st_blksize anyway. */ + struct stat64 statbuf; + if (__glibc_unlikely (__fxstat64 (_STAT_VER, fd, &statbuf) < 0)) + goto lose; + if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode))) + { + __set_errno (ENOTDIR); + lose: + close_not_cancel_no_status (fd); + return NULL; + } + + return __alloc_dir (fd, true, 0, &statbuf); +} + + +#if IS_IN (libc) +DIR * +internal_function +__opendirat (int dfd, const char *name) +{ + if (__glibc_unlikely (invalid_name (name))) + return NULL; + + if (need_isdir_precheck ()) + { + /* We first have to check whether the name is for a directory. We + cannot do this after the open() call since the open/close operation + performed on, say, a tape device might have undesirable effects. */ + struct stat64 statbuf; + if (__glibc_unlikely (__fxstatat64 (_STAT_VER, dfd, name, + &statbuf, 0) < 0)) + return NULL; + if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode))) + { + __set_errno (ENOTDIR); + return NULL; + } + } + + return opendir_tail (openat_not_cancel_3 (dfd, name, opendir_oflags)); +} +#endif + + +/* Open a directory stream on NAME. */ +DIR * +__opendir (const char *name) +{ + if (__glibc_unlikely (invalid_name (name))) + return NULL; + + if (need_isdir_precheck ()) + { + /* We first have to check whether the name is for a directory. We + cannot do this after the open() call since the open/close operation + performed on, say, a tape device might have undesirable effects. */ + struct stat64 statbuf; + if (__glibc_unlikely (__xstat64 (_STAT_VER, name, &statbuf) < 0)) + return NULL; + if (__glibc_unlikely (! S_ISDIR (statbuf.st_mode))) + { + __set_errno (ENOTDIR); + return NULL; + } + } + + return opendir_tail (open_not_cancel_2 (name, opendir_oflags)); +} +weak_alias (__opendir, opendir) + +DIR * +internal_function +__alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp) +{ + /* We have to set the close-on-exit flag if the user provided the + file descriptor. */ + if (!close_fd + && __builtin_expect (__fcntl (fd, F_SETFD, FD_CLOEXEC), 0) < 0) + goto lose; + + const size_t default_allocation = (4 * BUFSIZ < sizeof (struct dirent64) + ? sizeof (struct dirent64) : 4 * BUFSIZ); + const size_t small_allocation = (BUFSIZ < sizeof (struct dirent64) + ? sizeof (struct dirent64) : BUFSIZ); + size_t allocation = default_allocation; +#ifdef _STATBUF_ST_BLKSIZE + /* Increase allocation if requested, but not if the value appears to + be bogus. */ + if (statp != NULL) + allocation = MIN (MAX ((size_t) statp->st_blksize, default_allocation), + MAX_DIR_BUFFER_SIZE); +#endif + + DIR *dirp = (DIR *) malloc (sizeof (DIR) + allocation); + if (dirp == NULL) + { + allocation = small_allocation; + dirp = (DIR *) malloc (sizeof (DIR) + allocation); + + if (dirp == NULL) + lose: + { + if (close_fd) + { + int save_errno = errno; + close_not_cancel_no_status (fd); + __set_errno (save_errno); + } + return NULL; + } + } + + dirp->fd = fd; +#if IS_IN (libc) + __libc_lock_init (dirp->lock); +#endif + dirp->allocation = allocation; + dirp->size = 0; + dirp->offset = 0; + dirp->filepos = 0; + dirp->errcode = 0; + + return dirp; +} diff --git a/REORG.TODO/sysdeps/posix/pathconf.c b/REORG.TODO/sysdeps/posix/pathconf.c new file mode 100644 index 0000000000..46cc35629e --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pathconf.c @@ -0,0 +1,227 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stddef.h> +#include <unistd.h> +#include <limits.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <sys/statvfs.h> + + +/* Get file-specific information about PATH. */ +long int +__pathconf (const char *path, int name) +{ + if (path[0] == '\0') + { + __set_errno (ENOENT); + return -1; + } + + switch (name) + { + default: + __set_errno (EINVAL); + return -1; + + case _PC_LINK_MAX: +#ifdef LINK_MAX + return LINK_MAX; +#else + return -1; +#endif + + case _PC_MAX_CANON: +#ifdef MAX_CANON + return MAX_CANON; +#else + return -1; +#endif + + case _PC_MAX_INPUT: +#ifdef MAX_INPUT + return MAX_INPUT; +#else + return -1; +#endif + + case _PC_NAME_MAX: +#ifdef NAME_MAX + { + struct statvfs64 sv; + int save_errno = errno; + + if (__statvfs64 (path, &sv) < 0) + { + if (errno == ENOSYS) + { + errno = save_errno; + return NAME_MAX; + } + return -1; + } + else + { + return sv.f_namemax; + } + } +#else + return -1; +#endif + + case _PC_PATH_MAX: +#ifdef PATH_MAX + return PATH_MAX; +#else + return -1; +#endif + + case _PC_PIPE_BUF: +#ifdef PIPE_BUF + return PIPE_BUF; +#else + return -1; +#endif + + case _PC_CHOWN_RESTRICTED: +#ifdef _POSIX_CHOWN_RESTRICTED + return _POSIX_CHOWN_RESTRICTED; +#else + return -1; +#endif + + case _PC_NO_TRUNC: +#ifdef _POSIX_NO_TRUNC + return _POSIX_NO_TRUNC; +#else + return -1; +#endif + + case _PC_VDISABLE: +#ifdef _POSIX_VDISABLE + return _POSIX_VDISABLE; +#else + return -1; +#endif + + case _PC_SYNC_IO: +#ifdef _POSIX_SYNC_IO + return _POSIX_SYNC_IO; +#else + return -1; +#endif + + case _PC_ASYNC_IO: +#ifdef _POSIX_ASYNC_IO + { + /* AIO is only allowed on regular files and block devices. */ + struct stat64 st; + + if (__xstat64 (_STAT_VER, path, &st) < 0 + || (! S_ISREG (st.st_mode) && ! S_ISBLK (st.st_mode))) + return -1; + else + return 1; + } +#else + return -1; +#endif + + case _PC_PRIO_IO: +#ifdef _POSIX_PRIO_IO + return _POSIX_PRIO_IO; +#else + return -1; +#endif + + case _PC_SOCK_MAXBUF: +#ifdef SOCK_MAXBUF + return SOCK_MAXBUF; +#else + return -1; +#endif + + case _PC_FILESIZEBITS: +#ifdef FILESIZEBITS + return FILESIZEBITS; +#else + /* We let platforms with larger file sizes overwrite this value. */ + return 32; +#endif + + case _PC_REC_INCR_XFER_SIZE: + /* XXX It is not entirely clear what the limit is supposed to do. + What is incremented? */ + return -1; + + case _PC_REC_MAX_XFER_SIZE: + /* XXX It is not entirely clear what the limit is supposed to do. + In general there is no top limit of the number of bytes which + case be transported at once. */ + return -1; + + case _PC_REC_MIN_XFER_SIZE: + { + /* XXX It is not entirely clear what the limit is supposed to do. + I assume this is the block size of the filesystem. */ + struct statvfs64 sv; + + if (__statvfs64 (path, &sv) < 0) + return -1; + return sv.f_bsize; + } + + case _PC_REC_XFER_ALIGN: + { + /* XXX It is not entirely clear what the limit is supposed to do. + I assume that the number should reflect the minimal block + alignment. */ + struct statvfs64 sv; + + if (__statvfs64 (path, &sv) < 0) + return -1; + return sv.f_frsize; + } + + case _PC_ALLOC_SIZE_MIN: + { + /* XXX It is not entirely clear what the limit is supposed to do. + I assume that the number should reflect the minimal block + alignment. */ + struct statvfs64 sv; + + if (__statvfs64 (path, &sv) < 0) + return -1; + return sv.f_frsize; + } + + case _PC_SYMLINK_MAX: + /* In general there are no limits. If a system has one it should + overwrite this case. */ + return -1; + + case _PC_2_SYMLINKS: + /* Unix systems generally have symlinks. */ + return 1; + } +} + +#undef __pathconf +weak_alias (__pathconf, pathconf) diff --git a/REORG.TODO/sysdeps/posix/pause.c b/REORG.TODO/sysdeps/posix/pause.c new file mode 100644 index 0000000000..7996cd6dbb --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pause.c @@ -0,0 +1,56 @@ +/* pause -- suspend the process until a signal arrives. POSIX.1 version. + Copyright (C) 2003-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <signal.h> +#include <unistd.h> +#include <sysdep-cancel.h> + +/* Suspend the process until a signal arrives. + This always returns -1 and sets errno to EINTR. */ + +int +__libc_pause (void) +{ + sigset_t set; + + __sigemptyset (&set); + __sigprocmask (SIG_BLOCK, NULL, &set); + + /* pause is a cancellation point, but so is sigsuspend. + So no need for anything special here. */ + + return __sigsuspend (&set); +} +weak_alias (__libc_pause, pause) + +LIBC_CANCEL_HANDLED (); /* sigsuspend handles our cancellation. */ + +#ifndef NO_CANCELLATION +# include <not-cancel.h> + +int +__pause_nocancel (void) +{ + sigset_t set; + + __sigemptyset (&set); + __sigprocmask (SIG_BLOCK, NULL, &set); + + return sigsuspend_not_cancel (&set); +} +#endif diff --git a/REORG.TODO/sysdeps/posix/posix_fallocate.c b/REORG.TODO/sysdeps/posix/posix_fallocate.c new file mode 100644 index 0000000000..f87f536bd9 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/posix_fallocate.c @@ -0,0 +1,122 @@ +/* Copyright (C) 2000-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#include <sys/statfs.h> + +/* Reserve storage for the data of the file associated with FD. This + emulation is far from perfect, but the kernel cannot do not much + better for network file systems, either. */ + +int +posix_fallocate (int fd, __off_t offset, __off_t len) +{ + struct stat64 st; + + if (offset < 0 || len < 0) + return EINVAL; + + /* Perform overflow check. The outer cast relies on a GCC + extension. */ + if ((__off_t) ((uint64_t) offset + (uint64_t) len) < 0) + return EFBIG; + + /* pwrite below will not do the right thing in O_APPEND mode. */ + { + int flags = __fcntl (fd, F_GETFL, 0); + if (flags < 0 || (flags & O_APPEND) != 0) + return EBADF; + } + + /* We have to make sure that this is really a regular file. */ + if (__fxstat64 (_STAT_VER, fd, &st) != 0) + return EBADF; + if (S_ISFIFO (st.st_mode)) + return ESPIPE; + if (! S_ISREG (st.st_mode)) + return ENODEV; + + if (len == 0) + { + /* This is racy, but there is no good way to satisfy a + zero-length allocation request. */ + if (st.st_size < offset) + { + int ret = __ftruncate (fd, offset); + + if (ret != 0) + ret = errno; + return ret; + } + return 0; + } + + /* Minimize data transfer for network file systems, by issuing + single-byte write requests spaced by the file system block size. + (Most local file systems have fallocate support, so this fallback + code is not used there.) */ + + unsigned increment; + { + struct statfs64 f; + + if (__fstatfs64 (fd, &f) != 0) + return errno; + if (f.f_bsize == 0) + increment = 512; + else if (f.f_bsize < 4096) + increment = f.f_bsize; + else + /* NFS does not propagate the block size of the underlying + storage and may report a much larger value which would still + leave holes after the loop below, so we cap the increment at + 4096. */ + increment = 4096; + } + + /* Write a null byte to every block. This is racy; we currently + lack a better option. Compare-and-swap against a file mapping + might additional local races, but requires interposition of a + signal handler to catch SIGBUS. */ + for (offset += (len - 1) % increment; len > 0; offset += increment) + { + len -= increment; + + if (offset < st.st_size) + { + unsigned char c; + ssize_t rsize = __pread (fd, &c, 1, offset); + + if (rsize < 0) + return errno; + /* If there is a non-zero byte, the block must have been + allocated already. */ + else if (rsize == 1 && c != 0) + continue; + } + + if (__pwrite (fd, "", 1, offset) != 1) + return errno; + } + + return 0; +} diff --git a/REORG.TODO/sysdeps/posix/posix_fallocate64.c b/REORG.TODO/sysdeps/posix/posix_fallocate64.c new file mode 100644 index 0000000000..a637ebe0c6 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/posix_fallocate64.c @@ -0,0 +1,142 @@ +/* Copyright (C) 2000-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdint.h> +#include <sys/fcntl.h> +#include <sys/stat.h> +#include <sys/statfs.h> + +/* Reserve storage for the data of the file associated with FD. This + emulation is far from perfect, but the kernel cannot do not much + better for network file systems, either. */ + +int +__posix_fallocate64_l64 (int fd, __off64_t offset, __off64_t len) +{ + struct stat64 st; + + if (offset < 0 || len < 0) + return EINVAL; + + /* Perform overflow check. The outer cast relies on a GCC + extension. */ + if ((__off64_t) ((uint64_t) offset + (uint64_t) len) < 0) + return EFBIG; + + /* pwrite64 below will not do the right thing in O_APPEND mode. */ + { + int flags = __fcntl (fd, F_GETFL, 0); + if (flags < 0 || (flags & O_APPEND) != 0) + return EBADF; + } + + /* We have to make sure that this is really a regular file. */ + if (__fxstat64 (_STAT_VER, fd, &st) != 0) + return EBADF; + if (S_ISFIFO (st.st_mode)) + return ESPIPE; + if (! S_ISREG (st.st_mode)) + return ENODEV; + + if (len == 0) + { + /* This is racy, but there is no good way to satisfy a + zero-length allocation request. */ + if (st.st_size < offset) + { + int ret = __ftruncate64 (fd, offset); + + if (ret != 0) + ret = errno; + return ret; + } + return 0; + } + + /* Minimize data transfer for network file systems, by issuing + single-byte write requests spaced by the file system block size. + (Most local file systems have fallocate support, so this fallback + code is not used there.) */ + + unsigned increment; + { + struct statfs64 f; + + if (__fstatfs64 (fd, &f) != 0) + return errno; + if (f.f_bsize == 0) + increment = 512; + else if (f.f_bsize < 4096) + increment = f.f_bsize; + else + /* NFS clients do not propagate the block size of the underlying + storage and may report a much larger value which would still + leave holes after the loop below, so we cap the increment at + 4096. */ + increment = 4096; + } + + /* Write a null byte to every block. This is racy; we currently + lack a better option. Compare-and-swap against a file mapping + might address local races, but requires interposition of a signal + handler to catch SIGBUS. */ + for (offset += (len - 1) % increment; len > 0; offset += increment) + { + len -= increment; + + if (offset < st.st_size) + { + unsigned char c; + ssize_t rsize = __libc_pread64 (fd, &c, 1, offset); + + if (rsize < 0) + return errno; + /* If there is a non-zero byte, the block must have been + allocated already. */ + else if (rsize == 1 && c != 0) + continue; + } + + if (__libc_pwrite64 (fd, "", 1, offset) != 1) + return errno; + } + + return 0; +} + +#undef __posix_fallocate64_l64 +#include <shlib-compat.h> +#include <bits/wordsize.h> + +#if __WORDSIZE == 32 && SHLIB_COMPAT(libc, GLIBC_2_2, GLIBC_2_3_3) + +int +attribute_compat_text_section +__posix_fallocate64_l32 (int fd, off64_t offset, size_t len) +{ + return __posix_fallocate64_l64 (fd, offset, len); +} + +versioned_symbol (libc, __posix_fallocate64_l64, posix_fallocate64, + GLIBC_2_3_3); +compat_symbol (libc, __posix_fallocate64_l32, posix_fallocate64, GLIBC_2_2); +#else +strong_alias (__posix_fallocate64_l64, posix_fallocate64); +#endif diff --git a/REORG.TODO/sysdeps/posix/pread.c b/REORG.TODO/sysdeps/posix/pread.c new file mode 100644 index 0000000000..82d6d9c7d9 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pread.c @@ -0,0 +1,62 @@ +/* Read block from given position in file without changing file pointer. + POSIX version. + Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> + +/* Note: This implementation of pread is not multithread-safe. */ + +ssize_t +__libc_pread (int fd, void *buf, size_t nbyte, off_t offset) +{ + /* Since we must not change the file pointer preserve the value so that + we can restore it later. */ + int save_errno; + ssize_t result; + off_t old_offset = __libc_lseek (fd, 0, SEEK_CUR); + if (old_offset == (off_t) -1) + return -1; + + /* Set to wanted position. */ + if (__libc_lseek (fd, offset, SEEK_SET) == (off_t) -1) + return -1; + + /* Write out the data. */ + result = __libc_read (fd, buf, nbyte); + + /* Now we have to restore the position. If this fails we have to + return this as an error. But if the writing also failed we + return this error. */ + save_errno = errno; + if (__libc_lseek (fd, old_offset, SEEK_SET) == (off_t) -1) + { + if (result == -1) + __set_errno (save_errno); + return -1; + } + __set_errno (save_errno); + + return result; +} + +#ifndef __libc_pread +strong_alias (__libc_pread, __pread) +weak_alias (__libc_pread, pread) +#endif diff --git a/REORG.TODO/sysdeps/posix/pread64.c b/REORG.TODO/sysdeps/posix/pread64.c new file mode 100644 index 0000000000..f28ef31329 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pread64.c @@ -0,0 +1,62 @@ +/* Read block from given position in file without changing file pointer. + POSIX version. + Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> + +/* Note: This implementation of pread64 is not multithread-safe. */ + +ssize_t +__libc_pread64 (int fd, void *buf, size_t nbyte, off64_t offset) +{ + /* Since we must not change the file pointer preserve the value so that + we can restore it later. */ + int save_errno; + ssize_t result; + off64_t old_offset = __libc_lseek64 (fd, 0, SEEK_CUR); + if (old_offset == (off64_t) -1) + return -1; + + /* Set to wanted position. */ + if (__libc_lseek64 (fd, offset, SEEK_SET) == (off64_t) -1) + return -1; + + /* Write out the data. */ + result = __libc_read (fd, buf, nbyte); + + /* Now we have to restore the position. If this fails we have to + return this as an error. But if the writing also failed we + return this error. */ + save_errno = errno; + if (__libc_lseek64 (fd, old_offset, SEEK_SET) == (off64_t) -1) + { + if (result == -1) + __set_errno (save_errno); + return -1; + } + __set_errno (save_errno); + + return result; +} + +#ifndef __libc_pread64 +weak_alias (__libc_pread64, __pread64) +weak_alias (__libc_pread64, pread64) +#endif diff --git a/REORG.TODO/sysdeps/posix/preadv.c b/REORG.TODO/sysdeps/posix/preadv.c new file mode 100644 index 0000000000..7819a938a1 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/preadv.c @@ -0,0 +1,30 @@ +/* Read data into multiple buffers. Generic version. + Copyright (C) 2009-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/types.h> + +#ifndef __OFF_T_MATCHES_OFF64_T + +# define PREADV preadv +# define PREAD __pread +# define OFF_T off_t +# include <sysdeps/posix/preadv_common.c> + +libc_hidden_def (preadv) + +#endif diff --git a/REORG.TODO/sysdeps/posix/preadv2.c b/REORG.TODO/sysdeps/posix/preadv2.c new file mode 100644 index 0000000000..2a7cf11e27 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/preadv2.c @@ -0,0 +1,38 @@ +/* Generic version of preadv2. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <sys/uio.h> + +#ifndef __OFF_T_MATCHES_OFF64_T + +/* Since we define no flags for preadv2 just route to preadv. */ +ssize_t +preadv2 (int fd, const struct iovec *vector, int count, OFF_T offset, + int flags) +{ + if (flags != 0) + { + __set_errno (EOPNOTSUPP); + return -1; + } + + return preadv (fd, vector, count, offset); +} + +#endif diff --git a/REORG.TODO/sysdeps/posix/preadv64.c b/REORG.TODO/sysdeps/posix/preadv64.c new file mode 100644 index 0000000000..374b5bc45c --- /dev/null +++ b/REORG.TODO/sysdeps/posix/preadv64.c @@ -0,0 +1,28 @@ +/* Read data into multiple buffers. Generic LFS version. + Copyright (C) 2009-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define PREADV preadv64 +#define PREAD __pread64 +#define OFF_T off64_t +#include <sysdeps/posix/preadv_common.c> + +libc_hidden_def (preadv64) +#ifdef __OFF_T_MATCHES_OFF64_T +strong_alias (preadv64, preadv) +libc_hidden_def (preadv) +#endif diff --git a/REORG.TODO/sysdeps/posix/preadv64v2.c b/REORG.TODO/sysdeps/posix/preadv64v2.c new file mode 100644 index 0000000000..e084f3f9e1 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/preadv64v2.c @@ -0,0 +1,37 @@ +/* Generic version of preadv2. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.> +#include <sys/uio.h> + +ssize_t +preadv64v2 (int fd, const struct iovec *vector, int count, OFF_T offset, + int flags) +{ + if (flags != 0) + { + __set_errno (EOPNOTSUPP); + return -1; + } + + return preadv64 (fd, vector, count, offset); +} + +#ifdef __OFF_T_MATCHES_OFF64_T +strong_alias (preadv64v2, preadv2) +#endif diff --git a/REORG.TODO/sysdeps/posix/preadv_common.c b/REORG.TODO/sysdeps/posix/preadv_common.c new file mode 100644 index 0000000000..37efdc0ec0 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/preadv_common.c @@ -0,0 +1,83 @@ +/* Read data into multiple buffers. Base implementation for preadv + and preadv64. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <sys/uio.h> +#include <sys/param.h> +#include <errno.h> +#include <malloc.h> + +#include <ldsodefs.h> + +/* Read data from file descriptor FD at the given position OFFSET + without change the file pointer, and put the result in the buffers + described by VECTOR, which is a vector of COUNT 'struct iovec's. + The buffers are filled in the order specified. Operates just like + 'pread' (see <unistd.h>) except that data are put in VECTOR instead + of a contiguous buffer. */ +ssize_t +PREADV (int fd, const struct iovec *vector, int count, OFF_T offset) +{ + /* Find the total number of bytes to be read. */ + size_t bytes = 0; + for (int i = 0; i < count; ++i) + { + /* Check for ssize_t overflow. */ + if (SSIZE_MAX - bytes < vector[i].iov_len) + { + __set_errno (EINVAL); + return -1; + } + bytes += vector[i].iov_len; + } + + /* Allocate a temporary buffer to hold the data. It could be done with a + stack allocation, but due limitations on some system (Linux with + O_DIRECT) it aligns the buffer to pagesize. A possible optimization + would be querying if the syscall would impose any alignment constraint, + but 1. it is system specific (not meant in generic implementation), and + 2. it would make the implementation more complex, and 3. it will require + another syscall (fcntl). */ + void *buffer = NULL; + if (__posix_memalign (&buffer, GLRO(dl_pagesize), bytes) != 0) + return -1; + + ssize_t bytes_read = PREAD (fd, buffer, bytes, offset); + if (bytes_read < 0) + goto end; + + /* Copy the data from BUFFER into the memory specified by VECTOR. */ + bytes = bytes_read; + void *buf = buffer; + for (int i = 0; i < count; ++i) + { + size_t copy = MIN (vector[i].iov_len, bytes); + + memcpy (vector[i].iov_base, buf, copy); + + buf += copy; + bytes -= copy; + if (bytes == 0) + break; + } + +end: + free (buffer); + return bytes_read; +} diff --git a/REORG.TODO/sysdeps/posix/profil.c b/REORG.TODO/sysdeps/posix/profil.c new file mode 100644 index 0000000000..4d3fbe0b8a --- /dev/null +++ b/REORG.TODO/sysdeps/posix/profil.c @@ -0,0 +1,120 @@ +/* Low-level statistical profiling support function. Mostly POSIX.1 version. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include <sys/time.h> +#include <libc-internal.h> +#include <sigsetops.h> + +#ifndef SIGPROF + +#include <gmon/profil.c> + +#else + +static u_short *samples; +static size_t nsamples; +static size_t pc_offset; +static u_int pc_scale; + +static inline void +profil_count (void *pc) +{ + size_t i = (pc - pc_offset - (void *) 0) / 2; + + if (sizeof (unsigned long long int) > sizeof (size_t)) + i = (unsigned long long int) i * pc_scale / 65536; + else + i = i / 65536 * pc_scale + i % 65536 * pc_scale / 65536; + + if (i < nsamples) + ++samples[i]; +} + +/* Get the machine-dependent definition of `__profil_counter', the signal + handler for SIGPROF. It calls `profil_count' (above) with the PC of the + interrupted code. */ +#include "profil-counter.h" + +/* Enable statistical profiling, writing samples of the PC into at most + SIZE bytes of SAMPLE_BUFFER; every processor clock tick while profiling + is enabled, the system examines the user PC and increments + SAMPLE_BUFFER[((PC - OFFSET) / 2) * SCALE / 65536]. If SCALE is zero, + disable profiling. Returns zero on success, -1 on error. */ + +int +__profil (u_short *sample_buffer, size_t size, size_t offset, u_int scale) +{ + struct sigaction act; + struct itimerval timer; +#if !IS_IN (rtld) + static struct sigaction oact; + static struct itimerval otimer; +# define oact_ptr &oact +# define otimer_ptr &otimer + + if (sample_buffer == NULL) + { + /* Disable profiling. */ + if (samples == NULL) + /* Wasn't turned on. */ + return 0; + + if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0) + return -1; + samples = NULL; + return __sigaction (SIGPROF, &oact, NULL); + } + + if (samples) + { + /* Was already turned on. Restore old timer and signal handler + first. */ + if (__setitimer (ITIMER_PROF, &otimer, NULL) < 0 + || __sigaction (SIGPROF, &oact, NULL) < 0) + return -1; + } +#else + /* In ld.so profiling should never be disabled once it runs. */ + //assert (sample_buffer != NULL); +# define oact_ptr NULL +# define otimer_ptr NULL +#endif + + samples = sample_buffer; + nsamples = size / sizeof *samples; + pc_offset = offset; + pc_scale = scale; + + act.sa_handler = (sighandler_t) &__profil_counter; + act.sa_flags = SA_RESTART; + __sigfillset (&act.sa_mask); + if (__sigaction (SIGPROF, &act, oact_ptr) < 0) + return -1; + + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = 1000000 / __profile_frequency (); + timer.it_interval = timer.it_value; + return __setitimer (ITIMER_PROF, &timer, otimer_ptr); +} +weak_alias (__profil, profil) + +#endif diff --git a/REORG.TODO/sysdeps/posix/pwrite.c b/REORG.TODO/sysdeps/posix/pwrite.c new file mode 100644 index 0000000000..764e9172be --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pwrite.c @@ -0,0 +1,62 @@ +/* Write block to given position in file without changing file pointer. + POSIX version. + Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> + +/* Note: This implementation of pwrite is not multithread-safe. */ + +ssize_t +__libc_pwrite (int fd, const void *buf, size_t nbyte, off_t offset) +{ + /* Since we must not change the file pointer preserve the value so that + we can restore it later. */ + int save_errno; + ssize_t result; + off_t old_offset = __libc_lseek (fd, 0, SEEK_CUR); + if (old_offset == (off_t) -1) + return -1; + + /* Set to wanted position. */ + if (__libc_lseek (fd, offset, SEEK_SET) == (off_t) -1) + return -1; + + /* Write out the data. */ + result = __libc_write (fd, buf, nbyte); + + /* Now we have to restore the position. If this fails we have to + return this as an error. But if the writing also failed we + return this error. */ + save_errno = errno; + if (__libc_lseek (fd, old_offset, SEEK_SET) == (off_t) -1) + { + if (result == -1) + __set_errno (save_errno); + return -1; + } + __set_errno (save_errno); + + return result; +} + +#ifndef __libc_pwrite +strong_alias (__libc_pwrite, __pwrite) +weak_alias (__libc_pwrite, pwrite) +#endif diff --git a/REORG.TODO/sysdeps/posix/pwrite64.c b/REORG.TODO/sysdeps/posix/pwrite64.c new file mode 100644 index 0000000000..601a268f59 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pwrite64.c @@ -0,0 +1,62 @@ +/* Write block to given position in file without changing file pointer. + POSIX version. + Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <unistd.h> + +/* Note: This implementation of pwrite64 is not multithread-safe. */ + +ssize_t +__libc_pwrite64 (int fd, const void *buf, size_t nbyte, off64_t offset) +{ + /* Since we must not change the file pointer preserve the value so that + we can restore it later. */ + int save_errno; + ssize_t result; + off64_t old_offset = __libc_lseek64 (fd, 0, SEEK_CUR); + if (old_offset == (off64_t) -1) + return -1; + + /* Set to wanted position. */ + if (__libc_lseek64 (fd, offset, SEEK_SET) == (off64_t) -1) + return -1; + + /* Write out the data. */ + result = __libc_write (fd, buf, nbyte); + + /* Now we have to restore the position. If this fails we have to + return this as an error. But if the writing also failed we + return this error. */ + save_errno = errno; + if (__libc_lseek64 (fd, old_offset, SEEK_SET) == (off64_t) -1) + { + if (result == -1) + __set_errno (save_errno); + return -1; + } + __set_errno (save_errno); + + return result; +} +#ifndef __libc_pwrite64 +weak_alias (__libc_pwrite64, __pwrite64) +libc_hidden_weak (__pwrite64) +weak_alias (__libc_pwrite64, pwrite64) +#endif diff --git a/REORG.TODO/sysdeps/posix/pwritev.c b/REORG.TODO/sysdeps/posix/pwritev.c new file mode 100644 index 0000000000..f9de092aa5 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pwritev.c @@ -0,0 +1,30 @@ +/* Write data into multiple buffers. Generic version. + Copyright (C) 2009-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/types.h> + +#ifndef __OFF_T_MATCHES_OFF64_T + +# define PWRITEV pwritev +# define PWRITE __pwrite +# define OFF_T off_t +# include <sysdeps/posix/pwritev_common.c> + +libc_hidden_def (pwritev) + +#endif diff --git a/REORG.TODO/sysdeps/posix/pwritev2.c b/REORG.TODO/sysdeps/posix/pwritev2.c new file mode 100644 index 0000000000..5b7650c4fc --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pwritev2.c @@ -0,0 +1,38 @@ +/* Generic version of pwritev2. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <sys/uio.h> + +#ifndef __OFF_T_MATCHES_OFF64_T + +/* Since we define no flags for pwritev2 just route to pwritev. */ +ssize_t +pwritev2 (int fd, const struct iovec *vector, int count, OFF_T offset, + int flags) +{ + if (flags != 0) + { + __set_errno (EOPNOTSUPP); + return -1; + } + + return pwritev (fd, vector, count, offset); +} + +#endif diff --git a/REORG.TODO/sysdeps/posix/pwritev64.c b/REORG.TODO/sysdeps/posix/pwritev64.c new file mode 100644 index 0000000000..c5392f7836 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pwritev64.c @@ -0,0 +1,28 @@ +/* Write data into multiple buffers. Generic LFS version. + Copyright (C) 2009-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define PWRITEV pwritev64 +#define PWRITE __pwrite64 +#define OFF_T off64_t +#include <sysdeps/posix/pwritev_common.c> + +libc_hidden_def (pwritev64) +#ifdef __OFF_T_MATCHES_OFF64_T +strong_alias (pwritev64, pwritev) +libc_hidden_def (pwritev) +#endif diff --git a/REORG.TODO/sysdeps/posix/pwritev64v2.c b/REORG.TODO/sysdeps/posix/pwritev64v2.c new file mode 100644 index 0000000000..0f2f9ef863 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pwritev64v2.c @@ -0,0 +1,38 @@ +/* Generic version of pwritev2. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <sys/uio.h> + +/* Since we define no flags for pwritev2 just route to pwritev. */ +ssize_t +pwritev64v2 (int fd, const struct iovec *vector, int count, OFF_T offset, + int flags) +{ + if (flags != 0) + { + __set_errno (EOPNOTSUPP); + return -1; + } + + return pwritev64 (fd, vector, count, offset); +} + +#ifdef __OFF_T_MATCHES_OFF64_T +strong_alias (pwritev64v2, pwritev2) +#endif diff --git a/REORG.TODO/sysdeps/posix/pwritev_common.c b/REORG.TODO/sysdeps/posix/pwritev_common.c new file mode 100644 index 0000000000..03830650e4 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/pwritev_common.c @@ -0,0 +1,72 @@ +/* Write data into multiple buffers. Base implementation for pwritev + and pwritev64. + Copyright (C) 2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> +#include <sys/uio.h> +#include <sys/param.h> +#include <errno.h> +#include <malloc.h> + +#include <ldsodefs.h> + +/* Write data pointed by the buffers described by IOVEC, which is a + vector of COUNT 'struct iovec's, to file descriptor FD at the given + position OFFSET without change the file pointer. The data is + written in the order specified. Operates just like 'write' (see + <unistd.h>) except that the data are taken from IOVEC instead of a + contiguous buffer. */ +ssize_t +PWRITEV (int fd, const struct iovec *vector, int count, OFF_T offset) +{ + /* Find the total number of bytes to be read. */ + size_t bytes = 0; + for (int i = 0; i < count; ++i) + { + /* Check for ssize_t overflow. */ + if (SSIZE_MAX - bytes < vector[i].iov_len) + { + __set_errno (EINVAL); + return -1; + } + bytes += vector[i].iov_len; + } + + /* Allocate a temporary buffer to hold the data. It could be done with a + stack allocation, but due limitations on some system (Linux with + O_DIRECT) it aligns the buffer to pagesize. A possible optimization + would be querying if the syscall would impose any alignment constraint, + but 1. it is system specific (not meant in generic implementation), and + 2. it would make the implementation more complex, and 3. it will require + another syscall (fcntl). */ + void *buffer = NULL; + if (__posix_memalign (&buffer, GLRO(dl_pagesize), bytes) != 0) + return -1; + + /* Copy the data from BUFFER into the memory specified by VECTOR. */ + char *ptr = buffer; + for (int i = 0; i < count; ++i) + ptr = __mempcpy ((void *) ptr, (void *) vector[i].iov_base, + vector[i].iov_len); + + ssize_t ret = PWRITE (fd, buffer, bytes, offset); + + free (buffer); + + return ret; +} diff --git a/REORG.TODO/sysdeps/posix/raise.c b/REORG.TODO/sysdeps/posix/raise.c new file mode 100644 index 0000000000..6660144e5f --- /dev/null +++ b/REORG.TODO/sysdeps/posix/raise.c @@ -0,0 +1,28 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <signal.h> +#include <unistd.h> + +/* Raise the signal SIG. */ +int +raise (int sig) +{ + return __kill (__getpid (), sig); +} +libc_hidden_def (raise) +weak_alias (raise, gsignal) diff --git a/REORG.TODO/sysdeps/posix/readdir.c b/REORG.TODO/sysdeps/posix/readdir.c new file mode 100644 index 0000000000..8e9384d472 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/readdir.c @@ -0,0 +1,122 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <string.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/types.h> +#include <assert.h> + +#include <dirstream.h> + +#ifndef __READDIR +# define __READDIR __readdir +# define __GETDENTS __getdents +# define DIRENT_TYPE struct dirent +# define __READDIR_ALIAS +#endif + +/* Read a directory entry from DIRP. */ +DIRENT_TYPE * +__READDIR (DIR *dirp) +{ + DIRENT_TYPE *dp; + int saved_errno = errno; + +#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +#endif + + do + { + size_t reclen; + + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ + + size_t maxread; + ssize_t bytes; + +#ifndef _DIRENT_HAVE_D_RECLEN + /* Fixed-size struct; must read one at a time (see below). */ + maxread = sizeof *dp; +#else + maxread = dirp->allocation; +#endif + + bytes = __GETDENTS (dirp->fd, dirp->data, maxread); + if (bytes <= 0) + { + /* On some systems getdents fails with ENOENT when the + open directory has been rmdir'd already. POSIX.1 + requires that we treat this condition like normal EOF. */ + if (bytes < 0 && errno == ENOENT) + bytes = 0; + + /* Don't modifiy errno when reaching EOF. */ + if (bytes == 0) + __set_errno (saved_errno); + dp = NULL; + break; + } + dirp->size = (size_t) bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + dp = (DIRENT_TYPE *) &dirp->data[dirp->offset]; + +#ifdef _DIRENT_HAVE_D_RECLEN + reclen = dp->d_reclen; +#else + /* The only version of `struct dirent*' that lacks `d_reclen' + is fixed-size. */ + assert (sizeof dp->d_name > 1); + reclen = sizeof *dp; + /* The name is not terminated if it is the largest possible size. + Clobber the following byte to ensure proper null termination. We + read jst one entry at a time above so we know that byte will not + be used later. */ + dp->d_name[sizeof dp->d_name] = '\0'; +#endif + + dirp->offset += reclen; + +#ifdef _DIRENT_HAVE_D_OFF + dirp->filepos = dp->d_off; +#else + dirp->filepos += reclen; +#endif + + /* Skip deleted files. */ + } while (dp->d_ino == 0); + +#if IS_IN (libc) + __libc_lock_unlock (dirp->lock); +#endif + + return dp; +} + +#ifdef __READDIR_ALIAS +weak_alias (__readdir, readdir) +#endif diff --git a/REORG.TODO/sysdeps/posix/readdir_r.c b/REORG.TODO/sysdeps/posix/readdir_r.c new file mode 100644 index 0000000000..4da2369d8b --- /dev/null +++ b/REORG.TODO/sysdeps/posix/readdir_r.c @@ -0,0 +1,154 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <string.h> +#include <dirent.h> +#include <unistd.h> +#include <sys/types.h> +#include <assert.h> + +#include <dirstream.h> + +#ifndef __READDIR_R +# define __READDIR_R __readdir_r +# define __GETDENTS __getdents +# define DIRENT_TYPE struct dirent +# define __READDIR_R_ALIAS +#endif + +/* Read a directory entry from DIRP. */ +int +__READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) +{ + DIRENT_TYPE *dp; + size_t reclen; + const int saved_errno = errno; + int ret; + + __libc_lock_lock (dirp->lock); + + do + { + if (dirp->offset >= dirp->size) + { + /* We've emptied out our buffer. Refill it. */ + + size_t maxread; + ssize_t bytes; + +#ifndef _DIRENT_HAVE_D_RECLEN + /* Fixed-size struct; must read one at a time (see below). */ + maxread = sizeof *dp; +#else + maxread = dirp->allocation; +#endif + + bytes = __GETDENTS (dirp->fd, dirp->data, maxread); + if (bytes <= 0) + { + /* On some systems getdents fails with ENOENT when the + open directory has been rmdir'd already. POSIX.1 + requires that we treat this condition like normal EOF. */ + if (bytes < 0 && errno == ENOENT) + { + bytes = 0; + __set_errno (saved_errno); + } + if (bytes < 0) + dirp->errcode = errno; + + dp = NULL; + break; + } + dirp->size = (size_t) bytes; + + /* Reset the offset into the buffer. */ + dirp->offset = 0; + } + + dp = (DIRENT_TYPE *) &dirp->data[dirp->offset]; + +#ifdef _DIRENT_HAVE_D_RECLEN + reclen = dp->d_reclen; +#else + /* The only version of `struct dirent*' that lacks `d_reclen' + is fixed-size. */ + assert (sizeof dp->d_name > 1); + reclen = sizeof *dp; + /* The name is not terminated if it is the largest possible size. + Clobber the following byte to ensure proper null termination. We + read just one entry at a time above so we know that byte will not + be used later. */ + dp->d_name[sizeof dp->d_name] = '\0'; +#endif + + dirp->offset += reclen; + +#ifdef _DIRENT_HAVE_D_OFF + dirp->filepos = dp->d_off; +#else + dirp->filepos += reclen; +#endif + +#ifdef NAME_MAX + if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1) + { + /* The record is very long. It could still fit into the + caller-supplied buffer if we can skip padding at the + end. */ + size_t namelen = _D_EXACT_NAMLEN (dp); + if (namelen <= NAME_MAX) + reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1; + else + { + /* The name is too long. Ignore this file. */ + dirp->errcode = ENAMETOOLONG; + dp->d_ino = 0; + continue; + } + } +#endif + + /* Skip deleted and ignored files. */ + } + while (dp->d_ino == 0); + + if (dp != NULL) + { + *result = memcpy (entry, dp, reclen); +#ifdef _DIRENT_HAVE_D_RECLEN + entry->d_reclen = reclen; +#endif + ret = 0; + } + else + { + *result = NULL; + ret = dirp->errcode; + } + + __libc_lock_unlock (dirp->lock); + + return ret; +} + +#ifdef __READDIR_R_ALIAS +weak_alias (__readdir_r, readdir_r) +#endif diff --git a/REORG.TODO/sysdeps/posix/readv.c b/REORG.TODO/sysdeps/posix/readv.c new file mode 100644 index 0000000000..5b0c124e89 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/readv.c @@ -0,0 +1,91 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> +#include <stdbool.h> +#include <sys/param.h> +#include <sys/uio.h> +#include <errno.h> + + +static void +ifree (char **ptrp) +{ + free (*ptrp); +} + +/* Read data from file descriptor FD, and put the result in the + buffers described by VECTOR, which is a vector of COUNT 'struct iovec's. + The buffers are filled in the order specified. + Operates just like 'read' (see <unistd.h>) except that data are + put in VECTOR instead of a contiguous buffer. */ +ssize_t +__readv (int fd, const struct iovec *vector, int count) +{ + /* Find the total number of bytes to be read. */ + size_t bytes = 0; + for (int i = 0; i < count; ++i) + { + /* Check for ssize_t overflow. */ + if (SSIZE_MAX - bytes < vector[i].iov_len) + { + __set_errno (EINVAL); + return -1; + } + bytes += vector[i].iov_len; + } + + /* Allocate a temporary buffer to hold the data. We should normally + use alloca since it's faster and does not require synchronization + with other threads. But we cannot if the amount of memory + required is too large. */ + char *buffer; + char *malloced_buffer __attribute__ ((__cleanup__ (ifree))) = NULL; + if (__libc_use_alloca (bytes)) + buffer = (char *) __alloca (bytes); + else + { + malloced_buffer = buffer = (char *) malloc (bytes); + if (buffer == NULL) + return -1; + } + + /* Read the data. */ + ssize_t bytes_read = __read (fd, buffer, bytes); + if (bytes_read < 0) + return -1; + + /* Copy the data from BUFFER into the memory specified by VECTOR. */ + bytes = bytes_read; + for (int i = 0; i < count; ++i) + { + size_t copy = MIN (vector[i].iov_len, bytes); + + (void) memcpy ((void *) vector[i].iov_base, (void *) buffer, copy); + + buffer += copy; + bytes -= copy; + if (bytes == 0) + break; + } + + return bytes_read; +} +weak_alias (__readv, readv) diff --git a/REORG.TODO/sysdeps/posix/remove.c b/REORG.TODO/sysdeps/posix/remove.c new file mode 100644 index 0000000000..1901622270 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/remove.c @@ -0,0 +1,43 @@ +/* ANSI C `remove' function to delete a file or directory. POSIX.1 version. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> + + +#ifndef IS_NO_DIRECTORY_ERROR +# define IS_NO_DIRECTORY_ERROR errno != EPERM +#endif + + +int +remove (const char *file) +{ + /* First try to unlink since this is more frequently the necessary action. */ + if (__unlink (file) != 0 + /* If it is indeed a directory... */ + && (IS_NO_DIRECTORY_ERROR + /* ...try to remove it. */ + || __rmdir (file) != 0)) + /* Cannot remove the object for whatever reason. */ + return -1; + + return 0; +} +libc_hidden_def (remove) diff --git a/REORG.TODO/sysdeps/posix/rename.c b/REORG.TODO/sysdeps/posix/rename.c new file mode 100644 index 0000000000..e5f721f366 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/rename.c @@ -0,0 +1,48 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> + +/* Rename the file OLD to NEW. */ +int +rename (const char *old, const char *new) +{ + int save = errno; + if (__link (old, new) < 0) + { + if (errno == EEXIST) + { + __set_errno (save); + /* Race condition, required for 1003.1 conformance. */ + if (__unlink (new) < 0 || + __link (old, new) < 0) + return -1; + } + else + return -1; + } + if (__unlink (old) < 0) + { + save = errno; + if (__unlink (new) == 0) + __set_errno (save); + return -1; + } + return 0; +} diff --git a/REORG.TODO/sysdeps/posix/rewinddir.c b/REORG.TODO/sysdeps/posix/rewinddir.c new file mode 100644 index 0000000000..06fa612382 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/rewinddir.c @@ -0,0 +1,41 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> +#include <dirent.h> +#include <sys/types.h> +#include <unistd.h> +#include <dirstream.h> + +/* Rewind DIRP to the beginning of the directory. */ +void +__rewinddir (DIR *dirp) +{ +#if IS_IN (libc) + __libc_lock_lock (dirp->lock); +#endif + (void) __lseek (dirp->fd, (off_t) 0, SEEK_SET); + dirp->filepos = 0; + dirp->offset = 0; + dirp->size = 0; + dirp->errcode = 0; +#if IS_IN (libc) + __libc_lock_unlock (dirp->lock); +#endif +} +libc_hidden_def (__rewinddir) +weak_alias (__rewinddir, rewinddir) diff --git a/REORG.TODO/sysdeps/posix/seekdir.c b/REORG.TODO/sysdeps/posix/seekdir.c new file mode 100644 index 0000000000..1f37525061 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/seekdir.c @@ -0,0 +1,35 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stddef.h> +#include <dirent.h> +#include <unistd.h> +#include <dirstream.h> + +/* Seek to position POS in DIRP. */ +/* XXX should be __seekdir ? */ +void +seekdir (DIR *dirp, long int pos) +{ + __libc_lock_lock (dirp->lock); + (void) __lseek (dirp->fd, pos, SEEK_SET); + dirp->size = 0; + dirp->offset = 0; + dirp->filepos = pos; + __libc_lock_unlock (dirp->lock); +} diff --git a/REORG.TODO/sysdeps/posix/shm-directory.c b/REORG.TODO/sysdeps/posix/shm-directory.c new file mode 100644 index 0000000000..f64e02614d --- /dev/null +++ b/REORG.TODO/sysdeps/posix/shm-directory.c @@ -0,0 +1,38 @@ +/* Determine directory for shm/sem files. Generic POSIX version. + Copyright (C) 2014-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <shm-directory.h> +#include <unistd.h> + +#if _POSIX_MAPPED_FILES + +# include <paths.h> + +# define SHMDIR (_PATH_DEV "shm/") + +const char * +__shm_directory (size_t *len) +{ + *len = sizeof SHMDIR - 1; + return SHMDIR; +} +# if IS_IN (libpthread) +hidden_def (__shm_directory) +# endif + +#endif diff --git a/REORG.TODO/sysdeps/posix/shm-directory.h b/REORG.TODO/sysdeps/posix/shm-directory.h new file mode 100644 index 0000000000..5c70e1a71e --- /dev/null +++ b/REORG.TODO/sysdeps/posix/shm-directory.h @@ -0,0 +1,66 @@ +/* Header for directory for shm/sem files. + Copyright (C) 2014-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#ifndef _SHM_DIRECTORY_H + +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> + +extern const char *__shm_directory (size_t *len); + +/* This defines local variables SHM_DIR and SHM_DIRLEN, giving the + directory prefix (with trailing slash) and length (not including '\0' + terminator) of the directory used for shm files. If that cannot be + determined, it sets errno to ENOSYS and returns RETVAL_FOR_INVALID. + + This uses the local variable NAME as an lvalue, and increments it past + any leading slashes. It then defines the local variable NAMELEN, giving + strlen (NAME) + 1. If NAME is invalid, it sets errno to + ERRNO_FOR_INVALID and returns RETVAL_FOR_INVALID. Finally, it defines + the local variable SHM_NAME, giving the absolute file name of the shm + file corresponding to NAME. PREFIX is a string constant used as a + prefix on NAME. */ + +#define SHM_GET_NAME(errno_for_invalid, retval_for_invalid, prefix) \ + size_t shm_dirlen; \ + const char *shm_dir = __shm_directory (&shm_dirlen); \ + /* If we don't know what directory to use, there is nothing we can do. */ \ + if (__glibc_unlikely (shm_dir == NULL)) \ + { \ + __set_errno (ENOSYS); \ + return retval_for_invalid; \ + } \ + /* Construct the filename. */ \ + while (name[0] == '/') \ + ++name; \ + size_t namelen = strlen (name) + 1; \ + /* Validate the filename. */ \ + if (namelen == 1 || namelen >= NAME_MAX || strchr (name, '/') != NULL) \ + { \ + __set_errno (errno_for_invalid); \ + return retval_for_invalid; \ + } \ + char *shm_name = __alloca (shm_dirlen + sizeof prefix - 1 + namelen); \ + __mempcpy (__mempcpy (__mempcpy (shm_name, shm_dir, shm_dirlen), \ + prefix, sizeof prefix - 1), \ + name, namelen) + +#endif /* shm-directory.h */ diff --git a/REORG.TODO/sysdeps/posix/shm_open.c b/REORG.TODO/sysdeps/posix/shm_open.c new file mode 100644 index 0000000000..64315de8f8 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/shm_open.c @@ -0,0 +1,55 @@ +/* shm_open -- open a POSIX shared memory object. Generic POSIX file version. + Copyright (C) 2001-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + +#if ! _POSIX_MAPPED_FILES + +# include <rt/shm_open.c> + +#else + +# include <fcntl.h> +# include <shm-directory.h> + + +/* Open shared memory object. */ +int +shm_open (const char *name, int oflag, mode_t mode) +{ + SHM_GET_NAME (EINVAL, -1, ""); + + oflag |= O_NOFOLLOW | O_CLOEXEC; + + /* Disable asynchronous cancellation. */ + int state; + pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state); + + int fd = open (shm_name, oflag, mode); + if (fd == -1 && __glibc_unlikely (errno == EISDIR)) + /* It might be better to fold this error with EINVAL since + directory names are just another example for unsuitable shared + object names and the standard does not mention EISDIR. */ + __set_errno (EINVAL); + + pthread_setcancelstate (state, NULL); + + return fd; +} + +#endif /* _POSIX_MAPPED_FILES */ diff --git a/REORG.TODO/sysdeps/posix/shm_unlink.c b/REORG.TODO/sysdeps/posix/shm_unlink.c new file mode 100644 index 0000000000..1d573d2a41 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/shm_unlink.c @@ -0,0 +1,43 @@ +/* shm_unlink -- remove a POSIX shared memory object. Generic POSIX version. + Copyright (C) 2001-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <unistd.h> + +#if ! _POSIX_MAPPED_FILES +#include <rt/shm_unlink.c> + +#else + +#include <errno.h> +#include <string.h> +#include "shm-directory.h" + + +/* Remove shared memory object. */ +int +shm_unlink (const char *name) +{ + SHM_GET_NAME (ENOENT, -1, ""); + + int result = unlink (shm_name); + if (result < 0 && errno == EPERM) + __set_errno (EACCES); + return result; +} + +#endif diff --git a/REORG.TODO/sysdeps/posix/sigblock.c b/REORG.TODO/sysdeps/posix/sigblock.c new file mode 100644 index 0000000000..1f8686458b --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sigblock.c @@ -0,0 +1,38 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> + +#include <sigset-cvt-mask.h> + +/* Block signals in MASK, returning the old mask. */ +int +__sigblock (int mask) +{ + sigset_t set, oset; + + if (sigset_set_old_mask (&set, mask) < 0) + return -1; + + if (__sigprocmask (SIG_BLOCK, &set, &oset) < 0) + return -1; + + return sigset_get_old_mask (&oset); +} + +weak_alias (__sigblock, sigblock) diff --git a/REORG.TODO/sysdeps/posix/sigignore.c b/REORG.TODO/sysdeps/posix/sigignore.c new file mode 100644 index 0000000000..601ae9685a --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sigignore.c @@ -0,0 +1,37 @@ +/* Set the disposition of SIG to SIG_IGN. + Copyright (C) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#define __need_NULL +#include <stddef.h> +#include <signal.h> +#include <string.h> /* For the real memset prototype. */ +#include <sigsetops.h> + +int +sigignore (int sig) +{ + struct sigaction act; + + act.sa_handler = SIG_IGN; + __sigemptyset (&act.sa_mask); + act.sa_flags = 0; + + return __sigaction (sig, &act, NULL); +} diff --git a/REORG.TODO/sysdeps/posix/sigintr.c b/REORG.TODO/sysdeps/posix/sigintr.c new file mode 100644 index 0000000000..a6202de6a9 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sigintr.c @@ -0,0 +1,55 @@ +/* Copyright (C) 1992-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> +#include <signal.h> +#include <errno.h> +#include <sigsetops.h> + +/* If INTERRUPT is nonzero, make signal SIG interrupt system calls + (causing them to fail with EINTR); if INTERRUPT is zero, make system + calls be restarted after signal SIG. */ +int +siginterrupt (int sig, int interrupt) +{ +#ifdef SA_RESTART + extern sigset_t _sigintr attribute_hidden; /* Defined in signal.c. */ + struct sigaction action; + + if (__sigaction (sig, (struct sigaction *) NULL, &action) < 0) + return -1; + + if (interrupt) + { + __sigaddset (&_sigintr, sig); + action.sa_flags &= ~SA_RESTART; + } + else + { + __sigdelset (&_sigintr, sig); + action.sa_flags |= SA_RESTART; + } + + if (__sigaction (sig, &action, (struct sigaction *) NULL) < 0) + return -1; + + return 0; +#else + __set_errno (ENOSYS); + return -1; +#endif +} diff --git a/REORG.TODO/sysdeps/posix/signal.c b/REORG.TODO/sysdeps/posix/signal.c new file mode 100644 index 0000000000..81ba17745d --- /dev/null +++ b/REORG.TODO/sysdeps/posix/signal.c @@ -0,0 +1,51 @@ +/* BSD-like signal function. + Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> +#include <string.h> /* For the real memset prototype. */ +#include <sigsetops.h> + +sigset_t _sigintr attribute_hidden; /* Set by siginterrupt. */ + +/* Set the handler for the signal SIG to HANDLER, + returning the old handler, or SIG_ERR on error. */ +__sighandler_t +__bsd_signal (int sig, __sighandler_t handler) +{ + struct sigaction act, oact; + + /* Check signal extents to protect __sigismember. */ + if (handler == SIG_ERR || sig < 1 || sig >= NSIG) + { + __set_errno (EINVAL); + return SIG_ERR; + } + + act.sa_handler = handler; + __sigemptyset (&act.sa_mask); + __sigaddset (&act.sa_mask, sig); + act.sa_flags = __sigismember (&_sigintr, sig) ? 0 : SA_RESTART; + if (__sigaction (sig, &act, &oact) < 0) + return SIG_ERR; + + return oact.sa_handler; +} +weak_alias (__bsd_signal, bsd_signal) +weak_alias (__bsd_signal, signal) +weak_alias (__bsd_signal, ssignal) diff --git a/REORG.TODO/sysdeps/posix/sigpause.c b/REORG.TODO/sysdeps/posix/sigpause.c new file mode 100644 index 0000000000..9038ed368d --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sigpause.c @@ -0,0 +1,89 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#define sigpause __rename_sigpause +#include <errno.h> +#include <signal.h> +#include <stddef.h> /* For NULL. */ +#include <sysdep-cancel.h> +#undef sigpause + +#include <sigset-cvt-mask.h> + +/* Set the mask of blocked signals to MASK, + wait for a signal to arrive, and then restore the mask. */ +static int +do_sigpause (int sig_or_mask, int is_sig) +{ + sigset_t set; + + if (is_sig != 0) + { + /* The modern X/Open implementation is requested. */ + if (__sigprocmask (0, NULL, &set) < 0 + || sigdelset (&set, sig_or_mask) < 0) + return -1; + } + else if (sigset_set_old_mask (&set, sig_or_mask) < 0) + return -1; + + /* Note the sigpause() is a cancellation point. But since we call + sigsuspend() which itself is a cancellation point we do not have + to do anything here. */ + return __sigsuspend (&set); +} + +int +__sigpause (int sig_or_mask, int is_sig) +{ + if (SINGLE_THREAD_P) + return do_sigpause (sig_or_mask, is_sig); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = do_sigpause (sig_or_mask, is_sig); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +libc_hidden_def (__sigpause) + +/* We have to provide a default version of this function since the + standards demand it. The version which is a bit more reasonable is + the BSD version. So make this the default. */ +int +__attribute__ ((weak)) +__default_sigpause (int mask) +{ + return __sigpause (mask, 0); +} +#undef sigpause +weak_alias (__default_sigpause, sigpause) +strong_alias (__default_sigpause, __libc_sigpause) + + +/* We have to provide a default version of this function since the + standards demand it. The version which is a bit more reasonable is + the BSD version. So make this the default. */ +int +__attribute__ ((weak)) +__xpg_sigpause (int sig) +{ + return __sigpause (sig, 1); +} +strong_alias (__xpg_sigpause, __libc___xpg_sigpause) diff --git a/REORG.TODO/sysdeps/posix/sigset.c b/REORG.TODO/sysdeps/posix/sigset.c new file mode 100644 index 0000000000..a4dfe0ae93 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sigset.c @@ -0,0 +1,75 @@ +/* Copyright (C) 1998-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#define __need_NULL +#include <stddef.h> +#include <signal.h> +#include <string.h> /* For the real memset prototype. */ +#include <sigsetops.h> + +/* Set the disposition for SIG. */ +__sighandler_t +sigset (int sig, __sighandler_t disp) +{ + struct sigaction act; + struct sigaction oact; + sigset_t set; + sigset_t oset; + + /* Check signal extents to protect __sigismember. */ + if (disp == SIG_ERR || sig < 1 || sig >= NSIG) + { + __set_errno (EINVAL); + return SIG_ERR; + } + + __sigemptyset (&set); + __sigaddset (&set, sig); + + if (disp == SIG_HOLD) + { + /* Add the signal to the current signal mask. */ + if (__sigprocmask (SIG_BLOCK, &set, &oset) < 0) + return SIG_ERR; + + /* If the signal was already blocked signal this to the caller. */ + if (__sigismember (&oset, sig)) + return SIG_HOLD; + + /* We need to determine whether a specific handler is installed. */ + if (__sigaction (sig, NULL, &oact) < 0) + return SIG_ERR; + + return oact.sa_handler; + } + else + { + act.sa_handler = disp; + __sigemptyset (&act.sa_mask); + act.sa_flags = 0; + if (__sigaction (sig, &act, &oact) < 0) + return SIG_ERR; + + /* Remove the signal from the current signal mask. */ + if (__sigprocmask (SIG_UNBLOCK, &set, &oset) < 0) + return SIG_ERR; + + /* If the signal was already blocked return SIG_HOLD. */ + return __sigismember (&oset, sig) ? SIG_HOLD : oact.sa_handler; + } +} diff --git a/REORG.TODO/sysdeps/posix/sigsetmask.c b/REORG.TODO/sysdeps/posix/sigsetmask.c new file mode 100644 index 0000000000..56c8358ad4 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sigsetmask.c @@ -0,0 +1,38 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> + +#include <sigset-cvt-mask.h> + +/* Set the mask of blocked signals to MASK, returning the old mask. */ +int +__sigsetmask (int mask) +{ + sigset_t set, oset; + + if (sigset_set_old_mask (&set, mask) < 0) + return -1; + + if (__sigprocmask (SIG_SETMASK, &set, &oset) < 0) + return -1; + + return sigset_get_old_mask (&oset); +} + +weak_alias (__sigsetmask, sigsetmask) diff --git a/REORG.TODO/sysdeps/posix/sigsuspend.c b/REORG.TODO/sysdeps/posix/sigsuspend.c new file mode 100644 index 0000000000..336a2e773e --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sigsuspend.c @@ -0,0 +1,51 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> +#include <stddef.h> +#include <unistd.h> + + +/* Change the set of blocked signals to SET, + wait until a signal arrives, and restore the set of blocked signals. */ +int +__sigsuspend (const sigset_t *set) +{ + sigset_t oset; + int save; + + if (set == NULL) + { + __set_errno (EINVAL); + return -1; + } + + if (sigprocmask (SIG_SETMASK, set, &oset) < 0) + return -1; + + (void) pause(); + save = errno; + + if (sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL) < 0) + return -1; + + __set_errno (save); + return -1; +} +libc_hidden_def (__sigsuspend) +weak_alias (__sigsuspend, sigsuspend) diff --git a/REORG.TODO/sysdeps/posix/sigwait.c b/REORG.TODO/sysdeps/posix/sigwait.c new file mode 100644 index 0000000000..d807dbf72c --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sigwait.c @@ -0,0 +1,108 @@ +/* Implementation of sigwait function from POSIX.1c. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> +#include <stddef.h> /* For NULL. */ +#include <sysdep-cancel.h> + +/* This is our dummy signal handler we use here. */ +static void ignore_signal (int sig); + +/* Place where to remember which signal we got. Please note that this + implementation cannot be used for the threaded libc. The + libpthread must provide an own version. */ +static int was_sig; + + +static int +do_sigwait (const sigset_t *set, int *sig) +{ + sigset_t tmp_mask; + struct sigaction saved[NSIG]; + struct sigaction action; + int save_errno; + int this; + + /* Prepare set. */ + __sigfillset (&tmp_mask); + + /* Unblock all signals in the SET and register our nice handler. */ + action.sa_handler = ignore_signal; + action.sa_flags = 0; + __sigfillset (&action.sa_mask); /* Block all signals for handler. */ + + /* Make sure we recognize error conditions by setting WAS_SIG to a + value which does not describe a legal signal number. */ + was_sig = -1; + + for (this = 1; this < NSIG; ++this) + if (__sigismember (set, this)) + { + /* Unblock this signal. */ + __sigdelset (&tmp_mask, this); + + /* Register temporary action handler. */ + if (__sigaction (this, &action, &saved[this]) != 0) + goto restore_handler; + } + + /* Now we can wait for signals. */ + __sigsuspend (&tmp_mask); + + restore_handler: + save_errno = errno; + + while (--this >= 1) + if (__sigismember (set, this)) + /* We ignore errors here since we must restore all handlers. */ + __sigaction (this, &saved[this], NULL); + + __set_errno (save_errno); + + /* Store the result and return. */ + *sig = was_sig; + return was_sig == -1 ? -1 : 0; +} + + +int +__sigwait (const sigset_t *set, int *sig) +{ + if (SINGLE_THREAD_P) + return do_sigwait (set, sig); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = do_sigwait (set, sig); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +libc_hidden_def (__sigwait) +weak_alias (__sigwait, sigwait) + + +static void +ignore_signal (int sig) +{ + /* Remember the signal. */ + was_sig = sig; +} diff --git a/REORG.TODO/sysdeps/posix/sleep.c b/REORG.TODO/sysdeps/posix/sleep.c new file mode 100644 index 0000000000..b3162baab1 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sleep.c @@ -0,0 +1,66 @@ +/* Sleep for a given number of seconds. POSIX.1 version. + Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <time.h> +#include <unistd.h> +#include <errno.h> +#include <sys/param.h> + + +/* Make the process sleep for SECONDS seconds, or until a signal arrives + and is not ignored. The function returns the number of seconds less + than SECONDS which it actually slept (zero if it slept the full time). + If a signal handler does a `longjmp' or modifies the handling of the + SIGALRM signal while inside `sleep' call, the handling of the SIGALRM + signal afterwards is undefined. There is no return value to indicate + error, but if `sleep' returns SECONDS, it probably didn't work. */ +unsigned int +__sleep (unsigned int seconds) +{ + int save_errno = errno; + + const unsigned int max + = (unsigned int) (((unsigned long int) (~((time_t) 0))) >> 1); + struct timespec ts = { 0, 0 }; + do + { + if (sizeof (ts.tv_sec) <= sizeof (seconds)) + { + /* Since SECONDS is unsigned assigning the value to .tv_sec can + overflow it. In this case we have to wait in steps. */ + ts.tv_sec += MIN (seconds, max); + seconds -= (unsigned int) ts.tv_sec; + } + else + { + ts.tv_sec = (time_t) seconds; + seconds = 0; + } + + if (__nanosleep (&ts, &ts) < 0) + /* We were interrupted. + Return the number of (whole) seconds we have not yet slept. */ + return seconds + ts.tv_sec; + } + while (seconds > 0); + + __set_errno (save_errno); + + return 0; +} +weak_alias (__sleep, sleep) diff --git a/REORG.TODO/sysdeps/posix/spawni.c b/REORG.TODO/sysdeps/posix/spawni.c new file mode 100644 index 0000000000..9cad25ca4e --- /dev/null +++ b/REORG.TODO/sysdeps/posix/spawni.c @@ -0,0 +1,319 @@ +/* Guts of POSIX spawn interface. Generic POSIX.1 version. + Copyright (C) 2000-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <spawn.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <sys/resource.h> +#include "spawn_int.h" +#include <not-cancel.h> +#include <local-setxid.h> +#include <shlib-compat.h> + + +/* The Unix standard contains a long explanation of the way to signal + an error after the fork() was successful. Since no new wait status + was wanted there is no way to signal an error using one of the + available methods. The committee chose to signal an error by a + normal program exit with the exit code 127. */ +#define SPAWN_ERROR 127 + + +/* The file is accessible but it is not an executable file. Invoke + the shell to interpret it as a script. */ +static void +internal_function +script_execute (const char *file, char *const argv[], char *const envp[]) +{ + /* Count the arguments. */ + int argc = 0; + while (argv[argc++]) + ; + + /* Construct an argument list for the shell. */ + { + char *new_argv[argc + 1]; + new_argv[0] = (char *) _PATH_BSHELL; + new_argv[1] = (char *) file; + while (argc > 1) + { + new_argv[argc] = argv[argc - 1]; + --argc; + } + + /* Execute the shell. */ + __execve (new_argv[0], new_argv, envp); + } +} + +static inline void +maybe_script_execute (const char *file, char *const argv[], char *const envp[], + int xflags) +{ + if (SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15) + && (xflags & SPAWN_XFLAGS_TRY_SHELL) + && errno == ENOEXEC) + script_execute (file, argv, envp); +} + +/* Spawn a new process executing PATH with the attributes describes in *ATTRP. + Before running the process perform the actions described in FILE-ACTIONS. */ +int +__spawni (pid_t *pid, const char *file, + const posix_spawn_file_actions_t *file_actions, + const posix_spawnattr_t *attrp, char *const argv[], + char *const envp[], int xflags) +{ + pid_t new_pid; + char *path, *p, *name; + size_t len; + size_t pathlen; + + /* Do this once. */ + short int flags = attrp == NULL ? 0 : attrp->__flags; + + /* Generate the new process. */ + if ((flags & POSIX_SPAWN_USEVFORK) != 0 + /* If no major work is done, allow using vfork. Note that we + might perform the path searching. But this would be done by + a call to execvp(), too, and such a call must be OK according + to POSIX. */ + || ((flags & (POSIX_SPAWN_SETSIGMASK | POSIX_SPAWN_SETSIGDEF + | POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER + | POSIX_SPAWN_SETPGROUP | POSIX_SPAWN_RESETIDS + | POSIX_SPAWN_SETSID)) == 0 + && file_actions == NULL)) + new_pid = __vfork (); + else + new_pid = __fork (); + + if (new_pid != 0) + { + if (new_pid < 0) + return errno; + + /* The call was successful. Store the PID if necessary. */ + if (pid != NULL) + *pid = new_pid; + + return 0; + } + + /* Set signal mask. */ + if ((flags & POSIX_SPAWN_SETSIGMASK) != 0 + && __sigprocmask (SIG_SETMASK, &attrp->__ss, NULL) != 0) + _exit (SPAWN_ERROR); + + /* Set signal default action. */ + if ((flags & POSIX_SPAWN_SETSIGDEF) != 0) + { + /* We have to iterate over all signals. This could possibly be + done better but it requires system specific solutions since + the sigset_t data type can be very different on different + architectures. */ + int sig; + struct sigaction sa; + + memset (&sa, '\0', sizeof (sa)); + sa.sa_handler = SIG_DFL; + + for (sig = 1; sig <= _NSIG; ++sig) + if (__sigismember (&attrp->__sd, sig) != 0 + && __sigaction (sig, &sa, NULL) != 0) + _exit (SPAWN_ERROR); + + } + +#ifdef _POSIX_PRIORITY_SCHEDULING + /* Set the scheduling algorithm and parameters. */ + if ((flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER)) + == POSIX_SPAWN_SETSCHEDPARAM) + { + if (__sched_setparam (0, &attrp->__sp) == -1) + _exit (SPAWN_ERROR); + } + else if ((flags & POSIX_SPAWN_SETSCHEDULER) != 0) + { + if (__sched_setscheduler (0, attrp->__policy, &attrp->__sp) == -1) + _exit (SPAWN_ERROR); + } +#endif + + if ((flags & POSIX_SPAWN_SETSID) != 0 + && __setsid () < 0) + _exit (SPAWN_ERROR); + + /* Set the process group ID. */ + if ((flags & POSIX_SPAWN_SETPGROUP) != 0 + && __setpgid (0, attrp->__pgrp) != 0) + _exit (SPAWN_ERROR); + + /* Set the effective user and group IDs. */ + if ((flags & POSIX_SPAWN_RESETIDS) != 0 + && (local_seteuid (__getuid ()) != 0 + || local_setegid (__getgid ()) != 0)) + _exit (SPAWN_ERROR); + + /* Execute the file actions. */ + if (file_actions != NULL) + { + int cnt; + struct rlimit64 fdlimit; + bool have_fdlimit = false; + + for (cnt = 0; cnt < file_actions->__used; ++cnt) + { + struct __spawn_action *action = &file_actions->__actions[cnt]; + + switch (action->tag) + { + case spawn_do_close: + if (close_not_cancel (action->action.close_action.fd) != 0) + { + if (! have_fdlimit) + { + __getrlimit64 (RLIMIT_NOFILE, &fdlimit); + have_fdlimit = true; + } + + /* Only signal errors for file descriptors out of range. */ + if (action->action.close_action.fd < 0 + || action->action.close_action.fd >= fdlimit.rlim_cur) + /* Signal the error. */ + _exit (SPAWN_ERROR); + } + break; + + case spawn_do_open: + { + int new_fd = open_not_cancel (action->action.open_action.path, + action->action.open_action.oflag + | O_LARGEFILE, + action->action.open_action.mode); + + if (new_fd == -1) + /* The `open' call failed. */ + _exit (SPAWN_ERROR); + + /* Make sure the desired file descriptor is used. */ + if (new_fd != action->action.open_action.fd) + { + if (__dup2 (new_fd, action->action.open_action.fd) + != action->action.open_action.fd) + /* The `dup2' call failed. */ + _exit (SPAWN_ERROR); + + if (close_not_cancel (new_fd) != 0) + /* The `close' call failed. */ + _exit (SPAWN_ERROR); + } + } + break; + + case spawn_do_dup2: + if (__dup2 (action->action.dup2_action.fd, + action->action.dup2_action.newfd) + != action->action.dup2_action.newfd) + /* The `dup2' call failed. */ + _exit (SPAWN_ERROR); + break; + } + } + } + + if ((xflags & SPAWN_XFLAGS_USE_PATH) == 0 || strchr (file, '/') != NULL) + { + /* The FILE parameter is actually a path. */ + __execve (file, argv, envp); + + maybe_script_execute (file, argv, envp, xflags); + + /* Oh, oh. `execve' returns. This is bad. */ + _exit (SPAWN_ERROR); + } + + /* We have to search for FILE on the path. */ + path = getenv ("PATH"); + if (path == NULL) + { + /* There is no `PATH' in the environment. + The default search path is the current directory + followed by the path `confstr' returns for `_CS_PATH'. */ + len = confstr (_CS_PATH, (char *) NULL, 0); + path = (char *) __alloca (1 + len); + path[0] = ':'; + (void) confstr (_CS_PATH, path + 1, len); + } + + len = strlen (file) + 1; + pathlen = strlen (path); + name = __alloca (pathlen + len + 1); + /* Copy the file name at the top. */ + name = (char *) memcpy (name + pathlen + 1, file, len); + /* And add the slash. */ + *--name = '/'; + + p = path; + do + { + char *startp; + + path = p; + p = __strchrnul (path, ':'); + + if (p == path) + /* Two adjacent colons, or a colon at the beginning or the end + of `PATH' means to search the current directory. */ + startp = name + 1; + else + startp = (char *) memcpy (name - (p - path), path, p - path); + + /* Try to execute this name. If it works, execv will not return. */ + __execve (startp, argv, envp); + + maybe_script_execute (startp, argv, envp, xflags); + + switch (errno) + { + case EACCES: + case ENOENT: + case ESTALE: + case ENOTDIR: + /* Those errors indicate the file is missing or not executable + by us, in which case we want to just try the next path + directory. */ + break; + + default: + /* Some other error means we found an executable file, but + something went wrong executing it; return the error to our + caller. */ + _exit (SPAWN_ERROR); + } + } + while (*p++ != '\0'); + + /* Return with an error. */ + _exit (SPAWN_ERROR); +} diff --git a/REORG.TODO/sysdeps/posix/sprofil.c b/REORG.TODO/sysdeps/posix/sprofil.c new file mode 100644 index 0000000000..f704b9e8f4 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sprofil.c @@ -0,0 +1,355 @@ +/* Copyright (C) 2001-2017 Free Software Foundation, Inc. + Contributed by David Mosberger-Tang <davidm@hpl.hp.com>. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sigsetops.h> + +#include <sys/time.h> +#include <sys/profil.h> + +#ifndef SIGPROF +# include <gmon/sprofil.c> +#else + +#include <libc-internal.h> + +struct region + { + size_t offset; + size_t nsamples; + unsigned int scale; + union + { + void *vp; + unsigned short *us; + unsigned int *ui; + } + sample; + size_t start; + size_t end; + }; + +struct prof_info + { + unsigned int num_regions; + struct region *region; + struct region *last, *overflow; + struct itimerval saved_timer; + struct sigaction saved_action; + }; + +static unsigned int overflow_counter; + +static struct region default_overflow_region = + { + .offset = 0, + .nsamples = 1, + .scale = 2, + .sample = { &overflow_counter }, + .start = 0, + .end = ~(size_t) 0 + }; + +static struct prof_info prof_info; + +static unsigned long int +pc_to_index (size_t pc, size_t offset, unsigned int scale, int prof_uint) +{ + size_t i = (pc - offset) / (prof_uint ? sizeof (int) : sizeof (short)); + + if (sizeof (unsigned long long int) > sizeof (size_t)) + return (unsigned long long int) i * scale / 65536; + else + return i / 65536 * scale + i % 65536 * scale / 65536; +} + +static inline size_t +index_to_pc (unsigned long int n, size_t offset, unsigned int scale, + int prof_uint) +{ + size_t pc, bin_size = (prof_uint ? sizeof (int) : sizeof (short)); + + if (sizeof (unsigned long long int) > sizeof (size_t)) + pc = offset + (unsigned long long int) n * bin_size * 65536ull / scale; + else + pc = (offset + n * bin_size / scale * 65536 + + n * bin_size % scale * 65536 / scale); + + if (pc_to_index (pc, offset, scale, prof_uint) < n) + /* Adjust for rounding error. */ + ++pc; + + assert (pc_to_index (pc - 1, offset, scale, prof_uint) < n + && pc_to_index (pc, offset, scale, prof_uint) >= n); + + return pc; +} + +static void +profil_count (void *pcp, int prof_uint) +{ + struct region *region, *r = prof_info.last; + size_t lo, hi, mid, pc = (unsigned long int) pcp; + unsigned long int i; + + /* Fast path: pc is in same region as before. */ + if (pc >= r->start && pc < r->end) + region = r; + else + { + /* Slow path: do a binary search for the right region. */ + lo = 0; hi = prof_info.num_regions - 1; + while (lo <= hi) + { + mid = (lo + hi) / 2; + + r = prof_info.region + mid; + if (pc >= r->start && pc < r->end) + { + prof_info.last = r; + region = r; + break; + } + + if (pc < r->start) + hi = mid - 1; + else + lo = mid + 1; + } + + /* No matching region: increment overflow count. There is no point + in updating the cache here, as it won't hit anyhow. */ + region = prof_info.overflow; + } + + i = pc_to_index (pc, region->offset, region->scale, prof_uint); + if (i < r->nsamples) + { + if (prof_uint) + { + if (r->sample.ui[i] < (unsigned int) ~0) + ++r->sample.ui[i]; + } + else + { + if (r->sample.us[i] < (unsigned short) ~0) + ++r->sample.us[i]; + } + } + else + { + if (prof_uint) + ++prof_info.overflow->sample.ui[0]; + else + ++prof_info.overflow->sample.us[0]; + } +} + +static inline void +profil_count_ushort (void *pcp) +{ + profil_count (pcp, 0); +} + +static inline void +profil_count_uint (void *pcp) +{ + profil_count (pcp, 1); +} + +/* Get the machine-dependent definition of `__profil_counter', the signal + handler for SIGPROF. It calls `profil_count' (above) with the PC of the + interrupted code. */ +#define __profil_counter __profil_counter_ushort +#define profil_count(pc) profil_count (pc, 0) +#include <profil-counter.h> + +#undef __profil_counter +#undef profil_count + +#define __profil_counter __profil_counter_uint +#define profil_count(pc) profil_count (pc, 1) +#include <profil-counter.h> + +static int +insert (int i, unsigned long int start, unsigned long int end, struct prof *p, + int prof_uint) +{ + struct region *r; + size_t to_copy; + + if (start >= end) + return 0; /* don't bother with empty regions */ + + if (prof_info.num_regions == 0) + r = malloc (sizeof (*r)); + else + r = realloc (prof_info.region, (prof_info.num_regions + 1) * sizeof (*r)); + if (r == NULL) + return -1; + + to_copy = prof_info.num_regions - i; + if (to_copy > 0) + memmove (r + i + 1, r + i, to_copy * sizeof (*r)); + + r[i].offset = p->pr_off; + r[i].nsamples = p->pr_size / (prof_uint ? sizeof (int) : sizeof (short)); + r[i].scale = p->pr_scale; + r[i].sample.vp = p->pr_base; + r[i].start = start; + r[i].end = end; + + prof_info.region = r; + ++prof_info.num_regions; + + if (p->pr_off == 0 && p->pr_scale == 2) + prof_info.overflow = r; + + return 0; +} + +/* Add a new profiling region. If the new region overlaps with + existing ones, this may add multiple subregions so that the final + data structure is free of overlaps. The absence of overlaps makes + it possible to use a binary search in profil_count(). Note that + this function depends on new regions being presented in DECREASING + ORDER of starting address. */ + +static int +add_region (struct prof *p, int prof_uint) +{ + unsigned long int nsamples; + size_t start, end; + unsigned int i; + + if (p->pr_scale < 2) + return 0; + + nsamples = p->pr_size / (prof_uint ? sizeof (int) : sizeof (short)); + + start = p->pr_off; + end = index_to_pc (nsamples, p->pr_off, p->pr_scale, prof_uint); + + /* Merge with existing regions. */ + for (i = 0; i < prof_info.num_regions; ++i) + { + if (start < prof_info.region[i].start) + { + if (end < prof_info.region[i].start) + break; + else if (insert (i, start, prof_info.region[i].start, p, prof_uint) + < 0) + return -1; + } + start = prof_info.region[i].end; + } + return insert (i, start, end, p, prof_uint); +} + +static int +pcmp (const void *left, const void *right) +{ + struct prof *l = *(struct prof **) left; + struct prof *r = *(struct prof **) right; + + if (l->pr_off < r->pr_off) + return 1; + else if (l->pr_off > r->pr_off) + return -1; + return 0; +} + +int +__sprofil (struct prof *profp, int profcnt, struct timeval *tvp, + unsigned int flags) +{ + struct prof *p[profcnt]; + struct itimerval timer; + struct sigaction act; + int i; + + if (tvp != NULL) + { + /* Return profiling period. */ + unsigned long int t = 1000000 / __profile_frequency (); + tvp->tv_sec = t / 1000000; + tvp->tv_usec = t % 1000000; + } + + if (prof_info.num_regions > 0) + { + /* Disable profiling. */ + if (__setitimer (ITIMER_PROF, &prof_info.saved_timer, NULL) < 0) + return -1; + + if (__sigaction (SIGPROF, &prof_info.saved_action, NULL) < 0) + return -1; + + free (prof_info.region); + return 0; + } + + prof_info.num_regions = 0; + prof_info.region = NULL; + prof_info.overflow = &default_overflow_region; + + for (i = 0; i < profcnt; ++i) + p[i] = profp + i; + + /* Sort in order of decreasing starting address: */ + qsort (p, profcnt, sizeof (p[0]), pcmp); + + /* Add regions in order of decreasing starting address: */ + for (i = 0; i < profcnt; ++i) + if (add_region (p[i], (flags & PROF_UINT) != 0) < 0) + { + free (prof_info.region); + prof_info.num_regions = 0; + prof_info.region = NULL; + return -1; + } + + if (prof_info.num_regions == 0) + return 0; + + prof_info.last = prof_info.region; + + /* Install SIGPROF handler. */ + if (flags & PROF_UINT) + act.sa_handler = (sighandler_t) &__profil_counter_uint; + else + act.sa_handler = (sighandler_t) &__profil_counter_ushort; + act.sa_flags = SA_RESTART; + __sigfillset (&act.sa_mask); + if (__sigaction (SIGPROF, &act, &prof_info.saved_action) < 0) + return -1; + + /* Setup profiling timer. */ + timer.it_value.tv_sec = 0; + timer.it_value.tv_usec = 1; + timer.it_interval = timer.it_value; + return __setitimer (ITIMER_PROF, &timer, &prof_info.saved_timer); +} + +weak_alias (__sprofil, sprofil) + +#endif /* SIGPROF */ diff --git a/REORG.TODO/sysdeps/posix/sysconf.c b/REORG.TODO/sysdeps/posix/sysconf.c new file mode 100644 index 0000000000..a95e1b3f05 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sysconf.c @@ -0,0 +1,1227 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <limits.h> +#include <grp.h> +#include <pwd.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> +#include <sys/param.h> +#include <sys/stat.h> +#include <sys/sysinfo.h> +#include <sys/types.h> +#include <regex.h> + +#define NEED_SPEC_ARRAY 0 +#include <posix-conf-vars.h> + +#define NEED_CHECK_SPEC \ + (!defined _XBS5_ILP32_OFF32 || !defined _XBS5_ILP32_OFFBIG \ + || !defined _XBS5_LP64_OFF64 || !defined _XBS5_LPBIG_OFFBIG \ + || !defined _POSIX_V6_ILP32_OFF32 || !defined _POSIX_V6_ILP32_OFFBIG \ + || !defined _POSIX_V6_LP64_OFF64 || !defined _POSIX_V6_LPBIG_OFFBIG \ + || !defined _POSIX_V7_ILP32_OFF32 || !defined _POSIX_V7_ILP32_OFFBIG \ + || !defined _POSIX_V7_LP64_OFF64 || !defined _POSIX_V7_LPBIG_OFFBIG) +#if NEED_CHECK_SPEC +static long int __sysconf_check_spec (const char *spec); +#endif + + +/* Get the value of the system variable NAME. */ +long int +__sysconf (int name) +{ + switch (name) + { + /* Also add obsolete or unnecessarily added constants here. */ + case _SC_EQUIV_CLASS_MAX: + default: + __set_errno (EINVAL); + return -1; + + case _SC_ARG_MAX: +#ifdef ARG_MAX + return ARG_MAX; +#else + return -1; +#endif + + case _SC_CHILD_MAX: +#ifdef CHILD_MAX + return CHILD_MAX; +#else + return __get_child_max (); +#endif + + case _SC_CLK_TCK: + return __getclktck (); + + case _SC_NGROUPS_MAX: +#ifdef NGROUPS_MAX + return NGROUPS_MAX; +#else + return -1; +#endif + + case _SC_OPEN_MAX: + return __getdtablesize (); + + case _SC_STREAM_MAX: +#ifdef STREAM_MAX + return STREAM_MAX; +#else + return FOPEN_MAX; +#endif + + case _SC_TZNAME_MAX: + return -1; + + case _SC_JOB_CONTROL: +#if CONF_IS_DEFINED_SET (_POSIX_JOB_CONTROL) + return _POSIX_JOB_CONTROL; +#else + return -1; +#endif + + case _SC_SAVED_IDS: +#if CONF_IS_DEFINED_SET (_POSIX_SAVED_IDS) + return 1; +#else + return -1; +#endif + + case _SC_REALTIME_SIGNALS: +#if CONF_IS_DEFINED_SET (_POSIX_REALTIME_SIGNALS) + return _POSIX_REALTIME_SIGNALS; +#else + return -1; +#endif + + case _SC_PRIORITY_SCHEDULING: +#if CONF_IS_DEFINED_SET (_POSIX_PRIORITY_SCHEDULING) + return _POSIX_PRIORITY_SCHEDULING; +#else + return -1; +#endif + + case _SC_TIMERS: +#if CONF_IS_DEFINED_SET (_POSIX_TIMERS) + return _POSIX_TIMERS; +#else + return -1; +#endif + + case _SC_ASYNCHRONOUS_IO: +#if CONF_IS_DEFINED_SET (_POSIX_ASYNCHRONOUS_IO) + return _POSIX_ASYNCHRONOUS_IO; +#else + return -1; +#endif + + case _SC_PRIORITIZED_IO: +#if CONF_IS_DEFINED_SET (_POSIX_PRIORITIZED_IO) + return _POSIX_PRIORITIZED_IO; +#else + return -1; +#endif + + case _SC_SYNCHRONIZED_IO: +#if CONF_IS_DEFINED_SET (_POSIX_SYNCHRONIZED_IO) + return _POSIX_SYNCHRONIZED_IO; +#else + return -1; +#endif + + case _SC_FSYNC: +#if CONF_IS_DEFINED_SET (_POSIX_FSYNC) + return _POSIX_FSYNC; +#else + return -1; +#endif + + case _SC_MAPPED_FILES: +#if CONF_IS_DEFINED_SET (_POSIX_MAPPED_FILES) + return _POSIX_MAPPED_FILES; +#else + return -1; +#endif + + case _SC_MEMLOCK: +#if CONF_IS_DEFINED_SET (_POSIX_MEMLOCK) + return _POSIX_MEMLOCK; +#else + return -1; +#endif + + case _SC_MEMLOCK_RANGE: +#if CONF_IS_DEFINED_SET (_POSIX_MEMLOCK_RANGE) + return _POSIX_MEMLOCK_RANGE; +#else + return -1; +#endif + + case _SC_MEMORY_PROTECTION: +#if CONF_IS_DEFINED_SET (_POSIX_MEMORY_PROTECTION) + return _POSIX_MEMORY_PROTECTION; +#else + return -1; +#endif + + case _SC_MESSAGE_PASSING: +#if CONF_IS_DEFINED_SET (_POSIX_MESSAGE_PASSING) + return _POSIX_MESSAGE_PASSING; +#else + return -1; +#endif + + case _SC_SEMAPHORES: +#if CONF_IS_DEFINED_SET (_POSIX_SEMAPHORES) + return _POSIX_SEMAPHORES; +#else + return -1; +#endif + + case _SC_SHARED_MEMORY_OBJECTS: +#if CONF_IS_DEFINED_SET (_POSIX_SHARED_MEMORY_OBJECTS) + return _POSIX_SHARED_MEMORY_OBJECTS; +#else + return -1; +#endif + + case _SC_VERSION: + return _POSIX_VERSION; + + case _SC_PAGESIZE: + return __getpagesize (); + + case _SC_AIO_LISTIO_MAX: +#ifdef AIO_LISTIO_MAX + return AIO_LISTIO_MAX; +#else + return -1; +#endif + + case _SC_AIO_MAX: +#ifdef AIO_MAX + return AIO_MAX; +#else + return -1; +#endif + + case _SC_AIO_PRIO_DELTA_MAX: +#ifdef AIO_PRIO_DELTA_MAX + return AIO_PRIO_DELTA_MAX; +#else + return -1; +#endif + + case _SC_DELAYTIMER_MAX: +#ifdef DELAYTIMER_MAX + return DELAYTIMER_MAX; +#else + return -1; +#endif + + case _SC_MQ_OPEN_MAX: +#ifdef MQ_OPEN_MAX + return MQ_OPEN_MAX; +#else + return -1; +#endif + + case _SC_MQ_PRIO_MAX: +#ifdef MQ_PRIO_MAX + return MQ_PRIO_MAX; +#else + return -1; +#endif + + case _SC_RTSIG_MAX: +#ifdef RTSIG_MAX + return RTSIG_MAX; +#else + return -1; +#endif + + case _SC_SEM_NSEMS_MAX: +#ifdef SEM_NSEMS_MAX + return SEM_NSEMS_MAX; +#else + return -1; +#endif + + case _SC_SEM_VALUE_MAX: +#ifdef SEM_VALUE_MAX + return SEM_VALUE_MAX; +#else + return -1; +#endif + + case _SC_SIGQUEUE_MAX: +#ifdef SIGQUEUE_MAX + return SIGQUEUE_MAX; +#else + return -1; +#endif + + case _SC_TIMER_MAX: +#ifdef TIMER_MAX + return TIMER_MAX; +#else + return -1; +#endif + + case _SC_BC_BASE_MAX: +#ifdef BC_BASE_MAX + return BC_BASE_MAX; +#else + return -1; +#endif + + case _SC_BC_DIM_MAX: +#ifdef BC_DIM_MAX + return BC_DIM_MAX; +#else + return -1; +#endif + + case _SC_BC_SCALE_MAX: +#ifdef BC_SCALE_MAX + return BC_SCALE_MAX; +#else + return -1; +#endif + + case _SC_BC_STRING_MAX: +#ifdef BC_STRING_MAX + return BC_STRING_MAX; +#else + return -1; +#endif + + case _SC_COLL_WEIGHTS_MAX: +#ifdef COLL_WEIGHTS_MAX + return COLL_WEIGHTS_MAX; +#else + return -1; +#endif + + case _SC_EXPR_NEST_MAX: +#ifdef EXPR_NEST_MAX + return EXPR_NEST_MAX; +#else + return -1; +#endif + + case _SC_LINE_MAX: +#ifdef LINE_MAX + return LINE_MAX; +#else + return -1; +#endif + + case _SC_RE_DUP_MAX: +#ifdef RE_DUP_MAX + return RE_DUP_MAX; +#else + return -1; +#endif + + case _SC_CHARCLASS_NAME_MAX: +#ifdef CHARCLASS_NAME_MAX + return CHARCLASS_NAME_MAX; +#else + return -1; +#endif + + case _SC_PII: +#if CONF_IS_DEFINED_SET (_POSIX_PII) + return 1; +#else + return -1; +#endif + + case _SC_PII_XTI: +#if CONF_IS_DEFINED_SET (_POSIX_PII_XTI) + return 1; +#else + return -1; +#endif + + case _SC_PII_SOCKET: +#if CONF_IS_DEFINED_SET (_POSIX_PII_SOCKET) + return 1; +#else + return -1; +#endif + + case _SC_PII_INTERNET: +#if CONF_IS_DEFINED_SET (_POSIX_PII_INTERNET) + return 1; +#else + return -1; +#endif + + case _SC_PII_OSI: +#if CONF_IS_DEFINED_SET (_POSIX_PII_OSI) + return 1; +#else + return -1; +#endif + + case _SC_POLL: +#if CONF_IS_DEFINED_SET (_POSIX_POLL) + return 1; +#else + return -1; +#endif + + case _SC_SELECT: +#if CONF_IS_DEFINED_SET (_POSIX_SELECT) + return 1; +#else + return -1; +#endif + + /* The same as _SC_IOV_MAX. */ + case _SC_UIO_MAXIOV: +#ifdef UIO_MAXIOV + return UIO_MAXIOV; +#else + return -1; +#endif + + case _SC_PII_INTERNET_STREAM: +#if CONF_IS_DEFINED_SET (_POSIX_PII_INTERNET_STREAM) + return 1; +#else + return -1; +#endif + + case _SC_PII_INTERNET_DGRAM: +#if CONF_IS_DEFINED_SET (_POSIX_PII_INTERNET_DGRAM) + return 1; +#else + return -1; +#endif + + case _SC_PII_OSI_COTS: +#if CONF_IS_DEFINED_SET (_POSIX_PII_OSI_COTS) + return 1; +#else + return -1; +#endif + + case _SC_PII_OSI_CLTS: +#if CONF_IS_DEFINED_SET (_POSIX_PII_OSI_CLTS) + return 1; +#else + return -1; +#endif + + case _SC_PII_OSI_M: +#if CONF_IS_DEFINED_SET (_POSIX_PII_OSI_M) + return 1; +#else + return -1; +#endif + + case _SC_T_IOV_MAX: +#ifdef _T_IOV_MAX + return _T_IOV_MAX; +#else + return -1; +#endif + + case _SC_2_VERSION: + return _POSIX2_VERSION; + + case _SC_2_C_BIND: +#ifdef _POSIX2_C_BIND + return _POSIX2_C_BIND; +#else + return -1; +#endif + + case _SC_2_C_DEV: +#ifdef _POSIX2_C_DEV + return _POSIX2_C_DEV; +#else + return -1; +#endif + + case _SC_2_C_VERSION: +#ifdef _POSIX2_C_VERSION + return _POSIX2_C_VERSION; +#else + return -1; +#endif + + case _SC_2_FORT_DEV: +#ifdef _POSIX2_FORT_DEV + return _POSIX2_FORT_DEV; +#else + return -1; +#endif + + case _SC_2_FORT_RUN: +#ifdef _POSIX2_FORT_RUN + return _POSIX2_FORT_RUN; +#else + return -1; +#endif + + case _SC_2_LOCALEDEF: +#ifdef _POSIX2_LOCALEDEF + return _POSIX2_LOCALEDEF; +#else + return -1; +#endif + + case _SC_2_SW_DEV: +#ifdef _POSIX2_SW_DEV + return _POSIX2_SW_DEV; +#else + return -1; +#endif + + case _SC_2_CHAR_TERM: +#ifdef _POSIX2_CHAR_TERM + return _POSIX2_CHAR_TERM; +#else + return -1; +#endif + + case _SC_2_UPE: +#ifdef _POSIX2_UPE + return _POSIX2_UPE; +#else + return -1; +#endif + + /* POSIX 1003.1c (POSIX Threads). */ + case _SC_THREADS: +#if CONF_IS_DEFINED_SET (_POSIX_THREADS) + return _POSIX_THREADS; +#else + return -1; +#endif + + case _SC_THREAD_SAFE_FUNCTIONS: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_SAFE_FUNCTIONS) + return _POSIX_THREAD_SAFE_FUNCTIONS; +#else + return -1; +#endif + + case _SC_GETGR_R_SIZE_MAX: + return NSS_BUFLEN_GROUP; + + case _SC_GETPW_R_SIZE_MAX: + return NSS_BUFLEN_PASSWD; + + case _SC_LOGIN_NAME_MAX: +#ifdef LOGIN_NAME_MAX + return LOGIN_NAME_MAX; +#else + return -1; +#endif + + case _SC_TTY_NAME_MAX: +#ifdef TTY_NAME_MAX + return TTY_NAME_MAX; +#else + return -1; +#endif + + case _SC_THREAD_DESTRUCTOR_ITERATIONS: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_DESTRUCTOR_ITERATIONS) + return _POSIX_THREAD_DESTRUCTOR_ITERATIONS; +#else + return -1; +#endif + + case _SC_THREAD_KEYS_MAX: +#ifdef PTHREAD_KEYS_MAX + return PTHREAD_KEYS_MAX; +#else + return -1; +#endif + + case _SC_THREAD_STACK_MIN: +#ifdef PTHREAD_STACK_MIN + return PTHREAD_STACK_MIN; +#else + return -1; +#endif + + case _SC_THREAD_THREADS_MAX: +#ifdef PTHREAD_THREADS_MAX + return PTHREAD_THREADS_MAX; +#else + return -1; +#endif + + case _SC_THREAD_ATTR_STACKADDR: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_ATTR_STACKADDR) + return _POSIX_THREAD_ATTR_STACKADDR; +#else + return -1; +#endif + + case _SC_THREAD_ATTR_STACKSIZE: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_ATTR_STACKSIZE) + return _POSIX_THREAD_ATTR_STACKSIZE; +#else + return -1; +#endif + + case _SC_THREAD_PRIORITY_SCHEDULING: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_PRIORITY_SCHEDULING) + return _POSIX_THREAD_PRIORITY_SCHEDULING; +#else + return -1; +#endif + + case _SC_THREAD_PRIO_INHERIT: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_PRIO_INHERIT) + return _POSIX_THREAD_PRIO_INHERIT; +#else + return -1; +#endif + + case _SC_THREAD_PRIO_PROTECT: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_PRIO_PROTECT) + return _POSIX_THREAD_PRIO_PROTECT; +#else + return -1; +#endif + + case _SC_THREAD_PROCESS_SHARED: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_PROCESS_SHARED) + return _POSIX_THREAD_PROCESS_SHARED; +#else + return -1; +#endif + + case _SC_NPROCESSORS_CONF: + return __get_nprocs_conf (); + + case _SC_NPROCESSORS_ONLN: + return __get_nprocs (); + + case _SC_PHYS_PAGES: + return __get_phys_pages (); + + case _SC_AVPHYS_PAGES: + return __get_avphys_pages (); + + case _SC_ATEXIT_MAX: + /* We have no limit since we use lists. */ + return INT_MAX; + + case _SC_PASS_MAX: + /* We have no limit but since the return value might be used to + allocate a buffer we restrict the value. */ + return BUFSIZ; + + case _SC_XOPEN_VERSION: + return _XOPEN_VERSION; + + case _SC_XOPEN_XCU_VERSION: + return _XOPEN_XCU_VERSION; + + case _SC_XOPEN_UNIX: + return _XOPEN_UNIX; + + case _SC_XOPEN_CRYPT: +#ifdef _XOPEN_CRYPT + return _XOPEN_CRYPT; +#else + return -1; +#endif + + case _SC_XOPEN_ENH_I18N: +#ifdef _XOPEN_ENH_I18N + return _XOPEN_ENH_I18N; +#else + return -1; +#endif + + case _SC_XOPEN_SHM: +#ifdef _XOPEN_SHM + return _XOPEN_SHM; +#else + return -1; +#endif + + case _SC_XOPEN_XPG2: +#ifdef _XOPEN_XPG2 + return _XOPEN_XPG2; +#else + return -1; +#endif + + case _SC_XOPEN_XPG3: +#ifdef _XOPEN_XPG3 + return _XOPEN_XPG3; +#else + return -1; +#endif + + case _SC_XOPEN_XPG4: +#ifdef _XOPEN_XPG4 + return _XOPEN_XPG4; +#else + return -1; +#endif + + case _SC_CHAR_BIT: + return CHAR_BIT; + + case _SC_CHAR_MAX: + return CHAR_MAX; + + case _SC_CHAR_MIN: + return CHAR_MIN; + + case _SC_INT_MAX: + return INT_MAX; + + case _SC_INT_MIN: + return INT_MIN; + + case _SC_LONG_BIT: + return sizeof (long int) * CHAR_BIT; + + case _SC_WORD_BIT: + return sizeof (int) * CHAR_BIT; + + case _SC_MB_LEN_MAX: + return MB_LEN_MAX; + + case _SC_NZERO: + return NZERO; + + case _SC_SSIZE_MAX: + return _POSIX_SSIZE_MAX; + + case _SC_SCHAR_MAX: + return SCHAR_MAX; + + case _SC_SCHAR_MIN: + return SCHAR_MIN; + + case _SC_SHRT_MAX: + return SHRT_MAX; + + case _SC_SHRT_MIN: + return SHRT_MIN; + + case _SC_UCHAR_MAX: + return UCHAR_MAX; + + case _SC_UINT_MAX: + return UINT_MAX; + + case _SC_ULONG_MAX: + return ULONG_MAX; + + case _SC_USHRT_MAX: + return USHRT_MAX; + + case _SC_NL_ARGMAX: +#ifdef NL_ARGMAX + return NL_ARGMAX; +#else + return -1; +#endif + + case _SC_NL_LANGMAX: +#ifdef NL_LANGMAX + return NL_LANGMAX; +#else + return -1; +#endif + + case _SC_NL_MSGMAX: +#ifdef NL_MSGMAX + return NL_MSGMAX; +#else + return -1; +#endif + + case _SC_NL_NMAX: +#ifdef NL_NMAX + return NL_NMAX; +#else + return -1; +#endif + + case _SC_NL_SETMAX: +#ifdef NL_SETMAX + return NL_SETMAX; +#else + return -1; +#endif + + case _SC_NL_TEXTMAX: +#ifdef NL_TEXTMAX + return NL_TEXTMAX; +#else + return -1; +#endif + +#define START_ENV_GROUP(VERSION) \ + /* Empty. */ + +#define END_ENV_GROUP(VERSION) \ + /* Empty. */ + +#define KNOWN_ABSENT_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX) \ + case _SC_##SC_PREFIX##_##SUFFIX: \ + return _##ENV_PREFIX##_##SUFFIX; + +#define KNOWN_PRESENT_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX) \ + case _SC_##SC_PREFIX##_##SUFFIX: \ + return _##ENV_PREFIX##_##SUFFIX; + +#define UNKNOWN_ENVIRONMENT(SC_PREFIX, ENV_PREFIX, SUFFIX) \ + case _SC_##SC_PREFIX##_##SUFFIX: \ + return __sysconf_check_spec (#SUFFIX); + +#include <posix/posix-envs.def> + +#undef START_ENV_GROUP +#undef END_ENV_GROUP +#undef KNOWN_ABSENT_ENVIRONMENT +#undef KNOWN_PRESENT_ENVIRONMENT +#undef UNKNOWN_ENVIRONMENT + + case _SC_XOPEN_LEGACY: + return _XOPEN_LEGACY; + + case _SC_XOPEN_REALTIME: +#ifdef _XOPEN_REALTIME + return _XOPEN_REALTIME; +#else + return -1; +#endif + case _SC_XOPEN_REALTIME_THREADS: +#ifdef _XOPEN_REALTIME_THREADS + return _XOPEN_REALTIME_THREADS; +#else + return -1; +#endif + + case _SC_ADVISORY_INFO: +#if CONF_IS_DEFINED_SET (_POSIX_ADVISORY_INFO) + return _POSIX_ADVISORY_INFO; +#else + return -1; +#endif + + case _SC_BARRIERS: +#if CONF_IS_DEFINED_SET (_POSIX_BARRIERS) + return _POSIX_BARRIERS; +#else + return -1; +#endif + + case _SC_BASE: +#if CONF_IS_DEFINED_SET (_POSIX_BASE) + return _POSIX_BASE; +#else + return -1; +#endif + case _SC_C_LANG_SUPPORT: +#if CONF_IS_DEFINED_SET (_POSIX_C_LANG_SUPPORT) + return _POSIX_C_LANG_SUPPORT; +#else + return -1; +#endif + case _SC_C_LANG_SUPPORT_R: +#if CONF_IS_DEFINED_SET (_POSIX_C_LANG_SUPPORT_R) + return _POSIX_C_LANG_SUPPORT_R; +#else + return -1; +#endif + + case _SC_CLOCK_SELECTION: +#if CONF_IS_DEFINED_SET (_POSIX_CLOCK_SELECTION) + return _POSIX_CLOCK_SELECTION; +#else + return -1; +#endif + + case _SC_CPUTIME: +#if CONF_IS_DEFINED_SET (_POSIX_CPUTIME) + return _POSIX_CPUTIME; +#else + return -1; +#endif + + case _SC_DEVICE_IO: +#if CONF_IS_DEFINED_SET (_POSIX_DEVICE_IO) + return _POSIX_DEVICE_IO; +#else + return -1; +#endif + case _SC_DEVICE_SPECIFIC: +#if CONF_IS_DEFINED_SET (_POSIX_DEVICE_SPECIFIC) + return _POSIX_DEVICE_SPECIFIC; +#else + return -1; +#endif + case _SC_DEVICE_SPECIFIC_R: +#if CONF_IS_DEFINED_SET (_POSIX_DEVICE_SPECIFIC_R) + return _POSIX_DEVICE_SPECIFIC_R; +#else + return -1; +#endif + + case _SC_FD_MGMT: +#if CONF_IS_DEFINED_SET (_POSIX_FD_MGMT) + return _POSIX_FD_MGMT; +#else + return -1; +#endif + + case _SC_FIFO: +#if CONF_IS_DEFINED_SET (_POSIX_FIFO) + return _POSIX_FIFO; +#else + return -1; +#endif + case _SC_PIPE: +#if CONF_IS_DEFINED_SET (_POSIX_PIPE) + return _POSIX_PIPE; +#else + return -1; +#endif + + case _SC_FILE_ATTRIBUTES: +#if CONF_IS_DEFINED_SET (_POSIX_FILE_ATTRIBUTES) + return _POSIX_FILE_ATTRIBUTES; +#else + return -1; +#endif + case _SC_FILE_LOCKING: +#if CONF_IS_DEFINED_SET (_POSIX_FILE_LOCKING) + return _POSIX_FILE_LOCKING; +#else + return -1; +#endif + case _SC_FILE_SYSTEM: +#if CONF_IS_DEFINED_SET (_POSIX_FILE_SYSTEM) + return _POSIX_FILE_SYSTEM; +#else + return -1; +#endif + + case _SC_MONOTONIC_CLOCK: +#if CONF_IS_DEFINED_SET (_POSIX_MONOTONIC_CLOCK) + return _POSIX_MONOTONIC_CLOCK; +#else + return -1; +#endif + + case _SC_MULTI_PROCESS: +#if CONF_IS_DEFINED_SET (_POSIX_MULTI_PROCESS) + return _POSIX_MULTI_PROCESS; +#else + return -1; +#endif + case _SC_SINGLE_PROCESS: +#if CONF_IS_DEFINED_SET (_POSIX_SINGLE_PROCESS) + return _POSIX_SINGLE_PROCESS; +#else + return -1; +#endif + + case _SC_NETWORKING: +#if CONF_IS_DEFINED_SET (_POSIX_NETWORKING) + return _POSIX_NETWORKING; +#else + return -1; +#endif + + case _SC_READER_WRITER_LOCKS: +#if CONF_IS_DEFINED_SET (_POSIX_READER_WRITER_LOCKS) + return _POSIX_READER_WRITER_LOCKS; +#else + return -1; +#endif + case _SC_SPIN_LOCKS: +#if CONF_IS_DEFINED_SET (_POSIX_SPIN_LOCKS) + return _POSIX_SPIN_LOCKS; +#else + return -1; +#endif + + case _SC_REGEXP: +#if CONF_IS_DEFINED_SET (_POSIX_REGEXP) + return _POSIX_REGEXP; +#else + return -1; +#endif + /* _REGEX_VERSION has been removed with IEEE Std 1003.1-2001/Cor 2-2004, + item XSH/TC2/D6/137. */ + case _SC_REGEX_VERSION: + return -1; + + case _SC_SHELL: +#if CONF_IS_DEFINED_SET (_POSIX_SHELL) + return _POSIX_SHELL; +#else + return -1; +#endif + + case _SC_SIGNALS: +#if CONF_IS_DEFINED (_POSIX_SIGNALS) + return _POSIX_SIGNALS; +#else + return -1; +#endif + + case _SC_SPAWN: +#if CONF_IS_DEFINED_SET (_POSIX_SPAWN) + return _POSIX_SPAWN; +#else + return -1; +#endif + + case _SC_SPORADIC_SERVER: +#if CONF_IS_DEFINED_SET (_POSIX_SPORADIC_SERVER) + return _POSIX_SPORADIC_SERVER; +#else + return -1; +#endif + case _SC_THREAD_SPORADIC_SERVER: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_SPORADIC_SERVER) + return _POSIX_THREAD_SPORADIC_SERVER; +#else + return -1; +#endif + + case _SC_SYSTEM_DATABASE: +#if CONF_IS_DEFINED_SET (_POSIX_SYSTEM_DATABASE) + return _POSIX_SYSTEM_DATABASE; +#else + return -1; +#endif + case _SC_SYSTEM_DATABASE_R: +#if CONF_IS_DEFINED_SET (_POSIX_SYSTEM_DATABASE_R) + return _POSIX_SYSTEM_DATABASE_R; +#else + return -1; +#endif + + case _SC_THREAD_CPUTIME: +#if CONF_IS_DEFINED_SET (_POSIX_THREAD_CPUTIME) + return _POSIX_THREAD_CPUTIME; +#else + return -1; +#endif + + case _SC_TIMEOUTS: +#if CONF_IS_DEFINED_SET (_POSIX_TIMEOUTS) + return _POSIX_TIMEOUTS; +#else + return -1; +#endif + + case _SC_TYPED_MEMORY_OBJECTS: +#if CONF_IS_DEFINED_SET (_POSIX_TYPED_MEMORY_OBJECTS) + return _POSIX_TYPED_MEMORY_OBJECTS; +#else + return -1; +#endif + + case _SC_USER_GROUPS: +#if CONF_IS_DEFINED_SET (_POSIX_USER_GROUPS) + return _POSIX_USER_GROUPS; +#else + return -1; +#endif + case _SC_USER_GROUPS_R: +#if CONF_IS_DEFINED_SET (_POSIX_USER_GROUPS_R) + return _POSIX_USER_GROUPS_R; +#else + return -1; +#endif + + case _SC_2_PBS: +#ifdef _POSIX2_PBS + return _POSIX2_PBS; +#else + return -1; +#endif + case _SC_2_PBS_ACCOUNTING: +#ifdef _POSIX2_PBS_ACCOUNTING + return _POSIX2_PBS_ACCOUNTING; +#else + return -1; +#endif + case _SC_2_PBS_CHECKPOINT: +#ifdef _POSIX2_PBS_CHECKPOINT + return _POSIX2_PBS_CHECKPOINT; +#else + return -1; +#endif + case _SC_2_PBS_LOCATE: +#ifdef _POSIX2_PBS_LOCATE + return _POSIX2_PBS_LOCATE; +#else + return -1; +#endif + case _SC_2_PBS_MESSAGE: +#ifdef _POSIX2_PBS_MESSAGE + return _POSIX2_PBS_MESSAGE; +#else + return -1; +#endif + case _SC_2_PBS_TRACK: +#ifdef _POSIX2_PBS_TRACK + return _POSIX2_PBS_TRACK; +#else + return -1; +#endif + + case _SC_SYMLOOP_MAX: +#ifdef SYMLOOP_MAX + return SYMLOOP_MAX; +#else + return -1; +#endif + + case _SC_STREAMS: +#ifdef _XOPEN_STREAMS + return _XOPEN_STREAMS; +#else + return -1; +#endif + + case _SC_HOST_NAME_MAX: +#ifdef HOST_NAME_MAX + return HOST_NAME_MAX; +#else + return -1; +#endif + + case _SC_TRACE: +#if CONF_IS_DEFINED_SET (_POSIX_TRACE) + return _POSIX_TRACE; +#else + return -1; +#endif + case _SC_TRACE_EVENT_FILTER: +#if CONF_IS_DEFINED_SET (_POSIX_TRACE_EVENT_FILTER) + return _POSIX_TRACE_EVENT_FILTER; +#else + return -1; +#endif + case _SC_TRACE_INHERIT: +#if CONF_IS_DEFINED_SET (_POSIX_TRACE_INHERIT) + return _POSIX_TRACE_INHERIT; +#else + return -1; +#endif + case _SC_TRACE_LOG: +#if CONF_IS_DEFINED_SET (_POSIX_TRACE_LOG) + return _POSIX_TRACE_LOG; +#else + return -1; +#endif + + case _SC_TRACE_EVENT_NAME_MAX: + case _SC_TRACE_NAME_MAX: + case _SC_TRACE_SYS_MAX: + case _SC_TRACE_USER_EVENT_MAX: + /* No support for tracing. */ + + case _SC_XOPEN_STREAMS: + /* No support for STREAMS. */ + return -1; + + case _SC_LEVEL1_ICACHE_SIZE: + case _SC_LEVEL1_ICACHE_ASSOC: + case _SC_LEVEL1_ICACHE_LINESIZE: + case _SC_LEVEL1_DCACHE_SIZE: + case _SC_LEVEL1_DCACHE_ASSOC: + case _SC_LEVEL1_DCACHE_LINESIZE: + case _SC_LEVEL2_CACHE_SIZE: + case _SC_LEVEL2_CACHE_ASSOC: + case _SC_LEVEL2_CACHE_LINESIZE: + case _SC_LEVEL3_CACHE_SIZE: + case _SC_LEVEL3_CACHE_ASSOC: + case _SC_LEVEL3_CACHE_LINESIZE: + case _SC_LEVEL4_CACHE_SIZE: + case _SC_LEVEL4_CACHE_ASSOC: + case _SC_LEVEL4_CACHE_LINESIZE: + /* In general we cannot determine these values. Therefore we + return zero which indicates that no information is + available. */ + return 0; + + case _SC_IPV6: +#if CONF_IS_DEFINED_SET (_POSIX_IPV6) + return _POSIX_IPV6; +#else + return -1; +#endif + + case _SC_RAW_SOCKETS: +#if CONF_IS_DEFINED_SET (_POSIX_RAW_SOCKETS) + return _POSIX_RAW_SOCKETS; +#else + return -1; +#endif + } +} + +#undef __sysconf +weak_alias (__sysconf, sysconf) +libc_hidden_def (__sysconf) + +#if NEED_CHECK_SPEC +static long int +__sysconf_check_spec (const char *spec) +{ + int save_errno = errno; + + const char *getconf_dir = __libc_secure_getenv ("GETCONF_DIR") ?: GETCONF_DIR; + size_t getconf_dirlen = strlen (getconf_dir); + size_t speclen = strlen (spec); + + char name[getconf_dirlen + sizeof ("/POSIX_V6_") + speclen]; + memcpy (mempcpy (mempcpy (name, getconf_dir, getconf_dirlen), + "/POSIX_V6_", sizeof ("/POSIX_V6_") - 1), + spec, speclen + 1); + + struct stat64 st; + long int ret = __xstat64 (_STAT_VER, name, &st) >= 0 ? 1 : -1; + + __set_errno (save_errno); + return ret; +} +#endif diff --git a/REORG.TODO/sysdeps/posix/system.c b/REORG.TODO/sysdeps/posix/system.c new file mode 100644 index 0000000000..d49cc3f01c --- /dev/null +++ b/REORG.TODO/sysdeps/posix/system.c @@ -0,0 +1,186 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> +#include <stddef.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <libc-lock.h> +#include <sysdep-cancel.h> + + +#define SHELL_PATH "/bin/sh" /* Path of the shell. */ +#define SHELL_NAME "sh" /* Name to give it. */ + + +#ifdef _LIBC_REENTRANT +static struct sigaction intr, quit; +static int sa_refcntr; +__libc_lock_define_initialized (static, lock); + +# define DO_LOCK() __libc_lock_lock (lock) +# define DO_UNLOCK() __libc_lock_unlock (lock) +# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; }) +# define ADD_REF() sa_refcntr++ +# define SUB_REF() --sa_refcntr +#else +# define DO_LOCK() +# define DO_UNLOCK() +# define INIT_LOCK() +# define ADD_REF() 0 +# define SUB_REF() 0 +#endif + + +/* Execute LINE as a shell command, returning its status. */ +static int +do_system (const char *line) +{ + int status, save; + pid_t pid; + struct sigaction sa; +#ifndef _LIBC_REENTRANT + struct sigaction intr, quit; +#endif + sigset_t omask; + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + __sigemptyset (&sa.sa_mask); + + DO_LOCK (); + if (ADD_REF () == 0) + { + if (__sigaction (SIGINT, &sa, &intr) < 0) + { + (void) SUB_REF (); + goto out; + } + if (__sigaction (SIGQUIT, &sa, &quit) < 0) + { + save = errno; + (void) SUB_REF (); + goto out_restore_sigint; + } + } + DO_UNLOCK (); + + /* We reuse the bitmap in the 'sa' structure. */ + __sigaddset (&sa.sa_mask, SIGCHLD); + save = errno; + if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) + { +#ifndef _LIBC + if (errno == ENOSYS) + __set_errno (save); + else +#endif + { + DO_LOCK (); + if (SUB_REF () == 0) + { + save = errno; + (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + out_restore_sigint: + (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); + __set_errno (save); + } + out: + DO_UNLOCK (); + return -1; + } + } + +#ifdef CLEANUP_HANDLER + CLEANUP_HANDLER; +#endif + +#ifdef FORK + pid = FORK (); +#else + pid = __fork (); +#endif + if (pid == (pid_t) 0) + { + /* Child side. */ + const char *new_argv[4]; + new_argv[0] = SHELL_NAME; + new_argv[1] = "-c"; + new_argv[2] = line; + new_argv[3] = NULL; + + /* Restore the signals. */ + (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL); + (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); + INIT_LOCK (); + + /* Exec the shell. */ + (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ); + _exit (127); + } + else if (pid < (pid_t) 0) + /* The fork failed. */ + status = -1; + else + /* Parent side. */ + { + /* Note the system() is a cancellation point. But since we call + waitpid() which itself is a cancellation point we do not + have to do anything here. */ + if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid) + status = -1; + } + +#ifdef CLEANUP_HANDLER + CLEANUP_RESET; +#endif + + save = errno; + DO_LOCK (); + if ((SUB_REF () == 0 + && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL) + | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) + || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) + { +#ifndef _LIBC + /* glibc cannot be used on systems without waitpid. */ + if (errno == ENOSYS) + __set_errno (save); + else +#endif + status = -1; + } + DO_UNLOCK (); + + return status; +} + +int +__libc_system (const char *line) +{ + if (line == NULL) + /* Check that we have a command processor available. It might + not be available after a chroot(), for example. */ + return do_system ("exit 0") == 0; + + return do_system (line); +} +weak_alias (__libc_system, system) diff --git a/REORG.TODO/sysdeps/posix/sysv_signal.c b/REORG.TODO/sysdeps/posix/sysv_signal.c new file mode 100644 index 0000000000..6893ec23e4 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/sysv_signal.c @@ -0,0 +1,58 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <signal.h> +#include <string.h> /* For the real memset prototype. */ +#include <sigsetops.h> + +/* Tolerate non-threads versions of Posix */ +#ifndef SA_ONESHOT +#define SA_ONESHOT 0 +#endif +#ifndef SA_NOMASK +#define SA_NOMASK 0 +#endif +#ifndef SA_INTERRUPT +#define SA_INTERRUPT 0 +#endif + +/* Set the handler for the signal SIG to HANDLER, + returning the old handler, or SIG_ERR on error. */ +__sighandler_t +__sysv_signal (int sig, __sighandler_t handler) +{ + struct sigaction act, oact; + + /* Check signal extents to protect __sigismember. */ + if (handler == SIG_ERR || sig < 1 || sig >= NSIG) + { + __set_errno (EINVAL); + return SIG_ERR; + } + + act.sa_handler = handler; + __sigemptyset (&act.sa_mask); + act.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT; + act.sa_flags &= ~SA_RESTART; + if (__sigaction (sig, &act, &oact) < 0) + return SIG_ERR; + + return oact.sa_handler; +} + +weak_alias (__sysv_signal, sysv_signal) diff --git a/REORG.TODO/sysdeps/posix/telldir.c b/REORG.TODO/sysdeps/posix/telldir.c new file mode 100644 index 0000000000..1d04da97ee --- /dev/null +++ b/REORG.TODO/sysdeps/posix/telldir.c @@ -0,0 +1,27 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <dirent.h> + +#include <dirstream.h> + +/* Return the current position of DIRP. */ +long int +telldir (DIR *dirp) +{ + return dirp->filepos; +} diff --git a/REORG.TODO/sysdeps/posix/tempname.c b/REORG.TODO/sysdeps/posix/tempname.c new file mode 100644 index 0000000000..b00bd588ec --- /dev/null +++ b/REORG.TODO/sysdeps/posix/tempname.c @@ -0,0 +1,305 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#if !_LIBC +# include <config.h> +# include "tempname.h" +#endif + +#include <sys/types.h> +#include <assert.h> + +#include <errno.h> +#ifndef __set_errno +# define __set_errno(Val) errno = (Val) +#endif + +#include <stdio.h> +#ifndef P_tmpdir +# define P_tmpdir "/tmp" +#endif +#ifndef TMP_MAX +# define TMP_MAX 238328 +#endif +#ifndef __GT_FILE +# define __GT_FILE 0 +# define __GT_DIR 1 +# define __GT_NOCREATE 2 +#endif +#if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR \ + || GT_NOCREATE != __GT_NOCREATE) +# error report this to bug-gnulib@gnu.org +#endif + +#include <stddef.h> +#include <stdlib.h> +#include <string.h> + +#include <fcntl.h> +#include <sys/time.h> +#include <stdint.h> +#include <unistd.h> + +#include <sys/stat.h> + +#if _LIBC +# define struct_stat64 struct stat64 +# define __secure_getenv __libc_secure_getenv +#else +# define struct_stat64 struct stat +# define __gen_tempname gen_tempname +# define __getpid getpid +# define __gettimeofday gettimeofday +# define __mkdir mkdir +# define __open open +# define __lxstat64(version, file, buf) lstat (file, buf) +# define __secure_getenv secure_getenv +#endif + +#ifdef _LIBC +# include <hp-timing.h> +# if HP_TIMING_AVAIL +# define RANDOM_BITS(Var) \ + if (__glibc_unlikely (value == UINT64_C (0))) \ + { \ + /* If this is the first time this function is used initialize \ + the variable we accumulate the value in to some somewhat \ + random value. If we'd not do this programs at startup time \ + might have a reduced set of possible names, at least on slow \ + machines. */ \ + struct timeval tv; \ + __gettimeofday (&tv, NULL); \ + value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ + } \ + HP_TIMING_NOW (Var) +# endif +#endif + +/* Use the widest available unsigned type if uint64_t is not + available. The algorithm below extracts a number less than 62**6 + (approximately 2**35.725) from uint64_t, so ancient hosts where + uintmax_t is only 32 bits lose about 3.725 bits of randomness, + which is better than not having mkstemp at all. */ +#if !defined UINT64_MAX && !defined uint64_t +# define uint64_t uintmax_t +#endif + +#if _LIBC +/* Return nonzero if DIR is an existent directory. */ +static int +direxists (const char *dir) +{ + struct_stat64 buf; + return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); +} + +/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is + non-null and exists, uses it; otherwise uses the first of $TMPDIR, + P_tmpdir, /tmp that exists. Copies into TMPL a template suitable + for use with mk[s]temp. Will fail (-1) if DIR is non-null and + doesn't exist, none of the searched dirs exists, or there's not + enough space in TMPL. */ +int +__path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, + int try_tmpdir) +{ + const char *d; + size_t dlen, plen; + + if (!pfx || !pfx[0]) + { + pfx = "file"; + plen = 4; + } + else + { + plen = strlen (pfx); + if (plen > 5) + plen = 5; + } + + if (try_tmpdir) + { + d = __secure_getenv ("TMPDIR"); + if (d != NULL && direxists (d)) + dir = d; + else if (dir != NULL && direxists (dir)) + /* nothing */ ; + else + dir = NULL; + } + if (dir == NULL) + { + if (direxists (P_tmpdir)) + dir = P_tmpdir; + else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) + dir = "/tmp"; + else + { + __set_errno (ENOENT); + return -1; + } + } + + dlen = strlen (dir); + while (dlen > 1 && dir[dlen - 1] == '/') + dlen--; /* remove trailing slashes */ + + /* check we have room for "${dir}/${pfx}XXXXXX\0" */ + if (tmpl_len < dlen + 1 + plen + 6 + 1) + { + __set_errno (EINVAL); + return -1; + } + + sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx); + return 0; +} +#endif /* _LIBC */ + +/* These are the characters used in temporary file names. */ +static const char letters[] = +"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +/* Generate a temporary file name based on TMPL. TMPL must match the + rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix). + The name constructed does not exist at the time of the call to + __gen_tempname. TMPL is overwritten with the result. + + KIND may be one of: + __GT_NOCREATE: simply verify that the name does not exist + at the time of the call. + __GT_FILE: create the file using open(O_CREAT|O_EXCL) + and return a read-write fd. The file is mode 0600. + __GT_DIR: create a directory, which will be mode 0700. + + We use a clever algorithm to get hard-to-predict names. */ +int +__gen_tempname (char *tmpl, int suffixlen, int flags, int kind) +{ + int len; + char *XXXXXX; + static uint64_t value; + uint64_t random_time_bits; + unsigned int count; + int fd = -1; + int save_errno = errno; + struct_stat64 st; + + /* A lower bound on the number of temporary files to attempt to + generate. The maximum total number of temporary file names that + can exist for a given template is 62**6. It should never be + necessary to try all of these combinations. Instead if a reasonable + number of names is tried (we define reasonable as 62**3) fail to + give the system administrator the chance to remove the problems. */ +#define ATTEMPTS_MIN (62 * 62 * 62) + + /* The number of times to attempt to generate a temporary file. To + conform to POSIX, this must be no smaller than TMP_MAX. */ +#if ATTEMPTS_MIN < TMP_MAX + unsigned int attempts = TMP_MAX; +#else + unsigned int attempts = ATTEMPTS_MIN; +#endif + + len = strlen (tmpl); + if (len < 6 + suffixlen || memcmp (&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) + { + __set_errno (EINVAL); + return -1; + } + + /* This is where the Xs start. */ + XXXXXX = &tmpl[len - 6 - suffixlen]; + + /* Get some more or less random data. */ +#ifdef RANDOM_BITS + RANDOM_BITS (random_time_bits); +#else + { + struct timeval tv; + __gettimeofday (&tv, NULL); + random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; + } +#endif + value += random_time_bits ^ __getpid (); + + for (count = 0; count < attempts; value += 7777, ++count) + { + uint64_t v = value; + + /* Fill in the random bits. */ + XXXXXX[0] = letters[v % 62]; + v /= 62; + XXXXXX[1] = letters[v % 62]; + v /= 62; + XXXXXX[2] = letters[v % 62]; + v /= 62; + XXXXXX[3] = letters[v % 62]; + v /= 62; + XXXXXX[4] = letters[v % 62]; + v /= 62; + XXXXXX[5] = letters[v % 62]; + + switch (kind) + { + case __GT_FILE: + fd = __open (tmpl, + (flags & ~O_ACCMODE) + | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); + break; + + case __GT_DIR: + fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); + break; + + case __GT_NOCREATE: + /* This case is backward from the other three. __gen_tempname + succeeds if __xstat fails because the name does not exist. + Note the continue to bypass the common logic at the bottom + of the loop. */ + if (__lxstat64 (_STAT_VER, tmpl, &st) < 0) + { + if (errno == ENOENT) + { + __set_errno (save_errno); + return 0; + } + else + /* Give up now. */ + return -1; + } + continue; + + default: + assert (! "invalid KIND in __gen_tempname"); + abort (); + } + + if (fd >= 0) + { + __set_errno (save_errno); + return fd; + } + else if (errno != EEXIST) + return -1; + } + + /* We got out of the loop because we ran out of combinations to try. */ + __set_errno (EEXIST); + return -1; +} diff --git a/REORG.TODO/sysdeps/posix/time.c b/REORG.TODO/sysdeps/posix/time.c new file mode 100644 index 0000000000..32ca177514 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/time.c @@ -0,0 +1,40 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stddef.h> /* For NULL. */ +#include <time.h> +#include <sys/time.h> + + +/* Return the current time as a `time_t' and also put it in *T if T is + not NULL. Time is represented as seconds from Jan 1 00:00:00 1970. */ +time_t +time (time_t *t) +{ + struct timeval tv; + time_t result; + + if (__gettimeofday (&tv, (struct timezone *) NULL)) + result = (time_t) -1; + else + result = (time_t) tv.tv_sec; + + if (t != NULL) + *t = result; + return result; +} +libc_hidden_def (time) diff --git a/REORG.TODO/sysdeps/posix/timespec_get.c b/REORG.TODO/sysdeps/posix/timespec_get.c new file mode 100644 index 0000000000..94b78cdcec --- /dev/null +++ b/REORG.TODO/sysdeps/posix/timespec_get.c @@ -0,0 +1,38 @@ +/* timespec_get -- C11 interface to sample a clock. Generic POSIX.1 version. + Copyright (C) 2013-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <time.h> + + +/* Set TS to calendar time based in time base BASE. */ +int +timespec_get (struct timespec *ts, int base) +{ + switch (base) + { + case TIME_UTC: + if (__clock_gettime (CLOCK_REALTIME, ts) < 0) + return 0; + break; + + default: + return 0; + } + + return base; +} diff --git a/REORG.TODO/sysdeps/posix/truncate.c b/REORG.TODO/sysdeps/posix/truncate.c new file mode 100644 index 0000000000..24e099c046 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/truncate.c @@ -0,0 +1,44 @@ +/* Truncate a file given by name. Generic POSIX.1 version. + Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> + +/* Truncate PATH to LENGTH bytes. */ +int +__truncate (const char *path, off_t length) +{ + int fd, ret, save; + + fd = __open (path, O_WRONLY | (length == 0 ? O_TRUNC : 0)); + if (fd < 0) + return -1; + + if (length == 0) + ret = 0; + else + ret = __ftruncate (fd, length); + save = errno; + (void) __close (fd); + if (ret < 0) + __set_errno (save); + return ret; +} +weak_alias (__truncate, truncate) diff --git a/REORG.TODO/sysdeps/posix/ttyname.c b/REORG.TODO/sysdeps/posix/ttyname.c new file mode 100644 index 0000000000..288e22b307 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/ttyname.c @@ -0,0 +1,129 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +char *__ttyname; + +static char *getttyname (int fd, dev_t mydev, ino_t myino, + int save, int *dostat) internal_function; + + +libc_freeres_ptr (static char *getttyname_name); + +static char * +internal_function +getttyname (int fd, dev_t mydev, ino_t myino, int save, int *dostat) +{ + static const char dev[] = "/dev"; + static size_t namelen; + struct stat st; + DIR *dirstream; + struct dirent *d; + + dirstream = __opendir (dev); + if (dirstream == NULL) + { + *dostat = -1; + return NULL; + } + + while ((d = __readdir (dirstream)) != NULL) + if (((ino_t) d->d_fileno == myino || *dostat) + && strcmp (d->d_name, "stdin") + && strcmp (d->d_name, "stdout") + && strcmp (d->d_name, "stderr")) + { + size_t dlen = _D_ALLOC_NAMLEN (d); + if (sizeof (dev) + dlen > namelen) + { + free (getttyname_name); + namelen = 2 * (sizeof (dev) + dlen); /* Big enough. */ + getttyname_name = malloc (namelen); + if (! getttyname_name) + { + *dostat = -1; + /* Perhaps it helps to free the directory stream buffer. */ + (void) __closedir (dirstream); + return NULL; + } + *((char *) __mempcpy (getttyname_name, dev, sizeof (dev) - 1)) + = '/'; + } + (void) __mempcpy (&getttyname_name[sizeof (dev)], d->d_name, dlen); + if (stat (getttyname_name, &st) == 0 +#ifdef _STATBUF_ST_RDEV + && S_ISCHR (st.st_mode) && st.st_rdev == mydev +#else + && (ino_t) d->d_fileno == myino && st.st_dev == mydev +#endif + ) + { + (void) __closedir (dirstream); + __ttyname = getttyname_name; + __set_errno (save); + return getttyname_name; + } + } + + (void) __closedir (dirstream); + __set_errno (save); + return NULL; +} + +/* Return the pathname of the terminal FD is open on, or NULL on errors. + The returned storage is good only until the next call to this function. */ +char * +ttyname (int fd) +{ + struct stat st; + int dostat = 0; + char *name; + int save = errno; + + if (!__isatty (fd)) + return NULL; + + if (fstat (fd, &st) < 0) + return NULL; + +#ifdef _STATBUF_ST_RDEV + name = getttyname (fd, st.st_rdev, st.st_ino, save, &dostat); +#else + name = getttyname (fd, st.st_dev, st.st_ino, save, &dostat); +#endif + + if (!name && dostat != -1) + { + dostat = 1; +#ifdef _STATBUF_ST_RDEV + name = getttyname (fd, st.st_rdev, st.st_ino, save, &dostat); +#else + name = getttyname (fd, st.st_dev, st.st_ino, save, &dostat); +#endif + } + + return name; +} diff --git a/REORG.TODO/sysdeps/posix/ttyname_r.c b/REORG.TODO/sysdeps/posix/ttyname_r.c new file mode 100644 index 0000000000..56bf18e4bc --- /dev/null +++ b/REORG.TODO/sysdeps/posix/ttyname_r.c @@ -0,0 +1,156 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <limits.h> +#include <stddef.h> +#include <dirent.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> + +#ifndef MIN +# define MIN(a, b) ((a) < (b) ? (a) : (b)) +#endif + +static const char dev[] = "/dev"; + +static int getttyname_r (int fd, char *buf, size_t buflen, + dev_t mydev, ino_t myino, int save, + int *dostat) __THROW internal_function; + +static int +internal_function +getttyname_r (int fd, char *buf, size_t buflen, dev_t mydev, ino_t myino, + int save, int *dostat) +{ + struct stat st; + DIR *dirstream; + struct dirent *d; + + dirstream = __opendir (dev); + if (dirstream == NULL) + { + *dostat = -1; + return errno; + } + + while ((d = __readdir (dirstream)) != NULL) + if (((ino_t) d->d_fileno == myino || *dostat) + && strcmp (d->d_name, "stdin") + && strcmp (d->d_name, "stdout") + && strcmp (d->d_name, "stderr")) + { + char *cp; + size_t needed = _D_EXACT_NAMLEN (d) + 1; + + if (needed > buflen) + { + *dostat = -1; + (void) __closedir (dirstream); + __set_errno (ERANGE); + return ERANGE; + } + + cp = __stpncpy (&buf[sizeof (dev)], d->d_name, needed); + cp[0] = '\0'; + + if (stat (buf, &st) == 0 +#ifdef _STATBUF_ST_RDEV + && S_ISCHR (st.st_mode) && st.st_rdev == mydev +#else + && (ino_t) d->d_fileno == myino && st.st_dev == mydev +#endif + ) + { + (void) __closedir (dirstream); + __set_errno (save); + return 0; + } + } + + (void) __closedir (dirstream); + __set_errno (save); + /* It is not clear what to return in this case. `isatty' says FD + refers to a TTY but no entry in /dev has this inode. */ + return ENOTTY; +} + +/* Store at most BUFLEN character of the pathname of the terminal FD is + open on in BUF. Return 0 on success, otherwise an error number. */ +int +__ttyname_r (int fd, char *buf, size_t buflen) +{ + struct stat st; + int dostat = 0; + int save = errno; + int ret; + + /* Test for the absolute minimal size. This makes life easier inside + the loop. */ + if (!buf) + { + __set_errno (EINVAL); + return EINVAL; + } + + if (buflen < (int) (sizeof (dev) + 1)) + { + __set_errno (ERANGE); + return ERANGE; + } + + if (!__isatty (fd)) + { + __set_errno (ENOTTY); + return ENOTTY; + } + + if (fstat (fd, &st) < 0) + return errno; + + /* Prepare the result buffer. */ + memcpy (buf, dev, sizeof (dev) - 1); + buf[sizeof (dev) - 1] = '/'; + buflen -= sizeof (dev); + +#ifdef _STATBUF_ST_RDEV + ret = getttyname_r (fd, buf, buflen, st.st_rdev, st.st_ino, save, + &dostat); +#else + ret = getttyname_r (fd, buf, buflen, st.st_dev, st.st_ino, save, + &dostat); +#endif + + if (ret && dostat != -1) + { + dostat = 1; +#ifdef _STATBUF_ST_RDEV + ret = getttyname_r (fd, buf, buflen, st.st_rdev, st.st_ino, + save, &dostat); +#else + ret = getttyname_r (fd, buf, buflen, st.st_dev, st.st_ino, + save, &dostat); +#endif + } + + return ret; +} + +weak_alias (__ttyname_r, ttyname_r) diff --git a/REORG.TODO/sysdeps/posix/ulimit.c b/REORG.TODO/sysdeps/posix/ulimit.c new file mode 100644 index 0000000000..2ae34758e2 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/ulimit.c @@ -0,0 +1,92 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdarg.h> +#include <sysdep.h> +#include <ulimit.h> +#include <unistd.h> +#include <limits.h> +#include <sys/resource.h> + +/* Function depends on CMD: + 1 = Return the limit on the size of a file, in units of 512 bytes. + 2 = Set the limit on the size of a file to NEWLIMIT. Only the + super-user can increase the limit. + 3 = illegal due to shared libraries; normally is + (Return the maximum possible address of the data segment.) + 4 = Return the maximum number of files that the calling process + can open. + Returns -1 on errors. */ +long int +__ulimit (int cmd, ...) +{ + struct rlimit limit; + va_list va; + long int result = -1; + + va_start (va, cmd); + + switch (cmd) + { + case UL_GETFSIZE: + /* Get limit on file size. */ + if (__getrlimit (RLIMIT_FSIZE, &limit) == 0) + /* Convert from bytes to 512 byte units. */ + result = (limit.rlim_cur == RLIM_INFINITY + ? LONG_MAX : limit.rlim_cur / 512); + break; + + case UL_SETFSIZE: + /* Set limit on file size. */ + { + long int newlimit = va_arg (va, long int); + long int newlen; + + if ((rlim_t) newlimit > RLIM_INFINITY / 512) + { + limit.rlim_cur = RLIM_INFINITY; + limit.rlim_max = RLIM_INFINITY; + newlen = LONG_MAX; + } + else + { + limit.rlim_cur = newlimit * 512; + limit.rlim_max = newlimit * 512; + newlen = newlimit; + } + + result = __setrlimit (RLIMIT_FSIZE, &limit); + if (result != -1) + result = newlen; + } + break; + + case __UL_GETOPENMAX: + result = __sysconf (_SC_OPEN_MAX); + break; + + default: + __set_errno (EINVAL); + } + + va_end (va); + + return result; +} + +weak_alias (__ulimit, ulimit); diff --git a/REORG.TODO/sysdeps/posix/usleep.c b/REORG.TODO/sysdeps/posix/usleep.c new file mode 100644 index 0000000000..581d2c2d39 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/usleep.c @@ -0,0 +1,33 @@ +/* Implementation of the BSD usleep function using nanosleep. + Copyright (C) 1996-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <time.h> +#include <unistd.h> + +int +usleep (useconds_t useconds) +{ + struct timespec ts = { .tv_sec = (long int) (useconds / 1000000), + .tv_nsec = (long int) (useconds % 1000000) * 1000ul }; + + /* Note the usleep() is a cancellation point. But since we call + nanosleep() which itself is a cancellation point we do not have + to do anything here. */ + return __nanosleep (&ts, NULL); +} diff --git a/REORG.TODO/sysdeps/posix/utime.c b/REORG.TODO/sysdeps/posix/utime.c new file mode 100644 index 0000000000..c8fe60ba91 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/utime.c @@ -0,0 +1,47 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sysdep.h> +#include <errno.h> +#include <utime.h> +#include <time.h> +#include <sys/types.h> +#include <sys/time.h> + + +/* Set the access and modification times of FILE to those given in TIMES. + If TIMES is NULL, set them to the current time. */ +int +utime (const char *file, const struct utimbuf *times) +{ + struct timeval timevals[2]; + struct timeval *tvp; + + if (times != NULL) + { + timevals[0].tv_sec = (time_t) times->actime; + timevals[0].tv_usec = 0L; + timevals[1].tv_sec = (time_t) times->modtime; + timevals[1].tv_usec = 0L; + tvp = timevals; + } + else + tvp = NULL; + + return __utimes (file, tvp); +} +libc_hidden_def (utime) diff --git a/REORG.TODO/sysdeps/posix/utimes.c b/REORG.TODO/sysdeps/posix/utimes.c new file mode 100644 index 0000000000..22caec24ec --- /dev/null +++ b/REORG.TODO/sysdeps/posix/utimes.c @@ -0,0 +1,42 @@ +/* Copyright (C) 1995-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <utime.h> +#include <sys/time.h> +#include <errno.h> +#include <stddef.h> + +/* Change the access time of FILE to TVP[0] and + the modification time of FILE to TVP[1]. */ +int +__utimes (const char *file, const struct timeval tvp[2]) +{ + struct utimbuf buf, *times; + + if (tvp) + { + times = &buf; + buf.actime = tvp[0].tv_sec + tvp[0].tv_usec / 1000000; + buf.modtime = tvp[1].tv_sec + tvp[1].tv_usec / 1000000; + } + else + times = NULL; + + return utime (file, times); +} + +weak_alias (__utimes, utimes) diff --git a/REORG.TODO/sysdeps/posix/wait.c b/REORG.TODO/sysdeps/posix/wait.c new file mode 100644 index 0000000000..f00d24b198 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/wait.c @@ -0,0 +1,30 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <sys/wait.h> + + +/* Wait for a child to die. When one does, put its status in *STAT_LOC + and return its process ID. For errors, return (pid_t) -1. */ +__pid_t +__libc_wait (int *stat_loc) +{ + return __waitpid (WAIT_ANY, (int *) stat_loc, 0); +} + +weak_alias (__libc_wait, __wait) +weak_alias (__libc_wait, wait) diff --git a/REORG.TODO/sysdeps/posix/wait3.c b/REORG.TODO/sysdeps/posix/wait3.c new file mode 100644 index 0000000000..a65214fdfc --- /dev/null +++ b/REORG.TODO/sysdeps/posix/wait3.c @@ -0,0 +1,39 @@ +/* Copyright (C) 1992-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <stddef.h> + +/* Wait for a child to exit. When one does, put its status in *STAT_LOC and + return its process ID. For errors return (pid_t) -1. If USAGE is not nil, + store information about the child's resource usage (as a `struct rusage') + there. If the WUNTRACED bit is set in OPTIONS, return status for stopped + children; otherwise don't. */ +pid_t +__wait3 (int *stat_loc, int options, struct rusage *usage) +{ + if (usage != NULL) + { + __set_errno (ENOSYS); + return (pid_t) -1; + } + return __waitpid (WAIT_ANY, stat_loc, options); +} + +weak_alias (__wait3, wait3) diff --git a/REORG.TODO/sysdeps/posix/waitid.c b/REORG.TODO/sysdeps/posix/waitid.c new file mode 100644 index 0000000000..2c23cdbb25 --- /dev/null +++ b/REORG.TODO/sysdeps/posix/waitid.c @@ -0,0 +1,166 @@ +/* Pseudo implementation of waitid. + Copyright (C) 1997-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Zack Weinberg <zack@rabi.phys.columbia.edu>, 1997. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <assert.h> +#include <errno.h> +#include <signal.h> +#define __need_NULL +#include <stddef.h> +#include <sys/wait.h> +#include <sys/types.h> +#include <sysdep-cancel.h> + + +#ifdef DO_WAITID +# define OUR_WAITID DO_WAITID +#elif !defined NO_DO_WAITID +# define OUR_WAITID do_waitid +#endif + +#ifdef OUR_WAITID +static int +OUR_WAITID (idtype_t idtype, id_t id, siginfo_t *infop, int options) +{ + pid_t pid, child; + int status; + + switch (idtype) + { + case P_PID: + if(id <= 0) + goto invalid; + pid = (pid_t) id; + break; + case P_PGID: + if (id < 0 || id == 1) + goto invalid; + pid = (pid_t) -id; + break; + case P_ALL: + pid = -1; + break; + default: + invalid: + __set_errno (EINVAL); + return -1; + } + + /* Technically we're supposed to return EFAULT if infop is bogus, + but that would involve mucking with signals, which is + too much hassle. User will have to deal with SIGSEGV/SIGBUS. + We just check for a null pointer. */ + + if (infop == NULL) + { + __set_errno (EFAULT); + return -1; + } + + /* This emulation using waitpid cannot support the waitid modes in which + we do not reap the child, or match only stopped and not dead children. */ + if (0 +#ifdef WNOWAIT + || (options & WNOWAIT) +#endif +#ifdef WEXITED + || ((options & (WEXITED|WSTOPPED|WCONTINUED)) + != (WEXITED | (options & WSTOPPED))) +#endif + ) + { + __set_errno (ENOTSUP); + return -1; + } + + /* Note the waitid() is a cancellation point. But since we call + waitpid() which itself is a cancellation point we do not have + to do anything here. */ + child = __waitpid (pid, &status, + options +#ifdef WEXITED + &~ WEXITED +#endif + ); + + if (child == -1) + /* `waitpid' set `errno' for us. */ + return -1; + + if (child == 0) + { + /* The WHOHANG bit in OPTIONS is set and there are children available + but none has a status for us. The XPG docs do not mention this + case so we clear the `siginfo_t' struct and return successfully. */ + infop->si_signo = 0; + infop->si_code = 0; + return 0; + } + + /* Decode the status field and set infop members... */ + infop->si_signo = SIGCHLD; + infop->si_pid = child; + infop->si_errno = 0; + + if (WIFEXITED (status)) + { + infop->si_code = CLD_EXITED; + infop->si_status = WEXITSTATUS (status); + } + else if (WIFSIGNALED (status)) + { + infop->si_code = WCOREDUMP (status) ? CLD_DUMPED : CLD_KILLED; + infop->si_status = WTERMSIG (status); + } + else if (WIFSTOPPED (status)) + { + infop->si_code = CLD_STOPPED; + infop->si_status = WSTOPSIG (status); + } +#ifdef WIFCONTINUED + else if (WIFCONTINUED (status)) + { + infop->si_code = CLD_CONTINUED; + infop->si_status = SIGCONT; + } +#endif + else + /* Can't happen. */ + assert (! "What?"); + + return 0; +} +#endif + + +int +__waitid (idtype_t idtype, id_t id, siginfo_t *infop, int options) +{ + if (SINGLE_THREAD_P) + return do_waitid (idtype, id, infop, options); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = do_waitid (idtype, id, infop, options); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} +weak_alias (__waitid, waitid) +strong_alias (__waitid, __libc_waitid) diff --git a/REORG.TODO/sysdeps/posix/writev.c b/REORG.TODO/sysdeps/posix/writev.c new file mode 100644 index 0000000000..7ce1deb80f --- /dev/null +++ b/REORG.TODO/sysdeps/posix/writev.c @@ -0,0 +1,91 @@ +/* Copyright (C) 1991-2017 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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.1 of the License, or (at your option) any later version. + + The GNU C 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 the GNU C Library; if not, see + <http://www.gnu.org/licenses/>. */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <limits.h> +#include <stdbool.h> +#include <sys/param.h> +#include <sys/uio.h> +#include <errno.h> + + +static void +ifree (char **ptrp) +{ + free (*ptrp); +} + + +/* Write data pointed by the buffers described by VECTOR, which + is a vector of COUNT 'struct iovec's, to file descriptor FD. + The data is written in the order specified. + Operates just like 'write' (see <unistd.h>) except that the data + are taken from VECTOR instead of a contiguous buffer. */ +ssize_t +__writev (int fd, const struct iovec *vector, int count) +{ + /* Find the total number of bytes to be written. */ + size_t bytes = 0; + for (int i = 0; i < count; ++i) + { + /* Check for ssize_t overflow. */ + if (SSIZE_MAX - bytes < vector[i].iov_len) + { + __set_errno (EINVAL); + return -1; + } + bytes += vector[i].iov_len; + } + + /* Allocate a temporary buffer to hold the data. We should normally + use alloca since it's faster and does not require synchronization + with other threads. But we cannot if the amount of memory + required is too large. */ + char *buffer; + char *malloced_buffer __attribute__ ((__cleanup__ (ifree))) = NULL; + if (__libc_use_alloca (bytes)) + buffer = (char *) __alloca (bytes); + else + { + malloced_buffer = buffer = (char *) malloc (bytes); + if (buffer == NULL) + /* XXX I don't know whether it is acceptable to try writing + the data in chunks. Probably not so we just fail here. */ + return -1; + } + + /* Copy the data into BUFFER. */ + size_t to_copy = bytes; + char *bp = buffer; + for (int i = 0; i < count; ++i) + { + size_t copy = MIN (vector[i].iov_len, to_copy); + + bp = __mempcpy ((void *) bp, (void *) vector[i].iov_base, copy); + + to_copy -= copy; + if (to_copy == 0) + break; + } + + ssize_t bytes_written = __write (fd, buffer, bytes); + + return bytes_written; +} +weak_alias (__writev, writev) |