diff --git a/ios/imagemounter/imagemounter.go b/ios/imagemounter/imagemounter.go index 6fc09a0b..f105c060 100644 --- a/ios/imagemounter/imagemounter.go +++ b/ios/imagemounter/imagemounter.go @@ -26,6 +26,7 @@ type DeveloperDiskImageMounter struct { type ImageMounter interface { ListImages() ([][]byte, error) MountImage(imagePath string) error + UnmountImage() error io.Closer } @@ -95,6 +96,19 @@ func (conn *DeveloperDiskImageMounter) MountImage(imagePath string) error { return hangUp(conn.plistRw) } +func (conn *DeveloperDiskImageMounter) UnmountImage() error { + req := map[string]interface{}{ + "Command": "UnmountImage", + "MountPath": "/Developer", + } + log.Debugf("sending: %+v", req) + err := conn.plistRw.Write(req) + if err != nil { + return err + } + return nil +} + func (conn *DeveloperDiskImageMounter) mountImage(signatureBytes []byte) error { req := map[string]interface{}{ "Command": "MountImage", @@ -189,6 +203,16 @@ func MountImage(device ios.DeviceEntry, path string) error { return conn.MountImage(path) } +func UnmountImage(device ios.DeviceEntry) error { + conn, err := NewImageMounter(device) + if err != nil { + return fmt.Errorf("failed connecting to image mounter: %v", err) + } + defer conn.Close() + + return conn.UnmountImage() +} + func listImages(prw ios.PlistCodecReadWriter, imageType string, v *semver.Version) ([][]byte, error) { err := prw.Write(map[string]interface{}{ "Command": "LookupImage", diff --git a/ios/imagemounter/personalized_image_mounter.go b/ios/imagemounter/personalized_image_mounter.go index 6cd0f3fa..17ca629b 100644 --- a/ios/imagemounter/personalized_image_mounter.go +++ b/ios/imagemounter/personalized_image_mounter.go @@ -129,6 +129,19 @@ func (p PersonalizedDeveloperDiskImageMounter) MountImage(imagePath string) erro return nil } +func (p PersonalizedDeveloperDiskImageMounter) UnmountImage() error { + req := map[string]interface{}{ + "Command": "UnmountImage", + "MountPath": "/System/Developer", + } + log.Debugf("sending: %+v", req) + err := p.plistRw.Write(req) + if err != nil { + return err + } + return nil +} + func (p PersonalizedDeveloperDiskImageMounter) queryPersonalizedImageNonce() ([]byte, error) { err := p.plistRw.Write(map[string]interface{}{ "Command": "QueryNonce", diff --git a/main.go b/main.go index e014be20..2e1d3da8 100644 --- a/main.go +++ b/main.go @@ -74,6 +74,7 @@ Usage: ios info [display | lockdown] [options] ios image list [options] ios image mount [--path=] [options] + ios image unmount [options] ios image auto [--basedir=] [options] ios syslog [options] ios screenshot [options] [--output=] [--stream] [--port=] @@ -160,6 +161,7 @@ The commands work as following: ios image list [options] List currently mounted developers images' signatures ios image mount [--path=] [options] Mount a image from > For iOS 17+ (personalized developer disk images) must point to the "Restore" directory inside the developer disk + ios image unmount [options] Unmount developer disk image ios image auto [--basedir=] [options] Automatically download correct dev image from the internets and mount it. > You can specify a dir where images should be cached. > The default is the current dir. @@ -1139,6 +1141,17 @@ func imageCommand1(device ios.DeviceEntry, arguments docopt.Opts) bool { } log.WithFields(log.Fields{"image": path, "udid": device.Properties.SerialNumber}).Info("success mounting image") } + + unmount, _ := arguments.Bool("unmount") + if unmount { + err := imagemounter.UnmountImage(device) + if err != nil { + log.WithFields(log.Fields{"udid": device.Properties.SerialNumber, "err": err}). + Error("error unmounting image") + return true + } + log.WithFields(log.Fields{"udid": device.Properties.SerialNumber}).Info("success unmounting image") + } } return b }