1433d6423SLionel Sambuc #include "inc.h"
2433d6423SLionel Sambuc
34d272e5aSDavid van Moolenbroek /* Private shm_perm.mode flags, synchronized with NetBSD kernel values */
44d272e5aSDavid van Moolenbroek #define SHM_ALLOC 0x0800 /* slot is in use (SHMSEG_ALLOCATED) */
5433d6423SLionel Sambuc
6433d6423SLionel Sambuc struct shm_struct {
7433d6423SLionel Sambuc struct shmid_ds shmid_ds;
8433d6423SLionel Sambuc vir_bytes page;
94d272e5aSDavid van Moolenbroek phys_bytes vm_id;
10433d6423SLionel Sambuc };
114d272e5aSDavid van Moolenbroek static struct shm_struct shm_list[SHMMNI];
124d272e5aSDavid van Moolenbroek static unsigned int shm_list_nr = 0; /* highest in-use slot number plus one */
13433d6423SLionel Sambuc
140baafa0eSDavid van Moolenbroek static struct shm_struct *
shm_find_key(key_t key)150baafa0eSDavid van Moolenbroek shm_find_key(key_t key)
16433d6423SLionel Sambuc {
174d272e5aSDavid van Moolenbroek unsigned int i;
184d272e5aSDavid van Moolenbroek
19433d6423SLionel Sambuc if (key == IPC_PRIVATE)
20433d6423SLionel Sambuc return NULL;
210baafa0eSDavid van Moolenbroek
224d272e5aSDavid van Moolenbroek for (i = 0; i < shm_list_nr; i++) {
234d272e5aSDavid van Moolenbroek if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
244d272e5aSDavid van Moolenbroek continue;
254d272e5aSDavid van Moolenbroek if (shm_list[i].shmid_ds.shm_perm._key == key)
264d272e5aSDavid van Moolenbroek return &shm_list[i];
274d272e5aSDavid van Moolenbroek }
280baafa0eSDavid van Moolenbroek
29433d6423SLionel Sambuc return NULL;
30433d6423SLionel Sambuc }
31433d6423SLionel Sambuc
320baafa0eSDavid van Moolenbroek static struct shm_struct *
shm_find_id(int id)330baafa0eSDavid van Moolenbroek shm_find_id(int id)
34433d6423SLionel Sambuc {
354d272e5aSDavid van Moolenbroek struct shm_struct *shm;
364d272e5aSDavid van Moolenbroek unsigned int i;
374d272e5aSDavid van Moolenbroek
384d272e5aSDavid van Moolenbroek i = IPCID_TO_IX(id);
394d272e5aSDavid van Moolenbroek if (i >= shm_list_nr)
40433d6423SLionel Sambuc return NULL;
414d272e5aSDavid van Moolenbroek
424d272e5aSDavid van Moolenbroek shm = &shm_list[i];
434d272e5aSDavid van Moolenbroek if (!(shm->shmid_ds.shm_perm.mode & SHM_ALLOC))
444d272e5aSDavid van Moolenbroek return NULL;
454d272e5aSDavid van Moolenbroek if (shm->shmid_ds.shm_perm._seq != IPCID_TO_SEQ(id))
464d272e5aSDavid van Moolenbroek return NULL;
474d272e5aSDavid van Moolenbroek return shm;
48433d6423SLionel Sambuc }
49433d6423SLionel Sambuc
500baafa0eSDavid van Moolenbroek int
do_shmget(message * m)510baafa0eSDavid van Moolenbroek do_shmget(message * m)
52433d6423SLionel Sambuc {
53433d6423SLionel Sambuc struct shm_struct *shm;
544d272e5aSDavid van Moolenbroek unsigned int i, seq;
554d272e5aSDavid van Moolenbroek key_t key;
564d272e5aSDavid van Moolenbroek size_t size, old_size;
57433d6423SLionel Sambuc int flag;
584d272e5aSDavid van Moolenbroek void *page;
59433d6423SLionel Sambuc
60433d6423SLionel Sambuc key = m->m_lc_ipc_shmget.key;
61433d6423SLionel Sambuc old_size = size = m->m_lc_ipc_shmget.size;
62433d6423SLionel Sambuc flag = m->m_lc_ipc_shmget.flag;
63433d6423SLionel Sambuc
640baafa0eSDavid van Moolenbroek if ((shm = shm_find_key(key)) != NULL) {
650baafa0eSDavid van Moolenbroek if (!check_perm(&shm->shmid_ds.shm_perm, m->m_source, flag))
66433d6423SLionel Sambuc return EACCES;
67433d6423SLionel Sambuc if ((flag & IPC_CREAT) && (flag & IPC_EXCL))
68433d6423SLionel Sambuc return EEXIST;
69433d6423SLionel Sambuc if (size && shm->shmid_ds.shm_segsz < size)
70433d6423SLionel Sambuc return EINVAL;
714d272e5aSDavid van Moolenbroek i = shm - shm_list;
72433d6423SLionel Sambuc } else { /* no key found */
73433d6423SLionel Sambuc if (!(flag & IPC_CREAT))
74433d6423SLionel Sambuc return ENOENT;
75433d6423SLionel Sambuc if (size <= 0)
76433d6423SLionel Sambuc return EINVAL;
770baafa0eSDavid van Moolenbroek size = roundup(size, PAGE_SIZE);
78433d6423SLionel Sambuc if (size <= 0)
79433d6423SLionel Sambuc return EINVAL;
80433d6423SLionel Sambuc
814d272e5aSDavid van Moolenbroek /* Find a free entry. */
824d272e5aSDavid van Moolenbroek for (i = 0; i < __arraycount(shm_list); i++)
834d272e5aSDavid van Moolenbroek if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
844d272e5aSDavid van Moolenbroek break;
854d272e5aSDavid van Moolenbroek if (i == __arraycount(shm_list))
86433d6423SLionel Sambuc return ENOSPC;
87433d6423SLionel Sambuc
884d272e5aSDavid van Moolenbroek /*
894d272e5aSDavid van Moolenbroek * Allocate memory to share. For now, we store the page
904d272e5aSDavid van Moolenbroek * reference as a numerical value so as to avoid issues with
914d272e5aSDavid van Moolenbroek * live update. TODO: a proper solution.
924d272e5aSDavid van Moolenbroek */
934d272e5aSDavid van Moolenbroek page = mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON, -1, 0);
944d272e5aSDavid van Moolenbroek if (page == MAP_FAILED)
954d272e5aSDavid van Moolenbroek return ENOMEM;
964d272e5aSDavid van Moolenbroek memset(page, 0, size);
974d272e5aSDavid van Moolenbroek
984d272e5aSDavid van Moolenbroek /* Initialize the entry. */
994d272e5aSDavid van Moolenbroek shm = &shm_list[i];
1004d272e5aSDavid van Moolenbroek seq = shm->shmid_ds.shm_perm._seq;
1010baafa0eSDavid van Moolenbroek memset(shm, 0, sizeof(*shm));
1024d272e5aSDavid van Moolenbroek
1034d272e5aSDavid van Moolenbroek shm->shmid_ds.shm_perm._key = key;
104433d6423SLionel Sambuc shm->shmid_ds.shm_perm.cuid =
1050baafa0eSDavid van Moolenbroek shm->shmid_ds.shm_perm.uid = getnuid(m->m_source);
106433d6423SLionel Sambuc shm->shmid_ds.shm_perm.cgid =
1070baafa0eSDavid van Moolenbroek shm->shmid_ds.shm_perm.gid = getngid(m->m_source);
1084d272e5aSDavid van Moolenbroek shm->shmid_ds.shm_perm.mode = SHM_ALLOC | (flag & ACCESSPERMS);
1094d272e5aSDavid van Moolenbroek shm->shmid_ds.shm_perm._seq = (seq + 1) & 0x7fff;
110433d6423SLionel Sambuc shm->shmid_ds.shm_segsz = old_size;
111433d6423SLionel Sambuc shm->shmid_ds.shm_atime = 0;
112433d6423SLionel Sambuc shm->shmid_ds.shm_dtime = 0;
1134d272e5aSDavid van Moolenbroek shm->shmid_ds.shm_ctime = clock_time(NULL);
1140baafa0eSDavid van Moolenbroek shm->shmid_ds.shm_cpid = getnpid(m->m_source);
115433d6423SLionel Sambuc shm->shmid_ds.shm_lpid = 0;
116433d6423SLionel Sambuc shm->shmid_ds.shm_nattch = 0;
1174d272e5aSDavid van Moolenbroek shm->page = (vir_bytes)page;
1184d272e5aSDavid van Moolenbroek shm->vm_id = vm_getphys(sef_self(), page);
119433d6423SLionel Sambuc
1204d272e5aSDavid van Moolenbroek assert(i <= shm_list_nr);
1214d272e5aSDavid van Moolenbroek if (i == shm_list_nr)
122433d6423SLionel Sambuc shm_list_nr++;
123433d6423SLionel Sambuc }
124433d6423SLionel Sambuc
1254d272e5aSDavid van Moolenbroek m->m_lc_ipc_shmget.retid = IXSEQ_TO_IPCID(i, shm->shmid_ds.shm_perm);
126433d6423SLionel Sambuc return OK;
127433d6423SLionel Sambuc }
128433d6423SLionel Sambuc
1290baafa0eSDavid van Moolenbroek int
do_shmat(message * m)1300baafa0eSDavid van Moolenbroek do_shmat(message * m)
131433d6423SLionel Sambuc {
13256dc79ceSDavid van Moolenbroek int id, flag, mask;
133433d6423SLionel Sambuc vir_bytes addr;
134433d6423SLionel Sambuc void *ret;
135433d6423SLionel Sambuc struct shm_struct *shm;
136433d6423SLionel Sambuc
137433d6423SLionel Sambuc id = m->m_lc_ipc_shmat.id;
138433d6423SLionel Sambuc addr = (vir_bytes)m->m_lc_ipc_shmat.addr;
139433d6423SLionel Sambuc flag = m->m_lc_ipc_shmat.flag;
140433d6423SLionel Sambuc
1410baafa0eSDavid van Moolenbroek if (addr % PAGE_SIZE) {
142433d6423SLionel Sambuc if (flag & SHM_RND)
1430baafa0eSDavid van Moolenbroek addr -= addr % PAGE_SIZE;
144433d6423SLionel Sambuc else
145433d6423SLionel Sambuc return EINVAL;
146433d6423SLionel Sambuc }
147433d6423SLionel Sambuc
1480baafa0eSDavid van Moolenbroek if ((shm = shm_find_id(id)) == NULL)
149433d6423SLionel Sambuc return EINVAL;
150433d6423SLionel Sambuc
15156dc79ceSDavid van Moolenbroek mask = 0;
152433d6423SLionel Sambuc if (flag & SHM_RDONLY)
15356dc79ceSDavid van Moolenbroek mask = IPC_R;
154433d6423SLionel Sambuc else
15556dc79ceSDavid van Moolenbroek mask = IPC_R | IPC_W;
15656dc79ceSDavid van Moolenbroek if (!check_perm(&shm->shmid_ds.shm_perm, m->m_source, mask))
157433d6423SLionel Sambuc return EACCES;
158433d6423SLionel Sambuc
1590baafa0eSDavid van Moolenbroek ret = vm_remap(m->m_source, sef_self(), (void *)addr,
1600baafa0eSDavid van Moolenbroek (void *)shm->page, shm->shmid_ds.shm_segsz);
161433d6423SLionel Sambuc if (ret == MAP_FAILED)
162433d6423SLionel Sambuc return ENOMEM;
163433d6423SLionel Sambuc
1644d272e5aSDavid van Moolenbroek shm->shmid_ds.shm_atime = clock_time(NULL);
1650baafa0eSDavid van Moolenbroek shm->shmid_ds.shm_lpid = getnpid(m->m_source);
1660baafa0eSDavid van Moolenbroek /* nattch is updated lazily */
167433d6423SLionel Sambuc
168433d6423SLionel Sambuc m->m_lc_ipc_shmat.retaddr = ret;
169433d6423SLionel Sambuc return OK;
170433d6423SLionel Sambuc }
171433d6423SLionel Sambuc
1720baafa0eSDavid van Moolenbroek void
update_refcount_and_destroy(void)1730baafa0eSDavid van Moolenbroek update_refcount_and_destroy(void)
174433d6423SLionel Sambuc {
175433d6423SLionel Sambuc u8_t rc;
1764d272e5aSDavid van Moolenbroek unsigned int i;
1774d272e5aSDavid van Moolenbroek
1784d272e5aSDavid van Moolenbroek for (i = 0; i < shm_list_nr; i++) {
1794d272e5aSDavid van Moolenbroek if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
1804d272e5aSDavid van Moolenbroek continue;
181433d6423SLionel Sambuc
182433d6423SLionel Sambuc rc = vm_getrefcount(sef_self(), (void *)shm_list[i].page);
183433d6423SLionel Sambuc if (rc == (u8_t)-1) {
184433d6423SLionel Sambuc printf("IPC: can't find physical region.\n");
185433d6423SLionel Sambuc continue;
186433d6423SLionel Sambuc }
187433d6423SLionel Sambuc shm_list[i].shmid_ds.shm_nattch = rc - 1;
188433d6423SLionel Sambuc
1894d272e5aSDavid van Moolenbroek if (shm_list[i].shmid_ds.shm_nattch == 0 &&
1904d272e5aSDavid van Moolenbroek (shm_list[i].shmid_ds.shm_perm.mode & SHM_DEST)) {
1910baafa0eSDavid van Moolenbroek munmap((void *)shm_list[i].page,
1920baafa0eSDavid van Moolenbroek roundup(shm_list[i].shmid_ds.shm_segsz,
1930baafa0eSDavid van Moolenbroek PAGE_SIZE));
1944d272e5aSDavid van Moolenbroek /* Mark the entry as free. */
1954d272e5aSDavid van Moolenbroek shm_list[i].shmid_ds.shm_perm.mode &= ~SHM_ALLOC;
196433d6423SLionel Sambuc }
197433d6423SLionel Sambuc }
1984d272e5aSDavid van Moolenbroek
1994d272e5aSDavid van Moolenbroek /*
2004d272e5aSDavid van Moolenbroek * Now that we may have removed an arbitrary set of slots, ensure that
2014d272e5aSDavid van Moolenbroek * shm_list_nr again equals the highest in-use slot number plus one.
2024d272e5aSDavid van Moolenbroek */
2034d272e5aSDavid van Moolenbroek while (shm_list_nr > 0 &&
2044d272e5aSDavid van Moolenbroek !(shm_list[shm_list_nr - 1].shmid_ds.shm_perm.mode & SHM_ALLOC))
2054d272e5aSDavid van Moolenbroek shm_list_nr--;
206433d6423SLionel Sambuc }
207433d6423SLionel Sambuc
2080baafa0eSDavid van Moolenbroek int
do_shmdt(message * m)2090baafa0eSDavid van Moolenbroek do_shmdt(message * m)
210433d6423SLionel Sambuc {
2114d272e5aSDavid van Moolenbroek struct shm_struct *shm;
212433d6423SLionel Sambuc vir_bytes addr;
213433d6423SLionel Sambuc phys_bytes vm_id;
2144d272e5aSDavid van Moolenbroek unsigned int i;
215433d6423SLionel Sambuc
216433d6423SLionel Sambuc addr = (vir_bytes)m->m_lc_ipc_shmdt.addr;
217433d6423SLionel Sambuc
2180baafa0eSDavid van Moolenbroek if ((vm_id = vm_getphys(m->m_source, (void *)addr)) == 0)
219433d6423SLionel Sambuc return EINVAL;
220433d6423SLionel Sambuc
221433d6423SLionel Sambuc for (i = 0; i < shm_list_nr; i++) {
2224d272e5aSDavid van Moolenbroek shm = &shm_list[i];
223433d6423SLionel Sambuc
2244d272e5aSDavid van Moolenbroek if (!(shm->shmid_ds.shm_perm.mode & SHM_ALLOC))
2254d272e5aSDavid van Moolenbroek continue;
2264d272e5aSDavid van Moolenbroek
2274d272e5aSDavid van Moolenbroek if (shm->vm_id == vm_id) {
2284d272e5aSDavid van Moolenbroek shm->shmid_ds.shm_atime = clock_time(NULL);
2290baafa0eSDavid van Moolenbroek shm->shmid_ds.shm_lpid = getnpid(m->m_source);
230433d6423SLionel Sambuc /* nattch is updated lazily */
231433d6423SLionel Sambuc
2320baafa0eSDavid van Moolenbroek vm_unmap(m->m_source, (void *)addr);
233433d6423SLionel Sambuc break;
234433d6423SLionel Sambuc }
235433d6423SLionel Sambuc }
236433d6423SLionel Sambuc if (i == shm_list_nr)
2370baafa0eSDavid van Moolenbroek printf("IPC: do_shmdt: ID %lu not found\n", vm_id);
238433d6423SLionel Sambuc
239433d6423SLionel Sambuc update_refcount_and_destroy();
240433d6423SLionel Sambuc
241433d6423SLionel Sambuc return OK;
242433d6423SLionel Sambuc }
243433d6423SLionel Sambuc
244*53458494SDavid van Moolenbroek /*
245*53458494SDavid van Moolenbroek * Fill a shminfo structure with actual information.
246*53458494SDavid van Moolenbroek */
247*53458494SDavid van Moolenbroek static void
fill_shminfo(struct shminfo * sinfo)248*53458494SDavid van Moolenbroek fill_shminfo(struct shminfo * sinfo)
249*53458494SDavid van Moolenbroek {
250*53458494SDavid van Moolenbroek
251*53458494SDavid van Moolenbroek memset(sinfo, 0, sizeof(*sinfo));
252*53458494SDavid van Moolenbroek
253*53458494SDavid van Moolenbroek sinfo->shmmax = (unsigned long)-1;
254*53458494SDavid van Moolenbroek sinfo->shmmin = 1;
255*53458494SDavid van Moolenbroek sinfo->shmmni = __arraycount(shm_list);
256*53458494SDavid van Moolenbroek sinfo->shmseg = (unsigned long)-1;
257*53458494SDavid van Moolenbroek sinfo->shmall = (unsigned long)-1;
258*53458494SDavid van Moolenbroek }
259*53458494SDavid van Moolenbroek
2600baafa0eSDavid van Moolenbroek int
do_shmctl(message * m)2610baafa0eSDavid van Moolenbroek do_shmctl(message * m)
262433d6423SLionel Sambuc {
263433d6423SLionel Sambuc struct shmid_ds tmp_ds;
2644d272e5aSDavid van Moolenbroek struct shm_struct *shm;
265433d6423SLionel Sambuc struct shminfo sinfo;
266433d6423SLionel Sambuc struct shm_info s_info;
2670baafa0eSDavid van Moolenbroek vir_bytes buf;
2684d272e5aSDavid van Moolenbroek unsigned int i;
269433d6423SLionel Sambuc uid_t uid;
2704d272e5aSDavid van Moolenbroek int r, id, cmd;
271433d6423SLionel Sambuc
2724d272e5aSDavid van Moolenbroek id = m->m_lc_ipc_shmctl.id;
2734d272e5aSDavid van Moolenbroek cmd = m->m_lc_ipc_shmctl.cmd;
2740baafa0eSDavid van Moolenbroek buf = (vir_bytes)m->m_lc_ipc_shmctl.buf;
2754d272e5aSDavid van Moolenbroek
2764d272e5aSDavid van Moolenbroek /*
2774d272e5aSDavid van Moolenbroek * For stat calls, sure that all information is up-to-date. Since this
2784d272e5aSDavid van Moolenbroek * may free the slot, do this before mapping from ID to slot below.
2794d272e5aSDavid van Moolenbroek */
2804d272e5aSDavid van Moolenbroek if (cmd == IPC_STAT || cmd == SHM_STAT)
281433d6423SLionel Sambuc update_refcount_and_destroy();
282433d6423SLionel Sambuc
2834d272e5aSDavid van Moolenbroek switch (cmd) {
2844d272e5aSDavid van Moolenbroek case IPC_INFO:
2854d272e5aSDavid van Moolenbroek case SHM_INFO:
2864d272e5aSDavid van Moolenbroek shm = NULL;
2874d272e5aSDavid van Moolenbroek break;
2884d272e5aSDavid van Moolenbroek case SHM_STAT:
2894d272e5aSDavid van Moolenbroek if (id < 0 || (unsigned int)id >= shm_list_nr)
290433d6423SLionel Sambuc return EINVAL;
2914d272e5aSDavid van Moolenbroek shm = &shm_list[id];
2924d272e5aSDavid van Moolenbroek if (!(shm->shmid_ds.shm_perm.mode & SHM_ALLOC))
2934d272e5aSDavid van Moolenbroek return EINVAL;
2944d272e5aSDavid van Moolenbroek break;
2954d272e5aSDavid van Moolenbroek default:
2960baafa0eSDavid van Moolenbroek if ((shm = shm_find_id(id)) == NULL)
2974d272e5aSDavid van Moolenbroek return EINVAL;
2984d272e5aSDavid van Moolenbroek break;
2994d272e5aSDavid van Moolenbroek }
300433d6423SLionel Sambuc
301433d6423SLionel Sambuc switch (cmd) {
302433d6423SLionel Sambuc case IPC_STAT:
3034d272e5aSDavid van Moolenbroek case SHM_STAT:
3044d272e5aSDavid van Moolenbroek /* Check whether the caller has read permission. */
30556dc79ceSDavid van Moolenbroek if (!check_perm(&shm->shmid_ds.shm_perm, m->m_source, IPC_R))
306433d6423SLionel Sambuc return EACCES;
3070baafa0eSDavid van Moolenbroek if ((r = sys_datacopy(SELF, (vir_bytes)&shm->shmid_ds,
3080baafa0eSDavid van Moolenbroek m->m_source, buf, sizeof(shm->shmid_ds))) != OK)
3094d272e5aSDavid van Moolenbroek return r;
3104d272e5aSDavid van Moolenbroek if (cmd == SHM_STAT)
3114d272e5aSDavid van Moolenbroek m->m_lc_ipc_shmctl.ret =
3124d272e5aSDavid van Moolenbroek IXSEQ_TO_IPCID(id, shm->shmid_ds.shm_perm);
313433d6423SLionel Sambuc break;
314433d6423SLionel Sambuc case IPC_SET:
3150baafa0eSDavid van Moolenbroek uid = getnuid(m->m_source);
316433d6423SLionel Sambuc if (uid != shm->shmid_ds.shm_perm.cuid &&
3170baafa0eSDavid van Moolenbroek uid != shm->shmid_ds.shm_perm.uid && uid != 0)
318433d6423SLionel Sambuc return EPERM;
3190baafa0eSDavid van Moolenbroek if ((r = sys_datacopy(m->m_source, buf, SELF,
3200baafa0eSDavid van Moolenbroek (vir_bytes)&tmp_ds, sizeof(tmp_ds))) != OK)
3214d272e5aSDavid van Moolenbroek return r;
322433d6423SLionel Sambuc shm->shmid_ds.shm_perm.uid = tmp_ds.shm_perm.uid;
323433d6423SLionel Sambuc shm->shmid_ds.shm_perm.gid = tmp_ds.shm_perm.gid;
3244d272e5aSDavid van Moolenbroek shm->shmid_ds.shm_perm.mode &= ~ACCESSPERMS;
3254d272e5aSDavid van Moolenbroek shm->shmid_ds.shm_perm.mode |=
3264d272e5aSDavid van Moolenbroek tmp_ds.shm_perm.mode & ACCESSPERMS;
3274d272e5aSDavid van Moolenbroek shm->shmid_ds.shm_ctime = clock_time(NULL);
328433d6423SLionel Sambuc break;
329433d6423SLionel Sambuc case IPC_RMID:
3300baafa0eSDavid van Moolenbroek uid = getnuid(m->m_source);
331433d6423SLionel Sambuc if (uid != shm->shmid_ds.shm_perm.cuid &&
3320baafa0eSDavid van Moolenbroek uid != shm->shmid_ds.shm_perm.uid && uid != 0)
333433d6423SLionel Sambuc return EPERM;
334433d6423SLionel Sambuc shm->shmid_ds.shm_perm.mode |= SHM_DEST;
3350baafa0eSDavid van Moolenbroek /* Destroy if possible. */
336433d6423SLionel Sambuc update_refcount_and_destroy();
337433d6423SLionel Sambuc break;
338433d6423SLionel Sambuc case IPC_INFO:
339*53458494SDavid van Moolenbroek fill_shminfo(&sinfo);
3400baafa0eSDavid van Moolenbroek if ((r = sys_datacopy(SELF, (vir_bytes)&sinfo, m->m_source,
3410baafa0eSDavid van Moolenbroek buf, sizeof(sinfo))) != OK)
3424d272e5aSDavid van Moolenbroek return r;
3434d272e5aSDavid van Moolenbroek if (shm_list_nr > 0)
3444d272e5aSDavid van Moolenbroek m->m_lc_ipc_shmctl.ret = shm_list_nr - 1;
3454d272e5aSDavid van Moolenbroek else
346433d6423SLionel Sambuc m->m_lc_ipc_shmctl.ret = 0;
347433d6423SLionel Sambuc break;
348433d6423SLionel Sambuc case SHM_INFO:
3494d272e5aSDavid van Moolenbroek memset(&s_info, 0, sizeof(s_info));
350433d6423SLionel Sambuc s_info.used_ids = shm_list_nr;
351433d6423SLionel Sambuc s_info.shm_tot = 0;
352433d6423SLionel Sambuc for (i = 0; i < shm_list_nr; i++)
353433d6423SLionel Sambuc s_info.shm_tot +=
354433d6423SLionel Sambuc shm_list[i].shmid_ds.shm_segsz / PAGE_SIZE;
355433d6423SLionel Sambuc s_info.shm_rss = s_info.shm_tot;
356433d6423SLionel Sambuc s_info.shm_swp = 0;
357433d6423SLionel Sambuc s_info.swap_attempts = 0;
358433d6423SLionel Sambuc s_info.swap_successes = 0;
3590baafa0eSDavid van Moolenbroek if ((r = sys_datacopy(SELF, (vir_bytes)&s_info, m->m_source,
3600baafa0eSDavid van Moolenbroek buf, sizeof(s_info))) != OK)
3614d272e5aSDavid van Moolenbroek return r;
3624d272e5aSDavid van Moolenbroek if (shm_list_nr > 0)
363433d6423SLionel Sambuc m->m_lc_ipc_shmctl.ret = shm_list_nr - 1;
3644d272e5aSDavid van Moolenbroek else
365433d6423SLionel Sambuc m->m_lc_ipc_shmctl.ret = 0;
366433d6423SLionel Sambuc break;
367433d6423SLionel Sambuc default:
368433d6423SLionel Sambuc return EINVAL;
369433d6423SLionel Sambuc }
370433d6423SLionel Sambuc return OK;
371433d6423SLionel Sambuc }
372433d6423SLionel Sambuc
373*53458494SDavid van Moolenbroek /*
374*53458494SDavid van Moolenbroek * Return shared memory information for a remote MIB call on the sysvipc_info
375*53458494SDavid van Moolenbroek * node in the kern.ipc subtree. The particular semantics of this call are
376*53458494SDavid van Moolenbroek * tightly coupled to the implementation of the ipcs(1) userland utility.
377*53458494SDavid van Moolenbroek */
378*53458494SDavid van Moolenbroek ssize_t
get_shm_mib_info(struct rmib_oldp * oldp)379*53458494SDavid van Moolenbroek get_shm_mib_info(struct rmib_oldp * oldp)
380*53458494SDavid van Moolenbroek {
381*53458494SDavid van Moolenbroek struct shm_sysctl_info shmsi;
382*53458494SDavid van Moolenbroek struct shmid_ds *shmds;
383*53458494SDavid van Moolenbroek unsigned int i;
384*53458494SDavid van Moolenbroek ssize_t r, off;
385*53458494SDavid van Moolenbroek
386*53458494SDavid van Moolenbroek off = 0;
387*53458494SDavid van Moolenbroek
388*53458494SDavid van Moolenbroek fill_shminfo(&shmsi.shminfo);
389*53458494SDavid van Moolenbroek
390*53458494SDavid van Moolenbroek /*
391*53458494SDavid van Moolenbroek * As a hackish exception, the requested size may imply that just
392*53458494SDavid van Moolenbroek * general information is to be returned, without throwing an ENOMEM
393*53458494SDavid van Moolenbroek * error because there is no space for full output.
394*53458494SDavid van Moolenbroek */
395*53458494SDavid van Moolenbroek if (rmib_getoldlen(oldp) == sizeof(shmsi.shminfo))
396*53458494SDavid van Moolenbroek return rmib_copyout(oldp, 0, &shmsi.shminfo,
397*53458494SDavid van Moolenbroek sizeof(shmsi.shminfo));
398*53458494SDavid van Moolenbroek
399*53458494SDavid van Moolenbroek /*
400*53458494SDavid van Moolenbroek * ipcs(1) blindly expects the returned array to be of size
401*53458494SDavid van Moolenbroek * shminfo.shmmni, using the SHMSEG_ALLOCATED (aka SHM_ALLOC) mode flag
402*53458494SDavid van Moolenbroek * to see whether each entry is valid. If we return a smaller size,
403*53458494SDavid van Moolenbroek * ipcs(1) will access arbitrary memory.
404*53458494SDavid van Moolenbroek */
405*53458494SDavid van Moolenbroek assert(shmsi.shminfo.shmmni > 0);
406*53458494SDavid van Moolenbroek
407*53458494SDavid van Moolenbroek if (oldp == NULL)
408*53458494SDavid van Moolenbroek return sizeof(shmsi) + sizeof(shmsi.shmids[0]) *
409*53458494SDavid van Moolenbroek (shmsi.shminfo.shmmni - 1);
410*53458494SDavid van Moolenbroek
411*53458494SDavid van Moolenbroek /*
412*53458494SDavid van Moolenbroek * Copy out entries one by one. For the first entry, copy out the
413*53458494SDavid van Moolenbroek * entire "shmsi" structure. For subsequent entries, reuse the single
414*53458494SDavid van Moolenbroek * embedded 'shmids' element of "shmsi" and copy out only that element.
415*53458494SDavid van Moolenbroek */
416*53458494SDavid van Moolenbroek for (i = 0; i < shmsi.shminfo.shmmni; i++) {
417*53458494SDavid van Moolenbroek shmds = &shm_list[i].shmid_ds;
418*53458494SDavid van Moolenbroek
419*53458494SDavid van Moolenbroek memset(&shmsi.shmids[0], 0, sizeof(shmsi.shmids[0]));
420*53458494SDavid van Moolenbroek if (i < shm_list_nr && (shmds->shm_perm.mode & SHM_ALLOC)) {
421*53458494SDavid van Moolenbroek prepare_mib_perm(&shmsi.shmids[0].shm_perm,
422*53458494SDavid van Moolenbroek &shmds->shm_perm);
423*53458494SDavid van Moolenbroek shmsi.shmids[0].shm_segsz = shmds->shm_segsz;
424*53458494SDavid van Moolenbroek shmsi.shmids[0].shm_lpid = shmds->shm_lpid;
425*53458494SDavid van Moolenbroek shmsi.shmids[0].shm_cpid = shmds->shm_cpid;
426*53458494SDavid van Moolenbroek shmsi.shmids[0].shm_atime = shmds->shm_atime;
427*53458494SDavid van Moolenbroek shmsi.shmids[0].shm_dtime = shmds->shm_dtime;
428*53458494SDavid van Moolenbroek shmsi.shmids[0].shm_ctime = shmds->shm_ctime;
429*53458494SDavid van Moolenbroek shmsi.shmids[0].shm_nattch = shmds->shm_nattch;
430*53458494SDavid van Moolenbroek }
431*53458494SDavid van Moolenbroek
432*53458494SDavid van Moolenbroek if (off == 0)
433*53458494SDavid van Moolenbroek r = rmib_copyout(oldp, off, &shmsi, sizeof(shmsi));
434*53458494SDavid van Moolenbroek else
435*53458494SDavid van Moolenbroek r = rmib_copyout(oldp, off, &shmsi.shmids[0],
436*53458494SDavid van Moolenbroek sizeof(shmsi.shmids[0]));
437*53458494SDavid van Moolenbroek
438*53458494SDavid van Moolenbroek if (r < 0)
439*53458494SDavid van Moolenbroek return r;
440*53458494SDavid van Moolenbroek off += r;
441*53458494SDavid van Moolenbroek }
442*53458494SDavid van Moolenbroek
443*53458494SDavid van Moolenbroek return off;
444*53458494SDavid van Moolenbroek }
445*53458494SDavid van Moolenbroek
446433d6423SLionel Sambuc #if 0
4470baafa0eSDavid van Moolenbroek static void
4480baafa0eSDavid van Moolenbroek list_shm_ds(void)
449433d6423SLionel Sambuc {
4504d272e5aSDavid van Moolenbroek unsigned int i;
4510baafa0eSDavid van Moolenbroek
452433d6423SLionel Sambuc printf("key\tid\tpage\n");
4534d272e5aSDavid van Moolenbroek for (i = 0; i < shm_list_nr; i++) {
4544d272e5aSDavid van Moolenbroek if (!(shm_list[i].shmid_ds.shm_perm.mode & SHM_ALLOC))
4554d272e5aSDavid van Moolenbroek continue;
456433d6423SLionel Sambuc printf("%ld\t%d\t%lx\n",
4574d272e5aSDavid van Moolenbroek shm_list[i].shmid_ds.shm_perm._key,
4584d272e5aSDavid van Moolenbroek IXSEQ_TO_IPCID(i, shm_list[i].shmid_ds.shm_perm),
459433d6423SLionel Sambuc shm_list[i].page);
460433d6423SLionel Sambuc }
4614d272e5aSDavid van Moolenbroek }
462433d6423SLionel Sambuc #endif
463433d6423SLionel Sambuc
4640baafa0eSDavid van Moolenbroek int
is_shm_nil(void)4650baafa0eSDavid van Moolenbroek is_shm_nil(void)
466433d6423SLionel Sambuc {
4670baafa0eSDavid van Moolenbroek
468433d6423SLionel Sambuc return (shm_list_nr == 0);
469433d6423SLionel Sambuc }
470