xref: /minix3/minix/servers/ipc/main.c (revision 534584945c0f50b9816e7051003856bd31bf8c65)
1433d6423SLionel Sambuc #include "inc.h"
2433d6423SLionel Sambuc 
35b1db956SDavid van Moolenbroek #define SEM_EVENTS	0x01	/* semaphore code wants process events */
45b1db956SDavid van Moolenbroek static unsigned int event_mask = 0;
55b1db956SDavid van Moolenbroek 
65b1db956SDavid van Moolenbroek static int verbose = 0;
75b1db956SDavid van Moolenbroek 
80baafa0eSDavid van Moolenbroek /*
90baafa0eSDavid van Moolenbroek  * The call table for this service.
100baafa0eSDavid van Moolenbroek  */
114d272e5aSDavid van Moolenbroek #define CALL(n) [((n) - IPC_BASE)]
124d272e5aSDavid van Moolenbroek static int (* const call_vec[])(message *) = {
134d272e5aSDavid van Moolenbroek 	CALL(IPC_SHMGET)	= do_shmget,
144d272e5aSDavid van Moolenbroek 	CALL(IPC_SHMAT)		= do_shmat,
154d272e5aSDavid van Moolenbroek 	CALL(IPC_SHMDT)		= do_shmdt,
164d272e5aSDavid van Moolenbroek 	CALL(IPC_SHMCTL)	= do_shmctl,
174d272e5aSDavid van Moolenbroek 	CALL(IPC_SEMGET)	= do_semget,
184d272e5aSDavid van Moolenbroek 	CALL(IPC_SEMCTL)	= do_semctl,
194d272e5aSDavid van Moolenbroek 	CALL(IPC_SEMOP)		= do_semop,
20433d6423SLionel Sambuc };
21433d6423SLionel Sambuc 
220baafa0eSDavid van Moolenbroek /*
23*53458494SDavid van Moolenbroek  * Remote MIB implementation of CTL_KERN KERN_SYSVIPC KERN_SYSVIPC_INFO.  This
24*53458494SDavid van Moolenbroek  * function handles all queries on the "kern.ipc.sysvipc_info" sysctl(2) node.
25*53458494SDavid van Moolenbroek  */
26*53458494SDavid van Moolenbroek static ssize_t
kern_ipc_info(struct rmib_call * call,struct rmib_node * node __unused,struct rmib_oldp * oldp,struct rmib_newp * newp __unused)27*53458494SDavid van Moolenbroek kern_ipc_info(struct rmib_call * call, struct rmib_node * node __unused,
28*53458494SDavid van Moolenbroek 	struct rmib_oldp * oldp, struct rmib_newp * newp __unused)
29*53458494SDavid van Moolenbroek {
30*53458494SDavid van Moolenbroek 
31*53458494SDavid van Moolenbroek 	if (call->call_namelen != 1)
32*53458494SDavid van Moolenbroek 		return EINVAL;
33*53458494SDavid van Moolenbroek 
34*53458494SDavid van Moolenbroek 	/*
35*53458494SDavid van Moolenbroek 	 * Let each IPC submodule provide information through it own function.
36*53458494SDavid van Moolenbroek 	 * An important security note: unlike IPC_STAT and the like, access to
37*53458494SDavid van Moolenbroek 	 * the sysvipc_info node does not require root privileges.  That is: on
38*53458494SDavid van Moolenbroek 	 * NetBSD, any user can get a full listing of all IPC objects in the
39*53458494SDavid van Moolenbroek 	 * system.  We therefore do not perform any security check here.
40*53458494SDavid van Moolenbroek 	 */
41*53458494SDavid van Moolenbroek 	switch (call->call_name[0]) {
42*53458494SDavid van Moolenbroek 	case KERN_SYSVIPC_SEM_INFO:
43*53458494SDavid van Moolenbroek 		return get_sem_mib_info(oldp);
44*53458494SDavid van Moolenbroek 
45*53458494SDavid van Moolenbroek 	case KERN_SYSVIPC_SHM_INFO:
46*53458494SDavid van Moolenbroek 		return get_shm_mib_info(oldp);
47*53458494SDavid van Moolenbroek 
48*53458494SDavid van Moolenbroek 	default:
49*53458494SDavid van Moolenbroek 		return EOPNOTSUPP;
50*53458494SDavid van Moolenbroek 	}
51*53458494SDavid van Moolenbroek }
52*53458494SDavid van Moolenbroek 
53*53458494SDavid van Moolenbroek /* The CTL_KERN KERN_SYSVIPC subtree. */
54*53458494SDavid van Moolenbroek static struct rmib_node kern_ipc_table[] = {
55*53458494SDavid van Moolenbroek /* 1*/	[KERN_SYSVIPC_INFO]	= RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0,
56*53458494SDavid van Moolenbroek 				    kern_ipc_info, "sysvipc_info",
57*53458494SDavid van Moolenbroek 				    "System V style IPC information"),
58*53458494SDavid van Moolenbroek /* 2*/	[KERN_SYSVIPC_MSG]	= RMIB_INT(RMIB_RO, 0, "sysvmsg", "System V "
59*53458494SDavid van Moolenbroek 				    "style message support available"),
60*53458494SDavid van Moolenbroek /* 3*/	[KERN_SYSVIPC_SEM]	= RMIB_INT(RMIB_RO, 1, "sysvsem", "System V "
61*53458494SDavid van Moolenbroek 				    "style semaphore support available"),
62*53458494SDavid van Moolenbroek /* 4*/	[KERN_SYSVIPC_SHM]	= RMIB_INT(RMIB_RO, 1, "sysvshm", "System V "
63*53458494SDavid van Moolenbroek 				    "style shared memory support available"),
64*53458494SDavid van Moolenbroek /* 5*/	/* KERN_SYSVIPC_SHMMAX: not yet supported */
65*53458494SDavid van Moolenbroek /* 6*/	/* KERN_SYSVIPC_SHMMNI: not yet supported */
66*53458494SDavid van Moolenbroek /* 7*/	/* KERN_SYSVIPC_SHMSEG: not yet supported */
67*53458494SDavid van Moolenbroek /* 8*/	/* KERN_SYSVIPC_SHMMAXPGS: not yet supported */
68*53458494SDavid van Moolenbroek /* 9*/	/* KERN_SYSVIPC_SHMUSEPHYS: not yet supported */
69*53458494SDavid van Moolenbroek 	/* In addition, NetBSD has a number of dynamic nodes here. */
70*53458494SDavid van Moolenbroek };
71*53458494SDavid van Moolenbroek 
72*53458494SDavid van Moolenbroek /* The CTL_KERN KERN_SYSVIPC node. */
73*53458494SDavid van Moolenbroek static struct rmib_node kern_ipc_node =
74*53458494SDavid van Moolenbroek     RMIB_NODE(RMIB_RO, kern_ipc_table, "ipc", "SysV IPC options");
75*53458494SDavid van Moolenbroek 
76*53458494SDavid van Moolenbroek /*
770baafa0eSDavid van Moolenbroek  * Initialize the IPC server.
78433d6423SLionel Sambuc  */
790baafa0eSDavid van Moolenbroek static int
sef_cb_init_fresh(int type __unused,sef_init_info_t * info __unused)800baafa0eSDavid van Moolenbroek sef_cb_init_fresh(int type __unused, sef_init_info_t * info __unused)
810baafa0eSDavid van Moolenbroek {
82*53458494SDavid van Moolenbroek 	const int mib[] = { CTL_KERN, KERN_SYSVIPC };
83*53458494SDavid van Moolenbroek 	int r;
840baafa0eSDavid van Moolenbroek 
85*53458494SDavid van Moolenbroek 	/*
86*53458494SDavid van Moolenbroek 	 * Register our own "kern.ipc" subtree with the MIB service.
87*53458494SDavid van Moolenbroek 	 *
88*53458494SDavid van Moolenbroek 	 * This call only returns local failures.  Remote failures (in the MIB
89*53458494SDavid van Moolenbroek 	 * service) are silently ignored.  So, we can safely panic on failure.
90*53458494SDavid van Moolenbroek 	 */
91*53458494SDavid van Moolenbroek 	if ((r = rmib_register(mib, __arraycount(mib), &kern_ipc_node)) != OK)
92*53458494SDavid van Moolenbroek 		panic("unable to register remote MIB tree: %d", r);
93*53458494SDavid van Moolenbroek 
940baafa0eSDavid van Moolenbroek 	return OK;
95433d6423SLionel Sambuc }
96433d6423SLionel Sambuc 
975b1db956SDavid van Moolenbroek /*
985b1db956SDavid van Moolenbroek  * The service has received a signal.
995b1db956SDavid van Moolenbroek  */
1000baafa0eSDavid van Moolenbroek static void
sef_cb_signal_handler(int signo)1010baafa0eSDavid van Moolenbroek sef_cb_signal_handler(int signo)
1020baafa0eSDavid van Moolenbroek {
1030baafa0eSDavid van Moolenbroek 
1040baafa0eSDavid van Moolenbroek 	/* Only check for termination signal, ignore anything else. */
1050baafa0eSDavid van Moolenbroek 	if (signo != SIGTERM) return;
106433d6423SLionel Sambuc 
107433d6423SLionel Sambuc 	/*
1080baafa0eSDavid van Moolenbroek 	 * Check if there are still IPC keys around.  If not, we can safely
1090baafa0eSDavid van Moolenbroek 	 * exit immediately.  Otherwise, warn the system administrator.
110433d6423SLionel Sambuc 	 */
111*53458494SDavid van Moolenbroek 	if (is_sem_nil() && is_shm_nil()) {
112*53458494SDavid van Moolenbroek 		rmib_deregister(&kern_ipc_node);
113*53458494SDavid van Moolenbroek 
1140baafa0eSDavid van Moolenbroek 		sef_exit(0);
115*53458494SDavid van Moolenbroek 	}
116433d6423SLionel Sambuc 
1170baafa0eSDavid van Moolenbroek 	printf("IPC: exit with unclean state\n");
118433d6423SLionel Sambuc }
119433d6423SLionel Sambuc 
1205b1db956SDavid van Moolenbroek /*
1215b1db956SDavid van Moolenbroek  * Perform SEF initialization.
1225b1db956SDavid van Moolenbroek  */
1230baafa0eSDavid van Moolenbroek static void
sef_local_startup(void)1240baafa0eSDavid van Moolenbroek sef_local_startup(void)
125433d6423SLionel Sambuc {
1260baafa0eSDavid van Moolenbroek 
127433d6423SLionel Sambuc 	/* Register init callbacks. */
128433d6423SLionel Sambuc 	sef_setcb_init_fresh(sef_cb_init_fresh);
129433d6423SLionel Sambuc 	sef_setcb_init_restart(sef_cb_init_fresh);
130433d6423SLionel Sambuc 
131433d6423SLionel Sambuc 	/* Register signal callbacks. */
132433d6423SLionel Sambuc 	sef_setcb_signal_handler(sef_cb_signal_handler);
133433d6423SLionel Sambuc 
134433d6423SLionel Sambuc 	/* Let SEF perform startup. */
135433d6423SLionel Sambuc 	sef_startup();
136433d6423SLionel Sambuc }
137433d6423SLionel Sambuc 
1385b1db956SDavid van Moolenbroek /*
1395b1db956SDavid van Moolenbroek  * Update the process event subscription mask if necessary, after one of the
1405b1db956SDavid van Moolenbroek  * modules has changed its subscription needs.  This code is set up so that
1415b1db956SDavid van Moolenbroek  * support for SysV IPC message queues can be added easily later.
1425b1db956SDavid van Moolenbroek  */
1435b1db956SDavid van Moolenbroek static void
update_sub(unsigned int new_mask)1445b1db956SDavid van Moolenbroek update_sub(unsigned int new_mask)
1455b1db956SDavid van Moolenbroek {
1465b1db956SDavid van Moolenbroek 
1475b1db956SDavid van Moolenbroek 	/* If the old and new mask are not both zero or nonzero, update. */
1485b1db956SDavid van Moolenbroek 	if (!event_mask != !new_mask) {
1495b1db956SDavid van Moolenbroek 		/*
1505b1db956SDavid van Moolenbroek 		 * Subscribe to PM process events, or unsubscribe.  While it
1515b1db956SDavid van Moolenbroek 		 * might be tempting to implement a system that subscribes to
1525b1db956SDavid van Moolenbroek 		 * events only from processes that are actually blocked (or
1535b1db956SDavid van Moolenbroek 		 * using the SysV IPC facilities at all), this would result in
1545b1db956SDavid van Moolenbroek 		 * race conditions where subscription could happen "too late"
1555b1db956SDavid van Moolenbroek 		 * for an ongoing signal delivery, causing the affected process
1565b1db956SDavid van Moolenbroek 		 * to deadlock.  Subscribing to events from any other call is
1575b1db956SDavid van Moolenbroek 		 * safe however, and we exploit that to limit the kernel-level
1585b1db956SDavid van Moolenbroek 		 * message passing overhead in the common case (which is that
1595b1db956SDavid van Moolenbroek 		 * the IPC servier is not being used at all).  After we have
1605b1db956SDavid van Moolenbroek 		 * unsubscribed, we may still get a few leftover events for the
1615b1db956SDavid van Moolenbroek 		 * previous subscription, and we must properly reply to those.
1625b1db956SDavid van Moolenbroek 		 */
1635b1db956SDavid van Moolenbroek 		if (new_mask)
1645b1db956SDavid van Moolenbroek 			proceventmask(PROC_EVENT_EXIT | PROC_EVENT_SIGNAL);
1655b1db956SDavid van Moolenbroek 		else
1665b1db956SDavid van Moolenbroek 			proceventmask(0);
1675b1db956SDavid van Moolenbroek 	}
1685b1db956SDavid van Moolenbroek 
1695b1db956SDavid van Moolenbroek 	event_mask = new_mask;
1705b1db956SDavid van Moolenbroek }
1715b1db956SDavid van Moolenbroek 
1725b1db956SDavid van Moolenbroek /*
1735b1db956SDavid van Moolenbroek  * Update the process event subscription mask for the semaphore code.
1745b1db956SDavid van Moolenbroek  */
1755b1db956SDavid van Moolenbroek void
update_sem_sub(int want_events)1765b1db956SDavid van Moolenbroek update_sem_sub(int want_events)
1775b1db956SDavid van Moolenbroek {
1785b1db956SDavid van Moolenbroek 	unsigned int new_mask;
1795b1db956SDavid van Moolenbroek 
1805b1db956SDavid van Moolenbroek 	new_mask = event_mask & ~SEM_EVENTS;
1815b1db956SDavid van Moolenbroek 	if (want_events)
1825b1db956SDavid van Moolenbroek 		new_mask |= SEM_EVENTS;
1835b1db956SDavid van Moolenbroek 
1845b1db956SDavid van Moolenbroek 	update_sub(new_mask);
1855b1db956SDavid van Moolenbroek }
1865b1db956SDavid van Moolenbroek 
1875b1db956SDavid van Moolenbroek /*
1885b1db956SDavid van Moolenbroek  * PM sent us a process event message.  Handle it, and reply.
1895b1db956SDavid van Moolenbroek  */
1905b1db956SDavid van Moolenbroek static void
got_proc_event(message * m)1915b1db956SDavid van Moolenbroek got_proc_event(message * m)
1925b1db956SDavid van Moolenbroek {
1935b1db956SDavid van Moolenbroek 	endpoint_t endpt;
1945b1db956SDavid van Moolenbroek 	int r, has_exited;
1955b1db956SDavid van Moolenbroek 
1965b1db956SDavid van Moolenbroek 	endpt = m->m_pm_lsys_proc_event.endpt;
1975b1db956SDavid van Moolenbroek 	has_exited = (m->m_pm_lsys_proc_event.event == PROC_EVENT_EXIT);
1985b1db956SDavid van Moolenbroek 
1995b1db956SDavid van Moolenbroek 	/*
2005b1db956SDavid van Moolenbroek 	 * Currently, only semaphore handling needs to know about processes
2015b1db956SDavid van Moolenbroek 	 * being signaled and exiting.
2025b1db956SDavid van Moolenbroek 	 */
2035b1db956SDavid van Moolenbroek 	if (event_mask & SEM_EVENTS)
2045b1db956SDavid van Moolenbroek 		sem_process_event(endpt, has_exited);
2055b1db956SDavid van Moolenbroek 
2065b1db956SDavid van Moolenbroek 	/* Echo the request as a reply back to PM. */
2075b1db956SDavid van Moolenbroek 	m->m_type = PROC_EVENT_REPLY;
2085b1db956SDavid van Moolenbroek 	if ((r = asynsend3(m->m_source, m, AMF_NOREPLY)) != OK)
2095b1db956SDavid van Moolenbroek 		printf("IPC: replying to PM process event failed (%d)\n", r);
2105b1db956SDavid van Moolenbroek }
2115b1db956SDavid van Moolenbroek 
2125b1db956SDavid van Moolenbroek /*
2135b1db956SDavid van Moolenbroek  * The System V IPC server.
2145b1db956SDavid van Moolenbroek  */
2150baafa0eSDavid van Moolenbroek int
main(int argc,char ** argv)2160baafa0eSDavid van Moolenbroek main(int argc, char ** argv)
217433d6423SLionel Sambuc {
2180baafa0eSDavid van Moolenbroek 	message m;
2190baafa0eSDavid van Moolenbroek 	unsigned int call_index;
2200baafa0eSDavid van Moolenbroek 	int r, ipc_status;
2210baafa0eSDavid van Moolenbroek 
2220baafa0eSDavid van Moolenbroek 	/* SEF local startup. */
2230baafa0eSDavid van Moolenbroek 	env_setargs(argc, argv);
2240baafa0eSDavid van Moolenbroek 	sef_local_startup();
2250baafa0eSDavid van Moolenbroek 
2260baafa0eSDavid van Moolenbroek 	/* The main message loop. */
2270baafa0eSDavid van Moolenbroek 	for (;;) {
2280baafa0eSDavid van Moolenbroek 		if ((r = sef_receive_status(ANY, &m, &ipc_status)) != OK)
2290baafa0eSDavid van Moolenbroek 			panic("IPC: sef_receive_status failed: %d", r);
230433d6423SLionel Sambuc 
231433d6423SLionel Sambuc 		if (verbose)
2320baafa0eSDavid van Moolenbroek 			printf("IPC: got %d from %d\n", m.m_type, m.m_source);
233433d6423SLionel Sambuc 
2340baafa0eSDavid van Moolenbroek 		if (is_ipc_notify(ipc_status)) {
2350baafa0eSDavid van Moolenbroek 			printf("IPC: ignoring notification from %d\n",
2360baafa0eSDavid van Moolenbroek 			    m.m_source);
237910831cbSDavid van Moolenbroek 			continue;
2380baafa0eSDavid van Moolenbroek 		}
239910831cbSDavid van Moolenbroek 
2405b1db956SDavid van Moolenbroek 		/* Process event messages from PM are handled separately. */
241910831cbSDavid van Moolenbroek 		if (m.m_source == PM_PROC_NR && m.m_type == PROC_EVENT) {
2425b1db956SDavid van Moolenbroek 			got_proc_event(&m);
243910831cbSDavid van Moolenbroek 
2440baafa0eSDavid van Moolenbroek 			continue;
245433d6423SLionel Sambuc 		}
246433d6423SLionel Sambuc 
247*53458494SDavid van Moolenbroek 		/* Remote MIB messages from MIB are handled separately too. */
248*53458494SDavid van Moolenbroek 		if (m.m_source == MIB_PROC_NR) {
249*53458494SDavid van Moolenbroek 			rmib_process(&m, ipc_status);
250*53458494SDavid van Moolenbroek 
251*53458494SDavid van Moolenbroek 			continue;
252*53458494SDavid van Moolenbroek 		}
253*53458494SDavid van Moolenbroek 
2540baafa0eSDavid van Moolenbroek 		/* Dispatch the request. */
2550baafa0eSDavid van Moolenbroek 		call_index = (unsigned int)(m.m_type - IPC_BASE);
256433d6423SLionel Sambuc 
2570baafa0eSDavid van Moolenbroek 		if (call_index < __arraycount(call_vec) &&
2580baafa0eSDavid van Moolenbroek 		    call_vec[call_index] != NULL) {
2590baafa0eSDavid van Moolenbroek 			r = call_vec[call_index](&m);
2600baafa0eSDavid van Moolenbroek 		} else
2610baafa0eSDavid van Moolenbroek 			r = ENOSYS;
2620baafa0eSDavid van Moolenbroek 
2630baafa0eSDavid van Moolenbroek 		/* Send a reply, if needed. */
2640baafa0eSDavid van Moolenbroek 		if (r != SUSPEND) {
2650baafa0eSDavid van Moolenbroek 			if (verbose)
2660baafa0eSDavid van Moolenbroek 				printf("IPC: call result %d\n", r);
2670baafa0eSDavid van Moolenbroek 
2680baafa0eSDavid van Moolenbroek 			m.m_type = r;
2690baafa0eSDavid van Moolenbroek 			/*
2700baafa0eSDavid van Moolenbroek 			 * Other fields may have been set by the handler
2710baafa0eSDavid van Moolenbroek 			 * function already.
2720baafa0eSDavid van Moolenbroek 			 */
2730baafa0eSDavid van Moolenbroek 
2740baafa0eSDavid van Moolenbroek 			if ((r = ipc_sendnb(m.m_source, &m)) != OK)
2750baafa0eSDavid van Moolenbroek 				printf("IPC: send error %d\n", r);
2760baafa0eSDavid van Moolenbroek 		}
2770baafa0eSDavid van Moolenbroek 
2780baafa0eSDavid van Moolenbroek 		/* XXX there must be a better way to do this! */
2790baafa0eSDavid van Moolenbroek 		update_refcount_and_destroy();
2800baafa0eSDavid van Moolenbroek 	}
2810baafa0eSDavid van Moolenbroek 
2820baafa0eSDavid van Moolenbroek 	/* NOTREACHED */
2830baafa0eSDavid van Moolenbroek 	return 0;
284433d6423SLionel Sambuc }
285