From: Markus Pfeiffer Date: Sat, 4 Jan 2014 15:46:52 +0000 (+0000) Subject: Bring in GSoC code: SysV IPC in userspace X-Git-Tag: v3.9.0~865 X-Git-Url: https://gitweb.dragonflybsd.org/~tuxillo/dragonfly.git/commitdiff_plain/8265747159d6085c462f06fcb5dcee70b773f66b Bring in GSoC code: SysV IPC in userspace This commit brings in the code for the GSoC 2013 project "SysV IPC in userspace". This is not extensively tested and probably needs some additional work which Larisa has agreed to do. For bug reports and improvements use the usual channels. To use this functionality, which is built into libc, see the man page for the userspace SysV IPC daemon sysvipcd(8). Contributed-By: Larisa Grigore Squashed commit of the following: commit e552a24765d9a1f3f9b641ddc5aeffe8db563f90 Author: Markus Pfeiffer Date: Fri Nov 15 21:53:53 2013 +0000 Make sysvipcd daemonize and add command line parsing commit 9b280b67f6a8782685f15d72397d9c5eacac1651 Author: Markus Pfeiffer Date: Fri Nov 15 20:01:20 2013 +0000 Add startup script for sysvipcd commit 274f3e79a304f924c339088e6a8b237a41deac8c Author: Larisa Grigore Date: Sun Sep 29 21:01:04 2013 +0300 lib: libc: gen: Makefile.inc: sync with master - fix buildworld commit 384bc109ba1d45f501969e8692102d8f19b112e9 Author: Larisa Grigore Date: Sun Sep 29 20:14:47 2013 +0300 usr.sbin: sysvipcd: adding sysvipc dir in /var/run commit fa75e402636a1d864eb75a8e385a7e73133ae58d Author: Larisa Grigore Date: Sun Sep 29 17:05:20 2013 +0300 libc: Create some *.3 MLINKS for IPC syscall manpages as hint. commit 7d252fc513b983c6f8f192880ef5eda22cc7d971 Author: Larisa Grigore Date: Sun Sep 29 17:04:32 2013 +0300 sysvipcd(8): Add a manual page. commit aae5d173d2d8e6378c867b34112eb1fd89016e3d Author: Larisa Grigore Date: Sun Sep 29 17:03:35 2013 +0300 libc: Add info about the XSI IPC userspace implementation commit 32686d52374b3e7c56d9a7d554dbd82ff71d2927 Author: Larisa Grigore Date: Sun Sep 29 17:02:41 2013 +0300 libc: Move some XSI IPC function manpages to section 2 commit 7fddf14e3c61b7d3dfedaabc4e4f93a1c0774bc7 Author: Larisa Grigore Date: Sun Sep 29 16:57:31 2013 +0300 usr.sbin: sysvipcd: utilsd.h: change SYSV_DIR path commit f382be540a964539a0fcdf03ca79ee2d0b371fc8 Author: Larisa Grigore Date: Sun Sep 29 16:57:00 2013 +0300 usr.sbin: sysvipcd: remove comments commit 00f17c0f7ac690c9fea3d9d9a4ebd939609447ce Author: Larisa Grigore Date: Sun Sep 29 16:55:54 2013 +0300 usr.sbin: sysvipcd: remove garbage out file commit b4d23ac5d8ed6ac44068b5842b776682a395afc0 Author: Larisa Grigore Date: Sun Sep 29 16:55:26 2013 +0300 usr.sbin: sysvipcd: remove man page commit d07861899269d311eb8b089211c6a811a46700c5 Author: Larisa Grigore Date: Sun Sep 29 16:54:08 2013 +0300 lib: libc: sysvipc: sysvipc_sockets.h: change socket place commit f4f68b0f1b46679f68bfb2faeea426bac9605b52 Author: Larisa Grigore Date: Sun Sep 29 16:52:49 2013 +0300 lib: libc: sysvipc: sem.c and msg.c: comments added commit a0b13a0dac3bc1013986d7bc361721b6723494a5 Author: Larisa Grigore Date: Sun Sep 29 16:50:57 2013 +0300 lib: libc: sysvipc: comments out commit 8eb33705b6cd3fcca3ef5e565dd6f97ef9cf201c Author: Larisa Grigore Date: Sun Sep 29 16:50:40 2013 +0300 lib: libc: sys: fork.c: copyright commit 27e9a42148d4d2d46616385b241c12d8a7deaa8b Author: Larisa Grigore Date: Sat Sep 28 16:04:13 2013 +0300 usr.sbin: Makefile: automatically build sysvipcd daemon commit d9124631f55ebd3f6cdda50ecbe86312fc216702 Author: Larisa Grigore Date: Sat Sep 28 15:06:29 2013 +0300 lib: libc: fix *.c files to include namespace.h and use the _* functions commit f06fe8191cf4622f5a830e5d8990ab5ae3cda9b7 Author: Larisa Grigore Date: Sat Sep 28 10:49:53 2013 +0300 usr.sbin: sysvipc: replace include commit 196fc276568b41ab3cb28c29a9d8c5cbbcf32eb0 Author: Larisa Grigore Date: Sat Sep 28 10:48:55 2013 +0300 lib: libc: sysvipc: replace pthread_mutex_lock with _pthread_mutex_lock commit b79f93f104936cccfe4845edb200758935d04efd Author: Larisa Grigore Date: Sat Sep 28 09:47:01 2013 +0300 lib: libc: sysvipc commit a56c5fb4812caef1680761a09ad531ef98b0b956 Author: Larisa Grigore Date: Sat Sep 28 09:44:22 2013 +0300 lib: libc: add new fork wrapper with a simple implementation for pthread_atfork for non-threaded apps commit e6c53467fd2a505ca47e3ed5affc5404c3bf8d7c Author: Larisa Grigore Date: Fri Sep 27 08:30:10 2013 +0300 lib: libc: Makefile: remove lpthread commit 6bea3e3284ce9648ddfe9709eef7be44226f36fb Author: Larisa Grigore Date: Fri Sep 27 08:29:15 2013 +0300 lib: Makefile: remove libsysvipc commit b1e7bbac6d5fe143de3a51ce2cc087f016122030 Author: Larisa Grigore Date: Tue Sep 24 22:11:02 2013 +0300 lib: libc: gen: sysvipc.c: environmental variable commit d49009fd0b306ceb5e4acdd15462ed7149428879 Author: Larisa Grigore Date: Tue Sep 24 21:37:08 2013 +0300 usr.sbin: sysvipcd: syslog added and "-d" option for debug messages commit 3d3c01c05a0b639fd3c65c103ae800ec9c6e7b02 Author: Larisa Grigore Date: Tue Sep 24 21:33:16 2013 +0300 lib: libc: sysvipc: umtx_wakeup before umtx_sleep bug solved commit 25752b0331e3c42f65342f78d7a7cdf97f31845a Author: Larisa Grigore Date: Tue Sep 24 21:32:19 2013 +0300 lib: libc: gen: bug in calling the syscalls solved commit dc4760a590a7593d1fc6154a478c0737c3de4fc4 Author: Larisa Grigore Date: Mon Sep 23 20:12:46 2013 +0300 lib: libc: add sysvipc framework commit 1f07ab3e2017473f8d453f744ef01cb87e889a2a Author: Larisa Grigore Date: Sun Sep 29 17:36:31 2013 +0300 lib: libc: sysvipc: trailing whitespaces commit 1843a7a59eaff1bedc09434ae0e0188f102dc7cc Author: Larisa Grigore Date: Mon Sep 23 19:18:01 2013 +0300 lib: libc: gen: remove msg* sem* shm* commit 0d199c6d71619a7fed728b20bbf79867bbe85df7 Author: Larisa Grigore Date: Mon Sep 23 19:15:49 2013 +0300 lib: remove libsysvipc commit ff22c099080b9f8f992d10cea7489a81327a2bc6 Author: Larisa Grigore Date: Sun Sep 22 17:20:04 2013 +0300 lib: libc: gen: sysvipc userland support commit 92655a0579b7c9fc4559698fcbe3fadd050574d1 Author: Larisa Grigore Date: Sun Sep 22 17:18:04 2013 +0300 lib: libsysvipc: add utils* commit 37e470e38d1cfc9da416e6ce6fc0fc64e9116602 Author: Larisa Grigore Date: Sun Sep 22 17:17:19 2013 +0300 usr.sbin: sysvipcd: refactoring commit 73878a4b3f134b9d00ef52d00c2aae9b22a1f85b Author: Larisa Grigore Date: Sun Sep 22 17:13:12 2013 +0300 sys: sys: headers back to origin commit 383130a64994354c103f38ad3dea79dbfcb07b02 Author: Larisa Grigore Date: Sun Sep 22 17:11:43 2013 +0300 lib: libsysvipc: refactoring commit d6b8b88962999cae2403a73b4e78f4bae6badbc0 Author: Larisa Grigore Date: Wed Sep 18 22:39:06 2013 +0300 usr.sbin: sysvipcd: utils*: refactoring commit fe03ba2c3d939913f59fa94dbd577309ab0afc24 Author: Larisa Grigore Date: Wed Sep 18 22:38:50 2013 +0300 usr.sbin: sysvipcd: sysvipcd.c: refactoring commit 562fb2448b91a7a7027f6bd1521b89ec9e85b1aa Author: Larisa Grigore Date: Wed Sep 18 22:38:17 2013 +0300 usr.sbin: sysvipcd: shm*: mark sems removed commit c0ae00dacdeaf9b8d5743bf4bbc2ef415cee9514 Author: Larisa Grigore Date: Wed Sep 18 22:37:36 2013 +0300 usr.sbin: sysvipcd: perm.c: refactoring commit 14f4aef119d71f41ec117dc36c516275088749df Author: Larisa Grigore Date: Wed Sep 18 22:36:47 2013 +0300 sys: sys: sem.h: temporary modification commit f855ee23ef2721a4f6d0183bb81ff5377fec928a Author: Larisa Grigore Date: Wed Sep 18 22:36:12 2013 +0300 lib: libsysvipc: msg*: refactoring commit b64af81c90c8fa472e56f06003a3dff4cf2a5eea Author: Larisa Grigore Date: Wed Sep 18 22:36:00 2013 +0300 lib: libsysvipc: ipc*: refactoring, release sysv locks only for parent commit 042cc145a42d7c7b3ddcf7180b247083cad1213c Author: Larisa Grigore Date: Wed Sep 18 22:35:14 2013 +0300 lib: libsysvipc: lock*: refactoring commit 7741fd2ae1b6d211d7434e4d457a99290ffc0f26 Author: Larisa Grigore Date: Wed Sep 18 22:33:43 2013 +0300 lib: libsysvipc: hash.c: refactoring commit c96ccc6a952090678adb69084cf407b22da55203 Author: Larisa Grigore Date: Wed Sep 18 22:33:23 2013 +0300 lib: libsysvipc: sockets.c: refactoring commit 7fdafbd1bdc3d16b5adca7611344af8fb3b89a65 Author: Larisa Grigore Date: Wed Sep 18 22:32:12 2013 +0300 lib: libsysvipc: sem.: rw locks, mutex per sem commit 16c307df5ea90fef06a0986185aacb02c77d8348 Author: Larisa Grigore Date: Wed Sep 18 22:30:45 2013 +0300 lib: libsysvipc: shm.*: release lock when error commit 9880617783961487c21a09da1a80723847207965 Author: Larisa Grigore Date: Wed Sep 18 22:30:05 2013 +0300 lib: libsysvipc: lib version updat commit b12c5184c9b752def5f10d1caa308c936311d475 Author: Larisa Grigore Date: Sat Sep 14 23:17:24 2013 +0300 usr: src: usr.sbin: sysvipcd: sysv daemon refactoring commit 078d51106669ce91b336496108f2855845579ef1 Author: Larisa Grigore Date: Sat Sep 14 23:16:42 2013 +0300 usr: src: lib: libsysvipc: : refactoring commit 1e0c06f5eb2bbebad8c7193bc093da2d11d79e6f Author: Larisa Grigore Date: Sat Sep 14 23:15:06 2013 +0300 usr: src: lib: libsysvipc: lock.h: mutex bug solved commit 88bf173f85d400dc61f7ac396434cb8bdfc2ded3 Author: Larisa Grigore Date: Thu Sep 12 11:16:53 2013 +0300 usr.sbin: sysvipcd: adding sysvipc daemon sources commit 717909ce0341baea52ea28261be68e1f3ba3c2ae Author: Larisa Grigore Date: Thu Sep 12 11:15:07 2013 +0300 lib:libsysvipc: remove objects commit 419cfa2fb7ff6a971cf12f74abe97cbdfb710ab7 Author: Larisa Grigore Date: Thu Sep 12 11:07:12 2013 +0300 lib:libsysvipc: add libsysvipc commit c8478bf431a7be470057151a2ba51768b4c030d5 Author: Larisa Grigore Date: Thu Sep 12 11:06:34 2013 +0300 usr.bin:sysvipc_test: remove sysvipc_test directory commit c2814d2af102c7c0399db3708a7640701111d48f Author: Larisa Grigore Date: Thu Sep 12 11:05:14 2013 +0300 sys:sys:shm.h Makefile: add libsysvipc support commit 2745814eca9002a01389e804a624e92062d4ff6d Author: Larisa Grigore Date: Thu Sep 12 11:05:01 2013 +0300 sys:sys:sem.h Makefile: add libsysvipc support commit f58824827b9a470b8fbdcc103cff56c57d89ffa1 Author: Larisa Grigore Date: Thu Sep 12 11:04:46 2013 +0300 sys:sys:msh.h Makefile: add libsysvipc support commit 1f9e0b0c1afb143ef02162386ebae6fb4c5b4121 Author: Larisa Grigore Date: Thu Sep 12 11:04:12 2013 +0300 lib: Makefile: add libsysvipc support commit d38abc72460ce7e348622b57c8c59f4d959d5f3c Author: Larisa Grigore Date: Fri Aug 23 03:26:43 2013 +0300 usr.bin: sysvipc_test: Makefile commit a1cf8d235f2d589872d63c1c02523d5b1464baa6 Author: Larisa Grigore Date: Fri Aug 23 03:26:06 2013 +0300 usr.bin: sysvipc_test: msg: msg support commit ba0959cfcd184def65e081dd2dd5bea593a9b94d Author: Larisa Grigore Date: Fri Aug 23 03:25:44 2013 +0300 usr.bin: sysvipc_test: lock*: sysv inter-process mutex support commit f1c1cee0e2cee6f87502f8b444f2558646538c22 Author: Larisa Grigore Date: Fri Aug 23 03:24:48 2013 +0300 usr.bin: sysvipc_test: tests.c commit a27779d60dcf96e6656ee89b7dbb6a39db3c795b Author: Larisa Grigore Date: Fri Aug 23 03:24:22 2013 +0300 usr.bin: sysvipc_test: sysvipc_daemon: msg support commit c1746abc71466e1da8ac0084f5d5b9fdfe083766 Author: Larisa Grigore Date: Fri Aug 23 03:23:52 2013 +0300 usr.bin: sysvipc_test: shm commit 9ac37102bc939e82b1134967120bf8d95e0a0f37 Author: Larisa Grigore Date: Fri Aug 23 03:23:40 2013 +0300 usr.bin: sysvipc_test: sem commit d892676db05421089b0755b84dd9aa9f8a45ec09 Author: Larisa Grigore Date: Fri Aug 23 03:23:10 2013 +0300 usr.bin: sysvipc_test: ipc: sysv fork bug commit 8da280200ab9dcc54746601fb0b80e6558b8bd02 Author: Larisa Grigore Date: Fri Aug 9 02:13:39 2013 +0300 usr.bin: sysvipc_test: tests.c: some of tested pieces of code commit a31143c6f405070ecc6db6c22cdca9ed2f7833be Author: Larisa Grigore Date: Fri Aug 9 02:13:01 2013 +0300 usr.bin: sysvipc_test: sysvipc_daemon.c: creds, sems and exec bugs commit d7ad12d8e96c30f1c8001e2166bf12f6a2567033 Author: Larisa Grigore Date: Fri Aug 9 02:12:05 2013 +0300 usr.bin: sysvipc_test: sockets.c: creds bug commit 97ca0b18d45dcdc7dafdd8a68308b7632588783c Author: Larisa Grigore Date: Fri Aug 9 02:11:42 2013 +0300 usr.bin: sysvipc_test: shm.c: refactoring commit f65ad9ded26cf70b54fa6de9bfbd23774019db60 Author: Larisa Grigore Date: Fri Aug 9 02:10:47 2013 +0300 usr.bin: sysvipc_test: ipc.c: receive bug commit 2304ecf088c368c34fe2e5fc831d81b7d7e2e165 Author: Larisa Grigore Date: Fri Aug 9 02:10:18 2013 +0300 usr.bin: sysvipc_test: hash commit 8c381a71eff9617079c2ff2e29e03b90519fefc4 Author: Larisa Grigore Date: Fri Aug 9 02:09:55 2013 +0300 usr.bin: sysvipc_test: Makefile commit 90a5084dbcb99b7c977435d1dcef351516e4f321 Author: Larisa Grigore Date: Thu Aug 8 01:02:13 2013 +0300 sys: sys: sysvipc.h commit 734ddf5dd25e2f3e0dff1586a4e1441e75b94cd2 Author: Larisa Grigore Date: Thu Aug 8 01:01:49 2013 +0300 usr.bin: sysvipc_test: ipc: changed connexion mode commit 968ca724490a3bfb32cdcb22bda3672cd7154cbc Author: Larisa Grigore Date: Thu Aug 8 01:01:02 2013 +0300 usr.bin: sysvipc_test: sysvipc_daemon commit 57c058e0141ecd95f51e7609d8f52e082ca2b37f Author: Larisa Grigore Date: Thu Aug 8 00:59:36 2013 +0300 usr.bin: sysvipc_test: hash commit ef28ec01bad43646288bc07678fd44a9ca470693 Author: Larisa Grigore Date: Thu Aug 8 00:59:05 2013 +0300 usr.bin: sysvipc_test: sem commit 0d5ce9d62251fd8f22c8528158e488dc279965ee Author: Larisa Grigore Date: Thu Aug 8 00:58:53 2013 +0300 usr.bin: sysvipc_test: shm commit 33808b5ba77e5593457875ff20e10371a12c8a38 Author: Larisa Grigore Date: Thu Aug 8 00:58:28 2013 +0300 usr.bin: sysvipc_test: sockets commit 33288df49c6c9c5eb3d646c18af5918dceaf4091 Author: Larisa Grigore Date: Thu Aug 8 00:57:56 2013 +0300 usr.bin: sysvipc_test: Makefile commit 32366c91a2f85938a5f0a2eef99bb303450c3e42 Author: Larisa Grigore Date: Thu Jul 25 08:10:04 2013 +0300 usr.bin: sysvipc_test: sem.*: adding support for semaphores commit 284d5bf19ffb13ff42e136522271b8a62d1f8a2d Author: Larisa Grigore Date: Thu Jul 25 08:09:32 2013 +0300 usr.bin: sysvipc_test: sysvipc_test.c: adding support for semaphores commit eed5fa03f02d0fb13ef47e53f40237ba561fdf9a Author: Larisa Grigore Date: Thu Jul 25 08:09:10 2013 +0300 usr.bin: sysvipc_test: shm.c: adding support for semaphores commit 5da2bbe4f06dcf9cff1e1c7ea73e752d9ca173d8 Author: Larisa Grigore Date: Thu Jul 25 08:08:36 2013 +0300 usr.bin: sysvipc_test: shm.h commit a26328fc07be7f2ffab88bf0e120176c046f091a Author: Larisa Grigore Date: Thu Jul 25 08:08:20 2013 +0300 usr.bin: sysvipc_test: ipc.h commit fe61283f6cdc8b6501d925a82fe644b0cfafa07f Author: Larisa Grigore Date: Thu Jul 25 08:08:05 2013 +0300 usr.bin: sysvipc_test: Makefile commit ffe93fa7711bed99b8e1836523f1c1a2371880ce Author: Larisa Grigore Date: Wed Jul 17 07:54:49 2013 +0300 sys: dev: misc: sysvipc: sysvipc.c commit beddc210e14f43fe07cd65922a8c9470113604be Author: Larisa Grigore Date: Wed Jul 17 07:53:29 2013 +0300 usr.bin: sysvipc_test: sysvipc_test.c commit 7aa3db7ee7df8c92daf0c54a6b5d44fc89ddb853 Author: Larisa Grigore Date: Wed Jul 17 07:53:13 2013 +0300 usr.bin: sysvipc_test: shm.c commit 6783c2af4025f96e55f25452327b04ce4d3696d9 Author: Larisa Grigore Date: Wed Jul 17 07:52:49 2013 +0300 usr.bin: sysvipc_test: ipc.h commit f8c8d8cac347249ea29664ebb75b649ac6e2b876 Author: Larisa Grigore Date: Wed Jul 17 07:52:18 2013 +0300 sys: sys: sysvipc.h commit 7d2d3298c5c3b56d1411c017dfac8a65f7b2f86f Author: Larisa Grigore Date: Sun Jul 14 12:02:11 2013 +0300 usr.bin: sysvipc_test: ipc.c ipc.h: sysv init commit c15d376aa5e9e44989dcda67f088dfe440cf0d33 Author: Larisa Grigore Date: Sun Jul 14 12:01:40 2013 +0300 usr.bin: sysvipc_test: hash.c hash.h: generic hash commit 54905f7fe718011e5daa5a6ccef1847e85c1760b Author: Larisa Grigore Date: Sun Jul 14 12:00:52 2013 +0300 usr.bin: sysvipc_test: shm.c shm.h: shm functions commit a225cbb05682f430dac293aa9f8ffbdb8ce39412 Author: Larisa Grigore Date: Sun Jul 14 12:00:21 2013 +0300 usr.bin: sysvipc_test: sysvipc_test: file path commit c33f2b8a6945315750666f00f091864f22595a87 Author: Larisa Grigore Date: Sun Jul 14 11:56:41 2013 +0300 usr.bin: sysvipc_test: sysvipc_test: shm support daemon commit 0cf68cdf24008f1fdd36bcb24a183e3e131accad Author: Larisa Grigore Date: Sun Jul 14 11:56:04 2013 +0300 usr.bin: sysvipc_test: Makefile commit 2b72c84a8aaf49c0bceccfa1e130fc3930281d69 Author: Larisa Grigore Date: Tue Jul 9 10:39:06 2013 +0300 usr.bin: sysvipc_test: sysvipc_test.c: support for shm in userland commit 496a796320b9302e23813f5ab3037f78d8595949 Author: Larisa Grigore Date: Tue Jul 9 10:37:59 2013 +0300 usr.bin: sysvipc_test: Makefile commit ad8ac8d11cf578fa6dee8dd70971c1a7d98205e2 Author: Larisa Grigore Date: Tue Jul 9 10:35:32 2013 +0300 sys: sys: sysvipc.h commit 20568c3163821d63dd295e6bf0d8987730f45999 Author: Larisa Grigore Date: Tue Jul 9 10:35:09 2013 +0300 sys: dev: misc: sysvipc: sysvipc.c: shm support in kernel commit 7d61ab289f8453a3ea76c3a6fefc45ee849497f9 Author: Larisa Grigore Date: Tue Jul 9 10:32:35 2013 +0300 usr.bin: sysvipc_test: ipc.h commit 00f3cfc210b64d1622e886e702a947535026adf8 Author: Larisa Grigore Date: Tue Jul 9 10:32:17 2013 +0300 usr.bin: sysvipc_test: ipc.c: messages between client and daemon commit 320c81549e8da93344beabce3607c1cdf671be85 Author: Larisa Grigore Date: Thu Jul 4 08:55:50 2013 +0300 use hashtable for retriving a client commit d4aca03cd6b936bc7d276a5133825236979544ad Author: Larisa Grigore Date: Thu Jul 4 08:54:52 2013 +0300 sysvipc driver locking commit 929143c10759580145dd3ef3ee3a29974fa75a0d Author: Larisa Grigore Date: Sat Jun 29 08:22:24 2013 +0300 support for multiple clients commit fda122e1cbeadc89ba1f38a54ff2ccb85c0164db Author: Larisa Grigore Date: Fri Jun 28 08:32:01 2013 +0300 remove client commit ed9fa34d503623ad421940ae488d79c1adac095c Author: Larisa Grigore Date: Fri Jun 28 08:01:45 2013 +0300 client data structures commit 4dfd91e02c5c7268fc5f477453d3628737ffa93f Author: Larisa Grigore Date: Fri Jun 28 08:00:34 2013 +0300 detach bug found commit de5b7b9f52d4b525cbcd12b0b3c099e9c0d85a83 Author: Larisa Grigore Date: Thu Jun 27 03:16:47 2013 +0300 usr.bin: sysvipc_test commit e2b5d88e00371291e1abd643d7879510fe557a01 Author: Larisa Grigore Date: Thu Jun 27 03:10:48 2013 +0300 dev: misc: sysvipc commit 2ae258db0b90eb6635a81cc6db5afcdae62bbefd Author: Larisa Grigore Date: Sun Jun 23 16:31:41 2013 +0300 usr.bin: sysvipc_test commit fffeb02bd449e239b75935992ca3fae80f5215d3 Author: Larisa Grigore Date: Sun Jun 23 16:09:56 2013 +0300 sys: sysvipc.h commit fffc5202b843838cd91c75eca1462bb723bea52a Author: Larisa Grigore Date: Fri Jun 21 06:03:16 2013 +0300 sys: dev: misc: add sysvipc driver --- diff --git a/etc/rc.d/Makefile b/etc/rc.d/Makefile index b8fdb0625b..27df6acaf3 100644 --- a/etc/rc.d/Makefile +++ b/etc/rc.d/Makefile @@ -20,7 +20,7 @@ FILES= DAEMON LOGIN NETWORKING SERVERS abi accounting addswap adjkerntz \ dntpd othermta pf pflog powerd ppp ppp-user pppoed pwcheck \ quota random rarpd rcconf resident rndcontrol root route6d routed \ routing rpcbind rtadvd rtsold rwho sysdb savecore sdpd securelevel \ - sendmail sensorsd serial sppp sshd statd swap1 syscons sysctl syslogd \ + sendmail sensorsd serial sppp sshd statd swap1 syscons sysctl syslogd sysvipcd \ timed ttys udevd udevd_early usbd \ varsym vfs_quota vinum virecover vkernel vknetd \ watchdogd wpa_supplicant \ diff --git a/etc/rc.d/sysvipcd b/etc/rc.d/sysvipcd new file mode 100644 index 0000000000..1d12e0b51d --- /dev/null +++ b/etc/rc.d/sysvipcd @@ -0,0 +1,17 @@ +#!/bin/sh +# +# $DragonFly: src/etc/rc.d/sysvipcd,v 1.0 2013/11/15 21:03:32 markusp Exp $ +# + +# PROVIDE: sysvipcd +# REQUIRE: DAEMON +# BEFORE: LOGIN + +. /etc/rc.subr + +name="sysvipcd" +rcvar=`set_rcvar` +command="/usr/sbin/${name}" + +load_rc_config $name +run_rc_command "$1" diff --git a/lib/libc/Makefile.inc b/lib/libc/Makefile.inc index c7d019f972..a8083cbdd0 100644 --- a/lib/libc/Makefile.inc +++ b/lib/libc/Makefile.inc @@ -19,6 +19,7 @@ WARNS=2 .include "${.CURDIR}/../libc/compat-43/Makefile.inc" .include "${.CURDIR}/../libc/gdtoa/Makefile.inc" .include "${.CURDIR}/../libc/gen/Makefile.inc" +.include "${.CURDIR}/../libc/sysvipc/Makefile.inc" .include "${.CURDIR}/../libc/gmon/Makefile.inc" .include "${.CURDIR}/../libc/iconv/Makefile.inc" .include "${.CURDIR}/../libc/locale/Makefile.inc" diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index ff78e9696b..22d029ecf3 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -4,6 +4,8 @@ # machine-independent gen sources .PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/gen ${.CURDIR}/../libc/gen +CFLAGS+=-I${.CURDIR}/../libc/sysvipc + CMAPS+= ${.CURDIR}/gen/Symbol.map SRCS+= _once_stub.c _pthread_stubs.c _rand48.c _spinlock_stub.c \ @@ -21,13 +23,15 @@ SRCS+= _once_stub.c _pthread_stubs.c _rand48.c _spinlock_stub.c \ getusershell.c getvfsbyname.c getvfsent.c glob.c \ initgroups.c isatty.c isinf.c isnan.c \ jrand48.c lcong48.c ldexp.c libc_dlopen.c \ - lockf.c lrand48.c modf.c mrand48.c msgctl.c \ - msgget.c msgrcv.c msgsnd.c nftw.c nice.c \ + lockf.c lrand48.c modf.c mrand48.c sysvipc_msgctl.c \ + sysvipc_msgget.c sysvipc_msgrcv.c sysvipc_msgsnd.c nftw.c nice.c \ nlist.c nrand48.c ntp_gettime.c opendir.c \ pause.c pmadvise.c popen.c posix_spawn.c posixshm.c \ psignal.c pw_scan.c pwcache.c \ raise.c readdir.c readpassphrase.c rewinddir.c \ - scandir.c seed48.c seekdir.c semconfig.c semctl.c semget.c semop.c \ + sysvipc.c sysvipc_shmget.c sysvipc_shmctl.c \ + sysvipc_shmdt.c sysvipc_shmat.c\ + scandir.c seed48.c seekdir.c semconfig.c sysvipc_semctl.c sysvipc_semget.c sysvipc_semop.c \ setdomainname.c sethostname.c setjmperr.c setmode.c setprogname.c \ setproctitle.c \ siginterrupt.c siglist.c signal.c \ @@ -64,7 +68,7 @@ MAN+= alarm.3 arc4random.3 clock.3 \ getttyent.3 getusershell.3 getvfsbyname.3 getvfsent.3 \ glob.3 initgroups.3 \ isgreater.3 \ - ldexp.3 lockf.3 makecontext.3 modf.3 msgctl.3 msgget.3 msgrcv.3 msgsnd.3 \ + ldexp.3 lockf.3 makecontext.3 modf.3 \ nice.3 nlist.3 pause.3 popen.3 posix_spawn.3 \ posix_spawn_file_actions_addopen.3 posix_spawn_file_actions_init.3 \ posix_spawnattr_getflags.3 posix_spawnattr_getpgroup.3 \ diff --git a/lib/libc/gen/Symbol.map b/lib/libc/gen/Symbol.map index 61a76a7226..abc48cf90d 100644 --- a/lib/libc/gen/Symbol.map +++ b/lib/libc/gen/Symbol.map @@ -653,4 +653,5 @@ DFprivate_1.0 { _wait; _waitpid; _warn; + __atfork; }; diff --git a/lib/libc/gen/_pthread_stubs.c b/lib/libc/gen/_pthread_stubs.c index 90a34440ee..a3a0272497 100644 --- a/lib/libc/gen/_pthread_stubs.c +++ b/lib/libc/gen/_pthread_stubs.c @@ -43,8 +43,7 @@ __weak_reference(f, _ ## n); \ __weak_reference(f, n) - -WR(stub_zero, pthread_atfork); +WR(__atfork, pthread_atfork); WR(stub_zero, pthread_attr_destroy); WR(stub_zero, pthread_attr_get_np); WR(stub_zero, pthread_attr_getdetachstate); @@ -239,3 +238,20 @@ _pthread_init(void) { _pthread_init_early(); } + +extern void (*cb_prepare)(void); +extern void (*cb_parent)(void); +extern void (*cb_child)(void); +extern int __isthreaded; + +int +__atfork(void (*prepare)(void), void (*parent)(void), + void (*child)(void)) +{ + if (__isthreaded) + return (-1); + cb_prepare = prepare; + cb_parent = parent; + cb_child = child; + return (0); +} diff --git a/lib/libc/gen/msgctl.3 b/lib/libc/gen/msgctl.3 index 42d60e1584..e69de29bb2 100644 --- a/lib/libc/gen/msgctl.3 +++ b/lib/libc/gen/msgctl.3 @@ -1,215 +0,0 @@ -.\" $NetBSD: msgctl.2,v 1.1 1995/10/16 23:49:15 jtc Exp $ -.\" -.\" Copyright (c) 1995 Frank van der Linden -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed for the NetBSD Project -.\" by Frank van der Linden -.\" 4. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" $FreeBSD: src/lib/libc/gen/msgctl.3,v 1.8.2.7 2003/03/13 18:05:37 trhodes Exp $ -.\" $DragonFly: src/lib/libc/gen/msgctl.3,v 1.3 2006/05/26 19:39:36 swildner Exp $ -.\"/ -.Dd November 24, 1997 -.Dt MSGCTL 3 -.Os -.Sh NAME -.Nm msgctl -.Nd message control operations -.Sh LIBRARY -.Lb libc -.Sh SYNOPSIS -.In sys/types.h -.In sys/ipc.h -.In sys/msg.h -.Ft int -.Fn msgctl "int msqid" "int cmd" "struct msqid_ds *buf" -.Sh DESCRIPTION -The -.Fn msgctl -system call performs some control operations on the message queue specified -by -.Fa msqid . -.Pp -Each message queue has a data structure associated with it, parts of which -may be altered by -.Fn msgctl -and parts of which determine the actions of -.Fn msgctl . -The data structure is defined in -.In sys/msg.h -and contains (amongst others) the following members: -.Bd -literal -struct msqid_ds { - struct ipc_perm msg_perm; /* msg queue permission bits */ - struct msg *msg_first; /* first message in the queue */ - struct msg *msg_last; /* last message in the queue */ - u_long msg_cbytes; /* number of bytes in use on the queue */ - u_long msg_qnum; /* number of msgs in the queue */ - u_long msg_qbytes; /* max # of bytes on the queue */ - pid_t msg_lspid; /* pid of last msgsnd() */ - pid_t msg_lrpid; /* pid of last msgrcv() */ - time_t msg_stime; /* time of last msgsnd() */ - long msg_pad1; - time_t msg_rtime; /* time of last msgrcv() */ - long msg_pad2; - time_t msg_ctime; /* time of last msgctl() */ - long msg_pad3; - long msg_pad4[4]; -}; -.Ed -.Pp -The -.Vt ipc_perm -structure used inside the -.Vt shmid_ds -structure is defined in -.In sys/ipc.h -and looks like this: -.Bd -literal -struct ipc_perm { - ushort cuid; /* creator user id */ - ushort cgid; /* creator group id */ - ushort uid; /* user id */ - ushort gid; /* group id */ - ushort mode; /* r/w permission */ - ushort seq; /* sequence # (to generate unique msg/sem/shm id) */ - key_t key; /* user specified msg/sem/shm key */ -}; -.Ed -.Pp -The operation to be performed by -.Fn msgctl -is specified in -.Fa cmd -and is one of: -.Bl -tag -width IPC_RMIDX -.It Dv IPC_STAT -Gather information about the message queue and place it in the -structure pointed to by -.Fa buf . -.It Dv IPC_SET -Set the value of the -.Va msg_perm.uid , -.Va msg_perm.gid , -.Va msg_perm.mode -and -.Va msg_qbytes -fields in the structure associated with -.Fa msqid . -The values are taken from the corresponding fields in the structure -pointed to by -.Fa buf . -This operation can only be executed by the super-user, or a process that -has an effective user id equal to either -.Va msg_perm.cuid -or -.Va msg_perm.uid -in the data structure associated with the message queue. -The value of -.Va msg_qbytes -can only be increased by the super-user. -Values for -.Va msg_qbytes -that exceed the system limit (MSGMNB from -.In sys/msg.h ) -are silently truncated to that limit. -.It Dv IPC_RMID -Remove the message queue specified by -.Fa msqid -and destroy the data associated with it. -Only the super-user or a process -with an effective uid equal to the -.Va msg_perm.cuid -or -.Va msg_perm.uid -values in the data structure associated with the queue can do this. -.El -.Pp -The permission to read from or write to a message queue (see -.Xr msgsnd 3 -and -.Xr msgrcv 3 ) -is determined by the -.Va msg_perm.mode -field in the same way as is -done with files (see -.Xr chmod 2 ) , -but the effective uid can match either the -.Va msg_perm.cuid -field or the -.Va msg_perm.uid -field, and the -effective gid can match either -.Va msg_perm.cgid -or -.Va msg_perm.gid . -.Sh RETURN VALUES -.Rv -std msgctl -.Sh ERRORS -The -.Fn msgctl -function -will fail if: -.Bl -tag -width Er -.It Bq Er EPERM -The -.Fa cmd -argument -is equal to IPC_SET or IPC_RMID and the caller is not the super-user, nor does -the effective uid match either the -.Va msg_perm.uid -or -.Va msg_perm.cuid -fields of the data structure associated with the message queue. -.Pp -An attempt is made to increase the value of -.Va msg_qbytes -through IPC_SET -but the caller is not the super-user. -.It Bq Er EACCES -The command is IPC_STAT -and the caller has no read permission for this message queue. -.It Bq Er EINVAL -The -.Fa msqid -argument -is not a valid message queue identifier. -.Pp -.Va cmd -is not a valid command. -.It Bq Er EFAULT -The -.Fa buf -argument -specifies an invalid address. -.El -.Sh SEE ALSO -.Xr msgget 3 , -.Xr msgrcv 3 , -.Xr msgsnd 3 -.Sh HISTORY -Message queues appeared in the first release of -.At V . diff --git a/lib/libc/gen/msgctl.c b/lib/libc/gen/msgctl.c deleted file mode 100644 index 8a6269294f..0000000000 --- a/lib/libc/gen/msgctl.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * $DragonFly: src/lib/libc/gen/msgctl.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ - */ - -#include -#include -#include - -int msgctl(int msqid, int cmd, struct msqid_ds *buf) -{ - return (msgsys(0, msqid, cmd, buf)); -} diff --git a/lib/libc/gen/msgget.3 b/lib/libc/gen/msgget.3 index 776c5df1ad..e69de29bb2 100644 --- a/lib/libc/gen/msgget.3 +++ b/lib/libc/gen/msgget.3 @@ -1,142 +0,0 @@ -.\" $NetBSD: msgget.2,v 1.1 1995/10/16 23:49:19 jtc Exp $ -.\" -.\" Copyright (c) 1995 Frank van der Linden -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed for the NetBSD Project -.\" by Frank van der Linden -.\" 4. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" $FreeBSD: src/lib/libc/gen/msgget.3,v 1.7.2.5 2003/03/15 15:11:05 trhodes Exp $ -.\" $DragonFly: src/lib/libc/gen/msgget.3,v 1.2 2003/06/17 04:26:42 dillon Exp $ -.\" -.\"/ -.Dd August 17, 1995 -.Dt MSGGET 3 -.Os -.Sh NAME -.Nm msgget -.Nd get message queue -.Sh LIBRARY -.Lb libc -.Sh SYNOPSIS -.In sys/types.h -.In sys/ipc.h -.In sys/msg.h -.Ft int -.Fn msgget "key_t key" "int msgflg" -.Sh DESCRIPTION -The -.Fn msgget -function -returns the message queue identifier associated with -.Fa key . -A message queue identifier is a unique integer greater than zero. -.Pp -A message queue is created if either -.Fa key -is equal to -.Dv IPC_PRIVATE , -or -.Fa key -does not have a message queue identifier associated with it, and the -.Dv IPC_CREAT -bit is set in -.Fa msgflg . -.Pp -If a new message queue is created, the data structure associated with it (the -.Va msqid_ds -structure, see -.Xr msgctl 3 ) -is initialized as follows: -.Bl -bullet -.It -.Va msg_perm.cuid -and -.Va msg_perm.uid -are set to the effective uid of the calling process. -.It -.Va msg_perm.gid -and -.Va msg_perm.cgid -are set to the effective gid of the calling process. -.It -.Va msg_perm.mode -is set to the lower 9 bits of -.Fa msgflg . -.It -.Va msg_cbytes , -.Va msg_qnum , -.Va msg_lspid , -.Va msg_lrpid , -.Va msg_rtime , -and -.Va msg_stime -are set to 0. -.It -.Va msg_qbytes -is set to the system wide maximum value for the number of bytes in a queue -.Pf ( Dv MSGMNB ) . -.It -.Va msg_ctime -is set to the current time. -.El -.Sh RETURN VALUES -Upon successful completion a positive message queue identifier is returned. -Otherwise, -1 is returned and the global variable -.Va errno -is set to indicate the error. -.Sh ERRORS -.Bl -tag -width Er -.It Bq Er EACCES -A message queue is already associated with -.Fa key -and the caller has no permission to access it. -.It Bq Er EEXIST -Both -.Dv IPC_CREAT -and -.Dv IPC_EXCL -are set in -.Fa msgflg , -and a message queue is already associated with -.Fa key . -.It Bq Er ENOSPC -A new message queue could not be created because the system limit for -the number of message queues has been reached. -.It Bq Er ENOENT -.Dv IPC_CREAT -was not set in -.Fa msgflg -and no message queue associated with -.Fa key -was found. -.El -.Sh SEE ALSO -.Xr msgctl 3 , -.Xr msgrcv 3 , -.Xr msgsnd 3 -.Sh HISTORY -Message queues appeared in the first release of -.At V . diff --git a/lib/libc/gen/msgget.c b/lib/libc/gen/msgget.c deleted file mode 100644 index deb5c36db2..0000000000 --- a/lib/libc/gen/msgget.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ - */ - -#include -#include -#include - -int msgget(key_t key, int msgflg) -{ - return (msgsys(1, key, msgflg)); -} diff --git a/lib/libc/gen/msgrcv.3 b/lib/libc/gen/msgrcv.3 index 92f1f1e33e..e69de29bb2 100644 --- a/lib/libc/gen/msgrcv.3 +++ b/lib/libc/gen/msgrcv.3 @@ -1,233 +0,0 @@ -.\" $NetBSD: msgrcv.2,v 1.1 1995/10/16 23:49:20 jtc Exp $ -.\" -.\" Copyright (c) 1995 Frank van der Linden -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed for the NetBSD Project -.\" by Frank van der Linden -.\" 4. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" $FreeBSD: src/lib/libc/gen/msgrcv.3,v 1.8.2.7 2003/03/15 15:11:05 trhodes Exp $ -.\" $DragonFly: src/lib/libc/gen/msgrcv.3,v 1.4 2006/02/17 19:35:06 swildner Exp $ -.\" -.\"/ -.Dd November 24, 1997 -.Dt MSGRCV 3 -.Os -.Sh NAME -.Nm msgrcv -.Nd receive a message from a message queue -.Sh LIBRARY -.Lb libc -.Sh SYNOPSIS -.In sys/types.h -.In sys/ipc.h -.In sys/msg.h -.Ft int -.Fn msgrcv "int msqid" "void *msgp" "size_t msgsz" "long msgtyp" "int msgflg" -.Sh DESCRIPTION -The -.Fn msgrcv -function receives a message from the message queue specified in -.Fa msqid , -and places it into the structure pointed to by -.Fa msgp . -This structure should consist of the following members: -.Bd -literal - long mtype; /* message type */ - char mtext[1]; /* body of message */ -.Ed -.Pp -.Va mtype -is an integer greater than 0 that can be used for selecting messages, -.Va mtext -is an array of bytes, with a size up to that of the system limit -.Pf ( Dv MSGMAX ) . -.Pp -The value of -.Fa msgtyp -has one of the following meanings: -.Bl -bullet -.It -The -.Fa msgtyp -argument -is greater than 0. The first message of type -.Fa msgtyp -will be received. -.It -The -.Fa msgtyp -argument -is equal to 0. The first message on the queue will be received. -.It -The -.Fa msgtyp -argument -is less than 0. The first message of the lowest message type that is -less than or equal to the absolute value of -.Fa msgtyp -will be received. -.El -.Pp -The -.Fa msgsz -argument -specifies the maximum length of the requested message. -If the received -message has a length greater than -.Fa msgsz -it will be silently truncated if the -.Dv MSG_NOERROR -flag is set in -.Fa msgflg , -otherwise an error will be returned. -.Pp -If no matching message is present on the message queue specified by -.Fa msqid , -the behavior of -.Fn msgrcv -depends on whether the -.Dv IPC_NOWAIT -flag is set in -.Fa msgflg -or not. -If -.Dv IPC_NOWAIT -is set, -.Fn msgrcv -will immediately return a value of -1, and set -.Va errno -to -.Er EAGAIN . -If -.Dv IPC_NOWAIT -is not set, the calling process will be blocked -until: -.Bl -bullet -.It -A message of the requested type becomes available on the message queue. -.It -The message queue is removed, in which case -1 will be returned, and -.Va errno -set to -.Er EINVAL . -.It -A signal is received and caught. -1 is returned, and -.Va errno -set to -.Er EINTR . -.El -.Pp -If a message is successfully received, the data structure associated with -.Fa msqid -is updated as follows: -.Bl -bullet -.It -.Va msg_cbytes -is decremented by the size of the message. -.It -.Va msg_lrpid -is set to the pid of the caller. -.It -.Va msg_lrtime -is set to the current time. -.It -.Va msg_qnum -is decremented by 1. -.El -.Sh RETURN VALUES -Upon successful completion, -.Fn msgrcv -returns the number of bytes received into the -.Va mtext -field of the structure pointed to by -.Fa msgp . -Otherwise, -1 is returned, and -.Va errno -set to indicate the error. -.Sh ERRORS -The -.Fn msgrcv -function -will fail if: -.Bl -tag -width Er -.It Bq Er EINVAL -The -.Fa msqid -argument -is not a valid message queue identifier. -.Pp -The message queue was removed while -.Fn msgrcv -was waiting for a message of the requested type to become available on it. -.Pp -The -.Fa msgsz -argument -is less than 0. -.It Bq Er E2BIG -A matching message was received, but its size was greater than -.Fa msgsz -and the -.Dv MSG_NOERROR -flag was not set in -.Fa msgflg . -.It Bq Er EACCES -The calling process does not have read access to the message queue. -.It Bq Er EFAULT -The -.Fa msgp -argument -points to an invalid address. -.It Bq Er EINTR -The system call was interrupted by the delivery of a signal. -.It Bq Er EAGAIN -There is no message of the requested type available on the message queue, -and -.Dv IPC_NOWAIT -is set in -.Fa msgflg . -.El -.Sh SEE ALSO -.Xr msgctl 3 , -.Xr msgget 3 , -.Xr msgsnd 3 -.Sh HISTORY -Message queues appeared in the first release of -.At V . -.Sh BUGS -.Nx , -.Dx , -and -.Fx -do not define the -.Er EIDRM -error value, which should be used in -the case of a removed message queue, nor the -.Er ENOMSG -value, which -should be used when no suitable message is available and -.Dv IPC_NOWAIT -is set. diff --git a/lib/libc/gen/msgrcv.c b/lib/libc/gen/msgrcv.c deleted file mode 100644 index 2a273fcdbd..0000000000 --- a/lib/libc/gen/msgrcv.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * $DragonFly: src/lib/libc/gen/msgrcv.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ - */ - -#include -#include -#include - -int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) -{ - return (msgsys(3, msqid, msgp, msgsz, msgtyp, msgflg)); -} diff --git a/lib/libc/gen/msgsnd.3 b/lib/libc/gen/msgsnd.3 index 78872ddb0d..e69de29bb2 100644 --- a/lib/libc/gen/msgsnd.3 +++ b/lib/libc/gen/msgsnd.3 @@ -1,169 +0,0 @@ -.\" $NetBSD: msgsnd.2,v 1.1 1995/10/16 23:49:24 jtc Exp $ -.\" -.\" Copyright (c) 1995 Frank van der Linden -.\" All rights reserved. -.\" -.\" Redistribution and use in source and binary forms, with or without -.\" modification, are permitted provided that the following conditions -.\" are met: -.\" 1. Redistributions of source code must retain the above copyright -.\" notice, this list of conditions and the following disclaimer. -.\" 2. Redistributions in binary form must reproduce the above copyright -.\" notice, this list of conditions and the following disclaimer in the -.\" documentation and/or other materials provided with the distribution. -.\" 3. All advertising materials mentioning features or use of this software -.\" must display the following acknowledgement: -.\" This product includes software developed for the NetBSD Project -.\" by Frank van der Linden -.\" 4. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission -.\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES -.\" OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. -.\" IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, -.\" INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT -.\" NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -.\" DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -.\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -.\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF -.\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -.\" -.\" $FreeBSD: src/lib/libc/gen/msgsnd.3,v 1.9.2.5 2001/12/14 18:33:51 ru Exp $ -.\" $DragonFly: src/lib/libc/gen/msgsnd.3,v 1.4 2006/02/17 19:35:06 swildner Exp $ -.\" -.Dd November 24, 1997 -.Dt MSGSND 3 -.Os -.Sh NAME -.Nm msgsnd -.Nd send a message to a message queue -.Sh LIBRARY -.Lb libc -.Sh SYNOPSIS -.In sys/types.h -.In sys/ipc.h -.In sys/msg.h -.Ft int -.Fn msgsnd "int msqid" "void *msgp" "size_t msgsz" "int msgflg" -.Sh DESCRIPTION -The -.Fn msgsnd -function sends a message to the message queue specified in -.Fa msqid . -.Fa msgp -points to a structure containing the message. -This structure should -consist of the following members: -.Bd -literal - long mtype; /* message type */ - char mtext[1]; /* body of message */ -.Ed -.Pp -.Va mtype -is an integer greater than 0 that can be used for selecting messages (see -.Xr msgrcv 3 ) , -.Va mtext -is an array of bytes, with a size up to that of the system limit -.Pf ( Dv MSGMAX ) . -.Pp -If the number of bytes already on the message queue plus -.Fa msgsz -is bigger than the maximum number of bytes on the message queue -.Pf ( Va msg_qbytes , -see -.Xr msgctl 3 ) , -or the number of messages on all queues system-wide is already equal to -the system limit, -.Fa msgflg -determines the action of -.Fn msgsnd . -If -.Fa msgflg -has -.Dv IPC_NOWAIT -mask set in it, the call will return immediately. -If -.Fa msgflg -does not have -.Dv IPC_NOWAIT -set in it, the call will block until: -.Bl -bullet -.It -The condition which caused the call to block does no longer exist. -The message will be sent. -.It -The message queue is removed, in which case -1 will be returned, and -.Va errno -is set to -.Er EINVAL . -.It -The caller catches a signal. -The call returns with -.Va errno -set to -.Er EINTR . -.El -.Pp -After a successful call, the data structure associated with the message -queue is updated in the following way: -.Bl -bullet -.It -.Va msg_cbytes -is incremented by the size of the message. -.It -.Va msg_qnum -is incremented by 1. -.It -.Va msg_lspid -is set to the pid of the calling process. -.It -.Va msg_stime -is set to the current time. -.El -.Sh RETURN VALUES -.Rv -std msgsnd -.Sh ERRORS -.Fn msgsnd -will fail if: -.Bl -tag -width Er -.It Bq Er EINVAL -.Fa msqid -is not a valid message queue identifier -.Pp -The message queue was removed while -.Fn msgsnd -was waiting for a resource to become available in order to deliver the -message. -.Pp -.Fa msgsz -is less than 0, or greater than -.Va msg_qbytes . -.Pp -.Fa mtype -is not greater than 0. -.It Bq Er EACCES -The calling process does not have write access to the message queue. -.It Bq Er EAGAIN -There was no space for this message either on the queue, or in the whole -system, and -.Dv IPC_NOWAIT -was set in -.Fa msgflg . -.It Bq Er EFAULT -.Fa msgp -points to an invalid address. -.It Bq Er EINTR -The system call was interrupted by the delivery of a signal. -.El -.Sh HISTORY -Message queues appeared in the first release of AT&T Unix System V. -.Sh BUGS -.Nx Ns , -.Dx Ns , -and -.Fx -do not define the -.Er EIDRM -error value, which should be used -in the case of a removed message queue. diff --git a/lib/libc/gen/msgsnd.c b/lib/libc/gen/msgsnd.c deleted file mode 100644 index 376976f985..0000000000 --- a/lib/libc/gen/msgsnd.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * $DragonFly: src/lib/libc/gen/msgsnd.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ - */ - -#include -#include -#include - -int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg) -{ - return (msgsys(2, msqid, msgp, msgsz, msgflg)); -} diff --git a/lib/libc/gen/semget.c b/lib/libc/gen/semget.c deleted file mode 100644 index f5271c1a2a..0000000000 --- a/lib/libc/gen/semget.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * $DragonFly: src/lib/libc/gen/semget.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ - */ - -#include -#include -#include - -int semget(key_t key, int nsems, int semflg) -{ - return (semsys(1, key, nsems, semflg)); -} diff --git a/lib/libc/gen/semop.c b/lib/libc/gen/semop.c deleted file mode 100644 index 41ca3ebdb1..0000000000 --- a/lib/libc/gen/semop.c +++ /dev/null @@ -1,12 +0,0 @@ -/* - * $DragonFly: src/lib/libc/gen/semop.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ - */ - -#include -#include -#include - -int semop(int semid, struct sembuf *sops, unsigned nsops) -{ - return (semsys(2, semid, sops, nsops, 0)); -} diff --git a/lib/libc/gen/sysvipc.c b/lib/libc/gen/sysvipc.c new file mode 100644 index 0000000000..f3c19981b3 --- /dev/null +++ b/lib/libc/gen/sysvipc.c @@ -0,0 +1,21 @@ +/* + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include +#include + +static void sysvipc_init(void) __attribute__ ((constructor)); + +char use_userland_impl = 0; + +static void +sysvipc_init(void) { + char *var = getenv("USR_SYSVIPC"); + if (var == NULL) + return; + if(strncmp(var, "1", 1) == 0) + use_userland_impl = 1; +} diff --git a/lib/libc/gen/sysvipc_msgctl.c b/lib/libc/gen/sysvipc_msgctl.c new file mode 100644 index 0000000000..74921c0ec2 --- /dev/null +++ b/lib/libc/gen/sysvipc_msgctl.c @@ -0,0 +1,22 @@ +/* + * $DragonFly: src/lib/libc/gen/msgctl.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_msg.h" + +extern char use_userland_impl; + +extern int __sys_msgctl(int, int, struct msqid_ds *); + +int msgctl(int msqid, int cmd, struct msqid_ds *buf) +{ + if (use_userland_impl) + return (sysvipc_msgctl(msqid, cmd, buf)); + + return (__sys_msgctl(msqid, cmd, buf)); +} diff --git a/lib/libc/gen/sysvipc_msgget.c b/lib/libc/gen/sysvipc_msgget.c new file mode 100644 index 0000000000..3070c09974 --- /dev/null +++ b/lib/libc/gen/sysvipc_msgget.c @@ -0,0 +1,22 @@ +/* + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_msg.h" + +extern char use_userland_impl; + +extern int __sys_msgget(key_t, int); + +int msgget(key_t key, int msgflg) +{ + if (use_userland_impl) + return (sysvipc_msgget(key, msgflg)); + + return (__sys_msgget(key, msgflg)); +} diff --git a/lib/libc/gen/sysvipc_msgrcv.c b/lib/libc/gen/sysvipc_msgrcv.c new file mode 100644 index 0000000000..e828878131 --- /dev/null +++ b/lib/libc/gen/sysvipc_msgrcv.c @@ -0,0 +1,22 @@ +/* + * $DragonFly: src/lib/libc/gen/msgrcv.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_msg.h" + +extern char use_userland_impl; + +extern int __sys_msgrcv(int, void *, size_t, long, int); + +int msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg) +{ + if (use_userland_impl) + return (sysvipc_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg)); + + return (__sys_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg)); +} diff --git a/lib/libc/gen/sysvipc_msgsnd.c b/lib/libc/gen/sysvipc_msgsnd.c new file mode 100644 index 0000000000..e321413e20 --- /dev/null +++ b/lib/libc/gen/sysvipc_msgsnd.c @@ -0,0 +1,22 @@ +/* + * $DragonFly: src/lib/libc/gen/msgsnd.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_msg.h" + +extern char use_userland_impl; + +extern int __sys_msgsnd(int, void *, size_t, int); + +int msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg) +{ + if (use_userland_impl) + return (sysvipc_msgsnd(msqid, msgp, msgsz, msgflg)); + + return (__sys_msgsnd(msqid, msgp, msgsz, msgflg)); +} diff --git a/lib/libc/gen/semctl.c b/lib/libc/gen/sysvipc_semctl.c similarity index 59% rename from lib/libc/gen/semctl.c rename to lib/libc/gen/sysvipc_semctl.c index eb25e30b1f..e9ad9aca27 100644 --- a/lib/libc/gen/semctl.c +++ b/lib/libc/gen/sysvipc_semctl.c @@ -1,4 +1,6 @@ -/* $DragonFly: src/lib/libc/gen/semctl.c,v 1.3 2005/04/26 06:08:42 joerg Exp $ */ +/* $DragonFly: src/lib/libc/gen/semctl.c,v 1.3 2005/04/26 06:08:42 joerg Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ #include #include @@ -6,21 +8,25 @@ #include #include +#include "sysvipc_sem.h" + +extern char use_userland_impl; + int semctl(int semid, int semnum, int cmd, ...) { va_list ap; - union semun semun; - union semun *semun_ptr; + union semun semun = {0}; + union semun *semun_ptr = NULL; va_start(ap, cmd); if (cmd == IPC_SET || cmd == IPC_STAT || cmd == GETALL || cmd == SETVAL || cmd == SETALL) { semun = va_arg(ap, union semun); semun_ptr = &semun; - } else { - semun_ptr = NULL; } va_end(ap); + if (use_userland_impl) + return (sysvipc_semctl(semid, semnum, cmd, semun)); return (semsys(0, semid, semnum, cmd, semun_ptr)); } diff --git a/lib/libc/gen/sysvipc_semget.c b/lib/libc/gen/sysvipc_semget.c new file mode 100644 index 0000000000..f08c6b0991 --- /dev/null +++ b/lib/libc/gen/sysvipc_semget.c @@ -0,0 +1,22 @@ +/* + * $DragonFly: src/lib/libc/gen/semget.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_sem.h" + +extern char use_userland_impl; + +extern int __sys_semget(key_t, int, int); + +int semget(key_t key, int nsems, int semflg) +{ + if (use_userland_impl) + return (sysvipc_semget(key, nsems, semflg)); + + return (__sys_semget(key, nsems, semflg)); +} diff --git a/lib/libc/gen/sysvipc_semop.c b/lib/libc/gen/sysvipc_semop.c new file mode 100644 index 0000000000..1ea64dbace --- /dev/null +++ b/lib/libc/gen/sysvipc_semop.c @@ -0,0 +1,21 @@ +/* + * $DragonFly: src/lib/libc/gen/semop.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_sem.h" + +extern char use_userland_impl; +extern int __sys_semop(int, struct sembuf *, unsigned); + +int semop(int semid, struct sembuf *sops, unsigned nsops) +{ + if (use_userland_impl) { + return (sysvipc_semop(semid, sops, nsops)); + } + return (__sys_semop(semid, sops, nsops)); +} diff --git a/lib/libc/gen/sysvipc_shmat.c b/lib/libc/gen/sysvipc_shmat.c new file mode 100644 index 0000000000..32a20b2dcc --- /dev/null +++ b/lib/libc/gen/sysvipc_shmat.c @@ -0,0 +1,20 @@ +/* + * $DragonFly: src/lib/libc/gen/semget.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_shm.h" + +extern char use_userland_impl; +extern void* __sys_shmat(int, const void *, int); + +void *shmat(int shmid, const void *addr, int flag) +{ + if (use_userland_impl) + return (sysvipc_shmat(shmid, addr, flag)); + return (__sys_shmat(shmid, addr, flag)); +} diff --git a/lib/libc/gen/sysvipc_shmctl.c b/lib/libc/gen/sysvipc_shmctl.c new file mode 100644 index 0000000000..50d059140f --- /dev/null +++ b/lib/libc/gen/sysvipc_shmctl.c @@ -0,0 +1,20 @@ +/* + * $DragonFly: src/lib/libc/gen/semget.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_shm.h" + +extern char use_userland_impl; +extern int __sys_shmctl(int, int, struct shmid_ds *); + +int shmctl(int shmid, int cmd, struct shmid_ds *buf) +{ + if (use_userland_impl) + return (sysvipc_shmctl(shmid, cmd, buf)); + return (__sys_shmctl(shmid, cmd, buf)); +} diff --git a/lib/libc/gen/sysvipc_shmdt.c b/lib/libc/gen/sysvipc_shmdt.c new file mode 100644 index 0000000000..bea80d3871 --- /dev/null +++ b/lib/libc/gen/sysvipc_shmdt.c @@ -0,0 +1,21 @@ +/* + * $DragonFly: src/lib/libc/gen/semget.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_shm.h" + +extern char use_userland_impl; +extern int __sys_shmdt(const void *); + +int shmdt(const void *addr) +{ + if (use_userland_impl) + return (sysvipc_shmdt(addr)); + + return (__sys_shmdt(addr)); +} diff --git a/lib/libc/gen/sysvipc_shmget.c b/lib/libc/gen/sysvipc_shmget.c new file mode 100644 index 0000000000..76264becbe --- /dev/null +++ b/lib/libc/gen/sysvipc_shmget.c @@ -0,0 +1,21 @@ +/* + * $DragonFly: src/lib/libc/gen/semget.c,v 1.2 2005/11/13 00:07:42 swildner Exp $ + * $DragonFly: src/lib/libc/gen/msgget.c,v 1.2 2013/09/24 21:37:00 Lrisa Grigore Exp $ + */ + +#include +#include +#include + +#include "sysvipc_shm.h" + +extern char use_userland_impl; + +extern int __sys_shmget(key_t, size_t, int); + +int shmget(key_t key, size_t size, int shmflg) +{ + if (use_userland_impl) + return (sysvipc_shmget(key, size, shmflg)); + return (__sys_shmget(key, size, shmflg)); +} diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 7e2e4eb8f9..be0c12fdf4 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -17,6 +17,8 @@ CMAPS+= ${.CURDIR}/sys/Symbol.map # .include "${.CURDIR}/../libc/${MACHINE_ARCH}/sys/Makefile.inc" +SRCS+= fork.c + # Sources common to both syscall interfaces: SRCS+= ftruncate.c lseek.c mmap.c truncate.c SRCS+= pread.c pwrite.c preadv.c pwritev.c @@ -76,7 +78,9 @@ MAN+= _exit.2 accept.2 access.2 acct.2 adjtime.2 \ madvise.2 mincore.2 minherit.2 mkdir.2 mkfifo.2 mknod.2 mlock.2 \ mlockall.2 mmap.2 \ modfind.2 modnext.2 modstat.2 \ - mount.2 mountctl.2 mprotect.2 msync.2 munmap.2 nanosleep.2 \ + mount.2 mountctl.2 mprotect.2 \ + msgctl.2 msgget.2 msgrcv.2 msgsnd.3 \ + msync.2 munmap.2 nanosleep.2 \ nfssvc.2 ntp_adjtime.2 ntp_gettime.2 \ open.2 pathconf.2 pipe.2 poll.2 profil.2 pselect.2 ptrace.2 quotactl.2 \ read.2 readlink.2 reboot.2 recv.2 rename.2 revoke.2 rfork.2 rmdir.2 \ @@ -140,6 +144,10 @@ MLINKS+=mlock.2 munlock.2 MLINKS+=mlockall.2 munlockall.2 MLINKS+=modnext.2 modfnext.2 MLINKS+=mount.2 unmount.2 +MLINKS+=msgctl.2 msgctl.3 +MLINKS+=msgget.2 msgget.3 +MLINKS+=msgrcv.2 msgrcv.3 +MLINKS+=msgsnd.2 msgsnd.3 MLINKS+=open.2 openat.2 MLINKS+=pathconf.2 fpathconf.2 pathconf.2 lpathconf.2 MLINKS+=read.2 pread.2 read.2 preadv.2 read.2 readv.2 @@ -157,11 +165,17 @@ MLINKS+=select.2 FD_CLR.2 \ select.2 FD_ISSET.2 \ select.2 FD_SET.2 \ select.2 FD_ZERO.2 +MLINKS+=semctl.2 semctl.3 +MLINKS+=semget.2 semget.3 +MLINKS+=semop.2 semop.3 MLINKS+=send.2 sendmsg.2 send.2 sendto.2 MLINKS+=setpgid.2 setpgrp.2 MLINKS+=setresuid.2 getresgid.2 setresuid.2 getresuid.2 setresuid.2 setresgid.2 MLINKS+=setuid.2 setegid.2 setuid.2 seteuid.2 setuid.2 setgid.2 -MLINKS+=shmat.2 shmdt.2 +MLINKS+=shmat.2 shmat.3 \ + shmat.2 shmdt.2 +MLINKS+=shmctl.2 shmctl.3 +MLINKS+=shmget.2 shmget.3 MLINKS+=stat.2 fstat.2 stat.2 fstatat.2 stat.2 lstat.2 MLINKS+=statfs.2 fstatfs.2 MLINKS+=statvfs.2 fstatvfs.2 diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index 7de749a081..4ecd4c2fb6 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -864,4 +864,5 @@ DFprivate_1.0 { _wait4; _write; _writev; + __fork; }; diff --git a/lib/libc/sys/fork.c b/lib/libc/sys/fork.c new file mode 100644 index 0000000000..a03c953ca7 --- /dev/null +++ b/lib/libc/sys/fork.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2013 Larisa Grigore + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Glass and Charles + * Hannum. + * 4. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include + +void (*cb_prepare)(void) = 0; +void (*cb_parent)(void) = 0; +void (*cb_child)(void) = 0; + +int +__fork() +{ + int ret; + + if (cb_prepare) + cb_prepare(); + + if ((ret = __syscall(SYS_fork)) == 0) { + if (cb_child) + cb_child(); + } else { + if (cb_parent) + cb_parent(); + } + return (ret); +} +__weak_reference(__fork, fork); diff --git a/lib/libc/gen/msgctl.3 b/lib/libc/sys/msgctl.2 similarity index 91% copy from lib/libc/gen/msgctl.3 copy to lib/libc/sys/msgctl.2 index 42d60e1584..42262db9b1 100644 --- a/lib/libc/gen/msgctl.3 +++ b/lib/libc/sys/msgctl.2 @@ -30,10 +30,9 @@ .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD: src/lib/libc/gen/msgctl.3,v 1.8.2.7 2003/03/13 18:05:37 trhodes Exp $ -.\" $DragonFly: src/lib/libc/gen/msgctl.3,v 1.3 2006/05/26 19:39:36 swildner Exp $ -.\"/ -.Dd November 24, 1997 -.Dt MSGCTL 3 +.\" +.Dd September 28, 2013 +.Dt MSGCTL 2 .Os .Sh NAME .Nm msgctl @@ -149,9 +148,9 @@ values in the data structure associated with the queue can do this. .El .Pp The permission to read from or write to a message queue (see -.Xr msgsnd 3 +.Xr msgsnd 2 and -.Xr msgrcv 3 ) +.Xr msgrcv 2 ) is determined by the .Va msg_perm.mode field in the same way as is @@ -168,11 +167,21 @@ or .Va msg_perm.gid . .Sh RETURN VALUES .Rv -std msgctl +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS The .Fn msgctl -function -will fail if: +system call will fail if: .Bl -tag -width Er .It Bq Er EPERM The @@ -207,9 +216,17 @@ argument specifies an invalid address. .El .Sh SEE ALSO -.Xr msgget 3 , -.Xr msgrcv 3 , -.Xr msgsnd 3 +.Xr msgget 2 , +.Xr msgrcv 2 , +.Xr msgsnd 2 .Sh HISTORY Message queues appeared in the first release of .At V . +.Sh AUTHORS +.An -nosplit +The +.Dx +specific userspace implementation (see +.Sx ENVIRONMENT ) +was written by +.An Larisa Grigore . diff --git a/lib/libc/gen/msgget.3 b/lib/libc/sys/msgget.2 similarity index 87% copy from lib/libc/gen/msgget.3 copy to lib/libc/sys/msgget.2 index 776c5df1ad..d5f5058213 100644 --- a/lib/libc/gen/msgget.3 +++ b/lib/libc/sys/msgget.2 @@ -28,12 +28,11 @@ .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" .\" $FreeBSD: src/lib/libc/gen/msgget.3,v 1.7.2.5 2003/03/15 15:11:05 trhodes Exp $ -.\" $DragonFly: src/lib/libc/gen/msgget.3,v 1.2 2003/06/17 04:26:42 dillon Exp $ .\" -.\"/ -.Dd August 17, 1995 -.Dt MSGGET 3 +.Dd September 28, 2013 +.Dt MSGGET 2 .Os .Sh NAME .Nm msgget @@ -49,7 +48,7 @@ .Sh DESCRIPTION The .Fn msgget -function +system call returns the message queue identifier associated with .Fa key . A message queue identifier is a unique integer greater than zero. @@ -68,7 +67,7 @@ bit is set in If a new message queue is created, the data structure associated with it (the .Va msqid_ds structure, see -.Xr msgctl 3 ) +.Xr msgctl 2 ) is initialized as follows: .Bl -bullet .It @@ -107,6 +106,17 @@ Upon successful completion a positive message queue identifier is returned. Otherwise, -1 is returned and the global variable .Va errno is set to indicate the error. +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS .Bl -tag -width Er .It Bq Er EACCES @@ -134,9 +144,17 @@ and no message queue associated with was found. .El .Sh SEE ALSO -.Xr msgctl 3 , -.Xr msgrcv 3 , -.Xr msgsnd 3 +.Xr msgctl 2 , +.Xr msgrcv 2 , +.Xr msgsnd 2 .Sh HISTORY Message queues appeared in the first release of .At V . +.Sh AUTHORS +.An -nosplit +The +.Dx +specific userspace implementation (see +.Sx ENVIRONMENT ) +was written by +.An Larisa Grigore . diff --git a/lib/libc/gen/msgrcv.3 b/lib/libc/sys/msgrcv.2 similarity index 89% copy from lib/libc/gen/msgrcv.3 copy to lib/libc/sys/msgrcv.2 index 92f1f1e33e..7f3438667a 100644 --- a/lib/libc/gen/msgrcv.3 +++ b/lib/libc/sys/msgrcv.2 @@ -28,12 +28,11 @@ .\" THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +.\" .\" $FreeBSD: src/lib/libc/gen/msgrcv.3,v 1.8.2.7 2003/03/15 15:11:05 trhodes Exp $ -.\" $DragonFly: src/lib/libc/gen/msgrcv.3,v 1.4 2006/02/17 19:35:06 swildner Exp $ .\" -.\"/ -.Dd November 24, 1997 -.Dt MSGRCV 3 +.Dd September 28, 2013 +.Dt MSGRCV 2 .Os .Sh NAME .Nm msgrcv @@ -49,7 +48,7 @@ .Sh DESCRIPTION The .Fn msgrcv -function receives a message from the message queue specified in +system call receives a message from the message queue specified in .Fa msqid , and places it into the structure pointed to by .Fa msgp . @@ -167,11 +166,21 @@ field of the structure pointed to by Otherwise, -1 is returned, and .Va errno set to indicate the error. +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS The .Fn msgrcv -function -will fail if: +system call will fail if: .Bl -tag -width Er .It Bq Er EINVAL The @@ -211,12 +220,20 @@ is set in .Fa msgflg . .El .Sh SEE ALSO -.Xr msgctl 3 , -.Xr msgget 3 , -.Xr msgsnd 3 +.Xr msgctl 2 , +.Xr msgget 2 , +.Xr msgsnd 2 .Sh HISTORY Message queues appeared in the first release of .At V . +.Sh AUTHORS +.An -nosplit +The +.Dx +specific userspace implementation (see +.Sx ENVIRONMENT ) +was written by +.An Larisa Grigore . .Sh BUGS .Nx , .Dx , diff --git a/lib/libc/gen/msgsnd.3 b/lib/libc/sys/msgsnd.2 similarity index 88% copy from lib/libc/gen/msgsnd.3 copy to lib/libc/sys/msgsnd.2 index 78872ddb0d..bfad3d18f5 100644 --- a/lib/libc/gen/msgsnd.3 +++ b/lib/libc/sys/msgsnd.2 @@ -30,10 +30,9 @@ .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD: src/lib/libc/gen/msgsnd.3,v 1.9.2.5 2001/12/14 18:33:51 ru Exp $ -.\" $DragonFly: src/lib/libc/gen/msgsnd.3,v 1.4 2006/02/17 19:35:06 swildner Exp $ .\" -.Dd November 24, 1997 -.Dt MSGSND 3 +.Dd September 28, 2013 +.Dt MSGSND 2 .Os .Sh NAME .Nm msgsnd @@ -49,7 +48,7 @@ .Sh DESCRIPTION The .Fn msgsnd -function sends a message to the message queue specified in +system call sends a message to the message queue specified in .Fa msqid . .Fa msgp points to a structure containing the message. @@ -62,7 +61,7 @@ consist of the following members: .Pp .Va mtype is an integer greater than 0 that can be used for selecting messages (see -.Xr msgrcv 3 ) , +.Xr msgrcv 2 ) , .Va mtext is an array of bytes, with a size up to that of the system limit .Pf ( Dv MSGMAX ) . @@ -72,7 +71,7 @@ If the number of bytes already on the message queue plus is bigger than the maximum number of bytes on the message queue .Pf ( Va msg_qbytes , see -.Xr msgctl 3 ) , +.Xr msgctl 2 ) , or the number of messages on all queues system-wide is already equal to the system limit, .Fa msgflg @@ -123,6 +122,17 @@ is set to the current time. .El .Sh RETURN VALUES .Rv -std msgsnd +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS .Fn msgsnd will fail if: @@ -158,6 +168,14 @@ The system call was interrupted by the delivery of a signal. .El .Sh HISTORY Message queues appeared in the first release of AT&T Unix System V. +.Sh AUTHORS +.An -nosplit +The +.Dx +specific userspace implementation (see +.Sx ENVIRONMENT ) +was written by +.An Larisa Grigore . .Sh BUGS .Nx Ns , .Dx Ns , diff --git a/lib/libc/sys/semctl.2 b/lib/libc/sys/semctl.2 index 966624421a..b61124a117 100644 --- a/lib/libc/sys/semctl.2 +++ b/lib/libc/sys/semctl.2 @@ -24,9 +24,8 @@ .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD: src/lib/libc/sys/semctl.2,v 1.9.2.6 2002/03/11 08:37:47 maxim Exp $ -.\" $DragonFly: src/lib/libc/sys/semctl.2,v 1.2 2003/06/17 04:26:47 dillon Exp $ .\" -.Dd September 12, 1995 +.Dd September 28, 2013 .Dt SEMCTL 2 .Os .Sh NAME @@ -162,6 +161,17 @@ returns the corresponding value; otherwise, 0 is returned. On failure, -1 is returned, and .Va errno is set to indicate the error. +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS .Fn Semctl will fail if: @@ -182,3 +192,11 @@ semaphore set. .Sh SEE ALSO .Xr semget 2 , .Xr semop 2 +.Sh AUTHORS +.An -nosplit +The +.Dx +specific userspace implementation (see +.Sx ENVIRONMENT ) +was written by +.An Larisa Grigore . diff --git a/lib/libc/sys/semget.2 b/lib/libc/sys/semget.2 index 276f7f1869..0de5e7b30a 100644 --- a/lib/libc/sys/semget.2 +++ b/lib/libc/sys/semget.2 @@ -24,9 +24,8 @@ .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" .\" $FreeBSD: src/lib/libc/sys/semget.2,v 1.7.2.5 2001/12/14 18:34:01 ru Exp $ -.\" $DragonFly: src/lib/libc/sys/semget.2,v 1.2 2003/06/17 04:26:47 dillon Exp $ .\" -.Dd September 12, 1995 +.Dd September 28, 2013 .Dt SEMGET 2 .Os .Sh NAME @@ -107,6 +106,17 @@ returns the id of a semaphore set if successful; otherwise, -1 is returned and .Va errno is set to indicate the error. +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS .Fn Semget will fail if: diff --git a/lib/libc/sys/semop.2 b/lib/libc/sys/semop.2 index 5755913dae..cf533643d6 100644 --- a/lib/libc/sys/semop.2 +++ b/lib/libc/sys/semop.2 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD: src/lib/libc/sys/semop.2,v 1.7.2.6 2001/12/14 18:34:01 ru Exp $ .\" -.Dd September 22, 1995 +.Dd September 28, 2013 .Dt SEMOP 2 .Os .Sh NAME @@ -163,6 +163,17 @@ be used to insure that a resource is released if a process terminates unexpectedly. .Sh RETURN VALUES .Rv -std semop +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS .Fn Semop will fail if: @@ -190,3 +201,11 @@ was not in the range of valid semaphores for the set. .Sh SEE ALSO .Xr semctl 2 , .Xr semget 2 +.Sh AUTHORS +.An -nosplit +The +.Dx +specific userspace implementation (see +.Sx ENVIRONMENT ) +was written by +.An Larisa Grigore . diff --git a/lib/libc/sys/shmat.2 b/lib/libc/sys/shmat.2 index b6b9dd551a..bb4e784fa9 100644 --- a/lib/libc/sys/shmat.2 +++ b/lib/libc/sys/shmat.2 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD: src/lib/libc/sys/shmat.2,v 1.8.2.6 2001/12/14 18:34:01 ru Exp $ .\" -.Dd October 29, 2011 +.Dd September 28, 2013 .Dt SHMAT 2 .Os .Sh NAME @@ -86,6 +86,17 @@ is returned and is set to indicate the error. .Pp .Rv -std shmdt +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS .Fn Shmat will fail if: @@ -108,3 +119,11 @@ does not point to a shared memory segment. .Sh "SEE ALSO" .Xr shmctl 2 , .Xr shmget 2 +.Sh AUTHORS +.An -nosplit +The +.Dx +specific userspace implementation (see +.Sx ENVIRONMENT ) +was written by +.An Larisa Grigore . diff --git a/lib/libc/sys/shmctl.2 b/lib/libc/sys/shmctl.2 index b251acc627..227b84b593 100644 --- a/lib/libc/sys/shmctl.2 +++ b/lib/libc/sys/shmctl.2 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD: src/lib/libc/sys/shmctl.2,v 1.9.2.4 2001/12/14 18:34:01 ru Exp $ .\" -.Dd October 29, 2011 +.Dd September 28, 2013 .Dt SHMCTL 2 .Os .Sh NAME @@ -112,6 +112,17 @@ struct shmid_ds { .Ed .Sh RETURN VALUES .Rv -std shmctl +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS .Fn Shmctl will fail if: @@ -136,3 +147,11 @@ shared memory segment. .Xr shmdt 2 , .Xr shmget 2 , .Xr ftok 3 +.Sh AUTHORS +.An -nosplit +The +.Dx +specific userspace implementation (see +.Sx ENVIRONMENT ) +was written by +.An Larisa Grigore . diff --git a/lib/libc/sys/shmget.2 b/lib/libc/sys/shmget.2 index ee89b26bb4..588311967a 100644 --- a/lib/libc/sys/shmget.2 +++ b/lib/libc/sys/shmget.2 @@ -25,7 +25,7 @@ .\" .\" $FreeBSD: src/lib/libc/sys/shmget.2,v 1.8.2.6 2001/12/14 18:34:01 ru Exp $ .\" -.Dd October 29, 2011 +.Dd September 28, 2013 .Dt SHMGET 2 .Os .Sh NAME @@ -110,6 +110,17 @@ returns the positive integer identifier of a shared memory segment. Otherwise, -1 is returned and .Va errno set to indicate the error. +.Sh ENVIRONMENT +The XSI Interprocess Communication family of functions is also available +as an implementation in userspace. +To use it, the +.Xr sysvipcd 8 +daemon has to be running. +.Pp +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation. .Sh ERRORS .Fn Shmget will fail if: @@ -139,3 +150,11 @@ already exists. .Xr shmctl 2 , .Xr shmdt 2 , .Xr ftok 3 +.Sh AUTHORS +.An -nosplit +The +.Dx +specific userspace implementation (see +.Sx ENVIRONMENT ) +was written by +.An Larisa Grigore . diff --git a/lib/libc/sysvipc/Makefile.inc b/lib/libc/sysvipc/Makefile.inc new file mode 100644 index 0000000000..2115b8d210 --- /dev/null +++ b/lib/libc/sysvipc/Makefile.inc @@ -0,0 +1,4 @@ +.PATH: ${.CURDIR}/../libc/${MACHINE_ARCH}/sysvipc ${.CURDIR}/../libc/sysvipc + +CMAPS+= ${.CURDIR}/sysvipc/Symbol.map +SRCS+= lock.c lock_generic.c sysvipc_hash.c ipc.c shm.c msg.c sem.c sockets.c utils.c diff --git a/lib/libc/sysvipc/ipc.c b/lib/libc/sysvipc/ipc.c new file mode 100644 index 0000000000..3b1285bc79 --- /dev/null +++ b/lib/libc/sysvipc/ipc.c @@ -0,0 +1,267 @@ +/** + * Copyright (c) 2013 Larisa Grigore. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +#include + +#include "sysvipc_ipc.h" +#include "sysvipc_sockets.h" +#include "sysvipc_sem.h" +#include "sysvipc_shm.h" +#include "sysvipc_hash.h" +#include "sysvipc_lock.h" +#include "sysvipc_lock_generic.h" + +#define SYSV_MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) +#define SYSV_MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) +#define SYSV_MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x) + +int daemon_fd = -1; + +extern pthread_mutex_t lock_resources; +//extern pthread_rwlock_t rwlock_addrs; +extern pthread_mutex_t lock_undo; +extern struct hashtable *shmaddrs; + +/* Send the type of the message followed by data. */ +int +send_message(int fd, int type, char *data, int size) { + _write(fd, &type, sizeof(type)); + return (send_msg_with_cred(fd, data, size)); +} + +/* Receive the type of the message that will follow. */ +int +receive_type_message(int fd) { + int type; + int r = _read(fd, &type, sizeof(type)); + return (r == 0 ? 0 : type); +} + +/* Receive data. */ +int +receive_message(int fd, char *data, int size) { + _read(fd, data, size); + return (0); +} + +int +is_sysvinit(void) { + return (daemon_fd == -1 ? 0:1); +} + +static int +register_to_daemon(void) { + int flags; + char test = 't'; + + daemon_fd = connect_to_daemon(LISTEN_SOCKET_FILE); + + flags = _fcntl(daemon_fd, F_GETFD, 0); + if (_fcntl(daemon_fd, F_SETFD, flags & FD_CLOEXEC) == -1) { + sysv_print_err("fcntl error\n"); + return (-1); + } + + /* Send a message such that daemon can obtain process credentials.*/ + send_msg_with_cred(daemon_fd, &test, sizeof(test)); + + sysv_print("register to daemon: sock fd = %d\n", daemon_fd); + + return (0); +} + +/* Used in fork case, to avoid deadlocks. + * The fork caller acquires all locks before fork and release them + * after because the child will have only a thread. If one lock is + * taken by another thread than, in the child process, nobody will + * release it. + */ +static void +acquire_locks(void) { + struct entries_list *list; + struct hashentry *tmp; + struct shm_data *data; + struct semid_pool *semaptr; + int i; + + SYSV_MUTEX_LOCK(&lock_undo); + SYSV_MUTEX_LOCK(&lock_resources); + //pthread_rwlock_wrlock(&rwlock_addrs); + + for (i=0; ientries[i]; + if (LIST_EMPTY(list)) + continue; + LIST_FOREACH(tmp, list, entry_link) { + data = (struct shm_data*)tmp->value; + if (data->type == SEMGET) { + semaptr = (struct semid_pool *)data->internal; +#ifdef SYSV_RWLOCK +#ifdef SYSV_SEMS + /* There is no need to acquire the mutexes from + * each semaphore in the group. It is enough + * to acquire the group lock in write mode. + */ +#endif + sysv_rwlock_wrlock(&semaptr->rwlock); +#else + sysv_mutex_lock(&semaptr->mutex); +#endif + } + } + } +} + +/* Function called by parent after fork to release locks + * acquired before fork. + */ +static void +parent_release_locks(void) { + struct entries_list *list; + struct hashentry *tmp; + struct shm_data *data; + struct semid_pool *semaptr; + int i; + + SYSV_MUTEX_UNLOCK(&lock_undo); + SYSV_MUTEX_UNLOCK(&lock_resources); + //pthread_rwlock_unlock(&rwlock_addrs); + + for (i=0; ientries[i]; + if (LIST_EMPTY(list)) + continue; + LIST_FOREACH(tmp, list, entry_link) { + data = (struct shm_data*)tmp->value; + if (data->type == SEMGET) { + semaptr = (struct semid_pool *)data->internal; +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&semaptr->rwlock); +#else + sysv_mutex_unlock(&semaptr->mutex); +#endif + } + } + } +} + +/* Function called by child after fork to release locks + * acquired before fork by the parent. + * Only locks specific to the address space are released. + * Those created in the shared memory are released by the + * parent. + */ +static void +child_release_locks(void) { + SYSV_MUTEX_UNLOCK(&lock_undo); + SYSV_MUTEX_UNLOCK(&lock_resources); + //pthread_rwlock_unlock(&rwlock_addrs); +} + +static void +prepare_parent_atfork(void) { + /* Function called only if the process has + * sysv ipc structures initialized. + */ + if (!is_sysvinit()) + return; + + /* Acquire all locks to be sure that neither one is + * held by another thread. + */ + acquire_locks(); +} + +static void +parent_atfork(void) { + if (!is_sysvinit()) + return; + + /* Release locks acquired before fork. */ + parent_release_locks(); +} + +static void +child_atfork(void) { + if (!is_sysvinit()) + return; + + /* Release locks acquired before fork. */ + child_release_locks(); + /* Close the file descriptor used by parent. */ + _close(daemon_fd); + + /* Register it to daemon too. */ + if (register_to_daemon() < 0) { + sysv_print_err("register to daemon error\n"); + exit(-1); + } + + /* Inform the daemon about each shared memory segment used. */ + shmchild(); +} + +/* The function is called only once, when the process uses for + * the first time sysv ipc resources. + */ +int +sysvinit(void) { + + if (is_sysvinit()) { + return (IPC_INITIALIZED); + } + + if (register_to_daemon() < 0) + return (-1); + + /* Add handlers for parent and child when fork is called. */ + if (_pthread_atfork(prepare_parent_atfork, parent_atfork, + child_atfork) < 0) { + sysv_print_err("pthread_atfork error\n"); + return (-1); + } + return 0; +} + +int +sysvexit(void) { + if (!is_sysvinit()) + return (-1); + + return (0); +} diff --git a/lib/libc/sysvipc/lock.c b/lib/libc/sysvipc/lock.c new file mode 100644 index 0000000000..8aba756cb8 --- /dev/null +++ b/lib/libc/sysvipc/lock.c @@ -0,0 +1,262 @@ +/* + * Copyright (c) 1995 John Birrell . + * Copyright (c) 1998 Alex Nash + * Copyright (c) 2006 David Xu . + * Copyright (c) 2013 Larisa Grigore . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by John Birrell. + * 4. Neither the name of the author nor the names of any co-contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_mutex.c,v 1.15 2008/05/09 16:03:27 dillon Exp $ + * $FreeBSD: src/lib/libpthread/thread/thr_rwlock.c,v 1.14 2004/01/08 15:37:09 deischen Exp $ + * $DragonFly: src/lib/libthread_xu/thread/thr_rwlock.c,v 1.7 2006/04/06 13:03:09 davidxu Exp $ + */ + +#include +#include +#include + +#include "sysvipc_utils.h" +#include "sysvipc_lock.h" +#include "sysvipc_lock_generic.h" + +#include +#include +#include + +#define MAX_READ_LOCKS (INT_MAX - 1) + +static int rdlock_count; + +int +sysv_mutex_init(struct sysv_mutex *mutex) { + if(mutex == NULL) + return (EINVAL); + mutex->_mutex_static_lock = 0; + mutex->pid_owner = -1; + mutex->tid_owner = -1; + return (0); +} + +int +sysv_mutex_lock(struct sysv_mutex *mutex) +{ + if (mutex->pid_owner == getpid() && + mutex->tid_owner == lwp_gettid()) { + sysv_print_err("deadlock: mutex aleady acquired by the thread\n"); + return (EDEADLK); + } + _sysv_umtx_lock(&mutex->_mutex_static_lock); + mutex->pid_owner = getpid(); + mutex->tid_owner = lwp_gettid(); + return (0); +} + +int +sysv_mutex_unlock(struct sysv_mutex *mutex) +{ + if (mutex->pid_owner != getpid() || + mutex->tid_owner != lwp_gettid()) { + sysv_print_err("eperm try unlock a mutex that is not acquired\n"); + return (EPERM); + } + + mutex->tid_owner = -1; + mutex->pid_owner = -1; + _sysv_umtx_unlock(&mutex->_mutex_static_lock); + return (0); +} + +static int +sysv_cond_wait(int *val, struct sysv_mutex *mutex) { + sysv_mutex_unlock(mutex); + + /* I use SYSV_TIMEOUT to avoid lossing a wakeup + * sent before going to sleep and remain blocked. + */ + umtx_sleep(val, *val, SYSV_TIMEOUT); + return (sysv_mutex_lock(mutex)); +} + +static int +sysv_cond_signal(int *val) { + return (umtx_wakeup(val, 0)); +} + +int +sysv_rwlock_init(struct sysv_rwlock *rwlock) +{ + int ret; + + if (rwlock == NULL) + return (EINVAL); + + /* Initialize the lock. */ + sysv_mutex_init(&rwlock->lock); + rwlock->state = 0; + rwlock->blocked_writers = 0; + + return (ret); +} + +int +sysv_rwlock_unlock (struct sysv_rwlock *rwlock) +{ + int ret; + + if (rwlock == NULL) + return (EINVAL); + + /* Grab the monitor lock. */ + if ((ret = sysv_mutex_lock(&rwlock->lock)) != 0) + return (ret); + + if (rwlock->state > 0) { + rdlock_count--; + rwlock->state--; + if (rwlock->state == 0 && rwlock->blocked_writers) { + ret = sysv_cond_signal(&rwlock->write_signal); + } + } else if (rwlock->state < 0) { + rwlock->state = 0; + + if (rwlock->blocked_writers) { + ret = sysv_cond_signal(&rwlock->write_signal); + } + else { + ret = sysv_cond_signal(&rwlock->read_signal); + } + } else + ret = EINVAL; + + sysv_mutex_unlock(&rwlock->lock); + + return (ret); +} + +int +sysv_rwlock_wrlock (struct sysv_rwlock *rwlock) +{ + int ret; + + if (rwlock == NULL) + return (EINVAL); + + /* Grab the monitor lock. */ + if ((ret = sysv_mutex_lock(&rwlock->lock)) != 0) + return (ret); + + while (rwlock->state != 0) { + rwlock->blocked_writers++; + + ret = sysv_cond_wait(&rwlock->write_signal, &rwlock->lock); + if (ret != 0) { + rwlock->blocked_writers--; + /* No unlock is required because only the lock + * operation can return error. + */ + //sysv_mutex_unlock(&rwlock->lock); + return (ret); + } + + rwlock->blocked_writers--; + } + + /* Indicate that we are locked for writing. */ + rwlock->state = -1; + + sysv_mutex_unlock(&rwlock->lock); + + return (ret); +} + +int +sysv_rwlock_rdlock(struct sysv_rwlock *rwlock) +{ + int ret; + +// sysv_print("try get rd lock\n"); + if (rwlock == NULL) + return (EINVAL); + + /* Grab the monitor lock. */ + if ((ret = sysv_mutex_lock(&rwlock->lock)) != 0) + return (ret); + + /* Check the lock count. */ + if (rwlock->state == MAX_READ_LOCKS) { + sysv_mutex_unlock(&rwlock->lock); + return (EAGAIN); + } + + if ((rdlock_count > 0) && (rwlock->state > 0)) { + /* + * Taken from the pthread implementation with only + * one change; rdlock_count is per process not per + * thread; + * Original comment: + * To avoid having to track all the rdlocks held by + * a thread or all of the threads that hold a rdlock, + * we keep a simple count of all the rdlocks held by + * a thread. If a thread holds any rdlocks it is + * possible that it is attempting to take a recursive + * rdlock. If there are blocked writers and precedence + * is given to them, then that would result in the thread + * deadlocking. So allowing a thread to take the rdlock + * when it already has one or more rdlocks avoids the + * deadlock. I hope the reader can follow that logic ;-) + */ + ; /* nothing needed */ + } else { + /* Give writers priority over readers. */ + while (rwlock->blocked_writers || rwlock->state < 0) { + ret = sysv_cond_wait(&rwlock->read_signal, + &rwlock->lock); + if (ret != 0) { + /* No unlock necessary because only lock + * operation can return error. + */ + //sysv_mutex_unlock(&rwlock->lock); + return (ret); + } + } + } + + rdlock_count++; + rwlock->state++; /* Indicate we are locked for reading. */ + + /* + * Something is really wrong if this call fails. Returning + * error won't do because we've already obtained the read + * lock. Decrementing 'state' is no good because we probably + * don't have the monitor lock. + */ + sysv_mutex_unlock(&rwlock->lock); + + return (ret); +} diff --git a/lib/libc/sysvipc/lock_generic.c b/lib/libc/sysvipc/lock_generic.c new file mode 100644 index 0000000000..7f2eeccbe4 --- /dev/null +++ b/lib/libc/sysvipc/lock_generic.c @@ -0,0 +1,82 @@ +/*- + * Copyright (c) 2005 David Xu + * Copyright (c) 2005 Matthew Dillon + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_umtx.c,v 1.4 2008/04/14 20:12:41 dillon Exp $ + */ + +#include +#include +#include +#include + +#include "sysvipc_lock_generic.h" + +/* + * This function is used to acquire a contested lock. + */ +int +__sysv_umtx_lock(volatile umtx_t *mtx, int timo) +{ + int v, errval, ret = 0; + + /* contested */ + do { + v = *mtx; + if (v == 2 || atomic_cmpset_acq_int(mtx, 1, 2)) { + if (timo == 0) + umtx_sleep(mtx, 2, timo); + else if ( (errval = umtx_sleep(mtx, 2, timo)) > 0) { + if (errval == EAGAIN) { + if (atomic_cmpset_acq_int(mtx, 0, 2)) + ret = 0; + else + ret = ETIMEDOUT; + break; + } + } + } + } while (!atomic_cmpset_acq_int(mtx, 0, 2)); + + return (ret); +} + +void +__sysv_umtx_unlock(volatile umtx_t *mtx) +{ + int v; + + for (;;) { + v = *mtx; + if (atomic_cmpset_acq_int(mtx, v, v-1)) { + if (v != 1) { + *mtx = 0; + umtx_wakeup(mtx, 1); + } + break; + } + } +} diff --git a/lib/libc/sysvipc/msg.c b/lib/libc/sysvipc/msg.c new file mode 100644 index 0000000000..d87bae1b1e --- /dev/null +++ b/lib/libc/sysvipc/msg.c @@ -0,0 +1,804 @@ +/* $FreeBSD: src/sys/kern/sysv_msg.c,v 1.23.2.5 2002/12/31 08:54:53 maxim Exp $ */ + +/* + * Implementation of SVID messages + * + * Author: Daniel Boulet + * + * Copyright 1993 Daniel Boulet and RTMX Inc. + * Copyright (c) 2013 Larisa Grigore + * + * This system call was implemented by Daniel Boulet under contract from RTMX. + * + * Redistribution and use in source forms, with and without modification, + * are permitted provided that this entire comment appears intact. + * + * Redistribution in binary form may occur without any restrictions. + * Obviously, it would be nice if you gave credit where credit is due + * but requiring it would be too onerous. + * + * This software is provided ``AS IS'' without any warranties of any kind. + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +#include "sysvipc_lock.h" +#include "sysvipc_ipc.h" +#include "sysvipc_hash.h" +#include "sysvipc_msg.h" +#include "sysvipc_shm.h" + +#define SYSV_MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) +#define SYSV_MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) +#define SYSV_MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x) + +extern struct hashtable *shmaddrs; +extern struct hashtable *shmres; +extern pthread_mutex_t lock_resources; + +struct msginfo msginfo = { + MSGMAX, /* max chars in a message */ + MSGMNI, /* # of message queue identifiers */ + MSGMNB, /* max chars in a queue */ + MSGTQL, /* max messages in system */ + MSGSSZ, /* size of a message segment (must be small power of 2 greater than 4) */ + MSGSEG /* number of message segments */ +}; + +static int +put_shmdata(int id) { + struct shm_data *data; + int ret = -1; + + SYSV_MUTEX_LOCK(&lock_resources); + data = _hash_lookup(shmres, id); + if (!data) { + sysv_print_err("something wrong put_shmdata\n"); + goto done; /* It should not reach here. */ + } + + data->used--; + if (data->used == 0 && data->removed) { + sysv_print("really remove the sem\n"); + SYSV_MUTEX_UNLOCK(&lock_resources); + /* OBS: Even if the shmctl fails (the thread doesn't + * have IPC_M permissions), all structures associated + * with it will be removed in the current process.*/ + shmdt(data->internal); + if (data->removed == SEG_ALREADY_REMOVED) + return 1; /* The queue was removed + by another process so there is nothing else + we must do. */ + /* Else inform the daemon that the segment is removed. */ + return (sysvipc_shmctl(id, IPC_RMID, NULL)); + } + + ret = 0; +done: + SYSV_MUTEX_UNLOCK(&lock_resources); + return (ret); +} + +static struct msqid_pool* +get_msqpptr(int msqid, int to_remove, int shm_access) { + struct msqid_pool *msqpptr; + + struct shm_data *shmdata = + get_shmdata(msqid, to_remove, shm_access); + if (!shmdata) { + /* Error is set in get_shmdata. */ + return NULL; + } + + msqpptr = (struct msqid_pool *)shmdata->internal; + if (!msqpptr) { + put_shmdata(msqid); + errno = EINVAL; + return NULL; + } + + return msqpptr; +} + +static int +msqp_exist(int msqid, struct msqid_pool *msqpptr) { + /* Was it removed? */ + if (msqpptr->gen == -1 || + msqpptr->ds.msg_perm.seq != IPCID_TO_SEQ(msqid)) + return 0; + + return 1; +} + +static int +try_rwlock_rdlock(int msqid, struct msqid_pool *msqpptr) { + sysv_print("try get rd lock\n"); +#ifdef SYSV_RWLOCK + sysv_rwlock_rdlock(&msqpptr->rwlock); +#else + sysv_mutex_lock(&msqpptr->mutex); +#endif + sysv_print("get rd lock\n"); + if (!msqp_exist(msqid, msqpptr)) { + errno = EINVAL; + sysv_print("error rd lock\n"); +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&msqpptr->rwlock); +#else + sysv_mutex_unlock(&msqpptr->mutex); +#endif + return -1; + } + sysv_print("end rd lock\n"); + return 0; +} + +static int +try_rwlock_wrlock(int msqid, struct msqid_pool *msqpptr) { + sysv_print("try get wr lock\n"); +#ifdef SYSV_RWLOCK + sysv_rwlock_wrlock(&msqpptr->rwlock); +#else + sysv_mutex_lock(&msqpptr->mutex); +#endif + sysv_print("get wr lock\n"); + if (!msqp_exist(msqid, msqpptr)) { + sysv_print("error rw lock\n"); + errno = EINVAL; +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&msqpptr->rwlock); +#else + sysv_mutex_unlock(&msqpptr->mutex); +#endif + return -1; + } + sysv_print("end rw lock\n"); + return 0; +} + +static int +rwlock_unlock(int msqid, struct msqid_pool *msqpptr) { + if (!msqp_exist(msqid, msqpptr)) { + errno = EINVAL; + return -1; + } +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&msqpptr->rwlock); +#else + sysv_mutex_unlock(&msqpptr->mutex); +#endif + sysv_print("unlock rw lock\n"); + return 0; +} + +static void +msg_freehdr(struct msqid_pool *msqpptr, struct msg *msghdr) +{ + while (msghdr->msg_ts > 0) { + short next; + if (msghdr->msg_spot < 0 || msghdr->msg_spot >= msginfo.msgseg) { + sysv_print_err("msghdr->msg_spot out of range"); + exit(-1); + } + next = msqpptr->msgmaps[msghdr->msg_spot].next; + msqpptr->msgmaps[msghdr->msg_spot].next = + msqpptr->free_msgmaps; + msqpptr->free_msgmaps = msghdr->msg_spot; + msqpptr->nfree_msgmaps++; + msghdr->msg_spot = next; + if (msghdr->msg_ts >= msginfo.msgssz) + msghdr->msg_ts -= msginfo.msgssz; + else + msghdr->msg_ts = 0; + } + if (msghdr->msg_spot != -1) { + sysv_print_err("msghdr->msg_spot != -1"); + exit(-1); + } + msghdr->msg_next = msqpptr->free_msghdrs; + msqpptr->free_msghdrs = (msghdr - &msqpptr->msghdrs[0]) / + sizeof(struct msg); +} + +int +sysvipc_msgget(key_t key, int msgflg) { + int msqid; + void *shmaddr; + size_t size = sizeof(struct msqid_pool); + + msqid = _shmget(key, size, msgflg, MSGGET); + if (msqid == -1) + goto done; + + /* If the msg is in process of being removed there are two cases: + * - the daemon knows that and it will handle this situation. + * - one of the threads from this address space remove it and the daemon + * wasn't announced yet; in this scenario, the msg is marked + * using "removed" field of shm_data and future calls will return + * EIDRM error. + */ + +#if 0 + /* Set access type. */ + shm_access = semflg & (IPC_W | IPC_R); + if(set_shmdata_access(semid, shm_access) != 0) { + /* errno already set. */ + goto done; + } +#endif + + shmaddr = sysvipc_shmat(msqid, NULL, 0); + if (!shmaddr) { + msqid = -1; + sysvipc_shmctl(msqid, IPC_RMID, NULL); + goto done; + } + sysv_print("shmaddr = %lx\n", (unsigned long)shmaddr); + +done: + return msqid; +} + +int +sysvipc_msgctl(int msqid, int cmd, struct msqid_ds *buf) { + int error; + struct msqid_pool *msqpptr = NULL; + struct shmid_ds shmds; + int shm_access = 0; + + error = 0; + + switch (cmd) { + case IPC_SET: /* Originally was IPC_M but this is checked + by daemon. */ + shm_access = IPC_W; + break; + case IPC_STAT: + shm_access = IPC_R; + break; + default: + break; + } + + msqpptr = get_msqpptr(msqid, cmd==IPC_RMID, shm_access); + if (!msqpptr) { + errno = EINVAL; + return -1; + } + + switch (cmd) { + case IPC_RMID: + /* Mark that the segment is removed. This is done in + * get_msqpptr call in order to announce other processes. + * It will be actually removed after put_shmdata call and + * not other thread from this address space use shm_data + * structure. + */ + break; + case IPC_SET: + error = try_rwlock_rdlock(msqid, msqpptr); + if (error) + break; + if (buf->msg_qbytes == 0) { + sysv_print_err("can't reduce msg_qbytes to 0\n"); + errno = EINVAL; /* non-standard errno! */ + rwlock_unlock(msqid, msqpptr); + break; + } + rwlock_unlock(msqid, msqpptr); + + memset(&shmds, 0, sizeof(shmds)/sizeof(unsigned char)); + memcpy(&shmds.shm_perm, &buf->msg_perm, + sizeof(struct ipc_perm)); + error = sysvipc_shmctl(msqid, cmd, &shmds); + if (error) + break; + + /* There is no need to check if we have right to modify the + * size because we have right to change other fileds. */ + + if (round_page(buf->msg_qbytes) != + round_page(msqpptr->ds.msg_qbytes)) { + sysv_print("change msg size\n"); + /* TODO same as in semundo_adjust only + * that there is no way to inform other + * processes about the change. */ + } + + error = try_rwlock_wrlock(msqid, msqpptr); + if (error) + break; + msqpptr->ds.msg_qbytes = buf->msg_qbytes; + rwlock_unlock(msqid, msqpptr); + /* OBS: didn't update ctime and mode as in kernel implementation + * it is done. Those fields are already updated for shmid_ds + * struct when calling shmctl + */ + break; + + case IPC_STAT: + error = sysvipc_shmctl(msqid, cmd, &shmds); + if (error) + break; + + memcpy(&buf->msg_perm, &shmds.shm_perm, + sizeof(struct ipc_perm)); + buf->msg_ctime = shmds.shm_ctime; + + /* Read fields that are not kept in shmds. */ + error = try_rwlock_rdlock(msqid, msqpptr); + if (error) + break; + buf->msg_first = (struct msg *)(u_long) + msqpptr->ds.first.msg_first_index; + buf->msg_last = (struct msg *)(u_long) + msqpptr->ds.last.msg_last_index; + buf->msg_cbytes = msqpptr->ds.msg_cbytes; + buf->msg_qnum = msqpptr->ds.msg_qnum; + buf->msg_qbytes = msqpptr->ds.msg_qbytes; + buf->msg_lspid = msqpptr->ds.msg_lspid; + buf->msg_lrpid = msqpptr->ds.msg_lrpid; + buf->msg_stime = msqpptr->ds.msg_stime; + buf->msg_rtime = msqpptr->ds.msg_rtime; + rwlock_unlock(msqid, msqpptr); + break; + default: + sysv_print_err("invalid command %d\n", cmd); + errno = EINVAL; + break; + } + + put_shmdata(msqid); + + return(error); +} + +int +sysvipc_msgsnd(int msqid, void *msgp, size_t msgsz, int msgflg) +{ + int segs_needed, error; + struct msg *msghdr; + struct msqid_pool *msqpptr, *auxmsqpptr; + struct msqid_ds_internal *msqptr; + short next; + int val_to_sleep; + char *auxmsgp = (char *)msgp; + int _index; + + sysv_print("call to msgsnd(%d, %ld, %d)\n", msqid, msgsz, msgflg); + + /*if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) + return (ENOSYS); +*/ + if (!msgp) { + errno = EINVAL; + return -1; + } + + msqpptr = get_msqpptr(msqid, 0, IPC_W); + if (!msqpptr) { + errno = EINVAL; + return -1; + } + error = -1; + + if (try_rwlock_wrlock(msqid, msqpptr) == -1) { + errno = EIDRM; + goto done; + } + + msqptr = &msqpptr->ds; + + segs_needed = (msgsz + msginfo.msgssz - 1) / msginfo.msgssz; + sysv_print("msgsz=%ld, msgssz=%d, segs_needed=%d\n", msgsz, msginfo.msgssz, + segs_needed); + for (;;) { + int need_more_resources = 0; + + if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) { + sysv_print("msgsz + msg_cbytes > msg_qbytes\n"); + need_more_resources = 1; + } + + if (segs_needed > msqpptr->nfree_msgmaps) { + sysv_print("segs_needed > nfree_msgmaps (= %d)\n", + msqpptr->nfree_msgmaps); + need_more_resources = 1; + } + + if (msqpptr->free_msghdrs == -1) { + sysv_print("no more msghdrs\n"); + need_more_resources = 1; + } + + if (need_more_resources) { + if ((msgflg & IPC_NOWAIT) != 0) { + sysv_print_err("need more resources but caller doesn't want to wait\n"); + errno = EAGAIN; + goto done; + } + + sysv_print("goodnight\n"); + val_to_sleep = msqpptr->gen; + rwlock_unlock(msqid, msqpptr); + put_shmdata(msqid); + + if (umtx_sleep((int *)&msqpptr->gen, val_to_sleep, SYSV_TIMEOUT) != 0) { + sysv_print_err("msgsnd: interrupted system call\n"); + errno = EINTR; + goto done; + } + + /* Check if another thread didn't remove the msg queue. */ + auxmsqpptr = get_msqpptr(msqid, 0, IPC_W); + if (!auxmsqpptr) { + errno = EIDRM; + return -1; + } + + if (auxmsqpptr != msqpptr) { + errno = EIDRM; + goto done; + } + + /* Check if another process didn't remove the queue. */ + if (try_rwlock_wrlock(msqid, msqpptr) == -1) { + errno = EIDRM; + goto done; + } + + if (msqptr != &msqpptr->ds) { + sysv_print("msqptr != &msqpptr->ds"); + exit(-1); + } + + } else { + sysv_print("got all the resources that we need\n"); + break; + } + } + + /* + * We have the resources that we need. + * Make sure! + */ +#if 0 + if (segs_needed > nfree_msgmaps) { + sysv_print_err("segs_needed > nfree_msgmaps"); + exit(-1); + } +#endif + if (msgsz + msqptr->msg_cbytes > msqptr->msg_qbytes) { + sysv_print_err("msgsz + msg_cbytes > msg_qbytes"); + exit(-1); + } + + /* + * Allocate a message header + */ + msghdr = &msqpptr->msghdrs[msqpptr->free_msghdrs]; + msqpptr->free_msghdrs = msghdr->msg_next; + msghdr->msg_spot = -1; + msghdr->msg_ts = msgsz; + + /* + * Allocate space for the message + */ + while (segs_needed > 0) { + next = msqpptr->free_msgmaps; + if (next < 0 || next > msginfo.msgseg) { + sysv_print_err("out of range free_msgmaps %d #1\n", next); + exit(-1); + } + + msqpptr->free_msgmaps = msqpptr->msgmaps[next].next; + msqpptr->nfree_msgmaps--; + msqpptr->msgmaps[next].next = msghdr->msg_spot; + msghdr->msg_spot = next; + segs_needed--; + } + + /* + * Copy in the message type + */ + memcpy(&msghdr->msg_type, auxmsgp, sizeof(msghdr->msg_type)); + auxmsgp = (char *)auxmsgp + sizeof(msghdr->msg_type); + + /* + * Validate the message type + */ + sysv_print("msg_type = %ld\n", msghdr->msg_type); + + if (msghdr->msg_type < 1) { + msg_freehdr(msqpptr, msghdr); + umtx_wakeup((int *)&msqpptr->gen, 0); + sysv_print_err("mtype (%ld) < 1\n", msghdr->msg_type); + errno = EINVAL; + goto done; + } + + /* + * Copy in the message body + */ + next = msghdr->msg_spot; + while (msgsz > 0) { + size_t tlen; + if (msgsz > (size_t)msginfo.msgssz) + tlen = msginfo.msgssz; + else + tlen = msgsz; + if (next < 0 || next > msginfo.msgseg) { + sysv_print_err("out of range free_msgmaps %d #2\n", next); + exit(-1); + } + + memcpy(&msqpptr->msgpool[next * msginfo.msgssz], auxmsgp, tlen); + msgsz -= tlen; + auxmsgp = (char *)auxmsgp + tlen; + next = msqpptr->msgmaps[next].next; + } + + /* + * Put the message into the queue + */ + _index = (msghdr - &msqpptr->msghdrs[0]) / + sizeof(struct msg); + sysv_print("index_msghdr = %d\n", _index); + if (msqptr->first.msg_first_index == -1) { + msqptr->first.msg_first_index = _index; + msqptr->last.msg_last_index = _index; + } else { + msqpptr->msghdrs[msqptr->last.msg_last_index].msg_next = _index; + msqptr->last.msg_last_index = _index; + } + msqpptr->msghdrs[msqptr->last.msg_last_index].msg_next = -1; + + msqptr->msg_cbytes += msghdr->msg_ts; + msqptr->msg_qnum++; + msqptr->msg_lspid = getpid(); + msqptr->msg_stime = time(NULL); + + umtx_wakeup((int *)&msqpptr->gen, 0); + error = 0; + +done: + rwlock_unlock(msqid, msqpptr); + put_shmdata(msqid); + return(error); +} + +int +sysvipc_msgrcv(int msqid, void *msgp, size_t msgsz, long mtype, int msgflg) +{ + size_t len; + struct msqid_pool *msqpptr, *auxmsqpptr; + struct msqid_ds_internal *msqptr; + struct msg *msghdr; + short msghdr_index; + int error; + short next; + int val_to_sleep; + char *auxmsgp = (char *)msgp; + + sysv_print("call to msgrcv(%d, %ld, %ld, %d)\n", msqid, msgsz, mtype, msgflg); +/* + if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) + return (ENOSYS); +*/ + + if (!msgp) { + errno = EINVAL; + return -1; + } + + msqpptr = get_msqpptr(msqid, 0, IPC_R); + if (!msqpptr) { + errno = EINVAL; + return -1; + } + + error = -1; + + if (try_rwlock_wrlock(msqid, msqpptr) == -1) { + errno = EIDRM; + goto done; + } + + msqptr = &msqpptr->ds; + + msghdr_index = -1; + while (msghdr_index == -1) { + if (mtype == 0) { + msghdr_index = msqptr->first.msg_first_index; + msghdr = &msqpptr->msghdrs[msghdr_index]; + if (msghdr_index != -1) { + if (msgsz < msghdr->msg_ts && + (msgflg & MSG_NOERROR) == 0) { + sysv_print_err("first message on the queue is too big" + "(want %d, got %d)\n", + msgsz, msghdr->msg_ts); + errno = E2BIG; + goto done; + } + if (msqptr->first.msg_first_index == msqptr->last.msg_last_index) { + msqptr->first.msg_first_index = -1; + msqptr->last.msg_last_index = -1; + } else { + msqptr->first.msg_first_index = msghdr->msg_next; + if (msqptr->first.msg_first_index == -1) { + sysv_print_err("first.msg_first_index/last screwed up #1"); + exit(-1); + } + } + } + } else { + short previous; + short prev; + previous = -1; + prev = msqptr->first.msg_first_index; + while ((msghdr_index = prev) != -1) { + msghdr = &msqpptr->msghdrs[msghdr_index]; + /* + * Is this message's type an exact match or is + * this message's type less than or equal to + * the absolute value of a negative mtype? + * Note that the second half of this test can + * NEVER be true if mtype is positive since + * msg_type is always positive! + */ + if (mtype == msghdr->msg_type || + msghdr->msg_type <= -mtype) { + sysv_print("found message type %d, requested %d\n", + msghdr->msg_type, mtype); + if (msgsz < msghdr->msg_ts && + (msgflg & MSG_NOERROR) == 0) { + sysv_print_err("requested message on the queue" + " is too big (want %d, got %d)\n", + msgsz, msghdr->msg_ts); + errno = E2BIG; + goto done; + } + prev = msghdr->msg_next; + if (msghdr_index == msqptr->last.msg_last_index) { + if (previous == -1) { + msqptr->first.msg_first_index = -1; + msqptr->last.msg_last_index = -1; + } else { + msqptr->last.msg_last_index = previous; + } + } + break; + } + previous = msghdr_index; + prev = msghdr->msg_next; + } + } + + /* + * We've either extracted the msghdr for the appropriate + * message or there isn't one. + * If there is one then bail out of this loop. + */ + if (msghdr_index != -1) + break; + + /* + * No message found. Does the user want to wait? + */ + if ((msgflg & IPC_NOWAIT) != 0) { + sysv_print_err("no appropriate message found (mtype=%d)\n", + mtype); + errno = ENOMSG; + goto done; + } + + /* + * Wait for something to happen + */ + sysv_print("goodnight\n"); + val_to_sleep = msqpptr->gen; + rwlock_unlock(msqid, msqpptr); + put_shmdata(msqid); + + /* We don't sleep more than SYSV_TIMEOUT because we could + * go to sleep after another process calls wakeup and remain + * blocked. + */ + if (umtx_sleep((int *)&msqpptr->gen, val_to_sleep, SYSV_TIMEOUT) != 0) { + sysv_print_err("msgrcv: interrupted system call\n"); + errno = EINTR; + goto done; + } + sysv_print("msgrcv: good morning (error=%d)\n", errno); + + /* Check if another thread didn't remove the msg queue. */ + auxmsqpptr = get_msqpptr(msqid, 0, IPC_R); + if (!auxmsqpptr) { + errno = EIDRM; + return -1; + } + + if (auxmsqpptr != msqpptr) { + errno = EIDRM; + goto done; + } + + /* Check if another process didn't remove the msg queue. */ + if (try_rwlock_wrlock(msqid, msqpptr) == -1) { + errno = EIDRM; + goto done; + } + + if (msqptr != &msqpptr->ds) { + sysv_print_err("msqptr != &msqpptr->ds"); + exit(-1); + } + } + + /* + * Return the message to the user. + */ + msqptr->msg_cbytes -= msghdr->msg_ts; + msqptr->msg_qnum--; + msqptr->msg_lrpid = getpid(); + msqptr->msg_rtime = time(NULL); + + /* + * Make msgsz the actual amount that we'll be returning. + * Note that this effectively truncates the message if it is too long + * (since msgsz is never increased). + */ + sysv_print("found a message, msgsz=%d, msg_ts=%d\n", msgsz, + msghdr->msg_ts); + if (msgsz > msghdr->msg_ts) + msgsz = msghdr->msg_ts; + + /* + * Return the type to the user. + */ + memcpy(auxmsgp, (caddr_t)&(msghdr->msg_type), sizeof(msghdr->msg_type)); + auxmsgp = (char *)auxmsgp + sizeof(msghdr->msg_type); + + /* + * Return the segments to the user + */ + next = msghdr->msg_spot; + for (len = 0; len < msgsz; len += msginfo.msgssz) { + size_t tlen; + + if (msgsz - len > (size_t)msginfo.msgssz) + tlen = msginfo.msgssz; + else + tlen = msgsz - len; + if (next < 0 || next > msginfo.msgseg) { + sysv_print_err("out of range free_msgmaps %d #3\n", next); + exit(-1); + } + + memcpy(auxmsgp, (caddr_t)&msqpptr->msgpool[next * msginfo.msgssz], tlen); + auxmsgp = (char *)auxmsgp + tlen; + next = msqpptr->msgmaps[next].next; + } + + /* + * Done, return the actual number of bytes copied out. + */ + msg_freehdr(msqpptr, msghdr); + umtx_wakeup((int *)&msqpptr->gen, 0); + error = msgsz; +done: + rwlock_unlock(msqid, msqpptr); + put_shmdata(msqid); + return(error); +} diff --git a/lib/libc/sysvipc/sem.c b/lib/libc/sysvipc/sem.c new file mode 100644 index 0000000000..562826d26b --- /dev/null +++ b/lib/libc/sysvipc/sem.c @@ -0,0 +1,887 @@ +/* $FreeBSD: src/sys/kern/sysv_sem.c,v 1.69 2004/03/17 09:37:13 cperciva Exp $ */ + +/* + * Implementation of SVID semaphores + * + * Author: Daniel Boulet + * Copyright (c) 2013 Larisa Grigore + * + * This software is provided ``AS IS'' without any warranties of any kind. + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +#include "sysvipc_lock.h" +#include "sysvipc_ipc.h" +#include "sysvipc_shm.h" +#include "sysvipc_sem.h" +#include "sysvipc_hash.h" + + +#define SYSV_MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) +#define SYSV_MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) +#define SYSV_MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x) + +extern struct hashtable *shmaddrs; +extern struct hashtable *shmres; +extern pthread_mutex_t lock_resources; + +struct sem_undo *undos = NULL; +pthread_mutex_t lock_undo = PTHREAD_MUTEX_INITIALIZER; + +static int semundo_clear(int, int); + +static int +put_shmdata(int id) { + struct shm_data *data; + int ret = -1; + + SYSV_MUTEX_LOCK(&lock_resources); + data = _hash_lookup(shmres, id); + if (!data) { + sysv_print_err("something wrong put_shmdata\n"); + goto done; /* It should not reach here. */ + } + + data->used--; + if (data->used == 0 && data->removed) { + sysv_print("really remove the sem\n"); + SYSV_MUTEX_UNLOCK(&lock_resources); + /* OBS: Even if the shmctl fails (the thread doesn't + * have IPC_M permissions), all structures associated + * with it will be removed in the current process.*/ + sysvipc_shmdt(data->internal); + semundo_clear(id, -1); + if (data->removed == SEG_ALREADY_REMOVED) + return 1; /* The semaphore was removed + by another process so there is nothing else + we must do. */ + /* Else inform the daemon that the segment is removed. */ + return (sysvipc_shmctl(id, IPC_RMID, NULL)); + } + + ret = 0; +done: + SYSV_MUTEX_UNLOCK(&lock_resources); + return (ret); +} + +static struct semid_pool* +get_semaptr(int semid, int to_remove, int shm_access) { + struct semid_pool *semaptr; + + struct shm_data *shmdata = get_shmdata(semid, to_remove, shm_access); + if (!shmdata) { + /* Error is set in get_shmdata. */ + return (NULL); + } + + semaptr = (struct semid_pool *)shmdata->internal; + if (!semaptr) { + put_shmdata(semid); + errno = EINVAL; + return (NULL); + } + + return (semaptr); +} + +static int +sema_exist(int semid, struct semid_pool *semaptr) { + /* Was it removed? */ + if (semaptr->gen == -1 || + semaptr->ds.sem_perm.seq != IPCID_TO_SEQ(semid)) + return (0); + + return (1); +} + +/* This is the function called when a the semaphore + * is descovered as removed. It marks the process + * internal data and munmap the */ +static void +mark_for_removal(int shmid) { + sysv_print("Mark that the segment was removed\n"); + get_shmdata(shmid, SEG_ALREADY_REMOVED, 0); + /* Setting SEG_ALREADY_REMOVED parameter, when put_shmdata + * is called, the internal resources will be freed. + */ + /* Decrement the "usage" field. */ + put_shmdata(shmid); +} + +static int +try_rwlock_rdlock(int semid, struct semid_pool *semaptr) { + sysv_print(" before rd lock id = %d %x\n", semid, semaptr); +#ifdef SYSV_RWLOCK + sysv_rwlock_rdlock(&semaptr->rwlock); + sysv_print("rd lock id = %d\n", semid); +#else + sysv_mutex_lock(&semaptr->mutex); + sysv_print("lock id = %d\n", semid); +#endif + if (!sema_exist(semid, semaptr)) { + errno = EINVAL; + sysv_print("error sema %d doesn't exist\n", semid); +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&semaptr->rwlock); +#else + sysv_mutex_unlock(&semaptr->mutex); +#endif + /* Internal resources must be freed. */ + mark_for_removal(semid); + return (-1); + } + return (0); +} + +static int +try_rwlock_wrlock(int semid, struct semid_pool *semaptr) { +#ifdef SYSV_RWLOCK + sysv_print("before wrlock id = %d %x\n", semid, semaptr); + sysv_rwlock_wrlock(&semaptr->rwlock); +#else + sysv_print("before lock id = %d %x\n", semid, semaptr); + sysv_mutex_lock(&semaptr->mutex); +#endif + sysv_print("lock id = %d\n", semid); + if (!sema_exist(semid, semaptr)) { + errno = EINVAL; + sysv_print("error sema %d doesn't exist\n", semid); +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&semaptr->rwlock); +#else + sysv_mutex_unlock(&semaptr->mutex); +#endif + /* Internal resources must be freed. */ + mark_for_removal(semid); + return (-1); + } + return (0); +} + +static int +rwlock_unlock(int semid, struct semid_pool *semaptr) { + sysv_print("unlock id = %d %x\n", semid, semaptr); + if (!sema_exist(semid, semaptr)) { + /* Internal resources must be freed. */ + mark_for_removal(semid); + errno = EINVAL; + return (-1); + } +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&semaptr->rwlock); +#else + sysv_mutex_unlock(&semaptr->mutex); +#endif + return (0); +} + +int +sysvipc_semget(key_t key, int nsems, int semflg) { + int semid; + void *shmaddr; + //int shm_access; + int size = sizeof(struct semid_pool) + nsems * sizeof(struct sem); + + //TODO resources limits + sysv_print("handle semget\n"); + + semid = _shmget(key, size, semflg, SEMGET); + if (semid == -1) { + /* errno already set. */ + goto done; + } + + /* If the semaphore is in process of being removed there are two cases: + * - the daemon knows that and it will handle this situation. + * - one of the threads from this address space remove it and the daemon + * wasn't announced yet; in this scenario, the semaphore is marked + * using "removed" field of shm_data and future calls will return + * EIDRM error. + */ + +#if 0 + /* Set access type. */ + shm_access = semflg & (IPC_W | IPC_R); + if(set_shmdata_access(semid, shm_access) != 0) { + /* errno already set. */ + goto done; + } +#endif + shmaddr = sysvipc_shmat(semid, NULL, 0); + if (!shmaddr) { + semid = -1; + sysvipc_shmctl(semid, IPC_RMID, NULL); + goto done; + } + + //TODO more semaphores in a single file + +done: + sysv_print("end handle semget %d\n", semid); + return (semid); +} + +static int +semundo_clear(int semid, int semnum) +{ + struct undo *sunptr; + int i; + + sysv_print("semundo clear\n"); + + SYSV_MUTEX_LOCK(&lock_undo); + if (!undos) + goto done; + + sunptr = &undos->un_ent[0]; + i = 0; + + while (i < undos->un_cnt) { + if (sunptr->un_id == semid) { + if (semnum == -1 || sunptr->un_num == semnum) { + undos->un_cnt--; + if (i < undos->un_cnt) { + undos->un_ent[i] = + undos->un_ent[undos->un_cnt]; + continue; + } + } + if (semnum != -1) + break; + } + ++i; + ++sunptr; + } + + //TODO Shrink memory if case; not sure if necessary +done: + SYSV_MUTEX_UNLOCK(&lock_undo); + sysv_print("end semundo clear\n"); + return (0); +} + +int +sysvipc_semctl(int semid, int semnum , int cmd, union semun arg) { + int i, error; + struct semid_pool *semaptr = NULL; + struct sem *semptr = NULL; + struct shmid_ds shmds; + int shm_access = 0; + + /*if (!jail_sysvipc_allowed && cred->cr_prison != NULL) + return (ENOSYS); +*/ + + sysv_print("semctl cmd = %d\n", cmd); + + error = 0; + + switch (cmd) { + case IPC_SET: /* Originally was IPC_M but this is checked + by daemon. */ + case SETVAL: + case SETALL: + shm_access = IPC_W; + break; + case IPC_STAT: + case GETNCNT: + case GETPID: + case GETVAL: + case GETALL: + case GETZCNT: + shm_access = IPC_R; + break; + default: + break; + } + + semaptr = get_semaptr(semid, cmd==IPC_RMID, shm_access); + if (!semaptr) { + /* errno already set. */ + return (-1); + } + + switch (cmd) { + case IPC_RMID: + /* Mark that the segment is removed. This is done in + * get_semaptr call in order to announce other processes. + * It will be actually removed after put_shmdata call and + * not other thread from this address space use shm_data + * structure. + */ + break; + + case IPC_SET: + if (!arg.buf) { + error = EFAULT; + break; + } + + memset(&shmds, 0, sizeof(shmds)/sizeof(unsigned char)); + memcpy(&shmds.shm_perm, &arg.buf->sem_perm, + sizeof(struct ipc_perm)); + error = sysvipc_shmctl(semid, cmd, &shmds); + /* OBS: didn't update ctime and mode as in kernel implementation + * it is done. Those fields are already updated for shmid_ds + * struct when calling shmctl + */ + break; + + case IPC_STAT: + if (!arg.buf) { + error = EFAULT; + break; + } + + error = sysvipc_shmctl(semid, cmd, &shmds); + if (error) + break; + + memcpy(&arg.buf->sem_perm, &shmds.shm_perm, + sizeof(struct ipc_perm)); + arg.buf->sem_nsems = (shmds.shm_segsz - sizeof(struct semid_pool)) / + sizeof(struct sem); + arg.buf->sem_ctime = shmds.shm_ctime; + + /* otime is semaphore specific so read it from + * semaptr + */ + error = try_rwlock_rdlock(semid, semaptr); + if (error) + break; + arg.buf->sem_otime = semaptr->ds.sem_otime; + rwlock_unlock(semid, semaptr); + break; + + case GETNCNT: + if (semnum < 0 || semnum >= semaptr->ds.sem_nsems) { + errno = EINVAL; + break; + } + + error = try_rwlock_rdlock(semid, semaptr); + if (error) + break; + error = semaptr->ds.sem_base[semnum].semncnt; + rwlock_unlock(semid, semaptr); + break; + + case GETPID: + if (semnum < 0 || semnum >= semaptr->ds.sem_nsems) { + errno = EINVAL; + break; + } + + error = try_rwlock_rdlock(semid, semaptr); + if (error) + break; + error = semaptr->ds.sem_base[semnum].sempid; + rwlock_unlock(semid, semaptr); + break; + + case GETVAL: + if (semnum < 0 || semnum >= semaptr->ds.sem_nsems) { + errno = EINVAL; + break; + } + + error = try_rwlock_rdlock(semid, semaptr); + if (error) + break; + error = semaptr->ds.sem_base[semnum].semval; + rwlock_unlock(semid, semaptr); + break; + + case GETALL: + if (!arg.array) { + error = EFAULT; + break; + } + + error = try_rwlock_rdlock(semid, semaptr); + if (error) + break; + for (i = 0; i < semaptr->ds.sem_nsems; i++) { + arg.array[i] = semaptr->ds.sem_base[i].semval; + } + rwlock_unlock(semid, semaptr); + break; + + case GETZCNT: + if (semnum < 0 || semnum >= semaptr->ds.sem_nsems) { + errno = EINVAL; + break; + } + + error = try_rwlock_rdlock(semid, semaptr); + if (error) + break; + error = semaptr->ds.sem_base[semnum].semzcnt; + rwlock_unlock(semid, semaptr); + break; + + case SETVAL: + if (semnum < 0 || semnum >= semaptr->ds.sem_nsems) { + errno = EINVAL; + break; + } + + error = try_rwlock_wrlock(semid, semaptr); + if (error) + break; + semptr = &semaptr->ds.sem_base[semnum]; + semptr->semval = arg.val; + semundo_clear(semid, semnum); + if (semptr->semzcnt || semptr->semncnt) + umtx_wakeup((int *)&semptr->semval, 0); + rwlock_unlock(semid, semaptr); + break; + + case SETALL: + if (!arg.array) { + error = EFAULT; + break; + } + + error = try_rwlock_wrlock(semid, semaptr); + if (error) + break; + for (i = 0; i < semaptr->ds.sem_nsems; i++) { + semptr = &semaptr->ds.sem_base[i]; + semptr->semval = arg.array[i]; + if (semptr->semzcnt || semptr->semncnt) + umtx_wakeup((int *)&semptr->semval, 0); + } + semundo_clear(semid, -1); + rwlock_unlock(semid, semaptr); + break; + + default: + errno = EINVAL; + break; + } + + put_shmdata(semid); + + sysv_print("end semctl\n"); + return (error); +} + +/* + * Adjust a particular entry for a particular proc + */ +static int +semundo_adjust(int semid, int semnum, int adjval) +{ + struct undo *sunptr; + int i; + int error = 0; + size_t size; + int undoid; + void *addr; + struct shm_data *data; + + sysv_print("semundo adjust\n"); + if (!adjval) + goto done; + + SYSV_MUTEX_LOCK(&lock_undo); + if (!undos) { + sysv_print("get undo segment\n"); + undoid = _shmget(IPC_PRIVATE, PAGE_SIZE, IPC_CREAT | IPC_EXCL | 0600, + UNDOGET); + if (undoid == -1) { + sysv_print_err("no undo segment\n"); + return (-1); + } + + addr = sysvipc_shmat(undoid, NULL, 0); + if (!addr) { + sysv_print_err("can not map undo segment\n"); + sysvipc_shmctl(undoid, IPC_RMID, NULL); + return (-1); + } + + undos = (struct sem_undo *)addr; + undos->un_pages = 1; + undos->un_cnt = 0; + } + + /* + * Look for the requested entry and adjust it (delete if adjval becomes + * 0). + */ + sunptr = &undos->un_ent[0]; + for (i = 0; i < undos->un_cnt; i++, sunptr++) { + if (sunptr->un_id != semid && sunptr->un_num != semnum) + continue; + sunptr->un_adjval += adjval; + if (sunptr->un_adjval == 0) { + undos->un_cnt--; + if (i < undos->un_cnt) + undos->un_ent[i] = undos->un_ent[undos->un_cnt]; + } + goto done; + } + + /* Didn't find the right entry - create it */ + size = sizeof(struct sem_undo) + (undos->un_cnt + 1) * + sizeof(struct sem_undo); + if (size > (unsigned int)(undos->un_pages * PAGE_SIZE)) { + sysv_print("need more undo space\n"); + sysvipc_shmdt(undos); + undos->un_pages++; + + SYSV_MUTEX_LOCK(&lock_resources); + data = _hash_lookup(shmaddrs, (u_long)undos); + SYSV_MUTEX_UNLOCK(&lock_resources); + + /* It is not necessary any lock on "size" because it is used + * only by shmat and shmdt. + * shmat for undoid is called only from this function and it + * is protected by undo_lock. + * shmdt for undoid is not called anywhere because the segment + * is destroyed by the daemon when the client dies. + */ + data->size = undos->un_pages * PAGE_SIZE; + undos = sysvipc_shmat(data->shmid, NULL, 0); + } + + sunptr = &undos->un_ent[undos->un_cnt]; + undos->un_cnt++; + sunptr->un_adjval = adjval; + sunptr->un_id = semid; + sunptr->un_num = semnum; + //if (suptr->un_cnt == seminfo.semume) TODO move it in daemon + /*} else { + error = EINVAL; //se face prin notificare + }*/ +done: + SYSV_MUTEX_UNLOCK(&lock_undo); + + sysv_print("semundo adjust end\n"); + return (error); +} + +int sysvipc_semop (int semid, struct sembuf *sops, unsigned nsops) { + struct semid_pool *semaptr = NULL, *auxsemaptr = NULL; + struct sembuf *sopptr; + struct sem *semptr = NULL; + struct sem *xsemptr = NULL; + int eval = 0; + int i, j; + int do_undos; + int val_to_sleep; + + sysv_print("[client %d] call to semop(%d, %u)\n", + getpid(), semid, nsops); +//TODO + /*if (!jail_sysvipc_allowed && td->td_ucred->cr_prison != NULL) + return (ENOSYS); + */ + + semaptr = get_semaptr(semid, 0, IPC_W); + if (!semaptr) { + errno = EINVAL; + return (-1); + } + +#ifdef SYSV_SEMS + if (try_rwlock_rdlock(semid, semaptr) == -1) { +#else + if (try_rwlock_wrlock(semid, semaptr) == -1) { +#endif + sysv_print("sema removed\n"); + errno = EIDRM; + goto done2; + } + + if (nsops > MAX_SOPS) { + sysv_print("too many sops (max=%d, nsops=%u)\n", + getpid(), MAX_SOPS, nsops); + eval = E2BIG; + goto done; + } + + /* + * Loop trying to satisfy the vector of requests. + * If we reach a point where we must wait, any requests already + * performed are rolled back and we go to sleep until some other + * process wakes us up. At this point, we start all over again. + * + * This ensures that from the perspective of other tasks, a set + * of requests is atomic (never partially satisfied). + */ + do_undos = 0; + + for (;;) { + + semptr = NULL; + + for (i = 0; i < (int)nsops; i++) { + sopptr = &sops[i]; + + if (sopptr->sem_num >= semaptr->ds.sem_nsems) { + eval = EFBIG; + goto done; + } + + semptr = &semaptr->ds.sem_base[sopptr->sem_num]; +#ifdef SYSV_SEMS + sysv_mutex_lock(&semptr->sem_mutex); +#endif + sysv_print("semop: sem[%d]=%d : op=%d, flag=%s\n", + sopptr->sem_num, semptr->semval, sopptr->sem_op, + (sopptr->sem_flg & IPC_NOWAIT) ? "nowait" : "wait"); + + if (sopptr->sem_op < 0) { + if (semptr->semval + sopptr->sem_op < 0) { + sysv_print("semop: can't do it now\n"); + break; + } else { + semptr->semval += sopptr->sem_op; + if (semptr->semval == 0 && + semptr->semzcnt > 0) + umtx_wakeup((int *)&semptr->semval, 0); + } + if (sopptr->sem_flg & SEM_UNDO) + do_undos = 1; + } else if (sopptr->sem_op == 0) { + if (semptr->semval > 0) { + sysv_print("semop: not zero now\n"); + break; + } + } else { + semptr->semval += sopptr->sem_op; + if (sopptr->sem_flg & SEM_UNDO) + do_undos = 1; + if (semptr->semncnt > 0) + umtx_wakeup((int *)&semptr->semval, 0); + } +#ifdef SYSV_SEMS + sysv_mutex_unlock(&semptr->sem_mutex); +#endif + } + + /* + * Did we get through the entire vector? + */ + if (i >= (int)nsops) + goto donex; + + if (sopptr->sem_op == 0) + semptr->semzcnt++; + else + semptr->semncnt++; +#ifdef SYSV_SEMS + sysv_mutex_unlock(&semptr->sem_mutex); +#endif + /* + * Rollback the semaphores we had acquired. + */ + sysv_print("semop: rollback 0 through %d\n", i-1); + for (j = 0; j < i; j++) { + xsemptr = &semaptr->ds.sem_base[sops[j].sem_num]; +#ifdef SYSV_SEMS + sysv_mutex_lock(&semptr->sem_mutex); +#endif + xsemptr->semval -= sops[j].sem_op; + if (xsemptr->semval == 0 && xsemptr->semzcnt > 0) + umtx_wakeup((int *)&xsemptr->semval, 0); + if (xsemptr->semval <= 0 && xsemptr->semncnt > 0) + umtx_wakeup((int *)&xsemptr->semval, 0); //?! +#ifdef SYSV_SEMS + sysv_mutex_unlock(&semptr->sem_mutex); +#endif + } + + /* + * If the request that we couldn't satisfy has the + * NOWAIT flag set then return with EAGAIN. + */ + if (sopptr->sem_flg & IPC_NOWAIT) { + eval = EAGAIN; + goto done; + } + + /* + * Release semaptr->lock while sleeping, allowing other + * semops (like SETVAL, SETALL, etc), which require an + * exclusive lock and might wake us up. + * + * Reload and recheck the validity of semaptr on return. + * Note that semptr itself might have changed too, but + * we've already interlocked for semptr and that is what + * will be woken up if it wakes up the tsleep on a MP + * race. + * + */ + + sysv_print("semop: good night!\n"); + val_to_sleep = semptr->semval; + rwlock_unlock(semid, semaptr); + put_shmdata(semid); + + /* We don't sleep more than SYSV_TIMEOUT because we could + * go to sleep after another process calls wakeup and remain + * blocked. + */ + eval = umtx_sleep((int *)&semptr->semval, val_to_sleep, SYSV_TIMEOUT); + /* return code is checked below, after sem[nz]cnt-- */ + + /* + * Make sure that the semaphore still exists + */ + + /* Check if another thread didn't remove the semaphore. */ + auxsemaptr = get_semaptr(semid, 0, IPC_W); /* Redundant access check. */ + if (!auxsemaptr) { + errno = EIDRM; + return (-1); + } + + if (auxsemaptr != semaptr) { + errno = EIDRM; + goto done; + } + + /* Check if another process didn't remove the semaphore. */ +#ifdef SYSV_SEMS + if (try_rwlock_rdlock(semid, semaptr) == -1) { +#else + if (try_rwlock_wrlock(semid, semaptr) == -1) { +#endif + errno = EIDRM; + goto done; + } + sysv_print("semop: good morning (eval=%d)!\n", eval); + + /* The semaphore is still alive. Readjust the count of + * waiting processes. + */ + semptr = &semaptr->ds.sem_base[sopptr->sem_num]; +#ifdef SYSV_SEMS + sysv_mutex_lock(&semptr->sem_mutex); +#endif + if (sopptr->sem_op == 0) + semptr->semzcnt--; + else + semptr->semncnt--; +#ifdef SYSV_SEMS + sysv_mutex_unlock(&semptr->sem_mutex); +#endif + + /* + * Is it really morning, or was our sleep interrupted? + * (Delayed check of tsleep() return code because we + * need to decrement sem[nz]cnt either way.) + */ + if (eval) { + eval = EINTR; + goto done; + } + + sysv_print("semop: good morning!\n"); + /* RETRY LOOP */ +} + +donex: + /* + * Process any SEM_UNDO requests. + */ + if (do_undos) { + for (i = 0; i < (int)nsops; i++) { + /* + * We only need to deal with SEM_UNDO's for non-zero + * op's. + */ + int adjval; + + if ((sops[i].sem_flg & SEM_UNDO) == 0) + continue; + adjval = sops[i].sem_op; + if (adjval == 0) + continue; + eval = semundo_adjust(semid, sops[i].sem_num, -adjval); + if (eval == 0) + continue; + + /* + * Oh-Oh! We ran out of either sem_undo's or undo's. + * Rollback the adjustments to this point and then + * rollback the semaphore ups and down so we can return + * with an error with all structures restored. We + * rollback the undo's in the exact reverse order that + * we applied them. This guarantees that we won't run + * out of space as we roll things back out. + */ + for (j = i - 1; j >= 0; j--) { + if ((sops[j].sem_flg & SEM_UNDO) == 0) + continue; + adjval = sops[j].sem_op; + if (adjval == 0) + continue; + if (semundo_adjust(semid, sops[j].sem_num, + adjval) != 0) + sysv_print("semop - can't undo undos"); + } + + for (j = 0; j < (int)nsops; j++) { + xsemptr = &semaptr->ds.sem_base[ + sops[j].sem_num]; +#ifdef SYSV_SEMS + sysv_mutex_lock(&semptr->sem_mutex); +#endif + xsemptr->semval -= sops[j].sem_op; + if (xsemptr->semval == 0 && + xsemptr->semzcnt > 0) + umtx_wakeup((int *)&xsemptr->semval, 0); + if (xsemptr->semval <= 0 && + xsemptr->semncnt > 0) + umtx_wakeup((int *)&xsemptr->semval, 0); //?! +#ifdef SYSV_SEMS + sysv_mutex_unlock(&semptr->sem_mutex); +#endif + } + + sysv_print("eval = %d from semundo_adjust\n", eval); + goto done; + } + } + + /* Set sempid field for each semaphore. */ + for (i = 0; i < (int)nsops; i++) { + sopptr = &sops[i]; + semptr = &semaptr->ds.sem_base[sopptr->sem_num]; +#ifdef SYSV_SEMS + sysv_mutex_lock(&semptr->sem_mutex); +#endif + semptr->sempid = getpid(); +#ifdef SYSV_SEMS + sysv_mutex_unlock(&semptr->sem_mutex); +#endif + } + + sysv_print("semop: done\n"); + semaptr->ds.sem_otime = time(NULL); +done: + rwlock_unlock(semid, semaptr); +done2: + put_shmdata(semid); + + return (eval); +} diff --git a/lib/libc/sysvipc/shm.c b/lib/libc/sysvipc/shm.c new file mode 100644 index 0000000000..f629d23bd1 --- /dev/null +++ b/lib/libc/sysvipc/shm.c @@ -0,0 +1,538 @@ +/* + * Copyright (c) 2013 Larisa Grigore . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Glass and Charles + * Hannum. + * 4. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "namespace.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "un-namespace.h" + +#include "sysvipc_lock.h" +#include "sysvipc_ipc.h" +#include "sysvipc_sockets.h" +#include "sysvipc_shm.h" +#include "sysvipc_hash.h" + +#define SYSV_MUTEX_LOCK(x) if (__isthreaded) _pthread_mutex_lock(x) +#define SYSV_MUTEX_UNLOCK(x) if (__isthreaded) _pthread_mutex_unlock(x) +#define SYSV_MUTEX_DESTROY(x) if (__isthreaded) _pthread_mutex_destroy(x) + +struct hashtable *shmres = NULL; +struct hashtable *shmaddrs = NULL; +pthread_mutex_t lock_resources = PTHREAD_MUTEX_INITIALIZER; + +/* File descriptor used to communicate with the daemon. */ +extern int daemon_fd; +/* Structure used to save semaphore operation with SEMUNDO flag. */ +extern struct sem_undo *undos; + +static int +shminit(void) { + if (shmres) { + errno = EPERM; + return (-1); + } + + shmres = _hash_init(MAXSIZE); + if (!shmres) + goto out_resources; + + shmaddrs = _hash_init(MAXSIZE); + if (!shmaddrs) + goto out_addrs; + + return 0; + +out_addrs: + _hash_destroy(shmres); +out_resources: + return -1; +} + +/*static int +shmexit(void) { + if (!shmres) + return -EPERM; + + _hash_destroy(shmres); + _hash_destroy(shmaddrs); + SYSV_MUTEX_DESTROY(lock_resources); + + return 0; +}*/ + +/* Init sysv ipc resources and those used for shared memory. */ +static int +shmcheck(void) { + int ret; + + /* Init sysv resources. */ + if ((ret = sysvinit()) != 0) + return (ret); + /* Init resorces used for shared memory. */ + if ((ret = shminit()) < 0) + return (ret); + return (0); +} + +/* Check if sysv ipc resources are initialized. */ +static int +is_shm_started(void) { + if (!is_sysvinit()) + return (0); + if (!shmres) + return (0); + return (1); +} + +/* OBS: It is used only a rwlock for both hashtables and + * socket. I've made that choice because is I considered to + * be much expensive to acquire/release more than one especially + * as the daemon is not multithreading. + */ + +/* This function has another parameter apart from shmget. + * The parameter has information about the type of sysv + * ipc resource (shm, sem, msg, undo). + * The undo segment is used for sem ops with UNDO flag set. + */ +int +_shmget(key_t key, size_t size, int shmflg, int type) { + struct shmget_msg msg; + struct shm_data *data; + int shmid, fd; + int flags; + + SYSV_MUTEX_LOCK(&lock_resources); + if (shmcheck() < 0) { + sysv_print_err("init sysv ipc\n"); + goto done; + } + + msg.key = key; + msg.size = size; + msg.shmflg = shmflg; + msg.type = type; + + send_message(daemon_fd, type, (char *)&msg, sizeof(msg)); + + /* Accept a file installed by the daemon. + * The file is used as shared memory. */ + fd = receive_fd(daemon_fd); + if (fd < 0) { + shmid = -1; + goto done; + } + + flags = _fcntl(fd, F_GETFD, 0); + if (_fcntl(fd, F_SETFD, flags & FD_CLOEXEC) == -1) { + sysv_print_err("fcntl error\n"); + shmid = -1; + goto done; + } + + /* Receive the resource id or error. */ + receive_message(daemon_fd, (char *)&shmid, sizeof(shmid)); + + if (shmid < 0) { + errno = -shmid; + shmid = -1; + goto done; + } + + /* Do we already have an entry for this resource? */ + data = _hash_lookup(shmres, shmid); + if (data) + goto done; + + /* If not, add necessary data about it. */ + data = malloc(sizeof(struct shm_data)); + data->fd = fd; + data->size = size; + data->shmid = shmid; + data->type = type; + data->used = 0; + data->removed = 0; + data->access = 0; /* Used for sems. */ + + /* Insert data in hashtable using the shmid. */ + _hash_insert(shmres, shmid, data); +done: + SYSV_MUTEX_UNLOCK(&lock_resources); + return (shmid); +} + +int +sysvipc_shmget(key_t key, size_t size, int shmflg) { + return (_shmget(key, size, shmflg, SHMGET)); +} + +void * +sysvipc_shmat(int shmid, const void *shmaddr, int shmflg) { + struct shmat_msg msg; + void *addr = NULL; + int error; + int flags, prot; + size_t size; + struct shm_data *data; + + SYSV_MUTEX_LOCK(&lock_resources); + if (!is_shm_started()) { + errno = EINVAL; + goto done; + } + + /* Get data using shmid. */ + data = _hash_lookup(shmres, shmid); + if (data == NULL) { + errno = EINVAL; + goto done; + } + + size = round_page(data->size); + +#ifdef VM_PROT_READ_IS_EXEC + prot = PROT_READ | PROT_EXECUTE; +#else + prot = PROT_READ; +#endif + if ((shmflg & SHM_RDONLY) == 0) + prot |= PROT_WRITE; + + flags = MAP_SHARED; + if (shmaddr) { + if (shmflg & SHM_RND) { + addr = (void *)((vm_offset_t)shmaddr & ~(SHMLBA-1)); + } else if (((vm_offset_t)shmaddr & (SHMLBA-1)) == 0) { + addr = __DECONST(void *, shmaddr); + } else { + errno = EINVAL; + goto done; + } + } + + msg.shmid = shmid; + msg.shmaddr = shmaddr; + msg.shmflg = shmflg; + msg.size = data->size; /* For undo segment. */ + + send_message(daemon_fd, SHMAT, (char *)&msg, sizeof(msg)); + receive_message(daemon_fd, (char *)&error, sizeof(error)); + if (error) { + errno = error; + goto done; + } + + addr = mmap(addr, size, prot, flags, data->fd, 0); + if (!addr) { + sysv_print_err("mmap\n"); + /* Detach ourselves from the segment. */ + send_message(daemon_fd, SHMDT, (char *)&shmid, sizeof(shmid)); + goto done; + } + + /* Necessary for SEMGET, MSGGET, UNDOGET. */ + data->internal = addr; + + /* Save the mapped address for munmap call. */ + _hash_insert(shmaddrs, (u_long)addr, data); +done: + SYSV_MUTEX_UNLOCK(&lock_resources); + return (addr); +} + +/* Remove a sysv ipc resource. */ +static +void shmremove(int shmid) { + struct shm_data *data; + data = _hash_remove(shmres, shmid); + + //TODO nu trebuie demapat? + _close(data->fd); + free(data); + data = NULL; +} + +int +sysvipc_shmctl(int shmid, int cmd, struct shmid_ds *buf) { + int size, ret; + struct shmctl_msg *msg; + +/* if (cmd == IPC_SET) + size = sizeof(struct shmctl_msg) + sizeof(struct shmid_ds); + else + size = sizeof(struct shmctl_msg); +*/ + SYSV_MUTEX_LOCK(&lock_resources); + + ret = -1; + + if (!is_shm_started()) { + errno = EINVAL; + goto done; + } + + size = sizeof(struct shmctl_msg); + msg = malloc(size); + msg->shmid = shmid; + msg->cmd = cmd; + + if (cmd == IPC_SET) + msg->buf = *buf; + + send_message(daemon_fd, SHMCTL, (char *)msg, sizeof(*msg)); + + receive_message(daemon_fd, (char *)&ret, sizeof(ret)); + + /* Get data in IPC_STAT case. */ + if (ret == 0 && cmd == IPC_STAT) + receive_message(daemon_fd, (char *)buf, sizeof(*buf)); + + /* Free all resources specific to a shmid in IPC_RMID case. */ + if (ret == 0 && cmd == IPC_RMID) + shmremove(shmid); + + errno = ret; +done: + SYSV_MUTEX_UNLOCK(&lock_resources); + return (ret == 0 ? 0 : -1); +} + +/* Functionality of shmdt with the possibility to inform or not + * the daemon. + * Inform the daemon when shmdt is called and not when an error + * occurs and the daemon doesn't know that the process is attaced. + */ +static int +_shmdt(const void *shmaddr, int send_to_daemon) { + int ret; + size_t size; + struct shm_data *data; + + ret = -1; + + SYSV_MUTEX_LOCK(&lock_resources); + if (!is_shm_started()) { + errno = EINVAL; + goto done; + } + + /* Verify if shmaddr was returned from a shmat call. */ + data = _hash_remove(shmaddrs, (u_long)shmaddr); + if (data == NULL) { + errno = EINVAL; + goto done; + } + + size = round_page(data->size); + + ret = munmap(__DECONST(void *, shmaddr), size); + if (ret) + goto done; + + if (send_to_daemon) + send_message(daemon_fd, SHMDT, (char *)&data->shmid, sizeof(int)); + + shmaddr = NULL; + free(data); + data = NULL; +done: + SYSV_MUTEX_UNLOCK(&lock_resources); + return (ret); +} + +int +sysvipc_shmdt(const void *shmaddr) { + return (_shmdt(shmaddr, 1)); +} + +void +shmchild(void) { + int i; + struct entries_list *list; + struct hashentry *tmp, *ttmp; + struct shmat_msg msg; + struct shm_data *data; + int error; + +/* OBS: no locking is necessary because this function is called + * after the child is created and at that moment only one thread + * exists in the process. + */ + for (i=0; ientries[i]; + if (LIST_EMPTY(list)) + continue; + LIST_FOREACH_MUTABLE(tmp, list, entry_link, ttmp) { + data = (struct shm_data*)tmp->value; + /* Inform daemon that we are attached. */ + + if (data->type == UNDOGET) { + continue; + } + + msg.shmid = data->shmid; + msg.shmaddr = data->internal; + msg.shmflg = 0; /* This is enough at this moment. */ + msg.size = data->size; + /* Last field is not necessary because it is used only + * for undo segments. + */ + + send_message(daemon_fd, SHMAT, (char *)&msg, sizeof(msg)); + receive_message(daemon_fd, (char *)&error, sizeof(error)); + + /* If the daemon returned error munmap the region. */ + if (error) { + errno = error; + _shmdt(data->internal, 0); + shmremove(data->shmid); + sysv_print_err(" %d shmchild\n", error); + sleep(20); + } + + } + } + + /* Remove semundo structures. Those are specific only for the parent. + * The child must create for itself a new one. + */ + data = _hash_remove(shmaddrs, (u_long)undos); + if (undos) { + munmap(undos, round_page(data->size)); + undos = NULL; + } +} + +/* Called each time a thread tries to access the sem/msg. + * It is used in order to protect data against its removal + * by another thread. + */ +struct shm_data* +get_shmdata(int id, int to_remove, int shm_access) { + struct shm_data *data = NULL; + + SYSV_MUTEX_LOCK(&lock_resources); + if (!is_shm_started()) { + errno = EINVAL; + goto done; + } + + data = _hash_lookup(shmres, id); + if (!data) { + errno = EINVAL; + goto done; + } + + /* If segment was removed by another thread we can't use it. */ + if (data->removed) { + sysv_print("segment already removed\n"); + errno = EINVAL; + data = NULL; + goto done; + } + + /* Mark for removal. Inform the other threads from the + * same address space. */ + if (to_remove) { + sysv_print("segment is removed\n"); + data->removed = to_remove; /* 1 if it is removed by + the current process and 2 if it was removed by + another one. */ + + /* No need for any rights check because this is + * done by daemon if this is the process that removes + * the sem/msg. + * If not, there is no need for any right to clean + * internal resources. + */ + goto done2; + } + + /* Avoid segmentation fault if the memory zone + * is accessed without necessary permissions + * (it was mapped according to them). + */ + if (!(data->access & shm_access)) { +#if 0 + sysv_print("no access rights has %o and wants %o\n", + data->access, shm_access); + errno = EACCES; + data = NULL; + goto done; +#endif + } + +done2: + data->used++; +done: + SYSV_MUTEX_UNLOCK(&lock_resources); + return (data); +} + +/* Set the shm_access type (IPC_R, IPC_W) for sem/msg. */ +int +set_shmdata_access(int id, int shm_access) { + struct shm_data *data; + int ret = -1; + + SYSV_MUTEX_LOCK(&lock_resources); + if (!is_shm_started()) { + errno = EINVAL; + goto done; + } + + data = _hash_lookup(shmres, id); + if (!data) { + errno = EINVAL; + goto done; + } + + /* If segment was removed by another thread we can't use it. */ + if (data->removed) { + errno = EINVAL; + goto done; + } + + data->access = shm_access; + ret = 0; +done: + SYSV_MUTEX_UNLOCK(&lock_resources); + + return (ret); +} diff --git a/lib/libc/sysvipc/sockets.c b/lib/libc/sysvipc/sockets.c new file mode 100644 index 0000000000..ec95e59116 --- /dev/null +++ b/lib/libc/sysvipc/sockets.c @@ -0,0 +1,335 @@ +/** + * Copyright (c) 2013 Larisa Grigore. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysvipc_utils.h" +#include "sysvipc_sockets.h" + +#define MAX_CONN 10 + +int +init_socket(const char *sockfile) +{ + struct sockaddr_un un_addr; + int sock; + + /* create server socket */ + if ( (sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + sysv_print_err("init socket"); + return (-1); + } + + /* bind it */ + memset(&un_addr, 0, sizeof(un_addr)); + un_addr.sun_len = sizeof(un_addr); + un_addr.sun_family = AF_UNIX; + strcpy(un_addr.sun_path, sockfile); + + unlink(un_addr.sun_path); + + if (bind(sock, (struct sockaddr *)&un_addr, sizeof(un_addr)) < 0) { + close(sock); + sysv_print_err("bind"); + return (-1); + } + + if (listen(sock, MAX_CONN) < 0) { + close(sock); + sysv_print_err("listen"); + return (-1); + } + + /* turn on credentials passing */ + return (sock); +} + +int +handle_new_connection(int sock) +{ + int fd, flags; + + do { + fd = accept(sock, NULL, NULL); + } while (fd < 0 && errno == EINTR); + + if (fd < 0) { + sysv_print_err("accept"); + return (-1); + } + + flags = fcntl(fd, F_GETFL, 0); + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + + return (fd); +} + +int +connect_to_daemon(const char *sockfile) +{ + int sock, flags; + struct sockaddr_un serv_addr; + + if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) { + sysv_print_err("socket(%d)\n", sock); + return (-1); + } + + flags = fcntl(sock, F_GETFL, 0); + fcntl(sock, F_SETFL, flags & ~O_NONBLOCK); + + memset(&serv_addr, 0, sizeof(serv_addr)); + serv_addr.sun_family = AF_UNIX; + strcpy(serv_addr.sun_path, sockfile); + + if (connect(sock, (struct sockaddr *)&serv_addr, + sizeof(serv_addr)) < 0) { + close(sock); + sysv_print_err("connect(%d)\n", sock); + return (-1); + } + + return (sock); +} + +int +send_fd(int sock, int fd) +{ + struct msghdr msg; + struct iovec vec; +#ifndef HAVE_ACCRIGHTS_IN_MSGHDR + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + struct cmsghdr *cmsg; +#endif + int result = 0; + ssize_t n; + + memset(&msg, 0, sizeof(msg)); + + if (fd < 0) + result = errno; + else { +#ifdef HAVE_ACCRIGHTS_IN_MSGHDR + msg.msg_accrights = (caddr_t)&fd; + msg.msg_accrightslen = sizeof(fd); +#else + msg.msg_control = (caddr_t)cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_len = CMSG_LEN(sizeof(int)); + cmsg->cmsg_level = SOL_SOCKET; + cmsg->cmsg_type = SCM_RIGHTS; + *(int *)CMSG_DATA(cmsg) = fd; +#endif + } + + vec.iov_base = (caddr_t)&result; + vec.iov_len = sizeof(int); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + + if ((n = sendmsg(sock, &msg, 0)) == -1) { + sysv_print_err("sendmsg(%d)\n", + sock, getpid()); + return (-1); + } + if (n != sizeof(int)) { + sysv_print_err("sendmsg: expected sent 1 got %ld\n", + (long)n); + return (-1); + } + + return (0); +} + +/**/ +int +receive_fd(int sock) +{ + struct msghdr msg; + struct iovec vec; +#ifndef HAVE_ACCRIGHTS_IN_MSGHDR + union { + struct cmsghdr hdr; + char buf[CMSG_SPACE(sizeof(int))]; + } cmsgbuf; + struct cmsghdr *cmsg; +#endif + ssize_t n; + int result; + int fd; + + memset(&msg, 0, sizeof(msg)); + vec.iov_base = (caddr_t)&result; + vec.iov_len = sizeof(int); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + +#ifdef HAVE_ACCRIGHTS_IN_MSGHDR + msg.msg_accrights = (caddr_t)&fd; + msg.msg_accrightslen = sizeof(fd); +#else + msg.msg_control = &cmsgbuf.buf; + msg.msg_controllen = sizeof(cmsgbuf.buf); +#endif + + if ((n = recvmsg(sock, &msg, 0)) == -1) + sysv_print_err("recvmsg\n"); + if (n != sizeof(int)) { + sysv_print_err("recvmsg: expected received 1 got %ld\n", + (long)n); + } + if (result == 0) { + cmsg = CMSG_FIRSTHDR(&msg); + if (cmsg == NULL) { + sysv_print_err("no message header\n"); + return (-1); + } + if (cmsg->cmsg_type != SCM_RIGHTS) + sysv_print_err("expected type %d got %d\n", + SCM_RIGHTS, cmsg->cmsg_type); + + fd = (*(int *)CMSG_DATA(cmsg)); + return (fd); + } else { + errno = result; + return (-1); + } +} + +static void +close_fds(int *fds, int num_fds) { + int i; + + for (i=0; i < num_fds; i++) + close(fds[i]); +} + +/* Send with the message, credentials too. */ +int +send_msg_with_cred(int sock, char *buffer, size_t size) { + struct msghdr msg; + struct iovec vec; + ssize_t n; + + struct { + struct cmsghdr hdr; + char cred[CMSG_SPACE(sizeof(struct cmsgcred))]; + } cmsg; + + memset(&cmsg, 0, sizeof(cmsg)); + cmsg.hdr.cmsg_len = CMSG_LEN(sizeof(struct cmsgcred)); + cmsg.hdr.cmsg_level = SOL_SOCKET; + cmsg.hdr.cmsg_type = SCM_CREDS; + + memset(&msg, 0, sizeof(struct msghdr)); + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + msg.msg_control = (caddr_t)&cmsg; + msg.msg_controllen = CMSG_SPACE(sizeof(struct cmsgcred)); + + vec.iov_base = buffer; + vec.iov_len = size; + + if ((n = sendmsg(sock, &msg, 0)) == -1) { + sysv_print_err("sendmsg on fd %d\n", sock); + return (-1); + } + + return (0); +} + +/* Receive a message and the credentials of the sender. */ +int +receive_msg_with_cred(int sock, char *buffer, size_t size, + struct cmsgcred *cred) { + struct msghdr msg = {0}; + struct iovec vec; + ssize_t n; + int result; + struct cmsghdr *cmp; + struct { + struct cmsghdr hdr; + char cred[CMSG_SPACE(sizeof(struct cmsgcred))]; + } cmsg; + + memset(&msg, 0, sizeof(msg)); + vec.iov_base = buffer; + vec.iov_len = size; + msg.msg_iov = &vec; + msg.msg_iovlen = 1; + + msg.msg_control = &cmsg; + msg.msg_controllen = sizeof(cmsg); + + do { + n = recvmsg(sock, &msg, 0); + } while (n < 0 && errno == EINTR); + + if (n < 0) { + sysv_print_err("recvmsg on fd %d\n", sock); + return (-1); + } + + if (n == 0) { + return (-1); + } + + result = -1; + cmp = CMSG_FIRSTHDR(&msg); + + while(cmp != NULL) { + if (cmp->cmsg_level == SOL_SOCKET + && cmp->cmsg_type == SCM_CREDS) { + if (cred) + memcpy(cred, CMSG_DATA(cmp), sizeof(*cred)); + result = n; + } else if (cmp->cmsg_level == SOL_SOCKET + && cmp->cmsg_type == SCM_RIGHTS) { + close_fds((int *) CMSG_DATA(cmp), + (cmp->cmsg_len - CMSG_LEN(0)) + / sizeof(int)); + } + cmp = CMSG_NXTHDR(&msg, cmp); + } + + return (result); +} diff --git a/lib/libc/sysvipc/sysvipc_hash.c b/lib/libc/sysvipc/sysvipc_hash.c new file mode 100644 index 0000000000..ad3417ba7d --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_hash.c @@ -0,0 +1,143 @@ +/*- + * Copyright (c) 2013 Larisa Grigore + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include + +#include "sysvipc_hash.h" + +struct hashtable * +_hash_init(int nr_elems) { + long hashsize; + struct hashtable *hashtable; + int i; + + if (nr_elems <= 0) + return NULL; + for (hashsize = 2; hashsize < nr_elems; hashsize <<= 1) + continue; + + hashtable = malloc(sizeof(struct hashtable)); + if (!hashtable) { + return NULL; + } + + hashtable->entries = malloc(hashsize * sizeof(struct entries_list)); + if (!hashtable->entries) { + free(hashtable); + hashtable = NULL; + goto out; + } + + hashtable->nr_elems = hashsize; + + for (i = 0; i < hashsize; i++) + LIST_INIT(&hashtable->entries[i]); + +out: + return hashtable; +} + +int +_hash_destroy(struct hashtable *hashtable) { + struct entries_list *tmp; + u_long hashmask = hashtable->nr_elems -1; + + for (tmp = &hashtable->entries[0]; tmp <= &hashtable->entries[hashmask]; tmp++) { + if (!LIST_EMPTY(tmp)) + return -1; + } + free(hashtable->entries); + free(hashtable); + hashtable = NULL; + return 0; +} + +void +_hash_insert(struct hashtable *hashtable, + u_long key, + void *value) { + + u_long hashmask = hashtable->nr_elems -1; + struct entries_list *list = + &hashtable->entries[key & hashmask]; + struct hashentry *new_entry = malloc(sizeof(struct hashentry)); + new_entry->value = value; + new_entry->key = key; + LIST_INSERT_HEAD(list, new_entry, entry_link); +} + +void * +_hash_lookup(struct hashtable *hashtable, u_long key) { + + u_long hashmask = hashtable->nr_elems -1; + struct entries_list *list = + &hashtable->entries[key & hashmask]; + struct hashentry *tmp; + + LIST_FOREACH(tmp, list, entry_link) { + if (tmp->key == key) { + return tmp->value; + } + } + + return NULL; +} + +void * +_hash_remove(struct hashtable *hashtable, + u_long key) { + + void *value; + u_long hashmask = hashtable->nr_elems -1; + struct entries_list *list = + &hashtable->entries[key & hashmask]; + struct hashentry *tmp; + + LIST_FOREACH(tmp, list, entry_link) { + if (tmp->key == key) + goto done; + } + + return NULL; + +done: + LIST_REMOVE(tmp, entry_link); + value = tmp->value; + free(tmp); + return value; +} + +int +get_hash_size(int nr_elems) { + long hashsize = 0; + + for (hashsize = 2; hashsize < nr_elems; hashsize <<= 1) + continue; + + return hashsize; +} diff --git a/lib/libc/sysvipc/sysvipc_hash.h b/lib/libc/sysvipc/sysvipc_hash.h new file mode 100644 index 0000000000..5c043c5a71 --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_hash.h @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2013 Larisa Grigore. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +struct hashentry { + u_long key; + void * value; + LIST_ENTRY(hashentry) entry_link; +}; + +LIST_HEAD(entries_list, hashentry); + +struct hashtable { + int nr_elems; + struct entries_list *entries; +}; + +struct hashtable * _hash_init(int); +int _hash_destroy(struct hashtable *); +void _hash_insert(struct hashtable *, u_long, void *); +void *_hash_lookup(struct hashtable *, u_long); +void *_hash_remove(struct hashtable *, u_long); +int get_hash_size(int); diff --git a/lib/libc/sysvipc/sysvipc_ipc.h b/lib/libc/sysvipc/sysvipc_ipc.h new file mode 100644 index 0000000000..e5ce359b2c --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_ipc.h @@ -0,0 +1,105 @@ +/** + * Copyright (c) 2013 Larisa Grigore. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYSV_IPC_H_ +#define _SYSV_IPC_H_ + +#define MAXSIZE 100 + +#define IPC_INITIALIZED 1 + +#define SHMGET 1 +#define SEMGET 2 +#define MSGGET 3 +#define UNDOGET 4 + +#define SHMAT 5 +#define SHMDT 6 +#define SHMCTL 7 + +#define SEMOP 8 +#define SEMCTL 9 + +#define PIPE_READ 0 +#define PIPE_WRITE 1 + +#define IPCID_TO_IX(id) ((id) & 0xffff) +#define IPCID_TO_SEQ(id) (((id) >> 16) & 0xffff) +#define IXSEQ_TO_IPCID(ix,perm) (((perm.seq) << 16) | (ix & 0xffff)) + +#include +#include "sysvipc_utils.h" + +/* Structures used to send/receive + * messages to/from daemon. + */ +struct shmget_msg { + key_t key; + size_t size; + int shmflg; + int type; +}; + +struct shmat_msg { + int shmid; + const void *shmaddr; + int shmflg; + size_t size; +}; + +struct shmdt_msg { + const void *shmaddr; +}; + +struct shmctl_msg { + int shmid; + int cmd; + struct shmid_ds buf; +}; + +struct sysvipc_msg { + int type; + char data[0]; +}; + +struct semget_msg { + key_t key; + int nsems; + int shmflg; +}; + +/* Send/receive messages. */ +int send_message(int, int, char *, int); +int receive_type_message(int); +int receive_message(int, char *, int); + +/* sysv ipc structures initialization. */ +int is_sysvinit(void); +int sysvinit(void); +int sysvexit(void); + +#endif diff --git a/lib/libc/sysvipc/sysvipc_lock.h b/lib/libc/sysvipc/sysvipc_lock.h new file mode 100644 index 0000000000..3385ccc0c5 --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_lock.h @@ -0,0 +1,59 @@ +/** + * Copyright (c) 2013 Larisa Grigore. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYSV_DFLY_UMTX_GEN_H_ +#define _SYSV_DFLY_UMTX_GEN_H_ + +#include "sysvipc_lock_generic.h" + +#define SYSV_RWLOCK + +struct sysv_mutex { + umtx_t _mutex_static_lock; + int pid_owner; + int tid_owner; +}; + +struct sysv_rwlock { + struct sysv_mutex lock; /* monitor lock */ + int read_signal; + int write_signal; + int state; /* 0 = idle >0 = # of readers -1 = writer */ + int blocked_writers; +}; + +int sysv_mutex_init(struct sysv_mutex *); +int sysv_mutex_lock(struct sysv_mutex *); +int sysv_mutex_unlock(struct sysv_mutex *); + +int sysv_rwlock_init(struct sysv_rwlock *); +int sysv_rwlock_unlock(struct sysv_rwlock *); +int sysv_rwlock_wrlock(struct sysv_rwlock *); +int sysv_rwlock_rdlock(struct sysv_rwlock *); + +#endif + diff --git a/lib/libc/sysvipc/sysvipc_lock_generic.h b/lib/libc/sysvipc/sysvipc_lock_generic.h new file mode 100644 index 0000000000..3c5f43391b --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_lock_generic.h @@ -0,0 +1,65 @@ +/*- + * Copyright (c) 2003 David Xu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $DragonFly: src/lib/libthread_xu/thread/thr_umtx.h,v 1.5 2008/04/14 20:12:41 dillon Exp $ + * $DragonFly: src/lib/libsysvipc/lock_generic.h,v 1 2013/09/20 Larisa Grigore + */ + +#ifndef _SYSV_DFLY_UMTX_H_ +#define _SYSV_DFLY_UMTX_H_ + +#include +#include + +#define SYSV_TIMEOUT 4000 + +typedef int umtx_t; + +int __sysv_umtx_lock(volatile umtx_t *mtx, int timo); +void __sysv_umtx_unlock(volatile umtx_t *mtx); + +static inline void +_sysv_umtx_init(volatile umtx_t *mtx) +{ + *mtx = 0; +} + +static inline int +_sysv_umtx_lock(volatile umtx_t *mtx) +{ + if (atomic_cmpset_acq_int(mtx, 0, 1)) + return (0); + return (__sysv_umtx_lock(mtx, 0)); +} + +static inline void +_sysv_umtx_unlock(volatile umtx_t *mtx) +{ + if (atomic_cmpset_acq_int(mtx, 1, 0)) + return; + __sysv_umtx_unlock(mtx); +} + +#endif diff --git a/lib/libc/sysvipc/sysvipc_msg.h b/lib/libc/sysvipc/sysvipc_msg.h new file mode 100644 index 0000000000..998827cd92 --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_msg.h @@ -0,0 +1,126 @@ +/* $FreeBSD: src/sys/kern/sysv_msg.c,v 1.23.2.5 2002/12/31 08:54:53 maxim Exp $ */ + +/* + * Implementation of SVID messages + * + * Author: Daniel Boulet + * + * Copyright 1993 Daniel Boulet and RTMX Inc. + * Copyright (c) 2013 Larisa Grigore + * + * This system call was implemented by Daniel Boulet under contract from RTMX. + * + * Redistribution and use in source forms, with and without modification, + * are permitted provided that this entire comment appears intact. + * + * Redistribution in binary form may occur without any restrictions. + * Obviously, it would be nice if you gave credit where credit is due + * but requiring it would be too onerous. + * + * This software is provided ``AS IS'' without any warranties of any kind. + */ + +#ifndef _SYSV_MSG_H_ +#define _SYSV_MSG_H_ + +#include +#include "sysvipc_lock.h" +#include "sysvipc_lock_generic.h" + +struct msg { + short msg_next; /* next msg in the chain */ + long msg_type; /* type of this message */ + /* >0 -> type of this message */ + /* 0 -> free header */ + u_short msg_ts; /* size of this message */ + short msg_spot; /* location of start of msg in buffer */ +}; + +/* Intarnal structure defined to keep compatbility with + * th kernel implementation. + */ +struct msqid_ds_internal { + struct ipc_perm msg_perm; /* msg queue permission bits */ + union { + struct msg *msg_first; + int msg_first_index; + } first; + union { + struct msg *msg_last; + int msg_last_index; + } last; + u_long msg_cbytes; /* number of bytes in use on the queue */ + u_long msg_qnum; /* number of msgs in the queue */ + u_long msg_qbytes; /* max # of bytes on the queue */ + pid_t msg_lspid; /* pid of last msgsnd() */ + pid_t msg_lrpid; /* pid of last msgrcv() */ + time_t msg_stime; /* time of last msgsnd() */ + long msg_pad1; + time_t msg_rtime; /* time of last msgrcv() */ + long msg_pad2; + time_t msg_ctime; /* time of last msgctl() */ + long msg_pad3; + long msg_pad4[4]; +}; + +#ifndef MSGSSZ +#define MSGSSZ 8 /* Each segment must be 2^N long */ +#endif +#ifndef MSGSEG +#define MSGSEG 256 /* must be calculated such that all + structure fits in PAGE_SIZE. */ +#endif +#define MSGMAX (MSGSSZ*MSGSEG) +#ifndef MSGMNB +#define MSGMNB 2048 /* max # of bytes in a queue */ +#endif +#ifndef MSGMNI +#define MSGMNI 40 +#endif +#ifndef MSGTQL +#define MSGTQL 10//40 +#endif + + /* Each message is broken up and stored in segments that are msgssz bytes + * long. For efficiency reasons, this should be a power of two. Also, + * it doesn't make sense if it is less than 8 or greater than about 256. + * Consequently, msginit in kern/sysv_msg.c checks that msgssz is a power of + * two between 8 and 1024 inclusive (and panic's if it isn't). + */ +struct msginfo { + int msgmax, /* max chars in a message */ + msgmni, /* max message queue identifiers */ + msgmnb, /* max chars in a queue */ + msgtql, /* max messages in system */ + msgssz, /* size of a message segment (see notes above) */ + msgseg; /* number of message segments */ +}; + +struct msgmap { + short next; /* next segment in buffer */ + /* -1 -> available */ + /* 0..(MSGSEG-1) -> index of next segment */ +}; + +struct msqid_pool { +#ifdef SYSV_RWLOCK + struct sysv_rwlock rwlock; +#else + struct sysv_mutex mutex; +#endif + struct msqid_ds_internal ds; + char gen; + int nfree_msgmaps; /* # of free map entries */ + short free_msgmaps; /* head of linked list of free map entries */ + short free_msghdrs;/* list of free msg headers */ + struct msg msghdrs[MSGTQL]; /* MSGTQL msg headers */ + struct msgmap msgmaps[MSGSEG]; /* MSGSEG msgmap structures */ + char msgpool[MSGMAX]; /* MSGMAX byte long msg buffer pool */ +}; + +int sysvipc_msgctl (int, int, struct msqid_ds *); +int sysvipc_msgget (key_t, int); +int sysvipc_msgsnd (int, void *, size_t, int); +int sysvipc_msgrcv (int, void*, size_t, long, int); + +#endif /* !_SYSV_MSG_H_ */ diff --git a/lib/libc/sysvipc/sysvipc_sem.h b/lib/libc/sysvipc/sysvipc_sem.h new file mode 100644 index 0000000000..b3471c5e7e --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_sem.h @@ -0,0 +1,79 @@ +/* $FreeBSD: src/sys/kern/sysv_sem.c,v 1.69 2004/03/17 09:37:13 cperciva Exp $ */ + +/* + * Implementation of SVID semaphores + * + * Author: Daniel Boulet + * Copyright (c) 2013 Larisa Grigore + * + * This software is provided ``AS IS'' without any warranties of any kind. + */ + +#ifndef _SYSV_SEM_H_ +#define _SYSV_SEM_H_ + +#include + +#include "sysvipc_lock.h" +#include "sysvipc_lock_generic.h" + +//#define SYSV_SEMS + /* Used to define if each semaphore in the + * set is protected by a mutex, the entire + * group being protected by a read lock. + * If SYSV_SEMS is not defined, then the entire + * group is protected only by a write lock. + */ +struct sem { + u_short semval; /* semaphore value */ + pid_t sempid; /* pid of last operation */ + u_short semncnt; /* # awaiting semval > cval */ + u_short semzcnt; /* # awaiting semval = 0 */ +#ifdef SYSV_SEMS + struct sysv_mutex sem_mutex; +#endif +}; + +/* Used internally. The struct semid_ds is used only + * by caller, as argument to semctl. + */ +struct semid_ds_internal { + struct ipc_perm sem_perm; /* operation permission struct */ + u_short sem_nsems; /* number of sems in set */ + time_t sem_otime; /* last operation time */ + time_t sem_ctime; /* last change time */ + /* Times measured in secs since */ + /* 00:00:00 GMT, Jan. 1, 1970 */ + struct sem sem_base[0]; /* pointer to first semaphore in set */ +}; + +struct semid_pool { +#ifdef SYSV_RWLOCK + struct sysv_rwlock rwlock; +#else + struct sysv_mutex mutex; +#endif + struct semid_ds_internal ds; + char gen; +}; + +/* + * Undo structure (one per process) + */ +struct sem_undo { +// pthread_rwlock_t un_lock; + int un_pages; + short un_cnt; /* # of active entries */ + short un_unused; + struct undo { + short un_adjval; /* adjust on exit values */ + short un_num; /* semaphore # */ + int un_id; /* semid */ + } un_ent[0]; /* undo entries */ +}; + +int sysvipc_semctl (int, int, int, union semun); +int sysvipc_semget (key_t, int, int); +int sysvipc_semop (int, struct sembuf *, unsigned); + +#endif /* !_SEM_H_ */ diff --git a/lib/libc/sysvipc/sysvipc_shm.h b/lib/libc/sysvipc/sysvipc_shm.h new file mode 100644 index 0000000000..371978f2f0 --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_shm.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2013 Larisa Grigore . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Glass and Charles + * Hannum. + * 4. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYSV_SHM_H_ +#define _SYSV_SHM_H_ + +#include + +/* This flag is used to mark a semaphore group + * as removed by another process. + */ +#define SEG_ALREADY_REMOVED 2 + +struct shm_data { + int fd; /* The file descriptor of the file used as + shared memory. */ + size_t size; + int shmid; + int type; /* shm, sem, msg or undo; + undo segments are used for semops with UNDO flag set. */ + void *internal; + int used; /* Number of thread that use this segment. */ + int removed; /* The segment was mark for removal by a thread. */ + int access; /* Used only for sems to avoid a segfault when try to + access a semaphore wthout permission. */ +}; + +int _shmget(key_t, size_t, int, int); +void shmchild(void); + +int sysvipc_shmget (key_t, size_t, int); +int sysvipc_shmctl (int, int, struct shmid_ds *); +void *sysvipc_shmat (int, const void *, int); +int sysvipc_shmdt (const void *); + +struct shm_data *get_shmdata(int, int, int); +int set_shmdata_access(int, int); + +#endif /* !_SYSV_SHM_H_ */ diff --git a/lib/libc/sysvipc/sysvipc_sockets.h b/lib/libc/sysvipc/sysvipc_sockets.h new file mode 100644 index 0000000000..d34024c8d2 --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_sockets.h @@ -0,0 +1,44 @@ +/** + * Copyright (c) 2013 Larisa Grigore. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYSV_SOCK_H_ +#define _SYSV_SOCK_H_ + +#include + +#define LISTEN_SOCKET_FILE "/var/run/sysvipc/sysvipc_socket" + +int init_socket(const char *); +int handle_new_connection(int); +int connect_to_daemon(const char *); + +int send_msg_with_cred(int, char *, size_t); +int receive_msg_with_cred(int, char *, size_t, struct cmsgcred *); + +int send_fd(int, int); +int receive_fd(int); + +#endif diff --git a/lib/libc/sysvipc/sysvipc_utils.h b/lib/libc/sysvipc/sysvipc_utils.h new file mode 100644 index 0000000000..d42e6790eb --- /dev/null +++ b/lib/libc/sysvipc/sysvipc_utils.h @@ -0,0 +1,35 @@ +/** + * Copyright (c) 2013 Larisa Grigore. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _SYSV_UTILS_H_ +#define _SYSV_UTILS_H_ + +/* Print wrappers. */ +void sysv_print_err(const char *fmt, ...); +void sysv_print(const char *fmt, ...); + +#endif diff --git a/lib/libc/sysvipc/utils.c b/lib/libc/sysvipc/utils.c new file mode 100644 index 0000000000..6d2a092e0b --- /dev/null +++ b/lib/libc/sysvipc/utils.c @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2013 Larisa Grigore. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "sysvipc_utils.h" + +//#define SYSV_DEBUG +#ifdef SYSV_DEBUG +void +sysv_print(const char *fmt, ...) { + va_list ap; + char format[50]; + + sprintf(format, "[%d %d] %s", + getpid(), lwp_gettid(), fmt); + va_start(ap, fmt); + vprintf(format, ap); + va_end(ap); + fflush(stdout); +} +#else +void +sysv_print(const char *fmt, ...) {} +#endif + +void +sysv_print_err(const char *fmt, ...) { + va_list ap; + char format[50]; + + sprintf(format, "[%d %d] error(%d): %s", + getpid(), lwp_gettid(), errno, fmt); + va_start(ap, fmt); + vprintf(format, ap); + va_end(ap); +} diff --git a/lib/libc/x86_64/sys/Makefile.inc b/lib/libc/x86_64/sys/Makefile.inc index 4ba301a47c..c7f42e1e62 100644 --- a/lib/libc/x86_64/sys/Makefile.inc +++ b/lib/libc/x86_64/sys/Makefile.inc @@ -9,7 +9,8 @@ MDASM= vfork.S brk.S cerror.S exect.S getcontext.S pipe.S ptrace.S \ # Don't generate default code for these syscalls: NOASM= break.o exit.o ftruncate.o getdomainname.o getlogin.o \ lseek.o mmap.o openbsd_poll.o pread.o \ - pwrite.o setdomainname.o sstk.o truncate.o uname.o vfork.o yield.o + pwrite.o setdomainname.o sstk.o truncate.o uname.o vfork.o yield.o \ + fork.o PSEUDO= _getlogin.o _exit.o diff --git a/lib/libthread_xu/thread/thr_fork.c b/lib/libthread_xu/thread/thr_fork.c index 9079997c9b..b1d2a007ae 100644 --- a/lib/libthread_xu/thread/thr_fork.c +++ b/lib/libthread_xu/thread/thr_fork.c @@ -58,6 +58,8 @@ */ #include "namespace.h" +#include + #include #include @@ -139,7 +141,7 @@ _fork(void) #endif if (!_thr_is_inited()) - return (__sys_fork()); + return (__syscall(SYS_fork)); curthread = tls_get_curthread(); @@ -182,7 +184,7 @@ _fork(void) _thr_signal_block(curthread); /* Fork a new process: */ - if ((ret = __sys_fork()) == 0) { + if ((ret = __syscall(SYS_fork)) == 0) { /* Child process */ errsave = errno; inprogress = 0; diff --git a/lib/libthread_xu/thread/thr_private.h b/lib/libthread_xu/thread/thr_private.h index 64aabcb743..f615db2d7f 100644 --- a/lib/libthread_xu/thread/thr_private.h +++ b/lib/libthread_xu/thread/thr_private.h @@ -754,7 +754,6 @@ int __sys_nanosleep(const struct timespec *, struct timespec *); #ifdef _UNISTD_H_ int __sys_close(int); int __sys_execve(const char *, char * const *, char * const *); -int __sys_fork(void); int __sys_fsync(int); pid_t __sys_getpid(void); int __sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *); diff --git a/sys/dev/misc/sysvipc/Makefile b/sys/dev/misc/sysvipc/Makefile new file mode 100644 index 0000000000..4f6728b607 --- /dev/null +++ b/sys/dev/misc/sysvipc/Makefile @@ -0,0 +1,4 @@ +KMOD= sysvipc +SRCS= sysvipc.c + +.include diff --git a/sys/dev/misc/sysvipc/sysvipc.c b/sys/dev/misc/sysvipc/sysvipc.c new file mode 100644 index 0000000000..e5498b3013 --- /dev/null +++ b/sys/dev/misc/sysvipc/sysvipc.c @@ -0,0 +1,478 @@ +/* + * Copyright (c) 2013 Larisa Grigore . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +static cdev_t sysvipc_dev; +static d_open_t sysvipc_dev_open; +static d_close_t sysvipc_dev_close; +//static d_read_t sysvipc_dev_read; +//static d_write_t sysvipc_dev_write; +static d_ioctl_t sysvipc_dev_ioctl; +static d_kqfilter_t sysvipc_dev_kqfilter; + +static struct dev_ops sysvipc_dev_ops = { + { "sysv", 0, 0 }, + .d_open = sysvipc_dev_open, + .d_close = sysvipc_dev_close, + .d_ioctl = sysvipc_dev_ioctl, + .d_kqfilter = sysvipc_dev_kqfilter, +}; + +struct sysvipc_req { + struct proc *proc; + int fd[2]; + TAILQ_ENTRY(sysvipc_req) req_link; +}; + +TAILQ_HEAD(_req_list, sysvipc_req); + +struct sysvipc_softc { + cdev_t sysvipc_dev; + struct kqinfo sysvipc_rkq; + int opened; + struct _req_list consumed_list; + struct _req_list req_list; + struct lock consumed_mtx; + struct lock req_mtx; + struct thread *sysvipc_daemon_thread; +}; + +static int +sysvipc_register(cdev_t dev) +{ + struct sysvipc_softc *sysv; + + if (dev->si_drv1 != NULL) + return (EEXIST); + + kprintf("aloc sysv\n"); + dev->si_drv1 = sysv = (struct sysvipc_softc *) + kmalloc(sizeof(*sysv), M_TEMP, + M_ZERO | M_WAITOK); + sysv->sysvipc_dev = dev; + TAILQ_INIT(&sysv->req_list); + TAILQ_INIT(&sysv->consumed_list); + lockinit(&sysv->req_mtx, "sysvlkr", 0, LK_CANRECURSE); + lockinit(&sysv->consumed_mtx, "sysvlkc", 0, LK_CANRECURSE); + sysv->sysvipc_daemon_thread = curthread; + + return 0; +} + +static int +sysvipc_unregister(cdev_t dev) +{ + struct sysvipc_softc *sysv = dev->si_drv1; + + kfree(sysv, M_TEMP); + dev->si_drv1 = NULL; + + return 0; +} + +/* + * dev stuff + */ +static int +sysvipc_dev_open(struct dev_open_args *ap) +{ + return 0; +} + +static int +sysvipc_dev_close(struct dev_close_args *ap) +{ + return 0; +} + +static void filt_sysvipc_detach(struct knote *); +static int filt_sysvipc_read(struct knote *, long); + +static struct filterops sysvipc_read_filtops = + { FILTEROP_ISFD, NULL, filt_sysvipc_detach, filt_sysvipc_read }; + +static int +sysvipc_dev_kqfilter(struct dev_kqfilter_args *ap) +{ + cdev_t dev = ap->a_head.a_dev; + struct knote *kn = ap->a_kn; + struct sysvipc_softc *sysv = dev->si_drv1; + struct klist *list; + + if(sysv==NULL){ + kprintf("error read\n"); + return -1; + } + kprintf("kqfilter\n"); + + sysv = dev->si_drv1; + list = &sysv->sysvipc_rkq.ki_note; + ap->a_result =0; + + switch(kn->kn_filter) { + case EVFILT_READ: + kprintf("event read\n"); + kn->kn_fop = &sysvipc_read_filtops; + kn->kn_hook = (void *)sysv; + break; + default: + ap->a_result = EOPNOTSUPP; + return(0); + } + + knote_insert(list, kn); + return(0); + +} + +/* TODO: kernel panic at line 181. it is called after unregister_daemon.*/ +static void +filt_sysvipc_detach(struct knote *kn) +{ + /*kprintf("detach\n"); + if(!kn) + return; + kprintf("detach 1\n"); + + struct sysvipc_softc * sysv = + (struct sysvipc_softc *)kn->kn_hook; + + if(!sysv) + return; + kprintf("detach 2\n"); + + knote_remove(&sysv->sysvipc_rkq.ki_note, kn); + kprintf("end detach\n"); +*/ +} + +static int +filt_sysvipc_read(struct knote *kn, long hint) +{ + struct sysvipc_softc * sysv = + (struct sysvipc_softc *)kn->kn_hook; + int ready = 0; + + //TODO what type of lock should I use?!?! + lockmgr(&sysv->req_mtx, LK_EXCLUSIVE); + ready = !(TAILQ_EMPTY(&sysv->req_list)); + lockmgr(&sysv->req_mtx, LK_RELEASE); + return (ready); +} + +static int +sysvipc_install_fd(struct proc *p_from, struct proc *p_to, int fd) +{ + struct filedesc *fdp_from = p_from->p_fd; + struct filedesc *fdp_to = p_to->p_fd; + + struct file *fp; + int error, newfd; + int flags; + + /* + * Get the file corresponding to fd from the process p_from. + */ + spin_lock(&fdp_from->fd_spin); + if ((unsigned)fd >= fdp_from->fd_nfiles || fdp_from->fd_files[fd].fp == NULL) { + spin_unlock(&fdp_from->fd_spin); + return (EBADF); + } + + fp = fdp_from->fd_files[fd].fp; + flags = fdp_from->fd_files[fd].fileflags; + fhold(fp); /* MPSAFE - can be called with a spinlock held */ + spin_unlock(&fdp_from->fd_spin); + + /* + * Reserve a fd in the process p_to. + */ + error = fdalloc(p_to, 1, &newfd); + if (error) { + fdrop(fp); + return (error); + } + + /* + * Set fd for the fp file. + */ + fsetfd(fdp_to, fp, newfd); + fdp_to->fd_files[newfd].fileflags = flags; + fdrop(fp); + + return (newfd); +} + +static struct sysvipc_req* +sysvipc_find_req(struct _req_list *list, + struct lock *req_mtx, pid_t pid) +{ + struct sysvipc_req *reqtmp; + lockmgr(req_mtx, LK_EXCLUSIVE); + TAILQ_FOREACH(reqtmp, list, req_link) { + if(reqtmp->proc->p_pid == pid) { + lockmgr(req_mtx, LK_RELEASE); + return reqtmp; + } + } + lockmgr(req_mtx, LK_RELEASE); + return NULL; +} + +static int +get_proc_shm_cred(struct proc *p, struct ipc_perm *perm) +{ + struct ucred *cred; + + cred = p->p_ucred; + perm->cuid = perm->uid = cred->cr_uid; + perm->cgid = perm->gid = cred->cr_gid; + + return 1; +} + +static int +sysvipc_dev_ioctl(struct dev_ioctl_args *ap) +{ + int error; + struct client *cl; + struct proc *proc_to, *proc_from; + struct sysvipc_req *req; + cdev_t dev = ap->a_head.a_dev; + struct sysvipc_softc *sysv = dev->si_drv1; + struct client_shm_data *client_data; + + error = 0; + + switch(ap->a_cmd) { + case REGISTER_DAEMON: + kprintf("[driver] register daemon\n"); + sysvipc_register(dev); + break; + case UNREGISTER_DAEMON: + sysvipc_unregister(dev); + break; + case INSTALL_PIPE: + kprintf("[driver] install pipe\n"); + + if(curthread != sysv->sysvipc_daemon_thread) + return (EPERM); + + cl = (struct client *)ap->a_data; + + //kprintf("sysv ipc pid = %d fd 0 = %d fd 1 = %d!\n", + //cl->pid, cl->fd[0], cl->fd[1]); + + if(cl->pid <= 0) + return (EINVAL); + + proc_from = curthread->td_proc; + proc_to = pfind(cl->pid); + + /* Find the request associated with the client. */ + req = sysvipc_find_req(&sysv->consumed_list, + &sysv->consumed_mtx, cl->pid); + if(!req) + return (EINVAL); + + /* Install for the client two file descriptors. + * The first one is used for read and the second one for + * write purpose. + */ + req->fd[0] = sysvipc_install_fd(proc_from, + proc_to, cl->fd[0]); + req->fd[1] = sysvipc_install_fd(proc_from, + proc_to, cl->fd[1]); + PRELE(proc_to); + + /* Wakeup the client. */ + wakeup(req); + + break; + case REGISTER_TO_DAEMON: + + if(sysv == NULL) + return (EEXIST); + + if(curthread == sysv->sysvipc_daemon_thread) + return (EPERM); + + kprintf("[driver] register to daemon\n"); + cl = (struct client *)ap->a_data; + + /* Allocate a struture for the request. */ + req = (struct sysvipc_req*)kmalloc( sizeof(*req), + M_TEMP, M_ZERO | M_WAITOK); + + req->proc = curthread->td_proc; + + /* Add the request to the list used read be daemon. */ + lockmgr(&sysv->req_mtx, LK_EXCLUSIVE); + TAILQ_INSERT_HEAD(&sysv->req_list, req, req_link); + lockmgr(&sysv->req_mtx, LK_RELEASE); + + /* Wake up daemon to process the request. */ + wakeup(sysv); + KNOTE(&sysv->sysvipc_rkq.ki_note, 0); + + /* Wait so that the daemon processes the request and + * installs the two new file descriptors. + */ + tsleep(req, 0, "regist", 0); + + //kprintf("client wake up %d %d\n", req->fd[0], req->fd[1]); + cl->fd[0] = req->fd[0]; + cl->fd[1] = req->fd[1]; + + /* Remove the request from the list of consumed requests. */ + lockmgr(&sysv->consumed_mtx, LK_EXCLUSIVE); + TAILQ_REMOVE(&sysv->consumed_list, req, req_link); + lockmgr(&sysv->consumed_mtx, LK_RELEASE); + + kfree(req, M_TEMP); + break; + case CONSUME_REQUEST: + if(curthread != sysv->sysvipc_daemon_thread) + return (EPERM); + + /* Wait for new requests. */ + lockmgr(&sysv->req_mtx, LK_EXCLUSIVE); + while(TAILQ_EMPTY(&sysv->req_list)) + lksleep(sysv, &sysv->req_mtx, 0, "sysv", 0); + kprintf("wake up to consume request\n"); + + /* Remove the request from the req_list and add it to the + * list of consumed requests. + */ + req = TAILQ_LAST( &sysv->req_list, _req_list); + if(!req) + return (EINVAL); + TAILQ_REMOVE(&sysv->req_list, req, req_link); + lockmgr(&sysv->req_mtx, LK_RELEASE); + + lockmgr(&sysv->consumed_mtx, LK_EXCLUSIVE); + TAILQ_INSERT_HEAD(&sysv->consumed_list, req, req_link); + kprintf("pid received = %d\n", req->proc->p_pid); + *(pid_t *)ap->a_data = req->proc->p_pid; + lockmgr(&sysv->consumed_mtx, LK_RELEASE); + + break; + case INSTALL_FD: + if(curthread != sysv->sysvipc_daemon_thread) + return (EPERM); + + kprintf("[driver] install fd\n"); + client_data = (struct client_shm_data *)ap->a_data; + + /* Get process structure. */ + proc_from = curthread->td_proc; + proc_to = pfind(client_data->pid); + + /* Get client's credentials. */ + //get_proc_shm_cred(proc_to, &client_data->shm_perm); + + /* Install for the client the file descriptor. */ + client_data->fd = sysvipc_install_fd(proc_from, + proc_to, client_data->fd); + + PRELE(proc_to); + + break; + default: + break; + } + + return(error); +} + + +static int +sysvipc_modevent(module_t mod, int type, void *unused) +{ + struct sysvipc_softc *sysv; + + switch (type) { + case MOD_LOAD: + sysvipc_dev = make_dev(&sysvipc_dev_ops, + 0, + UID_ROOT, + GID_WHEEL, + 0600, + "sysvipc"); + + kprintf("sysv ipc driver ready!\n"); + return 0; + + case MOD_UNLOAD: + sysv = sysvipc_dev->si_drv1; + if(sysv != NULL) + sysvipc_unregister(sysvipc_dev); + destroy_dev(sysvipc_dev); + kprintf("sysv ipc driver unloaded.\n"); + return 0; + } + + return EINVAL; +} + +static moduledata_t sysvipc_mod = { + "tessysvipc", + sysvipc_modevent, + 0 +}; + +DECLARE_MODULE(sysvipc, sysvipc_mod, SI_SUB_DRIVERS, SI_ORDER_ANY); +MODULE_VERSION(sysvipc, 1); diff --git a/sys/sys/msg.h b/sys/sys/msg.h index 73cb24431a..7542dc43f5 100644 --- a/sys/sys/msg.h +++ b/sys/sys/msg.h @@ -33,12 +33,18 @@ #define MSG_NOERROR 010000 /* don't complain about too long msgs */ +/*!!! In the kernel implementation, both msg_first and msg_last + * have 'struct msg*' type. + * In the userland implementation, a pointer to a msg is useless + * because each message queue is mapped at different addresses in + * the process space address so my choice was to use indexes. + */ struct msg; struct msqid_ds { struct ipc_perm msg_perm; /* msg queue permission bits */ - struct msg *msg_first; /* first message in the queue */ - struct msg *msg_last; /* last message in the queue */ + struct msg *msg_first; /* first message in the queue. */ + struct msg *msg_last; /* last message in the queue. */ u_long msg_cbytes; /* number of bytes in use on the queue */ u_long msg_qnum; /* number of msgs in the queue */ u_long msg_qbytes; /* max # of bytes on the queue */ diff --git a/sys/sys/shm.h b/sys/sys/shm.h index 1ace4e6dbe..1c9ccbb3d6 100644 --- a/sys/sys/shm.h +++ b/sys/sys/shm.h @@ -96,9 +96,9 @@ void shmfork (struct proc *, struct proc *); __BEGIN_DECLS int shmsys (int, ...); -void *shmat (int, const void *, int); int shmget (key_t, size_t, int); int shmctl (int, int, struct shmid_ds *); +void *shmat (int, const void *, int); int shmdt (const void *); __END_DECLS diff --git a/sys/sys/sysvipc.h b/sys/sys/sysvipc.h new file mode 100644 index 0000000000..a466f94897 --- /dev/null +++ b/sys/sys/sysvipc.h @@ -0,0 +1,39 @@ +#ifndef __PPI_H +#define __PPI_H + +#include +#include +#include + +struct id_attached { + int shmid; + LIST_ENTRY(id_attached) link; +}; + +struct client { + //int fd[2]; + int sock; + pid_t pid; + int undoid; + LIST_HEAD(_ids_attached, id_attached) ids_attached; +}; + +struct client_shm_data { + int fd; + pid_t pid; +// struct ipc_perm shm_perm; +}; + +#ifndef _KERNEL +# include +#endif +#include + +#define REGISTER_DAEMON _IO('S', 1) +#define REGISTER_TO_DAEMON _IOR('S', 2, struct client) +#define UNREGISTER_DAEMON _IO('S', 3) +#define INSTALL_PIPE _IOW('S', 4, struct client) +#define CONSUME_REQUEST _IOR('S', 5, pid_t) +#define INSTALL_FD _IOWR('S', 5, const void *) + +#endif diff --git a/usr.sbin/Makefile b/usr.sbin/Makefile index 6e24110b20..5dda66a47f 100644 --- a/usr.sbin/Makefile +++ b/usr.sbin/Makefile @@ -116,6 +116,7 @@ SUBDIR= 802_11 \ slstat \ spray \ syslogd \ + sysvipcd \ tcpdchk \ tcpdmatch \ tcpdump \ diff --git a/usr.sbin/sysvipcd/Makefile b/usr.sbin/sysvipcd/Makefile new file mode 100644 index 0000000000..4ee96d8aef --- /dev/null +++ b/usr.sbin/sysvipcd/Makefile @@ -0,0 +1,12 @@ +PROG= sysvipcd +MAN= sysvipcd.8 + +.PATH: ${.CURDIR}/../../lib/libc/sysvipc +SRCS= sysvipcd.c perm.c shmd.c sockets.c sysvipc_hash.c lock.c utilsd.c + +HEADERSDIR=${.CURDIR}/../../lib/libc/sysvipc +CFLAGS+=-I$(HEADERSDIR) + +.include + + diff --git a/usr.sbin/sysvipcd/limits.h b/usr.sbin/sysvipcd/limits.h new file mode 100644 index 0000000000..14a4d5a4d3 --- /dev/null +++ b/usr.sbin/sysvipcd/limits.h @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved. + * Copyright (c) 2013 Larisa Grigore . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Glass and Charles + * Hannum. + * 4. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SYSVD_LIMITS_H +#define SYSVD_LIMITS_H + +/* + * Tuneable values + */ +#ifndef SHMMIN +#define SHMMIN 1 +#endif +#ifndef SHMMNI +#define SHMMNI 512 * 4 /* 512 for each type of sysv resource plus the + segments used for UNDO operations (sysv sems). + */ +#endif +#ifndef SHMSEG +#define SHMSEG 1024 +#endif + +struct shminfo { +// long shmmax, /* max shared memory segment size (bytes) */ + long shmmin, /* min shared memory segment size (bytes) */ + shmmni, /* max number of shared memory identifiers */ + shmseg; /* max shared memory segments per process */ +// shmall; /* max amount of shared memory (pages) */ +}; + +#endif diff --git a/usr.sbin/sysvipcd/perm.c b/usr.sbin/sysvipcd/perm.c new file mode 100644 index 0000000000..cb243319f4 --- /dev/null +++ b/usr.sbin/sysvipcd/perm.c @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2013 Larisa Grigore . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Herb Peyerl. + * 4. The name of Herb Peyerl may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#include "perm.h" +#include + +static int +is_root(struct cmsgcred *cred) { + return (cred->cmcred_euid == 0); +} + +static int +is_grpmember(gid_t gid, struct cmsgcred *cred) { + int n; + + if (cred->cmcred_gid == gid) + return (1); + + for (n = 0 ; n < cred->cmcred_ngroups ; n++) { + if (cred->cmcred_groups[n] == gid) + return (1); + } + + return (0); +} + +int +ipcperm(struct cmsgcred *cred, struct ipc_perm *perm, int mode) { + if (cred == NULL) + return (0); + + if (cred->cmcred_euid != perm->cuid + && cred->cmcred_euid != perm->uid) { + /* In order to modify control info the caller must be + * owner, creator or privileged. + */ + if (mode & IPC_M) + return (is_root(cred) ? 0 : EACCES); + + /* Check for group match. */ + mode >>= 3; + if (!is_grpmember(perm->gid, cred) && + !is_grpmember(perm->cgid, cred)) + mode >>= 3; + } + + if (mode & IPC_M) + return (0); + + if ((mode & perm->mode) == mode) + return (0); + + if (is_root(cred)) + return (0); + + return (EACCES); +} diff --git a/usr.sbin/sysvipcd/perm.h b/usr.sbin/sysvipcd/perm.h new file mode 100644 index 0000000000..c8018aef8b --- /dev/null +++ b/usr.sbin/sysvipcd/perm.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2013 Larisa Grigore . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Herb Peyerl. + * 4. The name of Herb Peyerl may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SYSVD_PERM_H +#define SYSVD_PERM_H + +#include +#include + +int ipcperm(struct cmsgcred *, struct ipc_perm *, int); + +#endif diff --git a/usr.sbin/sysvipcd/shmd.c b/usr.sbin/sysvipcd/shmd.c new file mode 100644 index 0000000000..b4df98230b --- /dev/null +++ b/usr.sbin/sysvipcd/shmd.c @@ -0,0 +1,1005 @@ +/* + * Copyright (c) 1994 Adam Glass and Charles Hannum. All rights reserved. + * Copyright (c) 2013 Larisa Grigore + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Adam Glass and Charles + * Hannum. + * 4. The names of the authors may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "limits.h" +#include "perm.h" +#include "utilsd.h" + +#include "shmd.h" +#include "sysvipc_hash.h" +#include "sysvipc_sockets.h" + +static struct shminfo shminfo = { +// 0, + SHMMIN, + SHMMNI, + SHMSEG +// 0 +}; + +/* Shared memory.*/ +static int shm_last_free, shm_committed, shmalloced; +int shm_nused; +static struct shmid_ds *shmsegs; + +/* Message queues.*/ +extern struct msginfo msginfo; + +extern struct hashtable *clientshash; + +static int +create_sysv_file(struct shmget_msg *msg, size_t size, + struct shmid_ds *shmseg) { + char filename[FILENAME_MAX]; + int fd; + void *addr; + int nsems; + struct semid_pool *sems; + struct msqid_pool *msgq; + key_t key = msg->key; + int i; + + errno = 0; + + switch(msg->type) { + case SHMGET: + sprintf(filename, "%s/%s_%ld", DIRPATH, SHM_NAME, key); + break; + case SEMGET: + sprintf(filename, "%s/%s_%ld", DIRPATH, SEM_NAME, key); + break; + case MSGGET: + sprintf(filename, "%s/%s_%ld", DIRPATH, MSG_NAME, key); + break; + case UNDOGET: + sprintf(filename, "%s/%s_%ld", DIRPATH, UNDO_NAME, key); + break; + default: + return (-EINVAL); + } + + fd = open(filename, O_RDWR | O_CREAT, 0666); + if (fd < 0) { + sysvd_print_err("create sysv file: open\n"); + goto out; + } + + ftruncate(fd, size); + + switch(msg->type) { + case SEMGET: + /* Map the semaphore to initialize it. */ + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + //TODO modify 0 for more sems on a page + if (!addr) { + sysvd_print_err("create sysv file: mmap"); + goto error; + } + + /* There is no need for any lock because all clients + * that try to access this segment are blocked until + * it becames ~SHMSEG_REMOVED. */ + sems = (struct semid_pool*)addr; + nsems = (msg->size - sizeof(struct semid_pool)) / + sizeof(struct sem); + sysvd_print("alocate %d sems\n", nsems); + + /* Init lock. */ +#ifdef SYSV_RWLOCK + sysv_rwlock_init(&sems->rwlock); +#else + sysv_mutex_init(&sems->mutex); +#endif + /* Credentials are kept in shmid_ds structure. */ + sems->ds.sem_perm.seq = shmseg->shm_perm.seq; + sems->ds.sem_nsems = nsems; + sems->ds.sem_otime = 0; + //sems->ds.sem_ctime = time(NULL); + //semtot += nsems; + sems->gen = 0;; + + /* Initialize each sem. */ + memset(sems->ds.sem_base, 0, nsems + sizeof(struct sem)); + +#ifdef SYSV_SEMS + int l; + for (l=0; l < nsems; l++) + sysv_mutex_init(&sems->ds.sem_base[l].sem_mutex); +#endif + + munmap(addr, size); + + break; + case MSGGET: + /* Map the message queue to initialize it. */ + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (!addr) { + sysvd_print_err("create sysv file: mmap"); + goto error; + } + + /* There is no need for any lock because all clients + * that try to access this segment are blocked until + * it becames ~SHMSEG_REMOVED. */ + msgq = (struct msqid_pool*)addr; //TODO + /*sysvd_print("Attention!!! : %ld %ld %ld %ld\n", + sizeof(struct msqid_pool), + sizeof(msgq->msghdrs), + sizeof(msgq->msgmaps), + sizeof(msgq->msgpool));*/ + + /* Init lock. */ +#ifdef SYSV_RWLOCK + sysv_rwlock_init(&msgq->rwlock); +#else + sysv_mutex_init(&msgq->mutex); +#endif + /* In kernel implementation, this was done globally. */ + for (i = 0; i < msginfo.msgseg; i++) { + if (i > 0) + msgq->msgmaps[i-1].next = i; + msgq->msgmaps[i].next = -1; /* implies entry is available */ + } + msgq->free_msgmaps = 0; + msgq->nfree_msgmaps = msginfo.msgseg; + + for (i = 0; i < msginfo.msgtql; i++) { + msgq->msghdrs[i].msg_type = 0; + if (i > 0) + msgq->msghdrs[i-1].msg_next = i; + msgq->msghdrs[i].msg_next = -1; + } + msgq->free_msghdrs = 0; + + /* Credentials are kept in shmid_ds structure. */ + msgq->ds.msg_perm.seq = shmseg->shm_perm.seq; + msgq->ds.first.msg_first_index = -1; + msgq->ds.last.msg_last_index = -1; + msgq->ds.msg_cbytes = 0; + msgq->ds.msg_qnum = 0; + msgq->ds.msg_qbytes = msginfo.msgmnb; + msgq->ds.msg_lspid = 0; + msgq->ds.msg_lrpid = 0; + msgq->ds.msg_stime = 0; + msgq->ds.msg_rtime = 0; + + munmap(addr, size); + + break; + default: + break; + } + + unlink(filename); +out: + return (fd); +error: + close(fd); + return (-1); +} + +/* Install for the client the file corresponding to fd. */ +static int +install_fd_client(pid_t pid, int fd) { + int ret; + struct client *cl = _hash_lookup(clientshash, pid); + if (!cl) { + sysvd_print_err("no client entry for pid = %d\n", pid); + return (-1); + } + + ret = send_fd(cl->sock, fd); + if (ret < 0) { + sysvd_print_err("can not send fd to client %d\n", pid); + return (-1); + } + + return (0); +} + +static int +shm_find_segment_by_key(key_t key) +{ + int i; + + for (i = 0; i < shmalloced; i++) { + if ((shmsegs[i].shm_perm.mode & SHMSEG_ALLOCATED) && + shmsegs[i].shm_perm.key == key) + return (i); + } + return (-1); +} + +static struct shmid_ds * +shm_find_segment_by_shmid(int shmid) +{ + int segnum; + struct shmid_ds *shmseg; + + segnum = IPCID_TO_IX(shmid); + if (segnum < 0 || segnum >= shmalloced) { + sysvd_print_err("segnum out of range\n"); + return (NULL); + } + + shmseg = &shmsegs[segnum]; + if ((shmseg->shm_perm.mode & (SHMSEG_ALLOCATED | SHMSEG_REMOVED)) + != SHMSEG_ALLOCATED || + shmseg->shm_perm.seq != IPCID_TO_SEQ(shmid)) { + sysvd_print("segment most probably removed\n"); + return (NULL); + } + return (shmseg); +} + +/* Remove a shared memory segment. */ +static void +shm_deallocate_segment(int segnum) +{ + size_t size; + struct shmid_ds *shmseg = &shmsegs[segnum]; + struct shm_handle *internal = + (struct shm_handle *)shmseg->shm_internal; +// int nsems; + + sysvd_print("deallocate segment %d\n", segnum); + + size = round_page(shmseg->shm_segsz); + +#if 0 + if (internal->type == SEMGET) { + nsems = (shmseg->shm_segsz - sizeof(struct semid_pool)) / + sizeof(struct sem); + semtot -= nsems; + sysvd_print("freed %d sems\n", nsems); + } +#endif + + /* Close the corresponding file. */ + close(internal->fd); + + /* Free other resources. */ + free(shmseg->shm_internal); + shmseg->shm_internal = NULL; + shm_committed -= btoc(size); + shm_nused--; + + shmseg->shm_perm.mode = SHMSEG_FREE; +} + +static void *map_seg(int); +static int munmap_seg(int, void *); + +/* In sem and msg case notify the other processes that use it. */ +static void +mark_segment_removed(int shmid, int type) { + struct semid_pool *semaptr; + struct msqid_pool *msgq; + + switch (type) { + case SEMGET: + semaptr = (struct semid_pool *)map_seg(shmid); +#ifdef SYSV_RWLOCK + sysv_rwlock_wrlock(&semaptr->rwlock); +#else + sysv_mutex_lock(&semaptr->mutex); +#endif + semaptr->gen = -1; + + /* It is not necessary to wake waiting threads because + * if the group of semaphores is acquired by a thread, + * the smaptr lock is held, so it is impossible to + * reach this point. + */ +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&semaptr->rwlock); +#else + sysv_mutex_unlock(&semaptr->mutex); +#endif + munmap_seg(shmid, semaptr); + break; + case MSGGET : + msgq = (struct msqid_pool*)map_seg(shmid); +#ifdef SYSV_RWLOCK + sysv_rwlock_wrlock(&msgq->rwlock); +#else + sysv_mutex_lock(&msgq->mutex); +#endif + msgq->gen = -1; + +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&msgq->rwlock); +#else + sysv_mutex_unlock(&msgq->mutex); +#endif + munmap_seg(shmid, msgq); + break; + default: + break; + } +} + +/* Get the id of an existing shared memory segment. */ +static int +shmget_existing(struct shmget_msg *shmget_msg, int mode, + int segnum, struct cmsgcred *cred) +{ + struct shmid_ds *shmseg; + int error; + + shmseg = &shmsegs[segnum]; + if (shmseg->shm_perm.mode & SHMSEG_REMOVED) { + /* + * This segment is in the process of being allocated. Wait + * until it's done, and look the key up again (in case the + * allocation failed or it was freed). + */ + //TODO Maybe it will be necessary if the daemon is multithreading + /*shmseg->shm_perm.mode |= SHMSEG_WANTED; + error = tsleep((caddr_t)shmseg, PCATCH, "shmget", 0); + if (error) + return error; + return EAGAIN;*/ + } + if ((shmget_msg->shmflg & (IPC_CREAT | IPC_EXCL)) == (IPC_CREAT | IPC_EXCL)) + return (-EEXIST); + error = ipcperm(cred, &shmseg->shm_perm, mode); + if (error) + return (-error); + if (shmget_msg->size && (shmget_msg->size > shmseg->shm_segsz)) + return (-EINVAL); + return (IXSEQ_TO_IPCID(segnum, shmseg->shm_perm)); +} + +/* Create a shared memory segment and return the id. */ +static int +shmget_allocate_segment(pid_t pid, struct shmget_msg *shmget_msg, + int mode, struct cmsgcred *cred) +{ + int i, segnum, shmid; + size_t size; + struct shmid_ds *shmseg; + struct shm_handle *handle; +#if 0 + /* It is possible after a process calls exec(). + * We don't create another segment but return the old one + * with all information. + * This segment is destroyed only when process dies. + * */ + if (shmget_msg->type == UNDOGET) { + struct client *cl= _hash_lookup(clientshash, pid); + if (cl->undoid != -1) + return cl->undoid; + } +#endif + if ((long)shmget_msg->size < shminfo.shmmin) + //|| (long)shmget_msg->size > shminfo.shmmax) + /* There is no need to check the max limit, + * the operating system do this for us. + */ + return (-EINVAL); + if (shm_nused >= shminfo.shmmni) /* any shmids left? */ + return (-ENOSPC); + + /* Compute the size of the segment. */ + size = round_page(shmget_msg->size); + + /* Find a free entry in the shmsegs vector. */ + if (shm_last_free < 0) { + // shmrealloc(); /* maybe expand the shmsegs[] array */ + for (i = 0; i < shmalloced; i++) { + if (shmsegs[i].shm_perm.mode & SHMSEG_FREE) + break; + } + if (i == shmalloced) { + sysvd_print("i == shmalloced\n"); + return (-ENOSPC); + } + segnum = i; + } else { + segnum = shm_last_free; + shm_last_free = -1; + } + shmseg = &shmsegs[segnum]; + /* + * In case we sleep in malloc(), mark the segment present but deleted + * so that noone else tries to create the same key. + */ + shmseg->shm_perm.mode = SHMSEG_ALLOCATED | SHMSEG_REMOVED; + shmseg->shm_perm.key = shmget_msg->key; + shmseg->shm_perm.seq = (shmseg->shm_perm.seq + 1) & 0x7fff; + + /* Create the file for the shared memory segment. */ + handle = shmseg->shm_internal = malloc(sizeof(struct shm_handle)); + handle->type = shmget_msg->type; + handle->fd = create_sysv_file(shmget_msg, size, shmseg); + if (handle->fd == -1) { + free(handle); + handle = NULL; + shmseg->shm_perm.mode = SHMSEG_FREE; + shm_last_free = segnum; + errno = -ENFILE; + return (-1); + } + + LIST_INIT(&handle->attached_list); + + if (handle->fd < 0) { + free(shmseg->shm_internal); + shmseg->shm_internal = NULL; + shm_last_free = segnum; + shmseg->shm_perm.mode = SHMSEG_FREE; + return (-errno); + } + + /* Get the id. */ + shmid = IXSEQ_TO_IPCID(segnum, shmseg->shm_perm); + + shmseg->shm_perm.cuid = shmseg->shm_perm.uid = cred->cmcred_euid; + shmseg->shm_perm.cgid = shmseg->shm_perm.gid = cred->cmcred_gid; + shmseg->shm_perm.mode = (shmseg->shm_perm.mode & SHMSEG_WANTED) | + (mode & ACCESSPERMS) | SHMSEG_ALLOCATED; + + shmseg->shm_cpid = pid; + shmseg->shm_lpid = shmseg->shm_nattch = 0; + shmseg->shm_atime = shmseg->shm_dtime = 0; + shmseg->shm_ctime = time(NULL); + + shmseg->shm_segsz = shmget_msg->size; + shm_committed += btoc(size); + shm_nused++; + + if (shmseg->shm_perm.mode & SHMSEG_WANTED) { + /* + * Somebody else wanted this key while we were asleep. Wake + * them up now. + */ + shmseg->shm_perm.mode &= ~SHMSEG_WANTED; + //TODO multithreading + //wakeup((caddr_t)shmseg); + } + shmseg->shm_perm.mode &= ~SHMSEG_REMOVED; + + if (shmget_msg->type == UNDOGET) { + /* The file is used by daemon when clients terminates + * and sem_undo resources must be cleaned. + */ + struct client *cl= _hash_lookup(clientshash, pid); + cl->undoid = shmid; + } + + return (shmid); +} + +/* Handle a shmget() request. */ +int +handle_shmget(pid_t pid, struct shmget_msg *shmget_msg, + struct cmsgcred *cred ) { + int segnum, mode, error; + struct shmid_ds *shmseg; + struct shm_handle *handle; + + //if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL) + // return (ENOSYS); + mode = shmget_msg->shmflg & ACCESSPERMS; + + sysvd_print("ask for key = %ld\n", shmget_msg->key); + shmget_msg->key = (shmget_msg->key & 0x3FFF) | + (shmget_msg->type << 30); + sysvd_print("ask for key = %ld\n", shmget_msg->key); + + if (shmget_msg->key != IPC_PRIVATE) { + //again: + segnum = shm_find_segment_by_key(shmget_msg->key); + if (segnum >= 0) { + error = shmget_existing(shmget_msg, mode, segnum, cred); + //TODO if daemon is multithreading + //if (error == EAGAIN) + // goto again; + goto done; + } + if ((shmget_msg->shmflg & IPC_CREAT) == 0) { + error = -ENOENT; + goto done_err; + } + } + error = shmget_allocate_segment(pid, shmget_msg, mode, cred); + sysvd_print("allocate segment = %d\n", error); +done: + /* + * Install to th client the file corresponding to the + * shared memory segment. + * client_fd is the file descriptor added in the client + * files table. + */ + shmseg = shm_find_segment_by_shmid(error); + if (shmseg == NULL) { + sysvd_print_err("can not find segment by shmid\n"); + return (-1); + } + + handle = (struct shm_handle *)shmseg->shm_internal; + if (install_fd_client(pid, handle->fd) != 0) + error = errno; +done_err: + return (error); + +} + +/* Handle a shmat() request. */ +int +handle_shmat(pid_t pid, struct shmat_msg *shmat_msg, + struct cmsgcred *cred ) { + int error; + int fd; + struct shmid_ds *shmseg; + struct pid_attached *pidatt; + struct shm_handle *handle; + size_t new_size = shmat_msg->size; + struct client *cl; + struct id_attached *idatt; + + /*if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL) + return (ENOSYS); + +again:*/ + shmseg = shm_find_segment_by_shmid(shmat_msg->shmid); + if (shmseg == NULL) { + sysvd_print_err("shmat error: segment was not found\n"); + error = EINVAL; + goto done; + } + error = ipcperm(cred, &shmseg->shm_perm, + (shmat_msg->shmflg & SHM_RDONLY) ? IPC_R : IPC_R|IPC_W); + if (error) + goto done; + + handle = shmseg->shm_internal; + + if (shmat_msg->size > shmseg->shm_segsz) { + if (handle->type != UNDOGET) { + error = EINVAL; + goto done; + } + + fd = ((struct shm_handle*)shmseg->shm_internal)->fd; + ftruncate(fd, round_page(new_size)); + shmseg->shm_segsz = new_size; + } + + shmseg->shm_lpid = pid; + shmseg->shm_atime = time(NULL); + + if (handle->type != UNDOGET) + shmseg->shm_nattch++; + else + shmseg->shm_nattch = 1; /* Only a process calls shmat and + only once. If it does it for more than once that is because + it called exec() and reinitialized the undo segment. */ + + /* Insert the pid in the segment list of attaced pids. + * The list is checked in handle_shmdt so that only + * attached pids can dettached from this segment. + */ + sysvd_print("nattch = %d pid = %d\n", + shmseg->shm_nattch, pid); + + pidatt = malloc(sizeof(*pidatt)); + pidatt->pid = pid; + LIST_INSERT_HEAD(&handle->attached_list, pidatt, link); + + /* Add the segment at the list of attached segments of the client. + * It is used when the process finishes its execution. The daemon + * walks through the list to dettach the segments. + */ + idatt = malloc(sizeof(*idatt)); + idatt->shmid = shmat_msg->shmid; + cl = _hash_lookup(clientshash, pid); + LIST_INSERT_HEAD(&cl->ids_attached, idatt, link); + + return (0); +done: + return (error); +} + +/* Handle a shmdt() request. */ +int +handle_shmdt(pid_t pid, int shmid) { + struct shmid_ds *shmseg; + int segnum; + struct shm_handle *handle; + struct pid_attached *pidatt; + struct id_attached *idatt; + struct client *cl; + + sysvd_print("shmdt pid %d shmid %d\n", pid, shmid); + /*if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL) + return (ENOSYS); + */ + + segnum = IPCID_TO_IX(shmid); + shmseg = &shmsegs[segnum]; + handle = shmseg->shm_internal; + + /* Check if pid is attached. */ + LIST_FOREACH(pidatt, &handle->attached_list, link) + if (pidatt->pid == pid) + break; + if (!pidatt) { + sysvd_print_err("process %d is not attached to %d (1)\n", + pid, shmid); + return (EINVAL); + } + LIST_REMOVE(pidatt, link); + + /* Remove the segment from the list of attached segments of the pid.*/ + cl = _hash_lookup(clientshash, pid); + LIST_FOREACH(idatt, &cl->ids_attached, link) + if (idatt->shmid == shmid) + break; + if (!idatt) { + sysvd_print_err("process %d is not attached to %d (2)\n", + pid, shmid); + return (EINVAL); + } + LIST_REMOVE(idatt, link); + + shmseg->shm_dtime = time(NULL); + + /* If no other process attaced remove the segment. */ + if ((--shmseg->shm_nattch <= 0) && + (shmseg->shm_perm.mode & SHMSEG_REMOVED)) { + shm_deallocate_segment(segnum); + shm_last_free = segnum; + } + + return (0); +} + +/* Handle a shmctl() request. */ +int +handle_shmctl(struct shmctl_msg *shmctl_msg, + struct cmsgcred *cred ) { + int error = 0; + struct shmid_ds *shmseg, *inbuf; + + /* if (!jail_sysvipc_allowed && td->td_cmsgcred->cr_prison != NULL) + return (ENOSYS); + */ + shmseg = shm_find_segment_by_shmid(shmctl_msg->shmid); + + if (shmseg == NULL) { + error = EINVAL; + goto done; + } + + switch (shmctl_msg->cmd) { + case IPC_STAT: + sysvd_print("IPC STAT\n"); + error = ipcperm(cred, &shmseg->shm_perm, IPC_R); + if (error) { + sysvd_print("IPC_STAT not allowed\n"); + break; + } + shmctl_msg->buf = *shmseg; + break; + case IPC_SET: + sysvd_print("IPC SET\n"); + error = ipcperm(cred, &shmseg->shm_perm, IPC_M); + if (error) { + sysvd_print("IPC_SET not allowed\n"); + break; + } + inbuf = &shmctl_msg->buf; + + shmseg->shm_perm.uid = inbuf->shm_perm.uid; + shmseg->shm_perm.gid = inbuf->shm_perm.gid; + shmseg->shm_perm.mode = + (shmseg->shm_perm.mode & ~ACCESSPERMS) | + (inbuf->shm_perm.mode & ACCESSPERMS); + shmseg->shm_ctime = time(NULL); + break; + case IPC_RMID: + sysvd_print("IPC RMID shmid = %d\n", + shmctl_msg->shmid); + error = ipcperm(cred, &shmseg->shm_perm, IPC_M); + if (error) { + sysvd_print("IPC_RMID not allowed\n"); + break; + } + shmseg->shm_perm.key = IPC_PRIVATE; + shmseg->shm_perm.mode |= SHMSEG_REMOVED; + if (shmseg->shm_nattch <= 0) { + shm_deallocate_segment(IPCID_TO_IX(shmctl_msg->shmid)); + shm_last_free = IPCID_TO_IX(shmctl_msg->shmid); + } + else { + /* In sem and msg cases, other process must be + * noticed about the removal. */ + struct shm_handle *internal = + (struct shm_handle *)shmseg->shm_internal; + mark_segment_removed(shmctl_msg->shmid, + internal->type); + } + break; +#if 0 + case SHM_LOCK: + case SHM_UNLOCK: +#endif + default: + error = EINVAL; + break; + } +done: + return (error); + +} + +/* Function used by daemon to map a sysv resource. */ +static void * +map_seg(int shmid) { + struct shmid_ds *shmseg; + struct shm_handle *internal; + + int fd; + size_t size; + void *addr; + + shmseg = shm_find_segment_by_shmid(shmid); + if (!shmseg) { + sysvd_print_err("map_seg error:" + "semid %d not found\n", shmid); + return (NULL); + } + + internal = (struct shm_handle *)shmseg->shm_internal; + if (!internal) { + sysvd_print_err("map_seg error: internal for" + "semid %d not found\n", shmid); + return (NULL); + } + + fd = internal->fd; + + size = round_page(shmseg->shm_segsz); + + addr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (!addr) { + sysvd_print_err("map_seg: error mmap semid = %d\n", shmid); + return (NULL); + } + + return (addr); +} + +/* Function used by daemon to munmap a sysv resource. */ +static int +munmap_seg(int shmid, void *addr) { + struct shmid_ds *shmseg; + struct shm_handle *internal; + + size_t size; + + shmseg = shm_find_segment_by_shmid(shmid); + if (!shmseg) { + sysvd_print_err("munmap_seg error:" + "semid %d not found\n", shmid); + return (-1); + } + + internal = (struct shm_handle *)shmseg->shm_internal; + if (!internal) { + sysvd_print_err("munmap_seg error: internal for" + "semid %d not found\n", shmid); + return (-1); + } + + size = round_page(shmseg->shm_segsz); + munmap(addr, size); + + return (0); +} + +void +shminit(void) { + int i; + + shmalloced = shminfo.shmmni; + shmsegs = malloc(shmalloced * sizeof(shmsegs[0])); + for (i = 0; i < shmalloced; i++) { + shmsegs[i].shm_perm.mode = SHMSEG_FREE; + shmsegs[i].shm_perm.seq = 0; + } + shm_last_free = 0; + shm_nused = 0; + shm_committed = 0; + + /* + * msginfo.msgssz should be a power of two for efficiency reasons. + * It is also pretty silly if msginfo.msgssz is less than 8 + * or greater than about 256 so ... + */ + i = 8; + while (i < 1024 && i != msginfo.msgssz) + i <<= 1; + if (i != msginfo.msgssz) { + sysvd_print_err("msginfo.msgssz=%d (0x%x)\n", msginfo.msgssz, + msginfo.msgssz); + sysvd_print_err("msginfo.msgssz not a small power of 2"); + exit(-1); + } + msginfo.msgmax = msginfo.msgseg * msginfo.msgssz; +} + +/*static void +shmfree(void) { + free(shmsegs); +}*/ + +int +semexit(int undoid) { + struct sem_undo *suptr; + struct sem *semptr; + struct shmid_ds *undoseg; + + if (undoid < 0) { + return (-1); + } + + undoseg = shm_find_segment_by_shmid(undoid); + /* The UNDO segment must be mapped by only one segment. */ + if (undoseg->shm_nattch != 1) { + sysvd_print_err("undo segment mapped by more" + "than one process\n"); + exit(-1); + } + + suptr = (struct sem_undo *)map_seg(undoid); + if (suptr == NULL) { + sysvd_print_err("no %d undo segment found\n", undoid); + return (-1); + } + + /* No locking mechanism is required because only the + * client and the daemon can access the UNDO segment. + * At this moment the client is disconnected so only + * the daemon can modify this segment. + */ + while (suptr->un_cnt) { + struct semid_pool *semaptr; + int semid; + int semnum; + int adjval; + int ix; + + ix = suptr->un_cnt - 1; + semid = suptr->un_ent[ix].un_id; + semnum = suptr->un_ent[ix].un_num; + adjval = suptr->un_ent[ix].un_adjval; + + semaptr = (struct semid_pool *)map_seg(semid); + if (!semaptr) { + return (-1); + } + + /* Was it removed? */ + if (semaptr->gen == -1 || + semaptr->ds.sem_perm.seq != IPCID_TO_SEQ(semid) || + (semaptr->ds.sem_perm.mode & SHMSEG_ALLOCATED) == 0) { + --suptr->un_cnt; + sysvd_print_err("semexit - semid not allocated\n"); + continue; + } + if (semnum >= semaptr->ds.sem_nsems) { + --suptr->un_cnt; + sysvd_print_err("semexit - semnum out of range\n"); + continue; + } + +#ifdef SYSV_RWLOCK +#ifdef SYSV_SEMS + sysv_rwlock_rdlock(&semaptr->rwlock); +#else + sysv_rwlock_wrlock(&semaptr->rwlock); +#endif //SYSV_SEMS +#else + sysv_mutex_lock(&semaptr->mutex); + /* Nobody can remove the semaphore beteen the check and the + * lock acquisition because it must first send a IPC_RMID + * to me and I will process that after finishing this function. + */ +#endif //SYSV_RWLOCK + semptr = &semaptr->ds.sem_base[semnum]; +#ifdef SYSV_SEMS + sysv_mutex_lock(&semptr->sem_mutex); +#endif + if (ix == suptr->un_cnt - 1 && + semid == suptr->un_ent[ix].un_id && + semnum == suptr->un_ent[ix].un_num && + adjval == suptr->un_ent[ix].un_adjval) { + --suptr->un_cnt; + + if (adjval < 0) { + if (semptr->semval < -adjval) + semptr->semval = 0; + else + semptr->semval += adjval; + } else { + semptr->semval += adjval; + } + /* TODO multithreaded daemon: + * Check again if the semaphore was removed and do + * not wake anyone if it was.*/ + umtx_wakeup((int *)&semptr->semval, 0); + } +#ifdef SYSV_SEMS + sysv_mutex_unlock(&semptr->sem_mutex); +#endif + +#ifdef SYSV_RWLOCK + sysv_rwlock_unlock(&semaptr->rwlock); +#else + sysv_mutex_unlock(&semaptr->mutex); +#endif + munmap_seg(semid, semaptr); + } + + munmap_seg(undoid, suptr); + return (0); +} + +void +shmexit(struct client *cl) { + struct id_attached *idatt; + + while (!LIST_EMPTY(&cl->ids_attached)) { + idatt = LIST_FIRST(&cl->ids_attached); + handle_shmdt(cl->pid, idatt->shmid); + } +} diff --git a/usr.sbin/sysvipcd/shmd.h b/usr.sbin/sysvipcd/shmd.h new file mode 100644 index 0000000000..a9a5868a32 --- /dev/null +++ b/usr.sbin/sysvipcd/shmd.h @@ -0,0 +1,26 @@ +#ifndef SYSVD_SHMD_H +#define SYSVD_SHMD_H + +#include +#include +#include +#include + +#include "sysvipc_ipc.h" +#include "sysvipc_sem.h" +#include "sysvipc_shm.h" +#include "sysvipc_msg.h" + +#include "utilsd.h" +#include "perm.h" + +int handle_shmget(pid_t, struct shmget_msg *, struct cmsgcred *); +int handle_shmat(pid_t, struct shmat_msg *, struct cmsgcred *); +int handle_shmdt(pid_t, int); +int handle_shmctl(struct shmctl_msg *, struct cmsgcred *); + +void shminit(void); +int semexit(int); +void shmexit(struct client *); + +#endif diff --git a/usr.sbin/sysvipcd/sysvipcd.8 b/usr.sbin/sysvipcd/sysvipcd.8 new file mode 100644 index 0000000000..a64db3c606 --- /dev/null +++ b/usr.sbin/sysvipcd/sysvipcd.8 @@ -0,0 +1,89 @@ +.\" +.\" Copyright (c) 2013 +.\" The DragonFly Project. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in +.\" the documentation and/or other materials provided with the +.\" distribution. +.\" 3. Neither the name of The DragonFly Project nor the names of its +.\" contributors may be used to endorse or promote products derived +.\" from this software without specific, prior written permission. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +.\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +.\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +.\" COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +.\" INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, +.\" BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +.\" LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +.\" AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +.\" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +.\" OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.Dd September 26, 2013 +.Dt SYSVIPCD 8 +.Os +.Sh NAME +.Nm sysvipcd +.Nd SysV IPC daemon +.Sh DESCRIPTION +The +.Nm +daemon handles the resource management for the userspace implementation of +the XSI Interprocess Communication functions. +It is responsible for mapping shared memory, semaphores and message queues +into the clients' address spaces and it has to be running for the +userspace implementation to work. +.Pp +Clients connect to it through a +.Ux socket . +The daemon also monitors the +.Xr fork 2 +system call and any children of a process using the userspace +implementation automatically connect to the daemon too. +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl d +run in debugging mode (prints debug messages) +.El +.Sh ENVIRONMENT +If the +.Ev USR_SYSVIPC +variable is set in a process' environment, the process and its children +will use the userspace implementation of the XSI Interprocess Communication +functions. +.Sh FILES +.Bl -tag -width ".Pa /var/run/sysvipc/sysvipc_socket" -compact +.It Pa /var/run/sysvipc/sysvipc_socket +name of the +.Ux +domain stream socket for client communication +.El +.Sh SEE ALSO +.Xr msgctl 2 , +.Xr msgget 2 , +.Xr msgrcv 2 , +.Xr msgsnd 2 , +.Xr semctl 2 , +.Xr semget 2 , +.Xr semop 2 , +.Xr shmat 2 , +.Xr shmctl 2 , +.Xr shmget 2 +.Sh HISTORY +The +.Nm +daemon was added in +.Dx 3.5 +.Sh AUTHORS +.An Larisa Grigore diff --git a/usr.sbin/sysvipcd/sysvipcd.c b/usr.sbin/sysvipcd/sysvipcd.c new file mode 100644 index 0000000000..c064deecad --- /dev/null +++ b/usr.sbin/sysvipcd/sysvipcd.c @@ -0,0 +1,383 @@ +/** + * Copyright (c) 2013 Larisa Grigore. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sysvipc_hash.h" +#include "sysvipc_sockets.h" +#include "utilsd.h" +#include "shmd.h" + +#define MAX_CLIENTS 256 + +void usage(void); + + +struct pollfd poll_fds[MAX_CLIENTS]; +struct client *clients[MAX_CLIENTS]; +int nr_poll_fds; + +struct hashtable *clientshash = NULL; + +int sysvd_debug; +int sysvd_daemon; +const char *pidfile = "/var/run/sysvpicd.pid"; + +static int +remove_sysv_dir(void) +{ + /* + * It is not necessary to check if the dir is empty and delete all files + * in it. Every time a client or the daemon exists all fds are closed + * and all resources are deleted (the daemon calls unlink after open a + * file for a sysv resource. + */ + return (rmdir(DIRPATH)); +} + +static int +create_sysv_dir(void) +{ + remove_sysv_dir(); + return (mkdir(DIRPATH, 0600)); +} + +static int +daemon_init(void) +{ + int error; + int socket_fd; + + /* Create and init structures used for clients. */ + clientshash = _hash_init(MAX_CLIENTS); + if (!clientshash) + return (-1); + + /* Create sysv resources directory. */ + error = create_sysv_dir(); + if (error) { + sysvd_print_err("You must first remove %s dir\n", + DIRPATH); + goto err; + } + + /* Open socket used to receive connections. */ + unlink(LISTEN_SOCKET_FILE); + umask(0); + int fd_tmp = open(LISTEN_SOCKET_FILE, O_EXCL | O_CREAT, 0666); + if (fd_tmp < 0) { + sysvd_print_err("Could not open %s\n", LISTEN_SOCKET_FILE); + goto err; + } + close(fd_tmp); + + socket_fd = init_socket(LISTEN_SOCKET_FILE); + if (socket_fd < 0) { + sysvd_print_err("Could not init %s socket\n", LISTEN_SOCKET_FILE); + goto err; + } + + poll_fds[SOCKET_FD_IDX].fd = socket_fd; + poll_fds[SOCKET_FD_IDX].events = POLLIN | POLLPRI; + poll_fds[SOCKET_FD_IDX].revents = 0; + nr_poll_fds++; + + shminit(); + + return (0); +err: + free(clientshash); + return (-1); +} + +static int +daemon_add_client(void) +{ + struct client *cl; + //int on = 1; + struct cmsgcred cred; + char test; + + cl = malloc(sizeof(*cl)); + if (!cl) { + sysvd_print_err("malloc"); + return (-1); + } + + cl->undoid = -1; + + /* Segments attached to a process. It is used + * when the process dies. + */ + LIST_INIT(&cl->ids_attached); + + /* Init communication channel between daemon and client. */ + cl->sock = handle_new_connection(poll_fds[SOCKET_FD_IDX].fd); + + poll_fds[nr_poll_fds].fd = cl->sock; + poll_fds[nr_poll_fds].events = POLLIN; + poll_fds[nr_poll_fds].revents = 0; + + clients[nr_poll_fds] = cl; + nr_poll_fds++; + + if(nr_poll_fds == MAX_CLIENTS) { + sysvd_print_err("No room for another client; connection refused\n"); + poll_fds[SOCKET_FD_IDX].events = 0; + } + + /* Get the client pid. */ + receive_msg_with_cred(cl->sock, &test, sizeof(test), &cred); + cl->pid = cred.cmcred_pid; + + sysvd_print("total = %d...another one will be added\n", nr_poll_fds); + sysvd_print("pid = %d conected\n", cl->pid); + + /* Verify if the client is already connected using the hashtable. */ + if (_hash_lookup(clientshash, cl->pid)) { + errno = EEXIST; + sysvd_print_err("client already added"); + free(cl); + return (-1); + } + + /* Insert client in hashtable. */ + _hash_insert(clientshash, cl->pid, cl); + + return (0); +} + +static void +daemon_remove_client(int i) +{ + + struct client *cl = clients[i]; + sysvd_print("pid %d disconected\n", cl->pid); + sysvd_print("total = %d\n", nr_poll_fds); + + /* Close communication channels. */ + close(cl->sock); + + /* Put last client on i position. */ + if (i != nr_poll_fds - 1) { + poll_fds[i] = poll_fds[nr_poll_fds - 1]; + clients[i] = clients[nr_poll_fds - 1]; + } + + semexit(cl->undoid); + shmexit(cl); + + _hash_remove(clientshash, cl->pid); + nr_poll_fds--; + free(cl); + cl = NULL; + + if(nr_poll_fds == MAX_CLIENTS - 1) { + sysvd_print_err("Now another connexion can be handled\n"); + poll_fds[SOCKET_FD_IDX].events = POLLIN | POLLPRI; + } +} + +static int +daemon_handle_msg(int i) +{ + int msg_type; + struct shmget_msg shmget_msg; + struct shmctl_msg shmctl_msg; + struct shmat_msg shmat_msg; + int shmid; + int error; + struct cmsgcred cred; + + int fd_send, fd_recv; + fd_send = fd_recv = clients[i]->sock; + + msg_type = receive_type_message(fd_recv); + sysvd_print("type = %d from %d\n", msg_type, clients[i]->pid); + + switch(msg_type) { + case CONNEXION_CLOSED: + sysvd_print("connection closed\n"); + return (EOF); + case SHMGET: + case SEMGET: + case MSGGET: + case UNDOGET: + receive_msg_with_cred(fd_recv, (char *)&shmget_msg, + sizeof(shmget_msg), &cred); + shmid = handle_shmget(clients[i]->pid, + &shmget_msg, &cred); + + /* Send the shmid. */ + write(fd_send, (char *)&shmid, + sizeof(shmid)); + sysvd_print("sent %d to client %d\n", + shmid, clients[i]->pid); + break; + case SHMAT: + receive_msg_with_cred(fd_recv, (char *)&shmat_msg, + sizeof(shmat_msg), &cred); + error = handle_shmat(clients[i]->pid, + &shmat_msg, &cred); + + /* Send the error after few checks. */ + write(fd_send, (char *)&error, + sizeof(error)); + break; + case SHMCTL: + receive_msg_with_cred(fd_recv, (char *)&shmctl_msg, + sizeof(shmctl_msg), &cred); + error = handle_shmctl(&shmctl_msg, &cred); + + /* Send the error after few checks. */ + write(fd_send, (char *)&error, + sizeof(error)); + if (error == 0 && shmctl_msg.cmd == IPC_STAT) { + + write(fd_send, (char *)&shmctl_msg.buf, + sizeof(struct shmid_ds)); + } + break; + case SHMDT: + receive_msg_with_cred(fd_recv, (char *)&shmid, + sizeof(shmid), NULL); + shmid = handle_shmdt(clients[i]->pid, shmid); + break; + default: + break; + } + sysvd_print("end\n"); + return (0); +} + + +static int +daemon_func(void) +{ + int i; + //int msg; + int ret, r; + + while(1) + { + ret = poll(poll_fds, nr_poll_fds, INFTIM); + if (ret < 0) { + sysvd_print_err("poll"); + return (-1); + } + for (i=0; (i < nr_poll_fds) && ret; i++) { + if (poll_fds[i].revents == 0) + continue; + ret--; + + switch(i) { + case SOCKET_FD_IDX: + daemon_add_client(); + break; + default: + r = daemon_handle_msg(i); + if (r == EOF) { + daemon_remove_client(i); + i--; + } + break; + } + } + fflush(stdout); + } + + return (0); +} + +void +usage(void) +{ + return; +} + +int +main(int argc, char *argv[]) +{ + int c; + int error; + + sysvd_debug = 0; + sysvd_daemon = 1; + + while ((c = getopt(argc,argv,"df:p")) !=-1) { + switch(c) { + case 'd': + sysvd_debug = 1; + break; + case 'f': + sysvd_daemon = 0; + break; + case 'p': + pidfile = optarg; + break; + default: + usage(); + break; + } + } + +#ifdef SYSV_SEMS + sysvd_print_err("SYSV_SEMS defined (used for sysv sems; a group of semaphores is protected)" + "by a rwlock and each semaphore is protected by a mutex\n"); +#else + sysvd_print_err("SYSV_SEMS not defined (used for sysv sems; a group of semaphores is protected)" + "by a rwlock\n"); +#endif + + sysvd_print("daemon starting\n"); + error = daemon_init(); + if (error) + goto out; + + if (sysvd_daemon == 1) { + daemon(1,0); + } + + daemon_func(); + + /* It won't reach here. */ + sysvd_print("daemon finished\n"); + + //shmfree(); + remove_sysv_dir(); +out: + return (0); +} diff --git a/usr.sbin/sysvipcd/utilsd.c b/usr.sbin/sysvipcd/utilsd.c new file mode 100644 index 0000000000..a69304d732 --- /dev/null +++ b/usr.sbin/sysvipcd/utilsd.c @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2013 Larisa Grigore. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include "utilsd.h" + +extern int sysvd_debug; + +void +sysvd_print(const char *fmt, ...) { + va_list ap; + char format[50]; + + if(!sysvd_debug) + return; + + sprintf(format, "[sysvd %d] %s", + getpid(), fmt); + va_start(ap, fmt); +// vsyslog(LOG_DEBUG, format, ap); + vprintf(format, ap); + va_end(ap); +} + +void +sysvd_print_err(const char *fmt, ...) { + va_list ap; + char format[50]; + + sprintf(format, "[sysvd %d] error(%d): %s", + getpid(), errno, fmt); + va_start(ap, fmt); +// vsyslog(LOG_ERR, format, ap); + vprintf(format, ap); + va_end(ap); +} diff --git a/usr.sbin/sysvipcd/utilsd.h b/usr.sbin/sysvipcd/utilsd.h new file mode 100644 index 0000000000..39151dc43f --- /dev/null +++ b/usr.sbin/sysvipcd/utilsd.h @@ -0,0 +1,87 @@ +/** + * Copyright (c) 2013 Larisa Grigore . + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef SYSVD_UTILS_H +#define SYSVD_UTILS_H + +#define SOCKET_FD_IDX 0 + +#define POLLPIPE (POLLIN | POLLPRI | POLLRDNORM | POLLRDBAND) + +#define CONNEXION_CLOSED 0 + +#define SHMSEG_FREE 0x0200 +#define SHMSEG_REMOVED 0x0400 +#define SHMSEG_ALLOCATED 0x0800 +#define SHMSEG_WANTED 0x1000 + +#define DIRPATH "/var/run/sysvipc" + +#define SHM_NAME "shm" +#define SEM_NAME "sem" +#define MSG_NAME "msg" +#define UNDO_NAME "undo" + +#include + +struct client { + //int fd[2]; + int sock; + pid_t pid; + int undoid; + LIST_HEAD(_ids_attached, id_attached) ids_attached; +}; + +struct client_entry { + struct client *client; + LIST_ENTRY(client_entry) client_link; +}; + +LIST_HEAD(client_hashtable, client_entry) *clienthashtable; +u_long clientmask; + +struct pid_attached { + int pid; + LIST_ENTRY(pid_attached) link; +}; + +struct id_attached { + int shmid; + LIST_ENTRY(id_attached) link; +}; + +struct shm_handle { + int type; + int fd; + LIST_HEAD(_attached_list, pid_attached) attached_list; +}; + +/* Print wrappers. */ +void sysvd_print_err(const char *fmt, ...); +void sysvd_print(const char *fmt, ...); + +#endif