static void resend_signal(siginfo_t* info, bool crash_dump_started) { // Signals can either be fatal or nonfatal. // For fatal signals, crash_dump will send us the signal we crashed with // before resuming us, so that processes using waitpid on us will see that we // exited with the correct exit status (e.g. so that sh will report // "Segmentation fault" instead of "Killed"). For this to work, we need // to deregister our signal handler for that signal before continuing. if (info->si_signo != DEBUGGER_SIGNAL) { signal(info->si_signo, SIG_DFL); } // We need to return from our signal handler so that crash_dump can see the // signal via ptrace and dump the thread that crashed. However, returning // does not guarantee that the signal will be thrown again, even for SIGSEGV // and friends, since the signal could have been sent manually. We blocked // all signals when registering the handler, so resending the signal (using // rt_tgsigqueueinfo(2) to preserve SA_SIGINFO) will cause it to be delivered // when our signal handler returns. if (crash_dump_started || info->si_signo != DEBUGGER_SIGNAL) { int rc = syscall(SYS_rt_tgsigqueueinfo, __getpid(), __gettid(), info->si_signo, info); if (rc != 0) { fatal_errno("failed to resend signal during crash"); } } }
int __pthread_kill (pthread_t threadid, int signo) { struct pthread *pd = (struct pthread *) threadid; /* Make sure the descriptor is valid. */ if (DEBUGGING_P && INVALID_TD_P (pd)) /* Not a valid thread handle. */ return ESRCH; /* Force load of pd->tid into local variable or register. Otherwise if a thread exits between ESRCH test and tgkill, we might return EINVAL, because pd->tid would be cleared by the kernel. */ pid_t tid = atomic_forced_read (pd->tid); if (__glibc_unlikely (tid <= 0)) /* Not a valid thread handle. */ return ESRCH; /* Disallow sending the signal we use for cancellation, timers, for the setxid implementation. */ if (signo == SIGCANCEL || signo == SIGTIMER || signo == SIGSETXID) return EINVAL; /* We have a special syscall to do the work. */ INTERNAL_SYSCALL_DECL (err); pid_t pid = __getpid (); int val = INTERNAL_SYSCALL_CALL (tgkill, err, pid, tid, signo); return (INTERNAL_SYSCALL_ERROR_P (val, err) ? INTERNAL_SYSCALL_ERRNO (val, err) : 0); }
/* Remove the environment variable "_<PID>_GNU_nonoption_argv_flags_" if it is still available. If the getopt functions are also used in the application it does not exist anymore since it was saved for the use in getopt. */ void __getopt_clean_environment (char **env) { /* Bash 2.0 puts a special variable in the environment for each command it runs, specifying which ARGV elements are the results of file name wildcard expansion and therefore should not be considered as options. */ static const char envvar_tail[] = "_GNU_nonoption_argv_flags_="; char var[50]; char *cp, **ep; size_t len; /* Construct the "_<PID>_GNU_nonoption_argv_flags_=" string. We must not use `sprintf'. */ cp = memcpy (&var[sizeof (var) - sizeof (envvar_tail)], envvar_tail, sizeof (envvar_tail)); cp = _itoa_word (__getpid (), cp, 10, 0); /* Note: we omit adding the leading '_' since we explicitly test for it before calling strncmp. */ len = (var + sizeof (var) - 1) - cp; for (ep = env; *ep != NULL; ++ep) if ((*ep)[0] == '_' && __builtin_expect (strncmp (*ep + 1, cp, len) == 0, 0)) { /* Found it. Store this pointer and move later ones back. */ char **dp = ep; __getopt_nonoption_flags = &(*ep)[len]; do dp[0] = dp[1]; while (*dp++); /* Continue the loop in case the name appears again. */ } }
void test_pid(void) { pid_t pid; int sc; pid = getpid(); printf( "getpid = %d\n", pid ); pid = __getpid(); printf( "__getpid = %d\n", pid ); pid = getppid(); printf( "getppid = %d\n", pid ); puts( "setsid - EPERM" ); pid = setsid(); rtems_test_assert( pid == -1 ); rtems_test_assert( errno == EPERM ); sc = issetugid(); rtems_test_assert( sc == 0 ); puts( "getpgrp - return local node - OK" ); pid = getpgrp(); printf( "getpgrp returned %d\n", pid ); }
pthread_start_thread(void *arg) { pthread_descr self = (pthread_descr) arg; struct pthread_request request; void * outcome; #if HP_TIMING_AVAIL hp_timing_t tmpclock; #endif /* Initialize special thread_self processing, if any. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr); #endif #if HP_TIMING_AVAIL HP_TIMING_NOW (tmpclock); THREAD_SETMEM (self, p_cpuclock_offset, tmpclock); #endif /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ THREAD_SETMEM(self, p_pid, __getpid()); /* Initial signal mask is that of the creating thread. (Otherwise, we'd just inherit the mask of the thread manager.) */ sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); /* Set the scheduling policy and priority for the new thread, if needed */ if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) /* Explicit scheduling attributes were provided: apply them */ __sched_setscheduler(THREAD_GETMEM(self, p_pid), THREAD_GETMEM(self, p_start_args.schedpolicy), &self->p_start_args.schedparam); else if (manager_thread->p_priority > 0) /* Default scheduling required, but thread manager runs in realtime scheduling: switch new thread to SCHED_OTHER policy */ { struct sched_param default_params; default_params.sched_priority = 0; __sched_setscheduler(THREAD_GETMEM(self, p_pid), SCHED_OTHER, &default_params); } #if !(USE_TLS && HAVE___THREAD) /* Initialize thread-locale current locale to point to the global one. With __thread support, the variable's initializer takes care of this. */ __uselocale (LC_GLOBAL_LOCALE); #else /* Initialize __resp. */ __resp = &self->p_res; #endif /* Make gdb aware of new thread */ if (__pthread_threads_debug && __pthread_sig_debug > 0) { request.req_thread = self; request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); } /* Run the thread code */ outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, p_start_args.arg)); /* Exit with the given return value */ __pthread_do_exit(outcome, CURRENT_STACK_FRAME); }
/* * Bind a socket to a privileged IP port */ int bindresvport (int sd, struct sockaddr_in *sin) { static short port; struct sockaddr_in myaddr; int i; #define STARTPORT 600 #define LOWPORT 512 #define ENDPORT (IPPORT_RESERVED - 1) #define NPORTS (ENDPORT - STARTPORT + 1) static short startport = STARTPORT; if (sin == (struct sockaddr_in *) 0) { sin = &myaddr; __bzero (sin, sizeof (*sin)); sin->sin_family = AF_INET; } else if (sin->sin_family != AF_INET) { __set_errno (EAFNOSUPPORT); return -1; } if (port == 0) { port = (__getpid () % NPORTS) + STARTPORT; } /* Initialize to make gcc happy. */ int res = -1; int nports = ENDPORT - startport + 1; int endport = ENDPORT; again: for (i = 0; i < nports; ++i) { sin->sin_port = htons (port++); if (port > endport) port = startport; res = __bind (sd, (const struct sockaddr *)sin, sizeof (struct sockaddr_in)); if (res >= 0 || errno != EADDRINUSE) break; } if (i == nports && startport != LOWPORT) { startport = LOWPORT; endport = STARTPORT - 1; nports = STARTPORT - LOWPORT; port = LOWPORT + port % (STARTPORT - LOWPORT); goto again; } return res; }
void __pthread_message(char * fmt, ...) { char buffer[1024]; va_list args; sprintf(buffer, "%05d : ", __getpid()); va_start(args, fmt); vsnprintf(buffer + 8, sizeof(buffer) - 8, fmt, args); va_end(args); TEMP_FAILURE_RETRY(__libc_write(2, buffer, strlen(buffer))); }
int lockf64 (int fd, int cmd, off64_t len64) { struct flock fl; off_t len = (off_t) len64; if (len64 != (off64_t) len) { /* We can't represent the length. */ __set_errno (EOVERFLOW); return -1; } memset ((char *) &fl, '\0', sizeof (fl)); /* lockf is always relative to the current file position. */ fl.l_whence = SEEK_CUR; fl.l_start = 0; fl.l_len = len; switch (cmd) { case F_TEST: /* Test the lock: return 0 if FD is unlocked or locked by this process; return -1, set errno to EACCES, if another process holds the lock. */ fl.l_type = F_RDLCK; if (__fcntl (fd, F_GETLK, &fl) < 0) return -1; if (fl.l_type == F_UNLCK || fl.l_pid == __getpid ()) return 0; __set_errno (EACCES); return -1; case F_ULOCK: fl.l_type = F_UNLCK; cmd = F_SETLK; break; case F_LOCK: fl.l_type = F_WRLCK; cmd = F_SETLKW; break; case F_TLOCK: fl.l_type = F_WRLCK; cmd = F_SETLK; break; default: __set_errno (EINVAL); return -1; } return __fcntl (fd, cmd, &fl); }
extern "C" void __libc_init_main_thread_early(const KernelArgumentBlock& args, bionic_tcb* temp_tcb) { __libc_shared_globals()->auxv = args.auxv; #if defined(__i386__) __libc_init_sysinfo(); // uses AT_SYSINFO auxv entry #endif __init_tcb(temp_tcb, &main_thread); __init_tcb_dtv(temp_tcb); __set_tls(&temp_tcb->tls_slot(0)); main_thread.tid = __getpid(); main_thread.set_cached_pid(main_thread.tid); }
void __pthread_abort(void) { PTHREAD_NORETURN void (*_libc_abort)(void); _libc_abort = dlsym(RTLD_DEFAULT, "abort"); if (_libc_abort) { _libc_abort(); } else { __kill(__getpid(), __SIGABRT, 0); } }
pid_t getpid() { pthread_internal_t* self = __get_thread(); if (__predict_true(self)) { // Do we have a valid cached pid? pid_t cached_pid; if (__predict_true(self->get_cached_pid(&cached_pid))) { return cached_pid; } } // We're still in the dynamic linker or we're in the middle of forking, so ask the kernel. // We don't know whether it's safe to update the cached value, so don't try. return __getpid(); }
int __pthread_mutex_transfer_np (pthread_mutex_t *mtxp, pthread_t th) { struct __pthread *self = _pthread_self (); struct __pthread *pt = __pthread_getid (th); if (pt == NULL) return ESRCH; else if (pt == self) return 0; int ret = 0; int flags = mtxp->__flags & GSYNC_SHARED; switch (MTX_TYPE (mtxp)) { case PT_MTX_NORMAL: break; case PT_MTX_RECURSIVE: case PT_MTX_ERRORCHECK: if (!mtx_owned_p (mtxp, self, flags)) ret = EPERM; else mtx_set_owner (mtxp, pt, flags); break; case PT_MTX_NORMAL | PTHREAD_MUTEX_ROBUST: case PT_MTX_RECURSIVE | PTHREAD_MUTEX_ROBUST: case PT_MTX_ERRORCHECK | PTHREAD_MUTEX_ROBUST: /* Note that this can be used to transfer an inconsistent * mutex as well. The new owner will still have the same * flags as the original. */ if (mtxp->__owner_id != self->thread || (int) (mtxp->__lock & LLL_OWNER_MASK) != __getpid ()) ret = EPERM; else mtxp->__owner_id = pt->thread; break; default: ret = EINVAL; } return ret; }
int lockf (int fd, int cmd, off_t len) { struct flock fl; memset ((char *) &fl, '\0', sizeof (fl)); /* lockf is always relative to the current file position. */ fl.l_whence = SEEK_CUR; fl.l_start = 0; fl.l_len = len; switch (cmd) { case F_TEST: /* Test the lock: return 0 if FD is unlocked or locked by this process; return -1, set errno to EACCES, if another process holds the lock. */ fl.l_type = F_RDLCK; if (__fcntl (fd, F_GETLK, &fl) < 0) return -1; if (fl.l_type == F_UNLCK || fl.l_pid == __getpid ()) return 0; __set_errno (EACCES); return -1; case F_ULOCK: fl.l_type = F_UNLCK; cmd = F_SETLK; break; case F_LOCK: fl.l_type = F_WRLCK; cmd = F_SETLKW; break; case F_TLOCK: fl.l_type = F_WRLCK; cmd = F_SETLK; break; default: __set_errno (EINVAL); return -1; } /* lockf() is a cancellation point but so is fcntl() if F_SETLKW is used. Therefore we don't have to care about cancellation here, the fcntl() function will take care of it. */ return __fcntl (fd, cmd, &fl); }
static int __msgwrite (int sock, void *data, size_t cnt) { #ifndef SCM_CREDENTIALS /* We cannot implement this reliably. */ __set_errno (ENOSYS); return -1; #else struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg = &cm.cmsg; struct ucred cred; int len; /* XXX I'm not sure, if gete?id() is always correct, or if we should use get?id(). But since keyserv needs geteuid(), we have no other chance. It would be much better, if the kernel could pass both to the server. */ cred.pid = __getpid (); cred.uid = __geteuid (); cred.gid = __getegid (); memcpy (CMSG_DATA(cmsg), &cred, sizeof (struct ucred)); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_CREDENTIALS; cmsg->cmsg_len = sizeof(*cmsg) + sizeof(struct ucred); iov.iov_base = data; iov.iov_len = cnt; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_control = cmsg; msg.msg_controllen = CMSG_ALIGN(cmsg->cmsg_len); msg.msg_flags = 0; restart: len = sendmsg (sock, &msg, 0); if (len >= 0) return len; if (errno == EINTR) goto restart; return -1; #endif }
/* Return any pending signal or wait for one for the given time. */ int __sigqueue (pid_t pid, int sig, const union sigval val) { siginfo_t info; /* First, clear the siginfo_t structure, so that we don't pass our stack content to other tasks. */ memset (&info, 0, sizeof (siginfo_t)); /* We must pass the information about the data in a siginfo_t value. */ info.si_signo = sig; info.si_code = SI_QUEUE; info.si_pid = __getpid (); info.si_uid = __getuid (); info.si_value = val; return INLINE_SYSCALL (rt_sigqueueinfo, 3, pid, sig, &info); }
pthread_start_thread(void *arg) { pthread_descr self = (pthread_descr) arg; struct pthread_request request; void * outcome; /* Initialize special thread_self processing, if any. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr); #endif PDEBUG("\n"); /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ THREAD_SETMEM(self, p_pid, __getpid()); /* Initial signal mask is that of the creating thread. (Otherwise, we'd just inherit the mask of the thread manager.) */ sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); /* Set the scheduling policy and priority for the new thread, if needed */ if (THREAD_GETMEM(self, p_start_args.schedpolicy) >= 0) /* Explicit scheduling attributes were provided: apply them */ sched_setscheduler(THREAD_GETMEM(self, p_pid), THREAD_GETMEM(self, p_start_args.schedpolicy), &self->p_start_args.schedparam); else if (__pthread_manager_thread.p_priority > 0) /* Default scheduling required, but thread manager runs in realtime scheduling: switch new thread to SCHED_OTHER policy */ { struct sched_param default_params; default_params.sched_priority = 0; sched_setscheduler(THREAD_GETMEM(self, p_pid), SCHED_OTHER, &default_params); } /* Make gdb aware of new thread */ if (__pthread_threads_debug && __pthread_sig_debug > 0) { request.req_thread = self; request.req_kind = REQ_DEBUG; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *) &request, sizeof(request))); suspend(self); } /* Run the thread code */ outcome = self->p_start_args.start_routine(THREAD_GETMEM(self, p_start_args.arg)); /* Exit with the given return value */ pthread_exit(outcome); }
pthread_start_thread_event(void *arg) { pthread_descr self = (pthread_descr) arg; #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, self->p_nr); #endif /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ THREAD_SETMEM(self, p_pid, __getpid()); /* Get the lock the manager will free once all is correctly set up. */ __pthread_lock (THREAD_GETMEM(self, p_lock), NULL); /* Free it immediately. */ __pthread_unlock (THREAD_GETMEM(self, p_lock)); /* Continue with the real function. */ pthread_start_thread (arg); }
int lockf64 (int fd, int cmd, off64_t len64) { struct flock64 fl64; int cmd64; int result; memset ((char *) &fl64, '\0', sizeof (fl64)); fl64.l_whence = SEEK_CUR; fl64.l_start = 0; fl64.l_len = len64; switch (cmd) { case F_TEST: /* Test the lock: return 0 if FD is unlocked or locked by this process; return -1, set errno to EACCES, if another process holds the lock. */ fl64.l_type = F_RDLCK; INTERNAL_SYSCALL_DECL (err); result = INTERNAL_SYSCALL (fcntl64, err, 3, fd, F_GETLK64, &fl64); if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err))) return INLINE_SYSCALL_ERROR_RETURN_VALUE (INTERNAL_SYSCALL_ERRNO (result, err)); if (fl64.l_type == F_UNLCK || fl64.l_pid == __getpid ()) return 0; return INLINE_SYSCALL_ERROR_RETURN_VALUE (EACCES); case F_ULOCK: fl64.l_type = F_UNLCK; cmd64 = F_SETLK64; break; case F_LOCK: fl64.l_type = F_WRLCK; cmd64 = F_SETLKW64; break; case F_TLOCK: fl64.l_type = F_WRLCK; cmd64 = F_SETLK64; break; default: return INLINE_SYSCALL_ERROR_RETURN_VALUE (EINVAL); } return INLINE_SYSCALL (fcntl64, 3, fd, cmd64, &fl64); }
/* For asynchronous cancellation we use a signal. This is the handler. */ static void sigcancel_handler (int sig, siginfo_t *si, void *ctx) { /* Safety check. It would be possible to call this function for other signals and send a signal from another process. This is not correct and might even be a security problem. Try to catch as many incorrect invocations as possible. */ if (sig != SIGCANCEL || si->si_pid != __getpid() || si->si_code != SI_TKILL) return; struct pthread *self = THREAD_SELF; int oldval = THREAD_GETMEM (self, cancelhandling); while (1) { /* We are canceled now. When canceled by another thread this flag is already set but if the signal is directly send (internally or from another process) is has to be done here. */ int newval = oldval | CANCELING_BITMASK | CANCELED_BITMASK; if (oldval == newval || (oldval & EXITING_BITMASK) != 0) /* Already canceled or exiting. */ break; int curval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, newval, oldval); if (curval == oldval) { /* Set the return value. */ THREAD_SETMEM (self, result, PTHREAD_CANCELED); /* Make sure asynchronous cancellation is still enabled. */ if ((newval & CANCELTYPE_BITMASK) != 0) /* Run the registered destructors and terminate the thread. */ __do_cancel (); break; } oldval = curval; } }
int lockf64 (int fd, int cmd, off64_t len64) { struct flock64 fl64; int cmd64; memset ((char *) &fl64, '\0', sizeof (fl64)); fl64.l_whence = SEEK_CUR; fl64.l_start = 0; fl64.l_len = len64; switch (cmd) { case F_TEST: /* Test the lock: return 0 if FD is unlocked or locked by this process; return -1, set errno to EACCES, if another process holds the lock. */ fl64.l_type = F_RDLCK; if (INLINE_SYSCALL (fcntl64, 3, fd, F_GETLK64, &fl64) < 0) return -1; if (fl64.l_type == F_UNLCK || fl64.l_pid == __getpid ()) return 0; __set_errno (EACCES); return -1; case F_ULOCK: fl64.l_type = F_UNLCK; cmd64 = F_SETLK64; break; case F_LOCK: fl64.l_type = F_WRLCK; cmd64 = F_SETLKW64; break; case F_TLOCK: fl64.l_type = F_WRLCK; cmd64 = F_SETLK64; break; default: __set_errno (EINVAL); return -1; } return INLINE_SYSCALL (fcntl64, 3, fd, cmd64, &fl64); }
/* We use the SIGSETXID signal in the setuid, setgid, etc. implementations to tell each thread to call the respective setxid syscall on itself. This is the handler. */ static void sighandler_setxid (int sig, siginfo_t *si, void *ctx) { int result; /* Safety check. It would be possible to call this function for other signals and send a signal from another process. This is not correct and might even be a security problem. Try to catch as many incorrect invocations as possible. */ if (sig != SIGSETXID || si->si_pid != __getpid () || si->si_code != SI_TKILL) return; INTERNAL_SYSCALL_DECL (err); result = INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0], __xidcmd->id[1], __xidcmd->id[2]); int error = 0; if (__glibc_unlikely (INTERNAL_SYSCALL_ERROR_P (result, err))) error = INTERNAL_SYSCALL_ERRNO (result, err); __nptl_setxid_error (__xidcmd, error); /* Reset the SETXID flag. */ struct pthread *self = THREAD_SELF; int flags, newval; do { flags = THREAD_GETMEM (self, cancelhandling); newval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, flags & ~SETXID_BITMASK, flags); } while (flags != newval); /* And release the futex. */ self->setxid_futex = 1; futex_wake (&self->setxid_futex, 1, FUTEX_PRIVATE); if (atomic_decrement_val (&__xidcmd->cntr) == 0) futex_wake ((unsigned int *) &__xidcmd->cntr, 1, FUTEX_PRIVATE); }
static int pthread_start_thread(void * arg) { pthread_descr self = (pthread_descr) arg; void * outcome; /* Initialize special thread_self processing, if any. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self); #endif /* Make sure our pid field is initialized, just in case we get there before our father has initialized it. */ self->p_pid = __getpid(); /* Initial signal mask is that of the creating thread. (Otherwise, we'd just inherit the mask of the thread manager.) */ sigprocmask(SIG_SETMASK, &self->p_start_args.mask, NULL); /* Set the scheduling policy and priority for the new thread, if needed */ if (self->p_start_args.schedpolicy != SCHED_OTHER) __sched_setscheduler(self->p_pid, self->p_start_args.schedpolicy, &self->p_start_args.schedparam); /* Run the thread code */ outcome = self->p_start_args.start_routine(self->p_start_args.arg); /* Exit with the given return value */ pthread_exit(outcome); return 0; }
void __pthread_reset_main_thread() { pthread_descr self = thread_self(); if (__pthread_manager_request != -1) { /* Free the thread manager stack */ free(__pthread_manager_thread_bos); __pthread_manager_thread_bos = __pthread_manager_thread_tos = NULL; /* Close the two ends of the pipe */ __libc_close(__pthread_manager_request); __libc_close(__pthread_manager_reader); __pthread_manager_request = __pthread_manager_reader = -1; } /* Update the pid of the main thread */ THREAD_SETMEM(self, p_pid, __getpid()); /* Make the forked thread the main thread */ __pthread_main_thread = self; THREAD_SETMEM(self, p_nextlive, self); THREAD_SETMEM(self, p_prevlive, self); /* Now this thread modifies the global variables. */ THREAD_SETMEM(self, p_errnop, &_errno); THREAD_SETMEM(self, p_h_errnop, &_h_errno); }
void __vsyslog_chk(int pri, int flag, const char *fmt, va_list ap) { struct tm now_tm; time_t now; int fd; FILE *f; char *buf = 0; size_t bufsize = 0; size_t msgoff; #ifndef NO_SIGPIPE struct sigaction action, oldaction; int sigpipe; #endif int saved_errno = errno; char failbuf[3 * sizeof (pid_t) + sizeof "out of memory []"]; #define INTERNALLOG LOG_ERR|LOG_CONS|LOG_PERROR|LOG_PID /* Check for invalid bits. */ if (pri & ~(LOG_PRIMASK|LOG_FACMASK)) { syslog(INTERNALLOG, "syslog: unknown facility/priority: %x", pri); pri &= LOG_PRIMASK|LOG_FACMASK; } /* Check priority against setlogmask values. */ if ((LOG_MASK (LOG_PRI (pri)) & LogMask) == 0) return; /* Set default facility if none specified. */ if ((pri & LOG_FACMASK) == 0) pri |= LogFacility; /* Build the message in a memory-buffer stream. */ f = __open_memstream (&buf, &bufsize); if (f == NULL) { /* We cannot get a stream. There is not much we can do but emitting an error messages. */ char numbuf[3 * sizeof (pid_t)]; char *nump; char *endp = __stpcpy (failbuf, "out of memory ["); pid_t pid = __getpid (); nump = numbuf + sizeof (numbuf); /* The PID can never be zero. */ do *--nump = '0' + pid % 10; while ((pid /= 10) != 0); endp = __mempcpy (endp, nump, (numbuf + sizeof (numbuf)) - nump); *endp++ = ']'; *endp = '\0'; buf = failbuf; bufsize = endp - failbuf; msgoff = 0; } else { __fsetlocking (f, FSETLOCKING_BYCALLER); fprintf (f, "<%d>", pri); (void) time (&now); f->_IO_write_ptr += __strftime_l (f->_IO_write_ptr, f->_IO_write_end - f->_IO_write_ptr, "%h %e %T ", __localtime_r (&now, &now_tm), _nl_C_locobj_ptr); msgoff = ftell (f); if (LogTag == NULL) LogTag = __progname; if (LogTag != NULL) __fputs_unlocked (LogTag, f); if (LogStat & LOG_PID) fprintf (f, "[%d]", (int) __getpid ()); if (LogTag != NULL) { putc_unlocked (':', f); putc_unlocked (' ', f); } /* Restore errno for %m format. */ __set_errno (saved_errno); /* We have the header. Print the user's format into the buffer. */ if (flag == -1) vfprintf (f, fmt, ap); else __vfprintf_chk (f, flag, fmt, ap); /* Close the memory stream; this will finalize the data into a malloc'd buffer in BUF. */ fclose (f); } /* Output to stderr if requested. */ if (LogStat & LOG_PERROR) { struct iovec iov[2]; struct iovec *v = iov; v->iov_base = buf + msgoff; v->iov_len = bufsize - msgoff; /* Append a newline if necessary. */ if (buf[bufsize - 1] != '\n') { ++v; v->iov_base = (char *) "\n"; v->iov_len = 1; } __libc_cleanup_push (free, buf == failbuf ? NULL : buf); /* writev is a cancellation point. */ (void)__writev(STDERR_FILENO, iov, v - iov + 1); __libc_cleanup_pop (0); } /* Prepare for multiple users. We have to take care: open and write are cancellation points. */ struct cleanup_arg clarg; clarg.buf = buf; clarg.oldaction = NULL; __libc_cleanup_push (cancel_handler, &clarg); __libc_lock_lock (syslog_lock); #ifndef NO_SIGPIPE /* Prepare for a broken connection. */ memset (&action, 0, sizeof (action)); action.sa_handler = sigpipe_handler; sigemptyset (&action.sa_mask); sigpipe = __sigaction (SIGPIPE, &action, &oldaction); if (sigpipe == 0) clarg.oldaction = &oldaction; #endif /* Get connected, output the message to the local logger. */ if (!connected) openlog_internal(LogTag, LogStat | LOG_NDELAY, 0); /* If we have a SOCK_STREAM connection, also send ASCII NUL as a record terminator. */ if (LogType == SOCK_STREAM) ++bufsize; if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0) { if (connected) { /* Try to reopen the syslog connection. Maybe it went down. */ closelog_internal (); openlog_internal(LogTag, LogStat | LOG_NDELAY, 0); } if (!connected || __send(LogFile, buf, bufsize, send_flags) < 0) { closelog_internal (); /* attempt re-open next time */ /* * Output the message to the console; don't worry * about blocking, if console blocks everything will. * Make sure the error reported is the one from the * syslogd failure. */ if (LogStat & LOG_CONS && (fd = __open(_PATH_CONSOLE, O_WRONLY|O_NOCTTY, 0)) >= 0) { __dprintf (fd, "%s\r\n", buf + msgoff); (void)__close(fd); } } } #ifndef NO_SIGPIPE if (sigpipe == 0) __sigaction (SIGPIPE, &oldaction, (struct sigaction *) NULL); #endif /* End of critical section. */ __libc_cleanup_pop (0); __libc_lock_unlock (syslog_lock); if (buf != failbuf) free (buf); }
/* Generate a temporary file name based on TMPL. TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX"). 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_BIGFILE: same as __GT_FILE but use open64(). __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 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 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. */ unsigned int 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. */ unsigned int attempts = attempts_min < TMP_MAX ? TMP_MAX : attempts_min; len = strlen (tmpl); if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) { __set_errno (EINVAL); return -1; } /* This is where the Xs start. */ XXXXXX = &tmpl[len - 6]; /* Get some more or less random data. */ #ifdef RANDOM_BITS RANDOM_BITS (random_time_bits); #else # if HAVE_GETTIMEOFDAY || _LIBC { struct timeval tv; __gettimeofday (&tv, NULL); random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; } # else random_time_bits = time (NULL); # endif #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, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); break; case __GT_BIGFILE: fd = __open64 (tmpl, 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"); } 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; }
/* Generate a temporary file name based on TMPL. TMPL must match the rules for mk[s]temp (i.e. end in "XXXXXX"). 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_BIGFILE: same as __GT_FILE but use open64(). __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 kind) { int len; char *XXXXXX; static uint64_t value; uint64_t random_time_bits; int count, fd = -1; int save_errno = errno; struct_stat64 st; len = strlen (tmpl); if (len < 6 || strcmp (&tmpl[len - 6], "XXXXXX")) { __set_errno (EINVAL); return -1; } /* This is where the Xs start. */ XXXXXX = &tmpl[len - 6]; /* Get some more or less random data. */ #ifdef RANDOM_BITS RANDOM_BITS (random_time_bits); #else # if HAVE_GETTIMEOFDAY || _LIBC { struct timeval tv; __gettimeofday (&tv, NULL); random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; } # else random_time_bits = time (NULL); # endif #endif value += random_time_bits ^ __getpid (); for (count = 0; count < TMP_MAX; 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, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); break; case __GT_BIGFILE: fd = __open64 (tmpl, 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"); } 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; }
int __try_tempname (char *tmpl, int suffixlen, void *args, int (*tryfunc) (char *, void *)) { int len; char *XXXXXX; static uint64_t value; uint64_t random_time_bits; unsigned int count; int fd = -1; int save_errno = errno; /* 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]; fd = tryfunc (tmpl, args); 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; }
/* Bare-bones printf implementation. This function only knows about the formats and flags needed and can handle only up to 64 stripes in the output. */ static void _dl_debug_vdprintf (int fd, int tag_p, const char *fmt, va_list arg) { # define NIOVMAX 64 struct iovec iov[NIOVMAX]; int niov = 0; pid_t pid = 0; char pidbuf[12]; while (*fmt != '\0') { const char *startp = fmt; if (tag_p > 0) { /* Generate the tag line once. It consists of the PID and a colon followed by a tab. */ if (pid == 0) { char *p; pid = __getpid (); assert (pid >= 0 && sizeof (pid_t) <= 4); p = _itoa (pid, &pidbuf[10], 10, 0); while (p > pidbuf) *--p = ' '; pidbuf[10] = ':'; pidbuf[11] = '\t'; } /* Append to the output. */ assert (niov < NIOVMAX); iov[niov].iov_len = 12; iov[niov++].iov_base = pidbuf; /* No more tags until we see the next newline. */ tag_p = -1; } /* Skip everything except % and \n (if tags are needed). */ while (*fmt != '\0' && *fmt != '%' && (! tag_p || *fmt != '\n')) ++fmt; /* Append constant string. */ assert (niov < NIOVMAX); if ((iov[niov].iov_len = fmt - startp) != 0) iov[niov++].iov_base = (char *) startp; if (*fmt == '%') { /* It is a format specifier. */ char fill = ' '; int width = -1; int prec = -1; #if LONG_MAX != INT_MAX int long_mod = 0; #endif /* Recognize zero-digit fill flag. */ if (*++fmt == '0') { fill = '0'; ++fmt; } /* See whether with comes from a parameter. Note that no other way to specify the width is implemented. */ if (*fmt == '*') { width = va_arg (arg, int); ++fmt; } /* Handle precision. */ if (*fmt == '.' && fmt[1] == '*') { prec = va_arg (arg, int); fmt += 2; }
/* Raise the signal SIG. */ int raise (int sig) { return __kill (__getpid (), sig); }
int lockf64 (int fd, int cmd, off64_t len64) { #if __ASSUME_FCNTL64 == 0 struct flock fl; off_t len = (off_t) len64; #endif #ifdef __NR_fcntl64 struct flock64 fl64; int cmd64; #endif #if __ASSUME_FCNTL64 == 0 memset ((char *) &fl, '\0', sizeof (fl)); /* lockf is always relative to the current file position. */ fl.l_whence = SEEK_CUR; fl.l_start = 0; fl.l_len = len; #endif #ifdef __NR_fcntl64 # if __ASSUME_FCNTL64 == 0 if (!__have_no_fcntl64) { # endif memset ((char *) &fl64, '\0', sizeof (fl64)); fl64.l_whence = SEEK_CUR; fl64.l_start = 0; fl64.l_len = len64; # if __ASSUME_FCNTL64 == 0 } # endif #endif #if __ASSUME_FCNTL64 == 0 && !defined __NR_fcntl64 if (len64 != (off64_t) len) { /* We can't represent the length. */ __set_errno (EOVERFLOW); return -1; } #endif switch (cmd) { case F_TEST: /* Test the lock: return 0 if FD is unlocked or locked by this process; return -1, set errno to EACCES, if another process holds the lock. */ #if __ASSUME_FCNTL64 > 0 fl64.l_type = F_RDLCK; if (INLINE_SYSCALL (fcntl64, 3, fd, F_GETLK64, &fl64) < 0) return -1; if (fl64.l_type == F_UNLCK || fl64.l_pid == __getpid ()) return 0; __set_errno (EACCES); return -1; #else # ifdef __NR_fcntl64 if (!__have_no_fcntl64) { int res; fl64.l_type = F_RDLCK; res = INLINE_SYSCALL (fcntl64, 3, fd, F_GETLK64, &fl64); /* If errno == ENOSYS try the 32bit interface if len64 can be represented with 32 bits. */ if (res == 0) { if (fl64.l_type == F_UNLCK || fl64.l_pid == __getpid ()) return 0; __set_errno (EACCES); return -1; } else if (errno == ENOSYS) __have_no_fcntl64 = 1; else /* res < 0 && errno != ENOSYS. */ return -1; if (len64 != (off64_t) len) { /* We can't represent the length. */ __set_errno (EOVERFLOW); return -1; } } # endif fl.l_type = F_RDLCK; if (__fcntl (fd, F_GETLK, &fl) < 0) return -1; if (fl.l_type == F_UNLCK || fl.l_pid == __getpid ()) return 0; __set_errno (EACCES); return -1; #endif case F_ULOCK: #if __ASSUME_FCNTL64 == 0 fl.l_type = F_UNLCK; cmd = F_SETLK; #endif #ifdef __NR_fcntl64 fl64.l_type = F_UNLCK; cmd64 = F_SETLK64; #endif break; case F_LOCK: #if __ASSUME_FCNTL64 == 0 fl.l_type = F_WRLCK; cmd = F_SETLKW; #endif #ifdef __NR_fcntl64 fl64.l_type = F_WRLCK; cmd64 = F_SETLKW64; #endif break; case F_TLOCK: #if __ASSUME_FCNTL64 == 0 fl.l_type = F_WRLCK; cmd = F_SETLK; #endif #ifdef __NR_fcntl64 fl64.l_type = F_WRLCK; cmd64 = F_SETLK64; #endif break; default: __set_errno (EINVAL); return -1; } #if __ASSUME_FCNTL64 > 0 return INLINE_SYSCALL (fcntl64, 3, fd, cmd64, &fl64); #else # ifdef __NR_fcntl64 if (!__have_no_fcntl64) { int res = INLINE_SYSCALL (fcntl64, 3, fd, cmd64, &fl64); /* If errno == ENOSYS try the 32bit interface if len64 can be represented with 32 bits. */ if (res == 0 || errno != ENOSYS) return res; __have_no_fcntl64 = 1; if (len64 != (off64_t) len) { /* We can't represent the length. */ __set_errno (EOVERFLOW); return -1; } } # endif return __fcntl (fd, cmd, &fl); #endif }