mknod system call to clone /dev/null

I'm trying to use the "mknod" call in C to create a clone of /dev/null. I am stumped as to the final parameter I should provide to "mknod()". I am supposed to give it a type dev_t, which specifies a major & minor number. I want to specify major 3, minor 1, but how can I do this?

dev_t seems to be a long long. It takes up 8 bytes, but I can't find anything about it. I've searched through quite a few /usr/include files, but I still can't find anything (nor on google).

If I 'stat()' /dev/null and then print the value of st_dev as an int (%d), I get '16'. But when I try and create a file called 'mynull', a clone of /dev/null, I get a major number of 0 and minor number of 16 , as shown below ( mknod() fails unless I call it as root ).

c---------  1 root root 0, 16 Sep 18 21:20 mynull

From my man page:

       If the file type is S_IFCHR or S_IFBLK then dev specifies the major and minor  numbers of the newly created device special file; otherwise it is ignored.

Does anyone have any ideas as to how I can create a character special file with major number 1 and minor number 3?

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>

/* int mknod(const char *pathname, mode_t mode, dev_t dev); */

main( argc, argv )
  int   argc;
  char  *argv[];
{
  int rc;
  char path[256];
  char errstr[1024];

  strcpy( path, "mynull" );

  rc = mknod( path, S_IFCHR, 16 );

  if ( rc < 0 )
    perror( "mknod" );

  return(rc);
}

Here's what I get when I stat /dev/null:

  rc = stat( "/dev/null" , &fstatus );
  printf("dev_t for /dev/null = %d\n", fstatus.st_dev);

$ a.out
dev_t for /dev/null = 16

nathan,
You are referencing the wrong struct member to get device numbers. You should be referring to st_rdev and not st_dev.

From man stat:

dev_t    st_dev;      /* ID of device containing */
                           /* a directory entry for this file */
     dev_t    st_rdev;     /* ID of device */
                           /* This entry is defined only for */
                           /* char special or block special files */

Also, if you know the major and the minor device numbers, you can use the makedevice macro to create the device number. The makedevice macro is defined in /usr/include/sys/sysmacros.h. Maybe you could take a look at that file as well.

blowtorch, thanks for the explanation. You are right, the macro is defined in /usr/include/sys/sysmacros.h. I was able to find the correct value using makedev(1,3).

If I would have printed the correct member from the stat() call, I would have found that it is the number 259.

Thanks for your help.

The final code is below, with changes in red.

$ cat mknod.c
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <strings.h>
#include <errno.h>

/* int mknod(const char *pathname, mode_t mode, dev_t dev); */

main( argc, argv )
  int   argc;
  char  *argv[];
{
  int rc;
  int old_umask;
  char path[256];
  char errstr[1024];

  strcpy( path, "mynull" );

  old_umask = umask(0);
  rc = mknod( path, S_IFCHR|S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH, makedev(1,3) );

  if ( rc < 0 )
    perror( "mknod" );

  return(rc);
}
[root@localhost c]# a.out
[root@localhost c]# ll mynull
crw-rw-rw-  1 root root 1, 3 Sep 19 23:21 mynull