How to monitor the data in both source and destination folders? - c

I'm working on the file monitoring system project in which, first all the data will be copied to the destination folder then it should monitor the data in both source and destination folders. But unfortunately, it is just monitoring the data from the source folder.
I divided the inotify function into two parts because I used inotifyFunc1 to help me in copying the folders first. And once the data is copied then I used inotifyFunc2 to monitor the data in both folders. But as I said it is just monitoring the first source folder.
This code is big but I don't know how to make it understand in a short way.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/inotify.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <unistd.h>
#define STRING_LEN 200
#define MAX_EVENTS 1024
#define NAME_LEN 16
#define EVENT_SIZE (sizeof(struct inotify_event))
#define BUFFER_LEN (MAX_EVENTS * (EVENT_SIZE + NAME_LEN))
typedef struct{
int fd, wd, result, length;
uint32_t mask[2];
char path1[STRING_LEN], path2[STRING_LEN], cmd[STRING_LEN], option, buffer[BUFFER_LEN];
} monitoring;
monitoring monitor;
void sig_handler(int signal){
printf("\nThe program is closed\n");
inotify_rm_watch(monitor.fd, monitor.wd);
close(monitor.fd);
exit(0);
}
void inotifyFunc1(char *path1, uint32_t *maskPtr1){
monitor.fd = inotify_init();
if(fcntl(monitor.fd, F_SETFL, O_NONBLOCK)){
perror("inotify not initialized: ");
exit(0);
}
monitor.wd = inotify_add_watch(monitor.fd, path1, *maskPtr1);
if(monitor.wd < 0){
perror("Sorry");
exit(1);
}
}
void inotifyFunc2(char *path2, uint32_t *maskPtr2)
{
while(1)
{
int i = 0;
monitor.length = read(monitor.fd, monitor.buffer, BUFFER_LEN);
while(i<monitor.length){
struct inotify_event *event = (struct inotify_event *)&monitor.buffer[i];
if(event->len){
if(event->mask & *maskPtr2){
if(event->mask & IN_ISDIR){
printf("Directory is created\n");
break;
}
else{
printf("File is created\n");
break;
}
}
}
}
}
}
void monitoringSystem(char *pathname1, char *pathname2)
{
/* Closing inotify */
signal(SIGINT,sig_handler);
do
{
printf("Choose the source path: ");
scanf("%s", pathname1);
monitor.mask[0] = ENOENT;
inotifyFunc1(pathname1, &monitor.mask[0]);
printf("Choose the destination path: ");
scanf("%s", pathname2);
inotifyFunc1(pathname2, &monitor.mask[0]);
monitor.result = strcmp(pathname1, pathname2);
if(monitor.result == 0){
printf("Error: Both locations are the same\n");
exit(3);
}
else{
sprintf(monitor.cmd, "cp -r %s %s", pathname1, pathname2);
system(monitor.cmd);
printf("Data is copied from source to destination\n");
}
printf("\nBoth locations are being monitored\n");
monitor.mask[1] = IN_CREATE;
inotifyFunc1(pathname1, &monitor.mask[1]);
inotifyFunc2(pathname1, &monitor.mask[1]);
inotifyFunc1(pathname2, &monitor.mask[1]);
inotifyFunc2(pathname2, &monitor.mask[1]);
printf("Do you want to give location again? [y/n]: ");
scanf("%s", &monitor.option);
} while(monitor.option == 'y');
}
int main(int argc, char *argv[])
{
printf("DATA RECOVERY SYSTEM\n");
printf("WELCOME TO THE MAIN MENU\n\n");
monitoringSystem(monitor.path1, monitor.path2);
return 0;
}

void inotifyFunc1(char *path1, uint32_t *maskPtr1){
monitor.fd = inotify_init();
Your inotifyFunc1 function creates a brand new inotify instance and stores its handle in monitor.fd.
inotifyFunc1(pathname1, &monitor.mask[0]);
printf("Choose the destination path: ");
scanf("%s", pathname2);
inotifyFunc1(pathname2, &monitor.mask[0]);
But you call it twice. The second time, it again creates a new inotify instance and stores its handle in monitor.fd, leaking the old handle.
If you only want one inotify instance to watch more than one thing, you need to create only one inotify instance.
inotifyFunc1(pathname1, &monitor.mask[1]);
inotifyFunc2(pathname1, &monitor.mask[1]);
This also doesn't make sense. Why are you calling inotifyFunc1 again? If you thought it was already monitoring both locations, what do you think this accomplishes? If you didn't think it was already monitoring both locations, why is this after you say it is?
It's hard to explain what incorrect reasoning led you to call those functions because there are no comments in the code. But it makes no sense.
You want to:
Create only one inotify instance.
Add each location to it only once.

Related

Filter repetitive inotify events about the same file in C

I'm developing a basic dropbox program. Very simple. I'm kinda stuck with the inotify thing. I need events that notifies about file creation, modification and deletion. I also need to filter out temporary files. I assume I need to be careful to not filter out truthful events, like if a user modifies the same file two or more times in a row.
If a modify a simple text file, I get three separate events: IN_CLOSE_WRITE test.c, IN_MOVED_TO test.c and IN_CLOSE_WRITE test.c. My expected result would be a single notify event about this file. Either one it's fine. All of them sends the same signal to server, to upload the file.
If I copy a file 'test.c': IN_CREATE test (copy).c and IN_CLOSE_WRITE test (copy).c. See the example above for the expected result.
Here's my code so far.
#include <stdio.h>
#include <sys/inotify.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#define EVENT_BUF_LEN 4096
#define EVENT_SIZE sizeof(struct inotify_event)
typedef struct
{
int length, fd, wd;
char buffer[EVENT_BUF_LEN] __attribute__((aligned(__alignof__(struct inotify_event))));
} notification;
notification inotify;
void getNotified(char *pathname)
{
char command[256];
notification inotify;
inotify.fd = inotify_init();
inotify.wd = inotify_add_watch(inotify.fd, pathname, IN_CLOSE_WRITE | IN_CREATE | IN_MOVED_TO | IN_MOVED_FROM);
while (1)
{
inotify.length = read(inotify.fd, inotify.buffer, EVENT_BUF_LEN);
int i = 0;
while (i < inotify.length)
{
struct inotify_event *event = (struct inotify_event *)&inotify.buffer[i];
// Filtering out temporary files.
if (strstr(event->name, ".gout") != NULL)
{
i += (EVENT_SIZE + event->len);
continue;
}
if (event->mask & IN_CLOSE_WRITE)
strcpy(command, "IN_CLOSE_WRITE ");
else if (event->mask & IN_CREATE)
strcpy(command, "IN_CREATE ");
else if (event->mask & IN_MOVED_FROM)
strcpy(command, "IN_MOVED_FROM ");
else if (event->mask & IN_MOVED_TO)
strcpy(command, "IN_MOVED_TO ");
strcat(command, event->name);
printf("%s\n", command);
i += (EVENT_SIZE + event->len);
}
}
inotify_rm_watch(inotify.fd, inotify.wd);
close(inotify.fd);
}
int main(void)
{
getNotified(".");
return 0;
}

How to make synchronism between two distinct C programs?

First of all, I don't know if I can explain well my problem or you can get it in the appropriate way. But I will try to make it clear for you.
In fact, I have two different C programs.
The first one is a simple loop print of a message on the console :
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main ()
{
while(1)
{
printf("WAITING\n");
sleep(1);
}
}
The second one is a blocking program that waits for an event ( press button ) to turn on led in my embedded board.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <errno.h>
#include <linux/input.h>
#define BTN_FILE_PATH "/dev/input/event0"
#define LED_PATH "/sys/class/leds"
#define green "green"
void change_led_state(char *led_path, int led_value)
{
char lpath[64];
FILE *led_fd;
strncpy(lpath, led_path, sizeof(lpath) - 1);
lpath[sizeof(lpath) - 1] = '\0';
led_fd = fopen(lpath, "w");
if (led_fd == NULL) {
fprintf(stderr, "simplekey: unable to access led\n");
return;
}
fprintf(led_fd, "%d\n", led_value);
fclose(led_fd);
}
void reset_leds(void)
{
change_led_state(LED_PATH "/" green "/brightness", 0);
}
int configure_leds(void)
{
FILE *l_fd;
FILE *r_fd;
char *none_str = "none";
/* Configure leds for hand control */
r_fd = fopen(LED_PATH "/" green "/trigger", "w");
fprintf(r_fd, "%s\n", none_str);
fclose(r_fd);
/* Switch off leds */
reset_leds();
return 0;
}
void eval_keycode(int code)
{
static int green_state = 0;
switch (code) {
case 260:
printf("BTN left pressed\n");
/* figure out red state */
green_state = green_state ? 0 : 1;
change_led_state(LED_PATH "/" green "/brightness", green_state);
break;
}
}
int main(void)
{
int file;
/* how many bytes were read */
size_t rb;
int ret;
int yalv;
/* the events (up to 64 at once) */
struct input_event ev[64];
char *str = BTN_FILE_PATH;
printf("Starting simplekey app\n");
ret = configure_leds();
if (ret < 0)
exit(1);
printf("File Path: %s\n", str);
if((file = open(str, O_RDONLY)) < 0) {
perror("simplekey: File can not open");
exit(1);
}
for (;;) {
/* Blocking read */
rb= read(file, &ev, sizeof(ev));
if (rb < (int) sizeof(struct input_event)) {
perror("simplekey: short read");
exit(1);
}
for (yalv = 0;
yalv < (int) (rb / sizeof(struct input_event));
yalv++) {
if (ev[yalv].type == EV_KEY) {
printf("%ld.%06ld ",
ev[yalv].time.tv_sec,
ev[yalv].time.tv_usec);
printf("type %d code %d value %d\n",
ev[yalv].type,
ev[yalv].code, ev[yalv].value);
/* Change state on button pressed */
if (ev[yalv].value == 0)
eval_keycode(ev[yalv].code);
}
}
}
close(file);
reset_leds();
exit(0);
}
When I execute the second code, the program starts waiting for the event to switch on/off the led.
My question is :
How can I make interaction between the two programs ? I want to execute the firs one --> It starts printing for me " WAITING " until I press the BUTTON --> the LED turn on --> and then it goes back to the first program and re-start printing " WAITING " on the console.
I don't know if I explained well the issue but I hope that you can help me! Thank you.
You need a communication mechanism between your two programs. This is also known als inter-process communication.
Generally, you have several options to achieve this (depending on the operating system you are using, not all of them may be available):
Shared memory / shared files
Message passing (e.g. via sockets)
Pipes
Signals
A helpful introduction can be found here.

how to print name of newly created file(s) within a directory in C?

This code scans for newly created files within a directory, however where "%s" should contain the name of the new file(s) this does not occur.
I can imagine there are unnecessary pieces of code written here, however being quite unfamiliar with C I'm simply happy it compiles at this point (and actually recognizes new files) !
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/inotify.h>
int main (int argc, char *argv[])
{
char target[FILENAME_MAX];
int result;
int fd;
int wd; /* watch descriptor */
const int event_size = sizeof(struct inotify_event);
const int buf_len = 1024 * (event_size + FILENAME_MAX);
fd = inotify_init();
if (fd < 0) {
perror("inotify_init");
}
wd = inotify_add_watch(fd, "/home/joe/Documents", IN_CREATE);
while (1) {
char buff[buf_len];
int no_of_events, count = 0;
no_of_events = read (fd, buff, buf_len);
while (count < no_of_events) {
struct inotify_event *event = (struct inotify_event *)&buff[count];
if (event->len) {
if (event->mask & IN_CREATE)
if(!(event->mask & IN_ISDIR)) {
printf("The file %s has been created\n", target);
fflush(stdout);
}
}
count += event_size + event->len;
}
}
return 0;
}
You're printing out target when you get an event, however target is never modified.
The name of the created file is stored in event->name. That's what you want to print.
printf("The file %s has been created\n", event->name);

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.

Polling interface names via SIOCGIFCONF in Linux

I'm attempting to poll networking device names. I've pieced this together from various snippets,
http://unixhelp.ed.ac.uk/CGI/man-cgi?netdevice+7
http://lists.apple.com/archives/Unix-porting/2002/Apr/msg00134.html
http://ubuntuforums.org/showthread.php?t=1421487
But my output is just gibberish.
#include <stdio.h>
#include <stdlib.h>
#include <net/route.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#define BUFLEN 1024
#define SEQ 9999
int main (int argc, const char* argv[])
{
// File descriptor for socket
int socketfd;
struct ifconf conf;
struct ifreq req[10];
struct ifreq *ifr;
printf("Opening socket...");
socketfd = socket(AF_ROUTE, SOCK_RAW, 0);
if (socketfd >= 0) {
printf(" OK\n");
conf.ifc_len = sizeof(req);
conf.ifc_buf = (__caddr_t) req;
ioctl(socketfd,SIOCGIFCONF,&conf);
printf("Discovering interfaces...\n");
int i;
for (i=0; i<conf.ifc_len/sizeof(req[0]); i++) {
ifr = &conf.ifc_req[i];
printf("%d. %s\n", i+1, req[i].ifr_name);
}
}
else {
printf("Failed!\n");
}
return 0;
}
Output:
Opening socket... OK
Discovering interfaces...
?u???}??Gh???
2. p?9}?
3.
4. v?=?n??u?`?y??]g?<?~?v??
5.
6.
7.
8. ?v?T?
9. ?|?mw??j??v??h??|??v?T00~??v?$?|??|?#
10. T00~??v?$?|??|?#
I tried outputting each char of the ifr_name array one-by-one to see if they were null terminated but that didn't change much. Each iteration of my program outputs something different so this leads me to think I'm referencing something wrong. Can someone provide me some insight as to what I may be doing wrong?
Here's some code I put together for Mac OS X:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <arpa/inet.h>
#include <netinet/in.h>
/* This is defined on Mac OS X */
#ifndef _SIZEOF_ADDR_IFREQ
#define _SIZEOF_ADDR_IFREQ sizeof
#endif
int main (int argc, const char* argv[])
{
// File descriptor for socket
int socketfd;
struct ifconf conf;
char data[4096];
struct ifreq *ifr;
char addrbuf[1024];
int i;
printf("Opening socket...");
socketfd = socket(AF_INET, SOCK_DGRAM, 0);
if (socketfd >= 0) {
printf(" OK\n");
conf.ifc_len = sizeof(data);
conf.ifc_buf = (caddr_t) data;
if (ioctl(socketfd,SIOCGIFCONF,&conf) < 0) {
perror("ioctl");
}
printf("Discovering interfaces...\n");
i = 0;
ifr = (struct ifreq*)data;
while ((char*)ifr < data+conf.ifc_len) {
switch (ifr->ifr_addr.sa_family) {
case AF_INET:
++i;
printf("%d. %s : %s\n", i, ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in*)&ifr->ifr_addr)->sin_addr, addrbuf, sizeof(addrbuf)));
break;
#if 0
case AF_INET6:
++i;
printf("%d. %s : %s\n", i, ifr->ifr_name, inet_ntop(ifr->ifr_addr.sa_family, &((struct sockaddr_in6*)&ifr->ifr_addr)->sin6_addr, addrbuf, sizeof(addrbuf)));
break;
#endif
}
ifr = (struct ifreq*)((char*)ifr +_SIZEOF_ADDR_IFREQ(*ifr));
}
close(socketfd);
}
else {
printf(" Failed!\n");
}
return 0;
}
Poll as in you want to be notified if an interface is added or removed? Or polled as in you just want to find out the interface names once from the system? If the latter, take a look at getifaddrs().
Please see http://git.netfilter.org/cgi-bin/gitweb.cgi?p=libmnl.git;a=blob;f=examples/rtnl/rtnl-link-dump.c;hb=HEAD on how to get the list of interfaces on Linux. AF_ROUTE is some BSD thing and the use of ioctl is discouraged on Linux for its apparent limitations (such as to convey multiple addresses on a single interface).

Resources