/* SysV shmctl for Hurd. Copyright (C) 2005-2015 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 . */ #include #include #include #include #include #include #include #include #include "sysvshm.h" /* Provide operations to control 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; } weak_alias(__shmctl, shmctl)