0

While reading dup3 system call, I got that it will change only O_CLOEXEC flag of duplicated file desriptor. But when I have written below program for all the 3 outputs it printed the flag is either present or not and it is based on whether O_CLOEXEC is specified in original file descriptor when opening. What's wrong ? I really don't understand.

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h> 
#include <errno.h>
#include <fcntl.h>
#include <string.h>

#define TRUE 1
#define FALSE 0

void PrintUsage();
void PrintVersion();
void PrintStatusCloexec( int );
void dup3_code( const char * );

void main(int argc, char *argv[])
{
    int hflag = FALSE, vflag = FALSE, nflag = FALSE, src_flag = FALSE;
    char *src_file_name = NULL; 
    int src_len = 0;
    char c;
    int option_index;

    struct option long_options[] = { 
            { "version", no_argument, 0, 0},
            { "help", no_argument, 0, 0}, 
            { "src_file", required_argument, 0, 0},
            {0,0,0,0}
        };      

    while( ( c = getopt_long(argc, argv, "hvs:", long_options, &option_index) ) != -1 )
    {
        switch( c )
        {
            case 'h':
                hflag = TRUE;
                break;
            case 'v':
                vflag = TRUE;
                break;
            case 's':
                src_flag = TRUE;
                src_len = strlen( optarg );
                src_file_name = (char *)calloc(1, src_len + 1);
                strncpy(src_file_name, optarg, src_len);
                break;
            case 0:
                switch(option_index)
                {
                    case 0: vflag = TRUE;
                        break; 
                    case 1: hflag = TRUE;
                        break;
                    case 2: src_flag = TRUE;
                        src_file_name = (char *) calloc(1, strlen(optarg) + 1);
                        strncpy(src_file_name, optarg, src_len);
                        break;
                    default: printf(" Invalid argument index : %d", option_index );
                        exit(EXIT_FAILURE); 
                }
                break;

            case '?':
                break;
            default:
                printf( " Invalid option %c", c);
                exit(EXIT_FAILURE);
        }
    }

    if( vflag == FALSE && src_flag == FALSE ) 
    {
        PrintUsage();
    }

    if(hflag == TRUE)
    {
        PrintUsage();
    }

    if(vflag == TRUE )
    {
        PrintVersion();
    }

    if(src_flag == TRUE)
    {
        printf(" src file name : %s\n", src_file_name);
        dup3_code( src_file_name );
    }

    exit(EXIT_SUCCESS);
}

void PrintUsage()
{
    printf(" Usage : %s [-h] [-v] [-s|src_file file_name]\n" , __FILE__ );
}

void PrintVersion()
{
    printf(" Version : 1.0\n");
}

void dup3_code( const char *file_name )
{
    int fd = open( file_name, O_RDWR | O_CLOEXEC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP );
    if( fd == -1 )
    {
        printf(" Error opening file %s : %s\n", file_name, strerror(errno));
        exit(EXIT_FAILURE);
    }
    printf( "After file is opened:\n");
    PrintStatusCloexec( fd );

    int new_fd = dup( fd );
    printf( "After dup:\n" );
    PrintStatusCloexec( new_fd );
    close( new_fd );

    new_fd = dup3( fd, new_fd, O_CLOEXEC );
    printf( "After dup3:\n" );
    PrintStatusCloexec( new_fd );
    close( new_fd );

    close( fd );
}

void PrintStatusCloexec( int fd )
{
    int flags = fcntl( fd, F_GETFL );
    if( flags & O_CLOEXEC )
    {
        printf( " close on exec flag for file id %d is set\n", fd );
    }
    else
    {
        printf( " close on exec flag for file id %d is not set\n", fd );
    }

}

Also My GNU C library version :

GNU C Library (Ubuntu EGLIBC 2.15-0ubuntu10) stable release version 2.15.
mantal
  • 1,093
  • 1
  • 20
  • 38
Sanjay Bhosale
  • 685
  • 2
  • 8
  • 18
  • What are you doing with those argument strings? `calloc()` with cast? `strncpy()`? I think those are things you need to look into. – unwind Aug 21 '14 at 12:40
  • They are working correctly. No issue for them. – Sanjay Bhosale Aug 21 '14 at 13:02
  • My linux manual states that you should `#define _GNU_SOURCE` before including unistd.h; dup3() is a BSDism, IIRC (but I could not get it to work either) BTW: main() should return int, not void. – joop Aug 21 '14 at 13:16

1 Answers1

1

To get the current status of the flag you need to use F_GETFD and look at the FD_CLOEXEC bit. F_GETFL only returns flags that belong to the open file description (i.e. the flags that are shared among dup'ed descriptors and forked processes). The presence or absence of O_CLOEXEC in the result of F_GETFL is not meaningful.

  • Thanks for your answer. After changing fcntl and condition statements to int flags = fcntl( fd, F_GETFD ); if( flags & FD_CLOEXEC ) its working as per expectation. Thanks. – Sanjay Bhosale Aug 21 '14 at 13:06