Skip to content

Commit 85d1495

Browse files
tklauserianlancetaylor
authored andcommitted
unix: add Major, Minor and Mkdev functions on Linux
Add Major, Minor and Mkdev functions for converting devices numbers to their major/minor components and vice versa. The functions follow the behavior of glibc's corresponding macros. Also add an explanatory comment about the device number format, so the magic numbers make more sense. Test the conversion macros with some well-known device numbers for devices which should be present on any Linux system. Fixes golang/go#8106 Change-Id: Id336317985d6ac85ee83bc54e5f23703257c9121 Reviewed-on: https://go-review.googlesource.com/50550 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
1 parent a7f1d9e commit 85d1495

File tree

2 files changed

+93
-0
lines changed

2 files changed

+93
-0
lines changed

unix/dev_linux.go

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
// Functions to access/create device major and minor numbers matching the
6+
// encoding used by the Linux kernel and glibc.
7+
//
8+
// The information below is extracted and adapted from bits/sysmacros.h in the
9+
// glibc sources:
10+
//
11+
// dev_t in glibc is 64-bit, with 32-bit major and minor numbers. glibc's
12+
// default encoding is MMMM Mmmm mmmM MMmm, where M is a hex digit of the major
13+
// number and m is a hex digit of the minor number. This is backward compatible
14+
// with legacy systems where dev_t is 16 bits wide, encoded as MMmm. It is also
15+
// backward compatible with the Linux kernel, which for some architectures uses
16+
// 32-bit dev_t, encoded as mmmM MMmm.
17+
18+
package unix
19+
20+
// Major returns the major component of a Linux device number.
21+
func Major(dev uint64) uint32 {
22+
major := uint32((dev & 0x00000000000fff00) >> 8)
23+
major |= uint32((dev & 0xfffff00000000000) >> 32)
24+
return major
25+
}
26+
27+
// Minor returns the minor component of a Linux device number.
28+
func Minor(dev uint64) uint32 {
29+
minor := uint32((dev & 0x00000000000000ff) >> 0)
30+
minor |= uint32((dev & 0x00000ffffff00000) >> 12)
31+
return minor
32+
}
33+
34+
// Mkdev returns a Linux device number generated from the given major and minor
35+
// components.
36+
func Mkdev(major, minor uint32) uint64 {
37+
dev := uint64((major & 0x00000fff) << 8)
38+
dev |= uint64((major & 0xfffff000) << 32)
39+
dev |= uint64((minor & 0x000000ff) << 0)
40+
dev |= uint64((minor & 0xffffff00) << 12)
41+
return dev
42+
}

unix/dev_linux_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Copyright 2017 The Go Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package unix_test
6+
7+
import (
8+
"fmt"
9+
"testing"
10+
11+
"golang.org/x/sys/unix"
12+
)
13+
14+
func TestDevices(t *testing.T) {
15+
testCases := []struct {
16+
path string
17+
major uint32
18+
minor uint32
19+
}{
20+
// well known major/minor numbers according to
21+
// https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/admin-guide/devices.txt
22+
{"/dev/null", 1, 3},
23+
{"/dev/zero", 1, 5},
24+
{"/dev/random", 1, 8},
25+
{"/dev/full", 1, 7},
26+
{"/dev/urandom", 1, 9},
27+
{"/dev/tty", 5, 0},
28+
}
29+
for _, tc := range testCases {
30+
t.Run(fmt.Sprintf("%s %v:%v", tc.path, tc.major, tc.minor), func(t *testing.T) {
31+
var stat unix.Stat_t
32+
err := unix.Stat(tc.path, &stat)
33+
if err != nil {
34+
t.Errorf("failed to stat device: %v", err)
35+
return
36+
}
37+
38+
dev := uint64(stat.Rdev)
39+
if unix.Major(dev) != tc.major {
40+
t.Errorf("for %s Major(%#x) == %d, want %d", tc.path, dev, unix.Major(dev), tc.major)
41+
}
42+
if unix.Minor(dev) != tc.minor {
43+
t.Errorf("for %s Minor(%#x) == %d, want %d", tc.path, dev, unix.Minor(dev), tc.minor)
44+
}
45+
if unix.Mkdev(tc.major, tc.minor) != dev {
46+
t.Errorf("for %s Mkdev(%d, %d) == %#x, want %#x", tc.path, tc.major, tc.minor, unix.Mkdev(tc.major, tc.minor), dev)
47+
}
48+
})
49+
50+
}
51+
}

0 commit comments

Comments
 (0)