Как проверить, является ли файл исполняемым, используя ANSI C?

Я пытаюсь написать программу, которая проверяет файлы в каталоге. Когда создается новый файл, я должен проверить, является ли он исполняемым, и если это так, я должен его выполнить.

Я использую интерфейс inotify, и он работает хорошо, но у меня возникают проблемы, когда я пытаюсь проверить, является ли файл исполняемым, используя stat(2). Я обнаружил, что у меня нет разрешения на его выполнение.

Создает ли передача программе абсолютный путь к каталогу, который я хочу проверить, проблемы с разрешениями?

int main(int argc,char * argv []){

int fd,wd,len,i=0;
char buffer [EVENT_SIZE_BUF];

if(argc != 2)
    usage();

if((fd = inotify_init()) == -1)
    perror("inotify_init()");   


if((wd = inotify_add_watch(fd,argv[1],IN_CREATE) -1))
    perror("inotify_add_watch()");

while(1){


    if((len = read(fd,buffer,EVENT_SIZE_BUF)) < 0)
        perror("read()");

    struct inotify_event * ev = (struct inotify_event *)&buffer;

    if(ev->len > 0){

        if(ev->mask & IN_CREATE && ((ev-> mask & IN_ISDIR) == 0x00)){

            printf("SPY; new file is created %s\n",ev->name);

            char * path = strcat(argv[1],ev->name);
            printf("%s\n",path);

            struct stat sb;

            if(!stat(path,&sb)){

                printf( (S_ISDIR(sb.st_mode)) ? "d" : "-");
                printf( (sb.st_mode & S_IRUSR) ? "r" : "-");
                printf( (sb.st_mode & S_IWUSR) ? "w" : "-");
                printf( (sb.st_mode & S_IXUSR) ? "x" : "-");
                printf( (sb.st_mode & S_IRGRP) ? "r" : "-");
                printf( (sb.st_mode & S_IWGRP) ? "w" : "-");
                printf( (sb.st_mode & S_IXGRP) ? "x" : "-");
                printf( (sb.st_mode & S_IROTH) ? "r" : "-");
                printf( (sb.st_mode & S_IWOTH) ? "w" : "-");
                printf( (sb.st_mode & S_IXOTH) ? "x" : "-");
                fflush(stdout);
                printf("\n");
            }




        }else{ printf("dir\n"); }
    }               
}

inotify_rm_watch(fd,wd);
close(fd);
return 0;
}

person dirtybloom    schedule 16.04.2013    source источник
comment
Я отредактировал вопрос, чтобы попытаться сделать его немного яснее. Не стесняйтесь откатывать/редактировать его, если я сделал неправильные изменения/что-то забыл.   -  person Hydronium    schedule 16.04.2013


Ответы (3)


Вы используете Linux, поэтому можете использовать функцию access().

if (access("/my/file", X_OK) != -1) {
    printf("execution permission enabled\n");
} else {
    printf("execution permission disabled\n");
}
person MOHAMED    schedule 16.04.2013
comment
Спасибо за ответ. Я тоже пытался получить доступ, но вы уверены, что если он возвращает -1, это означает, что файл не является исполняемым? потому что справочная страница Linux говорит, что она возвращает -1 в случае ошибки - person dirtybloom; 16.04.2013
comment
ах хорошо да, но он всегда говорит, что у меня нет разрешений. но у меня есть разрешение на выполнение обоих файлов - person dirtybloom; 16.04.2013
comment
проверьте свой файл, у него не должно быть разрешения на выполнение - person MOHAMED; 16.04.2013
comment
Готово. у меня есть разрешение на оба файла, проверено статистикой из оболочки - person dirtybloom; 16.04.2013
comment
Обратите внимание, что в случае обычной (не setuid, не setgid) программы access() дает ответ, который вы хотите, но проверка, которую она выполняет, заключается в том, имеет ли реальный UID или реальный GID (или один из дополнительных идентификаторов группы) соответствующий доступ, а не эффективный UID или эффективный GID, но именно эффективный UID и эффективный GID (плюс дополнительные идентификаторы группы) будут фактически контролировать доступ. Таким образом, вы можете получить неправильный ответ, если программа запускается с SUID или SGID. По общему признанию, это придирки к деталям, но они имеют значение... иногда. - person Jonathan Leffler; 26.05.2013

Вы решаете упражнения Ренцо Даволи? :)

Однако я застрял, как и вы, и обнаружил, что копирование исполняемого файла с помощью Nautilus создает «Исполняемый файл (копирование)», который возвращает ошибку X-Permission с stat() или access().

Копирование с помощью cp cp exe1 exe2 работает!!

Это мой код:

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <sys/stat.h>

#define _GNU_SOURCE 
#define EVENT_SIZE  ( sizeof (struct inotify_event) )
#define EVENT_BUF_LEN     ( 1024 * ( EVENT_SIZE + 16 ) )

void main(int argc, char **argv){

int fd, wd, length, i=0;
char buffer[EVENT_BUF_LEN];

char* dir = argv[1];

/*creating the INOTIFY instance*/
if((fd = inotify_init()) < 0)
    perror( "inotify_init" );


/*adding the 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, dir, IN_CREATE | IN_DELETE );

while(1) {

    i=0;
    pid_t p;
    struct stat st;

    /*read to determine the event change happens on “/tmp” directory. Actually this read blocks until the change event occurs*/ 
    if((length = read(fd, buffer, EVENT_BUF_LEN )) < 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.\n", event->name );
                else{
                    printf("New file %s created.\n", event->name );
                    char* file_name;
                    asprintf(&file_name, "%s/%s", dir, event->name);

                    printf("Check if %s is executable\n", file_name);
                    if (access(file_name, X_OK) == 0){ //If file is executable
                        printf("Executable file! Call fork()\n");
                        if ((p = fork()) == 0) {  // Child process: do your work here
                            if (execlp(file_name, file_name,  (char*) 0)<0)
                                fprintf(stderr, "execlp error\n");
                            exit(0);
                        }
                        else{
                            while(waitpid(p, NULL, WNOHANG) != p);
                            remove (event->name);
                            printf("%s done & gone\n", event->name);
                        }
                    }
                    else
                        fprintf(stderr, "Not executable file\n");
                }
            }
            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;
    }
}

/*removing the “/tmp” directory from the watch list.*/
inotify_rm_watch( fd, wd );

/*closing the INOTIFY instance*/
close( fd );

 }
person Gorgo    schedule 25.05.2013

Это невозможно в ANSI C, вам нужен POSIX.

person Polluks    schedule 08.03.2021