182657471SMarkus Pfeiffer /**
282657471SMarkus Pfeiffer * Copyright (c) 2013 Larisa Grigore<larisagrigore@gmail.com>.
382657471SMarkus Pfeiffer * All rights reserved.
482657471SMarkus Pfeiffer *
582657471SMarkus Pfeiffer * Redistribution and use in source and binary forms, with or without
682657471SMarkus Pfeiffer * modification, are permitted provided that the following conditions
782657471SMarkus Pfeiffer * are met:
882657471SMarkus Pfeiffer * 1. Redistributions of source code must retain the above copyright
982657471SMarkus Pfeiffer * notice, this list of conditions and the following disclaimer.
1082657471SMarkus Pfeiffer * 2. Redistributions in binary form must reproduce the above copyright
1182657471SMarkus Pfeiffer * notice, this list of conditions and the following disclaimer in the
1282657471SMarkus Pfeiffer * documentation and/or other materials provided with the distribution.
1382657471SMarkus Pfeiffer * 3. The name of the author may not be used to endorse or promote products
1482657471SMarkus Pfeiffer * derived from this software without specific prior written permission.
1582657471SMarkus Pfeiffer *
1682657471SMarkus Pfeiffer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1782657471SMarkus Pfeiffer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1882657471SMarkus Pfeiffer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1982657471SMarkus Pfeiffer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2082657471SMarkus Pfeiffer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2182657471SMarkus Pfeiffer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2282657471SMarkus Pfeiffer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2382657471SMarkus Pfeiffer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2482657471SMarkus Pfeiffer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2582657471SMarkus Pfeiffer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2682657471SMarkus Pfeiffer */
2782657471SMarkus Pfeiffer
2882657471SMarkus Pfeiffer #include "namespace.h"
2982657471SMarkus Pfeiffer #include <sys/param.h>
3082657471SMarkus Pfeiffer #include <sys/types.h>
3182657471SMarkus Pfeiffer #include <sys/stat.h>
3282657471SMarkus Pfeiffer #include <sys/ioctl.h>
3382657471SMarkus Pfeiffer #include <pthread.h>
3482657471SMarkus Pfeiffer #include <stdlib.h>
3582657471SMarkus Pfeiffer #include <unistd.h>
3682657471SMarkus Pfeiffer #include <fcntl.h>
3782657471SMarkus Pfeiffer #include "un-namespace.h"
3882657471SMarkus Pfeiffer
3982657471SMarkus Pfeiffer #include <stdio.h>
4082657471SMarkus Pfeiffer
4182657471SMarkus Pfeiffer #include "sysvipc_ipc.h"
4282657471SMarkus Pfeiffer #include "sysvipc_sockets.h"
4382657471SMarkus Pfeiffer #include "sysvipc_sem.h"
4482657471SMarkus Pfeiffer #include "sysvipc_shm.h"
4582657471SMarkus Pfeiffer #include "sysvipc_hash.h"
4682657471SMarkus Pfeiffer #include "sysvipc_lock.h"
4782657471SMarkus Pfeiffer #include "sysvipc_lock_generic.h"
4882657471SMarkus Pfeiffer
4982657471SMarkus Pfeiffer #define SYSV_MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x)
5082657471SMarkus Pfeiffer #define SYSV_MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x)
5182657471SMarkus Pfeiffer #define SYSV_MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x)
5282657471SMarkus Pfeiffer
5382657471SMarkus Pfeiffer int daemon_fd = -1;
5482657471SMarkus Pfeiffer
5582657471SMarkus Pfeiffer extern pthread_mutex_t lock_resources;
5682657471SMarkus Pfeiffer //extern pthread_rwlock_t rwlock_addrs;
5782657471SMarkus Pfeiffer extern pthread_mutex_t lock_undo;
5882657471SMarkus Pfeiffer extern struct hashtable *shmaddrs;
5982657471SMarkus Pfeiffer
6082657471SMarkus Pfeiffer /* Send the type of the message followed by data. */
6182657471SMarkus Pfeiffer int
send_message(int fd,int type,char * data,int size)62*ff86f401SSascha Wildner send_message(int fd, int type, char *data, int size)
63*ff86f401SSascha Wildner {
6482657471SMarkus Pfeiffer _write(fd, &type, sizeof(type));
6582657471SMarkus Pfeiffer return (send_msg_with_cred(fd, data, size));
6682657471SMarkus Pfeiffer }
6782657471SMarkus Pfeiffer
6882657471SMarkus Pfeiffer /* Receive the type of the message that will follow. */
6982657471SMarkus Pfeiffer int
receive_type_message(int fd)70*ff86f401SSascha Wildner receive_type_message(int fd)
71*ff86f401SSascha Wildner {
7282657471SMarkus Pfeiffer int type;
7382657471SMarkus Pfeiffer int r = _read(fd, &type, sizeof(type));
7482657471SMarkus Pfeiffer return (r == 0 ? 0 : type);
7582657471SMarkus Pfeiffer }
7682657471SMarkus Pfeiffer
7782657471SMarkus Pfeiffer /* Receive data. */
7882657471SMarkus Pfeiffer int
receive_message(int fd,char * data,int size)79*ff86f401SSascha Wildner receive_message(int fd, char *data, int size)
80*ff86f401SSascha Wildner {
8182657471SMarkus Pfeiffer _read(fd, data, size);
8282657471SMarkus Pfeiffer return (0);
8382657471SMarkus Pfeiffer }
8482657471SMarkus Pfeiffer
8582657471SMarkus Pfeiffer int
is_sysvinit(void)86*ff86f401SSascha Wildner is_sysvinit(void)
87*ff86f401SSascha Wildner {
8882657471SMarkus Pfeiffer return (daemon_fd == -1 ? 0:1);
8982657471SMarkus Pfeiffer }
9082657471SMarkus Pfeiffer
9182657471SMarkus Pfeiffer static int
register_to_daemon(void)92*ff86f401SSascha Wildner register_to_daemon(void)
93*ff86f401SSascha Wildner {
9482657471SMarkus Pfeiffer int flags;
9582657471SMarkus Pfeiffer char test = 't';
9682657471SMarkus Pfeiffer
9782657471SMarkus Pfeiffer daemon_fd = connect_to_daemon(LISTEN_SOCKET_FILE);
9882657471SMarkus Pfeiffer
9982657471SMarkus Pfeiffer flags = _fcntl(daemon_fd, F_GETFD, 0);
10082657471SMarkus Pfeiffer if (_fcntl(daemon_fd, F_SETFD, flags & FD_CLOEXEC) == -1) {
10182657471SMarkus Pfeiffer sysv_print_err("fcntl error\n");
10282657471SMarkus Pfeiffer return (-1);
10382657471SMarkus Pfeiffer }
10482657471SMarkus Pfeiffer
10582657471SMarkus Pfeiffer /* Send a message such that daemon can obtain process credentials.*/
10682657471SMarkus Pfeiffer send_msg_with_cred(daemon_fd, &test, sizeof(test));
10782657471SMarkus Pfeiffer
10882657471SMarkus Pfeiffer sysv_print("register to daemon: sock fd = %d\n", daemon_fd);
10982657471SMarkus Pfeiffer
11082657471SMarkus Pfeiffer return (0);
11182657471SMarkus Pfeiffer }
11282657471SMarkus Pfeiffer
11382657471SMarkus Pfeiffer /* Used in fork case, to avoid deadlocks.
11482657471SMarkus Pfeiffer * The fork caller acquires all locks before fork and release them
11582657471SMarkus Pfeiffer * after because the child will have only a thread. If one lock is
11682657471SMarkus Pfeiffer * taken by another thread than, in the child process, nobody will
11782657471SMarkus Pfeiffer * release it.
11882657471SMarkus Pfeiffer */
11982657471SMarkus Pfeiffer static void
acquire_locks(void)120*ff86f401SSascha Wildner acquire_locks(void)
121*ff86f401SSascha Wildner {
12282657471SMarkus Pfeiffer struct entries_list *list;
12382657471SMarkus Pfeiffer struct hashentry *tmp;
12482657471SMarkus Pfeiffer struct shm_data *data;
12582657471SMarkus Pfeiffer struct semid_pool *semaptr;
12682657471SMarkus Pfeiffer int i;
12782657471SMarkus Pfeiffer
12882657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_undo);
12982657471SMarkus Pfeiffer SYSV_MUTEX_LOCK(&lock_resources);
13082657471SMarkus Pfeiffer //pthread_rwlock_wrlock(&rwlock_addrs);
13182657471SMarkus Pfeiffer
13282657471SMarkus Pfeiffer for (i=0; i<get_hash_size(MAXSIZE); i++) {
13382657471SMarkus Pfeiffer list = &shmaddrs->entries[i];
13482657471SMarkus Pfeiffer if (LIST_EMPTY(list))
13582657471SMarkus Pfeiffer continue;
13682657471SMarkus Pfeiffer LIST_FOREACH(tmp, list, entry_link) {
13782657471SMarkus Pfeiffer data = (struct shm_data*)tmp->value;
13882657471SMarkus Pfeiffer if (data->type == SEMGET) {
13982657471SMarkus Pfeiffer semaptr = (struct semid_pool *)data->internal;
14082657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
14182657471SMarkus Pfeiffer #ifdef SYSV_SEMS
14282657471SMarkus Pfeiffer /* There is no need to acquire the mutexes from
14382657471SMarkus Pfeiffer * each semaphore in the group. It is enough
14482657471SMarkus Pfeiffer * to acquire the group lock in write mode.
14582657471SMarkus Pfeiffer */
14682657471SMarkus Pfeiffer #endif
14782657471SMarkus Pfeiffer sysv_rwlock_wrlock(&semaptr->rwlock);
14882657471SMarkus Pfeiffer #else
14982657471SMarkus Pfeiffer sysv_mutex_lock(&semaptr->mutex);
15082657471SMarkus Pfeiffer #endif
15182657471SMarkus Pfeiffer }
15282657471SMarkus Pfeiffer }
15382657471SMarkus Pfeiffer }
15482657471SMarkus Pfeiffer }
15582657471SMarkus Pfeiffer
15682657471SMarkus Pfeiffer /* Function called by parent after fork to release locks
15782657471SMarkus Pfeiffer * acquired before fork.
15882657471SMarkus Pfeiffer */
15982657471SMarkus Pfeiffer static void
parent_release_locks(void)160*ff86f401SSascha Wildner parent_release_locks(void)
161*ff86f401SSascha Wildner {
16282657471SMarkus Pfeiffer struct entries_list *list;
16382657471SMarkus Pfeiffer struct hashentry *tmp;
16482657471SMarkus Pfeiffer struct shm_data *data;
16582657471SMarkus Pfeiffer struct semid_pool *semaptr;
16682657471SMarkus Pfeiffer int i;
16782657471SMarkus Pfeiffer
16882657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_undo);
16982657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources);
17082657471SMarkus Pfeiffer //pthread_rwlock_unlock(&rwlock_addrs);
17182657471SMarkus Pfeiffer
17282657471SMarkus Pfeiffer for (i=0; i<get_hash_size(MAXSIZE); i++) {
17382657471SMarkus Pfeiffer list = &shmaddrs->entries[i];
17482657471SMarkus Pfeiffer if (LIST_EMPTY(list))
17582657471SMarkus Pfeiffer continue;
17682657471SMarkus Pfeiffer LIST_FOREACH(tmp, list, entry_link) {
17782657471SMarkus Pfeiffer data = (struct shm_data*)tmp->value;
17882657471SMarkus Pfeiffer if (data->type == SEMGET) {
17982657471SMarkus Pfeiffer semaptr = (struct semid_pool *)data->internal;
18082657471SMarkus Pfeiffer #ifdef SYSV_RWLOCK
18182657471SMarkus Pfeiffer sysv_rwlock_unlock(&semaptr->rwlock);
18282657471SMarkus Pfeiffer #else
18382657471SMarkus Pfeiffer sysv_mutex_unlock(&semaptr->mutex);
18482657471SMarkus Pfeiffer #endif
18582657471SMarkus Pfeiffer }
18682657471SMarkus Pfeiffer }
18782657471SMarkus Pfeiffer }
18882657471SMarkus Pfeiffer }
18982657471SMarkus Pfeiffer
19082657471SMarkus Pfeiffer /* Function called by child after fork to release locks
19182657471SMarkus Pfeiffer * acquired before fork by the parent.
19282657471SMarkus Pfeiffer * Only locks specific to the address space are released.
19382657471SMarkus Pfeiffer * Those created in the shared memory are released by the
19482657471SMarkus Pfeiffer * parent.
19582657471SMarkus Pfeiffer */
19682657471SMarkus Pfeiffer static void
child_release_locks(void)197*ff86f401SSascha Wildner child_release_locks(void)
198*ff86f401SSascha Wildner {
19982657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_undo);
20082657471SMarkus Pfeiffer SYSV_MUTEX_UNLOCK(&lock_resources);
20182657471SMarkus Pfeiffer //pthread_rwlock_unlock(&rwlock_addrs);
20282657471SMarkus Pfeiffer }
20382657471SMarkus Pfeiffer
20482657471SMarkus Pfeiffer static void
prepare_parent_atfork(void)205*ff86f401SSascha Wildner prepare_parent_atfork(void)
206*ff86f401SSascha Wildner {
20782657471SMarkus Pfeiffer /* Function called only if the process has
20882657471SMarkus Pfeiffer * sysv ipc structures initialized.
20982657471SMarkus Pfeiffer */
21082657471SMarkus Pfeiffer if (!is_sysvinit())
21182657471SMarkus Pfeiffer return;
21282657471SMarkus Pfeiffer
21382657471SMarkus Pfeiffer /* Acquire all locks to be sure that neither one is
21482657471SMarkus Pfeiffer * held by another thread.
21582657471SMarkus Pfeiffer */
21682657471SMarkus Pfeiffer acquire_locks();
21782657471SMarkus Pfeiffer }
21882657471SMarkus Pfeiffer
21982657471SMarkus Pfeiffer static void
parent_atfork(void)220*ff86f401SSascha Wildner parent_atfork(void)
221*ff86f401SSascha Wildner {
22282657471SMarkus Pfeiffer if (!is_sysvinit())
22382657471SMarkus Pfeiffer return;
22482657471SMarkus Pfeiffer
22582657471SMarkus Pfeiffer /* Release locks acquired before fork. */
22682657471SMarkus Pfeiffer parent_release_locks();
22782657471SMarkus Pfeiffer }
22882657471SMarkus Pfeiffer
22982657471SMarkus Pfeiffer static void
child_atfork(void)230*ff86f401SSascha Wildner child_atfork(void)
231*ff86f401SSascha Wildner {
23282657471SMarkus Pfeiffer if (!is_sysvinit())
23382657471SMarkus Pfeiffer return;
23482657471SMarkus Pfeiffer
23582657471SMarkus Pfeiffer /* Release locks acquired before fork. */
23682657471SMarkus Pfeiffer child_release_locks();
23782657471SMarkus Pfeiffer /* Close the file descriptor used by parent. */
23882657471SMarkus Pfeiffer _close(daemon_fd);
23982657471SMarkus Pfeiffer
24082657471SMarkus Pfeiffer /* Register it to daemon too. */
24182657471SMarkus Pfeiffer if (register_to_daemon() < 0) {
24282657471SMarkus Pfeiffer sysv_print_err("register to daemon error\n");
24382657471SMarkus Pfeiffer exit(-1);
24482657471SMarkus Pfeiffer }
24582657471SMarkus Pfeiffer
24682657471SMarkus Pfeiffer /* Inform the daemon about each shared memory segment used. */
24782657471SMarkus Pfeiffer shmchild();
24882657471SMarkus Pfeiffer }
24982657471SMarkus Pfeiffer
25082657471SMarkus Pfeiffer /* The function is called only once, when the process uses for
25182657471SMarkus Pfeiffer * the first time sysv ipc resources.
25282657471SMarkus Pfeiffer */
25382657471SMarkus Pfeiffer int
sysvinit(void)254*ff86f401SSascha Wildner sysvinit(void)
255*ff86f401SSascha Wildner {
25682657471SMarkus Pfeiffer if (is_sysvinit()) {
25782657471SMarkus Pfeiffer return (IPC_INITIALIZED);
25882657471SMarkus Pfeiffer }
25982657471SMarkus Pfeiffer
26082657471SMarkus Pfeiffer if (register_to_daemon() < 0)
26182657471SMarkus Pfeiffer return (-1);
26282657471SMarkus Pfeiffer
26382657471SMarkus Pfeiffer /* Add handlers for parent and child when fork is called. */
26482657471SMarkus Pfeiffer if (_pthread_atfork(prepare_parent_atfork, parent_atfork,
26582657471SMarkus Pfeiffer child_atfork) < 0) {
26682657471SMarkus Pfeiffer sysv_print_err("pthread_atfork error\n");
26782657471SMarkus Pfeiffer return (-1);
26882657471SMarkus Pfeiffer }
26982657471SMarkus Pfeiffer return 0;
27082657471SMarkus Pfeiffer }
27182657471SMarkus Pfeiffer
27282657471SMarkus Pfeiffer int
sysvexit(void)273*ff86f401SSascha Wildner sysvexit(void)
274*ff86f401SSascha Wildner {
27582657471SMarkus Pfeiffer if (!is_sysvinit())
27682657471SMarkus Pfeiffer return (-1);
27782657471SMarkus Pfeiffer
27882657471SMarkus Pfeiffer return (0);
27982657471SMarkus Pfeiffer }
280