rendered paste body#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <sys/ipc.h>#include <sys/shm.h>#include <sys/mman.h>#include <fcntl.h>#include <errno.h>extern int errno;static key_t key = -1;const char* device = "/dev/mem";static const char* program_name = "test_shm_mmap";static size_t shm_size = 0;static void print_action(const char* device, size_t shm_size, size_t size, off_t offset);static void usage(void);static void pause_for_ipcs(int shmid);static int os_create_shm_region(void);static void* os_attach_shm_region(int shmid);static int os_destroy_shm_region(caddr_t addr);static void* mmap_shm_region(caddr_t addr, size_t size, off_t offset, int* fd);static int munmap_shm_region(caddr_t addr, size_t size);extern char* optarg;extern int optind, opterr, optopt;intmain(int argc, char* argv[]){ size_t size = 0; int fd = -1; off_t offset = 0x0; int c; int err = 0; caddr_t addr = NULL; int shmid = -1; if (shm_size == 0) size = shm_size = sysconf(_SC_PAGESIZE) * 1024; /* 4MB */ while ((c = getopt(argc, argv, "d:s:o:")) != -1) { switch(c) { case 'd': device = strdup(optarg); break; case 's': size = (size_t) atoi(optarg); break; case 'o': offset = (off_t) atoi(optarg); break; default: (void) fprintf(stderr, "Unknonwn option -%c\n", optopt); ++err; break; } } if (err) usage(); print_action(device, shm_size, size, offset); if ((shmid = os_create_shm_region()) < 0) return -1; if ((addr = os_attach_shm_region(shmid)) == (caddr_t) -1) return -1; if ((addr = mmap_shm_region(addr, size, offset, &fd)) == (caddr_t) -1) return -1; pause_for_ipcs(shmid); if ((munmap_shm_region(addr, size)) != 0) return -1; if ((os_destroy_shm_region(addr)) != 0) return -1; return 0;}voidprint_action(const char* device, size_t shm_size, size_t size, off_t offset){ (void) fprintf(stderr, "Attempting to mmap(2) device \"%s\" onto a shared memory segment of size %u bytes with size %u bytes at offset 0x%x\n", device, shm_size, size, offset);}voidusage(void){ (void) fprintf(stderr, "Usage: %s -s <size> -o <mmap offset>\n", program_name); exit(0);}void pause_for_ipcs(int shmid){ char c; (void) fprintf(stderr, "If you now do '%> ipcs -a' in a different terminal, you should see a shared memory segment with id 0x%x owned by uid %u\n", shmid, getuid()); (void) fprintf(stderr, "Press any key to continue.\n"); c = fgetc(stdin); (void) fprintf(stderr, "cleaning up\n");}intmunmap_shm_region(caddr_t addr, size_t size){ int ret; if ((ret = munmap(addr, size)) != 0) { (void) fprintf(stderr, "%s: munmap(2) failed: %s\n", __func__, strerror(errno)); } return ret;}void*mmap_shm_region(caddr_t addr, size_t size, off_t offset, int* fd){ void* ret = (void *) -1; if (fd == NULL) { (void) fprintf(stderr, "%s: bad fd pointer\n", __func__); goto mmap_fail; } if (size % sysconf(_SC_PAGESIZE)) { (void) fprintf(stderr, "%s: mmap'ed size must be a multple of %u\n", __func__, sysconf(_SC_PAGESIZE)); goto mmap_fail; } if (size > shm_size) { (void) fprintf(stderr, "%s: mmap'ed size cannot exceed shmseg size %u\n", __func__, shm_size); goto mmap_fail; } if (offset && (offset % sysconf(_SC_PAGESIZE))) { (void) fprintf(stderr, "%s: offset 0x%x is not 0 and is not a multiple of %u\n", __func__, offset, sysconf(_SC_PAGESIZE)); goto mmap_fail; } *fd = open(device, O_RDONLY, (mode_t) 0444); if (*fd == -1) { (void) fprintf(stderr, "%s: open(2) failed: %s\n", __func__, strerror(errno)); goto mmap_fail; } if ((ret = mmap(addr, size, PROT_READ, MAP_SHARED|MAP_FIXED|MAP_NORESERVE, *fd, offset)) == MAP_FAILED) { (void) fprintf(stderr, "%s: mmap(2) failed: %s\n", __func__, strerror(errno)); goto mmap_fail; } (void) fprintf(stderr, "%s: mmap(2)'ed shmseg at address 0x%x [0x%x] with flags (MAP_SHARED|MAP_FIXED|MAP_NORESERVE) size %u\n", __func__, ret, addr, size);mmap_fail: return ret;}intos_destroy_shm_region(caddr_t addr){ int ret; if ((ret = shmdt(addr)) != 0) (void) fprintf(stderr, "%s: shmdt(2) failed: %s\n", __func__, strerror(errno)); else (void) fprintf(stderr, "%s: detached shm seg at address 0x%p\n", __func__, addr); return ret;}void*os_attach_shm_region(int shmid){ void* ret = NULL; struct shmid_ds ds; if ((ret = shmat(shmid, (void *) 0, 0)) == (void *) -1) (void) fprintf(stderr, "%s: shmat(2) failed: %s\n", __func__, strerror(errno)); else (void) fprintf(stderr, "%s: attached shmseg 0x%x at address 0x%p\n", __func__, shmid, ret); (void) memset(&ds, '\0', sizeof(ds)); if ((shmctl(shmid, IPC_STAT, &ds) != 0)) (void) fprintf(stderr, "%s: shmctl(2) IPC_STAT failed: %s\n", __func__, strerror(errno)); ds.shm_perm.mode = 0666; if ((shmctl(shmid, IPC_SET, &ds) != 0)) (void) fprintf(stderr, "%s: shmctl(2) IPC_SET failed: %s\n", __func__, strerror(errno)); return ret;}intos_create_shm_region(void){ int shmid = -1; if (key == -1) key = ftok(".", rand()); if ((shmid = shmget(key, shm_size, IPC_CREAT)) == -1) (void) fprintf(stderr, "%s: shmget(2) failed: %s\n", __func__, strerror(errno)); else (void) fprintf(stderr, "%s: created a %u bytes shared memory segment for key 0x%x with id 0x%x\n", __func__, shm_size, key, shmid); return shmid;}