diff options
Diffstat (limited to 'sysdeps/mach/hurd/shmctl.c')
-rw-r--r-- | sysdeps/mach/hurd/shmctl.c | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/sysdeps/mach/hurd/shmctl.c b/sysdeps/mach/hurd/shmctl.c new file mode 100644 index 0000000000..a991a0c8de --- /dev/null +++ b/sysdeps/mach/hurd/shmctl.c @@ -0,0 +1,132 @@ +/* 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 + <http://www.gnu.org/licenses/>. */ + +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <sys/stat.h> +#include <fcntl.h> + +#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) |