Program Behavior:
Server:
Create FIFOs
Listen to Write from Client, Block until something is read.
if Something is read, prompt a message to Write to Client.
repeat...
Client:
Prompt Message to write to Server.
After write, Listen to Incoming messages.
If something is read, prompt a message to reply.
repeat...
================================ISSUES===================================
The Programs does communicate, however sometimes the call READ won't catch the WRITE call from the other program.
========================================================================
Server Code:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#define SERVER_FIFO_FILE "/lab7_server_fifo"
#define CLIENT_FIFO_FILE "/lab7_client_fifo"
#define PERM 0666
int main(int argc, char** argv)
{
int s_read = 0;
int s_write = 0;
int exit = 0;
int listening = 1;
int writing = 0;
char* w_buffer = NULL;
size_t w_buffer_len = 0;
char r_buffer[BUFSIZ];
char* home = getenv("HOME");
char SERVER_FIFO[100];
char CLIENT_FIFO[100];
strcpy(SERVER_FIFO,home);
strcat(SERVER_FIFO, SERVER_FIFO_FILE);
strcpy(CLIENT_FIFO,home);
strcat(CLIENT_FIFO, CLIENT_FIFO_FILE);
mkfifo(SERVER_FIFO, PERM);
mkfifo(CLIENT_FIFO, PERM);
s_read = open(SERVER_FIFO, O_RDONLY | O_NONBLOCK);
s_write = open(CLIENT_FIFO, O_WRONLY | O_NONBLOCK);
while (!exit)
{
if (writing)
{
printf(">>>");
getline(&w_buffer,&w_buffer_len,stdin);
if (strcmp("exit",w_buffer)==0)
{
exit = 1;
}
else
{
write(s_write,w_buffer,w_buffer_len);
writing = 0;
listening = 1;
}
}
else
{
if (listening)
{
printf("listening...\n");
listening = 0;
}
read(s_read, r_buffer, BUFSIZ);
if (strlen(r_buffer) != 0)
{
if (strcmp(r_buffer,"exit") == 0)
{
exit = 1;
}
else
{
printf("%s",r_buffer);
writing = 1;
}
}
}
memset(r_buffer, 0, sizeof(r_buffer));
}
close(s_read);
close(s_write);
remove(SERVER_FIFO);
remove(CLIENT_FIFO);
return 0;
}
Client Code:
#include <fcntl.h>
#include <stdio.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#define SERVER_FIFO_FILE "/lab7_server_fifo"
#define CLIENT_FIFO_FILE "/lab7_client_fifo"
int main(int argc, char** argv)
{
int c_read = 0;
int c_write = 0;
int exit = 0;
int listening = 0;
int writing = 1;
char* w_buffer = NULL;
size_t w_buffer_len = 0;
char r_buffer[BUFSIZ];
char* home = getenv("HOME");
char SERVER_FIFO[100];
char CLIENT_FIFO[100];
strcpy(SERVER_FIFO,home);
strcat(SERVER_FIFO, SERVER_FIFO_FILE);
strcpy(CLIENT_FIFO,home);
strcat(CLIENT_FIFO, CLIENT_FIFO_FILE);
c_write = open(SERVER_FIFO, O_WRONLY | O_NONBLOCK);
c_read = open(CLIENT_FIFO, O_RDONLY | O_NONBLOCK);
while (!exit)
{
if (writing)
{
printf(">>>");
getline(&w_buffer,&w_buffer_len,stdin);
if (strcmp("exit",w_buffer)==0)
{
exit = 1;
}
else
{
write(c_write,w_buffer,w_buffer_len);
writing = 0;
listening = 1;
}
}
else
{
if (listening)
{
printf("listening...\n");
listening = 0;
}
read(c_read, r_buffer, BUFSIZ);
if (strlen(r_buffer) != 0)
{
printf("%s",r_buffer);
writing = 1;
}
}
memset(r_buffer, 0, sizeof(r_buffer));
}
close(c_read);
close(c_write);
return 0;
}
CURRENT OUTPUT:
server:
listening...
hello
>>>hi
listening...
client:
>>>hello
listening...
hi
>>how are you
listening...
ISSUE: Server Does Not Receive the message "how are you" from server.
client went into listening stage, causing the programs to stuck in a loop of listening.
SOLVED All i had to do was add the flag O_SYNC to write in server and client so it'll auto flush to disk causing it to be slower, that way read will have enough time to catch the call.
Related
I need to read an eeprom in an embedded device.
So far this "almost" worked:
#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <fcntl.h>
#include <linux/i2c-dev.h>
#define READ_SIZE (256)
#define NB_PAGES (128)
void dump_to_file(const char *output_file_path,
const uint8_t *buffer, const int buffer_length)
{
int output_file = open(output_file_path, O_RDWR|O_APPEND|O_CREAT);
if (output_file < 0) {
printf("Failed opening output file %s\n", output_file_path);
return;
}
write(output_file, buffer, buffer_length);
}
int main(int argc, char *argv[])
{
/* got these values from i2cdetect */
const char *i2c_device = "/dev/i2c-4";
const int device_address = 0x50;
/* open the i2c device file */
int file = open(i2c_device, O_RDWR);
if (file < 0) {
printf("Failed opening %s\n", i2c_device);
return 1;
}
if (ioctl(file, I2C_SLAVE, device_address) < 0) {
printf("Failed addressing device at %02X\n", device_address);
close(file);
return 1;
}
int i = 0;
for (i = 0; i < NB_PAGES; i++) {
char buf[READ_SIZE] = {0};
if (read(file, buf, READ_SIZE) != READ_SIZE) {
printf("Failed reading\n");
close(file);
return 1;
}
dump_to_file(argv[1], buf, READ_SIZE);
}
close(file);
return 0;
}
By "almost" I mean that it dumps the full eeprom but the START depends on the last block read..
It's not always the same.
If I read 10 blocks. then run the program again I read the next ones and not the first 10.
How to set the starting address?
Update:
if I do:
i2cset -y 4 0x50 0x00 0x00
and the run the above code, it works.
so how can I put the equivalent of the i2cset command in the code?
Done!
It wasn't easy because I could not find documentations anywhere.. but I thought that since the eeprom is 32K, maybe it was "like" a 24c256. But even in that case I found nothing in userspace until I decided to go by instinct.
I studied i2cset source, understood what it did and put it in the code.
Here is the result, which dumps a full i2c 32k eprom from userspace.
Note a full backup and restore utility can be found here:
https://gist.github.com/Zibri/cf8ac0b311301aeeaa8910c7da824bff
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <linux/i2c-dev.h>
#define READ_SIZE (256)
#define NB_PAGES (128)
void dump_to_file(const char *output_file_path,
const uint8_t *buffer, const int buffer_length)
{
int output_file = open(output_file_path, O_RDWR|O_APPEND|O_CREAT);
if (output_file < 0) {
printf("Failed opening output file %s\n", output_file_path);
return;
}
write(output_file, buffer, buffer_length);
}
int main(int argc, char *argv[])
{
const char *i2c_device = "/dev/i2c-4";
const int device_address = 0x50;
int file = open(i2c_device, O_RDWR);
if (file < 0) {
printf("Failed opening %s\n", i2c_device);
return 1;
}
if (ioctl(file, I2C_SLAVE, device_address) < 0) {
printf("Failed addressing device at %02X\n", device_address);
close(file);
return 1;
}
int i = 0;
write(file,'\x00\x00',2); // ADDRESS
for (i = 0; i < NB_PAGES; i++) {
char buf[READ_SIZE] = {0};
if (read(file, buf, READ_SIZE) != READ_SIZE) {
printf("Failed reading\n");
close(file);
return 1;
}
dump_to_file(argv[1], buf, READ_SIZE);
}
close(file);
return 0;
}
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; }
I'm trying to lock some critical resources that are accessed by multiple applications under linux.
All the applications will call the acquireLock function on the same file when entering the critical section, and the releaseLock when leaving.
If the lock is not acquired for more than timeot the caller will go ahead doing something else.
The code below works whit slow processes, but under stress the lock is easily broken the lock is acquired by multiple processes, so I guess I'm stumbling in a race condition somewhere.
Can somebody point me out why it's not working and what would be the correct implementation?
Thanks a lot!
MV
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>
//************************************************************
#define CYCLETIME 1000
//************************************************************
//************************************************************
int acquireLock(char *lockFile, int msTimeout)
{
int lockFd;
int cntTimeout = 0;
if ((lockFd = open(lockFile, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
return -1;
while (flock(lockFd, LOCK_EX | LOCK_NB) < 0){
usleep(CYCLETIME);
cntTimeout++;
if(cntTimeout >= msTimeout){
return -1;
}
}
return lockFd;
}
//*************************************************************
void releaseLock (int lockFd)
{
flock(lockFd, LOCK_UN);
close(lockFd);
}
//************************************************************
It appears that the mistake was in another part of the code, the lock is working as expected.
I share the code I'm using in case it can be helpful to somebody else.
Those are the locking functions:
/* ----------------------------------------------------------------------- *
* Code derived by the flock.c in the "util-linux" ubuntu package
* by Peter Anvin
* ----------------------------------------------------------------------- */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <sys/file.h>
#include <sys/time.h>
#include <signal.h>
//************************************************************
static sig_atomic_t timeout_expired = 0;
//************************************************************
static void timeout_handler(int sig)
{
(void)sig;
timeout_expired = 1;
}
//************************************************************
int acquireLock(char *lockFile, int msTimeout)
{
struct itimerval timeout, old_timer;
struct sigaction sa, old_sa;
int err;
int sTimeout = msTimeout/1000;
memset(&timeout, 0, sizeof timeout);
timeout.it_value.tv_sec = sTimeout;
timeout.it_value.tv_usec = ((msTimeout-(sTimeout*1000))*1000);
memset(&sa, 0, sizeof sa);
sa.sa_handler = timeout_handler;
sa.sa_flags = SA_RESETHAND;
sigaction(SIGALRM, &sa, &old_sa);
setitimer(ITIMER_REAL, &timeout, &old_timer);
int lockFd;
int cntTimeout = 0;
if ((lockFd = open(lockFile, O_CREAT | O_RDWR, S_IRWXU | S_IRWXG | S_IRWXO)) < 0)
return -1;
while (flock(lockFd, LOCK_EX))
{
switch( (err = errno) ) {
case EINTR: /* Signal received */
if ( timeout_expired )
setitimer(ITIMER_REAL, &old_timer, NULL); /* Cancel itimer */
sigaction(SIGALRM, &old_sa, NULL); /* Cancel signal handler */
return -1; /* -w option set and failed to lock */
continue; /* otherwise try again */
default: /* Other errors */
return -1;
}
}
setitimer(ITIMER_REAL, &old_timer, NULL); /* Cancel itimer */
sigaction(SIGALRM, &old_sa, NULL); /* Cancel signal handler */
return lockFd;
}
//***************************************************************
void releaseLock (int lockFd)
{
flock(lockFd, LOCK_UN);
close(lockFd);
}
//************************************************************
... and those can be tried by reading and writing a FIFO
#include <stdio.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include "lock.h"
#define LOCKED 1
void main(int argc, char **argv)
{
const char *filename;
const char *fifo_name;
const char *message;
int lockfd, fifoHandle;
filename = argv[1];
fifo_name = argv[2];
message = argv[3];
char bufin[1024];
char bufout[1024];
struct stat st;
int bufsize = strlen(message)+1;
int sleeptime = 0;
int j = 0;
if (stat(fifo_name, &st) != 0)
mkfifo(fifo_name, 0666);
while (1){
if (LOCKED)
lockfd=acquireLock(filename, 15000);
if (lockfd==-1)
printf("timeout expired \n");
fifoHandle= open(fifo_name, O_RDWR);
strcpy(bufin, message);
bufin[bufsize-1] = 0x0;
write(fifoHandle, bufin, sizeof(char)*bufsize);
sleeptime = rand() % 100000;
usleep(sleeptime);
read(fifoHandle, &bufout, sizeof(char)*(bufsize+1));
printf("%s - %d \n", bufout, j);
j= j+1;
if (LOCKED)
releaseLock(lockfd);
sleeptime = rand() % 10000;
}
unlink(fifo_name);
return;
}
by sending in two terminals
./locktestFIFO ./lck ./fifo messageA
./locktestFIFO ./lck ./fifo messageB
if LOCKED is not set to 1 the messages will mix up, otherwise the two threads will take and release the resource correctly.
I am writing small C program which will act like daemon and do something every second. I managed it to run only single instance using filelock and last thing I need to know is if it is possible to send commandline arguments to running program, something like that:
first program start:
./sampleprogram
then decide to take some action/update setting
./sampleprogram -r
it will be another rotation script for my thinkpad X41 convertible:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
/*#include <stdbool.h>*/
#define TRUE 1
#define FALSE 0
#define NIL -1
int fdlock;
int get_lock(void)
{
struct flock fl;
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 1;
if((fdlock = open("oneproc.lock", O_WRONLY|O_CREAT, 0666)) == -1) { return 0; }
if(fcntl(fdlock, F_SETLK, &fl) == -1) { return 0; }
return 1;
}
int main() {
if(!get_lock()) {
fputs("Process already running!\n", stderr);
return 1;
}
int tabletmode;
int autorotate = TRUE;
int prevmode = NIL;
FILE *fstate;
char state[1];
FILE *fgyrovals;
char gyroval_a[1];
while (TRUE) {
fstate = fopen("/sys/devices/platform/thinkpad_acpi/hotkey_tablet_mode", "r");
fread(state, sizeof(state[0]), 1, fstate);
/*
printf("picaa");
fflush(stdout);
*/
/*tabletmode = atoi(state[0]);*/
tabletmode = state[0] - '0';
printf("koko: %d", tabletmode);
fflush(stdout);
fclose(fstate);
if (prevmode != tabletmode) {
if (tabletmode) {
system("notify-send 'Notebook v tablet móde'");
} else {
system("notify-send 'Notebook v štandartnom režime'");
}
}
if (tabletmode) {
if (autorotate) {
fgyrovals = fopen("/sys/devices/platform/hdaps/position", "r");
fclose(fgyrovals);
}
}
prevmode = tabletmode;
sleep(1);
}
return 0;
}
Why does the following code print ‘read(): Resource temporarily unavailable’ 80% of the time? That is the EAGAIN code, which is the same as WOULD BLOCK which means there is no data waiting to be read, but select is returning 1 saying there is data (tested in Linux):
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/errno.h>
int main(int argc, char** argv)
{
int fd = open("/dev/lp0", O_RDWR | O_NONBLOCK);
int ret = 0;
int status = 0;
char buffer[1024];
char teststr[] = "This is a test\n";
char XMIT_STATUS_OFFLINE[] = {0x10,0x04,0x02};
char XMIT_STATUS_ERROR[] = {0x10,0x04,0x03};
char XMIT_STATUS_ROLL[] = {0x10,0x04,0x04};
char XMIT_STATUS_SLIP[] = {0x10,0x04,0x05};
fd_set rfds;
FD_ZERO( &rfds );
FD_SET( fd, &rfds );
struct timeval sleep;
sleep.tv_sec = 5;
sleep.tv_usec = 0;
/* Offline status */
ret = write(fd, XMIT_STATUS_OFFLINE, sizeof(XMIT_STATUS_OFFLINE));
//printf("write() returned %d\n", ret);
do {
ret = select( fd + 1, &rfds, NULL, NULL, &sleep );
} while (ret < 0 && (errno == EINTR));
ret = read(fd, buffer, 1024);
if(ret == -1) {
perror("read(): ");
} else {
status = buffer[0];
if((status & 0x04) != 0)
{
printf("The cover is open.\n");
} else {
printf("OFFLINE is good.\n");
}
}
close(fd);
return 0;
}
Your select call will return 0 after the 5 second timeout elapses if no data is available. Your code will ignore this and try to read from the device anyways. Check for ret == 0 and that will fix your problem.