-
Notifications
You must be signed in to change notification settings - Fork 10
/
cmd_restore.go
168 lines (154 loc) · 4.88 KB
/
cmd_restore.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
package main
import (
"bytes"
"context"
"fmt"
"time"
"github.com/golang/glog"
"github.com/spf13/cobra"
"github.com/freemyipod/wInd3x/pkg/app"
"github.com/freemyipod/wInd3x/pkg/cache"
"github.com/freemyipod/wInd3x/pkg/devices"
"github.com/freemyipod/wInd3x/pkg/dfu"
"github.com/freemyipod/wInd3x/pkg/mse"
"github.com/freemyipod/wInd3x/pkg/usbms"
)
var restoreFull bool
var restoreVersion string
var restoreCmd = &cobra.Command{
Use: "restore",
Short: "Restore iPod to stock firmware",
Long: "Restores an iPod to stock/factory firmware from DFU mode, downloading everything necessary along the way. You _will_ lose all data stored on the device.",
Args: cobra.ExactArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
app, err := app.NewAny()
if err != nil {
return err
}
defer app.Close()
hasBootloader := true
switch app.Desc.Kind {
case devices.Nano3:
hasBootloader = false
}
switch restoreVersion {
case "list":
versions := cache.GetFirmwareVersions(app.Desc.Kind)
glog.Infof("Available versions for %s:", app.Desc.Kind)
for _, version := range versions {
glog.Infof("- %s", version)
}
return nil
case "", "current":
default:
cache.FirmwareVersionOverrides = map[devices.Kind]string{
app.Desc.Kind: restoreVersion,
}
}
firmware, err := cache.Get(app, cache.PayloadKindFirmwareUpstream)
if err != nil {
return fmt.Errorf("could not get firmware: %w", err)
}
m, err := mse.Parse(bytes.NewReader(firmware))
if err != nil {
return fmt.Errorf("could not parse firmware: %w", err)
}
firmware, err = m.Serialize()
if err != nil {
return fmt.Errorf("could not serialize modified firmware: %w", err)
}
var bootloader []byte
if hasBootloader {
bootloader, err = cache.Get(app, cache.PayloadKindBootloaderUpstream)
if err != nil {
return fmt.Errorf("could not get bootloader: %s", err)
}
}
for {
glog.Infof("Found %s in %s", app.Desc.Kind, app.InterfaceKind)
switch app.InterfaceKind {
case devices.DFU:
wtf, err := cache.Get(app, cache.PayloadKindWTFUpstream)
if err != nil {
return fmt.Errorf("could not get wtf payload: %s", err)
}
glog.Infof("Sending WTF...")
if err := dfu.SendImage(app.Usb, wtf, app.Desc.Kind.DFUVersion()); err != nil {
return fmt.Errorf("Failed to send image: %w", err)
}
glog.Infof("Waiting 10s for device to switch to WTF mode...")
ctx, _ := context.WithTimeout(cmd.Context(), 10*time.Second)
if err := app.WaitSwitch(ctx, devices.WTF); err != nil {
return fmt.Errorf("device did not switch to WTF mode: %w", err)
}
time.Sleep(time.Second)
case devices.WTF:
recovery, err := cache.Get(app, cache.PayloadKindRecoveryUpstream)
if err != nil {
return fmt.Errorf("could not get recovery payload: %s", err)
}
glog.Infof("Sending recovery firmware...")
for i := 0; i < 10; i++ {
err = dfu.SendImage(app.Usb, recovery, app.Desc.Kind.DFUVersion())
if err == nil {
break
} else {
glog.Errorf("%v", err)
time.Sleep(time.Second)
}
}
if err != nil {
return err
}
glog.Infof("Waiting 30s for device to switch to Recovery mode...")
ctx, _ := context.WithTimeout(cmd.Context(), 30*time.Second)
if err := app.WaitSwitch(ctx, devices.Disk); err != nil {
return fmt.Errorf("device did not switch to Recovery mode: %w", err)
}
time.Sleep(time.Second)
case devices.Disk:
h := usbms.Host{
InEndpoint: app.MSEndpoints.In,
OutEndpoint: app.MSEndpoints.Out,
}
di, err := h.IPodDeviceInformation()
if err != nil {
glog.Errorf("Could not get device information: %v", err)
} else {
fmt.Printf("SerialNumber: %s\n", di.SerialNumber)
fmt.Printf(" BuildID: %s\n", di.BuildID)
}
if restoreFull {
partsize := len(firmware)
glog.Infof("Reformatting to %d MiB system partition...", partsize>>20)
if err := h.IPodRepartition(partsize); err != nil {
return fmt.Errorf("repartitioning failed: %w", err)
}
if hasBootloader {
glog.Infof("Writing bootloader...")
if err := h.IPodUpdateSendFull(usbms.IPodUpdateBootloader, bootloader); err != nil {
return fmt.Errorf("writing bootloader failed: %w", err)
}
}
}
glog.Infof("Writing firmware...")
if err := h.IPodUpdateSendFull(usbms.IPodUpdateFirmware, firmware); err != nil {
return fmt.Errorf("writing firmware failed: %w", err)
}
if restoreFull {
glog.Infof("Finalizing...")
if err := h.IPodFinalize(false); err != nil {
return fmt.Errorf("rebooting failed: %w", err)
}
glog.Infof("Please reformat the main partition of the device as FAT32, otherwise it will refuse to boot.")
} else {
glog.Infof("Resetting...")
if err := h.IPodFinalize(true); err != nil {
return fmt.Errorf("rebooting failed: %w", err)
}
}
return nil
}
}
},
}