int __stat(struct _reent *r, const char *str, struct stat *sb) { int fd, rv; fd = open(str, 0); if (fd < 0) return (-1); rv = __fstat(r, fd, sb); (void)close(fd); return (rv); }
int fstat(int fd, struct stat *st) { int ret; struct freebsd_stat fst; ret = __fstat(fd, &fst); if (ret == -1) { errno = EBADF; return -1; } st->st_size = fst.st_size; switch (fst.st_mode & FREEBSD_S_IFMT) { case FREEBSD_S_IFBLK: __ioctl(fd, DIOCGMEDIASIZE, &fst.st_size); break; case FREEBSD_S_IFCHR: /* XXX only for tap device */ ret = __ioctl(fd, SIOCGIFADDR, st->st_hwaddr); if (ret == 0) { /* say we are a "socket" ie network device */ fst.st_mode = FREEBSD_S_IFSOCK; /* add to poll */ __platform_pollfd[__platform_npoll].fd = fd; __platform_pollfd[__platform_npoll].events = POLLIN | POLLPRI; __platform_npoll++; } break; } st->st_mode = (FREEBSD_S_ISDIR (fst.st_mode) ? S_IFDIR : 0) | (FREEBSD_S_ISCHR (fst.st_mode) ? S_IFCHR : 0) | (FREEBSD_S_ISBLK (fst.st_mode) ? S_IFBLK : 0) | (FREEBSD_S_ISREG (fst.st_mode) ? S_IFREG : 0) | (FREEBSD_S_ISFIFO(fst.st_mode) ? S_IFIFO : 0) | (FREEBSD_S_ISLNK (fst.st_mode) ? S_IFLNK : 0) | (FREEBSD_S_ISSOCK(fst.st_mode) ? S_IFSOCK : 0); return 0; }
/* Initialize STREAM as necessary. This may change I/O functions, give a buffer, etc. If no buffer is allocated, but the bufsize is set, the bufsize will be used to allocate the buffer. */ void __stdio_init_stream (FILE *stream) { const int fd = (int) stream->__cookie; struct stat statb; if (stream->__buffer != NULL || stream->__userbuf) /* If's unbuffered by request, we can't do anything useful. */ return; /* Find out what sort of file this is. */ if (__fstat (fd, &statb) < 0) return; if (S_ISCHR (statb.st_mode)) { /* It's a character device. Make it line-buffered if it's a terminal. */ if (__isatty (fd)) { stream->__linebuf = 1; /* Unix terminal devices have the bad habit of claiming to be seekable. On systems I have tried, seeking on a terminal device seems to set its file position as specified, such that a later tell says the same thing. This is in no way related to actual seekability--the ability to seek back and read old data. Unix terminal devices will let you "seek back", and then read more new data from the terminal. I can think of nothing to do about this lossage except to preemptively disable seeking on terminal devices. */ stream->__io_funcs.__seek = NULL; /* Seeks get ESPIPE. */ } } #ifdef _STATBUF_ST_BLKSIZE /* Use the block-size field to determine the system's optimal buffering size. */ stream->__bufsize = statb.st_blksize; #endif }
/* Open the shared memory segment KEY (creating it if it doesn't yet exist) and return a file descriptor to it in R_FD. */ static error_t get_shared (int shmflags, size_t size, key_t key, int *r_fd) { error_t err = 0; char filename[sizeof (SHM_DIR) - 1 + SHM_NAMEMAX]; int fd = -1; int create_flag; create_flag = (shmflags & IPC_CREAT) ? O_CREAT : 0; sprintf (filename, SHM_DIR SHM_NAMEPRI, key); do { fd = __open (filename, O_NORW | create_flag, shmflags & 0777); if (fd < 0 && errno != ENOENT) /* We give up. */ return errno; else if (fd >= 0) { int res; struct stat statbuf; /* Check the size (we only need to do this if we did not create the shared memory segment file ourselves). */ res = __fstat (fd, &statbuf); if (res < 0) { err = errno; __close (fd); return err; } if (statbuf.st_size < size) { __close (fd); return EINVAL; } } else { /* The memory segment doesn't exist. */ if (create_flag) { /* Try to create it exclusively. */ err = get_exclusive (shmflags, size, &key, &fd); if (err == EEXIST) /* If somebody created it in the meanwhile, just try again. */ err = 0; } else err = ENOENT; } } while (fd < 0 && !err); if (!err) *r_fd = fd; else *r_fd = -1; return err; }
int fstat(int fd, struct stat *sb) { return __fstat(_GLOBAL_REENT, fd, sb); }
/* Provide operations to control over shared memory segments. */ int __shmctl (int id, int cmd, struct shmid_ds *buf) { error_t err = 0; int fd; int res; char filename[sizeof (SHM_DIR) - 1 + SHM_NAMEMAX]; struct stat statbuf; sprintf (filename, SHM_DIR SHM_NAMEPRI, id); /* SysV requires read access for IPC_STAT. */ fd = __open (filename, O_NORW); if (fd < 0) { if (errno == ENOENT) errno = EINVAL; return -1; } res = __fstat (fd, &statbuf); if (res < 0) { err = errno; __close (fd); errno = err; return -1; } switch (cmd) { case IPC_STAT: buf->shm_perm.__key = id; buf->shm_perm.uid = statbuf.st_uid; buf->shm_perm.gid = statbuf.st_gid; /* We do not support the creator. */ buf->shm_perm.cuid = statbuf.st_uid; buf->shm_perm.cgid = statbuf.st_gid; /* We just want the protection bits. */ buf->shm_perm.mode = statbuf.st_mode & 0777; /* Hopeless. We do not support a sequence number. */ buf->shm_perm.__seq = statbuf.st_ino; buf->shm_segsz = statbuf.st_size; /* Hopeless. We do not support any of these. */ buf->shm_atime = statbuf.st_atime; buf->shm_dtime = statbuf.st_mtime; /* Well, this comes at least close. */ buf->shm_ctime = statbuf.st_ctime; /* We do not support the PID. */ buf->shm_cpid = 0; buf->shm_lpid = 0; if (statbuf.st_mode & S_IMMAP0) buf->shm_nattch = 0; else /* 42 is the answer. Of course this is bogus, but for most applications, this should be fine. */ buf->shm_nattch = 42; break; case IPC_SET: if (statbuf.st_uid != buf->shm_perm.uid || statbuf.st_gid != buf->shm_perm.gid) { res = __fchown (fd, (statbuf.st_uid != buf->shm_perm.uid) ? buf->shm_perm.uid : -1, (statbuf.st_gid != buf->shm_perm.gid) ? buf->shm_perm.gid : -1); if (res < 0) err = errno; } if (!err && statbuf.st_mode & 0777 != buf->shm_perm.mode & 0777) { res = __fchmod (fd, (statbuf.st_mode & ~0777) | (buf->shm_perm.mode & 0777)); if (res < 0) err = errno; } break; case IPC_RMID: res = __unlink (filename); /* FIXME: Check error (mapping ENOENT to EINVAL). */ break; default: err = EINVAL; } __close (fd); errno = err; return err ? -1 : 0; }