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 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 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 79 receive_message(int fd, char *data, int size) 80 { 81 _read(fd, data, size); 82 return (0); 83 } 84 85 int 86 is_sysvinit(void) 87 { 88 return (daemon_fd == -1 ? 0:1); 89 } 90 91 static int 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 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 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 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 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 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 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 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 273 sysvexit(void) 274 { 275 if (!is_sysvinit()) 276 return (-1); 277 278 return (0); 279 } 280