]>
Commit | Line | Data |
---|---|---|
1 | /* Copyright (C) 1995-2015 Free Software Foundation, Inc. | |
2 | This file is part of the GNU C Library. | |
3 | Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, August 1995. | |
4 | ||
5 | The GNU C Library is free software; you can redistribute it and/or | |
6 | modify it under the terms of the GNU Lesser General Public | |
7 | License as published by the Free Software Foundation; either | |
8 | version 2.1 of the License, or (at your option) any later version. | |
9 | ||
10 | The GNU C Library is distributed in the hope that it will be useful, | |
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | Lesser General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU Lesser General Public | |
16 | License along with the GNU C Library; if not, see | |
17 | <http://www.gnu.org/licenses/>. */ | |
18 | ||
19 | #include <errno.h> | |
20 | #include <sys/shm.h> | |
21 | #include <ipc_priv.h> | |
22 | ||
23 | #include <sysdep.h> | |
24 | #include <string.h> | |
25 | #include <sys/syscall.h> | |
26 | #include <bits/wordsize.h> | |
27 | #include <shlib-compat.h> | |
28 | ||
29 | #include <kernel-features.h> | |
30 | ||
31 | struct __old_shmid_ds | |
32 | { | |
33 | struct __old_ipc_perm shm_perm; /* operation permission struct */ | |
34 | int shm_segsz; /* size of segment in bytes */ | |
35 | __time_t shm_atime; /* time of last shmat() */ | |
36 | __time_t shm_dtime; /* time of last shmdt() */ | |
37 | __time_t shm_ctime; /* time of last change by shmctl() */ | |
38 | __ipc_pid_t shm_cpid; /* pid of creator */ | |
39 | __ipc_pid_t shm_lpid; /* pid of last shmop */ | |
40 | unsigned short int shm_nattch; /* number of current attaches */ | |
41 | unsigned short int __shm_npages; /* size of segment (pages) */ | |
42 | unsigned long int *__shm_pages; /* array of ptrs to frames -> SHMMAX */ | |
43 | struct vm_area_struct *__attaches; /* descriptors for attaches */ | |
44 | }; | |
45 | ||
46 | struct __old_shminfo | |
47 | { | |
48 | int shmmax; | |
49 | int shmmin; | |
50 | int shmmni; | |
51 | int shmseg; | |
52 | int shmall; | |
53 | }; | |
54 | ||
55 | /* Provide operations to control over shared memory segments. */ | |
56 | #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2) | |
57 | int __old_shmctl (int, int, struct __old_shmid_ds *); | |
58 | #endif | |
59 | int __new_shmctl (int, int, struct shmid_ds *); | |
60 | ||
61 | #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_2) | |
62 | int | |
63 | attribute_compat_text_section | |
64 | __old_shmctl (int shmid, int cmd, struct __old_shmid_ds *buf) | |
65 | { | |
66 | return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0, buf); | |
67 | } | |
68 | compat_symbol (libc, __old_shmctl, shmctl, GLIBC_2_0); | |
69 | #endif | |
70 | ||
71 | int | |
72 | __new_shmctl (int shmid, int cmd, struct shmid_ds *buf) | |
73 | { | |
74 | #if __ASSUME_IPC64 > 0 | |
75 | return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0, | |
76 | buf); | |
77 | #else | |
78 | switch (cmd) { | |
79 | case SHM_STAT: | |
80 | case IPC_STAT: | |
81 | case IPC_SET: | |
82 | #if __WORDSIZE != 32 | |
83 | case IPC_INFO: | |
84 | #endif | |
85 | break; | |
86 | default: | |
87 | return INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0, buf); | |
88 | } | |
89 | ||
90 | { | |
91 | int save_errno = errno, result; | |
92 | union | |
93 | { | |
94 | struct __old_shmid_ds ds; | |
95 | struct __old_shminfo info; | |
96 | } old; | |
97 | ||
98 | /* Unfortunately there is no way how to find out for sure whether | |
99 | we should use old or new shmctl. */ | |
100 | result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd | __IPC_64, 0, | |
101 | buf); | |
102 | if (result != -1 || errno != EINVAL) | |
103 | return result; | |
104 | ||
105 | __set_errno(save_errno); | |
106 | if (cmd == IPC_SET) | |
107 | { | |
108 | old.ds.shm_perm.uid = buf->shm_perm.uid; | |
109 | old.ds.shm_perm.gid = buf->shm_perm.gid; | |
110 | old.ds.shm_perm.mode = buf->shm_perm.mode; | |
111 | if (old.ds.shm_perm.uid != buf->shm_perm.uid || | |
112 | old.ds.shm_perm.gid != buf->shm_perm.gid) | |
113 | { | |
114 | __set_errno (EINVAL); | |
115 | return -1; | |
116 | } | |
117 | } | |
118 | result = INLINE_SYSCALL (ipc, 5, IPCOP_shmctl, shmid, cmd, 0, &old.ds); | |
119 | if (result != -1 && (cmd == SHM_STAT || cmd == IPC_STAT)) | |
120 | { | |
121 | memset(buf, 0, sizeof(*buf)); | |
122 | buf->shm_perm.__key = old.ds.shm_perm.__key; | |
123 | buf->shm_perm.uid = old.ds.shm_perm.uid; | |
124 | buf->shm_perm.gid = old.ds.shm_perm.gid; | |
125 | buf->shm_perm.cuid = old.ds.shm_perm.cuid; | |
126 | buf->shm_perm.cgid = old.ds.shm_perm.cgid; | |
127 | buf->shm_perm.mode = old.ds.shm_perm.mode; | |
128 | buf->shm_perm.__seq = old.ds.shm_perm.__seq; | |
129 | buf->shm_atime = old.ds.shm_atime; | |
130 | buf->shm_dtime = old.ds.shm_dtime; | |
131 | buf->shm_ctime = old.ds.shm_ctime; | |
132 | buf->shm_segsz = old.ds.shm_segsz; | |
133 | buf->shm_nattch = old.ds.shm_nattch; | |
134 | buf->shm_cpid = old.ds.shm_cpid; | |
135 | buf->shm_lpid = old.ds.shm_lpid; | |
136 | } | |
137 | #if __WORDSIZE != 32 | |
138 | else if (result != -1 && cmd == IPC_INFO) | |
139 | { | |
140 | struct shminfo *i = (struct shminfo *)buf; | |
141 | ||
142 | memset(i, 0, sizeof(*i)); | |
143 | i->shmmax = old.info.shmmax; | |
144 | i->shmmin = old.info.shmmin; | |
145 | i->shmmni = old.info.shmmni; | |
146 | i->shmseg = old.info.shmseg; | |
147 | i->shmall = old.info.shmall; | |
148 | } | |
149 | #endif | |
150 | return result; | |
151 | } | |
152 | #endif | |
153 | } | |
154 | ||
155 | versioned_symbol (libc, __new_shmctl, shmctl, GLIBC_2_2); |