1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
|
/* Copyright (C) 1995,1997,1998,2000,2003,2004,2006
Free Software Foundation, Inc.
This file is part of the GNU C Library.
Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995.
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, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
#include <errno.h>
#include <sys/shm.h>
#include <ipc_priv.h>
#include <sysdep.h>
#include <string.h>
#include <sys/syscall.h>
#include <bits/wordsize.h>
#include <shlib-compat.h>
#include <bp-checks.h>
#include <kernel-features.h>
struct __old_shmid_ds
{
struct __old_ipc_perm shm_perm; /* operation permission struct */
int shm_segsz; /* size of segment in bytes */
__time_t shm_atime; /* time of last shmat() */
__time_t shm_dtime; /* time of last shmdt() */
__time_t shm_ctime; /* time of last change by shmctl() */
__ipc_pid_t shm_cpid; /* pid of creator */
__ipc_pid_t shm_lpid; /* pid of last shmop */
unsigned short int shm_nattch; /* number of current attaches */
unsigned short int __shm_npages; /* size of segment (pages) */
unsigned long int *__unbounded __shm_pages; /* array of ptrs to frames -> SHMMAX */
struct vm_area_struct *__unbounded __attaches; /* descriptors for attaches */
};
struct __old_shminfo
{
int shmmax;
int shmmin;
int shmmni;
int shmseg;
int shmall;
};
/* Provide operations to control over shared memory segments. */
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
int __old_shmctl (int, int, struct __old_shmid_ds *);
#endif
int __new_shmctl (int, int, struct shmid_ds *);
#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2)
int
attribute_compat_text_section
__old_shmctl (int shmid, int cmd, struct __old_shmid_ds *buf)
{
return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid,
cmd, 0, CHECK_1_NULL_OK (buf));
}
compat_symbol (libc, __old_shmctl, shmctl, GLIBC_2_0);
#endif
int
__new_shmctl (int shmid, int cmd, struct shmid_ds *buf)
{
#if __ASSUME_IPC64 > 0
return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0,
CHECK_1 (buf));
#else
switch (cmd) {
case SHM_STAT:
case IPC_STAT:
case IPC_SET:
#if __WORDSIZE != 32
case IPC_INFO:
#endif
break;
default:
return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0,
CHECK_1 (buf));
}
{
int save_errno = errno, result;
union
{
struct __old_shmid_ds ds;
struct __old_shminfo info;
} old;
/* Unfortunately there is no way how to find out for sure whether
we should use old or new shmctl. */
result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0,
CHECK_1 (buf));
if (result != -1 || errno != EINVAL)
return result;
__set_errno(save_errno);
if (cmd == IPC_SET)
{
old.ds.shm_perm.uid = buf->shm_perm.uid;
old.ds.shm_perm.gid = buf->shm_perm.gid;
old.ds.shm_perm.mode = buf->shm_perm.mode;
if (old.ds.shm_perm.uid != buf->shm_perm.uid ||
old.ds.shm_perm.gid != buf->shm_perm.gid)
{
__set_errno (EINVAL);
return -1;
}
}
result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0,
__ptrvalue (&old.ds));
if (result != -1 && (cmd == SHM_STAT || cmd == IPC_STAT))
{
memset(buf, 0, sizeof(*buf));
buf->shm_perm.__key = old.ds.shm_perm.__key;
buf->shm_perm.uid = old.ds.shm_perm.uid;
buf->shm_perm.gid = old.ds.shm_perm.gid;
buf->shm_perm.cuid = old.ds.shm_perm.cuid;
buf->shm_perm.cgid = old.ds.shm_perm.cgid;
buf->shm_perm.mode = old.ds.shm_perm.mode;
buf->shm_perm.__seq = old.ds.shm_perm.__seq;
buf->shm_atime = old.ds.shm_atime;
buf->shm_dtime = old.ds.shm_dtime;
buf->shm_ctime = old.ds.shm_ctime;
buf->shm_segsz = old.ds.shm_segsz;
buf->shm_nattch = old.ds.shm_nattch;
buf->shm_cpid = old.ds.shm_cpid;
buf->shm_lpid = old.ds.shm_lpid;
}
#if __WORDSIZE != 32
else if (result != -1 && cmd == IPC_INFO)
{
struct shminfo *i = (struct shminfo *)buf;
memset(i, 0, sizeof(*i));
i->shmmax = old.info.shmmax;
i->shmmin = old.info.shmmin;
i->shmmni = old.info.shmmni;
i->shmseg = old.info.shmseg;
i->shmall = old.info.shmall;
}
#endif
return result;
}
#endif
}
versioned_symbol (libc, __new_shmctl, shmctl, GLIBC_2_2);
|