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 _write(fd, &type, sizeof(type)); 64 return (send_msg_with_cred(fd, data, size)); 65 } 66 67 /* Receive the type of the message that will follow. */ 68 int 69 receive_type_message(int fd) { 70 int type; 71 int r = _read(fd, &type, sizeof(type)); 72 return (r == 0 ? 0 : type); 73 } 74 75 /* Receive data. */ 76 int 77 receive_message(int fd, char *data, int size) { 78 _read(fd, data, size); 79 return (0); 80 } 81 82 int 83 is_sysvinit(void) { 84 return (daemon_fd == -1 ? 0:1); 85 } 86 87 static int 88 register_to_daemon(void) { 89 int flags; 90 char test = 't'; 91 92 daemon_fd = connect_to_daemon(LISTEN_SOCKET_FILE); 93 94 flags = _fcntl(daemon_fd, F_GETFD, 0); 95 if (_fcntl(daemon_fd, F_SETFD, flags & FD_CLOEXEC) == -1) { 96 sysv_print_err("fcntl error\n"); 97 return (-1); 98 } 99 100 /* Send a message such that daemon can obtain process credentials.*/ 101 send_msg_with_cred(daemon_fd, &test, sizeof(test)); 102 103 sysv_print("register to daemon: sock fd = %d\n", daemon_fd); 104 105 return (0); 106 } 107 108 /* Used in fork case, to avoid deadlocks. 109 * The fork caller acquires all locks before fork and release them 110 * after because the child will have only a thread. If one lock is 111 * taken by another thread than, in the child process, nobody will 112 * release it. 113 */ 114 static void 115 acquire_locks(void) { 116 struct entries_list *list; 117 struct hashentry *tmp; 118 struct shm_data *data; 119 struct semid_pool *semaptr; 120 int i; 121 122 SYSV_MUTEX_LOCK(&lock_undo); 123 SYSV_MUTEX_LOCK(&lock_resources); 124 //pthread_rwlock_wrlock(&rwlock_addrs); 125 126 for (i=0; i<get_hash_size(MAXSIZE); i++) { 127 list = &shmaddrs->entries[i]; 128 if (LIST_EMPTY(list)) 129 continue; 130 LIST_FOREACH(tmp, list, entry_link) { 131 data = (struct shm_data*)tmp->value; 132 if (data->type == SEMGET) { 133 semaptr = (struct semid_pool *)data->internal; 134 #ifdef SYSV_RWLOCK 135 #ifdef SYSV_SEMS 136 /* There is no need to acquire the mutexes from 137 * each semaphore in the group. It is enough 138 * to acquire the group lock in write mode. 139 */ 140 #endif 141 sysv_rwlock_wrlock(&semaptr->rwlock); 142 #else 143 sysv_mutex_lock(&semaptr->mutex); 144 #endif 145 } 146 } 147 } 148 } 149 150 /* Function called by parent after fork to release locks 151 * acquired before fork. 152 */ 153 static void 154 parent_release_locks(void) { 155 struct entries_list *list; 156 struct hashentry *tmp; 157 struct shm_data *data; 158 struct semid_pool *semaptr; 159 int i; 160 161 SYSV_MUTEX_UNLOCK(&lock_undo); 162 SYSV_MUTEX_UNLOCK(&lock_resources); 163 //pthread_rwlock_unlock(&rwlock_addrs); 164 165 for (i=0; i<get_hash_size(MAXSIZE); i++) { 166 list = &shmaddrs->entries[i]; 167 if (LIST_EMPTY(list)) 168 continue; 169 LIST_FOREACH(tmp, list, entry_link) { 170 data = (struct shm_data*)tmp->value; 171 if (data->type == SEMGET) { 172 semaptr = (struct semid_pool *)data->internal; 173 #ifdef SYSV_RWLOCK 174 sysv_rwlock_unlock(&semaptr->rwlock); 175 #else 176 sysv_mutex_unlock(&semaptr->mutex); 177 #endif 178 } 179 } 180 } 181 } 182 183 /* Function called by child after fork to release locks 184 * acquired before fork by the parent. 185 * Only locks specific to the address space are released. 186 * Those created in the shared memory are released by the 187 * parent. 188 */ 189 static void 190 child_release_locks(void) { 191 SYSV_MUTEX_UNLOCK(&lock_undo); 192 SYSV_MUTEX_UNLOCK(&lock_resources); 193 //pthread_rwlock_unlock(&rwlock_addrs); 194 } 195 196 static void 197 prepare_parent_atfork(void) { 198 /* Function called only if the process has 199 * sysv ipc structures initialized. 200 */ 201 if (!is_sysvinit()) 202 return; 203 204 /* Acquire all locks to be sure that neither one is 205 * held by another thread. 206 */ 207 acquire_locks(); 208 } 209 210 static void 211 parent_atfork(void) { 212 if (!is_sysvinit()) 213 return; 214 215 /* Release locks acquired before fork. */ 216 parent_release_locks(); 217 } 218 219 static void 220 child_atfork(void) { 221 if (!is_sysvinit()) 222 return; 223 224 /* Release locks acquired before fork. */ 225 child_release_locks(); 226 /* Close the file descriptor used by parent. */ 227 _close(daemon_fd); 228 229 /* Register it to daemon too. */ 230 if (register_to_daemon() < 0) { 231 sysv_print_err("register to daemon error\n"); 232 exit(-1); 233 } 234 235 /* Inform the daemon about each shared memory segment used. */ 236 shmchild(); 237 } 238 239 /* The function is called only once, when the process uses for 240 * the first time sysv ipc resources. 241 */ 242 int 243 sysvinit(void) { 244 245 if (is_sysvinit()) { 246 return (IPC_INITIALIZED); 247 } 248 249 if (register_to_daemon() < 0) 250 return (-1); 251 252 /* Add handlers for parent and child when fork is called. */ 253 if (_pthread_atfork(prepare_parent_atfork, parent_atfork, 254 child_atfork) < 0) { 255 sysv_print_err("pthread_atfork error\n"); 256 return (-1); 257 } 258 return 0; 259 } 260 261 int 262 sysvexit(void) { 263 if (!is_sysvinit()) 264 return (-1); 265 266 return (0); 267 } 268