Named piped error - c

Sorry for the poor title, i didnt' know how to explain this simply.
I have 2 programs : a server and a client.
Server make a named pipe and waits to read something. Client connects and send a message to the pipe. Server checks a part of the message to get the "type" of the message (in this case, type is "HELO") reading char 4 to 8 of the sent string. If i send "HELO", server prints "Type : HELO" as expected.
But if i send a message with something else, it doesn't print "No match" as expected : it just does nothing.
Here is the code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#define BUF_SIZE 256
char * getType(char * message){
char* type = malloc(sizeof(char)*5);
memcpy(type,&message[4],4);
type[4] = '\0';
return type;
}
int main(int argc, char* argv[]){
mkfifo("tchatserv", 0666);
int fd = open("tchatserv", O_RDONLY);
char buf[BUF_SIZE];
int val;
while(1){
val = read(fd, buf , BUF_SIZE );
if(val >0){
char * type = getType(buf);
if(strcmp("HELO",type) == 0){
printf("Type: %s\n", type);
}
else{
printf("no match");
}
}
}
}
Here is client :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <string.h>
#include <fcntl.h>
char * makeInt(int val){
char* res = malloc(sizeof(char)*5);
char l [5] = "";
sprintf(l,"%d",val);
if(val < 10){
strcat(res,"000");
strcat(res,l);
}
else if(val < 100){
strcat(res,"00");
strcat(res,l);
}
else if(val < 1000){
strcat(res,"0");
strcat(res,l);
}
else if( val < 10000){
strcat(res,l);
}
return res;
}
char * makeString(char * ch, int final){
int t = strlen(ch);
if(final == 1){
t = t+4;
}
char * chaine = makeInt(t);
strcat(chaine,ch);
return chaine;
}
void connection(){
printf("Pseudo:\n");
char * pseudo = malloc(sizeof(char)*30);
pseudo[0] = '\0';
scanf("%s", pseudo);
printf("Tube:\n");
char * tube = malloc(sizeof(char)*30);
tube[0] = '\0';
scanf("%s", tube);
char * message = malloc(sizeof(char)*100);
char * type = "HELO";
message[0] = '\0';
strcat(message,type);
pseudo = makeString(pseudo,0);
strcat(message,pseudo);
tube = makeString(tube,0);
strcat(message,tube);
message = makeString(message,1);
printf("%s",message);
int fd = open("tchatserv", O_WRONLY);
write(fd,message,256);
}
int main(int argc, char* argv[]){
connection();
return 0;
}
EDIT: When i try to send something else than HELO it doesn't print "no match" but then i send HELO and it prints : "no match Type: HELO", like if the first "no match" got stuck in the pipe instead of getting printed immediately, i don't understand why.

When i try to send something else than HELO it doesn't print "no match" but then i send HELO and it prints : "no match Type: HELO", like if the first "no match" got stuck in the pipe instead of getting printed immediately, i don't understand why.
The no match indeed got stuck in a way, though not in the pipe, but rather in the server's buffer of the standard output stream, which is presumably line buffered, i. e., characters are transmitted (printed) when a new-line is encountered. To cure this, just change the printf("no match") to printf("no match\n") or puts("no match").

Related

Why do I get segmentation fault using fopen?

I'm writing a client-server model in C which works using fifos. I send a file name plus a name for a unique fifo for the client to recieve the data from the client and the server opens the file and writes the first line of it on the fifo. The thing is that even if the file exists i get a segmentation fault when opening it. Seems like the fopen() function works but I still get the error. If the file doesn't exist it just sends an empty string.
Here is client.c :
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#define BUFSIZE 512
struct sent {
char name[BUFSIZE];
char fifo[BUFSIZE];
};
int main()
{
char name[BUFSIZE];
char recieved[BUFSIZE];
int client_server_fifo;
char cs_fifo[BUFSIZE] = "cs_fifo";
int server_client_fifo;
char sc_fifo[BUFSIZE];
sprintf(sc_fifo, "sc_fifo_%d", getpid());
struct sent *sent;
mkfifo(sc_fifo, 0777);
while(1) {
printf("Write the name of the file: ");
scanf("%s", name);
printf("1111\n");
client_server_fifo = open(cs_fifo, O_WRONLY);
printf("2222\n");
printf("%s", name);
printf("%s", cs_fifo);
sent->name = name;
sent->fifo = cs_fifo;
printf("%s", name);
printf("%s", cs_fifo);
write(client_server_fifo, sent, sizeof(*sent));
server_client_fifo = open(sc_fifo, O_RDONLY);
if (read(server_client_fifo, recieved, sizeof(recieved)) == -1) {
printf("An error ocurred.\n");
} else {
printf("First line of the file: \n%s\n", recieved);
close(client_server_fifo);
close(server_client_fifo);
}
memset(recieved, 0, sizeof(recieved));
}
return 0;
}
And here's server.c :
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#define BUFSIZE 512
struct sent {
char name[BUFSIZE];
char fifo[BUFSIZE];
};
int main()
{
int client_server_fifo;
char cs_fifo[BUFSIZE] = "cs_fifo";
int server_client_fifo;
char sc_fifo[BUFSIZE];
struct sent *sent;
char name[BUFSIZE];
char line[BUFSIZE];
FILE *file;
printf("Server running...\n");
mkfifo(cs_fifo, 0777);
while (1)
{
client_server_fifo = open(cs_fifo, O_RDONLY);
read(client_server_fifo, sent, sizeof(*sent));
strcpy(name, sent->name);
strcpy(sc_fifo, sent->fifo);
if((file = fopen(name, "r")) != NULL) {
printf("%s\n", name);
fgets(line, BUFSIZE, file);
printf("%s\n", name);
}
server_client_fifo = open(sc_fifo, O_WRONLY);
write(server_client_fifo, line, strlen(line));
memset(name, 0, sizeof(name));
memset(line, 0, sizeof(line));
close(client_server_fifo);
}
return 0;
}
Why does this happen?
The program has undefined behavior because in gthis statement
sprintf(sc_fifo, "sc_fifo_%d", getpid());
you are trying to change a string literal pointed to by the pointer sc_fifo.
char *cs_fifo = "cs_fifo";
When you declare a pointer to a string literal always declare them with the qualifier const. In this case you will get ban error at compilation time if you will tray to change a string literal.
Also you are using uninitialized pointer sent
struct sent *sent;
in this statement
read(client_server_fifo, sent, sizeof(*sent));
There are other errors. For example arrays do not have the assignment operator. So these statements in client.c
sent->name = name;
sent->fifo = cs_fifo;
are incorrect.

Error when changing the console output to file in C

I'm new to stack overflow so bear with me :)
I am trying to create a custom linux shell as a project.
Right now I want to make the default output going to a file instead of console when the user uses > symbol for example ls > filename.txt
But , the program crashes and a Bad address error pops yet it writes the command output to the file.
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
typedef char* string;
int main (int argc,char** argv) {
int error = 0;
int posIn=0; int posOut=0; int appendMark=0;
string Output,Input;
while (1) {
error=0;
char progName[255];
printf("\nmysh3 > ");
if(fgets(progName,500,stdin)==NULL){return 0 ;}
char dir[1024];
string params[40];
string pch=progName;
int i=0;
while ((pch = strtok (pch," \n")) != NULL){
params[i]=pch;
if (strcmp(pch,"<")==0) { posIn = i;params[i]=NULL;i--;} // < is skipped and we put only the name of the command on the params array
if (strcmp(pch,">")==0) { posOut = i;params[i]=NULL;i--;} //output
if (strcmp(pch,">>")==0) {appendMark=1;params[i]=NULL;i--;}
i++;
pch = NULL;
}
params[i]=NULL;
if(strlen(progName)>255){
printf("The commands can't be over 255 characters\n");
return 0;
}
if (posOut) {
int out = open(params[posOut], O_CREAT|O_TRUNC|O_WRONLY, 0777);
params[posOut]=NULL;
if (out < 0) {
error = 1;
fprintf(stderr,"open error: %d [%s]\n",errno,strerror(errno));
exit(1); }
int k = dup2(out,1);
if (k<0) {
error = 1;
perror("Cannot redirect output");
}
close(out);
}
pid_t proccess1,waitpid;
int status;
proccess1 = fork();
if (proccess1<0) {perror("Out of memory"); } //Monos tropos na apotyxei h fork einai na mhn yparxei mnhmh
else if (proccess1==0) {
execvp(params[0],params);
if (!error) {perror("Unknown command");}
}
else {
waitpid=wait(&status);
if (waitpid==-1) {perror("ERROR: A NEW ZOMBIE IS BORN 3:)");return 0;}
}
}
return 0; }

write() warning message in compilation

I have a piece of code to create function to print a message from input parameter.
I've been compiling the code with c9.io and works pretty well without warnings but when i do it locally it shows a warning like this:
child2bok: c39:11: warning: Ignoring return value of 'write', declares with attribute warn_unused_result [-Wunused -result]
And this is the code.Sure it is a problem with write() definition but i'm so novice with unix programming and no idea to solve it. It executes well but i'd like to remove the warning before i deliver to the teacher.
Here you are the code:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/time.h>
#include <unistd.h>
#include "rutines.h"
void children();
void show_help();
int main(int argc, char *argv[])
{
int ord;
if (argc > 1)
ord = atoi(argv[1]);
if (argc == 1)
{
show_help("Error");
exit(1);
}
children(ord);
}
void children(int ord)
{
char msg[10];
srand(getpid());
sleep(rand() % 5);
sprintf(msg, " %d", ord);
while (strlen(msg) > 0)
{
int written= write(1, msg, strlen(msg));
if (written < 0)
break;
exit(0);
}
void show_help(char *err_message)
{
write_string(err_message,"");
write_string("Usage: child2aok \n","");
}
You should check and handle the value returned by the write() command. From the write documentation:
write [...] may return less than count even under valid conditions.
Why don't you simply use printf(" %d", ord); instead of sprintf(msg, " %d", ord); write(1, msg, strlen(msg))?
write does not guarantee to write all the data; it may write as little as one byte (or block, or return an error, ...). So you have to use it in a loop:
bool write_all(int fd, void * buf, size_t len)
{
size_t remaining = len;
for (size_t n; (n = write(fd, buf, remaining)) > 0; remaining -= n)
{ }
return remaining == 0;
}
This function returns true if all bytes were written, and false on error.

File sent over TCP is created with type: application/octet-stream

I'm trying to transfer a file from a server to a client using TCP protocol.
I manage to send the whole syze of the file, but when the client creates the file, it cant be open. In this case, im sending an jpg file.
heres the code for server.c:
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#define PORT 59000
int main(int argc,char *argv[]) {
int port, fd, newfd, n, nw, addrlen;
int port_was_given = 0;
char buffer[128], *ptr, *topic, *data;
size_t result;
struct hostent *h;
struct sockaddr_in addr;
FILE *send;
if((fd=socket(AF_INET,SOCK_STREAM,0))==-1)exit(1); //error
memset((void*)&addr,(int)'\0',sizeof(addr));
addr.sin_family=AF_INET;
addr.sin_addr.s_addr=htonl(INADDR_ANY);
if (argc == 3) {
port = atoi(argv[2]);
port_was_given = 1;
}
if(port_was_given == 1)
addr.sin_port=htons((u_short)port);
else
addr.sin_port=htons((u_short)PORT);
if(bind(fd,(struct sockaddr*)&addr,sizeof(addr))==-1)exit(1); //error
if(listen(fd,5)==-1)exit(1); //error
while(1) {
addrlen=sizeof(addr);
if((newfd=accept(fd,(struct sockaddr*)&addr,&addrlen))==-1)exit(1); //erro
h=gethostbyaddr((char*)&addr.sin_addr,sizeof(struct in_addr),AF_INET);
while((n=read(newfd,buffer,128))!=0) {
if(n==-1)exit(1);
topic = strtok(buffer," ");
topic = strtok(NULL," ");
if (strcmp(topic, "Nacional\n")==0) {
send = fopen("flag","r");
fseek(send, 0L, SEEK_END); //vai ate ao fim do ficheiro
int sz = ftell(send); //size of file
fseek(send,0L,SEEK_SET);
//rewind(send);
data = (char*)malloc(sizeof(char)*sz);
result = fread(data,1,sz,send);
//fseek(send,0L,SEEK_SET);
fclose(send);
char ptr2[300] = "REP ok ";
char *ptrInt; //for s -> int
sprintf(ptrInt, "%d", sz);
strcat(ptr2, ptrInt);
strcat(ptr2, " ");
strcat(ptr2, data);
strcat(ptr2, "\n");
while(n>0) {
nw=write(newfd,ptr2,n); //write n bytes on each cycle
}
}
}
close(newfd);
}
close(fd);
exit(0);
}
Ok so the logic is: client requests a type of content, in this case the content is "Nacional", so the server has to send the "flag.jpg" to the client.
The answer of the server has the following type:
REP status size data
In which status can be "ok" or "nok". If "nok" then the file is not sent.
size is the size of the data.
data is data of the file itself.
Now the client.c:
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>
#define PORT 58000
#define NG 10
int main (int argc,char *argv[])
{
/** ... variables declarations and other stuff ... */
fdtcp=socket(AF_INET,SOCK_STREAM,0);
if (fdtcp==-1) exit(1); // Erro
inet_aton(ip, &address);
if (strcmp(lsname, "localhost")==0)
newHost = gethostbyname("localhost");
else
newHost = gethostbyaddr((const void *)&address,sizeof ip,AF_INET);
newPort = atoi(newport);
memset((void*)&addrtcp,(int)'\0',sizeof(addrtcp));
addrtcp.sin_family=AF_INET;
addrtcp.sin_addr.s_addr=((struct in_addr *)(newHost->h_addr_list[0]))->s_addr;
addrtcp.sin_port=htons((u_short)newPort);
k = connect(fdtcp,(struct sockaddr*)&addrtcp,sizeof(addrtcp));
if (k==-1) exit(1); // Erro
// REQ Tn (Conteudo Solicitado)
ptr = strcat(reqdata, tn);
ptr = strcat(reqdata, "\n");
// Envia-se o Comando REQ
nreqleft = 25;
while(nreqleft>0) {
kwrite=write(fdtcp,ptr,nreqleft);
if (kwrite<=0) exit(1); // Erro
nreqleft -= kwrite;
ptr += kwrite;
}
// Recebe-se o Comando REP
nreqleft = 128;
ptr = &buffertcp[0];
kread=read(fdtcp,ptr,nreqleft);
if (kread==-1) exit(1); // Erro
cmd = strtok(buffertcp, " "); // REP
cmd = strtok(NULL, " "); // Status
if(strcmp(cmd,"ok")) {
printf("ERR\n");
exit(1); // Erro
}
cmd = strtok(NULL, " "); // Size
size = atoi(cmd);
// Recebem-se os Dados do Conteúdo Desejado
nreqleft = size;
char data[size];
ptr = &data[0];
while(nreqleft>0) {
kread=read(fdtcp,ptr,nreqleft);
if (kread==-1) exit(1); // Erro
nreqleft -= kread;
ptr += kread;
}
file = fopen("file","w");
fwrite(data, 1, size, file);
fclose(file);
close(fdtcp);
// --------------------------------------------------- //
exit(0);
}
The "other stuff" part is just variables declarations and a UDP connection with another server which has nothing to do with this part, so I'm 100% sure it won't affect this part. In fact, on client.c, if I place an printf of the message received from the server, it will show "REP ok 31800 ?????" which ??? I assume would be the data of the file.
The problem is that the "file" created can't be open. Help?
One problem is that 31800 is much larger than 300, and so when you append the data to your ptr2 array in the server, you have buffer overrun. You can correct that by not sending the data with a separate write() call after sending your "header" in ptr2. Your write() loop looks like it will loop forever, but I am guessing you are not showing all of your code.
In the receiver, I don't see any attempt to parse the header to separate the header from the data. Since you read in up to 128 bytes, that read may have received both the header and some data of the file, and you make no attempt to detect and save that part of the file.
When debugging file transfer applications, I would start with textual files so that you can visually see the resulting file, and run a simple diff on the file you saved with the actual file to see if there are differences.

Convert Linux C Char Array to Int

need some advice on this one as im struggling abit and cannot figure it out.
i have a file that gets updated on a PC to indicate a system ran and what time it ran. i am writing a very simple linux console app (will eventually be a nagios plugin). that reads this file and responds depending on what it found within the file.
i am a total newbie to programming on Linux and using C so please be patient and if you would explain any answers it would really be appreciated.
basically i want to convert a char array containing 5 characters into an integer, however the 5th char in the array is always a letter. so technically all i want to-do is convert the first 4 chars in the array to a integer... how?? ive tried multiple ways with no success, my problem is that presently i do not have a good grasp of the language so have no real ideas on what it can and cannot do.
here is the source to my program.
basically the buf array will be holding a string taken from the file that will look something like this
3455Y (the number will be random but always 4 chars long).
Sorry for the poor formatting of the code, but i cannot get this stupid window for love nor money to format it correctly....
include <fcntl.h>
include <unistd.h>
include <stdio.h>
include <stdlib.h>
include <time.h>
include <string.h>
define COPYMODE 0644
int main(int argc, char *argv[])
{
int i, nRead, fd;
int source;
int STATE_OK = 0;
int STATE_WARNING = 1;
int STATE_CRITICAL = 2;
int STATE_UNKNOWN = 3;
int system_paused = 0;
char buf[5];
int testnumber;
if((fd = open(argv[1], O_RDONLY)) == -1)
{
printf("failed open : %s", argv[1]);
return STATE_UNKNOWN;
}
else
{
nRead = read(fd, buf, 5);
}
close(source);
if (buf[4] == 'P')
{
printf("Software Paused");
return STATE_WARNING;
}
else
{
return STATE_OK;
}
time_t ltime; /* calendar time */
struct tm *Tm;
ltime=time(NULL); /* get current cal time */
Tm=localtime(&ltime);
int test;
test = Tm->tm_hour + Tm->tm_min;
printf("%d", test);
printf("%d", strtoi(buf));
}
You can use sscanf to do the job:
int num = 0;
sscanf(buf, "%4d", &num);
Then num should hold the number from the line in the file.
You can use atoi
atoi requires one char * argument and returns an int.
If the string is empty, or first character isn't a number or a minus sign, then atoi returns 0.If atoi encounters a non-number character, it returns the number formed up until that point
int num = atoi(buf);
if you want to convert the first four characters of a string to an integer do this:
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <stdint.h>
uint8_t convertFirstFourChars(char * str, uint32_t *value){
char tmp[5] = {0};
strncpy((char *) tmp, str, 4);
*value = strtoul(tmp);
return errno;
}
then call / test this function like this
#include <stdint.h>
#include <stdio.h>
int main(int argc, char **argv){
char test1[5] = "1234A";
char test2[5] = "ABCDE";
uint32_t val = 0;
if(convertFirstFourChars((char *) test1, &val) == 0){
printf("conversion of %s succeeded, value = %ld\n", test1, val);
}
else{
printf("conversion of %s failed!\n", test1);
}
if(convertFirstFourChars((char *) test2, &val) == 0){
printf("conversion succeeded of %s, value = %ld\n", test2, val);
}
else{
printf("conversion of %s failed!\n", test2);
}
return 0;
}
FWIW, don't use atoi(...) because it converts any string to an integer regardless of its validity as a number. atoi("foo") === 0.
this is as much of your code as I was able to recover from the formatting:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#define COPYMODE 0644
int main(int argc, char *argv[])
{
int i, nRead, fd;
int source;
int STATE_OK = 0;
int STATE_WARNING = 1;
int STATE_CRITICAL = 2;
int STATE_UNKNOWN = 3;
int system_paused = 0;
char buf[5];
int testnumber;
if((fd = open(argv[1], O_RDONLY)) == -1)
{
printf("failed open : %s", argv[1]);
return STATE_UNKNOWN;
}
else
{
nRead = read(fd, buf, 5);
}
close(source);
if (buf[4] == 'P')
{
printf("Software Paused");
return STATE_WARNING;
} else {
return STATE_OK;
}
time_t ltime; /* calendar time /
struct tm Tm;
ltime=time(NULL); / get current cal time */
Tm=localtime(&ltime);
int test;
test = Tm->tm_hour + Tm->tm_min;
printf("%d", test);
printf("%d", strtoi(buf));
}
this is the version that does what you specified:
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <time.h>
#define COPYMODE 0644
int main(int argc, char *argv[])
{
int i, nRead, fd;
int source;
int STATE_OK = 0;
int STATE_WARNING = 1;
int STATE_CRITICAL = 2;
int STATE_UNKNOWN = 3;
int system_paused = 0;
char buf[5];
int testnumber;
if((fd = open(argv[1], O_RDONLY)) == -1)
{
printf("failed open : %s", argv[1]);
return STATE_UNKNOWN;
}
else
{
nRead = read(fd, buf, 5);
}
close(source);
if (buf[4] == 'P')
{
printf("Software Paused");
return STATE_WARNING;
}/* else {
return STATE_OK;
buf[4] = 0;
} */
time_t ltime; /* calendar time */
struct tm *Tm;
ltime=time(NULL); /* get current cal time */
Tm=localtime(&ltime);
int test;
test = Tm->tm_hour + Tm->tm_min;
printf("%d\n", test);
printf("%d\n", atoi(buf));
}
The biggest problem with your code was the if statement with the returns in each branch, insuring that nothing after the if statement was ever executed.

Resources