Tuesday, 9 July 2019

Makefile variable assign difference between := vs =

makefile difference between := vs =



There are two ways that a variable in GNU make can have a value:

Note: Got the comment as "Can you use early evaluation here with :=", so it will be good to use :=

The Two Flavors of Variables:  recursively expanded

  • The first flavor of variable is a recursively expanded variable.
  • Variables of this sort are defined by lines using ‘=’ or  Defining Multi-Line Variables
  • if it contains references to other variables, these references are expanded whenever this variable is substituted (in the course of expanding some other string). When this happens, it is called recursive expansion.
For Example,

foo = $(bar)
bar = $(ugh)
ugh = Huh?

all:;echo $(foo)

Second flavor of variable: simply expanded variables.

  • Simply expanded variables are defined by lines using ‘:=’ or ‘::=’ (see Setting Variables). Both forms are equivalent in GNU make;
  • The value of a simply expanded variable is scanned once and for all, expanding any references to other variables and functions, when the variable is defined.
  • It does not contain any references to other variables.
  • it contains their values as of the time this variable was defined
  • its value is substituted verbatim.
For example,
       
x := foo
y := $(x) bar
x := later

is equivalent to

y := foo bar
x := later
 

Program:

# Simply expanded variables:
x := foo
# y is assigned with 'foo bar' value, so in future x value changes also won't affect y
# y use value of x not an variable of x.
y := $(x) bar
x := later

# Recursively expanded variable:
a = foo
# y is assgined with '$(a) bar', so in future x value changes also will reflect in y.
# Because y always use variable x not an value of x.
b = $(a) bar
a = later

Test:
        echo $(x)
        echo $(y)
        echo '-----------------------'
        echo $(a)
        echo $(b)

Output:


~/velrajk/sample/makefile/make_:=$ make
echo later
later
echo foo  bar
foo bar
echo '-----------------------'
-----------------------
echo later
later
echo later bar
later bar




Reference: https://www.gnu.org/software/make/manual/make.html#Flavors
 

Wednesday, 3 July 2019

How to compile 32 bit binary on 64 bit machine



GCC option to compile 32 bit binary on 64 bit machine:


Generate code for a 32-bit or 64-bit environment.
  • -m32 
    • sets "int", "long", and pointer types to 32 bits, and generates code that runs on any i386 system.
  • -m64
    •  sets "int" to 32 bits and "long" and pointer types to 64 bits, and generates code for the x86-64 architecture.
    • For Darwin only the -m64 option also turns off the -fno-pic and -mdynamic-no-pic options.
  • -mx32
    • sets "int", "long", and pointer types to 32 bits, and generates code for the x86-64 architecture.


Compile:

velrajk/sample$ gcc sizeof.c
velrajk/sample$ gcc -m32 sizeof.c -o 32_bit
velrajk/sample$

Output:

velrajk/sample$ ./32_bit
size of vel = 4 int= 4 float = 4double= 8 0 = 4 NULL = 4  "" = 1 int * = 4 unsigned long = 4 Unsigned int = 4
velrajk/sample$ ./a.out
size of vel = 4 int= 4 float = 4double= 8 0 = 4 NULL = 8  "" = 1 int * = 8 unsigned long = 8 Unsigned int = 4
velrajk/sample$


File lock using fcntl()

File lock:


File lock using fcntl()

NAME

       fcntl - manipulate file descriptor

SYNOPSIS

#include <unistd.h>
#include <fcntl.h>

int fcntl(int fd, int cmd, ... /* arg */ );

DESCRIPTION

  • fcntl() performs one of the operations described below on the open file descriptor fd.  The operation is determined by cmd.
  •  fcntl()  can  take  an optional third argument.  Whether or not this argument is required is determined by cmd.  The required argument type is indicated in parentheses after each cmd        name (in most cases, the required type is int, and we identify the argument using the name arg), or void is specified if the argument is not required.


   struct flock {
               ...
               short l_type;    /* Type of lock: F_RDLCK,
                                   F_WRLCK, F_UNLCK */
               short l_whence;  /* How to interpret l_start:
                                   SEEK_SET, SEEK_CUR, SEEK_END */
               off_t l_start;   /* Starting offset for lock */
               off_t l_len;     /* Number of bytes to lock */
               pid_t l_pid;     /* PID of process blocking our lock
                                   (F_GETLK only) */
               ...
           };

  • The l_whence, l_start, and l_len fields of this structure specify the range of bytes we wish to lock.  Bytes past the end of the file may be locked, but not bytes before the start of  the file.
  • F_SETLK (struct flock *)
    • Acquire  a lock (when l_type is F_RDLCK or F_WRLCK) or release a lock (when l_type is F_UNLCK) on the bytes specified by the l_whence, l_start, and l_len fields of lock.  
    • If a conflicting lock is held by another process, this call returns -1 and sets errno to EACCES or EAGAIN.
  • F_SETLKW (struct flock *)
    • As for F_SETLK, but if a conflicting lock is held on the file, then wait for that lock to be released.  If a signal is caught while waiting, then the call is  interrupted  and (after the signal handler has returned) returns immediately (with return value -1 and errno set to EINTR;
    • Note: currently we are using F_SETLKW
  • F_GETLK (struct flock *)
    • On  input  to this call, lock describes a lock we would like to place on the file.  If the lock could be placed, fcntl() does not actually place it, but returns F_UNLCK in the l_type field of lock and leaves the other fields of the structure unchanged. 
    • If one or more incompatible locks would prevent this lock  being  placed,  then  fcntl()  returns details about one of these locks in the l_type, l_whence, l_start, and l_len fields of lock and sets l_pid to be the PID of the process holding that lock.
Note: In order to place a read lock, fd must be open for reading.  In order to place a write lock, fd must be open for writing.  To place both types of lock, open a file read-write.

RETURN VALUE

    On Success return 0, otherwise retun -1 and errno is set appropriately.

My Understand:

  • Read lock: 
    • Read lock will be blocked if already this file is locked.
    • After unlock it won't reeceive value, but next call it will get
  • Write lock:
    • Write lock will be blocked if already this file is locked with write lock on another process.  
    • After unlock, it exeepcted to overwrite the old value, but reality it won't overwrite the value the output file file contain both value, need to handle this if 2 differect process take the write lock.  

Program:

 
/* File lock using fcntl()
 * Check : http://velrajcoding.blogspot.in
 */
#include <stdio.h>
#include <unistd.h>  // For fcntl
#include <fcntl.h>   // For  struct flock, F_WRLCK & F_SETLKW
#include <errno.h>   // For errno


enum {
    FILE_LOCK,
    FILE_UNLOCK,
};


int file_lock_and_ulock(int fd, const char *path, int is_lock, char ch)
{
    char         str[128] = {0};
    struct flock lock;

    lock.l_type = (is_lock == FILE_LOCK) ? ((ch == 'r') ? F_RDLCK : F_WRLCK) : F_UNLCK;
    lock.l_start = 0;
    lock.l_whence = SEEK_SET;
    lock.l_len = 0;
    lock.l_pid = getpid();

    /*
     * Read lock: read lock will be blocked if already this file is locked.
     *            After unlock it won't reeceive value, but next call it will get
     * Write lock: Write lock will be blocked if already this file is locked with write lock on another process.
     *             After unlock, it exeepcted to overwrite the old value, but reality it won't overwrite the value
     *             the output file file contain both value, need to handle this if 2 differect process take the write lock
     */
    if (fcntl(fd, F_SETLKW, &lock) < 0) {
        strerror_r(errno, str, sizeof(str));
        printf("Error to lock the file errno:%d err des:%s \n", errno, str);
        return 0;
    }
    printf("File %s  is %s \n", path, (is_lock == FILE_LOCK) ? "Locked" : "Unlocked");

    return 1;

}

int file_read()
{
    FILE *fp = NULL;
    int  ret = 0, value = 0;
    unsigned long value_l = 0;
    char str[128] = {0};
    char str_2[128] = {0};


    fp = fopen("test.txt", "r");
    if (!fp) {
        printf("File open is failed errno:%d  ENOENT:<%d>\n", errno, ENOENT);
        return 1;
    }
    ret = file_lock_and_ulock(fileno(fp), "test.txt", FILE_LOCK, 'r');
    if (ret == 0) {
        printf("Error in locking \n");
        return 1;
    }

    fgets(str, sizeof(str), fp);
    fseek(fp, 0, SEEK_SET);
    fscanf(fp, "%s %d", str, &value);
    file_lock_and_ulock(fileno(fp), "test.txt", FILE_UNLOCK, 'r');
    printf("File content on filst line:<%s> & fscan read:%d \n", str, value);

    fseek(fp, 0, SEEK_SET);
    if (fgets(str, sizeof(str), fp) == NULL) {
        printf("Error in retrienve \n");
    }
    memset(str_2, 0, sizeof(str));
    value_l = 0;
    if ((ret = sscanf(str, "%s %lu", str_2, &value_l)) != 2) {
        printf("Error in sscanf: %d  \n", ret);
    }
    printf("File content using fgets & sscanf line:<%s> & fscan read:%d  ret:%d \n", str, value_l, ret);
    return 0;

}

int main()
{
    FILE *fp = NULL;
    int  ret = 0, choose = 0;

    printf("Option for file operation:   \n\t\t 1. Read \n\t\t 2.Write \n Choose your option: ");
    scanf("%d", &choose);

    switch (choose) {
        case 1:
            file_read();
            break;
        case 2:
            fp = fopen("test.txt", "w");
            ret = file_lock_and_ulock(fileno(fp), "test.txt", FILE_LOCK, 'w');
#if defined (AVOID_OVERRIGHT)
            fflush(fp);
            fsync(fileno(fp));
#endif

            if (ret == 0) {
                printf("Error in locking \n");
                return 1;
            }

            //sleep(5);
            fprintf(fp, "file_w_lock_b.c 2nd\n");
            fflush(fp);
            fsync(fileno(fp));
            file_lock_and_ulock(fileno(fp), "test.txt", FILE_UNLOCK, 'w');

            fclose(fp);
            break;
       default:
            printf("Wrong option \n");
    }

    return 0;
}


 

Program 2:

 
/* File lock using fcntl()
 * Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>
#include <unistd.h>  // For fcntl
#include <fcntl.h>   // For  struct flock, F_WRLCK & F_SETLKW
#include <errno.h>   // For errno

enum {
    FILE_LOCK,
    FILE_UNLOCK,
};


int file_lock_and_ulock(int fd, const char *path, int is_lock)
{
    char         str[128] = {0};
    struct flock lock;

    lock.l_type = (is_lock == FILE_LOCK) ? F_WRLCK : F_UNLCK;
    lock.l_start = 0;
    lock.l_whence = SEEK_SET;
    lock.l_len = 0;
    lock.l_pid = getpid();

    if (fcntl(fd, F_SETLKW, &lock) < 0) {
        strerror_r(errno, str, sizeof(str));
        printf("Error to lock the file errno:%d err des:%s \n", errno, str);
        return 0;
    }
    printf("File %s  is %s \n", path, (is_lock == FILE_LOCK) ? "Locked" : "Unlocked");

    return 1;

}

int file_check_back_slan_n()
{
    FILE     *fp = NULL;
    int      temp = 0;
    char     str[128] = {0};

    if (!(fp = fopen("test_2.txt", "w+"))) {
        printf("Error in open a file \n");
        return 1;
    }

    fprintf(fp, "velraj \n serte %d", 100);
    fflush(fp);
    fsync(fileno(fp));

    fseek(fp, 0, SEEK_SET);
    fscanf(fp, "%d", &temp);

    fseek(fp, 0, SEEK_SET);
    fgets(str, sizeof(str), fp);
    printf("Vel fscanf int:<%d> fgets:<%s> \n", temp, str);
    fclose(fp);

    return 0;
}

int main()
{
    FILE    *fp;
    char         str[128] = {0};

    /*
     *  w      Truncate file to zero length or create text file for writing.  The stream is positioned at the beginning of the file.
     *  w+     Open for reading and writing.  The file is created if it does not exist, otherwise it is truncated.  The stream is positioned at the beginning of the file.
     */
    if ((fp = fopen("test.txt", "w"))) {
        file_lock_and_ulock(fileno(fp), "test.txt", FILE_LOCK);
    } else {
        strerror_r(errno, str, sizeof(str));
        printf("Error to open a file errno:%d err des:%s \n", errno, str);
        return 1;
    }

    fprintf(fp, "file_w_lock.c: 1 This is testing for fprintf...\n");
//    fputs("This is testing for fputs...\n", fp);

#if defined (FLUSH_SYNC_AFTER_SLEEP)
    printf("Going to sleep and flush flush & sync after sleep");
    sleep(10);
#endif
    fflush(fp);
    fsync(fileno(fp));
#if !defined (FLUSH_SYNC_AFTER_SLEEP)
    printf("flush & sync donw now gonig to sleep ");
    /* After flush & sync the file */
    sleep(10);
#endif
    file_lock_and_ulock(fileno(fp), "test.txt", FILE_UNLOCK);
    fclose(fp);

    return 0;
    if ((fp = fopen("test.txt", "w"))) {
        file_lock_and_ulock(fileno(fp), "test.txt", FILE_LOCK);
    } else {
        strerror_r(errno, str, sizeof(str));
        printf("Error to open a file errno:%d err des:%s \n", errno, str);
        return 1;
    }



    fflush(fp);
    fsync(fileno(fp));
    file_lock_and_ulock(fileno(fp), "test.txt", FILE_UNLOCK);
    fclose(fp);

    file_check_back_slan_n();

    return 0;
} 

Output: 

   Lock & lock from first terminal 1st terminal:
           abuser@labuser-virtual-machine:~/velrajk/sample$ ./a.out
           File test.txt  is Locked
           File test.txt  is Unlocked
           labuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$



   Not using lock on second file 2nd terminal:
           abuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$ cat test.txt
           from_2
           labuser@labuser-virtual-machine:~/velrajk/sample$ === now antoher progr is still inlocking  ======
           ===: command not found
           labuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$
           labuser@labuser-virtual-machine:~/velrajk/sample$ ==== that is over unlcoked here not used lock ====
           ====: command not found
           labuser@labuser-virtual-machine:~/velrajk/sample$ cat test.txt
           This is testing for fprintf...
           This is testing for fputs...
           labuser@labuser-virtual-machine:~/velrajk/sample$

  issue:
  ------
   Lock on process 1 process 2 is got hanged due to process 1 lock, after process 1 release, process 2 write on first still process 1 data also present.


   labuser@labuser-virtual-machine:~/velrajk/sample$ cat test.txt
   from_2
   testing for fprintf...
   This is testing for fputs...
   labuser@labuser-virtual-machine:~/velrajk/sample$

Wednesday, 26 June 2019

strtol - convert str to interger


strtol - Convert the number from string into interger

NAME

  • strtol, strtoll, strtoq - convert a string to a long integer

SYNOPSIS

       #include <stdlib.h>

       long int strtol(const char *nptr, char **endptr, int base);
       long long int strtoll(const char *nptr, char **endptr, int base);

       strtoll():
           _ISOC99_SOURCE
               || /* Glibc versions <= 2.19: */ _SVID_SOURCE || _BSD_SOURCE

DESCRIPTION  

  • The strtol() function converts the initial part of the string in nptr to a long integer value according to the given base.
  • If base is 2 then binary, if 8 then octal, if 10 then decimal & 16 for hexa decimal.
  • In bases above 10, the letter 'A' in either uppercase or lowercase represents 10, 'B' represents 11, and so forth, with 'Z' representing 35.
  • Checked in sample program, Hence If u give base as 20 then, f as 15, g as 16, h as 17... j as 19, k will throw an error.
  •  
  • If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr.
  • If there were no digits at all, strtol() stores the original value of nptr in *endptr (and returns 0).

RETURN VALUE

  • The strtol() function returns the result of the conversion, unless the value would underflow or overflow.
  • If an underflow occurs, strtol() returns LONG_MIN.
  • If an overflow occurs, strtol() returns LONG_MAX.
  • In both cases, errno is set to ERANGE.

Note: Program should set errno to 0 before the call, after call check the errno.

Difference between atoi, strtol & sscanf :

atoi()
    Pro: Simple.
    Pro: Convert to an int.
    Pro: In the C standard library.
    Pro: Fast.
    Con: No error handling.
    Con: Handle neither hexadecimal nor octal.

atol()
    Pro: Simple.
    Pro: In the C standard library.
    Pro: Fast.
    Con: Converts to an long, not int which may differ in size.
    Con: No error handling.
    Con: Handle neither hexadecimal nor octal.

strtol()
    Pro: Simple.
    Pro: In the C standard library.
    Pro: Good error handling.
    Pro: Fast.
    Con: Convert to an long, not int which may differ in size.

strtoul()
    Pro: Simple.
    Pro: In the C standard library.
    Pro: Good error handling.
    Pro: Fast.
    ---: Appears to not complain about negative numbers.
    Con: Converts to an unsigned long, not int which may differ in size.

sscanf(..., "%i", ...)
    Pro: In the C standard library.
    Pro: Converts to int.
    ---: Middle-of-the-road complexity.
    Con: Slow.
    Con: OK error handling (overflow is not defined).
    #define BASE_DECIMAL             10
Eg: pid_count = (int)strtol(buf, NULL, BASE_DECIMAL);

Program:

/* strtol - convert str to interger by Velraj.K
 * Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>>
#include <errno.h>  // errno & ERANGE
#include <stdlib.h>  // strtol & LONG_MAX
#include <limits.h>  // LONG_MAX & LONG_MIN
#include <string.h>  // for strerror

enum {
    FAILED = -1,
    SUCCESS,
};

/*************************************************************************************
 * FUNCTION NAME: convert_str_to_int
 *
 * DESCRIPTION  : convert the string into interget value
 *
 * RETURNS      : None
 * RETURNS      : FAIL on failure,
 *                SUCCESS on successfull update.
 *************************************************************************************/
static int convert_str_to_int(char *str_val, unsigned int *conv_value, char **save_endptr)
{
    char *endptr = NULL;
    long int result = 0;

    if (!str_val || !conv_value) {
        printf("input string is NULL \n");
        return FAILED;
    }

   errno = 0;
    result = strtol(str_val, &endptr, 10);
    *conv_value = (unsigned int)result;
    if (((errno == ERANGE) && ((result == LONG_MAX) || (result == LONG_MIN))) ||
            ((errno != 0) && (result == 0))) {
        printf("Error: conversion %s(%d) \n", strerror(errno), errno);
        return FAILED;
    }

    /* Save the endptr string for any future usage, after conversion. */
    if (save_endptr) {
        *save_endptr = endptr;
        if ((*save_endptr) && (**save_endptr != '\0') &&
                (!isspace(**save_endptr))) {
            printf("End string of input value saved as:%s \n", *save_endptr);
        }
    }

    if (endptr == str_val) {
        printf("No digits were found \n");
        return FAILED;
    }


    return SUCCESS;
}

int main()
{
    int      value = 0;
    char     *endptr = NULL;
    char     str[32] = {0};

    while (1) {
        printf("Enter the number to convert strint to int   :   ");
//        scanf("%[^\t\n]s", str);
        fgets(str, sizeof(str), stdin);
        convert_str_to_int(str, &value, &endptr);
        /*
         * Check the endptr has any invalid trailing strings,
         * after strtol conversion.
         */
        if ((endptr) && (*endptr != '\0') && (!isspace(*endptr))) {
            printf("Error invalid string is present \n");
        } else {
            printf("Input value    :  %s", str);
            printf("Value after convert val to : %d\n",value);
        }
    }

        convert_str_to_int("5m", &value, &endptr);
    if ((endptr) && (*endptr != '\0') && (!isspace(*endptr))) {
        printf("Error invalid string is present for 5m \n");
    } else {
        printf("Value after conver 5m val : %d \n", value);
    }

    return 0;
}



Output: 

 velraj@virtual-machine:~/velrajk/sample$ ./a.out
Enter the number to convert strint to int   :   5
Input value    :  5
Value after convert val to : 5
Enter the number to convert strint to int   :   5m
End string of input value saved as:m

Error invalid string is present
Enter the number to convert strint to int   :   5
Input value    :  5
Value after convert val to : 5
Enter the number to convert strint to int   :   5    m
Input value    :  5    m
Value after convert val to : 5
Enter the number to convert strint to int   :   5 mnews
Input value    :  5 mnews
Value after convert val to : 5
Enter the number to convert strint to int   :   ^C
 

Friday, 7 June 2019

stat, fstat & lstat Usage & diff

Name

  • stat, fstat, lstat - get file status

Synopsis

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

  • int stat(const char *path, struct stat *buf);
  • int fstat(int fd, struct stat *buf);
  • int lstat(const char *path, struct stat *buf)

Description

  • These functions return information about a file.
  • No permissions are required for file, but-in the case of stat() and lstat() - execute (search) permission is required on all of the directories in path that lead to the file.

Def:

  • stat() stats the file pointed to by path and fills in buf.
  • lstat() is identical to stat(), except that if path is a symbolic link, then the link itself is stat-ed, not the file that it refers to.
  • fstat() is identical to stat(), except that the file to be stat-ed is specified by the file descriptor fd.

Difference:

  • lstat() - if pathname is a symbolic link, then it returns information about the link itself, not the file (target) that it refers to.
  • stat()  - if pathname is a symbolic link, then it returns information about the target file that it refers to.

Symbolic file behaviour while opening:

  • Even if we touch the symbalic file, the modified time for target fill only will get modified, symbolic file modified time will be remain same.
  • If we edit the file using symbolic link, then modified time for target will be get changed but not symbolic file.

  • All of these system calls return a stat structure, which contains the following fields:
    struct stat {
        dev_t     st_dev;     /* ID of device containing file */
        ino_t     st_ino;     /* inode number */
        mode_t    st_mode;    /* protection */
        nlink_t   st_nlink;   /* number of hard links */
        uid_t     st_uid;     /* user ID of owner */
        gid_t     st_gid;     /* group ID of owner */
        dev_t     st_rdev;    /* device ID (if special file) */
        off_t     st_size;    /* total size, in bytes */
        blksize_t st_blksize; /* blocksize for file system I/O */
        blkcnt_t  st_blocks;  /* number of 512B blocks allocated */
        time_t    st_atime;   /* time of last access */
        time_t    st_mtime;   /* time of last modification */
        time_t    st_ctime;   /* time of last status change */
    };

st_mode field:

The following POSIX macros are defined to check the file type using the st_mode field:
    S_ISREG(m)     is it a regular file?
    S_ISDIR(m)     directory?
    S_ISCHR(m)     character device?
    S_ISBLK(m)     block device?
    S_ISFIFO(m)    FIFO (named pipe)?
    S_ISLNK(m)     symbolic link? (Not in POSIX.1-1996.)
    S_ISSOCK(m)    socket? (Not in POSIX.1-1996

Return Value

On success, zero is returned. On error, -1 is returned, and errno is set appropriately.

Program:



/* Difference between stat & lstat  by Velraj.K
 * Check : http://velrajcoding.blogspot.in
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>         // For memset

/* Note:
 *     Even if we touch the symbalic file, the modified time for target fill only will get modified,
 *          symbolic file modified time will be remain same.
 *     If we edit the file using symbolic link, then modified time for target will be get changed but not symbolic file.
 *     Difference:
 *       lstat() - if pathname is a symbolic link, then it returns information about the link itself,
 *                     not the file (target) that it refers to.
 *       stat()  - if pathname is a symbolic link, then it returns information about the target file that it refers to.
 */

void hline(char ch)
{
    int i;

    for (i = 0; i < 80; printf("%c", ch), i++);
    printf("\n");

    return;
}

void stat_display(struct stat *sb, char *method)
{
    if (!sb || !method) {
        printf("Error stat details is NULL \n");
        return;
    }

    hline('*');
    printf("\n\t Retrieve the file stat details using %s API\n", method);
    printf("\n\t ------------------------------------------------\n");
    printf("File type:                ");

    switch (sb->st_mode & S_IFMT) {
        case S_IFBLK:  printf("block device\n");            break;
        case S_IFCHR:  printf("character device\n");        break;
        case S_IFDIR:  printf("directory\n");               break;
        case S_IFIFO:  printf("FIFO/pipe\n");               break;
        case S_IFLNK:  printf("symlink\n");                 break;
        case S_IFREG:  printf("regular file\n");            break;
        case S_IFSOCK: printf("socket\n");                  break;
        default:       printf("unknown?\n");                break;
    }

    printf("I-node number:            %ld\n", (long) sb->st_ino);

    printf("Mode:                     %lo (octal)\n",
            (unsigned long) sb->st_mode);

    printf("Link count:               %ld\n", (long) sb->st_nlink);
    printf("Ownership:                UID=%ld   GID=%ld\n",
            (long) sb->st_uid, (long) sb->st_gid);

    printf("Preferred I/O block size: %ld bytes\n",
            (long) sb->st_blksize);
    printf("File size:                %lld bytes\n",
            (long long) sb->st_size);
    printf("Blocks allocated:         %lld\n",
            (long long) sb->st_blocks);

    printf("Last status change:       %s", ctime(&sb->st_ctime));
    printf("Last file access:         %s", ctime(&sb->st_atime));
    printf("Last file modification:   %s", ctime(&sb->st_mtime));
    hline('*');


}

int main(int argc, char *argv[])
{
    struct stat sb = {0};

    if (argc != 2) {
        fprintf(stderr, "Usage: %s pathname\n", argv[0]);
        exit(EXIT_FAILURE);
    }

    if (stat(argv[1], &sb) == -1) {
        perror("stat");
        exit(EXIT_FAILURE);
    }

    stat_display(&sb, "stat");
    memset(&sb, 0, sizeof(struct stat));
    if (lstat(argv[1], &sb) == -1) {
        perror("stat");
        exit(EXIT_FAILURE);
    }
    stat_display(&sb, "lstat");



   exit(EXIT_SUCCESS);
}

 

Output:

 labuser@labuser-virtual-machine:~/velrajk/sample$ touch ../temp/new_s
labuser@labuser-virtual-machine:~/velrajk/sample$ ./a.out ../temp/new_s
********************************************************************************

         Retrieve the file stat details using stat API

         ------------------------------------------------
File type:                regular file
I-node number:            1887181
Mode:                     100664 (octal)
Link count:               1
Ownership:                UID=1000   GID=1000
Preferred I/O block size: 4096 bytes
File size:                11 bytes
Blocks allocated:         8
Last status change:       Fri Jun  7 12:05:50 2019
Last file access:         Fri Jun  7 12:05:50 2019
Last file modification:   Fri Jun  7 12:05:50 2019
********************************************************************************
********************************************************************************

         Retrieve the file stat details using lstat API

         ------------------------------------------------
File type:                symlink
I-node number:            1963069
Mode:                     120777 (octal)
Link count:               1
Ownership:                UID=1000   GID=1000
Preferred I/O block size: 4096 bytes
File size:                3 bytes
Blocks allocated:         0
Last status change:       Thu Jun  6 19:45:36 2019
Last file access:         Thu Jun  6 19:45:38 2019
Last file modification:   Thu Jun  6 19:45:36 2019
********************************************************************************
labuser@labuser-virtual-machine:~/velrajk/sample$
labuser@labuser-virtual-machine:~/velrajk/sample$
labuser@labuser-virtual-machine:~/velrajk/sample$
labuser@labuser-virtual-machine:~/velrajk/sample$ date
Fri Jun  7 12:06:05 IST 2019
labuser@labuser-virtual-machine:~/velrajk/sample$

Monday, 3 June 2019

Skip the String or Char or int using format specifier %*

Format specifiers in C

  •  It is a way to tell the compiler what type of data is in a variable during taking input using scanf() or printing using printf().
    •  EG: %c, %d, %f, etc.
    • printf(char *format, arg1, arg2, …)

printing format:


  • A minus(-) sign tells left alignment.
  • A number after % specifies the minimum field width to be printed if the characters are less than the size of width the remaining space is filled with space and if it is greater than it printed as it is without truncation.
  • A period( . ) symbol seperate field width with the precision.
  •  %%    Prints % character

Program:

/* Skip the String or Char or int using format specifier %*  by Velraj.K
 * Check : http://velrajcoding.blogspot.in
 */

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

int main () {
    int day = 0, year = 0, ret;
    char weekday[20] = {0}, month[20] = {0}, dtm[100]= {0}, time[128] = {0}, meridiem[8] = {0};

    /*
     * The abbreviations am and pm derive from Latin:
     *   AM = Ante meridiem: Before noon
     *   PM = Post meridiem: After noon
     */
    strcpy( dtm, "Saturday March 25 1989 v1Hour before 10 AM" );
    //sscanf( dtm, "%s %*s %d  %d", weekday, month, &day, &year );
    /*
     * %*s  -> Skip the string
     * %*c  -> Skip the character
     * %*d  -> Skip the interger
     */
    ret = sscanf(dtm, "%s %*s %d  %d %*c %s %*s %*d %s", weekday, &day, &year, time, meridiem);



    printf("ret:%d Value: Day:<%d> Year:<%d> Week:<%s> Time:%s Meridiem:%s\n", ret, day, year, weekday, time, meridiem);
    printf("Velraj %n \n", &ret);

    return(0);
} 

Output: 

  /sample$ ./a.out ret:5 Value: Day:25 Year:1989 Week:saturday Time:1Hour Meridiem:AM

Wednesday, 29 May 2019

Send an signal with an argument (integer value)

sigaction Definition

Name:

  •     sigaction, rt_sigaction - examine and change a signal action

Synopsis:

  • #include <signal.h>
  • int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);

DESCRIPTION

  • The sigaction() system call is used to change the action taken by a process on receipt of a specific signal.
  • signum specifies the signal and can be any valid signal except SIGKILL and SIGSTOP.
  • If act is non-NULL, the new action for signal signum is installed from act.
  • If oldact is non-NULL, the previous action is saved in oldact.

  • The sigaction structure is defined as something like:
           struct sigaction {
               void     (*sa_handler)(int);
               void     (*sa_sigaction)(int, siginfo_t *, void *);
               sigset_t   sa_mask;
               int        sa_flags;
               void     (*sa_restorer)(void);
           };

Note: On some architectures a union is involved: do not assign to both sa_handler and sa_sigaction.

  • The sa_restorer field is not intended for application use.
  • If SA_SIGINFO is specified in sa_flags, then sa_sigaction (instead of sa_handler)
    sa_mask specifies a mask of signals which should be blocked
  • The siginfo_t data type is a structure with the following fields:
           siginfo_t {
               int      si_signo;     /* Signal number */
               int      si_errno;     /* An errno value */
               int      si_code;      /* Signal code */
               int      si_trapno;    /* Trap number that caused
                                         hardware-generated signal
                                         (unused on most architectures) */
               pid_t    si_pid;       /* Sending process ID */
               uid_t    si_uid;       /* Real user ID of sending process */
               int      si_status;    /* Exit value or signal */
               clock_t  si_utime;     /* User time consumed */
               clock_t  si_stime;     /* System time consumed */
               sigval_t si_value;     /* Signal value */
               int      si_int;       /* POSIX.1b signal */
               void    *si_ptr;       /* POSIX.1b signal */
               int      si_overrun;   /* Timer overrun count;
                                         POSIX.1b timers */
               int      si_timerid;   /* Timer ID; POSIX.1b timers */
               void    *si_addr;      /* Memory location which caused fault */
               long     si_band;      /* Band event (was int in
                                         glibc 2.3.2 and earlier) */
               int      si_fd;        /* File descriptor */
               short    si_addr_lsb;  /* Least significant bit of address
                                         (since Linux 2.6.32) */
               void    *si_lower;     /* Lower bound when address violation
                                         occurred (since Linux 3.19) */
               void    *si_upper;     /* Upper bound when address violation
                                         occurred (since Linux 3.19) */
               int      si_pkey;      /* Protection key on PTE that caused
                                         fault (since Linux 4.6) */
               void    *si_call_addr; /* Address of system call instruction
                                         (since Linux 3.5) */
               int      si_syscall;   /* Number of attempted system call
                                         (since Linux 3.5) */
               unsigned int si_arch;  /* Architecture of attempted system call
                                         (since Linux 3.5) */
           }

  • si_signo, si_errno and si_code are defined for all signals.
  • Signals sent with kill(2) and sigqueue(3) fill in si_pid and si_uid.
  • In addition, signals sent with sigqueue(3) fill in si_int and si_ptr with the values specified by the sender of the signal

The si_code field:

  •     The si_code field inside the siginfo_t argument that is passed to a SA_SIGINFO signal handler is a value (not a bit mask) indicating why this signal was sent.
  • The following values can be placed in si_code for a SIGILL signal:
           ILL_ILLOPC
                  Illegal opcode.

           ILL_ILLOPN
                  Illegal operand.

           ILL_ILLADR
                  Illegal addressing mode.

           ILL_ILLTRP
                  Illegal trap.

           ILL_PRVOPC
                  Privileged opcode.

           ILL_PRVREG
                  Privileged register.

           ILL_COPROC
                  Coprocessor error.

RETURN VALUE

  • sigaction() returns 0 on success; on error, -1 is returned, and set errno.

ERRORS        

  • EFAULT act or oldact points to memory which is not a valid part of the process address space.

sigqueue

Name

  • sigqueue - queue a signal and data to a process

SYNOPSIS   

  •      #include <signal.h>
  •     int sigqueue(pid_t pid, int sig, const union sigval value);

DESCRIPTION       

  • sigqueue() sends the signal specified in sig to the process whose PID is given in pid.
  • The value argument is used to specify an accompanying item of data (either an integer or a pointer value) to be sent with the signal, and has the following type:
           union sigval {
               int   sival_int;
               void *sival_ptr;
           };
  • If the receiving process has installed a handler for this signal using the SA_SIGINFO flag to sigaction(2), then it can obtain this data via the si_value field of the siginfo_t structure

RETURN VALUE

  • On success, sigqueue() returns 0, Otherwise, -1 is returned and set errno .

Program


/* Send an signal with an argument (integer value) by Velraj.K
 * Check : http://velrajcoding.blogspot.in
 */

#include <stdio.h>
#include <stdlib.h>        // For exit()
#include <string.h>       // For memset()
#include <unistd.h>      // For fork() & sleep()
#include <sys/wait.h>      // For sig_atomic_t, siginfo_t, sigaction, SA_SIGINFO, SIGUSR1, SIGUSR2, sigqueue(), wait()
#include <assert.h>        // For assert()

static volatile sig_atomic_t got_value = 0;

void sig_handler(int sig, siginfo_t *info, void *x)
{
    pid_t pid = 0;

    pid = getpid();
    /* info->si_value.sival_int contains the integer value receive from sender */
    switch (info->si_value.sival_int) {
        case 1:
            printf("Vel Child:%d, received Signal with arg value as 1 sig num = %d SIG_USR1:%d SIG_USR2:%d \n", pid, sig, SIGUSR1, SIGUSR2);
            break;
        case 2:
            printf("Vel Child:%d, received Signal with arg value as 2 sig num = %d \n", pid, sig);
            break;
        default:
            printf("Invalid value \n");
            break;
    }
    ++got_value;

    return;
}


int main()
{
    struct sigaction act = {0};
    int ret;
    int status = 0;
    pid_t pid = -1;
    union sigval send_arg = {0};

    act.sa_flags = SA_SIGINFO;
    act.sa_sigaction = sig_handler;

    /* Install hangler for singal */
    ret = sigaction(SIGUSR1, &act, NULL);
    assert(ret == 0);

    ret = sigaction(SIGUSR2, &act, NULL);
    assert(ret == 0);

    /* Create child process & send the signal from parent to Child */
    pid = fork();
    /*
     * On success, parent process get child PID,
     * Child process get pid as 0
     */
    if (-1 == pid) {
        exit(1);
    } else if (0 == pid) {
        /* Child process */
        while (2 != got_value) {
            sleep(1);
        }
        exit(0);
    } else {
        /* Parent process */
        /* Send signal along with value 1 */
        send_arg.sival_int = 1;
        printf("Vel Parent:%d send SIGUSR2 with arg value as 1 to the Child:%d \n", getpid(), pid);
        sigqueue(pid, SIGUSR2, send_arg);

        /* Send signal along with value 2 */
        send_arg.sival_int = 2;
        printf("Vel Parent:%d send SIGUSR1 with arg value as 2 to the Child:%d \n", getpid(), pid);
        sigqueue(pid, SIGUSR1, send_arg);
        wait(&status);
        printf("Vel Parent:%d  -->  Status return by Child:%d \n", getpid(), status);
    }

    return 0;
}

 

Output:

 Vel Parent:10474 send SIGUSR2 with arg value as 1 to the Child:10475
Vel Parent:10474 send SIGUSR1 with arg value as 2 to the Child:10475
Vel Child:10475, received Signal with arg value as 1 sig num = 12 SIG_USR1:10 SIG_USR2:12
Vel Child:10475, received Signal with arg value as 2 sig num = 10
Vel Parent:10474  -->  Status return by Child:0



Reference:

  • http://man7.org/linux/man-pages/man2/sigaction.2.html
  • http://man7.org/linux/man-pages/man3/sigqueue.3.html