/****************************************************************************
 * include/unistd.h
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.  The
 * ASF licenses this file to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance with the
 * License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 * License for the specific language governing permissions and limitations
 * under the License.
 *
 ****************************************************************************/

#ifndef __INCLUDE_UNISTD_H
#define __INCLUDE_UNISTD_H

/****************************************************************************
 * Included Files
 ****************************************************************************/

#include <sys/types.h>
#include <limits.h>

#include <nuttx/compiler.h>
#include <nuttx/tls.h>

/****************************************************************************
 * Pre-processor Definitions
 ****************************************************************************/

/* Bit values for the second argument to access */

#define F_OK        0  /* Test existence */
#define X_OK        1  /* Test execute permission */
#define W_OK        2  /* Test write permission */
#define R_OK        4  /* Test read permission */

/* POSIX feature set macros */

#define POSIX_VERSION
#undef  _POSIX_SAVED_IDS
#undef  _POSIX_JOB_CONTROL
#define _POSIX_MESSAGE_PASSING 200112L
#define _POSIX_PRIORITY_SCHEDULING 1
#ifndef CONFIG_DISABLE_POSIX_TIMERS
#  define _POSIX_TIMERS 200112L
#endif
#if !defined(CONFIG_DISABLE_MQUEUE) && !defined(CONFIG_DISABLE_PTHREAD)
#  define _POSIX_TIMEOUTS 1
#endif
#define _POSIX_MEMLOCK 200112L
#define _POSIX_MEMLOCK_RANGE 200112L
#define _POSIX_FSYNC 200112L
#define _POSIX_SYNCHRONIZED_IO 200112L
#ifdef CONFIG_LIBC_PASSWD_LINESIZE
#  define _POSIX_GETPW_R_SIZE_MAX CONFIG_LIBC_PASSWD_LINESIZE
#endif

#define _POSIX_VERSION 201712L
#define _POSIX_PRIORITIZED_IO _POSIX_VERSION
#define _POSIX_CPUTIME _POSIX_VERSION
#define _POSIX_THREAD_CPUTIME _POSIX_VERSION
#define _POSIX_REALTIME_SIGNALS _POSIX_VERSION
#define _POSIX_THREAD_PRIORITY_SCHEDULING _POSIX_VERSION
#define _POSIX_SEMAPHORES _POSIX_VERSION
#define _POSIX_SHARED_MEMORY_OBJECTS _POSIX_VERSION
#define _POSIX_THREAD_PROCESS_SHARED _POSIX_VERSION
#define _POSIX_MAPPED_FILES _POSIX_VERSION
#define _POSIX_THREADS _POSIX_VERSION

/* For the PSE52 certification, define the following macros */

#define _POSIX_THREAD_ATTR_STACKADDR 200112L
#define _POSIX_THREAD_ATTR_STACKSIZE 200112L
#define _POSIX_THREAD_PRIO_INHERIT 200112L
#define _POSIX_THREAD_PRIO_PROTECT 200112L

#define _POSIX_THREAD_SAFE_FUNCTIONS 200112L

#ifdef CONFIG_FS_AIO
#  define _POSIX_ASYNCHRONOUS_IO _POSIX_VERSION
#else
#  undef  _POSIX_ASYNCHRONOUS_IO
#endif

#ifdef CONFIG_SCHED_SPORADIC
#  define _POSIX_SPORADIC_SERVER 1
#  define _POSIX_THREAD_SPORADIC_SERVER 1
#else
#  define _POSIX_SPORADIC_SERVER -1
#  define _POSIX_THREAD_SPORADIC_SERVER -1
#endif

/* Execution time constants (not supported) */

#define _POSIX_CHOWN_RESTRICTED 1
#define _POSIX_NO_TRUNC 1
#undef  _POSIX_VDISABLE

#define _POSIX_SYNC_IO 1
#define _POSIX_ASYNC_IO 1
#define _POSIX_PRIO_IO -1

#define _XOPEN_UNIX 1
#define _XOPEN_VERSION 700L

/* Constants used with POSIX pathconf().  pathconf() will return -1 and set
 * errno to ENOSYS for most of these.
 */

#define _PC_2_SYMLINKS                   0x0001
#define _PC_ALLOC_SIZE_MIN               0x0002
#define _PC_ASYNC_IO                     0x0003
#define _PC_CHOWN_RESTRICTED             0x0004
#define _PC_FILESIZEBITS                 0x0005
#define _PC_LINK_MAX                     0x0006
#define _PC_MAX_CANON                    0x0007
#define _PC_MAX_INPUT                    0x0008
#define _PC_NAME_MAX                     0x0009
#define _PC_NO_TRUNC                     0x000a
#define _PC_PATH_MAX                     0x000b
#define _PC_PIPE_BUF                     0x000c
#define _PC_PRIO_IO                      0x000d
#define _PC_REC_INCR_XFER_SIZE           0x000e
#define _PC_REC_MIN_XFER_SIZE            0x000f
#define _PC_REC_XFER_ALIGN               0x0010
#define _PC_SYMLINK_MAX                  0x0011
#define _PC_SYNC_IO                      0x0012
#define _PC_VDISABLE                     0x0013
#define _PC_REC_MAX_XFER_SIZE            0x0014

/* Constants used with POSIX sysconf().  sysconf() will return -1 and set
 * errno to ENOSYS for most of these.
 */

#define _SC_2_C_BIND                     0x0001
#define _SC_2_C_DEV                      0x0002
#define _SC_2_CHAR_TERM                  0x0003
#define _SC_2_FORT_DEV                   0x0004
#define _SC_2_FORT_RUN                   0x0005
#define _SC_2_LOCALEDEF                  0x0006
#define _SC_2_PBS                        0x0007
#define _SC_2_PBS_ACCOUNTING             0x0008
#define _SC_2_PBS_CHECKPOINT             0x0009
#define _SC_2_PBS_LOCATE                 0x000a
#define _SC_2_PBS_MESSAGE                0x000b
#define _SC_2_PBS_TRACK                  0x000c
#define _SC_2_SW_DEV                     0x000d
#define _SC_2_UPE                        0x000e
#define _SC_2_VERSION                    0x000f
#define _SC_ADVISORY_INFO                0x0010
#define _SC_AIO_LISTIO_MAX               0x0011
#define _SC_AIO_MAX                      0x0012
#define _SC_AIO_PRIO_DELTA_MAX           0x0013
#define _SC_ARG_MAX                      0x0014
#define _SC_ASYNCHRONOUS_IO              0x0015
#define _SC_ATEXIT_MAX                   0x0016
#define _SC_BARRIERS                     0x0017
#define _SC_BC_BASE_MAX                  0x0018
#define _SC_BC_DIM_MAX                   0x0019
#define _SC_BC_SCALE_MAX                 0x001a
#define _SC_BC_STRING_MAX                0x001b
#define _SC_CHILD_MAX                    0x001c
#define _SC_CLK_TCK                      0x001d
#define _SC_CLOCK_SELECTION              0x001e
#define _SC_COLL_WEIGHTS_MAX             0x001f
#define _SC_CPUTIME                      0x0020
#define _SC_DELAYTIMER_MAX               0x0021
#define _SC_EXPR_NEST_MAX                0x0022
#define _SC_FSYNC                        0x0023
#define _SC_GETGR_R_SIZE_MAX             0x0024
#define _SC_GETPW_R_SIZE_MAX             0x0025
#define _SC_HOST_NAME_MAX                0x0026
#define _SC_IOV_MAX                      0x0027
#define _SC_IPV6                         0x0028
#define _SC_JOB_CONTROL                  0x0029
#define _SC_LINE_MAX                     0x002a
#define _SC_LOGIN_NAME_MAX               0x002b
#define _SC_MAPPED_FILES                 0x002c
#define _SC_MEMLOCK                      0x002d
#define _SC_MEMLOCK_RANGE                0x002e
#define _SC_MEMORY_PROTECTION            0x002f
#define _SC_MESSAGE_PASSING              0x0030
#define _SC_MONOTONIC_CLOCK              0x0031
#define _SC_MQ_OPEN_MAX                  0x0032
#define _SC_MQ_PRIO_MAX                  0x0033
#define _SC_NGROUPS_MAX                  0x0034
#define _SC_OPEN_MAX                     0x0035
#define _SC_PAGE_SIZE                    0x0036
#define _SC_PAGESIZE                     _SC_PAGE_SIZE
#define _SC_PRIORITIZED_IO               0x0037
#define _SC_PRIORITY_SCHEDULING          0x0038
#define _SC_RAW_SOCKETS                  0x0039
#define _SC_RE_DUP_MAX                   0x003a
#define _SC_READER_WRITER_LOCKS          0x003b
#define _SC_REALTIME_SIGNALS             0x003c
#define _SC_REGEXP                       0x003d
#define _SC_RTSIG_MAX                    0x003e
#define _SC_SAVED_IDS                    0x003f
#define _SC_SEM_NSEMS_MAX                0x0040
#define _SC_SEM_VALUE_MAX                0x0041
#define _SC_SEMAPHORES                   0x0042
#define _SC_SHARED_MEMORY_OBJECTS        0x0043
#define _SC_SHELL                        0x0044
#define _SC_SIGQUEUE_MAX                 0x0045
#define _SC_SPAWN                        0x0046
#define _SC_SPIN_LOCKS                   0x0047
#define _SC_SPORADIC_SERVER              0x0048
#define _SC_SS_REPL_MAX                  0x0049
#define _SC_STREAM_MAX                   0x004a
#define _SC_SYMLOOP_MAX                  0x004b
#define _SC_SYNCHRONIZED_IO              0x004c
#define _SC_THREAD_ATTR_STACKADDR        0x004d
#define _SC_THREAD_ATTR_STACKSIZE        0x004e
#define _SC_THREAD_CPUTIME               0x004f
#define _SC_THREAD_DESTRUCTOR_ITERATIONS 0x0050
#define _SC_THREAD_KEYS_MAX              0x0051
#define _SC_THREAD_PRIO_INHERIT          0x0052
#define _SC_THREAD_PRIO_PROTECT          0x0053
#define _SC_THREAD_PRIORITY_SCHEDULING   0x0054
#define _SC_THREAD_PROCESS_SHARED        0x0055
#define _SC_THREAD_SAFE_FUNCTIONS        0x0056
#define _SC_THREAD_SPORADIC_SERVER       0x0057
#define _SC_THREAD_STACK_MIN             0x0058
#define _SC_THREAD_THREADS_MAX           0x0059
#define _SC_THREADS                      0x005a
#define _SC_TIMEOUTS                     0x005b
#define _SC_TIMER_MAX                    0x005c
#define _SC_TIMERS                       0x005d
#define _SC_TRACE                        0x005e
#define _SC_TRACE_EVENT_FILTER           0x005f
#define _SC_TRACE_EVENT_NAME_MAX         0x0060
#define _SC_TRACE_INHERIT                0x0061
#define _SC_TRACE_LOG                    0x0062
#define _SC_TRACE_NAME_MAX               0x0063
#define _SC_TRACE_SYS_MAX                0x0064
#define _SC_TRACE_USER_EVENT_MAX         0x0065
#define _SC_TTY_NAME_MAX                 0x0066
#define _SC_TYPED_MEMORY_OBJECTS         0x0067
#define _SC_TZNAME_MAX                   0x0068
#define _SC_V6_ILP32_OFF32               0x0069
#define _SC_V6_ILP32_OFFBIG              0x006a
#define _SC_V6_LP64_OFF64                0x006b
#define _SC_V6_LPBIG_OFFBIG              0x006c
#define _SC_VERSION                      0x006d
#define _SC_XBS5_ILP32_OFF32             0x006e  /* (LEGACY) */
#define _SC_XBS5_ILP32_OFFBIG            0x006f  /* (LEGACY) */
#define _SC_XBS5_LP64_OFF64              0x0070  /* (LEGACY) */
#define _SC_XBS5_LPBIG_OFFBIG            0x0071  /* (LEGACY) */
#define _SC_XOPEN_CRYPT                  0x0072
#define _SC_XOPEN_ENH_I18N               0x0073
#define _SC_XOPEN_LEGACY                 0x0074
#define _SC_XOPEN_REALTIME               0x0075
#define _SC_XOPEN_REALTIME_THREADS       0x0076
#define _SC_XOPEN_SHM                    0x0077
#define _SC_XOPEN_STREAMS                0x0078
#define _SC_XOPEN_UNIX                   0x0079
#define _SC_XOPEN_VERSION                0x007a

#define _SC_PHYS_PAGES                   0x007b
#define _SC_AVPHYS_PAGES                 0x007c

#define _SC_NPROCESSORS_CONF             0x007d
#define _SC_NPROCESSORS_ONLN             0x007e

/* Constants used with POSIX confstr(). */

#define _CS_PATH                           1
#define _CS_POSIX_V6_ILP32_OFF32_CFLAGS    2
#define _CS_POSIX_V6_ILP32_OFF32_LDFLAGS   3
#define _CS_POSIX_V6_ILP32_OFF32_LIBS      4
#define _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS   5
#define _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS  6
#define _CS_POSIX_V6_ILP32_OFFBIG_LIBS     7
#define _CS_POSIX_V6_LP64_OFF64_CFLAGS     8
#define _CS_POSIX_V6_LP64_OFF64_LDFLAGS    9
#define _CS_POSIX_V6_LP64_OFF64_LIBS       10
#define _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS   11
#define _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS  12
#define _CS_POSIX_V6_LPBIG_OFFBIG_LIBS     13
#define _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS 14

/* The following symbolic constants must be defined for file streams: */

#define STDERR_FILENO                    2       /* File number of stderr */
#define STDIN_FILENO                     0       /* File number of stdin */
#define STDOUT_FILENO                    1       /* File number of stdout */

/* Helpers and legacy compatibility definitions */

#define getdtablesize(f)                 ((int)sysconf(_SC_OPEN_MAX))
#define getpagesize(f)                   ((int)sysconf(_SC_PAGESIZE))

/* Accessor functions associated with getopt(). */

#define optarg                           (*(getoptargp()))
#define opterr                           (*(getopterrp()))
#define optind                           (*(getoptindp()))
#define optopt                           (*(getoptoptp()))

#if defined(CONFIG_FS_LARGEFILE)
#  define lseek64                        lseek
#  define pread64                        pread
#  define pwrite64                       pwrite
#  define truncate64                     truncate
#  define ftruncate64                    ftruncate
#  define lockf64                        lockf
#endif

/* NOTE: NuttX provides only one implementation:  If
 * CONFIG_LIBC_ENVPATH is defined, then only execvp/execlp/execvpe behavior
 * is supported; otherwise, only execv/execl/execve behavior is supported.
 */

#ifdef CONFIG_LIBC_EXECFUNCS
#  define execvp                         execv
#  define execlp                         execl
#  define execvpe                        execve
#endif

/* Commands for lockf()
 * F_ULOCK - Unlock
 * F_LOCK  - Blocking Exclusive Lock
 * F_TLOCK - Attempted Exclusive Locking
 * F_TEST  - Test Locked Status
 */

#define F_ULOCK                          0
#define F_LOCK                           1
#define F_TLOCK                          2
#define F_TEST                           3

#if defined(CONFIG_BUILD_FLAT) || defined(__KERNEL__)
#  define _SCHED_GETTID()            nxsched_gettid()
#else
#  define _SCHED_GETTID()            gettid()
#endif

/****************************************************************************
 * Public Data
 ****************************************************************************/

#undef EXTERN
#if defined(__cplusplus)
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif

/****************************************************************************
 * Public Function Prototypes
 ****************************************************************************/

/* Task Control Interfaces */

pid_t   fork(void);
pid_t   vfork(void);
pid_t   getpid(void);
pid_t   getpgid(pid_t);
pid_t   getpgrp(void);
pid_t   getppid(void);
void    _exit(int) noreturn_function;
unsigned int sleep(unsigned int);
int     usleep(useconds_t);
int     pause(void);
int     nice(int);

int     daemon(int, int);

/* File descriptor operations */

int     close(int);
int     dup(int);
int     dup2(int, int);
int     dup3(int, int, int);
int     fsync(int);
int     fdatasync(int);
off_t   lseek(int, off_t, int);
ssize_t read(int, FAR void *, size_t);
ssize_t write(int, FAR const void *, size_t);
ssize_t pread(int, FAR void *, size_t, off_t);
ssize_t pwrite(int, FAR const void *, size_t, off_t);
int     ftruncate(int, off_t);
int     fchown(int, uid_t, gid_t);
int     lockf(int, int, off_t);

/* Check if a file descriptor corresponds to a terminal I/O file */

int     isatty(int);

FAR char *ttyname(int);
int       ttyname_r(int, FAR char *, size_t);

/* Memory management */

#if defined(CONFIG_ARCH_ADDRENV) && defined(CONFIG_MM_PGALLOC) && \
    defined(CONFIG_ARCH_USE_MMU)
FAR void *sbrk(intptr_t incr);
#endif

/* Special devices */

int     pipe(int pipefd[2]);
int     pipe2(int pipefd[2], int flags);

/* Schedule an alarm */

unsigned int alarm(unsigned int);

/* Working directory operations */

int     chdir(FAR const char *);
int     fchdir(int);
FAR char *getcwd(FAR char *, size_t);
FAR char *get_current_dir_name(void);

/* File path operations */

int     access(FAR const char *, int);
int     faccessat(int, FAR const char *, int, int);
int     rmdir(FAR const char *);
int     unlink(FAR const char *);
int     unlinkat(int, FAR const char *, int);
int     truncate(FAR const char *, off_t);
int     link(FAR const char *, FAR const char *);
int     linkat(int, FAR const char *, int, FAR const char *, int);
int     symlink(FAR const char *, FAR const char *);
int     symlinkat(FAR const char *, int, FAR const char *);
ssize_t readlink(FAR const char *, FAR char *, size_t);
ssize_t readlinkat(int, FAR const char *, FAR char *, size_t);
int     chown(FAR const char *, uid_t, gid_t);
int     lchown(FAR const char *, uid_t, gid_t);
int     fchownat(int, FAR const char *, uid_t, gid_t, int);

/* Execution of programs from files */

#ifdef CONFIG_LIBC_EXECFUNCS
int     execl(FAR const char *, FAR const char *, ...);
int     execle(FAR const char *, FAR const char *, ...);
int     execv(FAR const char *, FAR char * const[]);
int     execve(FAR const char *, FAR char *const[],
               FAR char *const[]);
#endif

/* Byte operations */

void    swab(FAR const void *, FAR void *, ssize_t);

/* getopt and friends */

int     getopt(int, FAR char * const[], FAR const char *);

/* Accessor functions associated with getopt(). */

FAR char **getoptargp(void);  /* Optional argument following option */
FAR int   *getopterrp(void);  /* Print error message */
FAR int   *getoptindp(void);  /* Index into argv */
FAR int   *getoptoptp(void);  /* Unrecognized option character */

int     gethostname(FAR char *, size_t);
int     sethostname(FAR const char *, size_t);

/* Get configurable system variables */

long    sysconf(int);
long    fpathconf(int, int);
long    pathconf(FAR const char *, int);
size_t  confstr(int, FAR char *, size_t);

/* User and group identity management */

int     setuid(uid_t);
uid_t   getuid(void);
int     setgid(gid_t);
gid_t   getgid(void);

int     seteuid(uid_t);
uid_t   geteuid(void);
int     setegid(gid_t);
gid_t   getegid(void);

int     setreuid(uid_t, uid_t);
int     setregid(gid_t, gid_t);

int     getentropy(FAR void *, size_t);

void    sync(void);
int     syncfs(int);

int     profil(FAR unsigned short *, size_t, size_t, unsigned int);

FAR char *getpass(FAR const char *);
#ifdef CONFIG_CRYPTO
FAR char *crypt(FAR const char *, FAR const char *);
FAR char *crypt_r(FAR const char *, FAR const char *, FAR char *);
#endif

/****************************************************************************
 * Inline Functions
 ****************************************************************************/

/****************************************************************************
 * Name: gettid
 *
 * Description:
 *   Get the thread ID of the currently executing thread.
 *
 * Input parameters:
 *   None
 *
 * Returned Value:
 *   On success, returns the thread ID of the calling process.
 *
 ****************************************************************************/

static inline_function pid_t gettid(void)
{
#ifdef TLS_FROM_TCB
  DEBUGASSERT(this_task()->pid ==
              ((FAR struct tls_info_s *)tls_get_info())->tl_tid);
  return this_task()->pid;
#else
  FAR struct tls_info_s *tls = tls_get_info();
  return tls ? tls->tl_tid : IDLE_PROCESS_ID;
#endif
}

#if CONFIG_FORTIFY_SOURCE > 0
fortify_function(getcwd) FAR char *getcwd(FAR char *buf,
                                          size_t size)
{
  fortify_assert(size <= fortify_size(buf, 0));
  return __real_getcwd(buf, size);
}

fortify_function(gethostname) int gethostname(FAR char *name,
                                              size_t namelen)
{
  fortify_assert(namelen <= fortify_size(name, 0));
  return __real_gethostname(name, namelen);
}

fortify_function(pread) ssize_t pread(int fd, FAR void *buf,
                                      size_t nbytes, off_t offset)
{
  fortify_assert(nbytes <= fortify_size(buf, 0));
  return __real_pread(fd, buf, nbytes, offset);
}

fortify_function(read) ssize_t read(int fd, FAR void *buf,
                                    size_t nbytes)
{
  fortify_assert(nbytes <= fortify_size(buf, 0));
  return __real_read(fd, buf, nbytes);
}

fortify_function(readlink) ssize_t readlink(FAR const char *path,
                                            FAR char *buf,
                                            size_t bufsize)
{
  fortify_assert(bufsize <= fortify_size(buf, 0));
  return __real_readlink(path, buf, bufsize);
}

fortify_function(readlinkat) ssize_t readlinkat(int dirfd,
                                                FAR const char *path,
                                                FAR char *buf,
                                                size_t bufsize)
{
  fortify_assert(bufsize <= fortify_size(buf, 0));
  return __real_readlinkat(dirfd, path, buf, bufsize);
}

fortify_function(ttyname_r) int ttyname_r(int fd, FAR char *buf,
                                          size_t buflen)
{
  fortify_assert(buflen <= fortify_size(buf, 0));
  return __real_ttyname_r(fd, buf, buflen);
}

fortify_function(pwrite) ssize_t pwrite(int fd, FAR const void *buf,
                                        size_t nbytes, off_t offset)
{
  fortify_assert(nbytes <= fortify_size(buf, 0));
  return __real_pwrite(fd, buf, nbytes, offset);
}

fortify_function(write) ssize_t write(int fd, FAR const void *buf,
                                      size_t nbytes)
{
  fortify_assert(nbytes <= fortify_size(buf, 0));
  return __real_write(fd, buf, nbytes);
}
#endif

#undef EXTERN
#if defined(__cplusplus)
}
#endif

#endif /* __INCLUDE_UNISTD_H */