18

For homework I have to write a C program and one of the things it has to do is check to see a file exists and if it is executable by the owner.

Using (stat(path[j], &sb) >= 0 I'm able to see if the file indicated by path[j] exists.

I've looked through man pages, a lot of questions and answers on stackoverflow, and several websites but I'm not able to wrap my head around exactly how to check if a file is executable using stat. I thought it would be as simple as ((stat(path[j], &sb) >= 0) && (sb.st_mode > 0) && (S_IEXEC) but as far as I can tell by testing it, it seems to ignore the fact that these files aren't executable.

I think that perhaps stat doesn't work the way I think it does. Assuming I use stat, how can I go about fixing this?

4
  • 2
    && (S_IEXEC) doesn't depend on sb at all, what's that supposed to do in your test? Commented Oct 27, 2012 at 8:54
  • 2
    Lookup the bitwise AND operator. You need to use it and S_IXUSR against sb.st_mode Commented Oct 27, 2012 at 8:54
  • 1
    Funny that if this was a Python question, everybody would instantly shout out about how terribly dangerous this is because of a possible race condition if you plan to rely on that result later. If you do (and enjoy keeping it safe), you might want to obtain a lock on the file before calling stat. Commented Oct 27, 2012 at 9:13
  • @Mat Ahhhhh that is what I didn't really understand last night. I originally tried to use sb.S_IEXEC and it gave me an error. I didn't realize that was what I was supposed to compare to. Commented Oct 27, 2012 at 16:07

3 Answers 3

22

You can indeed use stat to do this. You just have to use S_IXUSR (S_IEXEC is an old synonym of S_IXUSR) to check if you have execute permission. Bitwise AND operator (&) checks whether the bits of S_IXUSR are set or not.

if (stat(file, &sb) == 0 && sb.st_mode & S_IXUSR) 
    /* executable */
else  
    /* non-executable */

Example:

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

int main(int argc, char **argv)
{
    if (argc > 1) {
        struct stat sb;
        printf("%s is%s executable.\n", argv[1], stat(argv[1], &sb) == 0 &&
                                                 sb.st_mode & S_IXUSR ? 
                                                 "" : " not");
    }
    return 0;
}   
Sign up to request clarification or add additional context in comments.

4 Comments

(sb.st_mode & S_IXUSR) just making sure I got it. So S_IXUSR stores whichever digit of sb.st_mode indicates it's executable surrounded by 0's and the bitwise and will only give a 1 if that particular bit is set to 1?
You are right. :) Just note it is possible that several bits of S_IXUSR are set to 1.
Does this also check if the file isn't a directory ? Nevermind, reading docs I found the S_ISDIR macro.
Correct me if I'm wrong, but this just checks if the file is executable by the file owner right? If the user running "this program" is not the owner of the file, then the check might incorrectly indicate that it is executable. In such a case, the program should also inspect S_IXGRP (if the calling user group is the same as the program group) and S_IXOTH (otherwise).
5

Try:

((stat(path[j], &sb) >= 0) && (sb.st_mode > 0) && (S_IEXEC & sb.st_mode)

Comments

2

We can leverage the libmagic.so library which comes along with the file(1) utility. It can detect all executable like ELF, bash/python/perl scripts etc

Here's my code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "magic.h"

int
main(int argc, char **argv)
{
   struct magic_set *ms;
   const char *result;
   char *desired;
   size_t desired_len;
   int i;
   FILE *fp;

   ms = magic_open(MAGIC_RAW);
   if (ms == NULL) {
      (void)fprintf(stderr, "ERROR opening MAGIC_NONE: out of memory\n");
      return -1;
   }
   if (magic_load(ms, NULL) == -1) {
      (void)fprintf(stderr, "ERROR loading with NULL file: %s\n", magic_error(ms));
      return 11;
   }

   if (argc > 1) {
      if (argc != 2) {
         (void)fprintf(stderr, "Usage:  ./a.out </path/to/file>\n");
      } else {
         if ((result = magic_file(ms, argv[1])) == NULL) {
            (void)fprintf(stderr, "ERROR loading file %s: %s\n", argv[1], magic_error(ms));
            return -1;
         } else {
             if (strstr(result, (const char *)"executable")) {
                printf("%s: is executable\n", argv[1], result);
             }
         }
      }
   }
   magic_close(ms);
   return 0;
}

$ gcc test.c -I/path/to/magic.h /usr/lib/libmagic.so.1

./a.out /bin/ls

./a.out a.out

./a.out test.c

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.