How to convert between dev_t and major / minor numbers?

I am trying to write a portable program that deals with ustar archives. For device files, these archives store major and minor device numbers. However struct stat, as indicated in POSIX, it contains only one member of the st_rdevtype dev_tdescribed in "Device ID (if the file is a character or special block)."

How can I convert a pair of major and minor device numbers and one member st_rdevreturned in a stat()portable way?

+4
source share
3 answers

While all POSIX programming interfaces use the device (type dev_t) number as it is, FUZxxl pointed out in a comment on this answer that the common UStar file format - the most common tar archive format - divides the device number into primary and minor. (Usually they are encoded as seven octal digits, so for compatibility reasons you should restrict yourself to a 21-bit unsigned major and a 21-bit unsigned minor. This also means that matching the device number only with the primary or only with the minor is not a reliable approach.)

, , ( makedev(), major(), minor()), .

#if defined(custom_makedev) && defined(custom_major) && defined(custom_minor)
/* Already defined */
#else

#undef custom_makedev
#undef custom_major
#undef custom_minor

#if defined(__linux__) || defined(__GLIBC__)
/* Linux, Android, and other systems using GNU C library */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum)           major(devnum)
#define custom_minor(devnum)           minor(devnum)

#elif defined(_WIN32)
/* 32- and 64-bit Windows. VERIFY: These are just a guess! */
#define custom_makedev(dmajor, dminor) ((((unsigned int)dmajor << 8) & 0xFF00U) | ((unsigned int)dminor & 0xFFFF00FFU))
#define custom_major(devnum)           (((unsigned int)devnum & 0xFF00U) >> 8)
#define custom_minor(devnum)           ((unsigned int)devnum & 0xFFFF00FFU)

#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
/* FreeBSD, OpenBSD, NetBSD, and DragonFlyBSD */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum)           major(devnum)
#define custom_minor(devnum)           minor(devnum)

#elif defined(__APPLE__) && defined(__MACH__)
/* Mac OS X */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum)           major(devnum)
#define custom_minor(devnum)           minor(devnum)

#elif defined(_AIX) || defined (__osf__)
/* AIX, OSF/1, Tru64 Unix */
#include <sys/types.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum)           major(devnum)
#define custom_minor(devnum)           minor(devnum)

#elif defined(hpux)
/* HP-UX */
#include <sys/sysmacros.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum)           major(devnum)
#define custom_minor(devnum)           minor(devnum)

#elif defined(sun)
/* Solaris */
#include <sys/types.h>
#include <sys/mkdev.h>
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum)           major(devnum)
#define custom_minor(devnum)           minor(devnum)

#else
/* Unknown OS. Try a the BSD approach. */
#ifndef _BSD_SOURCE
#define _BSD_SOURCE 1
#endif
#include <sys/types.h>
#if defined(makedev) && defined(major) && defined(minor)
#define custom_makedev(dmajor, dminor) makedev(dmajor, dminor)
#define custom_major(devnum)           major(devnum)
#define custom_minor(devnum)           minor(devnum)
#endif
#endif

#if !defined(custom_makedev) || !defined(custom_major) || !defined(custom_minor)
#error Unknown OS: please add definitions for custom_makedev(), custom_major(), and custom_minor(), for device number major/minor handling.
#endif

#endif

, UStar-. /, , .

GNU C, Linux ( Android), FreeBSD, OpenBSD, NetBSD, DragonFlyBSD, Mac OS X, AIX, Tru64, HP-UX Solaris, , , <sys/types.h> . Windows .

, Windows 0 HANDLE ( void) . , Windows, 8 , 8 - , , , , ( ) . tar- USTAR , Windows.

, BSD , . ( , , , , find, xargs grep, , . touch empty.h ; cpp -dM empty.h ; rm -f empty.h , / C.)

POSIX , dev_t ( , float double ), IEEE Std 1003.1, 2013 , . , POSIX-y dev_t . , Windows void HANDLE, Windows POSIX.

+3

major() minor() BSD_SOURCE.

makedev(), major() minor()        POSIX.1, .

http://man7.org/linux/man-pages/man3/major.3.html

+2

, ls Minix, . - () , . , GCC #pragma GCC diagnostic ignored .. (, clang -Weverything), -Wunused-macros, .

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-macros"
/* Defines to ensure major and minor macros are available */
#define _DARWIN_C_SOURCE    /* In <sys/types.h> on MacOS X */
#define _BSD_SOURCE         /* In <sys/sysmacros.h> via <sys/types.h> on Linux (Ubuntu 12.0.4) */
#define __EXTENSIONS__      /* Maybe beneficial on Solaris */
#pragma GCC diagnostic pop

/* From Solaris 2.6 sys/sysmacros.h
**
** WARNING: The device number macros defined here should not be used by
** device drivers or user software. [...]  Application software should make
** use of the library routines available in makedev(3). [...]  Macro
** routines bmajor(), major(), minor(), emajor(), eminor(), and makedev()
** will be removed or their definitions changed at the next major release
** following SVR4.
**
** #define  O_BITSMAJOR 7       -- # of SVR3 major device bits
** #define  O_BITSMINOR 8       -- # of SVR3 minor device bits
** #define  O_MAXMAJ    0x7f    -- SVR3 max major value
** #define  O_MAXMIN    0xff    -- SVR3 max major value
**
** #define  L_BITSMAJOR 14      -- # of SVR4 major device bits
** #define  L_BITSMINOR 18      -- # of SVR4 minor device bits
** #define  L_MAXMAJ    0x3fff  -- SVR4 max major value
** #define  L_MAXMIN    0x3ffff -- MAX minor for 3b2 software drivers.
** -- For 3b2 hardware devices the minor is restricted to 256 (0-255)
*/

/* AC_HEADER_MAJOR:
** - defines MAJOR_IN_MKDEV if found in sys/mkdev.h
** - defines MAJOR_IN_SYSMACROS if found in sys/macros.h
** - otherwise, hope they are in sys/types.h
*/

#if defined MAJOR_IN_MKDEV
#include <sys/mkdev.h>
#elif defined MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
#elif defined(MAJOR_MINOR_MACROS_IN_SYS_TYPES_H)
/* MacOS X 10.2 - for example */
/* MacOS X 10.5 requires -D_DARWIN_C_SOURCE or -U_POSIX_C_SOURCE - see above */
#elif defined(USE_CLASSIC_MAJOR_MINOR_MACROS)
#define major(x)    ((x>>8) & 0x7F)
#define minor(x)    (x & 0xFF)
#else
/* Hope the macros are in <sys/types.h> or otherwise magically visible */
#endif

#define MAJOR(x)    ((long)major(x))
#define MINOR(x)    ((long)minor(x))

, , ", ... " .

AC_HEADER_MAJOR autoconf, . , config.h, autoconf.

POSIX

, POSIX pax ustar , devmajor devminor , :

... . devmajor devminor , , POSIX.1-2008. .

, . ( ); . ustar , ( ) - .

+1

Source: https://habr.com/ru/post/1628710/


All Articles