Shared memory data using a header file - c

I'm doing an assignment for class in which we need to create some shared memory that can be accessed from 2 different programs. There is a header file called shm.h that has the kinds of data we need to be able to share. So far my code looks like this.
shm.h
#ifndef SHM_H
#define SHM_H
//<Define an enum called StatusEnus with the enumerations "INVALID", "VALID"
and "CONSUMED">
#define enum StatusEnus{INVALID, VALID, CONSUMED} StatusEnus
//<Define a typedef structure with the enum above and an "int" variable
//called "data">
#define struct ShmData{StatusEnus status; int data;}ShmData;
#define SIZE 8
#endif
server_template
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/shm.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/types.h>
#include "shm.h"
int main(int argc, char* argv[])
{
//void* memPtr;
int retVal = 0;
//<Confirm argc is 2 and if not print a usage string.>
if(argc != 2){
printf("Please enter 2 arguments5");
}
/*<Use the POSIX "shm_open" API to open file descriptor with
"O_CREAT | O_RDWR" options and the "0666" permissions> */
//returns -1 on error
int file = shm_open("sharedMem", O_CREAT | O_RDWR, 0666);
if (file == -1) retVal =-1;
/*<Use the "ftruncate" API to set the size to the size of your
structure shm.h>*/
retVal = ftruncate(file,SIZE);
//<Use the "mmap" API to memory map the file descriptor>
void* data = mmap(0, SIZE,PROT_WRITE | PROT_WRITE, MAP_SHARED, file, 0);
/*<Set the "status" field to INVALID>
<Set the "data" field to atoi(argv[1])>
<Set the "status" field to VALID>*/
ShmData->status = INVALID;
ShmData->data = atoi(argv[1]);
ShmData->status = VALID;
printf("[Server]: Server data Valid... waiting for client\n");
while(ShmData->status != CONSUMED)
{
sleep(1);
}
printf("[Server]: Server Data consumed!\n");
/*<use the "munmap" API to unmap the pointer>
<use the "close" API to close the file Descriptor>
<use the "shm_unlink" API to revert the shm_open call above>*/
printf("[Server]: Server exiting...\n");
return(retVal);
}
So my goal is to be able to access the fields like ShmData->StatusEnus from the server but also then be able to access these files from a separate program. However as it stands I keep getting to errors either related to the deceleration of ShmData. How do I make sure that the shared memory I am creating contains that enum and int field from my structure?

Related

allocation error when trying to do shmat

when trying to do shmat i get allocation error, telling me i cannot accsess the memory, it did not happen to me before and i really dont know what to do.
this is the error :
0xffffffffffffffff error: Cannot access memory at address 0xffffffffffffffff
and the wiered thing is that vecBoard is allocated in the process mapped area and only get crazy when shmat is triggered. thank you all!
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/fcntl.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <signal.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#define SHM_SIZE 4096
#define FLAGS IPC_CREAT
#define COLUMNS 8
#define ROWS 8
key_t key;
int main()
{
char* vecBoard;
// Creating shared memory :
if ((key = ftok("ex31.c",'k')) == -1)
{
perror("ftok");
exit(1);
}
int shm_id;
shm_id=shmget(key,SHM_SIZE,FLAGS);
if(shm_id==-1)
{
printf("error creating shared memory\n");
exit(0);
}
printf("the shared memory segment ID is: %d\n",shm_id);
vecBoard = (char *)shmat(shm_id,0,0);
if((vecBoard = (char *)shmat(shm_id,0,0)) == (char*)-1)
{
printf("error in attaching to the shared memory\n");
exit(0);
}
}
The shown code calls shmat() twice, for the same memory segment.
That's obviously wrong.
Looking at errno would help diagnose the problem (i.e. call perror on failure instead of just printf). The OS gives you information when a system call fails; don't ignore it!
If you carefully read the man page for shmget, the third argument (flags) is supposed to contain, in its low 9 bits, the permissions desired for the shared memory segment. If you just pass IPC_CREAT here, those bits are cleared to 0, so you create a segment for which nobody has either read or write permissions. Thus shmat fails (with EACCES because you are (implicitly) asking to both read and write that segment, and you don't have permission to do either.
You probably want to change it to something like IPC_CREAT | 0600, if you want the current user to be able to access the segment.
Note that before testing this again, you'll probably have to remove the existing shared memory segment with the erroneous permissions. Use the ipcs and ipcrm tools for this.

Setting Immutable Flag using ioctl() in C

I have attempted to make a script that creates a file and then sets it as immutable similar to the chattr +i command for linux. The script compiles (with gcc), runs and the file is created. However the file itself is not immutable and can be removed with a simple rm -f. I have attempted to stacktrace where chattr is called and I found a function called ioctl. I then used what little information I could gather and came up with what I have below. I narrowed it down from ext2_fs.h but it just doesn't seem to work. I've clearly overlooked something.
Updates to previous entry: Compiles but returns -1 on ioctl() function. Bad address shown with perror().
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
fp = fopen("/shovel.txt", "w+");
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
ioctl(fileno(fp), FS_IOC_SETFLAGS, 0x00000010);
fclose(fp);
}
Any help appreciated.
You are using the right ioctl command, but you're passing it the wrong arguments.
The manpage for ioctl_list(2) shows that FS_IOC_SETFLAGS expects to receive a pointer to int (an int *), yet you're passing it an integer literal (hence the Bad Address error).
The fact that you don't to any error checking whatsoever is also not helping.
The correct flag to pass to FS_IOC_SETFLAGS is a pointer holding the value EXT2_IMMUTABLE_FL, which is defined in ext2fs/ext2_fs.h (some older / different Linux distributions seem to have it under linux/ext2_fs.h), so you'll need to #include <ext2fs/etx2_fs.h>. Make sure to install e2fslibs-dev (and probably you'll need linux-headers too).
This code is working:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
#include <ext2fs/ext2_fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
if ((fp = fopen("shovel.txt", "w+")) == NULL) {
perror("fopen(3) error");
exit(EXIT_FAILURE);
}
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
int val = EXT2_IMMUTABLE_FL;
if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
perror("ioctl(2) error");
fclose(fp);
return 0;
}
Remember to run this as root.
UPDATE:
As Giuseppe Guerrini suggests in his answer, you might want to use FS_IMMUTABLE_FL instead, and you won't need to include ext2_fs.h:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <linux/fs.h>
int main()
{
FILE *fp;
char shovel[16] = "I have a shovel!";
if ((fp = fopen("shovel.txt", "w+")) == NULL) {
perror("fopen(3) error");
exit(EXIT_FAILURE);
}
fwrite(shovel, sizeof(shovel[0]), sizeof(shovel)/sizeof(shovel[0]), fp);
int val = FS_IMMUTABLE_FL;
if (ioctl(fileno(fp), FS_IOC_SETFLAGS, &val) < 0)
perror("ioctl(2) error");
fclose(fp);
return 0;
}
The main problem is that the ioctl wants a pointer to the mask, not a direct constant. You have to define a int variable, store the mask (0x10) in it and pass its address as third argument of ioctl.
Also, I'd add some hints:
other programs to change attributes are used to use low-level I/O directly (open, close...). Also, the file is usually opened with O_RDONLY.
Use FS_IMMUTABLE_FL istead the raw constant.
Get the current attribute mask first (FS_IOC_SETFLAGS) and mask it with the new flag, so other settings are not lost by the service.

How to read a file permission and store it in a variable in C

In Linux platform(Ubuntu system).
As describe in title.
I try to get a number like '0644' and store it in a variable for later use.
the stat, fstat, lstat system calls can be used to retrieve the permission of a file.
The field st_mode of the stat structure contains the permission of the file specified as argument of the system call. Then a variable of type mode_t can be used as local storage in your application.
This is an example :
#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#define FILE_NAME "test.c"
int main(int argc, char *argv[])
{
struct stat sb;
mode_t file_permision;
if (stat(FILE_NAME, &sb) == -1) {
perror("stat");
exit(EXIT_FAILURE);
}
file_permision = sb.st_mode;
printf(" File permission : %o (octal)\n",
(unsigned int) file_permision);
return 0;
}

open() function error when flags are a char string pointer instead of an int

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
int main(int argc,char *argv[])
{
int fd;
int i=1;
for(i=1;i<argc;++i)
{
char temp;
fd=open(argv[i],"O_RDWR");
if (fd==-1)
perror("file:");
while (read(fd,&temp,1)!=EOF)
{
putchar(temp);
}
}
}
I execute ./a.out a b. a and b are files in my directory. I get an error saying File exists.
The line open(argv[i],"O_RDWR") is not opening the file.
It is returning -1 since the file exists . How then should i open the file using the open system call?
fd=open(argv[i],"O_RDWR");
^ ^
You're passing a char * instead of an integer constant. Drop the ", it should be just:
fd = open(argv[i], O_RDWR);
Interestingly but likely off-topic, open must have thought you passed O_CREAT | O_EXCL, that's why it complained about the file already existing.
So what i have wriiten is right then???But the code is going into an
infinite look printing nothin
The function read(2) doesn't return EOF at and of input but rather 0.

Unix/C: put a file into shared memory

Have a problem.
I have a file which contents look like number:error_description.
Now i need to put this file to shared memory (POSIX). If any contents are modified it should be saved to the base-file.
There is a need to search in the content in the shared memory (results will be sent to a client over a message queue).
How do I implement all this? First I thought I have to open (fopen("my_file", "r")) and then I have to create shared memory and mmap the file.
Can someone help me?
edit:
#include <stdio.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <semaphore.h>
/*
* \ /tmp/errors -> Error File
*/
#define MSGQ_HANDLER "/error_handler"
#define PATH_TO_FILE "/tmp/errors"
#define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
int main(void) {
int fd = open(PATH_TO_FILE, O_RDWR);
struct stat file_stat;
fstat(fd, &file_stat);
printf("File size: %zd\n", file_stat.st_size);
char *byte_ptr = mmap(NULL, file_stat.st_size, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
if(byte_ptr == MAP_FAILED){
perror("error:");
}
while(1){
printf("%s\n", byte_ptr);
if(byte_ptr)
exit(1);
}
return EXIT_SUCCESS;
}
So far it is what I have now.
Read a line works.
How do I change the content?
Don't use fopen and forget about shared memory (the sh* API I mean). mmap is all that's needed.
Open your file with open and the right options (read/write). Then use mmap with the option MAP_SHARED. All changes in the file will be reflected directly and visible to all processes that map the same file. On Linux and Solaris (on other systems I don't know, but it is not guaranteed by POSIX or any standard) you can even access the file concurrently with read/write. It is a bad idea though.
Concurrent memory accesses from different processes will, of course, need synchronisation (mutex, semaphores etc.).

Resources