1 /**
2 * Copyright (c) 2013 Larisa Grigore<larisagrigore@gmail.com>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. The name of the author may not be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "namespace.h"
29 #include <sys/param.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/ioctl.h>
33 #include <pthread.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include "un-namespace.h"
38
39 #include <stdio.h>
40
41 #include "sysvipc_ipc.h"
42 #include "sysvipc_sockets.h"
43 #include "sysvipc_sem.h"
44 #include "sysvipc_shm.h"
45 #include "sysvipc_hash.h"
46 #include "sysvipc_lock.h"
47 #include "sysvipc_lock_generic.h"
48
49 #define SYSV_MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
50 #define SYSV_MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
51 #define SYSV_MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x)
52
53 int daemon_fd = -1;
54
55 extern pthread_mutex_t lock_resources;
56 //extern pthread_rwlock_t rwlock_addrs;
57 extern pthread_mutex_t lock_undo;
58 extern struct hashtable *shmaddrs;
59
60 /* Send the type of the message followed by data. */
61 int
send_message(int fd,int type,char * data,int size)62 send_message(int fd, int type, char *data, int size)
63 {
64 _write(fd, &type, sizeof(type));
65 return (send_msg_with_cred(fd, data, size));
66 }
67
68 /* Receive the type of the message that will follow. */
69 int
receive_type_message(int fd)70 receive_type_message(int fd)
71 {
72 int type;
73 int r = _read(fd, &type, sizeof(type));
74 return (r == 0 ? 0 : type);
75 }
76
77 /* Receive data. */
78 int
receive_message(int fd,char * data,int size)79 receive_message(int fd, char *data, int size)
80 {
81 _read(fd, data, size);
82 return (0);
83 }
84
85 int
is_sysvinit(void)86 is_sysvinit(void)
87 {
88 return (daemon_fd == -1 ? 0:1);
89 }
90
91 static int
register_to_daemon(void)92 register_to_daemon(void)
93 {
94 int flags;
95 char test = 't';
96
97 daemon_fd = connect_to_daemon(LISTEN_SOCKET_FILE);
98
99 flags = _fcntl(daemon_fd, F_GETFD, 0);
100 if (_fcntl(daemon_fd, F_SETFD, flags & FD_CLOEXEC) == -1) {
101 sysv_print_err("fcntl error\n");
102 return (-1);
103 }
104
105 /* Send a message such that daemon can obtain process credentials.*/
106 send_msg_with_cred(daemon_fd, &test, sizeof(test));
107
108 sysv_print("register to daemon: sock fd = %d\n", daemon_fd);
109
110 return (0);
111 }
112
113 /* Used in fork case, to avoid deadlocks.
114 * The fork caller acquires all locks before fork and release them
115 * after because the child will have only a thread. If one lock is
116 * taken by another thread than, in the child process, nobody will
117 * release it.
118 */
119 static void
acquire_locks(void)120 acquire_locks(void)
121 {
122 struct entries_list *list;
123 struct hashentry *tmp;
124 struct shm_data *data;
125 struct semid_pool *semaptr;
126 int i;
127
128 SYSV_MUTEX_LOCK(&lock_undo);
129 SYSV_MUTEX_LOCK(&lock_resources);
130 //pthread_rwlock_wrlock(&rwlock_addrs);
131
132 for (i=0; i<get_hash_size(MAXSIZE); i++) {
133 list = &shmaddrs->entries[i];
134 if (LIST_EMPTY(list))
135 continue;
136 LIST_FOREACH(tmp, list, entry_link) {
137 data = (struct shm_data*)tmp->value;
138 if (data->type == SEMGET) {
139 semaptr = (struct semid_pool *)data->internal;
140 #ifdef SYSV_RWLOCK
141 #ifdef SYSV_SEMS
142 /* There is no need to acquire the mutexes from
143 * each semaphore in the group. It is enough
144 * to acquire the group lock in write mode.
145 */
146 #endif
147 sysv_rwlock_wrlock(&semaptr->rwlock);
148 #else
149 sysv_mutex_lock(&semaptr->mutex);
150 #endif
151 }
152 }
153 }
154 }
155
156 /* Function called by parent after fork to release locks
157 * acquired before fork.
158 */
159 static void
parent_release_locks(void)160 parent_release_locks(void)
161 {
162 struct entries_list *list;
163 struct hashentry *tmp;
164 struct shm_data *data;
165 struct semid_pool *semaptr;
166 int i;
167
168 SYSV_MUTEX_UNLOCK(&lock_undo);
169 SYSV_MUTEX_UNLOCK(&lock_resources);
170 //pthread_rwlock_unlock(&rwlock_addrs);
171
172 for (i=0; i<get_hash_size(MAXSIZE); i++) {
173 list = &shmaddrs->entries[i];
174 if (LIST_EMPTY(list))
175 continue;
176 LIST_FOREACH(tmp, list, entry_link) {
177 data = (struct shm_data*)tmp->value;
178 if (data->type == SEMGET) {
179 semaptr = (struct semid_pool *)data->internal;
180 #ifdef SYSV_RWLOCK
181 sysv_rwlock_unlock(&semaptr->rwlock);
182 #else
183 sysv_mutex_unlock(&semaptr->mutex);
184 #endif
185 }
186 }
187 }
188 }
189
190 /* Function called by child after fork to release locks
191 * acquired before fork by the parent.
192 * Only locks specific to the address space are released.
193 * Those created in the shared memory are released by the
194 * parent.
195 */
196 static void
child_release_locks(void)197 child_release_locks(void)
198 {
199 SYSV_MUTEX_UNLOCK(&lock_undo);
200 SYSV_MUTEX_UNLOCK(&lock_resources);
201 //pthread_rwlock_unlock(&rwlock_addrs);
202 }
203
204 static void
prepare_parent_atfork(void)205 prepare_parent_atfork(void)
206 {
207 /* Function called only if the process has
208 * sysv ipc structures initialized.
209 */
210 if (!is_sysvinit())
211 return;
212
213 /* Acquire all locks to be sure that neither one is
214 * held by another thread.
215 */
216 acquire_locks();
217 }
218
219 static void
parent_atfork(void)220 parent_atfork(void)
221 {
222 if (!is_sysvinit())
223 return;
224
225 /* Release locks acquired before fork. */
226 parent_release_locks();
227 }
228
229 static void
child_atfork(void)230 child_atfork(void)
231 {
232 if (!is_sysvinit())
233 return;
234
235 /* Release locks acquired before fork. */
236 child_release_locks();
237 /* Close the file descriptor used by parent. */
238 _close(daemon_fd);
239
240 /* Register it to daemon too. */
241 if (register_to_daemon() < 0) {
242 sysv_print_err("register to daemon error\n");
243 exit(-1);
244 }
245
246 /* Inform the daemon about each shared memory segment used. */
247 shmchild();
248 }
249
250 /* The function is called only once, when the process uses for
251 * the first time sysv ipc resources.
252 */
253 int
sysvinit(void)254 sysvinit(void)
255 {
256 if (is_sysvinit()) {
257 return (IPC_INITIALIZED);
258 }
259
260 if (register_to_daemon() < 0)
261 return (-1);
262
263 /* Add handlers for parent and child when fork is called. */
264 if (_pthread_atfork(prepare_parent_atfork, parent_atfork,
265 child_atfork) < 0) {
266 sysv_print_err("pthread_atfork error\n");
267 return (-1);
268 }
269 return 0;
270 }
271
272 int
sysvexit(void)273 sysvexit(void)
274 {
275 if (!is_sysvinit())
276 return (-1);
277
278 return (0);
279 }
280