1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#include <linux/config.h>
19#include <linux/slab.h>
20#include <linux/mm.h>
21#include <linux/hugetlb.h>
22#include <linux/shm.h>
23#include <linux/init.h>
24#include <linux/file.h>
25#include <linux/mman.h>
26#include <linux/proc_fs.h>
27#include <linux/shmem_fs.h>
28#include <linux/security.h>
29#include <linux/audit.h>
30#include <asm/uaccess.h>
31
32#include "util.h"
33
34#define shm_flags shm_perm.mode
35
36static struct file_operations shm_file_operations;
37static struct vm_operations_struct shm_vm_ops;
38
39static struct ipc_ids shm_ids;
40
41#define shm_lock(id) ((struct shmid_kernel*)ipc_lock(&shm_ids,id))
42#define shm_unlock(shp) ipc_unlock(&(shp)->shm_perm)
43#define shm_get(id) ((struct shmid_kernel*)ipc_get(&shm_ids,id))
44#define shm_buildid(id, seq) \
45 ipc_buildid(&shm_ids, id, seq)
46
47static int newseg (key_t key, int shmflg, size_t size);
48static void shm_open (struct vm_area_struct *shmd);
49static void shm_close (struct vm_area_struct *shmd);
50#ifdef CONFIG_PROC_FS
51static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data);
52#endif
53
54size_t shm_ctlmax = SHMMAX;
55size_t shm_ctlall = SHMALL;
56int shm_ctlmni = SHMMNI;
57
58static int shm_tot;
59
60void __init shm_init (void)
61{
62 ipc_init_ids(&shm_ids, 1);
63#ifdef CONFIG_PROC_FS
64 create_proc_read_entry("sysvipc/shm", 0, NULL, sysvipc_shm_read_proc, NULL);
65#endif
66}
67
68static inline int shm_checkid(struct shmid_kernel *s, int id)
69{
70 if (ipc_checkid(&shm_ids,&s->shm_perm,id))
71 return -EIDRM;
72 return 0;
73}
74
75static inline struct shmid_kernel *shm_rmid(int id)
76{
77 return (struct shmid_kernel *)ipc_rmid(&shm_ids,id);
78}
79
80static inline int shm_addid(struct shmid_kernel *shp)
81{
82 return ipc_addid(&shm_ids, &shp->shm_perm, shm_ctlmni);
83}
84
85
86
87static inline void shm_inc (int id) {
88 struct shmid_kernel *shp;
89
90 if(!(shp = shm_lock(id)))
91 BUG();
92 shp->shm_atim = get_seconds();
93 shp->shm_lprid = current->tgid;
94 shp->shm_nattch++;
95 shm_unlock(shp);
96}
97
98
99static void shm_open (struct vm_area_struct *shmd)
100{
101 shm_inc (shmd->vm_file->f_dentry->d_inode->i_ino);
102}
103
104
105
106
107
108
109
110
111
112static void shm_destroy (struct shmid_kernel *shp)
113{
114 shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT;
115 shm_rmid (shp->id);
116 shm_unlock(shp);
117 if (!is_file_hugepages(shp->shm_file))
118 shmem_lock(shp->shm_file, 0, shp->mlock_user);
119 else
120 user_shm_unlock(shp->shm_file->f_dentry->d_inode->i_size,
121 shp->mlock_user);
122 fput (shp->shm_file);
123 security_shm_free(shp);
124 ipc_rcu_putref(shp);
125}
126
127
128
129
130
131
132
133static void shm_close (struct vm_area_struct *shmd)
134{
135 struct file * file = shmd->vm_file;
136 int id = file->f_dentry->d_inode->i_ino;
137 struct shmid_kernel *shp;
138
139 down (&shm_ids.sem);
140
141 if(!(shp = shm_lock(id)))
142 BUG();
143 shp->shm_lprid = current->tgid;
144 shp->shm_dtim = get_seconds();
145 shp->shm_nattch--;
146 if(shp->shm_nattch == 0 &&
147 shp->shm_flags & SHM_DEST)
148 shm_destroy (shp);
149 else
150 shm_unlock(shp);
151 up (&shm_ids.sem);
152}
153
154static int shm_mmap(struct file * file, struct vm_area_struct * vma)
155{
156 file_accessed(file);
157 vma->vm_ops = &shm_vm_ops;
158 if (!(vma->vm_flags & VM_WRITE))
159 vma->vm_flags &= ~VM_MAYWRITE;
160 shm_inc(file->f_dentry->d_inode->i_ino);
161 return 0;
162}
163
164static struct file_operations shm_file_operations = {
165 .mmap = shm_mmap
166};
167
168static struct vm_operations_struct shm_vm_ops = {
169 .open = shm_open,
170 .close = shm_close,
171 .nopage = shmem_nopage,
172#ifdef CONFIG_NUMA
173 .set_policy = shmem_set_policy,
174 .get_policy = shmem_get_policy,
175#endif
176};
177
178static int newseg (key_t key, int shmflg, size_t size)
179{
180 int error;
181 struct shmid_kernel *shp;
182 int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT;
183 struct file * file;
184 char name[13];
185 int id;
186
187 if (size < SHMMIN || size > shm_ctlmax)
188 return -EINVAL;
189
190 if (shm_tot + numpages > shm_ctlall)
191 return -ENOSPC;
192
193 shp = ipc_rcu_alloc(sizeof(*shp));
194 if (!shp)
195 return -ENOMEM;
196
197 shp->shm_perm.key = key;
198 shp->shm_flags = (shmflg & S_IRWXUGO);
199 shp->mlock_user = NULL;
200
201 shp->shm_perm.security = NULL;
202 error = security_shm_alloc(shp);
203 if (error) {
204 ipc_rcu_putref(shp);
205 return error;
206 }
207
208 if (shmflg & SHM_HUGETLB) {
209
210 file = hugetlb_zero_setup(size);
211 shp->mlock_user = current->user;
212 } else {
213 sprintf (name, "SYSV%08x", key);
214 file = shmem_file_setup(name, size, VM_ACCOUNT);
215 }
216 error = PTR_ERR(file);
217 if (IS_ERR(file))
218 goto no_file;
219
220 error = -ENOSPC;
221 id = shm_addid(shp);
222 if(id == -1)
223 goto no_id;
224
225 shp->shm_cprid = current->tgid;
226 shp->shm_lprid = 0;
227 shp->shm_atim = shp->shm_dtim = 0;
228 shp->shm_ctim = get_seconds();
229 shp->shm_segsz = size;
230 shp->shm_nattch = 0;
231 shp->id = shm_buildid(id,shp->shm_perm.seq);
232 shp->shm_file = file;
233 file->f_dentry->d_inode->i_ino = shp->id;
234 if (shmflg & SHM_HUGETLB)
235 set_file_hugepages(file);
236 else
237 file->f_op = &shm_file_operations;
238 shm_tot += numpages;
239 shm_unlock(shp);
240 return shp->id;
241
242no_id:
243 fput(file);
244no_file:
245 security_shm_free(shp);
246 ipc_rcu_putref(shp);
247 return error;
248}
249
250asmlinkage long sys_shmget (key_t key, size_t size, int shmflg)
251{
252 struct shmid_kernel *shp;
253 int err, id = 0;
254
255 down(&shm_ids.sem);
256 if (key == IPC_PRIVATE) {
257 err = newseg(key, shmflg, size);
258 } else if ((id = ipc_findkey(&shm_ids, key)) == -1) {
259 if (!(shmflg & IPC_CREAT))
260 err = -ENOENT;
261 else
262 err = newseg(key, shmflg, size);
263 } else if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) {
264 err = -EEXIST;
265 } else {
266 shp = shm_lock(id);
267 if(shp==NULL)
268 BUG();
269 if (shp->shm_segsz < size)
270 err = -EINVAL;
271 else if (ipcperms(&shp->shm_perm, shmflg))
272 err = -EACCES;
273 else {
274 int shmid = shm_buildid(id, shp->shm_perm.seq);
275 err = security_shm_associate(shp, shmflg);
276 if (!err)
277 err = shmid;
278 }
279 shm_unlock(shp);
280 }
281 up(&shm_ids.sem);
282
283 return err;
284}
285
286static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
287{
288 switch(version) {
289 case IPC_64:
290 return copy_to_user(buf, in, sizeof(*in));
291 case IPC_OLD:
292 {
293 struct shmid_ds out;
294
295 ipc64_perm_to_ipc_perm(&in->shm_perm, &out.shm_perm);
296 out.shm_segsz = in->shm_segsz;
297 out.shm_atime = in->shm_atime;
298 out.shm_dtime = in->shm_dtime;
299 out.shm_ctime = in->shm_ctime;
300 out.shm_cpid = in->shm_cpid;
301 out.shm_lpid = in->shm_lpid;
302 out.shm_nattch = in->shm_nattch;
303
304 return copy_to_user(buf, &out, sizeof(out));
305 }
306 default:
307 return -EINVAL;
308 }
309}
310
311struct shm_setbuf {
312 uid_t uid;
313 gid_t gid;
314 mode_t mode;
315};
316
317static inline unsigned long copy_shmid_from_user(struct shm_setbuf *out, void __user *buf, int version)
318{
319 switch(version) {
320 case IPC_64:
321 {
322 struct shmid64_ds tbuf;
323
324 if (copy_from_user(&tbuf, buf, sizeof(tbuf)))
325 return -EFAULT;
326
327 out->uid = tbuf.shm_perm.uid;
328 out->gid = tbuf.shm_perm.gid;
329 out->mode = tbuf.shm_flags;
330
331 return 0;
332 }
333 case IPC_OLD:
334 {
335 struct shmid_ds tbuf_old;
336
337 if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
338 return -EFAULT;
339
340 out->uid = tbuf_old.shm_perm.uid;
341 out->gid = tbuf_old.shm_perm.gid;
342 out->mode = tbuf_old.shm_flags;
343
344 return 0;
345 }
346 default:
347 return -EINVAL;
348 }
349}
350
351static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version)
352{
353 switch(version) {
354 case IPC_64:
355 return copy_to_user(buf, in, sizeof(*in));
356 case IPC_OLD:
357 {
358 struct shminfo out;
359
360 if(in->shmmax > INT_MAX)
361 out.shmmax = INT_MAX;
362 else
363 out.shmmax = (int)in->shmmax;
364
365 out.shmmin = in->shmmin;
366 out.shmmni = in->shmmni;
367 out.shmseg = in->shmseg;
368 out.shmall = in->shmall;
369
370 return copy_to_user(buf, &out, sizeof(out));
371 }
372 default:
373 return -EINVAL;
374 }
375}
376
377static void shm_get_stat(unsigned long *rss, unsigned long *swp)
378{
379 int i;
380
381 *rss = 0;
382 *swp = 0;
383
384 for (i = 0; i <= shm_ids.max_id; i++) {
385 struct shmid_kernel *shp;
386 struct inode *inode;
387
388 shp = shm_get(i);
389 if(!shp)
390 continue;
391
392 inode = shp->shm_file->f_dentry->d_inode;
393
394 if (is_file_hugepages(shp->shm_file)) {
395 struct address_space *mapping = inode->i_mapping;
396 *rss += (HPAGE_SIZE/PAGE_SIZE)*mapping->nrpages;
397 } else {
398 struct shmem_inode_info *info = SHMEM_I(inode);
399 spin_lock(&info->lock);
400 *rss += inode->i_mapping->nrpages;
401 *swp += info->swapped;
402 spin_unlock(&info->lock);
403 }
404 }
405}
406
407asmlinkage long sys_shmctl (int shmid, int cmd, struct shmid_ds __user *buf)
408{
409 struct shm_setbuf setbuf;
410 struct shmid_kernel *shp;
411 int err, version;
412
413 if (cmd < 0 || shmid < 0) {
414 err = -EINVAL;
415 goto out;
416 }
417
418 version = ipc_parse_version(&cmd);
419
420 switch (cmd) {
421 case IPC_INFO:
422 {
423 struct shminfo64 shminfo;
424
425 err = security_shm_shmctl(NULL, cmd);
426 if (err)
427 return err;
428
429 memset(&shminfo,0,sizeof(shminfo));
430 shminfo.shmmni = shminfo.shmseg = shm_ctlmni;
431 shminfo.shmmax = shm_ctlmax;
432 shminfo.shmall = shm_ctlall;
433
434 shminfo.shmmin = SHMMIN;
435 if(copy_shminfo_to_user (buf, &shminfo, version))
436 return -EFAULT;
437
438 err= shm_ids.max_id;
439 if(err<0)
440 err = 0;
441 goto out;
442 }
443 case SHM_INFO:
444 {
445 struct shm_info shm_info;
446
447 err = security_shm_shmctl(NULL, cmd);
448 if (err)
449 return err;
450
451 memset(&shm_info,0,sizeof(shm_info));
452 down(&shm_ids.sem);
453 shm_info.used_ids = shm_ids.in_use;
454 shm_get_stat (&shm_info.shm_rss, &shm_info.shm_swp);
455 shm_info.shm_tot = shm_tot;
456 shm_info.swap_attempts = 0;
457 shm_info.swap_successes = 0;
458 err = shm_ids.max_id;
459 up(&shm_ids.sem);
460 if(copy_to_user (buf, &shm_info, sizeof(shm_info))) {
461 err = -EFAULT;
462 goto out;
463 }
464
465 err = err < 0 ? 0 : err;
466 goto out;
467 }
468 case SHM_STAT:
469 case IPC_STAT:
470 {
471 struct shmid64_ds tbuf;
472 int result;
473 memset(&tbuf, 0, sizeof(tbuf));
474 shp = shm_lock(shmid);
475 if(shp==NULL) {
476 err = -EINVAL;
477 goto out;
478 } else if(cmd==SHM_STAT) {
479 err = -EINVAL;
480 if (shmid > shm_ids.max_id)
481 goto out_unlock;
482 result = shm_buildid(shmid, shp->shm_perm.seq);
483 } else {
484 err = shm_checkid(shp,shmid);
485 if(err)
486 goto out_unlock;
487 result = 0;
488 }
489 err=-EACCES;
490 if (ipcperms (&shp->shm_perm, S_IRUGO))
491 goto out_unlock;
492 err = security_shm_shmctl(shp, cmd);
493 if (err)
494 goto out_unlock;
495 kernel_to_ipc64_perm(&shp->shm_perm, &tbuf.shm_perm);
496 tbuf.shm_segsz = shp->shm_segsz;
497 tbuf.shm_atime = shp->shm_atim;
498 tbuf.shm_dtime = shp->shm_dtim;
499 tbuf.shm_ctime = shp->shm_ctim;
500 tbuf.shm_cpid = shp->shm_cprid;
501 tbuf.shm_lpid = shp->shm_lprid;
502 if (!is_file_hugepages(shp->shm_file))
503 tbuf.shm_nattch = shp->shm_nattch;
504 else
505 tbuf.shm_nattch = file_count(shp->shm_file) - 1;
506 shm_unlock(shp);
507 if(copy_shmid_to_user (buf, &tbuf, version))
508 err = -EFAULT;
509 else
510 err = result;
511 goto out;
512 }
513 case SHM_LOCK:
514 case SHM_UNLOCK:
515 {
516 shp = shm_lock(shmid);
517 if(shp==NULL) {
518 err = -EINVAL;
519 goto out;
520 }
521 err = shm_checkid(shp,shmid);
522 if(err)
523 goto out_unlock;
524
525 if (!capable(CAP_IPC_LOCK)) {
526 err = -EPERM;
527 if (current->euid != shp->shm_perm.uid &&
528 current->euid != shp->shm_perm.cuid)
529 goto out_unlock;
530 if (cmd == SHM_LOCK &&
531 !current->rlim[RLIMIT_MEMLOCK].rlim_cur)
532 goto out_unlock;
533 }
534
535 err = security_shm_shmctl(shp, cmd);
536 if (err)
537 goto out_unlock;
538
539 if(cmd==SHM_LOCK) {
540 struct user_struct * user = current->user;
541 if (!is_file_hugepages(shp->shm_file)) {
542 err = shmem_lock(shp->shm_file, 1, user);
543 if (!err) {
544 shp->shm_flags |= SHM_LOCKED;
545 shp->mlock_user = user;
546 }
547 }
548 } else if (!is_file_hugepages(shp->shm_file)) {
549 shmem_lock(shp->shm_file, 0, shp->mlock_user);
550 shp->shm_flags &= ~SHM_LOCKED;
551 shp->mlock_user = NULL;
552 }
553 shm_unlock(shp);
554 goto out;
555 }
556 case IPC_RMID:
557 {
558
559
560
561
562
563
564
565
566
567
568 down(&shm_ids.sem);
569 shp = shm_lock(shmid);
570 err = -EINVAL;
571 if (shp == NULL)
572 goto out_up;
573 err = shm_checkid(shp, shmid);
574 if(err)
575 goto out_unlock_up;
576
577 if (current->euid != shp->shm_perm.uid &&
578 current->euid != shp->shm_perm.cuid &&
579 !capable(CAP_SYS_ADMIN)) {
580 err=-EPERM;
581 goto out_unlock_up;
582 }
583
584 err = security_shm_shmctl(shp, cmd);
585 if (err)
586 goto out_unlock_up;
587
588 if (shp->shm_nattch){
589 shp->shm_flags |= SHM_DEST;
590
591 shp->shm_perm.key = IPC_PRIVATE;
592 shm_unlock(shp);
593 } else
594 shm_destroy (shp);
595 up(&shm_ids.sem);
596 goto out;
597 }
598
599 case IPC_SET:
600 {
601 if (copy_shmid_from_user (&setbuf, buf, version)) {
602 err = -EFAULT;
603 goto out;
604 }
605 if ((err = audit_ipc_perms(0, setbuf.uid, setbuf.gid, setbuf.mode)))
606 return err;
607 down(&shm_ids.sem);
608 shp = shm_lock(shmid);
609 err=-EINVAL;
610 if(shp==NULL)
611 goto out_up;
612 err = shm_checkid(shp,shmid);
613 if(err)
614 goto out_unlock_up;
615 err=-EPERM;
616 if (current->euid != shp->shm_perm.uid &&
617 current->euid != shp->shm_perm.cuid &&
618 !capable(CAP_SYS_ADMIN)) {
619 goto out_unlock_up;
620 }
621
622 err = security_shm_shmctl(shp, cmd);
623 if (err)
624 goto out_unlock_up;
625
626 shp->shm_perm.uid = setbuf.uid;
627 shp->shm_perm.gid = setbuf.gid;
628 shp->shm_flags = (shp->shm_flags & ~S_IRWXUGO)
629 | (setbuf.mode & S_IRWXUGO);
630 shp->shm_ctim = get_seconds();
631 break;
632 }
633
634 default:
635 err = -EINVAL;
636 goto out;
637 }
638
639 err = 0;
640out_unlock_up:
641 shm_unlock(shp);
642out_up:
643 up(&shm_ids.sem);
644 goto out;
645out_unlock:
646 shm_unlock(shp);
647out:
648 return err;
649}
650
651
652
653
654
655
656
657
658long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr)
659{
660 struct shmid_kernel *shp;
661 unsigned long addr;
662 unsigned long size;
663 struct file * file;
664 int err;
665 unsigned long flags;
666 unsigned long prot;
667 unsigned long o_flags;
668 int acc_mode;
669 void *user_addr;
670
671 if (shmid < 0) {
672 err = -EINVAL;
673 goto out;
674 } else if ((addr = (ulong)shmaddr)) {
675 if (addr & (SHMLBA-1)) {
676 if (shmflg & SHM_RND)
677 addr &= ~(SHMLBA-1);
678 else
679#ifndef __ARCH_FORCE_SHMLBA
680 if (addr & ~PAGE_MASK)
681#endif
682 return -EINVAL;
683 }
684 flags = MAP_SHARED | MAP_FIXED;
685 } else {
686 if ((shmflg & SHM_REMAP))
687 return -EINVAL;
688
689 flags = MAP_SHARED;
690 }
691
692 if (shmflg & SHM_RDONLY) {
693 prot = PROT_READ;
694 o_flags = O_RDONLY;
695 acc_mode = S_IRUGO;
696 } else {
697 prot = PROT_READ | PROT_WRITE;
698 o_flags = O_RDWR;
699 acc_mode = S_IRUGO | S_IWUGO;
700 }
701 if (shmflg & SHM_EXEC) {
702 prot |= PROT_EXEC;
703 acc_mode |= S_IXUGO;
704 }
705
706
707
708
709
710 shp = shm_lock(shmid);
711 if(shp == NULL) {
712 err = -EINVAL;
713 goto out;
714 }
715 err = shm_checkid(shp,shmid);
716 if (err) {
717 shm_unlock(shp);
718 goto out;
719 }
720 if (ipcperms(&shp->shm_perm, acc_mode)) {
721 shm_unlock(shp);
722 err = -EACCES;
723 goto out;
724 }
725
726 err = security_shm_shmat(shp, shmaddr, shmflg);
727 if (err) {
728 shm_unlock(shp);
729 return err;
730 }
731
732 file = shp->shm_file;
733 size = i_size_read(file->f_dentry->d_inode);
734 shp->shm_nattch++;
735 shm_unlock(shp);
736
737 down_write(¤t->mm->mmap_sem);
738 if (addr && !(shmflg & SHM_REMAP)) {
739 user_addr = ERR_PTR(-EINVAL);
740 if (find_vma_intersection(current->mm, addr, addr + size))
741 goto invalid;
742
743
744
745
746 if (addr < current->mm->start_stack &&
747 addr > current->mm->start_stack - size - PAGE_SIZE * 5)
748 goto invalid;
749 }
750
751 user_addr = (void*) do_mmap (file, addr, size, prot, flags, 0);
752
753invalid:
754 up_write(¤t->mm->mmap_sem);
755
756 down (&shm_ids.sem);
757 if(!(shp = shm_lock(shmid)))
758 BUG();
759 shp->shm_nattch--;
760 if(shp->shm_nattch == 0 &&
761 shp->shm_flags & SHM_DEST)
762 shm_destroy (shp);
763 else
764 shm_unlock(shp);
765 up (&shm_ids.sem);
766
767 *raddr = (unsigned long) user_addr;
768 err = 0;
769 if (IS_ERR(user_addr))
770 err = PTR_ERR(user_addr);
771out:
772 return err;
773}
774
775
776
777
778
779asmlinkage long sys_shmdt(char __user *shmaddr)
780{
781 struct mm_struct *mm = current->mm;
782 struct vm_area_struct *vma, *next;
783 unsigned long addr = (unsigned long)shmaddr;
784 loff_t size = 0;
785 int retval = -EINVAL;
786
787 down_write(&mm->mmap_sem);
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809 vma = find_vma(mm, addr);
810
811 while (vma) {
812 next = vma->vm_next;
813
814
815
816
817
818
819 if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
820 (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff) {
821
822
823 size = vma->vm_file->f_dentry->d_inode->i_size;
824 do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
825
826
827
828
829
830
831 retval = 0;
832 vma = next;
833 break;
834 }
835 vma = next;
836 }
837
838
839
840
841
842
843 size = PAGE_ALIGN(size);
844 while (vma && (loff_t)(vma->vm_end - addr) <= size) {
845 next = vma->vm_next;
846
847
848 if ((vma->vm_ops == &shm_vm_ops || is_vm_hugetlb_page(vma)) &&
849 (vma->vm_start - addr)/PAGE_SIZE == vma->vm_pgoff)
850
851 do_munmap(mm, vma->vm_start, vma->vm_end - vma->vm_start);
852 vma = next;
853 }
854
855 up_write(&mm->mmap_sem);
856 return retval;
857}
858
859#ifdef CONFIG_PROC_FS
860static int sysvipc_shm_read_proc(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
861{
862 off_t pos = 0;
863 off_t begin = 0;
864 int i, len = 0;
865
866 down(&shm_ids.sem);
867 len += sprintf(buffer, " key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime\n");
868
869 for(i = 0; i <= shm_ids.max_id; i++) {
870 struct shmid_kernel* shp;
871
872 shp = shm_lock(i);
873 if(shp!=NULL) {
874#define SMALL_STRING "%10d %10d %4o %10u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
875#define BIG_STRING "%10d %10d %4o %21u %5u %5u %5d %5u %5u %5u %5u %10lu %10lu %10lu\n"
876 char *format;
877
878 if (sizeof(size_t) <= sizeof(int))
879 format = SMALL_STRING;
880 else
881 format = BIG_STRING;
882 len += sprintf(buffer + len, format,
883 shp->shm_perm.key,
884 shm_buildid(i, shp->shm_perm.seq),
885 shp->shm_flags,
886 shp->shm_segsz,
887 shp->shm_cprid,
888 shp->shm_lprid,
889 is_file_hugepages(shp->shm_file) ? (file_count(shp->shm_file) - 1) : shp->shm_nattch,
890 shp->shm_perm.uid,
891 shp->shm_perm.gid,
892 shp->shm_perm.cuid,
893 shp->shm_perm.cgid,
894 shp->shm_atim,
895 shp->shm_dtim,
896 shp->shm_ctim);
897 shm_unlock(shp);
898
899 pos += len;
900 if(pos < offset) {
901 len = 0;
902 begin = pos;
903 }
904 if(pos > offset + length)
905 goto done;
906 }
907 }
908 *eof = 1;
909done:
910 up(&shm_ids.sem);
911 *start = buffer + (offset - begin);
912 len -= (offset - begin);
913 if(len > length)
914 len = length;
915 if(len < 0)
916 len = 0;
917 return len;
918}
919#endif
920