static char * next_line (int fd, char *const buffer, char **cp, char **re, char *const buffer_end) { char *res = *cp; char *nl = memchr (*cp, '\n', *re - *cp); if (nl == NULL) { if (*cp != buffer) { if (*re == buffer_end) { memmove (buffer, *cp, *re - *cp); *re = buffer + (*re - *cp); *cp = buffer; ssize_t n = read_not_cancel (fd, *re, buffer_end - *re); if (n < 0) return NULL; *re += n; nl = memchr (*cp, '\n', *re - *cp); while (nl == NULL && *re == buffer_end) { /* Truncate too long lines. */ *re = buffer + 3 * (buffer_end - buffer) / 4; n = read_not_cancel (fd, *re, buffer_end - *re); if (n < 0) return NULL; nl = memchr (*re, '\n', n); **re = '\n'; *re += n; } } else nl = memchr (*cp, '\n', *re - *cp); res = *cp; } if (nl == NULL) nl = *re - 1; } *cp = nl + 1; assert (*cp <= *re); return res == *re ? NULL : res; }
_IO_ssize_t _IO_file_read (_IO_FILE *fp, void *buf, _IO_ssize_t size) { return (__builtin_expect (fp->_flags2 & _IO_FLAGS2_NOTCANCEL, 0) ? read_not_cancel (fp->_fileno, buf, size) : read (fp->_fileno, buf, size)); }
static void backtrace_and_maps (int do_abort, bool written, int fd) { if (do_abort > 1 && written) { void *addrs[64]; #define naddrs (sizeof (addrs) / sizeof (addrs[0])) int n = __backtrace (addrs, naddrs); if (n > 2) { #define strnsize(str) str, strlen (str) #define writestr(str) write_not_cancel (fd, str) writestr (strnsize ("======= Backtrace: =========\n")); __backtrace_symbols_fd (addrs + 1, n - 1, fd); writestr (strnsize ("======= Memory map: ========\n")); int fd2 = open_not_cancel_2 ("/proc/self/maps", O_RDONLY); char buf[1024]; ssize_t n2; while ((n2 = read_not_cancel (fd2, buf, sizeof (buf))) > 0) if (write_not_cancel (fd, buf, n2) != n2) break; close_not_cancel_no_status (fd2); } } }
/* This function must be called with the LOCK held */ static struct UT *__get_unlocked(void) { if (static_fd < 0) { __set_unlocked(); if (static_fd < 0) return NULL; } if (read_not_cancel(static_fd, &static_utmp, sizeof(static_utmp)) == sizeof(static_utmp)) { return &static_utmp; } return NULL; }
int pthread_getname_np (pthread_t th, char *buf, size_t len) { const struct pthread *pd = (const struct pthread *) th; /* Unfortunately the kernel headers do not export the TASK_COMM_LEN macro. So we have to define it here. */ #define TASK_COMM_LEN 16 if (len < TASK_COMM_LEN) return ERANGE; if (pd == THREAD_SELF) return prctl (PR_GET_NAME, buf) ? errno : 0; #define FMT "/proc/self/task/%u/comm" char fname[sizeof (FMT) + 8]; sprintf (fname, FMT, (unsigned int) pd->tid); int fd = open_not_cancel_2 (fname, O_RDONLY); if (fd == -1) return errno; int res = 0; ssize_t n = TEMP_FAILURE_RETRY (read_not_cancel (fd, buf, len)); if (n < 0) res = errno; else { if (buf[n - 1] == '\n') buf[n - 1] = '\0'; else if (n == len) res = ERANGE; else buf[n] = '\0'; } close_not_cancel_no_status (fd); return res; }
/* Used like: return __statfs_chown_restricted (__statfs (name, &buf), &buf);*/ long int __statfs_chown_restricted (int result, const struct statfs *fsbuf) { if (result < 0) { if (errno == ENOSYS) /* Not possible, return the default value. */ return 1; /* Some error occured. */ return -1; } int fd; long int retval = 1; switch (fsbuf->f_type) { case XFS_SUPER_MAGIC: /* Read the value from /proc/sys/fs/xfs/restrict_chown. If we cannot read it default to assume the restriction is in place. */ fd = open_not_cancel_2 ("/proc/sys/fs/xfs/restrict_chown", O_RDONLY); if (fd != -1) { char buf[2]; if (TEMP_FAILURE_RETRY (read_not_cancel (fd, buf, 2)) == 2 && buf[0] >= '0' && buf[0] <= '1') retval = buf[0] - '0'; close_not_cancel_no_status (fd); } break; default: break; } return retval; }
int getloadavg (double loadavg[], int nelem) { int fd; fd = open_not_cancel_2 ("/proc/loadavg", O_RDONLY); if (fd < 0) return -1; else { char buf[65], *p; ssize_t nread; int i; nread = read_not_cancel (fd, buf, sizeof buf - 1); close_not_cancel_no_status (fd); if (nread <= 0) return -1; buf[nread - 1] = '\0'; if (nelem > 3) nelem = 3; p = buf; for (i = 0; i < nelem; ++i) { char *endp; loadavg[i] = __strtod_l (p, &endp, _nl_C_locobj_ptr); if (endp == p) /* This should not happen. The format of /proc/loadavg must have changed. Don't return with what we have, signal an error. */ return -1; p = endp; } return i; } }
int __open_catalog (const char *cat_name, const char *nlspath, const char *env_var, __nl_catd catalog) { int fd = -1; struct stat64 st; int swapping; size_t cnt; size_t max_offset; size_t tab_size; const char *lastp; int result = -1; char *buf = NULL; if (strchr (cat_name, '/') != NULL || nlspath == NULL) fd = open_not_cancel_2 (cat_name, O_RDONLY); else { const char *run_nlspath = nlspath; #define ENOUGH(n) \ if (__glibc_unlikely (bufact + (n) >= bufmax)) \ { \ char *old_buf = buf; \ bufmax += (bufmax < 256 + (n)) ? 256 + (n) : bufmax; \ buf = realloc (buf, bufmax); \ if (__glibc_unlikely (buf == NULL)) \ { \ free (old_buf); \ return -1; \ } \ } /* The RUN_NLSPATH variable contains a colon separated list of descriptions where we expect to find catalogs. We have to recognize certain % substitutions and stop when we found the first existing file. */ size_t bufact; size_t bufmax = 0; size_t len; fd = -1; while (*run_nlspath != '\0') { bufact = 0; if (*run_nlspath == ':') { /* Leading colon or adjacent colons - treat same as %N. */ len = strlen (cat_name); ENOUGH (len); memcpy (&buf[bufact], cat_name, len); bufact += len; } else while (*run_nlspath != ':' && *run_nlspath != '\0') if (*run_nlspath == '%') { const char *tmp; ++run_nlspath; /* We have seen the `%'. */ switch (*run_nlspath++) { case 'N': /* Use the catalog name. */ len = strlen (cat_name); ENOUGH (len); memcpy (&buf[bufact], cat_name, len); bufact += len; break; case 'L': /* Use the current locale category value. */ len = strlen (env_var); ENOUGH (len); memcpy (&buf[bufact], env_var, len); bufact += len; break; case 'l': /* Use language element of locale category value. */ tmp = env_var; do { ENOUGH (1); buf[bufact++] = *tmp++; } while (*tmp != '\0' && *tmp != '_' && *tmp != '.'); break; case 't': /* Use territory element of locale category value. */ tmp = env_var; do ++tmp; while (*tmp != '\0' && *tmp != '_' && *tmp != '.'); if (*tmp == '_') { ++tmp; do { ENOUGH (1); buf[bufact++] = *tmp++; } while (*tmp != '\0' && *tmp != '.'); } break; case 'c': /* Use code set element of locale category value. */ tmp = env_var; do ++tmp; while (*tmp != '\0' && *tmp != '.'); if (*tmp == '.') { ++tmp; do { ENOUGH (1); buf[bufact++] = *tmp++; } while (*tmp != '\0'); } break; case '%': ENOUGH (1); buf[bufact++] = '%'; break; default: /* Unknown variable: ignore this path element. */ bufact = 0; while (*run_nlspath != '\0' && *run_nlspath != ':') ++run_nlspath; break; } } else { ENOUGH (1); buf[bufact++] = *run_nlspath++; } ENOUGH (1); buf[bufact] = '\0'; if (bufact != 0) { fd = open_not_cancel_2 (buf, O_RDONLY); if (fd >= 0) break; } ++run_nlspath; } } /* Avoid dealing with directories and block devices */ if (__builtin_expect (fd, 0) < 0) { free (buf); return -1; } if (__builtin_expect (__fxstat64 (_STAT_VER, fd, &st), 0) < 0) goto close_unlock_return; if (__builtin_expect (!S_ISREG (st.st_mode), 0) || (size_t) st.st_size < sizeof (struct catalog_obj)) { /* `errno' is not set correctly but the file is not usable. Use an reasonable error value. */ __set_errno (EINVAL); goto close_unlock_return; } catalog->file_size = st.st_size; #ifdef _POSIX_MAPPED_FILES # ifndef MAP_COPY /* Linux seems to lack read-only copy-on-write. */ # define MAP_COPY MAP_PRIVATE # endif # ifndef MAP_FILE /* Some systems do not have this flag; it is superfluous. */ # define MAP_FILE 0 # endif catalog->file_ptr = (struct catalog_obj *) __mmap (NULL, st.st_size, PROT_READ, MAP_FILE|MAP_COPY, fd, 0); if (__builtin_expect (catalog->file_ptr != (struct catalog_obj *) MAP_FAILED, 1)) /* Tell the world we managed to mmap the file. */ catalog->status = mmapped; else #endif /* _POSIX_MAPPED_FILES */ { /* mmap failed perhaps because the system call is not implemented. Try to load the file. */ size_t todo; catalog->file_ptr = malloc (st.st_size); if (catalog->file_ptr == NULL) goto close_unlock_return; todo = st.st_size; /* Save read, handle partial reads. */ do { size_t now = read_not_cancel (fd, (((char *) catalog->file_ptr) + (st.st_size - todo)), todo); if (now == 0 || now == (size_t) -1) { #ifdef EINTR if (now == (size_t) -1 && errno == EINTR) continue; #endif free ((void *) catalog->file_ptr); goto close_unlock_return; } todo -= now; } while (todo > 0); catalog->status = malloced; } /* Determine whether the file is a catalog file and if yes whether it is written using the correct byte order. Else we have to swap the values. */ if (__glibc_likely (catalog->file_ptr->magic == CATGETS_MAGIC)) swapping = 0; else if (catalog->file_ptr->magic == SWAPU32 (CATGETS_MAGIC)) swapping = 1; else { invalid_file: /* Invalid file. Free the resources and mark catalog as not usable. */ #ifdef _POSIX_MAPPED_FILES if (catalog->status == mmapped) __munmap ((void *) catalog->file_ptr, catalog->file_size); else #endif /* _POSIX_MAPPED_FILES */ free (catalog->file_ptr); goto close_unlock_return; } #define SWAP(x) (swapping ? SWAPU32 (x) : (x)) /* Get dimensions of the used hashing table. */ catalog->plane_size = SWAP (catalog->file_ptr->plane_size); catalog->plane_depth = SWAP (catalog->file_ptr->plane_depth); /* The file contains two versions of the pointer tables. Pick the right one for the local byte order. */ #if __BYTE_ORDER == __LITTLE_ENDIAN catalog->name_ptr = &catalog->file_ptr->name_ptr[0]; #elif __BYTE_ORDER == __BIG_ENDIAN catalog->name_ptr = &catalog->file_ptr->name_ptr[catalog->plane_size * catalog->plane_depth * 3]; #else # error Cannot handle __BYTE_ORDER byte order #endif /* The rest of the file contains all the strings. They are addressed relative to the position of the first string. */ catalog->strings = (const char *) &catalog->file_ptr->name_ptr[catalog->plane_size * catalog->plane_depth * 3 * 2]; /* Determine the largest string offset mentioned in the table. */ max_offset = 0; tab_size = 3 * catalog->plane_size * catalog->plane_depth; for (cnt = 2; cnt < tab_size; cnt += 3) if (catalog->name_ptr[cnt] > max_offset) max_offset = catalog->name_ptr[cnt]; /* Now we can check whether the file is large enough to contain the tables it says it contains. */ if ((size_t) st.st_size <= (sizeof (struct catalog_obj) + 2 * tab_size + max_offset)) /* The last string is not contained in the file. */ goto invalid_file; lastp = catalog->strings + max_offset; max_offset = (st.st_size - sizeof (struct catalog_obj) + 2 * tab_size + max_offset); while (*lastp != '\0') { if (--max_offset == 0) goto invalid_file; ++lastp; } /* We succeeded. */ result = 0; /* Release the lock again. */ close_unlock_return: close_not_cancel_no_status (fd); free (buf); return result; }
__pthread_manager(void *arg) { pthread_descr self = manager_thread = arg; int reqfd = __pthread_manager_reader; struct pollfd ufd; sigset_t manager_mask; int n; struct pthread_request request; /* If we have special thread_self processing, initialize it. */ #ifdef INIT_THREAD_SELF INIT_THREAD_SELF(self, 1); #endif #if !(USE_TLS && HAVE___THREAD) /* Set the error variable. */ self->p_errnop = &self->p_errno; self->p_h_errnop = &self->p_h_errno; #endif /* Block all signals except __pthread_sig_cancel and SIGTRAP */ sigfillset(&manager_mask); sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */ sigdelset(&manager_mask, SIGTRAP); /* for debugging purposes */ if (__pthread_threads_debug && __pthread_sig_debug > 0) sigdelset(&manager_mask, __pthread_sig_debug); sigprocmask(SIG_SETMASK, &manager_mask, NULL); /* Raise our priority to match that of main thread */ __pthread_manager_adjust_prio(__pthread_main_thread->p_priority); /* Synchronize debugging of the thread manager */ n = TEMP_FAILURE_RETRY(read_not_cancel(reqfd, (char *)&request, sizeof(request))); ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG); ufd.fd = reqfd; ufd.events = POLLIN; /* Enter server loop */ while(1) { n = __poll(&ufd, 1, 2000); /* Check for termination of the main thread */ if (getppid() == 1) { pthread_kill_all_threads(SIGKILL, 0); _exit(0); } /* Check for dead children */ if (terminated_children) { terminated_children = 0; pthread_reap_children(); } /* Read and execute request */ if (n == 1 && (ufd.revents & POLLIN)) { n = TEMP_FAILURE_RETRY(read_not_cancel(reqfd, (char *)&request, sizeof(request))); #ifdef DEBUG if (n < 0) { char d[64]; write(STDERR_FILENO, d, snprintf(d, sizeof(d), "*** read err %m\n")); } else if (n != sizeof(request)) { write(STDERR_FILENO, "*** short read in manager\n", 26); } #endif switch(request.req_kind) { case REQ_CREATE: request.req_thread->p_retcode = pthread_handle_create((pthread_t *) &request.req_thread->p_retval, request.req_args.create.attr, request.req_args.create.fn, request.req_args.create.arg, &request.req_args.create.mask, request.req_thread->p_pid, request.req_thread->p_report_events, &request.req_thread->p_eventbuf.eventmask); restart(request.req_thread); break; case REQ_FREE: pthread_handle_free(request.req_args.free.thread_id); break; case REQ_PROCESS_EXIT: pthread_handle_exit(request.req_thread, request.req_args.exit.code); /* NOTREACHED */ break; case REQ_MAIN_THREAD_EXIT: main_thread_exiting = 1; /* Reap children in case all other threads died and the signal handler went off before we set main_thread_exiting to 1, and therefore did not do REQ_KICK. */ pthread_reap_children(); if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { restart(__pthread_main_thread); /* The main thread will now call exit() which will trigger an __on_exit handler, which in turn will send REQ_PROCESS_EXIT to the thread manager. In case you are wondering how the manager terminates from its loop here. */ } break; case REQ_POST: sem_post(request.req_args.post); break; case REQ_DEBUG: /* Make gdb aware of new thread and gdb will restart the new thread when it is ready to handle the new thread. */ if (__pthread_threads_debug && __pthread_sig_debug > 0) raise(__pthread_sig_debug); break; case REQ_KICK: /* This is just a prod to get the manager to reap some threads right away, avoiding a potential delay at shutdown. */ break; case REQ_FOR_EACH_THREAD: pthread_for_each_thread(request.req_args.for_each.arg, request.req_args.for_each.fn); restart(request.req_thread); break; } } } }
if (file_offset == -1l) { /* Not available. */ *result = NULL; return -1; } LOCK_FILE (file_fd, F_RDLCK) { nbytes = 0; LOCKING_FAILED (); } /* Read the next entry. */ nbytes = read_not_cancel (file_fd, &last_entry, sizeof (struct utmp)); UNLOCK_FILE (file_fd); if (nbytes != sizeof (struct utmp)) { if (nbytes != 0) file_offset = -1l; *result = NULL; return -1; } /* Update position pointer. */ file_offset += sizeof (struct utmp); memcpy (buffer, &last_entry, sizeof (struct utmp));
/* Get the value of the system variable NAME. */ long int __sysconf (int name) { const char *procfname = NULL; switch (name) { struct rlimit rlimit; #ifdef __NR_clock_getres case _SC_MONOTONIC_CLOCK: /* Check using the clock_getres system call. */ { struct timespec ts; INTERNAL_SYSCALL_DECL (err); int r; r = INTERNAL_SYSCALL (clock_getres, err, 2, CLOCK_MONOTONIC, &ts); return INTERNAL_SYSCALL_ERROR_P (r, err) ? -1 : _POSIX_VERSION; } #endif case _SC_CPUTIME: case _SC_THREAD_CPUTIME: return HAS_CPUCLOCK (name); case _SC_ARG_MAX: #if !__ASSUME_ARG_MAX_STACK_BASED /* Determine whether this is a kernel with an argument limit determined by the stack size. */ if (GLRO(dl_discover_osversion) () >= __LINUX_ARG_MAX_STACK_BASED_MIN_KERNEL) #endif /* Use getrlimit to get the stack limit. */ if (__getrlimit (RLIMIT_STACK, &rlimit) == 0) return MAX (legacy_ARG_MAX, rlimit.rlim_cur / 4); return legacy_ARG_MAX; case _SC_NGROUPS_MAX: /* Try to read the information from the /proc/sys/kernel/ngroups_max file. */ procfname = "/proc/sys/kernel/ngroups_max"; break; case _SC_SIGQUEUE_MAX: if (__getrlimit (RLIMIT_SIGPENDING, &rlimit) == 0) return rlimit.rlim_cur; /* The /proc/sys/kernel/rtsig-max file contains the answer. */ procfname = "/proc/sys/kernel/rtsig-max"; break; default: break; } if (procfname != NULL) { int fd = open_not_cancel_2 (procfname, O_RDONLY); if (fd != -1) { /* This is more than enough, the file contains a single integer. */ char buf[32]; ssize_t n; n = TEMP_FAILURE_RETRY (read_not_cancel (fd, buf, sizeof (buf) - 1)); close_not_cancel_no_status (fd); if (n > 0) { /* Terminate the string. */ buf[n] = '\0'; char *endp; long int res = strtol (buf, &endp, 10); if (endp != buf && (*endp == '\0' || *endp == '\n')) return res; } } } return posix_sysconf (name); }