Giorgio Napolitano
Giorgio Napolitano

Reputation: 395

S_IFMT and S_IFREG undefined with -std=c11 or -std=gnu11

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?

Upvotes: 8

Views: 8811

Answers (3)

Xopi Garc&#237;a
Xopi Garc&#237;a

Reputation: 386

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;
}

Upvotes: 2

Peter968475
Peter968475

Reputation: 51

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.

Upvotes: 5

Daniel Kleinstein
Daniel Kleinstein

Reputation: 5502

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).

Upvotes: 7

Related Questions