pax_global_header00006660000000000000000000000064141425071140014511gustar00rootroot0000000000000052 comment=82d34da6f26b6a6e996d435776af6b6e498ab4dd golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/000077500000000000000000000000001414250711400220365ustar00rootroot00000000000000golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/.gitignore000066400000000000000000000004121414250711400240230ustar00rootroot00000000000000# Compiled Object files, Static and Dynamic libs (Shared Objects) *.o *.a *.so # Folders _obj _test # Architecture specific extensions/prefixes *.[568vq] [568vq].out *.cgo1.go *.cgo2.c _cgo_defun.c _cgo_gotypes.go _cgo_export.* _testmain.go *.exe *.test *.prof golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/LICENSE000066400000000000000000000261361414250711400230530ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/README.md000066400000000000000000000003031414250711400233110ustar00rootroot00000000000000# go-udev Go bindings for libudev ## Documentation Documentation is on Godoc. [![GoDoc](https://godoc.org/github.com/jochenvg/go-udev?status.svg)](https://godoc.org/github.com/jochenvg/go-udev) golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/device.go000066400000000000000000000237551414250711400236400ustar00rootroot00000000000000// +build linux,cgo package udev /* #cgo LDFLAGS: -ludev #include #include #include #include */ import "C" import "errors" import "github.com/jkeiser/iter" // Device wraps a libudev device object type Device struct { ptr *C.struct_udev_device u *Udev } // Lock the udev context func (d *Device) lock() { d.u.m.Lock() } // Unlock the udev context func (d *Device) unlock() { d.u.m.Unlock() } func deviceUnref(d *Device) { C.udev_device_unref(d.ptr) } // Parent returns the parent Device, or nil if the receiver has no parent Device func (d *Device) Parent() *Device { d.lock() defer d.unlock() ptr := C.udev_device_get_parent(d.ptr) if ptr != nil { C.udev_device_ref(ptr) } return d.u.newDevice(ptr) } // ParentWithSubsystemDevtype returns the parent Device with the given subsystem and devtype, // or nil if the receiver has no such parent device func (d *Device) ParentWithSubsystemDevtype(subsystem, devtype string) *Device { d.lock() defer d.unlock() ss, dt := C.CString(subsystem), C.CString(devtype) defer freeCharPtr(ss) defer freeCharPtr(dt) ptr := C.udev_device_get_parent_with_subsystem_devtype(d.ptr, ss, dt) if ptr != nil { C.udev_device_ref(ptr) } return d.u.newDevice(ptr) } // Devpath returns the kernel devpath value of the udev device. // The path does not contain the sys mount point, and starts with a '/'. func (d *Device) Devpath() string { d.lock() defer d.unlock() return C.GoString(C.udev_device_get_devpath(d.ptr)) } // Subsystem returns the subsystem string of the udev device. // The string does not contain any "/". func (d *Device) Subsystem() string { d.lock() defer d.unlock() return C.GoString(C.udev_device_get_subsystem(d.ptr)) } // Devtype returns the devtype string of the udev device. func (d *Device) Devtype() string { d.lock() defer d.unlock() return C.GoString(C.udev_device_get_devtype(d.ptr)) } // Sysname returns the sysname of the udev device (e.g. ttyS3, sda1...). func (d *Device) Sysname() string { d.lock() defer d.unlock() return C.GoString(C.udev_device_get_sysname(d.ptr)) } // Syspath returns the sys path of the udev device. // The path is an absolute path and starts with the sys mount point. func (d *Device) Syspath() string { d.lock() defer d.unlock() return C.GoString(C.udev_device_get_syspath(d.ptr)) } // Sysnum returns the trailing number of of the device name func (d *Device) Sysnum() string { d.lock() defer d.unlock() return C.GoString(C.udev_device_get_sysnum(d.ptr)) } // Devnode returns the device node file name belonging to the udev device. // The path is an absolute path, and starts with the device directory. func (d *Device) Devnode() string { d.lock() defer d.unlock() return C.GoString(C.udev_device_get_devnode(d.ptr)) } // IsInitialized checks if udev has already handled the device and has set up // device node permissions and context, or has renamed a network device. // // This is only implemented for devices with a device node or network interfaces. // All other devices return 1 here. func (d *Device) IsInitialized() bool { d.lock() defer d.unlock() return C.udev_device_get_is_initialized(d.ptr) != 0 } // Devlinks retrieves the map of device links pointing to the device file of the udev device. // The path is an absolute path, and starts with the device directory. func (d *Device) Devlinks() (r map[string]struct{}) { d.lock() defer d.unlock() r = make(map[string]struct{}) for l := C.udev_device_get_devlinks_list_entry(d.ptr); l != nil; l = C.udev_list_entry_get_next(l) { r[C.GoString(C.udev_list_entry_get_name(l))] = struct{}{} } return } // DevlinkIterator returns an Iterator over the device links pointing to the device file of the udev device. // The Iterator is using the github.com/jkeiser/iter package. // Values are returned as an interface{} and should be cast to string. func (d *Device) DevlinkIterator() iter.Iterator { d.lock() defer d.unlock() l := C.udev_device_get_devlinks_list_entry(d.ptr) return iter.Iterator{ Next: func() (item interface{}, err error) { d.lock() defer d.unlock() if l != nil { item = C.GoString(C.udev_list_entry_get_name(l)) l = C.udev_list_entry_get_next(l) } else { err = iter.FINISHED } return }, Close: func() { }, } } // Properties retrieves a map[string]string of key/value device properties of the udev device. func (d *Device) Properties() (r map[string]string) { d.lock() defer d.unlock() r = make(map[string]string) for l := C.udev_device_get_properties_list_entry(d.ptr); l != nil; l = C.udev_list_entry_get_next(l) { r[C.GoString(C.udev_list_entry_get_name(l))] = C.GoString(C.udev_list_entry_get_value(l)) } return } // PropertyIterator returns an Iterator over the key/value device properties of the udev device. // The Iterator is using the github.com/jkeiser/iter package. // Values are returned as an interface{} and should be cast to []string, // which will have length 2 and represent a Key/Value pair. func (d *Device) PropertyIterator() iter.Iterator { d.lock() defer d.unlock() l := C.udev_device_get_properties_list_entry(d.ptr) return iter.Iterator{ Next: func() (item interface{}, err error) { d.lock() defer d.unlock() if l != nil { item = []string{ C.GoString(C.udev_list_entry_get_name(l)), C.GoString(C.udev_list_entry_get_value(l)), } l = C.udev_list_entry_get_next(l) } else { err = iter.FINISHED } return }, Close: func() { }, } } // Tags retrieves the Set of tags attached to the udev device. func (d *Device) Tags() (r map[string]struct{}) { d.lock() defer d.unlock() r = make(map[string]struct{}) for l := C.udev_device_get_tags_list_entry(d.ptr); l != nil; l = C.udev_list_entry_get_next(l) { r[C.GoString(C.udev_list_entry_get_name(l))] = struct{}{} } return } // TagIterator returns an Iterator over the tags attached to the udev device. // The Iterator is using the github.com/jkeiser/iter package. // Values are returned as an interface{} and should be cast to string. func (d *Device) TagIterator() iter.Iterator { d.lock() defer d.unlock() l := C.udev_device_get_tags_list_entry(d.ptr) return iter.Iterator{ Next: func() (item interface{}, err error) { d.lock() defer d.unlock() if l != nil { item = C.GoString(C.udev_list_entry_get_name(l)) l = C.udev_list_entry_get_next(l) } else { err = iter.FINISHED } return }, Close: func() { }, } } // Sysattrs returns a Set with the systems attributes of the udev device. func (d *Device) Sysattrs() (r map[string]struct{}) { d.lock() defer d.unlock() r = make(map[string]struct{}) for l := C.udev_device_get_sysattr_list_entry(d.ptr); l != nil; l = C.udev_list_entry_get_next(l) { r[C.GoString(C.udev_list_entry_get_name(l))] = struct{}{} } return } // SysattrIterator returns an Iterator over the systems attributes of the udev device. // The Iterator is using the github.com/jkeiser/iter package. // Values are returned as an interface{} and should be cast to string. func (d *Device) SysattrIterator() iter.Iterator { d.lock() defer d.unlock() l := C.udev_device_get_sysattr_list_entry(d.ptr) return iter.Iterator{ Next: func() (item interface{}, err error) { d.lock() defer d.unlock() if l != nil { item = C.GoString(C.udev_list_entry_get_name(l)) l = C.udev_list_entry_get_next(l) } else { err = iter.FINISHED } return }, Close: func() { }, } } // PropertyValue retrieves the value of a device property func (d *Device) PropertyValue(key string) string { d.lock() defer d.unlock() k := C.CString(key) defer freeCharPtr(k) return C.GoString(C.udev_device_get_property_value(d.ptr, k)) } // Driver returns the driver for the receiver func (d *Device) Driver() string { d.lock() defer d.unlock() return C.GoString(C.udev_device_get_driver(d.ptr)) } // Devnum returns the device major/minor number. func (d *Device) Devnum() Devnum { d.lock() defer d.unlock() return Devnum{C.udev_device_get_devnum(d.ptr)} } // Action returns the action for the event. // This is only valid if the device was received through a monitor. // Devices read from sys do not have an action string. // Usual actions are: add, remove, change, online, offline. func (d *Device) Action() string { d.lock() defer d.unlock() return C.GoString(C.udev_device_get_action(d.ptr)) } // Seqnum returns the sequence number of the event. // This is only valid if the device was received through a monitor. // Devices read from sys do not have a sequence number. func (d *Device) Seqnum() uint64 { d.lock() defer d.unlock() return uint64(C.udev_device_get_seqnum(d.ptr)) } // UsecSinceInitialized returns the number of microseconds passed since udev set up the device for the first time. // This is only implemented for devices with need to store properties in the udev database. // All other devices return 0 here. func (d *Device) UsecSinceInitialized() uint64 { d.lock() defer d.unlock() return uint64(C.udev_device_get_usec_since_initialized(d.ptr)) } // SysattrValue retrieves the content of a sys attribute file, and returns an empty string if there is no sys attribute value. // The retrieved value is cached in the device. // Repeated calls will return the same value and not open the attribute again. func (d *Device) SysattrValue(sysattr string) string { d.lock() defer d.unlock() s := C.CString(sysattr) defer freeCharPtr(s) return C.GoString(C.udev_device_get_sysattr_value(d.ptr, s)) } // SetSysattrValue sets the content of a sys attribute file, and returns an error if this fails. func (d *Device) SetSysattrValue(sysattr, value string) (err error) { d.lock() defer d.unlock() sa, val := C.CString(sysattr), C.CString(value) defer freeCharPtr(sa) defer freeCharPtr(val) if C.udev_device_set_sysattr_value(d.ptr, sa, val) < 0 { err = errors.New("udev: udev_device_set_sysattr_value failed") } return } // HasTag checks if the udev device has the tag specified func (d *Device) HasTag(tag string) bool { d.lock() defer d.unlock() t := C.CString(tag) defer freeCharPtr(t) return C.udev_device_has_tag(d.ptr, t) != 0 } golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/device_test.go000066400000000000000000000034151414250711400246660ustar00rootroot00000000000000// +build linux package udev import ( "fmt" "runtime" "testing" ) func ExampleDevice() { // Create Udev u := Udev{} // Create new Device based on subsystem and sysname d := u.NewDeviceFromSubsystemSysname("mem", "zero") // Extract information fmt.Printf("Sysname:%v\n", d.Sysname()) fmt.Printf("Syspath:%v\n", d.Syspath()) fmt.Printf("Devpath:%v\n", d.Devpath()) fmt.Printf("Devnode:%v\n", d.Devnode()) fmt.Printf("Subsystem:%v\n", d.Subsystem()) fmt.Printf("Devtype:%v\n", d.Devtype()) fmt.Printf("Sysnum:%v\n", d.Sysnum()) fmt.Printf("IsInitialized:%v\n", d.IsInitialized()) fmt.Printf("Driver:%v\n", d.Driver()) // Use one of the iterators it := d.PropertyIterator() it.Each(func(item interface{}) { kv := item.([]string) _ = fmt.Sprintf("Property:%v=%v\n", kv[0], kv[1]) }) // Output: // Sysname:zero // Syspath:/sys/devices/virtual/mem/zero // Devpath:/devices/virtual/mem/zero // Devnode:/dev/zero // Subsystem:mem // Devtype: // Sysnum: // IsInitialized:true // Driver: } func TestDeviceZero(t *testing.T) { u := Udev{} d := u.NewDeviceFromDeviceID("c1:5") if d.Subsystem() != "mem" { t.Fail() } if d.Sysname() != "zero" { t.Fail() } if d.Syspath() != "/sys/devices/virtual/mem/zero" { t.Fail() } if d.Devnode() != "/dev/zero" { t.Fail() } if d.PropertyValue("SUBSYSTEM") != "mem" { t.Fail() } if !d.IsInitialized() { t.Fail() } if d.SysattrValue("subsystem") != "mem" { t.Fail() } // Device should have Properties properties := d.Properties() if len(properties) == 0 { t.Fail() } // Device should have Sysattrs sysattrs := d.Sysattrs() if len(sysattrs) == 0 { t.Fail() } it := d.PropertyIterator() it.Each(func(item interface{}) { _ = item.([]string) }) } func TestDeviceGC(t *testing.T) { runtime.GC() } golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/devnum.go000066400000000000000000000014671414250711400236730ustar00rootroot00000000000000// +build linux,cgo package udev /* #cgo LDFLAGS: -ludev #include #include #include #include int go_udev_major(dev_t d) { return MAJOR(d); } int go_udev_minor(dev_t d) { return MINOR(d); } dev_t go_udev_mkdev(int major, int minor) { return MKDEV(major, minor); } */ import "C" // Devnum is a kernel device number type Devnum struct { d C.dev_t } // Major returns the major part of a Devnum func (d Devnum) Major() int { return int(C.go_udev_major(d.d)) } // Minor returns the minor part of a Devnum func (d Devnum) Minor() int { return int(C.go_udev_minor(d.d)) } // MkDev creates a Devnum from a major and minor number func MkDev(major, minor int) Devnum { return Devnum{C.go_udev_mkdev((C.int)(major), (C.int)(minor))} } golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/devnum_test.go000066400000000000000000000002651414250711400247250ustar00rootroot00000000000000// +build linux package udev import "testing" func TestDevnumMajorMinor(t *testing.T) { d := MkDev(1, 8) if d.Major() != 1 { t.Fail() } if d.Minor() != 8 { t.Fail() } } golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/enumerate.go000066400000000000000000000214421414250711400243550ustar00rootroot00000000000000// +build linux,cgo package udev /* #cgo LDFLAGS: -ludev #include #include #include #include */ import "C" import ( "errors" "github.com/jkeiser/iter" ) // Enumerate is an opaque struct wrapping a udev enumerate object. type Enumerate struct { ptr *C.struct_udev_enumerate u *Udev } // Lock the udev context func (e *Enumerate) lock() { e.u.m.Lock() } // Unlock the udev context func (e *Enumerate) unlock() { e.u.m.Unlock() } // Unref the Enumerate object func enumerateUnref(e *Enumerate) { C.udev_enumerate_unref(e.ptr) } // AddMatchSubsystem adds a filter for a subsystem of the device to include in the list. func (e *Enumerate) AddMatchSubsystem(subsystem string) (err error) { e.lock() defer e.unlock() s := C.CString(subsystem) defer freeCharPtr(s) if C.udev_enumerate_add_match_subsystem(e.ptr, s) != 0 { err = errors.New("udev: udev_enumerate_add_match_subsystem failed") } return } // AddNomatchSubsystem adds a filter for a subsystem of the device to exclude from the list. func (e *Enumerate) AddNomatchSubsystem(subsystem string) (err error) { e.lock() defer e.unlock() s := C.CString(subsystem) defer freeCharPtr(s) if C.udev_enumerate_add_nomatch_subsystem(e.ptr, s) != 0 { err = errors.New("udev: udev_enumerate_add_nomatch_subsystem failed") } return } // AddMatchSysattr adds a filter for a sys attribute at the device to include in the list. func (e *Enumerate) AddMatchSysattr(sysattr, value string) (err error) { e.lock() defer e.unlock() s, v := C.CString(sysattr), C.CString(value) defer freeCharPtr(s) defer freeCharPtr(v) if C.udev_enumerate_add_match_sysattr(e.ptr, s, v) != 0 { err = errors.New("udev: udev_enumerate_add_match_sysattr failed") } return } // AddNomatchSysattr adds a filter for a sys attribute at the device to exclude from the list. func (e *Enumerate) AddNomatchSysattr(sysattr, value string) (err error) { e.lock() defer e.unlock() s, v := C.CString(sysattr), C.CString(value) defer freeCharPtr(s) defer freeCharPtr(v) if C.udev_enumerate_add_nomatch_sysattr(e.ptr, s, v) != 0 { err = errors.New("udev: udev_enumerate_add_nomatch_sysattr failed") } return } // AddMatchProperty adds a filter for a property of the device to include in the list. func (e *Enumerate) AddMatchProperty(property, value string) (err error) { e.lock() defer e.unlock() p, v := C.CString(property), C.CString(value) defer freeCharPtr(p) defer freeCharPtr(v) if C.udev_enumerate_add_match_property(e.ptr, p, v) != 0 { err = errors.New("udev: udev_enumerate_add_match_property failed") } return } // AddMatchSysname adds a filter for the name of the device to include in the list. func (e *Enumerate) AddMatchSysname(sysname string) (err error) { e.lock() defer e.unlock() s := C.CString(sysname) defer freeCharPtr(s) if C.udev_enumerate_add_match_sysname(e.ptr, s) != 0 { err = errors.New("udev: udev_enumerate_add_match_sysname failed") } return } // AddMatchTag adds a filter for a tag of the device to include in the list. func (e *Enumerate) AddMatchTag(tag string) (err error) { e.lock() defer e.unlock() t := C.CString(tag) defer freeCharPtr(t) if C.udev_enumerate_add_match_tag(e.ptr, t) != 0 { err = errors.New("udev: udev_enumerate_add_match_tag failed") } return } // AddMatchParent adds a filter for a parent Device to include in the list. func (e *Enumerate) AddMatchParent(parent *Device) (err error) { e.lock() defer e.unlock() if C.udev_enumerate_add_match_parent(e.ptr, parent.ptr) != 0 { err = errors.New("udev: udev_enumerate_add_match_parent failed") } return } // AddMatchIsInitialized adds a filter matching only devices which udev has set up already. // This makes sure, that the device node permissions and context are properly set and that network devices are fully renamed. // Usually, devices which are found in the kernel but not already handled by udev, have still pending events. // Services should subscribe to monitor events and wait for these devices to become ready, instead of using uninitialized devices. // For now, this will not affect devices which do not have a device node and are not network interfaces. func (e *Enumerate) AddMatchIsInitialized() (err error) { e.lock() defer e.unlock() if C.udev_enumerate_add_match_is_initialized(e.ptr) != 0 { err = errors.New("udev: udev_enumerate_add_match_is_initialized failed") } return } // AddSyspath adds a device to the list of enumerated devices, to retrieve it back sorted in dependency order. func (e *Enumerate) AddSyspath(syspath string) (err error) { e.lock() defer e.unlock() s := C.CString(syspath) defer freeCharPtr(s) if C.udev_enumerate_add_syspath(e.ptr, s) != 0 { err = errors.New("udev: udev_enumerate_add_syspath failed") } return } // DeviceSyspaths retrieves a list of device syspaths matching the filter, sorted in dependency order. func (e *Enumerate) DeviceSyspaths() (s []string, err error) { e.lock() defer e.unlock() if C.udev_enumerate_scan_devices(e.ptr) < 0 { err = errors.New("udev: udev_enumerate_scan_devices failed") } else { s = make([]string, 0) for l := C.udev_enumerate_get_list_entry(e.ptr); l != nil; l = C.udev_list_entry_get_next(l) { s = append(s, C.GoString(C.udev_list_entry_get_name(l))) } } return } // DeviceSyspathIterator returns an Iterator over the device syspaths matching the filter, sorted in dependency order. // The Iterator is using the github.com/jkeiser/iter package. // Values are returned as an interface{} and should be cast to string. func (e *Enumerate) DeviceSyspathIterator() (it iter.Iterator, err error) { e.lock() defer e.unlock() if C.udev_enumerate_scan_devices(e.ptr) < 0 { err = errors.New("udev: udev_enumerate_scan_devices failed") } else { l := C.udev_enumerate_get_list_entry(e.ptr) it = iter.Iterator{ Next: func() (item interface{}, err error) { e.lock() defer e.unlock() if l != nil { item = C.GoString(C.udev_list_entry_get_name(l)) l = C.udev_list_entry_get_next(l) } else { err = iter.FINISHED } return }, Close: func() { }, } } return } // SubsystemSyspaths retrieves a list of subsystem syspaths matching the filter, sorted in dependency order. func (e *Enumerate) SubsystemSyspaths() (s []string, err error) { e.lock() defer e.unlock() if C.udev_enumerate_scan_subsystems(e.ptr) < 0 { err = errors.New("udev: udev_enumerate_scan_subsystems failed") } else { s = make([]string, 0) for l := C.udev_enumerate_get_list_entry(e.ptr); l != nil; l = C.udev_list_entry_get_next(l) { s = append(s, C.GoString(C.udev_list_entry_get_name(l))) } } return } // DeviceSubsystemIterator returns an Iterator over the subsystem syspaths matching the filter, sorted in dependency order. // The Iterator is using the github.com/jkeiser/iter package. // Values are returned as an interface{} and should be cast to string. func (e *Enumerate) DeviceSubsystemIterator() (it iter.Iterator, err error) { e.lock() defer e.unlock() if C.udev_enumerate_scan_subsystems(e.ptr) < 0 { err = errors.New("udev: udev_enumerate_scan_devices failed") } else { l := C.udev_enumerate_get_list_entry(e.ptr) it = iter.Iterator{ Next: func() (item interface{}, err error) { e.lock() defer e.unlock() if l != nil { item = C.GoString(C.udev_list_entry_get_name(l)) l = C.udev_list_entry_get_next(l) } else { err = iter.FINISHED } return }, Close: func() { }, } } return } // Devices retrieves a list of Devices matching the filter, sorted in dependency order. func (e *Enumerate) Devices() (m []*Device, err error) { e.lock() defer e.unlock() if C.udev_enumerate_scan_devices(e.ptr) < 0 { err = errors.New("udev: udev_enumerate_scan_devices failed") } else { m = make([]*Device, 0) for l := C.udev_enumerate_get_list_entry(e.ptr); l != nil; l = C.udev_list_entry_get_next(l) { s := C.udev_list_entry_get_name(l) m = append(m, e.u.newDevice(C.udev_device_new_from_syspath(e.u.ptr, s))) } } return } // DeviceIterator returns an Iterator over the Devices matching the filter, sorted in dependency order. // The Iterator is using the github.com/jkeiser/iter package. // Values are returned as an interface{} and should be cast to *Device. func (e *Enumerate) DeviceIterator() (it iter.Iterator, err error) { e.lock() defer e.unlock() if C.udev_enumerate_scan_devices(e.ptr) < 0 { err = errors.New("udev: udev_enumerate_scan_devices failed") } else { l := C.udev_enumerate_get_list_entry(e.ptr) it = iter.Iterator{ Next: func() (item interface{}, err error) { e.lock() defer e.unlock() if l != nil { s := C.udev_list_entry_get_name(l) item = e.u.newDevice(C.udev_device_new_from_syspath(e.u.ptr, s)) l = C.udev_list_entry_get_next(l) } else { err = iter.FINISHED } return }, Close: func() { }, } } return } golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/enumerate_test.go000066400000000000000000000043041414250711400254120ustar00rootroot00000000000000// +build linux package udev import ( "fmt" "runtime" "testing" ) func ExampleEnumerate_DeviceSyspaths() { // Create Udev and Enumerate u := Udev{} e := u.NewEnumerate() // Enumerate all device syspaths dsp, _ := e.DeviceSyspaths() for s := range dsp { fmt.Println(s) } } func TestEnumerateDeviceSyspaths(t *testing.T) { u := Udev{} e := u.NewEnumerate() dsp, err := e.DeviceSyspaths() if err != nil { t.Fail() } if len(dsp) <= 0 { t.Fail() } } func ExampleEnumerate_SubsystemSyspaths() { // Create Udev and Enumerate u := Udev{} e := u.NewEnumerate() // Enumerate all subsystem syspaths dsp, _ := e.SubsystemSyspaths() for s := range dsp { fmt.Println(s) } } func TestEnumerateSubsystemSyspaths(t *testing.T) { u := Udev{} e := u.NewEnumerate() ssp, err := e.SubsystemSyspaths() if err != nil { t.Fail() } if len(ssp) == 0 { t.Fail() } } func ExampleEnumerate_Devices() { // Create Udev and Enumerate u := Udev{} e := u.NewEnumerate() // Add some FilterAddMatchSubsystemDevtype e.AddMatchSubsystem("block") e.AddMatchIsInitialized() devices, _ := e.Devices() for i := range devices { device := devices[i] fmt.Println(device.Syspath()) } } func TestEnumerateDevicesWithFilter(t *testing.T) { u := Udev{} e := u.NewEnumerate() e.AddMatchSubsystem("block") e.AddMatchIsInitialized() e.AddNomatchSubsystem("mem") e.AddMatchProperty("ID_TYPE", "disk") e.AddMatchSysattr("partition", "1") e.AddMatchTag("systemd") // e.AddMatchProperty("DEVTYPE", "partition") ds, err := e.Devices() if err != nil || len(ds) == 0 { fmt.Println(len(ds)) t.Fail() } for i := range ds { if ds[i].Subsystem() != "block" { t.Error("Wrong subsystem") } if !ds[i].IsInitialized() { t.Error("Not initialized") } if ds[i].PropertyValue("ID_TYPE") != "disk" { t.Error("Wrong ID_TYPE") } if ds[i].SysattrValue("partition") != "1" { t.Error("Wrong partition") } if !ds[i].HasTag("systemd") { t.Error("Not tagged") } parent := ds[i].Parent() parent2 := ds[i].ParentWithSubsystemDevtype("block", "disk") if parent.Syspath() != parent2.Syspath() { t.Error("Parent syspaths don't match") } } } func TestEnumerateGC(t *testing.T) { runtime.GC() } golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/monitor.go000066400000000000000000000137541414250711400240660ustar00rootroot00000000000000// +build linux,cgo package udev /* #cgo LDFLAGS: -ludev #include #include #include #include */ import "C" import ( "context" "errors" "syscall" "golang.org/x/sys/unix" ) // Monitor is an opaque object handling an event source type Monitor struct { ptr *C.struct_udev_monitor u *Udev } const ( maxEpollEvents = 32 epollTimeout = 1000 ) // Lock the udev context func (m *Monitor) lock() { m.u.m.Lock() } // Unlock the udev context func (m *Monitor) unlock() { m.u.m.Unlock() } // Unref the monitor func monitorUnref(m *Monitor) { C.udev_monitor_unref(m.ptr) } // SetReceiveBufferSize sets the size of the kernel socket buffer. // This call needs the appropriate privileges to succeed. func (m *Monitor) SetReceiveBufferSize(size int) (err error) { m.lock() defer m.unlock() if C.udev_monitor_set_receive_buffer_size(m.ptr, (C.int)(size)) != 0 { err = errors.New("udev: udev_monitor_set_receive_buffer_size failed") } return } // FilterAddMatchSubsystem adds a filter matching the device against a subsystem. // This filter is efficiently executed inside the kernel, and libudev subscribers will usually not be woken up for devices which do not match. // The filter must be installed before the monitor is switched to listening mode with the DeviceChan function. func (m *Monitor) FilterAddMatchSubsystem(subsystem string) (err error) { m.lock() defer m.unlock() s := C.CString(subsystem) defer freeCharPtr(s) if C.udev_monitor_filter_add_match_subsystem_devtype(m.ptr, s, nil) != 0 { err = errors.New("udev: udev_monitor_filter_add_match_subsystem_devtype failed") } return } // FilterAddMatchSubsystemDevtype adds a filter matching the device against a subsystem and device type. // This filter is efficiently executed inside the kernel, and libudev subscribers will usually not be woken up for devices which do not match. // The filter must be installed before the monitor is switched to listening mode with the DeviceChan function. func (m *Monitor) FilterAddMatchSubsystemDevtype(subsystem, devtype string) (err error) { m.lock() defer m.unlock() s, d := C.CString(subsystem), C.CString(devtype) defer freeCharPtr(s) defer freeCharPtr(d) if C.udev_monitor_filter_add_match_subsystem_devtype(m.ptr, s, d) != 0 { err = errors.New("udev: udev_monitor_filter_add_match_subsystem_devtype failed") } return } // FilterAddMatchTag adds a filter matching the device against a tag. // This filter is efficiently executed inside the kernel, and libudev subscribers will usually not be woken up for devices which do not match. // The filter must be installed before the monitor is switched to listening mode. func (m *Monitor) FilterAddMatchTag(tag string) (err error) { m.lock() defer m.unlock() t := C.CString(tag) defer freeCharPtr(t) if C.udev_monitor_filter_add_match_tag(m.ptr, t) != 0 { err = errors.New("udev: udev_monitor_filter_add_match_tag failed") } return } // FilterUpdate updates the installed socket filter. // This is only needed, if the filter was removed or changed. func (m *Monitor) FilterUpdate() (err error) { m.lock() defer m.unlock() if C.udev_monitor_filter_update(m.ptr) != 0 { err = errors.New("udev: udev_monitor_filter_update failed") } return } // FilterRemove removes all filter from the Monitor. func (m *Monitor) FilterRemove() (err error) { m.lock() defer m.unlock() if C.udev_monitor_filter_remove(m.ptr) != 0 { err = errors.New("udev: udev_monitor_filter_remove failed") } return } // receiveDevice is a helper function receiving a device while the Mutex is locked func (m *Monitor) receiveDevice() (d *Device) { m.lock() defer m.unlock() return m.u.newDevice(C.udev_monitor_receive_device(m.ptr)) } // DeviceChan binds the udev_monitor socket to the event source and spawns a // goroutine. The goroutine efficiently waits on the monitor socket using epoll. // Data is received from the udev monitor socket and a new Device is created // with the data received. Pointers to the device are sent on the returned // channel. The function takes a context as argument, which when done will stop // the goroutine and close the device channel. Only socket connections with // uid=0 are accepted. func (m *Monitor) DeviceChan(ctx context.Context) (<-chan *Device, error) { var event unix.EpollEvent var events [maxEpollEvents]unix.EpollEvent // Lock the context m.lock() defer m.unlock() // Enable receiving if C.udev_monitor_enable_receiving(m.ptr) != 0 { return nil, errors.New("udev: udev_monitor_enable_receiving failed") } // Set the fd to non-blocking fd := C.udev_monitor_get_fd(m.ptr) if e := unix.SetNonblock(int(fd), true); e != nil { return nil, errors.New("udev: unix.SetNonblock failed") } // Create an epoll fd epfd, e := unix.EpollCreate1(0) if e != nil { return nil, errors.New("udev: unix.EpollCreate1 failed") } // Add the fd to the epoll fd event.Events = unix.EPOLLIN | unix.EPOLLET event.Fd = int32(fd) if e = unix.EpollCtl(epfd, unix.EPOLL_CTL_ADD, int(fd), &event); e != nil { return nil, errors.New("udev: unix.EpollCtl failed") } // Create the channel ch := make(chan *Device) // Create goroutine to epoll the fd go func(fd int32) { // Close the epoll fd when goroutine exits defer unix.Close(epfd) // Close the channel when goroutine exits defer close(ch) // Loop forever for { // Poll the file descriptor nevents, e := unix.EpollWait(epfd, events[:], epollTimeout) // Ignore the EINTR error case since cancelation is performed with the // context's Done() channel errno, isErrno := e.(syscall.Errno) if (e != nil && !isErrno) || (isErrno && errno != syscall.EINTR) { return } // Check for done signal select { case <-ctx.Done(): return default: } // Process events for ev := 0; ev < nevents; ev++ { if events[ev].Fd == fd { if (events[ev].Events & unix.EPOLLIN) != 0 { for d := m.receiveDevice(); d != nil; d = m.receiveDevice() { ch <- d } } } } } }(int32(fd)) return ch, nil } golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/monitor_test.go000066400000000000000000000037611414250711400251220ustar00rootroot00000000000000// +build linux package udev import ( "context" "fmt" "runtime" "sync" "testing" "time" ) func ExampleMonitor() { // Create Udev and Monitor u := Udev{} m := u.NewMonitorFromNetlink("udev") // Add filters to monitor m.FilterAddMatchSubsystemDevtype("block", "disk") m.FilterAddMatchTag("systemd") // Create a context ctx, cancel := context.WithCancel(context.Background()) // Start monitor goroutine and get receive channel ch, _ := m.DeviceChan(ctx) // WaitGroup for timers var wg sync.WaitGroup wg.Add(3) go func() { fmt.Println("Started listening on channel") for d := range ch { fmt.Println("Event:", d.Syspath(), d.Action()) } fmt.Println("Channel closed") wg.Done() }() go func() { fmt.Println("Starting timer to update filter") <-time.After(2 * time.Second) fmt.Println("Removing filter") m.FilterRemove() fmt.Println("Updating filter") m.FilterUpdate() wg.Done() }() go func() { fmt.Println("Starting timer to signal done") <-time.After(4 * time.Second) fmt.Println("Signalling done") cancel() wg.Done() }() wg.Wait() } func TestMonitorDeviceChan(t *testing.T) { u := Udev{} m := u.NewMonitorFromNetlink("udev") m.FilterAddMatchSubsystemDevtype("block", "disk") m.FilterAddMatchTag("systemd") ctx, cancel := context.WithCancel(context.Background()) ch, e := m.DeviceChan(ctx) if e != nil { t.Fail() } var wg sync.WaitGroup wg.Add(3) go func() { fmt.Println("Started listening on channel") for d := range ch { fmt.Println(d.Syspath(), d.Action()) } fmt.Println("Channel closed") wg.Done() }() go func() { fmt.Println("Starting timer to update filter") <-time.After(2 * time.Second) fmt.Println("Removing filter") m.FilterRemove() fmt.Println("Updating filter") m.FilterUpdate() wg.Done() }() go func() { fmt.Println("Starting timer to signal done") <-time.After(4 * time.Second) fmt.Println("Signalling done") cancel() wg.Done() }() wg.Wait() } func TestMonitorGC(t *testing.T) { runtime.GC() } golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/udev.go000066400000000000000000000114721414250711400233350ustar00rootroot00000000000000// +build linux,cgo // Package udev provides a cgo wrapper around the libudev C library package udev /* #cgo LDFLAGS: -ludev #include #include #include #include */ import "C" import ( "runtime" "sync" ) // Udev is an opaque struct wraping a udev library context type Udev struct { // A pointer to the C struct udev context ptr *C.struct_udev // Mutex for thread sync as libudev is not thread safe when called with the same struct udev m sync.Mutex once sync.Once } func udevUnref(u *Udev) { C.udev_unref(u.ptr) } // Lock locks a udev context func (u *Udev) lock() { u.once.Do(func() { u.ptr = C.udev_new() runtime.SetFinalizer(u, udevUnref) }) u.m.Lock() } // Unlock unlocks a udev context func (u *Udev) unlock() { u.m.Unlock() } // newDevice is a private helper function and returns a pointer to a new device. // The device is also added t the devices map in the udev context. // The agrument ptr is a pointer to the underlying C udev_device structure. // The function returns nil if the pointer passed is NULL. func (u *Udev) newDevice(ptr *C.struct_udev_device) (d *Device) { // If passed a NULL pointer, return nil if ptr == nil { return nil } // Create a new device object d = &Device{ ptr: ptr, u: u, } runtime.SetFinalizer(d, deviceUnref) // Return the device object return } // newMonitor is a private helper function and returns a pointer to a new monitor. // The monitor is also added t the monitors map in the udev context. // The agrument ptr is a pointer to the underlying C udev_monitor structure. // The function returns nil if the pointer passed is NULL. func (u *Udev) newMonitor(ptr *C.struct_udev_monitor) (m *Monitor) { // If passed a NULL pointer, return nil if ptr == nil { return nil } // Create a new device object m = &Monitor{ ptr: ptr, u: u, } runtime.SetFinalizer(m, monitorUnref) // Return the device object return } func (u *Udev) newEnumerate(ptr *C.struct_udev_enumerate) (e *Enumerate) { // If passed a NULL pointer, return nil if ptr == nil { return nil } // Create a new device object e = &Enumerate{ ptr: ptr, u: u, } runtime.SetFinalizer(e, enumerateUnref) // Return the device object return } // NewDeviceFromSyspath returns a pointer to a new device identified by its syspath, and nil on error // The device is identified by the syspath argument func (u *Udev) NewDeviceFromSyspath(syspath string) *Device { // Lock the udev context u.lock() defer u.unlock() // Convert Go strings to C strings for passing s := C.CString(syspath) defer freeCharPtr(s) // Return a new device return u.newDevice(C.udev_device_new_from_syspath(u.ptr, s)) } // NewDeviceFromDevnum returns a pointer to a new device identified by its Devnum, and nil on error // deviceType is 'c' for a character device and 'b' for a block device func (u *Udev) NewDeviceFromDevnum(deviceType uint8, n Devnum) *Device { u.lock() defer u.unlock() return u.newDevice(C.udev_device_new_from_devnum(u.ptr, C.char(deviceType), n.d)) } // NewDeviceFromSubsystemSysname returns a pointer to a new device identified by its subystem and sysname, and nil on error func (u *Udev) NewDeviceFromSubsystemSysname(subsystem, sysname string) *Device { u.lock() defer u.unlock() ss, sn := C.CString(subsystem), C.CString(sysname) defer freeCharPtr(ss) defer freeCharPtr(sn) return u.newDevice(C.udev_device_new_from_subsystem_sysname(u.ptr, ss, sn)) } // NewDeviceFromDeviceID returns a pointer to a new device identified by its device id, and nil on error func (u *Udev) NewDeviceFromDeviceID(id string) *Device { u.lock() defer u.unlock() i := C.CString(id) defer freeCharPtr(i) return u.newDevice(C.udev_device_new_from_device_id(u.ptr, i)) } // NewEnumerate returns a pointer to a new enumerate, and nil on error func (u *Udev) NewEnumerate() *Enumerate { u.lock() defer u.unlock() return u.newEnumerate(C.udev_enumerate_new(u.ptr)) } // NewMonitorFromNetlink returns a pointer to a new monitor listening to a NetLink socket, and nil on error // The name argument is either "kernel" or "udev". // When passing "kernel" the events are received before they are processed by udev. // When passing "udev" the events are received after udev has processed the events and created device nodes. // In most cases you will want to use "udev". func (u *Udev) NewMonitorFromNetlink(name string) *Monitor { u.lock() defer u.unlock() n := C.CString(name) defer freeCharPtr(n) return u.newMonitor(C.udev_monitor_new_from_netlink(u.ptr, n)) } /* // NewMonitorFromSocket returns a pointer to a new monitor listening to the specified socket, and nil on error func (u *Udev) NewMonitorFromSocket(socketPath string) *Monitor { u.lock() defer u.unlock() s := C.CString(socketPath) defer freeCharPtr(s) return u.newMonitor(C.udev_monitor_new_from_socket(u.ptr, s)) } */ golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/udev_test.go000066400000000000000000000042501414250711400243700ustar00rootroot00000000000000// +build linux package udev import ( "fmt" "testing" ) func ExampleUdev_NewDeviceFromDevnum() { u := Udev{} d := u.NewDeviceFromDevnum('c', MkDev(1, 8)) fmt.Println(d.Syspath()) // Output: // /sys/devices/virtual/mem/random } func TestNewDeviceFromDevnum(t *testing.T) { u := Udev{} d := u.NewDeviceFromDevnum('c', MkDev(1, 8)) if d.Devnum().Major() != 1 { t.Fail() } if d.Devnum().Minor() != 8 { t.Fail() } if d.Devpath() != "/devices/virtual/mem/random" { t.Fail() } } func ExampleUdev_NewDeviceFromSyspath() { u := Udev{} d := u.NewDeviceFromSyspath("/sys/devices/virtual/mem/random") fmt.Println(d.Syspath()) // Output: // /sys/devices/virtual/mem/random } func TestNewDeviceFromSyspath(t *testing.T) { u := Udev{} d := u.NewDeviceFromSyspath("/sys/devices/virtual/mem/random") if d.Devnum().Major() != 1 { t.Fail() } if d.Devnum().Minor() != 8 { t.Fail() } if d.Devpath() != "/devices/virtual/mem/random" { t.Fail() } } func ExampleUdev_NewDeviceFromSubsystemSysname() { u := Udev{} d := u.NewDeviceFromSubsystemSysname("mem", "random") fmt.Println(d.Syspath()) // Output: // /sys/devices/virtual/mem/random } func TestNewDeviceFromSubsystemSysname(t *testing.T) { u := Udev{} d := u.NewDeviceFromSubsystemSysname("mem", "random") if d.Devnum().Major() != 1 { t.Fail() } if d.Devnum().Minor() != 8 { t.Fail() } if d.Devpath() != "/devices/virtual/mem/random" { t.Fail() } } func ExampleUdev_NewDeviceFromDeviceID() { u := Udev{} d := u.NewDeviceFromDeviceID("c1:8") fmt.Println(d.Syspath()) // Output: // /sys/devices/virtual/mem/random } func TestNewDeviceFromDeviceID(t *testing.T) { u := Udev{} d := u.NewDeviceFromDeviceID("c1:8") if d.Devnum().Major() != 1 { t.Fail() } if d.Devnum().Minor() != 8 { t.Fail() } if d.Devpath() != "/devices/virtual/mem/random" { t.Fail() } } func ExampleUdev_NewMonitorFromNetlink() { u := Udev{} _ = u.NewMonitorFromNetlink("udev") } func TestNewMonitorFromNetlink(t *testing.T) { u := Udev{} _ = u.NewMonitorFromNetlink("udev") } func ExampleUdev_NewEnumerate() { u := Udev{} _ = u.NewEnumerate() } func TestNewEnumerate(t *testing.T) { u := Udev{} _ = u.NewEnumerate() } golang-github-jochenvg-go-udev-0.0~git20171110.d6b62d5/util.go000066400000000000000000000003731414250711400233450ustar00rootroot00000000000000// +build linux,cgo package udev /* #cgo LDFLAGS: -ludev #include #include #include #include */ import "C" import "unsafe" func freeCharPtr(s *C.char) { C.free(unsafe.Pointer(s)) }