7

It's my first time working with posix; I included:

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

And I've this snippet.

stat(pathname, &sb);
if ((sb.st_mode & S_IFMT) == S_IFREG) {
    /* Handle regular file */
}

But using GCC 4.8.3 on Gentoo if I compiled with -std=c99 or -std=c11 or -std=gnu99 or -std=gnu11 I got this error:

error: ‘S_ISFMT’ undeclared (first use in this function)

If I omit -std=* I got no errors. But I want all the features of -std=c99 too (like the keyword restrict or for(int i;;) etc ...) How could I compile my code?

  • This is a little bit strange. Can you please construct a minimal self-contained example so I can reproduce this issue on my system? I wasn't able to reproduce it otherwise. – fuz Feb 21 '15 at 10:57

3 Answers3

6

Modern POSIX-compliant systems are required to provide the S_IFMT and S_IFREG values. The only version of POSIX that does not require this (and in fact, forbids it) is POSIX.1-1990, which appears to be the standard on your machine.

In any case, every POSIX-compliant system provides macros that allow you to check the type of the file. These macros are equivalent to the masking method.

So in your case, instead of (sb.st_mode & S_IFMT) == S_IFREG, just write S_ISREG(sb.st_mode).

Daniel Kleinstein
  • 5,262
  • 1
  • 22
  • 39
  • This doesn't answer the question `__S_IFMT` and `__S_IFREG` are internal constants that should never be used by a user program. Also, OP asks about POSIX and you give a platform-specific non-answer. – fuz Feb 21 '15 at 10:56
  • @FUZxxl The first part of my answer *does* answer the question, the second part of my answer is just for the case where OP is really (and unnecessarily) insistent on doing the masking himself. – Daniel Kleinstein Feb 21 '15 at 10:58
  • @FUZxxl OP could also take the numerical values of the internal constants and just use them in his program, but it's just unnecessary because POSIX systems macros that do the masking for you (as explained in my non-platform-specific answer). – Daniel Kleinstein Feb 21 '15 at 11:22
  • But you can do the masking yourself with POSIX! POSIX explicitly specifies that masking with `S_IFMT` and then comparing must work. You don't need any internal macros for this. – fuz Feb 21 '15 at 11:27
  • @FUZxxl The standard doesn't specify that `S_IFMT` and `S_IFREG` have to be provided to user programs. It might work when compiled under `-std=c99` on your machine, but on mine and OP's machines it doesn't, and it shouldn't *have* to, because the POSIX macros make providing `S_IFMT` and `S_IFREG` to user programs unnecessary. Your downvote is unjustified. – Daniel Kleinstein Feb 21 '15 at 11:30
  • Yes, [it does](http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html) (for XSI compliant systems). This link contains all the things that have to be in `sys/stat.h`, including `S_IFMT` and `S_IFREG`. Please stop spreading misinformation. – fuz Feb 21 '15 at 11:58
  • The future directions do not even say that this stuff will be removed. It's interesting that they don't seem to say explicitly that can mask an `mode_t` with `S_IFMT` and then compare with one of the constants provided there, but that's sort of implied by how these macros work. Let me confirm with a coworker who's on the PASC. – fuz Feb 21 '15 at 12:11
  • @FUZxxl POSIX 2008 indeed does require describing the `S_IFMT` value. POSIX.1-1990 however, does not - in fact it demands the usage of the `S_IFREG` macro. Mine and OP's machines are apparently POSIX.1-1990 compliant. I've edited my answer accordingly, thank you for correcting me. – Daniel Kleinstein Feb 21 '15 at 12:20
  • Recent editions of the glibc are mostly POSIX 2008 compliant. They should actually expose these macros. That's why I'm wondering. – fuz Feb 21 '15 at 13:14
  • Sorry, the link is, idk, dead? Could you refresh information? Would be useful. – LRDPRDX Feb 02 '20 at 14:54
4

Put either #define _BSD_SOURCE or #define _XOPEN_SOURCE before any #include in your source code. To see why this works, look right above #define S_IFMT __S_IFMT in sys/stat.h, then in feature_test_macros(7) man page.

2

K&R2 provides:

#define S_IFMT 0160000 /* type of file: */
#define S_IFDIR 0040000 /* directory */

in chapter 8.6 Example-Listing Directories.

I do NOT encourage to use this solution, furthermore, I hope that some experts may teach us whether it is right or not implemented, pros-cons, alternatives, and so. Thx in advance!

Example of MWE.

MWE:

/* these defines at beginning to highlight them */
#define S_IFMT 0160000 /* type of file: */
#define S_IFDIR 0040000 /* directory */

/*
   Modify the fsize program to print the other information contained in the inode entry.
   */

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <dirent.h>
#include <pwd.h>


#define MAX_PATH 1024

#ifndef DIRSIZ
#define DIRSIZ 14
#endif


void dirwalk( char *dir,void (*fcn)(char *)){

    char name[MAX_PATH];
    struct dirent *dp;
    DIR *dfd;

    if((dfd = opendir(dir))==NULL){
        puts("Error: Cannot open Directory");
        return;
    }
    puts(dir);
    // Get each dir entry
    while((dp=readdir(dfd)) != NULL){
        // Skip . and .. is redundant.
        if(strcmp(dp->d_name,".") == 0
            || strcmp(dp->d_name,"..") ==0 )
            continue;
        if(strlen(dir)+strlen(dp->d_name)+2 > sizeof(name))
            puts("Error: Name too long!");
        else{
            sprintf(name,"%s/%s",dir,dp->d_name);
            // Call fsize
            (*fcn)(name);
        }
    }
    closedir(dfd);
}

void fsize(char *name){
    struct stat stbuf;

    if(stat(name,&stbuf) == -1){
        puts("Error: Cannot get file stats!");
        return;
    }

    if((stbuf.st_mode & S_IFMT) == S_IFDIR){
        dirwalk(name,fsize);
    }
    struct passwd *pwd = getpwuid(stbuf.st_uid);
    //print file name,size and owner
    printf("%81d %s Owner: %s\n",(int)stbuf.st_size,name,pwd->pw_name);
}

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

    if(argc==1)
        fsize(".");
    else 
        while(--argc>0)
            fsize(*++argv);
    return 0;
}
Xopi García
  • 359
  • 1
  • 2
  • 9
  • Ehm... To be precise, In K&R2 it is written "[...] The flag definitions are also included in ``[...]". – LRDPRDX Feb 02 '20 at 14:44