diskarbitration

package module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 30, 2026 License: BSD-3-Clause Imports: 8 Imported by: 0

README

go-macos/diskarbitration

ci Go Reference License

Apple's DiskArbitration framework from pure Go, CGO_ENABLED=0: which block devices exist, which volume is mounted where, and how to take one away politely. No cgo, no hdiutil, no diskutil, no plist parsing — it reaches the framework through purego, and its run loop through go-macos/objc.

s, err := diskarbitration.Open()
if err != nil {
	return err
}
defer s.Close()

for _, d := range must(s.Mounts()) {
	fmt.Println(d)
}
// disk3s1s1 4.0 TB "Macintosh HD" [apfs] on / (read-only, Apple Fabric)
// disk3s5   4.0 TB "Data"         [apfs] on /System/Volumes/Data (encrypted, Apple Fabric)

Why

A program that attaches a disk image needs three answers macOS will not give it from the filesystem alone:

  • Which /dev node did my image become?
  • Where did the system mount it?
  • How do I detach it without corrupting it?

Today those answers come from running hdiutil and diskutil and parsing their output — a subprocess, a plist parse, and a text format Apple never promised to keep stable. DiskArbitration is the service those tools themselves talk to.

The boundary

This package decodes no filesystem format. Not APFS, not HFS+, not FAT, not a partition map. It asks a macOS daemon what that daemon already believes and reports the answer. Description.VolumeKind is a label macOS handed over ("apfs", "hfs", "msdos"); nothing here parsed a superblock to earn it.

Filesystem decoding go-filesystems — 18 drivers behind go-filesystems/interface, OS-independent by construction.
Asking macOS this package.
Asking Linux go-fsctl, its own org, for the same reason.

Two OS-specific packages that ask their own system; one OS-independent org that reads bytes. The moment a superblock is parsed here, that independence is gone and one of those drivers has been forked into a macOS-only copy.

The API

Open() (*Session, error) DASessionCreate + a CFRunLoop on a dedicated thread.
(*Session) Close() error unregisters, unschedules, stops, releases. Idempotent.
(*Session) Disks() ([]string, error) the BSD names, in device order.
(*Session) Describe(name) (*Description, error) DADiskCreateFromBSDName + DADiskCopyDescription.
(*Session) DescribeAll() ([]*Description, error) every device; skips ones that vanish mid-scan.
(*Session) Mounts() ([]*Description, error) only the volumes that are mounted.
(*Session) Unmount(name, UnmountOptions) error DADiskUnmount, made synchronous.
(*Session) Eject(name) error DADiskEject, made synchronous.
(*Session) Watch(func(Event)) (*Watcher, error) DARegisterDiskAppeared / DiskDisappeared.
ValidName(string) bool is this a diskN[sM[sK]] name?

Description carries the typed fields (BSDName, MediaSize, Whole, Leaf, Removable, Ejectable, Writable, VolumePath, VolumeName, VolumeKind, Protocol, …) plus Raw, the whole description dictionary converted to Go values — because the typed fields are a selection, and needing a key nobody anticipated should not mean forking the package.

Registering a watch replays what is already there

w, err := s.Watch(func(e diskarbitration.Event) { events <- e })
defer w.Stop()

DiskArbitration delivers an Appeared event for every disk already present the moment the callback is registered. So a program that wants "what is here, and then what changes" needs only Watch — no separate enumeration, and no window between the two in which a disk could slip through unseen.

Callbacks run on the run-loop thread. Everything else the session does asynchronously — the completion of an Unmount, every other event — waits behind your handler. Send to a channel and return.

Unmount is not eject

The media must already be unmounted before it can be ejected; eject a mounted volume and the daemon answers busy. So detaching a disk image is two calls:

if err := s.Unmount(whole, diskarbitration.UnmountWhole); err != nil {
	return err
}
return s.Eject(whole)

UnmountWhole takes down every volume of the whole disk. UnmountForce is not a stronger request but a different one: open files are forcibly closed and another process's unwritten data may be lost.

Refusals say why, in the spelling macOS actually used

DADissenterGetStatus's documentation says a BSD return code "is encoded with unix_err()", and it means it. Measured on macOS 26.6.2, refusing to unmount a volume with an open file on it answers 0x0000C010 — not in the kDAReturn family at all. It is unix_err(EBUSY).

A binding that only knows the kDAReturn constants therefore reports the one failure everybody actually meets as an unrecognised number. This one decodes both:

diskarbitration: unmount disk4s1: EBUSY
Advice: Something still has the volume open. Close it, or unmount with the Force option.

errors.As into *DiskError for Op, Disk, Status and the daemon's own Message; Status.Errno() for the errno when there is one; Status.Advice() for the sentence to put in front of a person.

Enumeration reads /dev

DiskArbitration has no "list" call. Its own way to enumerate is the appearance replay above — which needs a run loop, a registration, and a guess at how long to wait before deciding the replay is over. Disks() scans /dev instead, which is exact and immediate; the two were checked against each other on a live machine and reported the same twenty devices.

Every platform

macOS only, but every symbol exists everywhere and every operation reports ErrUnsupported off darwin, so a consumer cross-compiles without build tags of its own. Verified building and vetting on windows/{amd64,arm64}, linux/{amd64,arm64,riscv64,s390x,ppc64le,loong64}, darwin/amd64, android/arm64 and js/wasm.

The OS-independent half — the BSD-name grammar, the ordering, the description typing, the DAReturn vocabulary, the session guards — is run, not merely compiled, on all six of Go's 64-bit architectures.

Tests do not touch this machine's disks

Coverage is 100 %, statement for statement, on darwin and off it. That is reached through seams, not through disks: every bound C entry point is a package variable, so a test can make DASessionCreate answer NULL, make an unmount go unanswered, or hand cfValue a CFData, without a device being involved.

The live suite talks to the real daemon, and is read-only about the machine's media. The two tests that exercise the write path aim at a BSD name they first prove is not a device, and assert the daemon refuses. The one test that needs a disk to actually disappear creates a small image of its own, attaches it with -nomount, and detaches that — never a device it did not create.

cmd/dalist

go run github.com/go-macos/diskarbitration/cmd/dalist@latest -l

Read-only: one line per device, -l for every description key, -mounts for the mounted ones, -watch 10s to follow appearances and disappearances.

Install

go get github.com/go-macos/diskarbitration

BSD-3-Clause.

Documentation

Overview

Package diskarbitration binds Apple's DiskArbitration framework: the macOS service that knows which block devices exist, which volume is mounted where, and how to take one away again politely.

What this package is for

A program that manipulates disk images needs three answers macOS will not give it from the filesystem alone. Which /dev node did my image become? Where did the system mount it? How do I detach it without corrupting it? Today those answers are obtained by running hdiutil and diskutil and parsing their output — a subprocess, a plist parse, and a text format Apple never promised to keep. DiskArbitration is the service those tools themselves talk to.

The boundary — read this before adding anything

THIS PACKAGE DECODES NO FILESYSTEM FORMAT. Not APFS, not HFS+, not FAT, not a partition map. It asks a macOS daemon what that daemon already believes and reports the answer. Description.VolumeKind is a label macOS handed over ("apfs", "hfs", "msdos"); nothing here has parsed a superblock to earn it.

Filesystem decoding lives in the go-filesystems org, behind github.com/go-filesystems/interface, and it is OS-independent by construction: eighteen drivers that read bytes and do not know what host they are on. The moment a superblock is parsed here, that independence is gone and one of those drivers has been forked into a macOS-only copy.

The Linux counterpart of THIS package — talking to a kernel that also already knows — is github.com/go-fsctl, in its own org, for the same reason. Two OS-specific packages that ask their own system, one OS-independent org that reads bytes. Keep them apart.

Shape of the API

Everything hangs off a Session:

s, err := diskarbitration.Open()
if err != nil { return err }
defer s.Close()

for _, d := range must(s.DescribeAll()) {
    fmt.Println(d)
}

Session.Disks enumerates the BSD names, Session.Describe answers with a Description, Session.Unmount and Session.Eject take a volume away, and Session.Watch delivers an Event each time a disk appears or disappears.

The run loop

DiskArbitration is asynchronous: unmount, eject and the appearance callbacks are delivered on a CFRunLoop, and a process that never runs one never hears them. Open therefore starts one on a dedicated, thread-pinned goroutine — github.com/go-macos/objc's Run, not a loop written here — and Session.Close stops it. Reads (Session.Describe) are synchronous and do not depend on it, but they are served from the same session so a caller has one object to keep and one thing to close.

Callbacks are invoked ON that run-loop thread. A handler that blocks stops every other event, including the completion of an unmount somebody is waiting for. Hand the event to a channel and return.

Platforms

macOS only. Every symbol exists on every platform and every operation reports ErrUnsupported elsewhere, so a consumer cross-compiles without build tags of its own. CGO_ENABLED=0 throughout: the framework is reached with purego, never cgo.

Index

Constants

View Source
const (
	KeyVolumePath      = "DAVolumePath"
	KeyVolumeName      = "DAVolumeName"
	KeyVolumeKind      = "DAVolumeKind"
	KeyVolumeMountable = "DAVolumeMountable"
	KeyVolumeNetwork   = "DAVolumeNetwork"
	KeyVolumeUUID      = "DAVolumeUUID"

	KeyMediaBSDName   = "DAMediaBSDName"
	KeyMediaName      = "DAMediaName"
	KeyMediaSize      = "DAMediaSize"
	KeyMediaBlockSize = "DAMediaBlockSize"
	KeyMediaWhole     = "DAMediaWhole"
	KeyMediaLeaf      = "DAMediaLeaf"
	KeyMediaRemovable = "DAMediaRemovable"
	KeyMediaEjectable = "DAMediaEjectable"
	KeyMediaWritable  = "DAMediaWritable"
	KeyMediaEncrypted = "DAMediaEncrypted"
	KeyMediaContent   = "DAMediaContent"
	KeyMediaPath      = "DAMediaPath"

	KeyDeviceProtocol = "DADeviceProtocol"
	KeyDeviceModel    = "DADeviceModel"
	KeyDeviceVendor   = "DADeviceVendor"
	KeyDeviceRevision = "DADeviceRevision"
	KeyDeviceInternal = "DADeviceInternal"
	KeyDevicePath     = "DADevicePath"

	KeyBusName = "DABusName"
	KeyBusPath = "DABusPath"

	KeyAppearanceTime = "DAAppearanceTime"
)

The DADiskDescription keys, as the strings DiskArbitration actually uses.

Apple documents these as kDADiskDescription*Key, each an exported CFStringRef VARIABLE. Reading one means dereferencing an exported data pointer, which is exactly what go vet's unsafeptr check rejects — and the value it holds is the literal spelled here. CoreFoundation dictionaries hash and compare CFStrings by content, so a key built from the literal finds the same entry. This is the same trade github.com/go-macos/objc makes for kCFRunLoopDefaultMode, and the values below were read back off a live description dictionary rather than transcribed from a header.

View Source
const (
	// ModelDiskImage is the DADeviceModel of an attached image.
	ModelDiskImage = "Disk Image"
	// ProtocolVirtualInterface is the DADeviceProtocol of an attached image
	// on current macOS.
	ProtocolVirtualInterface = "Virtual Interface"
)

How macOS marks a device that is an attached disk image rather than hardware. This is the answer to "which of these is my DMG": a caller that attached an image and wants its /dev node keeps the descriptions Description.IsDiskImage accepts.

The two constants are BOTH needed, and which one carries the mark has moved. Measured on macOS 26.0 (arm64) against a freshly attached image: the protocol is "Virtual Interface" and it is the MODEL that says "Disk Image". Older releases — and much code written against them — put "Disk Image" in the protocol. Neither is checked alone here, because a binding that picked the wrong one would answer "no disk images attached" on half the fleet and give no hint why.

View Source
const Framework = "/System/Library/Frameworks/DiskArbitration.framework/DiskArbitration"

Framework is the DiskArbitration framework's path, opened by the darwin half on first use. It is exported because a caller that loads frameworks of its own has one list to keep, not two.

Variables

View Source
var (
	// ErrUnsupported is returned by every operation on non-darwin platforms.
	// DiskArbitration is macOS-only; the symbols exist everywhere so
	// consumers cross-compile without build tags of their own.
	ErrUnsupported = errors.New("diskarbitration: unsupported on this platform (darwin only)")

	// ErrNoSession reports that DASessionCreate returned NULL. It is not a
	// disk-level failure: the process could not reach the arbitration daemon
	// at all, and nothing else in this package will work until it can.
	ErrNoSession = errors.New("diskarbitration: DASessionCreate returned no session")

	// ErrClosed reports use of a [Session] after [Session.Close].
	ErrClosed = errors.New("diskarbitration: session is closed")

	// ErrNoDisk reports that DADiskCreateFromBSDName returned NULL.
	//
	// It is RARE, and it does not mean "no such device". Creating a DADisk
	// reference is a local operation that does not consult the daemon:
	// measured on macOS 26.6.2, asking for "disk99" — a device that does not
	// exist — succeeds and yields a perfectly good reference. NULL here means
	// the framework could not allocate at all, or the session is unusable.
	// The absence of a device shows up as [ErrNoDescription].
	ErrNoDisk = errors.New("diskarbitration: no such disk")

	// ErrNoDescription reports that DADiskCopyDescription returned NULL,
	// which is what "there is no such device" actually looks like — see
	// [ErrNoDisk] for why the two are the other way round from what the
	// names suggest.
	//
	// It is also what a caller sees when a disk vanishes BETWEEN the
	// enumeration and the description: a removable drive being unplugged, or
	// a disk image detaching underneath. [Session.DescribeAll] skips those
	// rather than failing the whole listing.
	ErrNoDescription = errors.New("diskarbitration: disk has no description (it may have gone away)")

	// ErrBadName reports a BSD name that is not of the form macOS uses for a
	// block device: diskN, diskNsM, or diskNsMsK for an APFS volume inside a
	// container. It is checked BEFORE the name reaches C, because the name
	// crosses as a NUL-terminated string and an embedded NUL would silently
	// truncate it into a different, existing device.
	ErrBadName = errors.New("diskarbitration: not a BSD disk name")
)

Sentinel errors. They are stable and may be compared with errors.Is.

Functions

func ValidName

func ValidName(name string) bool

ValidName reports whether name is a macOS block-device name this package will speak about. Use it to check a name from a configuration file or a user before handing it to Session.Describe.

Types

type Description

type Description struct {
	// BSDName is the device node's name without /dev, e.g. "disk3s1s1".
	BSDName string
	// MediaName is the IOKit media name: a product string for a whole disk,
	// a partition label for a slice.
	MediaName string
	// MediaSize is the media's size in bytes.
	MediaSize int64
	// BlockSize is the media's block size in bytes.
	BlockSize int64
	// Whole reports a whole disk (diskN) rather than one of its slices.
	Whole bool
	// Leaf reports media with no further partition scheme below it.
	Leaf bool
	// Removable reports media that can be removed from its drive.
	Removable bool
	// Ejectable reports media macOS can eject — the precondition for
	// [Session.Eject] meaning anything.
	Ejectable bool
	// Writable reports media that is not write-protected.
	Writable bool
	// Encrypted reports media macOS considers encrypted.
	Encrypted bool
	// Content is the partition's type hint: a GPT type GUID, or a scheme
	// name such as "GUID_partition_scheme" on a whole disk.
	Content string
	// MediaPath is the IOKit registry path of the media object.
	MediaPath string

	// VolumePath is the mount point, or "" when nothing is mounted. It is
	// THE answer to "where did my image end up".
	VolumePath string
	// VolumeName is the volume's name as the Finder shows it.
	VolumeName string
	// VolumeKind is the filesystem macOS believes is there ("apfs", "hfs",
	// "msdos", …).
	//
	// It is a LABEL, not a decode: no superblock was parsed to produce it.
	// Reading the filesystem is github.com/go-filesystems' job.
	VolumeKind string
	// VolumeMountable reports a volume macOS knows how to mount.
	VolumeMountable bool
	// VolumeNetwork reports a network volume rather than local media.
	VolumeNetwork bool
	// VolumeUUID is the volume's UUID, or "".
	VolumeUUID string

	// Protocol is the transport: "USB", "Apple Fabric", "PCI-Express", or
	// [ProtocolDiskImage] for an attached image.
	Protocol string
	// Model, Vendor and Revision are the device's identification strings.
	Model    string
	Vendor   string
	Revision string
	// Internal reports a device built into the machine.
	Internal bool
	// DevicePath is the IOKit registry path of the device.
	DevicePath string
	// BusName and BusPath identify the bus the device hangs off.
	BusName string
	BusPath string

	// Raw is the whole description dictionary, converted to Go values
	// (string, bool, int64, []byte). It is kept because the typed fields
	// above are a selection, and a caller that needs a key nobody
	// anticipated should not have to fork this package to reach it.
	Raw map[string]any
}

Description is what DiskArbitration says about one disk: a typed view of the description dictionary. Absent keys are the zero value — macOS omits a key rather than reporting an empty one, so "" for Description.VolumeName means "no volume here", not "a volume with no name".

Nothing in it was computed by reading the device. It is the daemon's opinion, which is the only opinion that matches what the rest of macOS will do.

func (*Description) Device

func (d *Description) Device() string

Device is the full path of the block device node, e.g. "/dev/disk3s1s1". It is "" for a description with no BSD name, which is what a network volume looks like.

func (*Description) IsDiskImage

func (d *Description) IsDiskImage() bool

IsDiskImage reports whether the device is backed by a disk image rather than hardware. See ModelDiskImage for why it accepts three spellings.

func (*Description) Mounted

func (d *Description) Mounted() bool

Mounted reports whether the volume is mounted somewhere.

func (*Description) String

func (d *Description) String() string

String renders one line: the node, what is on it and where it is mounted.

type DiskError

type DiskError struct {
	// Op is the operation that failed: "unmount" or "eject".
	Op string
	// Disk is the BSD name it was asked about.
	Disk string
	// Status is the DAReturn the dissenter carried.
	Status Return
	// Message is the daemon's own status string, or "" when it gave none.
	Message string
}

DiskError is a failure DiskArbitration reported about one disk. It carries the dissenter's status and, when the daemon supplied one, its own sentence.

func (*DiskError) Advice

func (e *DiskError) Advice() string

Advice forwards Return.Advice for the status that was reported.

func (*DiskError) Error

func (e *DiskError) Error() string

Error renders the failure, preferring the daemon's own words when it had any.

type Event

type Event struct {
	// Kind is [Appeared] or [Disappeared].
	Kind EventKind
	// BSDName is the device node's name, or "" for a disk that has none —
	// which a mounted network volume does, and DiskArbitration reports it
	// alongside the real ones.
	BSDName string
	// Description is the disk's description at the moment of the event, or
	// nil for a [Disappeared] event (there is nothing left to describe).
	Description *Description
}

Event is one disk appearing or disappearing.

func (Event) String

func (e Event) String() string

String renders the event for a log line.

type EventKind

type EventKind int

EventKind is what happened to a disk.

const (
	// Appeared means a disk became known to DiskArbitration. Registering a
	// watch replays one of these for every disk ALREADY present, so a
	// watcher never has to enumerate separately to catch up.
	Appeared EventKind = iota + 1
	// Disappeared means a disk went away. Its description can no longer be
	// copied, so [Event.Description] is nil and only [Event.BSDName]
	// identifies it.
	Disappeared
)

func (EventKind) String

func (k EventKind) String() string

String names the kind.

type Return

type Return uint32

Return is a DAReturn: the status DiskArbitration reports for an operation it refused. The numeric values are Apple's, pinned here so a mis-ordered constant cannot turn "busy" into "not permitted" silently.

const (
	ReturnSuccess         Return = 0
	ReturnError           Return = 0xF8DA0001
	ReturnBusy            Return = 0xF8DA0002
	ReturnBadArgument     Return = 0xF8DA0003
	ReturnExclusiveAccess Return = 0xF8DA0004
	ReturnNoResources     Return = 0xF8DA0005
	ReturnNotFound        Return = 0xF8DA0006
	ReturnNotMounted      Return = 0xF8DA0007
	ReturnNotPermitted    Return = 0xF8DA0008
	ReturnNotPrivileged   Return = 0xF8DA0009
	ReturnNotReady        Return = 0xF8DA000A
	ReturnNotWritable     Return = 0xF8DA000B
	ReturnUnsupported     Return = 0xF8DA000C
)

The DAReturn values. kDAReturnSuccess is zero; the rest are err_local | err_local_diskarbitration | n, which is the 0xF8DA00nn family.

func (Return) Advice

func (r Return) Advice() string

Advice is the sentence to show a person, or "" when the status speaks for itself. It exists because the statuses that actually happen — a busy volume above all — are fixable by the person at the keyboard, and none of them says so.

It answers for the errno spellings as well as the kDAReturn ones, because the daemon uses both for the same situation and a caller should not have to know which it got today.

func (Return) Errno

func (r Return) Errno() (int, bool)

Errno reports the BSD errno the status carries, when it carries one. A kDAReturn constant is not an errno and answers false.

func (Return) String

func (r Return) String() string

String names the status the way Apple's own constant does, or the errno it wraps.

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session is a connection to the disk arbitration daemon plus the run loop its asynchronous answers are delivered on. Open one, keep it, close it.

Every method is safe to call from any goroutine. Closing is idempotent, and a method called on a closed session reports ErrClosed rather than reaching a released C object — which is the difference between an error and a crash in somebody else's stack frame.

func Open

func Open() (*Session, error)

Open connects to the disk arbitration daemon and starts the run loop its callbacks need. The caller must Close the result.

It reports ErrUnsupported off darwin and ErrNoSession when the daemon cannot be reached — which is a real outcome in a sandbox that has not been granted the service, not a defensive branch.

func (*Session) Close

func (s *Session) Close() error

Close unregisters every watch, stops the run loop and releases the session. It is idempotent and always reports nil, so it may be deferred without ceremony; the error is in the signature because a Closer that cannot fail today is still a Closer.

func (*Session) Describe

func (s *Session) Describe(name string) (*Description, error)

Describe answers what DiskArbitration knows about one disk. The name is a BSD name without /dev ("disk3s1s1"); a leading /dev/ is accepted and trimmed, because that is the form a caller has after reading a mount table.

It reports ErrBadName for a name that is not a block device's, and ErrNoDescription both when there is no such device and when there was one a moment ago — DiskArbitration does not distinguish those, and neither does this.

func (*Session) DescribeAll

func (s *Session) DescribeAll() ([]*Description, error)

DescribeAll describes every disk Session.Disks finds, in the same order.

A disk that goes away between the listing and its description is SKIPPED, not reported as an error. Enumerating a set of removable devices is inherently racy, and a caller asking "what is here" is better served by the four disks that answered than by an error about the fifth that left.

func (*Session) Disks

func (s *Session) Disks() ([]string, error)

Disks lists the BSD names of the block devices present, in device order (disk0, disk0s1, …, disk10). The names are what Session.Describe, Session.Unmount and Session.Eject take.

It enumerates by reading /dev rather than by asking DiskArbitration, and the reason is worth stating: DiskArbitration has no "list" call at all. The framework's own way to enumerate is to register an appearance callback and let the daemon replay one event per existing disk — which needs a run loop, a registration, and a guess at how long to wait before deciding the replay is over. The /dev scan is exact and immediate, and it was checked against the callback replay on a live machine: the same twenty devices, in both.

Session.Watch still uses the replay, because a watcher wants the events anyway.

func (*Session) Eject

func (s *Session) Eject(name string) error

Eject ejects the named disk and blocks until the daemon answers.

Ejecting is not unmounting. The media must already be unmounted — eject a mounted volume and the daemon answers ReturnBusy — so the sequence for a disk image or a removable drive is Unmount with UnmountWhole, then Eject the whole disk.

func (*Session) Mounts

func (s *Session) Mounts() ([]*Description, error)

Mounts returns the descriptions of the volumes that are currently mounted, which is the question a caller who just attached a disk image is actually asking.

func (*Session) Unmount

func (s *Session) Unmount(name string, opts UnmountOptions) error

Unmount unmounts the volume on the named disk and blocks until the daemon answers. A refusal comes back as a *DiskError carrying the Return and the daemon's own sentence; ReturnBusy is the common one and Return.Advice says what to do about it.

Pass UnmountWhole to take down every volume of the whole disk — the right option before ejecting a multi-partition image — and UnmountForce only where losing another process's unwritten data is acceptable.

func (*Session) Watch

func (s *Session) Watch(fn func(Event)) (*Watcher, error)

Watch delivers an Event to fn each time a disk appears or disappears.

Registration REPLAYS an Appeared event for every disk already present, so a caller that wants "what is here, and then what changes" needs only this — no separate enumeration, and no window between the two in which a disk could slip through unseen.

fn is called ON THE RUN-LOOP THREAD. Everything else this session does asynchronously — the completion of an Session.Unmount, every other event — waits behind it. Send to a channel and return; do not do work there, and above all do not call back into this session.

type UnmountOptions

type UnmountOptions uint32

UnmountOptions is a DADiskUnmountOptions bit set.

const (
	// UnmountDefault unmounts the one volume, and fails with [ReturnBusy] if
	// anything still has it open.
	UnmountDefault UnmountOptions = 0
	// UnmountWhole unmounts every volume of the whole disk the named device
	// belongs to. It is kDADiskUnmountOptionWhole, and it is what "detach
	// this image" means for an image with several partitions.
	UnmountWhole UnmountOptions = 0x00000001
	// UnmountForce unmounts even though something has the volume open.
	//
	// It is not a stronger request; it is a DIFFERENT one. Open files are
	// forcibly closed and unwritten data belonging to another process may be
	// lost. Reach for it when a person has been told what it means.
	UnmountForce UnmountOptions = 0x00080000
)

func (UnmountOptions) String

func (o UnmountOptions) String() string

String renders the options for an error message.

type Watcher

type Watcher struct {
	// contains filtered or unexported fields
}

Watcher is a live registration made by Session.Watch. Stop it when done; Session.Close stops any that are left.

func (*Watcher) Stop

func (w *Watcher) Stop()

Stop unregisters the callbacks. It is idempotent.

Directories

Path Synopsis
cmd
dalist command
Command dalist prints what DiskArbitration knows about this machine's disks.
Command dalist prints what DiskArbitration knows about this machine's disks.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL