Msgsnd in c: permission denied - c

I am trying to create a message queue and then send a message to it. Here is what I have tried:
int main(){
int myMsgQueue;
struct msgStruct{
long mtype;
char mtext[LENGTH];
};
struct msgStruct myMsg;
myMsg.mtype = (long)getpid();
strcpy(myMsg.mtext,"Hey there"); //Setting the string of the message
if((myMsgQueue = msgget(IPC_PRIVATE,IPC_CREAT | IPC_EXCL)) == -1) //Creating the message queue
errore(__LINE__);
if(msgsnd(myMsgQueue,&myMsg,sizeof(myMsg) - sizeof(long),0) == -1) //Sending the message
errore(__LINE__);
if(msgctl(myMsgQueue,IPC_RMID,0) == -1) //Deleting the message queue
errore(__LINE__);
}
The function errore simply prints out a string which explains the error using strerror(errno).
However, the code does not seem to work: errore prints "Permission denied" as msgsnd returns -1.
I cannot figure out what is the problem: I am initializing the message queue and an adequate message structure, then creating a message of a type corresponding to the process' pid and of a text corresponding to "Hey there", then sending the message.
What am I missing?

Read the man page man page
A message queue identifier exists for the argument key, but operation
permission as specified by the low-order 9 bits of msgflg would not be
granted;

Related

Cant get the right outcome with strtok() , need help , c

Am working on a project where it is a communication between server client. Server opens a specific file and stores the message from the client in a buffer using while(1) for repeated communication. All am trying is manage the message like, when client sends this message : AT+REG1=5 , i want to split it ("=") in order to determine operations and values : operation = AT+REG1 And value is 5. In my code i have a struct with informations for "operation" and "value". I use strtok function to split message but it doesnt work right and i dont know why , for example i send through client AT+REG1=5 and when i split the message like :
token=strtok("AT+REG1=5","="); // points to AT+REG1
value=strtok(NULL,"="); // points to the value but returns null
It returns that value is (null) despite that it must return "5".
My build for that is :
typedef enum operation{
insert,
read_reg,
info
}Operation;
typedef struct request{
Operation operation;
int ID;
int **regs;
}Request;
Function that handles the split of message:
Request *parse_request(char *buffer){
char *token=NULL,*value=NULL;
Request *rep=NULL;
rep=(Request*)malloc(sizeof(Request));
token=strtok(buffer,"=");
printf("token:%s\n",token);
value=strtok(NULL," ");
printf("value=%s\n",value);
return rep;
}
And now the main loop where i call this function after receiving the message :
char buffer[SIZE];
while(1){
//Clean buffer
memset(buffer,0,SIZE);
FD_ZERO(&readfd);
FD_SET(fd,&readfd);
timeout.tv_sec=100;
timeout.tv_usec=0;
status=select(40,&readfd,NULL,NULL,&timeout);
if(status==0){
printf("Cannot receive data from client\n");
printf("\tTime Out\n");
exit(1);
}
read_num=read(fd,buffer,sizeof(buffer));
if(read_num<0) perror("Error in reading file descriptor\n");
if(read_num>0){
request=parse_request(buffer);
break;
}
}
The main problem here is that strtok returns null in at value parameter despite that the message is AT+REG1=5 and it must show "5".

msgsnd no permission error

I want to send messages between two processes. But I get a EACCES error when im trying to send a message with msgsnd()
Creating the message queue
const char* MSG_QUEUE = "/tmp/msg_queue";
int file = open(MSG_QUEUE, O_CREAT | O_RDWR | O_APPEND, 0755);
close(file);
key_t key = ftok(MSG_QUEUE, 1);
errno = 0;
msg_queue = msgget(key, IPC_CREAT);
if(msg_queue == -1) {
M_DEBUG("Error %s\r\n", strerror(errno));
}
message struct
struct feld_msg_s {
long id;
char mtext[5];
};
sending a message
struct feld_msg_s a_msg = {1, "Test"};
errno = 0;
int ret = msgsnd(msg_queue, &a_msg, sizeof(a_msg.mtext), 0);
if(ret == -1) {
if(errno == EACCES) {
printf("\r\n NO PERMISSION\r\n");
} else {
printf("msgsnd ERROR!: %s\r\n", strerror(errno));
}
}
in the manpage of msgsnd is written
EACCES The calling process does not have read permission on the message queue, and does not have the CAP_IPC_OWNER capability.
so I've added the following capabilities with the setcap command
sudo setcap CAP_SETFCAP,CAP_IPC_OWNER+epi /home/mvollmer/build-APP-Desktop_Qt_5_6_1_GCC_64bit-Debug/APP
I've checked with getcap if the application got the capabilities. It's fine. But I still receive the No Permission Error.
When execute the application with root rights, its working!
One thing is very strange, altough msgget was succesfull ipcs dont show any message queues.
So where is my fault?
I'm using Linux Mint
Additional Question: Is is possible to use another datatype then char in the msg struct or is a message restricted to strings?
You need to read the man page. Per the POSIX msgget() standard:
SYNOPSIS
#include <sys/msg.h>
int msgget(key_t key, int msgflg); [Option End]
DESCRIPTION
...
The low-order 9 bits of msg_perm.mode shall be set to the low-order 9 bits of msgflg.
Thus, this code
msg_queue = msgget(key, IPC_CREAT);
has the "low-order 9 bits of msgflg" all set to zero. Thus the message queue mode is also all 0 - no permissions for anyone.

Message Passing In C/Printing a char array from a struct in C

I created this program to pass a message to a parent process. I want the parent process to print out the message it receives. I'm not sure if this is an issue with reading the char array or message passing as I am quite new to programming in c. Here is my attempt:
struct msg {
long int mtype; /* message type */
char mtext[1028]; /* message text */
} msg;
int pid, len;
int msgflg = 0;
int msqid;
char *mymsg[1028];
size_t msgsz;
long int msgtyp;
switch(pid=fork()) //fork child process
{//Child process
case 0:
mymsg[1] = "serving for sender\n";
len = strlen(mymsg[1]);
msgsnd(msqid,mymsg[1],len,msgflg);
break;
case -1:
printf("fork failed");
exit(-1);
break;
default:
msg.mtype = 0;
msqid = msgget(IPC_PRIVATE,msgflg);
wait((int *) 0);
msgrcv(msqid,&msg,msgsz,msgtyp,IPC_NOWAIT);
printf("%s",msg.mtext);
msgctl(msqid, IPC_RMID, NULL);
exit(0);
}
My question is, why is the message serving for sending not being displayed when this code is compiled and executed?
You haven't really asked a question, but a couple of issues I can see with the code are:
char *mymsg[1028];
...
mymsg[1] = "serving for sender\n";
Here you have mymsg which is an array of 1028 pointers to char, which is intended to be treated as a string. (By the way, why 1028? Not that it matters, but just so you know 2^10 is 1024). However, this array contains pointers that are not initialized and are pointing to random locations. Important thing is, there is no space allocated for the possible message you want to put in them.
Second issue is that arrays in C start with index 0, so you probably meant to write
mymsg[0] = "serving for sender\n";
That doesn't matter however.
More importantly, you can't copy strings in C using =, you should use strcpy and copy to a memory location that you have already allocated. Here are two ways to do it:
char mymsg[1028][1028]; // if you are sure your messages fit in 1028 chars
...
mymsg[1] = malloc(strlen("serving for sender)*sizeof(char)); // sizeof(char) not really needed
strcpy(mymsg[1], "serving for sender\n");
msgsnd(msqid,mymsg[1],len,msgflg);
free(mymsg[1]);
or
char *mymsg[1028];
...
char str_to_be_printed[] = "serving for sender\n";
mymsg[1] = malloc(strlen(str_to_be_printed)*sizeof(char)); // sizeof(char) not really needed
strcpy(mymsg[1], str_to_be_printed);
msgsnd(msqid,mymsg[1],len,msgflg);
free(mymsg[1]);
Edit: In the second case where you already have the string somewhere (and not in the form of "this is a string"), assigning the pointers is enough and you don't to copy or allocate memory. However, if your situation is more complex than this, and between assignment of mymsg[1] = ... and msgsnd there are other code, you have to make sure the original string stays alive until msgsnd is done. Otherwise, you have a dangling pointer which will cause you problems. Here's the idea:
+-+-+-+-+-+-+-+-+--+
str_to_be_printed ----->|A| |s|t|r|i|n|g|\0|
+-+-+-+-+-+-+-+-+--+
^
mymsg[1]---------------/
If you free the memory of str_to_be_printed, access to mymsg[1] would cause segmentation fault/access violation.
Note that, the code I wrote is just to give you a guideline, don't copy-paste it.
There are few observation related to your code.
When you use system calls (any function which returns any error code) check the return value of the function. In the case of system calls you have used will set errno i.e. error number which can be used to check for error. You can use perror or strerror to see the message (Pointed out by Jonathan Leffler already)
You need to create message queue before using it (Again pointed out by Jonathan Leffler already).
You are sending char * in msgsnd & receiving struct msg type in msgrcv.
You have set the size to be passed in the message queue send & receive calls, for which you are using msgsz but uninitialized. Set value of msgsz to the size you want to send/receive. While sending you seem to sending 17 bytes but while receiving it is not set.
mtype should have a value greater than 0.
Type for pid should be pid_t, which seems do you little good in this case anyway.
Some code sections for your reference:
#include <stdio.h> /*For perror*/
...
/* Create message queue */
msqid = msgget(IPC_PRIVATE, IPC_CREAT);
if( 0 > msqid )
{
perror("msgget");
/* Handle error as per your requirement */
}
...
/* Sending & receiving messages */
...
struct msg {
long int mtype; /* message type */
char mtext[1028]; /* message text */
} sender_msg, receiver_msg;
...
size_t msgsz = 10; /* Send & receive 10 bytes, this can vary as per need. You can receive less than what was sent */
...
switch(fork())
{
case 0: /* Child */
sender_msg.mtype = 1;
strncpy(sender_msg.mtext,"01234567890123", 1027);
/* Sending the whole text size */
if ( 0 > msgsnd(msqid, &sender_msg, strlen(sender_msg.mtext),msgflg))
{
perror("msgsnd");
/* Handle error as per your requirement */
}
break;
case -1:
perror("fork");
exit(-1);
break;
default:
wait((int *) 0);
receiver_msg.mtype = 1;
/* Receive only 10 bytes as set in msgsz */
if( 0 > msgrcv(msqid,&receiver_msg,msgsz,msgtyp,IPC_NOWAIT))
{
perror("msgrcv");
/* Error handling */
}
printf("%s",receiver_msg.mtext);
if (0 > msgctl(msqid, IPC_RMID, NULL))
{
perror("msgctl");
/* Handle error as per your requirement */
}
break;
}
You seem to be using System V message queues APIs here, you can look into the POSIX message queue APIs like mq_open, mq_close, mq_send, mq_receive etc.
For message queue overview see the man pages (man mq_overview)
Use man pages for information about APIs as well.
Hope this helps!
You have several problems:
You need to create the message queue before you call fork(), so that both the parent and child have access to it;
The permissions of the message queue are set from the low-order bits of the second parameter of msgget(), so you need to specify at least read and write permissions for the owner of the message queue. You can use the constant S_IRWXU from <sys/stat.h> here;
You are passing msgsnd() a pointer to a string, but it actually wants a pointer to a message struct like your struct msg.
You should check for msgrcv() failing.
With these issues fixed, the corrected code looks like:
int pid;
int msqid;
msqid = msgget(IPC_PRIVATE, S_IRWXU);
if (msgid < 0) {
perror("msgget");
exit(1);
}
switch(pid=fork()) //fork child process
{//Child process
case 0:
msg.mtype = 1; /* Must be a positive value */
strcpy(msg.mtext, "serving for sender\n");
msgsnd(msqid, &msg, strlen(msg.mtext) + 1, 0);
break;
case -1:
printf("fork failed");
exit(2);
break;
default:
wait(NULL);
if (msgrcv(msqid, &msg, sizeof msg.mtext, 0, IPC_NOWAIT) >= 0)
printf("%s",msg.mtext);
else
perror("msgrcv");
msgctl(msqid, IPC_RMID, NULL);
exit(0);

Receiving from message queues

I have successfully created the message queue by using the following command:
msgIdHareTurtle = msgget(keyHareTurtle, 0644 | IPC_CREAT | O_NONBLOCK);
Now I want to send the queue to some other process I used,
msgsnd(msgIdHareTurtle, (struct msgbuf *)&bufHareTurtle, sizeof(int), IPC_NOWAIT);
and I try to receive it in different process by:
msgrcv(msgIdHareTurtle, (struct msgbuf *)&bufHareTurtle, sizeof(int), 0, IPC_NOWAIT);
my structure bufHareTurtle is of following type:
typedef struct smsgbuf{
long mtype;
unsigned int position;
} smsgbuf;
My question: The sending was successful and the program(both the processes) is running too but whenever I am sending an unsigned integer for example 2 , I AM ALWAYS GETTING THE RECEIVED VALUE (IN LATTER PROCESS) AS 0 EVRYTIME. Could somebody tell me what is the error in this code or what could be possible error elsewhere.
The problem was there in synchronization. The sending to the queue was delayed due to sleep inserted in between. I corrected it and the error was gone

Different Linux message queues have the same id?

I open a mesage queue in a .c file, and upon success it says the message queue id is 3. While that program is still running, in another terminal I start another program (of another .c file), that creates a new message queue with a different mqd_t. But its id also appears as 3. Is this a problem?
server file goes like this:
void server(char* req_mq) {
struct mq_attr attr;
mqd_t mqdes;
struct request* msgptr;
int n;
char *bufptr;
int buflen;
pid_t apid;
//attr.mq_maxmsg = 300;
//attr.mq_msgsize = 1024;
mqdes = mq_open(req_mq, O_RDWR | O_CREAT, 0666, NULL);
if (mqdes == -1) {
perror("can not create msg queue\n");
exit(1);
}
printf("server mq created, mq id = %d\n", (int) mqdes);
and the client goes like:
void client(char* req_mq, int min, int max, char* dir_path_name, char* outfile) {
pid_t pid;
/* get the process id */
if ((pid = getpid()) < 0) {
perror("unable to get client pid");
}
mqd_t mqd, dq;
char pfx[50] = DQ_PRFX;
char suffix[50]; //
sprintf(suffix, "%d", pid);
strcat(pfx, suffix);
dq = mq_open(pfx, O_RDWR | O_CREAT, 0666, NULL);
if (dq == -1) {
perror("can not open data queue\n");
exit(1);
}
printf("data queue created, mq id = %d\n", (int) dq);
mqd = mq_open(req_mq, O_RDWR);
if (mqd == -1) {
perror("can not open msg queue\n");
exit(1);
}
mqdes and dq seem to share the same id 3.
Think of a handle as an array index. An index into an array held by the operating system, one for every process in the system.
When you open a handle (be it for a file, message queue, socket, etc) the operating system records the settings for that object in an array that is unique for your process. The operating system then returns an index into that array to your program.
Every time your program uses that "handle" the operating system is really just looking up a structure in that private array it keeps to find out how to deal with the object related to that "handle".
Linux typically reserves handles 0, 1 and 2 for STDIN, STDOUT, and STDERR respectively. But from then on any handles you open will be numbered 3, 4, and so forth. And your handle 3 might relate to file "/tmp/foo.txt" while another process's handle 3 might relate to file "/tmp/bar.txt". So if two processes are using similar file "handles" it is irrelevant.
By the way, you shouldn't need to know, or care, about what a handle actually contains. In theory it could be anything - a magic number, a pointer, an integer, it doesn't matter. The handle is really a secret token that you just hand to the operating system any time you want access to your system object.
maybe you didn't close the first message queue. because in that situation os gives the same id (index) to the new one.
Message queues are distinguished by the name you give them when you open a message queue using mq_open(3). Message queue descriptors returned by mq_open(3) are only meaningful within a process scope. Put in other words, what another process have as value for message queue descriptor is totally irrelevant to another process. This is completely analogous to file paths and file descriptors. Indeed, Linux is special in the sense that the message queue descriptors are actually file descriptors - see Linux manual page mq_overview(7). This is the explanation for the common value 3 that you see two processes get when opening message queue (in the most typical case 0, 1, 2 having been already opened for the purpose of providing STDIN, STDOUT, and STDERR like PP. already mentions in his answer).

Resources