Read from a file that is continuously being updated - c

I am writing some C code to process some data in a file, but I just learned that the file is going to be constantly added to (about 1 time/second, maybe faster). So I'm wondering how do I keep reading from the file as its being added to. Then when I get to the end, wait until the next line is added and then process it. Then wait again and then process, and so on and so on. I have something like:
while(1){
fgets(line, sizeof(line), file);
while(line == NULL){
//wait ? then try to read again?
}
//tokenize line and do my stuff here
}
I thought I could maybe use inotify, but I am getting nowhere with that. Does anyone have any advice?

The most efficient way is using inotify, and the direct way is using the read() system call directly.
using inotify
The following code may give you some help, It works well on Debian 7.0, GCC 4.7:
/*This is the sample program to notify us for the file creation and file deletion takes place in “/tmp/test_inotify” file*/
// Modified from: http://www.thegeekstuff.com/2010/04/inotify-c-program-example/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/inotify.h>
#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
int main( )
{
int length, i = 0;
int fd;
int wd;
char buffer[EVENT_BUF_LEN];
/*creating the INOTIFY instance*/
fd = inotify_init();
/*checking for error*/
if ( fd < 0 ) {
perror( "inotify_init error" );
}
/* adding the “/tmp/test_inotify” test into watch list. Here,
* the suggestion is to validate the existence of the
* directory before adding into monitoring list.
*/
wd = inotify_add_watch( fd, "/tmp/test_inotify", IN_CREATE | IN_DELETE | IN_ACCESS | IN_MODIFY | IN_OPEN );
/* read to determine the event change happens on “/tmp/test_inotify” file.
* Actually this read blocks until the change event occurs
*/
length = read( fd, buffer, EVENT_BUF_LEN );
/* checking for error */
if ( length < 0 ) {
perror( "read" );
}
/* actually read return the list of change events happens.
* Here, read the change event one by one and process it accordingly.
*/
while ( i < length ) {
struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
if( event->len == 0) {
// For a single file watching, the event->name is empty, and event->len = 0
printf(" Single file watching event happened\n");
} else if ( event->len ) {
if ( event->mask & IN_CREATE ) {
if ( event->mask & IN_ISDIR ) {
printf( "New directory %s created.\n", event->name );
} else {
printf( "New file %s created.\n", event->name );
}
} else if ( event->mask & IN_DELETE ) {
if ( event->mask & IN_ISDIR ) {
printf( "Directory %s deleted.\n", event->name );
} else {
printf( "File %s deleted.\n", event->name );
}
} else if( event->mask & IN_ACCESS ) {
if ( event->mask & IN_ISDIR ) {
printf( "Directory %s accessed.\n", event->name );
} else {
printf(" File %s accessed. \n", event->name );
}
} else if( event->mask & IN_MODIFY ) {
if ( event->mask & IN_ISDIR ) {
printf( "Directory %s modified.\n", event->name );
} else {
printf(" File %s modified. \n", event->name );
}
} else if( event->mask & IN_OPEN ) {
if ( event->mask & IN_ISDIR ) {
printf( "Directory %s opened.\n", event->name );
} else {
printf(" File %s opened. \n", event->name );
}
} else {
printf( "Directory or File is accessed by other mode\n");
}
}
i += EVENT_SIZE + event->len;
}
/* removing the “/tmp/test_inotify” directory from the watch list. */
inotify_rm_watch( fd, wd );
/* closing the INOTIFY instance */
close( fd );
}
When runing the above program. You could test it by create a file or directoy named /tmp/test_inotify.
A detailed explanation could be found here
Use read system call
If a file is open, and have read to the end of current file size. the read() system call will return 0. And if some writer wrote N bytes to this file later, and then the read() will just return min(N, buffersize).
So it works correctly for your circumstance. Following is an examples of the code.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef int FD ;
int main() {
FD filed = open("/tmp/test_inotify", O_RDWR );
char buf[128];
if( !filed ) {
printf("Openfile error\n");
exit(-1);
}
int nbytes;
while(1) {
nbytes = read(filed, buf, 16);
printf("read %d bytes from file.\n", nbytes);
if(nbytes > 0) {
split_buffer_by_newline(buf); // split buffer by new line.
}
sleep(1);
}
return 0;
}
Reference
Thanks to Jonathan Leffler's Comment
http://www.thegeekstuff.com/2010/04/inotify-c-program-example/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int
main()
{
char ch;
FILE *fp;
long int nbytes_read = 0;
char str [128];
int j = 0;
int first_time = 1;
memset(str, '\0', 128);
fp = fopen("file.txt", "r");
while (1) {
if (first_time != 1) {
fp = fopen("file.txt", "r");
fseek(fp, nbytes_read, SEEK_SET);
sleep(10);
}
if (fp != NULL) {
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n') {
str[j++] = ch;
printf("%s", str);
memset(str, '\0', 128);
j = 0;
} else {
str[j++] = ch;
}
nbytes_read++;
}
//printf("%ld\n", nbytes_read);
first_time = 0;
}
fclose(fp);
}
return 0;
}

You can use select() with the fileno(file) as the file-descriptor. select will return either with a timeout (if you set a timeout) or when you can read from the file.

Using select can be a good choice but if you do not wish to use it, you can add a sleep for a small amount of milliseconds before reading value.

Related

How do I go about reading a text file (like a .log) that is constantly updated? Is this called a stream? [duplicate]

I am writing some C code to process some data in a file, but I just learned that the file is going to be constantly added to (about 1 time/second, maybe faster). So I'm wondering how do I keep reading from the file as its being added to. Then when I get to the end, wait until the next line is added and then process it. Then wait again and then process, and so on and so on. I have something like:
while(1){
fgets(line, sizeof(line), file);
while(line == NULL){
//wait ? then try to read again?
}
//tokenize line and do my stuff here
}
I thought I could maybe use inotify, but I am getting nowhere with that. Does anyone have any advice?
The most efficient way is using inotify, and the direct way is using the read() system call directly.
using inotify
The following code may give you some help, It works well on Debian 7.0, GCC 4.7:
/*This is the sample program to notify us for the file creation and file deletion takes place in “/tmp/test_inotify” file*/
// Modified from: http://www.thegeekstuff.com/2010/04/inotify-c-program-example/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/inotify.h>
#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
int main( )
{
int length, i = 0;
int fd;
int wd;
char buffer[EVENT_BUF_LEN];
/*creating the INOTIFY instance*/
fd = inotify_init();
/*checking for error*/
if ( fd < 0 ) {
perror( "inotify_init error" );
}
/* adding the “/tmp/test_inotify” test into watch list. Here,
* the suggestion is to validate the existence of the
* directory before adding into monitoring list.
*/
wd = inotify_add_watch( fd, "/tmp/test_inotify", IN_CREATE | IN_DELETE | IN_ACCESS | IN_MODIFY | IN_OPEN );
/* read to determine the event change happens on “/tmp/test_inotify” file.
* Actually this read blocks until the change event occurs
*/
length = read( fd, buffer, EVENT_BUF_LEN );
/* checking for error */
if ( length < 0 ) {
perror( "read" );
}
/* actually read return the list of change events happens.
* Here, read the change event one by one and process it accordingly.
*/
while ( i < length ) {
struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
if( event->len == 0) {
// For a single file watching, the event->name is empty, and event->len = 0
printf(" Single file watching event happened\n");
} else if ( event->len ) {
if ( event->mask & IN_CREATE ) {
if ( event->mask & IN_ISDIR ) {
printf( "New directory %s created.\n", event->name );
} else {
printf( "New file %s created.\n", event->name );
}
} else if ( event->mask & IN_DELETE ) {
if ( event->mask & IN_ISDIR ) {
printf( "Directory %s deleted.\n", event->name );
} else {
printf( "File %s deleted.\n", event->name );
}
} else if( event->mask & IN_ACCESS ) {
if ( event->mask & IN_ISDIR ) {
printf( "Directory %s accessed.\n", event->name );
} else {
printf(" File %s accessed. \n", event->name );
}
} else if( event->mask & IN_MODIFY ) {
if ( event->mask & IN_ISDIR ) {
printf( "Directory %s modified.\n", event->name );
} else {
printf(" File %s modified. \n", event->name );
}
} else if( event->mask & IN_OPEN ) {
if ( event->mask & IN_ISDIR ) {
printf( "Directory %s opened.\n", event->name );
} else {
printf(" File %s opened. \n", event->name );
}
} else {
printf( "Directory or File is accessed by other mode\n");
}
}
i += EVENT_SIZE + event->len;
}
/* removing the “/tmp/test_inotify” directory from the watch list. */
inotify_rm_watch( fd, wd );
/* closing the INOTIFY instance */
close( fd );
}
When runing the above program. You could test it by create a file or directoy named /tmp/test_inotify.
A detailed explanation could be found here
Use read system call
If a file is open, and have read to the end of current file size. the read() system call will return 0. And if some writer wrote N bytes to this file later, and then the read() will just return min(N, buffersize).
So it works correctly for your circumstance. Following is an examples of the code.
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
typedef int FD ;
int main() {
FD filed = open("/tmp/test_inotify", O_RDWR );
char buf[128];
if( !filed ) {
printf("Openfile error\n");
exit(-1);
}
int nbytes;
while(1) {
nbytes = read(filed, buf, 16);
printf("read %d bytes from file.\n", nbytes);
if(nbytes > 0) {
split_buffer_by_newline(buf); // split buffer by new line.
}
sleep(1);
}
return 0;
}
Reference
Thanks to Jonathan Leffler's Comment
http://www.thegeekstuff.com/2010/04/inotify-c-program-example/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int
main()
{
char ch;
FILE *fp;
long int nbytes_read = 0;
char str [128];
int j = 0;
int first_time = 1;
memset(str, '\0', 128);
fp = fopen("file.txt", "r");
while (1) {
if (first_time != 1) {
fp = fopen("file.txt", "r");
fseek(fp, nbytes_read, SEEK_SET);
sleep(10);
}
if (fp != NULL) {
while ((ch = fgetc(fp)) != EOF) {
if (ch == '\n') {
str[j++] = ch;
printf("%s", str);
memset(str, '\0', 128);
j = 0;
} else {
str[j++] = ch;
}
nbytes_read++;
}
//printf("%ld\n", nbytes_read);
first_time = 0;
}
fclose(fp);
}
return 0;
}
You can use select() with the fileno(file) as the file-descriptor. select will return either with a timeout (if you set a timeout) or when you can read from the file.
Using select can be a good choice but if you do not wish to use it, you can add a sleep for a small amount of milliseconds before reading value.

How to watch the directory with multiple files changes using inotify in c

I have a some 50 files which is moved to a directory "/tmp" on some interval of time when its get modified. I am using inotify to watch this directory /tmp for these files moved to this directory so that I can merge these files to another file in another directory.
But the rate at which the files getting moved to this directory ("/tmp"), inotify is not able to give notifications for other files except one file.
How to watch the directory if multiple files with different names (unknown names) being created or moved to the directory using inotify.
I know I can create multiple watch discriptors for each file with its name .
But I dont know the file name which is getting created or moved to this directory. Dynamically the files gets created so I cannot create watch descriptors for each file.
Below is my code.
How can I check notifications for the multiple files gettign created in this directory.
Please help with the solution.
Your help is highly appreciated.
Thanks
int main( int argc, char **argv )
{
int length, i = 0;
int fd;
int wd;
char buffer[BUF_LEN];
fd = inotify_init();
if ( fd < 0 ) {
perror( "inotify_init" );
}
wd = inotify_add_watch( fd, "/tmp/", IN_MOVED_TO);
while (1){
struct inotify_event *event;
length = read( fd, buffer, BUF_LEN );
if ( length < 0 ) {
perror( "read" );
}
event = ( struct inotify_event * ) &buffer[ i ];
if ( event->len ) {
if ( event->mask & IN_CREATE || IN_MOVED_TO) {
printf( "The file %s was created.\n", event->name );
}
}
}
( void ) inotify_rm_watch( fd, wd );
( void ) close( fd );
exit( 0 );
}
To monitor a directory for file creation or deletion, you can create an inotify instance and monitor with the flags IN_CREATE | IN_DELETE. To monitor a file or directory, you first create the inotify instance with inotify_init which will return a file descriptor. You can then add files/directories to monitor with inotify_add_watch and supply the proper flags to look for the desired changes. You can then simply use read which will block until changes meeting you criteria are detected.
A simple example to monitor a directory (given as input as the first argument [./tmp default]) is as follows:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/inotify.h>
#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
int dir_exists (char *d);
int main (int argc, char **argv)
{
int length, i = 0;
int fd;
int wd;
char buffer[EVENT_BUF_LEN];
char *path = argc > 1 ? argv[1] : "./tmp";
/* check directory to monitor exists */
if (!dir_exists (path)) {
fprintf (stderr, "error: directory does not exist '%s'.\n", path);
return 1;
}
/* create inotify instance & validate */
if ((fd = inotify_init ()) < 0) {
perror ("inotify_init");
}
/* add path to inotify watch list monitor for file create, delete.
add IN_MOVED_FROM | IN_MOVED_TO or move to/from directory */
wd = inotify_add_watch (fd, path, IN_CREATE | IN_DELETE);
/* monitor path for new file creation or deletion
(read blocks until the change event occurs) */
if ((length = read (fd, buffer, EVENT_BUF_LEN)) < 0) {
perror ("read");
}
/* report name of file created or deleted */
while (i < length) {
struct inotify_event *event = (struct inotify_event *) &buffer[i];
if (event->len) {
if (event->mask & IN_CREATE) {
if (event->mask & IN_ISDIR) {
printf ("New directory %s created.\n", event->name);
} else {
printf ("New file %s created.\n", event->name);
}
} else if (event->mask & IN_DELETE) {
if (event->mask & IN_ISDIR) {
printf ("Directory %s deleted.\n", event->name);
} else {
printf ("File %s deleted.\n", event->name);
}
}
}
i += EVENT_SIZE + event->len;
}
/* remove monitoring of path from the watch list. */
inotify_rm_watch (fd, wd);
/* close the inotify instance */
close (fd);
return 0;
}
/** test that directory exists (>=1 success, 0 otherwise)
* NOTE: no directory is actually created. fail occurs instead.
*/
int dir_exists (char *d)
{
int flags = O_DIRECTORY | O_RDONLY;
int mode = S_IRUSR | S_IWUSR;
int fd = open (d, flags, mode);
if (fd < 0) /* directory does not exist */
return 0;
else if (fd) { /* directory exists, rtn fd */
close (fd);
}
return fd;
}
Compile
gcc -Wall -Wextra -o bin/inotify_watch inotify_watch.c
Example Use
$ ./bin/inotify_watch &
[1] 16916
$ touch tmp/file.txt
New file file.txt created.
[1]+ Done ./bin/inotify_watch
Use functions FindFirstFile and FindNextFile. For example, show this code:
#include <windows.h>
#include <stdio.h>
#include <sys/stat.h>
#include <io.h>
/*
HANDLE FindFirstFile
(
LPCTSTR lpFileName, // какой файл ищем, можно указывать маску *, ?
LPWIN32_FIND_DATA lpFindFileData // указатель на структуру с информацией
);*/
//В случае ошибке вернет INVALID_HANDLE_VALUE. Для продолжения поиска используется функция:
/*
BOOL FindNextFile
(
HANDLE hFindFile, // указатель на поиск
LPWIN32_FIND_DATA lpFindFileData // указатель на структуру с информацией
);*/
//Write this any address
#define DISK "C:\\"
void main()
{
WIN32_FIND_DATA FindFileData;
HANDLE hf;
struct stat st;
hf=FindFirstFile(DISK"*", &FindFileData);
if (hf!=INVALID_HANDLE_VALUE)
{
do
{
char s[MAX_PATH] = DISK;
int a;
strcat(s, FindFileData.cFileName);
stat(s, &st);
a = access(s, 04);
printf("%s\t\t%s\n", FindFileData.cFileName, st.st_mode & S_IFDIR ? "Directory" : (st.st_mode & S_IFREG ? "File" : "Other"));
}
while (FindNextFile(hf,&FindFileData)!=0);
FindClose(hf);
}
getchar();
}

Does inotify really work for files or only for directories?

I am trying to use inotify for monitoring changes to a file /dev/hvc0 using the following:
#include <stdio.h>
#include <sys/inotify.h>
#include <stdlib.h>
#define EVENT_SIZE (sizeof(struct inotify_event))
#define BUF_LEN (1024 * (EVENT_SIZE + 16))
#define WATCH_FILE "/dev/hvc0" /* This file should be present
before this program is run */
int main() {
int notify_fd;
int length;
int i = 0;
char buffer[BUF_LEN];
notify_fd = inotify_init();
if (notify_fd < 0) {
perror("inotify_init");
}
int wd = inotify_add_watch(notify_fd, WATCH_FILE, IN_MODIFY | IN_ACCESS);
int length_read = read(notify_fd, buffer, BUF_LEN);
if (length_read) {
perror("read");
}
while (i < length_read) {
struct inotify_event *event =
(struct inotify_event *) &buffer[i];
if (event->len) {
if (event->mask & IN_ACCESS) {
printf("The file %s was accessed.\n", event->name);
} else if (event->mask & IN_MODIFY) {
printf("The file %s was modified.\n", event->name);
}
}
}
(void) inotify_rm_watch(notify_fd, wd);
(void) close(notify_fd);
return 0;
}
However, this does not print if the file was accessed/modified. However whenever I change the path to be monitored to a directory and a file was changed, it prints the correct event occurred.
Does inotify work for monitoring file changes too? Or am I doing something wrong?
Thanks!
You are missing to increase i . Add this before the end of the loop:
i += EVENT_SIZE + event->len;
If you want to monitor the changes you also need to wrap the read / print operation in an endless loop.
I am not understanding why the event->len is return zero may be because the file name is not returned. but for only testing purpose you just comment it. And in second point
Your handling of i is broken, you never reset it to 0 in the loop. This causes any later inotify events to be considered only when they are longer than the longest event before them, which is not likely what you want.And please in while loop please put i += EVENT_SIZE + event->len;
int main() {
int notify_fd;
int length;
int i = 0;
char buffer[BUF_LEN];
notify_fd = inotify_init();
if (notify_fd < 0) {
perror("inotify_init");
}
int wd = inotify_add_watch(notify_fd, WATCH_FILE, IN_MODIFY | IN_ACCESS);
while(1)
{
length = read( notify_fd, buffer, BUF_LEN );
if ( length < 0 ) {
perror( "read" );
}
while ( i < length )
{
struct inotify_event *event =
(struct inotify_event *) &buffer[i];
// if (event->len) {
if (event->mask & IN_ACCESS) {
printf("The file %s was accessed.\n", event->name);
} else if (event->mask & IN_MODIFY) {
printf("The file %s was modified.\n", event->name);
}
// }
i += EVENT_SIZE + event->len;
}
}
( void ) inotify_rm_watch( notify_fd, wd );
( void ) close( notify_fd);
exit( 0 );
}
Per this answer, it appears that Linux does not watch on specific files. If you were to listen to specific files, you should listen to its parent directory first.

How to listen to the change in dir or file?

I have code to listen change in directory,
When I run it writes nothing in the file neither shows in out out on terminal.
Can any one please help me out to listen the changes take place in particular text file? I want to store timestamp and what change took place.
Code is:
/*This is the sample program to notify us for the file creation and file deletion takes place in “/tmp” directory*/
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <linux/inotify.h>
#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
int main( )
{
int length, i = 0;
int fd;
int wd;
char buffer[EVENT_BUF_LEN];
char str[] = "This is tutorialspoint.com";
FILE* fp=NULL;;
fp=fopen("f1.txt","rw+");
/*creating the INOTIFY instance*/
fd = inotify_init();
/*checking for error*/
if ( fd < 0 ) {
perror( "inotify_init" );
}
/*adding the “/tmp” directory into watch list. Here, the suggestion is to validate the existence of the directory before adding into monitoring list.*/
wd = inotify_add_watch( fd, "/tmp", IN_CREATE | IN_DELETE );
/*read to determine the event change happens on “/tmp” directory. Actually this read blocks until the change event occurs*/
length = read(fd, buffer, EVENT_BUF_LEN );
/*checking for error*/
if ( length < 0 ) {
perror( "read" );
}
/*actually read return the list of change events happens. Here, read the change event one by one and process it accordingly.*/
while ( i < length ) { struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ]; if ( event->len ) {
if ( event->mask & IN_CREATE ) {
if ( event->mask & IN_ISDIR ) {
printf( "New directory %s created.1\n", event->name );
fwrite(str , 1 , sizeof(str) , fd );
}
else {
printf( "New file %s created.\n2", event->name );
fwrite(str , 1 , sizeof(str) , fd );
}
}
else if ( event->mask & IN_DELETE ) {
if ( event->mask & IN_ISDIR ) {
fwrite(str , 1 , sizeof(str) , fd );
printf( "Directory %s deleted.\n", event->name );
}
else {
printf( "File %s deleted.\n", event->name );
}
}
}
i += EVENT_SIZE + event->len;
}
/*removing the “/tmp” directory from the watch list.*/
inotify_rm_watch( fd, wd );
fclose(fd);
/*closing the INOTIFY instance*/
close( fd );
}
My guess is that it simply blocks on the read call. From the comment above it:
Actually this read blocks until the change event occurs
There simply isn't happening any of the events you're waiting for, and this read call will block until there is.
I suggest you run this program in one terminal, and in another do e.g.
$ touch /tmp/foo

inotify file in C

I am trying to run an example of inotify in C..but it's not working.
I want to monitor modifications to a file (the file is tmp.cfg), but it doesn't work..I don't know if i'm running it correctly, because I understand how to monitor directories, but not a single file
Here´s the example:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <unistd.h>
#define EVENT_SIZE ( sizeof (struct inotify_event) )
#define BUF_LEN ( 1024 * ( EVENT_SIZE + 16 ) )
int main( int argc, char **argv )
{
int length, i = 0;
int fd;
int wd;
char buffer[BUF_LEN];
fd = inotify_init();
if ( fd < 0 ) {
perror( "inotify_init" );
}
wd = inotify_add_watch( fd, "/home/name/tmp.cfg",
IN_MODIFY | IN_CREATE | IN_DELETE );
length = read( fd, buffer, BUF_LEN );
if ( length < 0 ) {
perror( "read" );
}
while ( i < length ) {
struct inotify_event *event = ( struct inotify_event * ) &buffer[ i ];
if ( event->mask & IN_CREATE ) {
printf( "The file %s was created.\n", event->name );
}
else if ( event->mask & IN_DELETE ) {
printf( "The file %s was deleted.\n", event->name );
}
else if ( event->mask & IN_MODIFY ) {
printf( "The file %s was modified.\n", event->name );
}
i += EVENT_SIZE + event->len;
}
( void ) inotify_rm_watch( fd, wd );
( void ) close( fd );
return 0;
}
Once i run it, if i write something on the file and then save it, nothing happens.
i've tryed debugging it..the problem seems to be the if ( event->mask & IN_MODIFY ), as it doesn't recognize it as a modification
You have 2 issues. First, as far as I can tell, inotify does not really work on files - it needs directory name to watch.
Second, you missed if (event->len) { inside while loop.
This code works for me for creating, deleting and modifying files in current directory:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <unistd.h>
#define EVENT_SIZE (sizeof(struct inotify_event))
#define BUF_LEN (1024 * (EVENT_SIZE + 16))
int main(int argc, char **argv) {
int length, i = 0;
int fd;
int wd;
char buffer[BUF_LEN];
fd = inotify_init();
if (fd < 0) {
perror("inotify_init");
}
wd = inotify_add_watch(fd, ".",
IN_MODIFY | IN_CREATE | IN_DELETE);
length = read(fd, buffer, BUF_LEN);
if (length < 0) {
perror("read");
}
while (i < length) {
struct inotify_event *event =
(struct inotify_event *) &buffer[i];
if (event->len) {
if (event->mask & IN_CREATE) {
printf("The file %s was created.\n", event->name);
} else if (event->mask & IN_DELETE) {
printf("The file %s was deleted.\n", event->name);
} else if (event->mask & IN_MODIFY) {
printf("The file %s was modified.\n", event->name);
}
}
i += EVENT_SIZE + event->len;
}
(void) inotify_rm_watch(fd, wd);
(void) close(fd);
return 0;
}
It doesn't work on a single file because, when we use a editor to modify file, the editor opens a copy of the file and when we save the edited version from the text editor, the existing file is deleted and a new file of the same name is created with the modifications.
When the old file is deleted, the watch created on that file becomes invalid and it is deleted automatically.
You can see the old file being replaced by the new file if you monitor the parent directory.
There are two ways to solve it, monitor the parent directory and print the message when modifications is done to the particular that you want to watch.
Else create a new watch on the file whenever modifications are made. When the old file is deleted, IN_DELETE_SELF event is triggered.
event->name will be non-empty only when you watch a directory, as it will contain the name of the file on which the event has occurred in the watched directory.
I think you're not using your user name, which is your home directory, and you're not checking the return of inotify_add_watch which probably fails:
"/home/name/tmp.cfg"
Edit: okay second problem, you shouldn't print name because
The name field is only present when an event is returned for a file
inside a watched directory;
Edit2: third problem, the file must exist before you run the program because you add a watch on the file, I suggest you check the error from inotify_add_watch
In watching a file, if the file is manipulated by an editor which you might do to edit it and create a change, it is likely to be doing some operations that results in the original file you asked to watch being deleted. Hence the notifications will stop if you only watch the one file.

Resources