cat terminal , check usb removed (perror)? - c

For an assignment we have to create C program that functions similar to the cat command. The first hand-in requires it to mimic very minimal operations of cat....i.e print to output, redirect. The issue I'm having is that one requirement is to print an error in the case that an output file residing on a usb drive is lost, i.e usb pulled out whilst redirecting stdout to it.
How do I catch such an error, also how can perform a test-case for that particular error ??
Many Thanks....really have no idea
UPDATE CODE TEMP
int main(){
char c;
while((c = getchar()) != EOF){
putchar(c);
// Ensure newly created file exists
}
return EXIT_SUCCESS;
}

Assuming you are using fprintf(), from the man pages:
On success, the total number of characters written is returned.
So:
store the size of the char array you will write into a variable x
if fprintf() is less than x, the writing was interrupted.
exit gracefully
EDIT:
There are 2 things I'm thinking of:
1: When putchar() fails, it indicates an error when writing to the file. Since writing one byte doesn't take very long, this should be unlikely since it will be in a safe state once the byte is written (or you assume).
You can do this like so
if(putchar(c) == EOF){
//write error
}
2: If you're asked to quit the instant you detect a file removal, then you need to monitor the directory. Luckily, you're only looking at one directory. However that while loop gets in the way of things because getchar() is a blocking function (cannot return until something happens). You should use inotify to monitor the directory, then probably poll to poll the file descriptor of inotify(). When I did this I used select because we were forced to.
Some kind of an idea how to monitor a directory with inotify()
int length, i = 0;
char buffer[EVENT_BUF_LEN];
memset(buffer, 0, EVENT_BUF_LEN*sizeof(char));
//init inotify
fd = inotify_init();
if(fd < 0){
perror("inotify init");
}
//add directory to watch list
wd = inotify_add_watch(fd, path , IN_DELETE |
IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF | IN_MOVED_FROM | IN_MOVED_TO);
fd_set fds;
FD_ZERO(&fds);
FD_SET(fd, &fds);
//wait for event, since read() blocks
length = read( fd, buffer, EVENT_BUF_LEN );
if ( length < 0 ) {
perror("zero event length");
}
struct inotify_event *event;
while (i < length){
//cast the event to a char buffer
event = (struct inotify_event*) &buffer[i];
if (event->len){
//this was a custom function of mine
storeEvent(event);
}
i += EVENT_SIZE + event->len;
}
You'll have to check which attributes to use when adding a directory (like IN_DELETE or IN_MODIFY) since they will determine what triggers an inotify() event. Note this code will only detect one event, and blocks at the read() statement.

Related

Read chardevice with libevent

I wrote a chardevice that passes some messages received from the network to an user space application. The user space application has to both read the chardevice and send/receive messages via TCP sockets to other user-space applications. Both read and receiving should be blocking.
Since Libevent is able to handle multiple events at the same time, I thought registering an event for the file created by the chardevice and an event for a socket would just work, but I was wrong.
But a chardevice creates a "character special file", and libevent seems to not be able to block. If I implement a blocking mechanism inside the chardevice, i.e. mutex or semaphore, then the socket event blocks too, and the application cannot receive messages.
The user space application has to accept outside connections at any time.
Do you know how to make it work? Maybe also using another library, I just want a blocking behaviour for both socket and file reader.
Thank you in advance.
Update: Thanks to #Ahmed Masud for the help. This is what I've done
Kernel module chardevice:
Implement a poll function that waits until new data is available
struct file_operations fops = {
...
.read = kdev_read,
.poll = kdev_poll,
};
I have a global variable to handle if the user space has to stop, and a wait queue:
static working = 1;
static wait_queue_head_t access_wait;
This is the read function, I return -1 if there is an error in copy_to_user, > 0 if everything went well, and 0 if the module has to stop. used_buff is atomic since it handles the size of a buffer shared read by user application and written by kernel module.
ssize_t
kdev_read(struct file* filep, char* buffer, size_t len, loff_t* offset)
{
int error_count;
if (signal_pending(current) || !working) { // user called sigint
return 0;
}
atomic_dec(&used_buf);
size_t llen = sizeof(struct user_msg) + msg_buf[first_buf]->size;
error_count = copy_to_user(buffer, (char*)msg_buf[first_buf], llen);
if (error_count != 0) {
atomic_inc(&used_buf);
paxerr("send fewer characters to the user");
return error_count;
} else
first_buf = (first_buf + 1) % BUFFER_SIZE;
return llen;
}
When there is data to read, I simply increment used_buf and call wake_up_interruptible(&access_wait).
This is the poll function, I just wait until the used_buff is > 0
unsigned int
kdev_poll(struct file* file, poll_table* wait)
{
poll_wait(file, &access_wait, wait);
if (atomic_read(&used_buf) > 0)
return POLLIN | POLLRDNORM;
return 0;
}
Now, the problem here is that if I unload the module while the user space application is waiting, the latter will go into a blocked state and it won't be possible to stop it. That's why I wake up the application when the module is unloaded
void
kdevchar_exit(void)
{
working = 0;
atomic_inc(&used_buf); // increase buffer size to application is unlocked
wake_up_interruptible(&access_wait); // wake up application, but this time read will return 0 since working = 0;
... // unregister everything
}
User space application
Libevent by default uses polling, so simply create an event_base and a reader event.
base = event_base_new();
filep = open(fname, O_RDWR | O_NONBLOCK, 0);
evread = event_new(base, filep, EV_READ | EV_PERSIST,
on_read_file, base);
where on_read_file simply reads the file, no poll call is made (libevent handles that):
static void
on_read_file(evutil_socket_t fd, short event, void* arg)
{
struct event_base* base = arg;
int len = read(...);
if (len < 0)
return;
if (len == 0) {
printf("Stopped by kernel module\n");
event_base_loopbreak(base);
return;
}
... // handle message
}

Write atomically to a file using Write() with snprintf()

I want to be able to write atomically to a file, I am trying to use the write() function since it seems to grant atomic writes in most linux/unix systems.
Since I have variable string lengths and multiple printf's, I was told to use snprintf() and pass it as an argument to the write function in order to be able to do this properly, upon reading the documentation of this function I did a test implementation as below:
int file = open("file.txt", O_CREAT | O_WRONLY);
if(file < 0)
perror("Error:");
char buf[200] = "";
int numbytes = snprintf(buf, sizeof(buf), "Example string %s" stringvariable);
write(file, buf, numbytes);
From my tests it seems to have worked but my question is if this is the most correct way to implement it since I am creating a rather large buffer (something I am 100% sure will fit all my printfs) to store it before passing to write.
No, write() is not atomic, not even when it writes all of the data supplied in a single call.
Use advisory record locking (fcntl(fd, F_SETLKW, &lock)) in all readers and writers to achieve atomic file updates.
fcntl()-based record locks work over NFS on both Linux and BSDs; flock()-based file locks may not, depending on system and kernel version. (If NFS locking is disabled like it is on some web hosting services, no locking will be reliable.) Just initialize the struct flock with .l_whence = SEEK_SET, .l_start = 0, .l_len = 0 to refer to the entire file.
Use asprintf() to print to a dynamically allocated buffer:
char *buffer = NULL;
int length;
length = asprintf(&buffer, ...);
if (length == -1) {
/* Out of memory */
}
/* ... Have buffer and length ... */
free(buffer);
After adding the locking, do wrap your write() in a loop:
{
const char *p = (const char *)buffer;
const char *const q = (const char *)buffer + length;
ssize_t n;
while (p < q) {
n = write(fd, p, (size_t)(q - p));
if (n > 0)
p += n;
else
if (n != -1) {
/* Write error / kernel bug! */
} else
if (errno != EINTR) {
/* Error! Details in errno */
}
}
}
Although there are some local filesystems that guarantee write() does not return a short count unless you run out of storage space, not all do; especially not the networked ones. Using a loop like above lets your program work even on such filesystems. It's not too much code to add for reliable and robust operation, in my opinion.
In Linux, you can take a write lease on a file to exclude any other process opening that file for a while.
Essentially, you cannot block a file open, but you can delay it for up to /proc/sys/fs/lease-break-time seconds, typically 45 seconds. The lease is granted only when no other process has the file open, and if any other process tries to open the file, the lease owner gets a signal. (If the lease owner does not release the lease, for example by closing the file, the kernel will automagically break the lease after the lease-break-time is up.)
Unfortunately, these only work in Linux, and only on local files, so they are of limited use.
If readers do not keep the file open, but open, read, and close it every time they read it, you can write a full replacement file (must be on the same filesystem; I recommend using a lock-subdirectory for this), and hard-link it over the old file.
All readers will see either the old file or the new file, but those that keep their file open, will never see any changes.

Can't open /dev/input/js file descriptor after inotify event

I'm creating a Linux module for a game library that let's you hotplug multiple joysticks, it uses inotify to watch /dev/input.
I am testing it with 3 joysticks:
First I connect 2 joysticks.
Then I start the application, the joysticks work and I don't get a error.
After that I connect the third joystick, perror gives: /dev/input/js1: Permission denied.
When I check ls -l /proc/<pid-of-process>/fd it lists /dev/input/js0 and /dev/input/js2.
All the joysticks work fine when I run it as root.
This is how it's initialized:
static void createGamepad(char *locName){
char dirName[30];
int fd;
snprintf(dirName, 30, "/dev/input/%s", locName);
fd = open(dirName, O_RDONLY | O_NONBLOCK, 0);
if(fd < 0){
perror(dirName);
}
}
struct dirent *dir;
DIR *d;
int i, notifyfd, watch;
// Attach notifications to check if a device connects/disconnects
notifyfd = inotify_init();
watch = inotify_add_watch(notifyfd, "/dev/input", IN_CREATE | IN_DELETE);
d = opendir("/dev/input");
i = 0;
while((dir = readdir(d)) != NULL){
if(*dir->d_name == 'j' && *(dir->d_name + 1) == 's'){
createGamepad(dir->d_name, i);
i++;
}
}
closedir(d);
After that inotify handles it like this in the while(1) loop:
static bool canReadINotify(){
fd_set set;
struct timeval timeout;
FD_ZERO(&set);
FD_SET(notifyfd, &set);
timeout.tv_sec = 0;
timeout.tv_usec = 0;
return select(notifyfd + 1, &set, NULL, NULL, &timeout) > 0 &&
FD_ISSET(notifyfd, &set);
}
// Inside the event loop
struct inotify_event ne;
while(canReadINotify()){
if(read(notifyfd, &ne, sizeof(struct inotify_event) + 16) >= 0){
if(*ne.name != 'j' || *(ne.name + 1) != 's'){
continue;
}
if(ne.mask & IN_CREATE){
createGamepad(ne.name);
}
}
}
Is it even possible with inotify or should I use udev? And if it's possible, how can I solve this?
It is very likely a race condition. You see, you get the inotify event when the device node is created (by udev using a mknod() call), but the access permissions are set by udev using a separate chown() call, just a tiny bit later.
See systemd src/udev/udev-node.c, node_permissions_apply(). In this particular case, /dev/input/jsX is not a symlink, but the actual device node; at least with systemd the device node access mode gets set sometime later, after the actual node is created.
One robust solution would be to modify your createGamepad() function, so that instead of failing completely at fd == -1 && errno == EACCES, you instead retry after a short while; at least a few times, say for up to a second or two.
However, ninjalj pointed out a better suggestion: use also the access permissions change as a trigger to check the device node. This is trivially accomplished, by using IN_CREATE | IN_DELETE | IN_ATTRIBUTE in the inotify_add_watch() function!
(You'll also want to ignore open()==-1, errno==EACCES errors in createGamepad(), as they are likely caused by this race condition, and the following IN_ATTRIBUTE inotify event will yield access to the same device.)
Prior to ninjalj's comment, I'd personally have used an array of input devices, and another for "possible" input devices that can/need to be retried after a short timeout to decide whether they are available or not, but I think his suggestion is much better.
Need/want an example?

Read/Write struct to fifo in C

I'm trying to pass structs between processes using named pipes. I got stuck at trying to open the pipe non-blocking mode. Here's my code for writing to the fifo:
void writeUpdate() {
// Create fifo for writing updates:
strcpy(fifo_write, routing_table->routerName);
// Check if fifo exists:
if(access(fifo_write, F_OK) == -1 )
fd_write = mkfifo(fifo_write, 0777);
else if(access(fifo_write, F_OK) == 0) {
printf("writeUpdate: FIFO %s already exists\n", fifo_write);
//fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK);
}
fd_write = open(fifo_write, O_WRONLY|O_NONBLOCK);
if(fd_write < 0)
perror("Create fifo error");
else {
int num_bytes = write(fd_write, routing_table, sizeof(routing_table));
if(num_bytes == 0)
printf("Nothing was written to FIFO %s\n", fifo_write);
printf("Wrote %d bytes. Sizeof struct: %d\n", num_bytes,sizeof(routing_table)+1);
}
close(fd_write);
}
routing_table is a pointer to my struct, it's allocated, so there's no prob with the name of the fifo or smth like that.
If I open the fifo without the O_NONBLOCK option, it writes smth for the first time, but then it blocks because I'm having troubles reading the struct too. And after the first time, the initial fifo is created, but other fifo's appear, named '.', '..'.
With O_NONBLOCK option set, it creates the fifo but always throws an error: 'No such device or address'. Any idea why this happens? Thanks.
EDIT: Ok, so I'm clear now about opening the fifo, but I have another problem, in fact reading/writing the struct to the fifo was my issue to start with. My code to read the struct:
void readUpdate() {
struct rttable *updateData;
allocate();
strcpy(fifo_read, routing_table->table[0].router);
// Check if fifo exists:
if(access(fifo_read, F_OK) == -1 )
fd_read = mkfifo(fifo_read, 777);
else if(access(fifo_read, F_OK) == 0) {
printf("ReadUpdate: FIFO %s already exists\n Reading from %s\n", fifo_read, fifo_read);
}
fd_read = open(fifo_read, O_RDONLY|O_NONBLOCK);
int num_bytes = read(fd_read, updateData, sizeof(updateData));
close(fd_read);
if(num_bytes > 0) {
if(updateData == NULL)
printf("Read data is null: yes");
else
printf("Read from fifo: %s %d\n", updateData->routerName, num_bytes);
int result = unlink(fifo_read);
if(result < 0)
perror("Unlink fifo error\n");
else {
printf("Unlinking successful for fifo %s\n", fifo_read);
printf("Updating table..\n");
//update(updateData);
print_table_update(updateData);
}
} else
printf("Nothing was read from FIFO %s\n", fifo_read);
}
It opens the fifo and tries to read, but it seems like nothing is in the fifo, although in writeUpdate the first time it says it wrote 4 bytes (this seems wrong too). At reading, first time around it prints 'a' and then num_bytes is always <=0.
I've looked around and only found this example, with simple write/read, is there smth more needed when writing a struct?
My struct looks like this:
typedef struct distance_table {
char dest[20]; //destination network
char router[20]; // via router..
int distance;
} distance_table;
typedef struct rttable {
char routerName[10];
char networkName[20];
struct distance_table table[50];
int nrRouters;
} rttable;
struct rttable *routing_table;
"No such device or address" is the ENXIO error message. If you look at the open man page, you'll see that this error is reported in particular if:
O_NONBLOCK | O_WRONLY is set, the named file is a FIFO and no process
has the file open for reading. (...)
which is exactly your situation. So the behavior you are seeing is normal: you can't write (without blocking) to a pipe that has no readers. The kernel won't buffer your messages if nothing is connected to the pipe for reading.
So make sure you start the "consumer(s)" before your "producer", or remove the non-blocking option on the producer.
BTW: using access is, in most circumstances, opening yourself to time of check to time of use issues. Don't use it. Try the mkfifo - if it works, you're good. If it fails with EEXISTS, you're good too. If it fails otherwise, clean up and bail out.
For the second part of your question, it really depends completely on how exactly the data you are trying to send is structured. Serializing a random struct in C is not easy at all, especially if it contains variable data (like char *s for example).
If you struct contains only primitive types (and no pointers), and both sides are on the same machine (and compiled with the same compiler), then a raw write on one side and read on the other of the whole struct should work.
You can look at C - Serialization techniques for more complex data types for example.
Concerning your specific example: you're getting mixed up between pointers to your structs and plain structs.
On the write side you have:
int num_bytes = write(fd_write, routing_table, sizeof(routing_table));
This is incorrect since routing_table is a pointer. You need:
int num_bytes = write(fd_write, routing_table, sizeof(*routing_table));
// or sizeof(struct rttable)
Same thing on the read side. On the receiving size you're also not allocating updateData as far as I can tell. You need to do that too (with malloc, and remember to free it).
struct rttable *updateData = malloc(sizeof(struct rrtable));

What is wrong with this _popen / select example?

UPDATE: i updated the code and problem description to reflect my changes.
I know now that i'm trying a Socket operation on nonsocket. or that my fd_set is not valid since:
select returns -1 and
WSAGetLastError()returns 10038.
But i can't seem to figure out what it is. Platform is Windows. I have not posted the WSAStartup part.
int loop = 0;
FILE *output
int main()
{
fd_set fd;
output = _popen("tail -f test.txt","r");
while(forceExit == 0)
{
FD_ZERO(&fd);
FD_SET(_fileno(output),&fd);
int returncode = select(_fileno(output)+1,&fd,NULL,NULL,NULL);
if(returncode == 0)
{
printf("timed out");
}
else if (returncode < 0)
{
printf("returncode: %d\n",returncode);
printf("Last Error: %d\n",WSAGetLastError());
}
else
{
if(FD_ISSET(_fileno(output),&fd))
{
if(fgets(buff, sizeof(buff), output) != NULL )
{
printf("Output: %s\n", buff);
}
}
else
{
printf(".");
}
}
Sleep(500);
}
return 0;
}
The new outcome now is of course the print out of the returncode and the last error.
You have some data ready to be read, but you are not actually reading anything. When you poll the descriptor next time, the data will still be there. Drain the pipe before you continue to poll.
As far as I can tell, Windows anonymous pipes cannot be used with non-blocking calls like select. So, while your _popen and select code looks good independently, you can't join the two together.
Here's a similar thread elsewhere.
It's possible that calling SetNamedPipeHandleState with the PIPE_NOWAIT flag might work for you, but MSDN is more than a little cryptic on the subject.
So, I think you need to look at other ways of achieving this. I'd suggest having the reading in a separate thread, and use normal blocking I/O.
First of all, as yourself and others have pointed out, select() is only valid for sockets under Windows. select() does not work on streams which is what _popen() returns. Error 10038 clearly identifies this.
I don't get what the purpose of your example is. If you simply want to spawn a process and collect it's stdout, just do this (which comes directly from the MSDN _popen page):
int main( void )
{
char psBuffer[128];
FILE *pPipe;
if( (pPipe = _popen("tail -f test.txt", "rt" )) == NULL )
exit( 1 );
/* Read pipe until end of file, or an error occurs. */
while(fgets(psBuffer, 128, pPipe))
{
printf(psBuffer);
}
/* Close pipe and print return value of pPipe. */
if (feof( pPipe))
{
printf( "\nProcess returned %d\n", _pclose( pPipe ) );
}
else
{
printf( "Error: Failed to read the pipe to the end.\n");
}
}
That's it. No select required.
And I'm not sure how threads will help you here, this will just complicate your problem.
The first thing that I notice is wrong is that you are calling FD_ISSET on your exceptfds in each conditional. I think that you want something like this:
if (FD_ISSET(filePointer,&fd))
{
printf("i have data\n");
}
else ....
The except field in the select is typically used to report errors or out-of-band data on a socket. When one of the descriptors of your exception is set, it doesn't mean an error necessarily, but rather some "message" (i.e. out-of-band data). I suspect that for your application, you can probably get by without putting your file descriptor inside of an exception set. If you truly want to check for errors, you need to be checking the return value of select and doing something if it returns -1 (or SOCKET_ERROR on Windows). I'm not sure of your platform so I can't be more specific about the return code.
select() first argument is the highest number file descriptor in your set, plus 1. (i.e. output+1)
select(output+1, &fd, NULL, &exceptfds, NULL);
The first FD_ISSET(...) should be on the fd_set fd.
if (FD_ISSET(filePointer, &fd))
Your data stream has data, then you need to read that data stream. Use fgets(...) or similar to read from the data source.
char buf[1024];
...
fgets(buf, sizeof(buf) * sizeof(char), output);
The first argument to select needs to be the highest-numbered file descriptor in any of the three sets, plus 1:
int select(int nfds, fd_set *readfds, fd_set *writefds,
fd_set *exceptfds, struct timeval *timeout);
Also:
if(FD_ISSET(filePointer,&exceptfds))
{
printf("i have data\n");
}
Should be:
if(FD_ISSET(filePointer,&fd))
{
printf("i have data\n");
}
You should check the return code from select().
You also need to reset the fdsets each time you call select().
You don't need timeout since you're not using it.
Edit:
Apparently on Windows, nfds is ignored, but should probably be set correctly, just so the code is more portable.
If you want to use a timeout, you need to pass it into the select call as the last argument:
// Reset fd, exceptfds, and timeout before each select()...
int result = select(maxFDPlusOne, &fd, NULL, &exceptfds, &timeout);
if (result == 0)
{
// timeout
}
else if (result < 0)
{
// error
}
else
{
// something happened
if (FD_ISSET(filePointer,&fd))
{
// Need to read the data, otherwise you'll get notified each time.
}
}
since select doesn't work i used threads, specifically _beginthread , _beginthreadex.

Resources