Here I have a code under Linux, which should monitor changes in directories or files. This is called watchfulness. On this code I have two questions

1) How to exit the program? Here we use an infinite loop

while(1) 

while the user is not able to complete the process. There is only CTRL + C, but the text from the buffer does not fit into the log. Therefore, I added a function

 fflush(fp_log); 

which pushes the text from the buffer to the file. But in short, it is ugly. How to provide an exit from a cycle? I tried getch or getchar but I get errors.

2) When I create a directory or change a file, the message is displayed in the terminal, but when I delete a file or folder, or rename it, it is not displayed. How to make to output? Add another mask? Which one?

  /* Inotify ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠ΅Ρ‚ΡΡ для наблюдСния Π·Π° поддирСкториями Π²Ρ‹Π±Ρ€Π°Π½Π½ΠΎΠΉ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ*/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #include <sys/types.h> #include <sys/inotify.h> #include <dirent.h> #include <limits.h> #define MAX_LEN 1024 /*Π΄Π»ΠΈΠ½Π° ΠΏΡƒΡ‚ΠΈ для Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ*/ #define MAX_EVENTS 1024 /*максимальноС количСство событий для ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚ΠΊΠΈ Π·Π° ΠΎΠ΄ΠΈΠ½ Ρ€Π°Π·*/ #define LEN_NAME 16 /*ΠΏΡ€Π΅Π΄ΠΏΠΎΠ»ΠΎΠΆΠΈΠΌ, Ρ‡Ρ‚ΠΎ Π΄Π»ΠΈΠ½Π° ΠΈΠΌΠ΅Π½ΠΈ Ρ„Π°ΠΉΠ»Π° Π½Π΅ ΠΏΡ€Π΅Π²Ρ‹ΡˆΠ°Π΅Ρ‚ 16 Π±Π°ΠΉΡ‚*/ #define EVENT_SIZE ( sizeof (struct inotify_event) ) /*Ρ€Π°Π·ΠΌΠ΅Ρ€ структуры события*/ #define BUF_LEN ( MAX_EVENTS * ( EVENT_SIZE + LEN_NAME )) /*Π±ΡƒΡ„Π΅Ρ€ для хранСния Π΄Π°Π½Π½Ρ‹Ρ… события*/ /* Π€Π°ΠΉΠ» ΠΆΡƒΡ€Π½Π°Π»Π°*/ FILE *fp_log; /* Π”ΠΎΠ±Π°Π²ΠΈΠΌ наблюдСния inotify для ΠΏΠΎΠ΄Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΉ сразу послС добавлСния ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΉ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ */ void add_watches(int fd, char *root) { int wd; char *abs_dir; DIR *dp; dp = opendir(root); if (dp == NULL) { perror("Error opening the starting directory"); exit(0); } /* Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ наблюдСния для ΠΊΠΎΡ€Π½Π΅Π²ΠΎΠΉ Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΈ */ wd = inotify_add_watch(fd, root, IN_CREATE | IN_MODIFY | IN_DELETE); if (wd == -1) { fprintf(fp_log,"Couldn't add watch to %s\n",root); } else { printf("Watching:: %s\n",root); } closedir(dp); } /* Ѐункция main*/ int main( int argc, char **argv ) { int length, i = 0; int fd; char buffer[BUF_LEN], root[MAX_LEN]; char s; /*ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΊΠ° наличия ΠΏΠ°Ρ€Π°ΠΌΠ΅Ρ‚Ρ€Π° ΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΎΠΉ строки*/ switch(argc) { case 1: printf("No directory specified. Will monitor the entire filesystem...\n\n"); strcpy(root,"/"); break; case 2: strcpy(root,argv[1]); if(root[strlen(root)-1]!='/') strcat(root,"/"); puts(root); break; default: printf("Ignoring all other arguments after the first\n"); } /* ΠžΡ‚ΠΊΡ€Ρ‹Ρ‚ΠΈΠ΅ Ρ„Π°ΠΉΠ»Π° ΠΆΡƒΡ€Π½Π°Π»Π°*/ fp_log = fopen("asasas111.log","w+"); if (fp_log == NULL) { printf("Error opening logger. All output will be redirected to the stdout\n"); } fd = inotify_init(); if ( fd < 0 ) { perror( "Couldn't initialize inotify"); } /* ΠΎΠ±Ρ…ΠΎΠ΄ ΠΏΠΎΠ΄Π΄ΠΈΡ€Π΅ΠΊΡ‚ΠΎΡ€ΠΈΠΉ ΠΏΠ΅Ρ€Π²ΠΎΠ³ΠΎ уровня ΠΈ Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ наблюдСний */ add_watches(fd,root); /* бСсконСчный Ρ†ΠΈΠΊΠ»*/ while(1) { i = 0; 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) { if (event->mask & IN_ISDIR) { fprintf(fp_log,"%d DIR::%s CREATED\n", event->wd,event->name ); fflush(fp_log); printf("%d DIR::%s CREATED\n", event->wd,event->name ); } else { fprintf(fp_log, "%d FILE::%s CREATED\n", event->wd, event->name); fflush(fp_log); printf("%d FILE::%s CREATED\n", event->wd,event->name ); } } if ( event->mask & IN_MODIFY) { if (event->mask & IN_ISDIR) { fprintf(fp_log,"%d DIR::%s MODIFIED\n", event->wd,event->name ); fflush(fp_log); printf("%d DIR::%s MODIFIED\n", event->wd,event->name ); } else { fprintf(fp_log,"%d FILE::%s MODIFIED\n", event->wd,event->name ); printf("%d FILE::%s MODIFIED\n", event->wd,event->name ); } } if ( event->mask & IN_DELETE) { if (event->mask & IN_ISDIR) { fprintf(fp_log,"%d DIR::%s DELETED\n", event->wd,event->name ); fflush(fp_log); printf("%d DIR::%s DELETED\n", event->wd,event->name ); } else { fprintf(fp_log,"%d FILE::%s DELETED\n", event->wd,event->name ); fflush(fp_log); printf("%d FILE::%s DELETED\n", event->wd,event->name ); } } i += EVENT_SIZE + event->len; } } } /* освобоТдСниС рСсурсов*/ ( void ) close( fd ); return 0; } 
  • "I tried getch or getchar but I get errors." what kind of mistakes? Your question would be divided into two in a good way ... - Vladimir Martyanov

3 answers 3

How to exit the program?

So the same CTRL + C. You just need to catch signals. Here is a blank to demonstrate the approach:

 #include <signal.h> #include <stdlib.h> #include <unistd.h> #include <stdio.h> static int terminate = 0; static void signal_handler(int signo) { switch (signo) { case SIGINT: case SIGTERM: case SIGTSTP: /* Π½Π΅ ΠΏΠΎΠΌΠ΅ΡˆΠ°Π΅Ρ‚ ΠΏΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ: */ if (!terminate) { terminate = 1; /* Π·Π°Π²Π΅Ρ€ΡˆΠ°Π΅ΠΌ Π½Π°Ρ‡Π°Ρ‚ΠΎΠ΅ ΠΈ Π²Ρ‹Ρ…ΠΎΠ΄ΠΈΠΌ: */ printf("Got signal %u, bye!\n", signo); /* * fclose(fp_log); * close(fd); * ΠΈ Ρ‚.Π΄. */ exit(EXIT_SUCCESS); } break; default: break; } } int main() { /* Ctrl+C: */ signal(SIGINT, signal_handler); /* Ctrl+Z, Ссли Π½Π°Π΄ΠΎ: */ signal(SIGTSTP, signal_handler); signal(SIGTERM, signal_handler); while (1) { if (!terminate) { /* Ρ‡Ρ‚ΠΎ-Ρ‚ΠΎ Π΄Π΅Π»Π°Π΅ΠΌ: */ puts("do something..."); /* просто для ΠΈΠΌΠΈΡ‚Π°Ρ†ΠΈΠΈ Π΄Π΅ΡΡ‚Π΅Π»ΡŒΠ½ΠΎΡΡ‚ΠΈ: */ sleep(10); } } /* * Π° Π²ΠΎΡ‚ сюда ΠΌΡ‹ Π½ΠΈΠΊΠΎΠ³Π΄Π° ΠΏΠΎΠΏΠ°ΡΡ‚ΡŒ Π½Π΅ Π΄ΠΎΠ»ΠΆΠ½Ρ‹, Π½ΠΎ Π½Π° всякий случай * Π²Π΅Ρ€Π½Ρ‘ΠΌ ΠΎΡˆΠΈΠ±ΠΊΡƒ для ΠΈΠ½Π΄ΠΈΠΊΠ°Ρ†ΠΈΠΈ этого Π²ΠΎΠΏΠΈΡŽΡ‰Π΅Π³ΠΎ нСдоразумСния: */ return EXIT_FAILURE; } 

    For the correct completion of the program, you can offer a couple of options.

    Option 1 - create a named pipe and interrogate it periodically in the program, and when a program needs to be completed, a keyword is written to the channel and the program ends.

    Option 2 - in the program to make functions a signal handler and send these signals to the program.

      As far as I remember, you can also exit the loop through break . Although I did not use it myself - it was not necessary. And then after the cycle to exit the program, after writing down the logs and closing them.