]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/posix_shm.c
xnu-517.11.1.tar.gz
[apple/xnu.git] / bsd / kern / posix_shm.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /*
23 * Copyright (c) 1990, 1996-1998 Apple Computer, Inc.
24 * All Rights Reserved.
25 */
26 /*
27 * posix_shm.c : Support for POSIX shared memory APIs
28 *
29 * File: posix_shm.c
30 * Author: Ananthakrishna Ramesh
31 *
32 * HISTORY
33 * 2-Sep-1999 A.Ramesh
34 * Created for MacOSX
35 *
36 */
37
38 #include <sys/cdefs.h>
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/kernel.h>
42 #include <sys/file.h>
43 #include <sys/filedesc.h>
44 #include <sys/stat.h>
45 #include <sys/buf.h>
46 #include <sys/proc.h>
47 #include <sys/mount.h>
48 #include <sys/namei.h>
49 #include <sys/vnode.h>
50 #include <sys/ioctl.h>
51 #include <sys/tty.h>
52 #include <sys/malloc.h>
53 #include <sys/mman.h>
54
55 #include <bsm/audit_kernel.h>
56
57 #include <mach/mach_types.h>
58 #include <mach/vm_prot.h>
59 #include <mach/vm_inherit.h>
60 #include <mach/kern_return.h>
61 #include <mach/memory_object_control.h>
62
63
64 #define PSHMNAMLEN 31 /* maximum name segment length we bother with */
65
66 struct pshminfo {
67 unsigned int pshm_flags;
68 unsigned int pshm_usecount;
69 off_t pshm_length;
70 mode_t pshm_mode;
71 uid_t pshm_uid;
72 gid_t pshm_gid;
73 char pshm_name[PSHMNAMLEN + 1]; /* segment name */
74 void * pshm_memobject;
75 #if DIAGNOSTIC
76 unsigned int pshm_readcount;
77 unsigned int pshm_writecount;
78 struct proc * pshm_proc;
79 #endif /* DIAGNOSTIC */
80 };
81 #define PSHMINFO_NULL (struct pshminfo *)0
82
83 #define PSHM_NONE 1
84 #define PSHM_DEFINED 2
85 #define PSHM_ALLOCATED 4
86 #define PSHM_MAPPED 8
87 #define PSHM_INUSE 0x10
88 #define PSHM_REMOVED 0x20
89 #define PSHM_INCREATE 0x40
90 #define PSHM_INDELETE 0x80
91
92 struct pshmcache {
93 LIST_ENTRY(pshmcache) pshm_hash; /* hash chain */
94 struct pshminfo *pshminfo; /* vnode the name refers to */
95 int pshm_nlen; /* length of name */
96 char pshm_name[PSHMNAMLEN + 1]; /* segment name */
97 };
98 #define PSHMCACHE_NULL (struct pshmcache *)0
99
100 struct pshmstats {
101 long goodhits; /* hits that we can really use */
102 long neghits; /* negative hits that we can use */
103 long badhits; /* hits we must drop */
104 long falsehits; /* hits with id mismatch */
105 long miss; /* misses */
106 long longnames; /* long names that ignore cache */
107 };
108
109 struct pshmname {
110 char *pshm_nameptr; /* pointer to looked up name */
111 long pshm_namelen; /* length of looked up component */
112 u_long pshm_hash; /* hash value of looked up name */
113 };
114
115 struct pshmnode {
116 off_t mapp_addr;
117 size_t map_size;
118 struct pshminfo *pinfo;
119 unsigned int pshm_usecount;
120 #if DIAGNOSTIC
121 unsigned int readcnt;
122 unsigned int writecnt;
123 #endif
124 };
125 #define PSHMNODE_NULL (struct pshmnode *)0
126
127
128 #define PSHMHASH(pnp) \
129 (&pshmhashtbl[(pnp)->pshm_hash & pshmhash])
130 LIST_HEAD(pshmhashhead, pshmcache) *pshmhashtbl; /* Hash Table */
131 u_long pshmhash; /* size of hash table - 1 */
132 long pshmnument; /* number of cache entries allocated */
133 struct pshmstats pshmstats; /* cache effectiveness statistics */
134
135 static int pshm_read __P((struct file *fp, struct uio *uio,
136 struct ucred *cred, int flags, struct proc *p));
137 static int pshm_write __P((struct file *fp, struct uio *uio,
138 struct ucred *cred, int flags, struct proc *p));
139 static int pshm_ioctl __P((struct file *fp, u_long com,
140 caddr_t data, struct proc *p));
141 static int pshm_select __P((struct file *fp, int which, void *wql,
142 struct proc *p));
143 static int pshm_closefile __P((struct file *fp, struct proc *p));
144
145 static int pshm_kqfilter __P((struct file *fp, struct knote *kn, struct proc *p));
146
147 struct fileops pshmops =
148 { pshm_read, pshm_write, pshm_ioctl, pshm_select, pshm_closefile, pshm_kqfilter };
149
150 /*
151 * Lookup an entry in the cache
152 *
153 *
154 * status of -1 is returned if matches
155 * If the lookup determines that the name does not exist
156 * (negative cacheing), a status of ENOENT is returned. If the lookup
157 * fails, a status of zero is returned.
158 */
159
160 int
161 pshm_cache_search(pshmp, pnp, pcache)
162 struct pshminfo **pshmp;
163 struct pshmname *pnp;
164 struct pshmcache **pcache;
165 {
166 register struct pshmcache *pcp, *nnp;
167 register struct pshmhashhead *pcpp;
168
169 if (pnp->pshm_namelen > PSHMNAMLEN) {
170 pshmstats.longnames++;
171 return (0);
172 }
173
174 pcpp = PSHMHASH(pnp);
175 for (pcp = pcpp->lh_first; pcp != 0; pcp = nnp) {
176 nnp = pcp->pshm_hash.le_next;
177 if (pcp->pshm_nlen == pnp->pshm_namelen &&
178 !bcmp(pcp->pshm_name, pnp->pshm_nameptr, (u_int)pcp-> pshm_nlen))
179 break;
180 }
181
182 if (pcp == 0) {
183 pshmstats.miss++;
184 return (0);
185 }
186
187 /* We found a "positive" match, return the vnode */
188 if (pcp->pshminfo) {
189 pshmstats.goodhits++;
190 /* TOUCH(ncp); */
191 *pshmp = pcp->pshminfo;
192 *pcache = pcp;
193 return (-1);
194 }
195
196 /*
197 * We found a "negative" match, ENOENT notifies client of this match.
198 * The nc_vpid field records whether this is a whiteout.
199 */
200 pshmstats.neghits++;
201 return (ENOENT);
202 }
203
204 /*
205 * Add an entry to the cache.
206 */
207 int
208 pshm_cache_add(pshmp, pnp)
209 struct pshminfo *pshmp;
210 struct pshmname *pnp;
211 {
212 register struct pshmcache *pcp;
213 register struct pshmhashhead *pcpp;
214 struct pshminfo *dpinfo;
215 struct pshmcache *dpcp;
216
217 #if DIAGNOSTIC
218 if (pnp->pshm_namelen > NCHNAMLEN)
219 panic("cache_enter: name too long");
220 #endif
221
222 /*
223 * We allocate a new entry if we are less than the maximum
224 * allowed and the one at the front of the LRU list is in use.
225 * Otherwise we use the one at the front of the LRU list.
226 */
227 pcp = (struct pshmcache *)_MALLOC(sizeof(struct pshmcache), M_SHM, M_WAITOK);
228 /* if the entry has already been added by some one else return */
229 if (pshm_cache_search(&dpinfo, pnp, &dpcp) == -1) {
230 _FREE(pcp, M_SHM);
231 return(EEXIST);
232 }
233 pshmnument++;
234
235 bzero(pcp, sizeof(struct pshmcache));
236 /*
237 * Fill in cache info, if vp is NULL this is a "negative" cache entry.
238 * For negative entries, we have to record whether it is a whiteout.
239 * the whiteout flag is stored in the nc_vpid field which is
240 * otherwise unused.
241 */
242 pcp->pshminfo = pshmp;
243 pcp->pshm_nlen = pnp->pshm_namelen;
244 bcopy(pnp->pshm_nameptr, pcp->pshm_name, (unsigned)pcp->pshm_nlen);
245 pcpp = PSHMHASH(pnp);
246 #if DIAGNOSTIC
247 {
248 register struct pshmcache *p;
249
250 for (p = pcpp->lh_first; p != 0; p = p->pshm_hash.le_next)
251 if (p == pcp)
252 panic("cache_enter: duplicate");
253 }
254 #endif
255 LIST_INSERT_HEAD(pcpp, pcp, pshm_hash);
256 return(0);
257 }
258
259 /*
260 * Name cache initialization, from vfs_init() when we are booting
261 */
262 void
263 pshm_cache_init()
264 {
265 pshmhashtbl = hashinit(desiredvnodes, M_SHM, &pshmhash);
266 }
267
268 /*
269 * Invalidate a all entries to particular vnode.
270 *
271 * We actually just increment the v_id, that will do it. The entries will
272 * be purged by lookup as they get found. If the v_id wraps around, we
273 * need to ditch the entire cache, to avoid confusion. No valid vnode will
274 * ever have (v_id == 0).
275 */
276 void
277 pshm_cache_purge(void)
278 {
279 struct pshmcache *pcp;
280 struct pshmhashhead *pcpp;
281
282 for (pcpp = &pshmhashtbl[pshmhash]; pcpp >= pshmhashtbl; pcpp--) {
283 while (pcp = pcpp->lh_first)
284 pshm_cache_delete(pcp);
285 }
286 }
287
288 pshm_cache_delete(pcp)
289 struct pshmcache *pcp;
290 {
291 #if DIAGNOSTIC
292 if (pcp->pshm_hash.le_prev == 0)
293 panic("namecache purge le_prev");
294 if (pcp->pshm_hash.le_next == pcp)
295 panic("namecache purge le_next");
296 #endif /* DIAGNOSTIC */
297 LIST_REMOVE(pcp, pshm_hash);
298 pcp->pshm_hash.le_prev = 0;
299 pshmnument--;
300 }
301
302
303 struct shm_open_args {
304 const char *name;
305 int oflag;
306 int mode;
307 };
308
309 int
310 shm_open(p, uap, retval)
311 struct proc *p;
312 register struct shm_open_args *uap;
313 register_t *retval;
314 {
315 register struct filedesc *fdp = p->p_fd;
316 register struct file *fp;
317 register struct vnode *vp;
318 int i;
319 struct file *nfp;
320 int type, indx, error;
321 struct pshmname nd;
322 struct pshminfo *pinfo;
323 extern struct fileops pshmops;
324 char * pnbuf;
325 char * nameptr;
326 char * cp;
327 size_t pathlen, plen;
328 int fmode ;
329 int cmode = uap->mode;
330 int incache = 0;
331 struct pshmnode * pnode = PSHMNODE_NULL;
332 struct pshmcache * pcache = PSHMCACHE_NULL;
333 int pinfo_alloc=0;
334
335 AUDIT_ARG(fflags, uap->oflag);
336 AUDIT_ARG(mode, uap->mode);
337 pinfo = PSHMINFO_NULL;
338
339 MALLOC_ZONE(pnbuf, caddr_t,
340 MAXPATHLEN, M_NAMEI, M_WAITOK);
341 pathlen = MAXPATHLEN;
342 error = copyinstr((void *)uap->name, (void *)pnbuf,
343 MAXPATHLEN, &pathlen);
344 if (error) {
345 goto bad;
346 }
347 AUDIT_ARG(text, pnbuf);
348 if (pathlen > PSHMNAMLEN) {
349 error = ENAMETOOLONG;
350 goto bad;
351 }
352
353
354 #ifdef PSXSHM_NAME_RESTRICT
355 nameptr = pnbuf;
356 if (*nameptr == '/') {
357 while (*(nameptr++) == '/') {
358 plen--;
359 error = EINVAL;
360 goto bad;
361 }
362 } else {
363 error = EINVAL;
364 goto bad;
365 }
366 #endif /* PSXSHM_NAME_RESTRICT */
367
368 plen = pathlen;
369 nameptr = pnbuf;
370 nd.pshm_nameptr = nameptr;
371 nd.pshm_namelen = plen;
372 nd. pshm_hash =0;
373
374 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
375 nd.pshm_hash += (unsigned char)*cp * i;
376 }
377
378 error = pshm_cache_search(&pinfo, &nd, &pcache);
379
380 if (error == ENOENT) {
381 error = EINVAL;
382 goto bad;
383
384 }
385 if (!error) {
386 incache = 0;
387 } else
388 incache = 1;
389 fmode = FFLAGS(uap->oflag);
390 if ((fmode & (FREAD | FWRITE))==0) {
391 error = EINVAL;
392 goto bad;
393 }
394
395 if (error = falloc(p, &nfp, &indx))
396 goto bad;
397 fp = nfp;
398
399 cmode &= ALLPERMS;
400
401 if (fmode & O_CREAT) {
402 if ((fmode & O_EXCL) && incache) {
403 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid,
404 pinfo->pshm_gid, pinfo->pshm_mode);
405
406 /* shm obj exists and opened O_EXCL */
407 #if notyet
408 if (pinfo->pshm_flags & PSHM_INDELETE) {
409 }
410 #endif
411 error = EEXIST;
412 goto bad1;
413 }
414 if (!incache) {
415 /* create a new one */
416 pinfo = (struct pshminfo *)_MALLOC(sizeof(struct pshminfo), M_SHM, M_WAITOK);
417 bzero(pinfo, sizeof(struct pshminfo));
418 pinfo_alloc = 1;
419 pinfo->pshm_flags = PSHM_DEFINED | PSHM_INCREATE;
420 pinfo->pshm_usecount = 1;
421 pinfo->pshm_mode = cmode;
422 pinfo->pshm_uid = p->p_ucred->cr_uid;
423 pinfo->pshm_gid = p->p_ucred->cr_gid;
424 } else {
425 /* already exists */
426 if( pinfo->pshm_flags & PSHM_INDELETE) {
427 error = ENOENT;
428 goto bad1;
429 }
430 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid,
431 pinfo->pshm_gid, pinfo->pshm_mode);
432 if (error = pshm_access(pinfo, fmode, p->p_ucred, p))
433 goto bad1;
434 }
435 } else {
436 if (!incache) {
437 /* O_CREAT is not set and the shm obecj does not exist */
438 error = ENOENT;
439 goto bad1;
440 }
441 if( pinfo->pshm_flags & PSHM_INDELETE) {
442 error = ENOENT;
443 goto bad1;
444 }
445 if (error = pshm_access(pinfo, fmode, p->p_ucred, p))
446 goto bad1;
447 }
448 if (fmode & O_TRUNC) {
449 error = EINVAL;
450 goto bad2;
451 }
452 #if DIAGNOSTIC
453 if (fmode & FWRITE)
454 pinfo->pshm_writecount++;
455 if (fmode & FREAD)
456 pinfo->pshm_readcount++;
457 #endif
458 pnode = (struct pshmnode *)_MALLOC(sizeof(struct pshmnode), M_SHM, M_WAITOK);
459 bzero(pnode, sizeof(struct pshmnode));
460
461 if (!incache) {
462 if (error = pshm_cache_add(pinfo, &nd)) {
463 goto bad3;
464 }
465 }
466 pinfo->pshm_flags &= ~PSHM_INCREATE;
467 pinfo->pshm_usecount++;
468 pnode->pinfo = pinfo;
469 fp->f_flag = fmode & FMASK;
470 fp->f_type = DTYPE_PSXSHM;
471 fp->f_ops = &pshmops;
472 fp->f_data = (caddr_t)pnode;
473 *fdflags(p, indx) &= ~UF_RESERVED;
474 *retval = indx;
475 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
476 return (0);
477 bad3:
478 _FREE(pnode, M_SHM);
479
480 bad2:
481 if (pinfo_alloc)
482 _FREE(pinfo, M_SHM);
483 bad1:
484 fdrelse(p, indx);
485 ffree(nfp);
486 bad:
487 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
488 return (error);
489 }
490
491
492 /* ARGSUSED */
493 int
494 pshm_truncate(p, fp, fd, length, retval)
495 struct proc *p;
496 struct file *fp;
497 int fd;
498 off_t length;
499 register_t *retval;
500 {
501 struct pshminfo * pinfo;
502 struct pshmnode * pnode ;
503 kern_return_t kret;
504 vm_offset_t user_addr;
505 void * mem_object;
506 vm_size_t size;
507
508 if (fp->f_type != DTYPE_PSXSHM) {
509 return(EINVAL);
510 }
511
512
513 if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL )
514 return(EINVAL);
515
516 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
517 return(EINVAL);
518 if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED))
519 != PSHM_DEFINED) {
520 return(EINVAL);
521 }
522
523 size = round_page_64(length);
524 kret = vm_allocate(current_map(), &user_addr, size, TRUE);
525 if (kret != KERN_SUCCESS)
526 goto out;
527
528 kret = mach_make_memory_entry (current_map(), &size,
529 user_addr, VM_PROT_DEFAULT, &mem_object, 0);
530
531 if (kret != KERN_SUCCESS)
532 goto out;
533
534 vm_deallocate(current_map(), user_addr, size);
535
536 pinfo->pshm_flags &= ~PSHM_DEFINED;
537 pinfo->pshm_flags = PSHM_ALLOCATED;
538 pinfo->pshm_memobject = mem_object;
539 pinfo->pshm_length = size;
540 return(0);
541
542 out:
543 switch (kret) {
544 case KERN_INVALID_ADDRESS:
545 case KERN_NO_SPACE:
546 return (ENOMEM);
547 case KERN_PROTECTION_FAILURE:
548 return (EACCES);
549 default:
550 return (EINVAL);
551
552 }
553 }
554
555 int
556 pshm_stat(pnode, sb)
557 struct pshmnode *pnode;
558 struct stat *sb;
559 {
560 struct pshminfo *pinfo;
561
562 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
563 return(EINVAL);
564
565 bzero(sb, sizeof(struct stat));
566 sb->st_mode = pinfo->pshm_mode;
567 sb->st_uid = pinfo->pshm_uid;
568 sb->st_gid = pinfo->pshm_gid;
569 sb->st_size = pinfo->pshm_length;
570
571 return(0);
572 }
573
574 int
575 pshm_access(struct pshminfo *pinfo, int mode, struct ucred *cred, struct proc *p)
576 {
577 mode_t mask;
578 register gid_t *gp;
579 int i, error;
580
581 /* Otherwise, user id 0 always gets access. */
582 if (cred->cr_uid == 0)
583 return (0);
584
585 mask = 0;
586
587 /* Otherwise, check the owner. */
588 if (cred->cr_uid == pinfo->pshm_uid) {
589 if (mode & FREAD)
590 mask |= S_IRUSR;
591 if (mode & FWRITE)
592 mask |= S_IWUSR;
593 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
594 }
595
596 /* Otherwise, check the groups. */
597 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
598 if (pinfo->pshm_gid == *gp) {
599 if (mode & FREAD)
600 mask |= S_IRGRP;
601 if (mode & FWRITE)
602 mask |= S_IWGRP;
603 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
604 }
605
606 /* Otherwise, check everyone else. */
607 if (mode & FREAD)
608 mask |= S_IROTH;
609 if (mode & FWRITE)
610 mask |= S_IWOTH;
611 return ((pinfo->pshm_mode & mask) == mask ? 0 : EACCES);
612 }
613
614 struct mmap_args {
615 caddr_t addr;
616 size_t len;
617 int prot;
618 int flags;
619 int fd;
620 #ifdef DOUBLE_ALIGN_PARAMS
621 long pad;
622 #endif
623 off_t pos;
624 };
625
626 int
627 pshm_mmap(struct proc *p, struct mmap_args *uap, register_t *retval, struct file *fp, vm_size_t pageoff)
628 {
629 vm_offset_t user_addr = (vm_offset_t)uap->addr;
630 vm_size_t user_size = (vm_size_t)uap->len ;
631 int prot = uap->prot;
632 int flags = uap->flags;
633 vm_object_offset_t file_pos = (vm_object_offset_t)uap->pos;
634 int fd = uap->fd;
635 vm_map_t user_map;
636 boolean_t find_space,docow;
637 kern_return_t kret;
638 struct pshminfo * pinfo;
639 struct pshmnode * pnode;
640 void * mem_object;
641
642 if (user_size == 0)
643 return(0);
644
645 if ((flags & MAP_SHARED) == 0)
646 return(EINVAL);
647
648
649 if ((prot & PROT_WRITE) && ((fp->f_flag & FWRITE) == 0)) {
650 return(EPERM);
651 }
652
653 if (((pnode = (struct pshmnode *)fp->f_data)) == PSHMNODE_NULL )
654 return(EINVAL);
655
656 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
657 return(EINVAL);
658
659 if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) {
660 return(EINVAL);
661 }
662 if (user_size > pinfo->pshm_length) {
663 return(EINVAL);
664 }
665 if ((off_t)user_size + file_pos > pinfo->pshm_length) {
666 return(EINVAL);
667 }
668 if ((mem_object = pinfo->pshm_memobject) == NULL) {
669 return(EINVAL);
670 }
671
672
673 user_map = current_map();
674
675 if ((flags & MAP_FIXED) == 0) {
676 find_space = TRUE;
677 user_addr = round_page_32(user_addr);
678 } else {
679 if (user_addr != trunc_page_32(user_addr))
680 return (EINVAL);
681 find_space = FALSE;
682 (void) vm_deallocate(user_map, user_addr, user_size);
683 }
684 docow = FALSE;
685
686 kret = vm_map_64(user_map, &user_addr, user_size,
687 0, find_space, pinfo->pshm_memobject, file_pos, docow,
688 prot, VM_PROT_DEFAULT,
689 VM_INHERIT_DEFAULT);
690
691 if (kret != KERN_SUCCESS)
692 goto out;
693 kret = vm_inherit(user_map, user_addr, user_size,
694 VM_INHERIT_SHARE);
695 if (kret != KERN_SUCCESS) {
696 (void) vm_deallocate(user_map, user_addr, user_size);
697 goto out;
698 }
699 pnode->mapp_addr = user_addr;
700 pnode->map_size = user_size;
701 pinfo->pshm_flags |= (PSHM_MAPPED | PSHM_INUSE);
702 out:
703 switch (kret) {
704 case KERN_SUCCESS:
705 *fdflags(p, fd) |= UF_MAPPED;
706 *retval = (register_t)(user_addr + pageoff);
707 return (0);
708 case KERN_INVALID_ADDRESS:
709 case KERN_NO_SPACE:
710 return (ENOMEM);
711 case KERN_PROTECTION_FAILURE:
712 return (EACCES);
713 default:
714 return (EINVAL);
715 }
716
717 }
718
719 struct shm_unlink_args {
720 const char *name;
721 };
722
723 int
724 shm_unlink(p, uap, retval)
725 struct proc *p;
726 register struct shm_unlink_args *uap;
727 register_t *retval;
728 {
729 register struct filedesc *fdp = p->p_fd;
730 register struct file *fp;
731 int flags, i;
732 int error=0;
733 struct pshmname nd;
734 struct pshminfo *pinfo;
735 extern struct fileops pshmops;
736 char * pnbuf;
737 char * nameptr;
738 char * cp;
739 size_t pathlen, plen;
740 int fmode, cmode ;
741 int incache = 0;
742 struct pshmnode * pnode = PSHMNODE_NULL;
743 struct pshmcache *pcache = PSHMCACHE_NULL;
744 kern_return_t kret;
745
746 pinfo = PSHMINFO_NULL;
747
748 MALLOC_ZONE(pnbuf, caddr_t,
749 MAXPATHLEN, M_NAMEI, M_WAITOK);
750 pathlen = MAXPATHLEN;
751 error = copyinstr((void *)uap->name, (void *)pnbuf,
752 MAXPATHLEN, &pathlen);
753 if (error) {
754 goto bad;
755 }
756 AUDIT_ARG(text, pnbuf);
757 if (pathlen > PSHMNAMLEN) {
758 error = ENAMETOOLONG;
759 goto bad;
760 }
761
762
763 #ifdef PSXSHM_NAME_RESTRICT
764 nameptr = pnbuf;
765 if (*nameptr == '/') {
766 while (*(nameptr++) == '/') {
767 plen--;
768 error = EINVAL;
769 goto bad;
770 }
771 } else {
772 error = EINVAL;
773 goto bad;
774 }
775 #endif /* PSXSHM_NAME_RESTRICT */
776
777 plen = pathlen;
778 nameptr = pnbuf;
779 nd.pshm_nameptr = nameptr;
780 nd.pshm_namelen = plen;
781 nd. pshm_hash =0;
782
783 for (cp = nameptr, i=1; *cp != 0 && i <= plen; i++, cp++) {
784 nd.pshm_hash += (unsigned char)*cp * i;
785 }
786
787 error = pshm_cache_search(&pinfo, &nd, &pcache);
788
789 if (error == ENOENT) {
790 error = EINVAL;
791 goto bad;
792
793 }
794 if (!error) {
795 error = EINVAL;
796 goto bad;
797 } else
798 incache = 1;
799
800 if ((pinfo->pshm_flags & (PSHM_DEFINED | PSHM_ALLOCATED))==0) {
801 return (EINVAL);
802 }
803
804 if (pinfo->pshm_flags & PSHM_INDELETE) {
805 error = 0;
806 goto bad;
807 }
808
809 if (pinfo->pshm_memobject == NULL) {
810 error = EINVAL;
811 goto bad;
812 }
813
814 AUDIT_ARG(posix_ipc_perm, pinfo->pshm_uid, pinfo->pshm_gid,
815 pinfo->pshm_mode);
816 pinfo->pshm_flags |= PSHM_INDELETE;
817 pinfo->pshm_usecount--;
818 kret = mach_destroy_memory_entry(pinfo->pshm_memobject);
819 pshm_cache_delete(pcache);
820 _FREE(pcache, M_SHM);
821 pinfo->pshm_flags |= PSHM_REMOVED;
822 error = 0;
823 bad:
824 FREE_ZONE(pnbuf, MAXPATHLEN, M_NAMEI);
825 return (error);
826 out:
827 switch (kret) {
828 case KERN_INVALID_ADDRESS:
829 case KERN_PROTECTION_FAILURE:
830 return (EACCES);
831 default:
832 return (EINVAL);
833 }
834 }
835
836 int
837 pshm_close(pnode, flags, cred, p)
838 register struct pshmnode *pnode;
839 int flags;
840 struct ucred *cred;
841 struct proc *p;
842 {
843 int error=0;
844 kern_return_t kret;
845 register struct pshminfo *pinfo;
846
847 if ((pinfo = pnode->pinfo) == PSHMINFO_NULL)
848 return(EINVAL);
849
850 if ((pinfo->pshm_flags & PSHM_ALLOCATED) != PSHM_ALLOCATED) {
851 return(EINVAL);
852 }
853 #if DIAGNOSTIC
854 if(!pinfo->pshm_usecount) {
855 kprintf("negative usecount in pshm_close\n");
856 }
857 #endif /* DIAGNOSTIC */
858 pinfo->pshm_usecount--;
859
860 if ((pinfo->pshm_flags & PSHM_REMOVED) && !pinfo->pshm_usecount) {
861 _FREE(pinfo,M_SHM);
862 }
863 _FREE(pnode, M_SHM);
864 return (error);
865 }
866
867 static int
868 pshm_closefile(fp, p)
869 struct file *fp;
870 struct proc *p;
871 {
872 return (pshm_close(((struct pshmnode *)fp->f_data), fp->f_flag,
873 fp->f_cred, p));
874 }
875
876 static int
877 pshm_read(fp, uio, cred, flags, p)
878 struct file *fp;
879 struct uio *uio;
880 struct ucred *cred;
881 int flags;
882 struct proc *p;
883 {
884 return(EOPNOTSUPP);
885 }
886
887 static int
888 pshm_write(fp, uio, cred, flags, p)
889 struct file *fp;
890 struct uio *uio;
891 struct ucred *cred;
892 int flags;
893 struct proc *p;
894 {
895 return(EOPNOTSUPP);
896 }
897
898 static int
899 pshm_ioctl(fp, com, data, p)
900 struct file *fp;
901 u_long com;
902 caddr_t data;
903 struct proc *p;
904 {
905 return(EOPNOTSUPP);
906 }
907
908 static int
909 pshm_select(fp, which, wql, p)
910 struct file *fp;
911 int which;
912 void *wql;
913 struct proc *p;
914 {
915 return(EOPNOTSUPP);
916 }
917
918 static int
919 pshm_kqfilter(fp, kn, p)
920 struct file *fp;
921 struct knote *kn;
922 struct proc *p;
923 {
924 return(EOPNOTSUPP);
925 }