Esempio n. 1
0
        public Tasker.TaskFunc[] GetTasks()
        {
            var tasks = new List <Tasker.TaskFunc>();

            tasks.AddRange(new MembootTasks(
                               type: MembootTasks.MembootTaskType.MembootRecovery,
                               requireSD: true
                               ).Tasks);
            tasks.AddRange(new TaskFunc[] {
                MembootTasks.FlashUboot(ConfigIni.UbootType.SD),
                InstallSDPart1,
                ShellTasks.FormatDevice(DialogOptions.MakeBootable ? "/dev/mmcblk0p2" : "/dev/mmcblk0p1"),
                InstallSDPart2
            });
            tasks.Add(ShellTasks.Reboot);
            tasks.Add(MembootTasks.WaitForShellCycle());
            return(tasks.ToArray());
        }
Esempio n. 2
0
        public static TaskFunc ProcessNand(string nandDump, NandTasks task)
        {
            return((Tasker tasker, Object sync) =>
            {
                return TempHelpers.doWithTempFolder((tempFolder) =>
                {
                    NandTasks[] validTasks = { NandTasks.DumpNand, NandTasks.DumpSystemPartition, NandTasks.DumpUserPartition, NandTasks.FlashSystemPartition, NandTasks.FlashUserPartition };
                    if (!validTasks.Contains(task))
                    {
                        throw new ArgumentOutOfRangeException(Enum.GetName(typeof(NandTasks), task));
                    }

                    if (task == NandTasks.FlashSystemPartition || task == NandTasks.FlashUserPartition)
                    {
                        var extension = new FileInfo(nandDump).Extension.ToLower();

                        if (extension == ".gz" || extension == ".tgz" || extension == ".xz" || extension == ".bz2")
                        {
                            var tempFilename = Path.Combine(tempFolder, "dump.bin");

                            using (var extractor = ArchiveFactory.Open(nandDump))
                                using (var entryStream = extractor.Entries.First().OpenEntryStream())
                                    using (var extractedFile = File.Create(tempFilename))
                                    {
                                        tasker.SetStatus(Resources.ExtractingToTemporaryFolder);
                                        entryStream.CopyTo(extractedFile);
                                        nandDump = tempFilename;
                                    }
                        }
                    }

                    bool isHsqs = false;
                    bool isExtFs = false;
                    bool isTar = false;

                    if (task == NandTasks.FlashSystemPartition && !((isHsqs = Files.CheckFileType.IsSquashFs(nandDump)) || (isExtFs = Files.CheckFileType.IsExtFs(nandDump)) || (isTar = Files.CheckFileType.IsTar(nandDump))))
                    {
                        throw new Exception(Properties.Resources.InvalidHsqs);
                    }


                    if (task == NandTasks.FlashUserPartition)
                    {
                        if (!((isTar = Files.CheckFileType.IsTar(nandDump)) || (isExtFs = Files.CheckFileType.IsExtFs(nandDump))))
                        {
                            throw new Exception(Properties.Resources.InvalidUserDataBackup);
                        }
                    }

                    var nandInfo = Sunxi.NandInfo.GetNandInfo();

                    long partitionSize = 300 * 1024 * 1024;
                    var splitStream = new SplitterStream(Program.debugStreams);
                    string rootfsDevice = $"/dev/{nandInfo.GetRootfsPartition().Device}";
                    string osDecryptedDevice = rootfsDevice;
                    string userDataDevice = $"/dev/{nandInfo.GetDataPartition().Device}";
                    bool hasKeyfile = hakchi.Shell.Execute("[ -f /key-file ]") == 0;

                    if (hasKeyfile)
                    {
                        osDecryptedDevice = "/dev/mapper/root-crypt";
                    }

                    bool systemIsHsqs = hakchi.Shell.ExecuteSimple($"dd if={osDecryptedDevice} bs=1 count=4", 0) == "HSQS";

                    switch (task)
                    {
                    case NandTasks.DumpSystemPartition:
                        if (systemIsHsqs)
                        {
                            partitionSize = long.Parse(hakchi.Shell.ExecuteSimple($"echo $((($(hexdump -e '1/4 \"%u\"' -s $((0x28)) -n 4 {osDecryptedDevice})+0xfff)/0x1000))", throwOnNonZero: true).Trim()) * 4 * 1024;
                        }
                        else
                        {
                            partitionSize = long.Parse(hakchi.Shell.ExecuteSimple($"blockdev --getsize64 {osDecryptedDevice}", throwOnNonZero: true));
                        }
                        break;

                    case NandTasks.FlashSystemPartition:
                        hakchi.Shell.Execute("hakchi umount_base", null, splitStream, splitStream);
                        hakchi.Shell.Execute("umount /newroot");
                        if (hasKeyfile)
                        {
                            hakchi.Shell.Execute("cryptsetup close root-crypt");
                            hakchi.Shell.ExecuteSimple($"cryptsetup open {rootfsDevice} root-crypt --type plain --cipher aes-xts-plain --key-file /key-file", 2000, true);
                        }
                        partitionSize = long.Parse(hakchi.Shell.ExecuteSimple($"blockdev --getsize64 {osDecryptedDevice}", throwOnNonZero: true));
                        break;

                    case NandTasks.DumpUserPartition:
                        hakchi.Shell.Execute("hakchi mount_base", null, null, null, 0, true);
                        partitionSize = long.Parse(hakchi.Shell.ExecuteSimple("df -B 1 | grep /newroot/var/lib | head -n 1 | awk -e '{print $3 }'", throwOnNonZero: true).Trim());
                        break;

                    case NandTasks.FlashUserPartition:
                        partitionSize = long.Parse(hakchi.Shell.ExecuteSimple($"blockdev --getsize64 {userDataDevice}", throwOnNonZero: true));
                        break;

                    case NandTasks.DumpNand:
                        partitionSize = 536870912;
                        break;
                    }

                    FileMode mode = FileMode.Create;

                    if (task == NandTasks.FlashUserPartition || task == NandTasks.FlashSystemPartition)
                    {
                        mode = FileMode.Open;
                    }

                    tasker.SetStatus(mode == FileMode.Open ? Resources.FlashingNand : Resources.DumpingNand);
                    using (var file = new TrackableFileStream(nandDump, mode, mode == FileMode.Open ? FileAccess.Read : FileAccess.ReadWrite))
                    {
                        if (mode == FileMode.Open && file.Length > partitionSize)
                        {
                            throw new Exception(Resources.ImageTooLarge);
                        }

                        if (mode == FileMode.Create && task != NandTasks.DumpUserPartition && task != NandTasks.DumpSystemPartition)
                        {
                            file.SetLength(partitionSize);
                        }

                        if (task == NandTasks.DumpUserPartition)
                        {
                            file.OnProgress += (long position, long length) =>
                            {
                                tasker.OnProgress(Math.Min(position, partitionSize), partitionSize);
                            };
                        }
                        else if (task == NandTasks.DumpSystemPartition && !systemIsHsqs)
                        {
                            file.OnProgress += (long position, long length) =>
                            {
                                tasker.OnProgress(Math.Min(position, partitionSize) + partitionSize, partitionSize * 2);
                            };
                        }
                        else
                        {
                            file.OnProgress += tasker.OnProgress;
                        }

                        switch (task)
                        {
                        case NandTasks.DumpSystemPartition:
                            if (systemIsHsqs)
                            {
                                Shared.ShellPipe($"dd if={osDecryptedDevice} bs=128K count={(partitionSize / 1024) / 4 }", null, file, throwOnNonZero: true);
                            }
                            else
                            {
                                Regex mksquashfsProgress = new Regex(@"(\d+)/(\d+)", RegexOptions.Compiled);
                                using (var mksquashfs = File.OpenRead(Path.Combine(Program.BaseDirectoryInternal, "tools", "mksquashfs")))
                                {
                                    hakchi.Shell.Execute("cat > /mksquashfs", mksquashfs, throwOnNonZero: true);
                                    hakchi.Shell.Execute("chmod +x /mksquashfs", throwOnNonZero: true);
                                }

                                hakchi.Shell.ExecuteSimple("hakchi mount_base");
                                hakchi.Shell.ExecuteSimple("mkdir -p /tmp/");
                                using (EventStream mkSquashfsProgress = new EventStream())
                                {
                                    splitStream.AddStreams(mkSquashfsProgress);
                                    mkSquashfsProgress.OnData += (byte[] buffer) =>
                                    {
                                        string data = Encoding.ASCII.GetString(buffer);
                                        MatchCollection matches = mksquashfsProgress.Matches(data);

                                        if (matches.Count > 0)
                                        {
                                            tasker.SetProgress(long.Parse(matches[matches.Count - 1].Groups[1].Value), long.Parse(matches[matches.Count - 1].Groups[2].Value) * 2);
                                        }
                                    };

                                    hakchi.Shell.Execute("/mksquashfs /newroot/var/squashfs /tmp/rootfs.hsqs", null, splitStream, splitStream, throwOnNonZero: true);

                                    splitStream.RemoveStream(mkSquashfsProgress);
                                }

                                partitionSize = long.Parse(hakchi.Shell.ExecuteSimple("ls -la /tmp/rootfs.hsqs | awk -e '{ print $5 }'"));

                                hakchi.Shell.ExecuteSimple("hakchi umount_base");
                                Shared.ShellPipe("cat /tmp/rootfs.hsqs", stdout: file);
                                hakchi.Shell.ExecuteSimple("rm /tmp/rootfs.hsqs");
                            }

                            break;

                        case NandTasks.FlashSystemPartition:
                            if (isTar || (hakchi.IsMdPartitioning && !isExtFs))
                            {
                                using (var eventStream = new EventStream())
                                {
                                    eventStream.OnData += (byte[] data) =>
                                    {
                                        var dataString = Encoding.UTF8.GetString(data).Trim();
                                        tasker.SetStatus(dataString);
                                        Trace.WriteLine(dataString);
                                    };

                                    hakchi.Shell.Execute("mkdir -p /tmp/rootfs /tmp/squashfs", throwOnNonZero: true);

                                    if (isHsqs)
                                    {
                                        Shared.ShellPipe($"dd of=/tmp/squashfs/squash.hsqs bs=128K", file, throwOnNonZero: true);
                                    }

                                    ShellTasks.FormatDevice(osDecryptedDevice)(tasker);
                                    hakchi.Shell.Execute($"mount {osDecryptedDevice} /tmp/rootfs", throwOnNonZero: true);

                                    if (isTar)
                                    {
                                        hakchi.Shell.Execute($"tar -xvf - -C /tmp/rootfs", file, eventStream, null, throwOnNonZero: true);
                                    }
                                    else if (isHsqs)
                                    {
                                        tasker.SetStatus(Resources.FlashingNand);
                                        hakchi.Shell.Execute($"mount /tmp/squashfs/squash.hsqs /tmp/squashfs/", throwOnNonZero: true);
                                        hakchi.Shell.Execute("cd /tmp/squashfs; rsync -av ./ ../rootfs", null, eventStream, eventStream, throwOnNonZero: true);
                                        hakchi.Shell.Execute("umount /tmp/squashfs", throwOnNonZero: true);
                                        hakchi.Shell.Execute("rm -rf /tmp/squashfs", throwOnNonZero: true);
                                    }

                                    hakchi.Shell.Execute("umount /tmp/rootfs", throwOnNonZero: true);
                                    hakchi.Shell.Execute("rmdir /tmp/rootfs", throwOnNonZero: true);
                                }
                            }
                            else
                            {
                                Shared.ShellPipe($"dd of={osDecryptedDevice} bs=128K", file, throwOnNonZero: true);
                            }

                            if (hasKeyfile)
                            {
                                hakchi.Shell.Execute("cryptsetup close root-crypt", throwOnNonZero: true);
                            }
                            break;

                        case NandTasks.DumpUserPartition:
                            Shared.ShellPipe($"tar -cvC /newroot/var/lib/ .", null, file, null, throwOnNonZero: true);
                            break;

                        case NandTasks.FlashUserPartition:
                            if (isTar)
                            {
                                hakchi.Shell.Execute("hakchi mount_base", null, null, null, 0, true);
                                hakchi.Shell.Execute("rm -rf /newroot/var/lib/*", null, null, null, 0, true);
                                hakchi.Shell.Execute("tar -xvC /newroot/var/lib/", file, throwOnNonZero: true);
                            }
                            else
                            {
                                Shared.ShellPipe($"dd of={userDataDevice} bs=128K", file, throwOnNonZero: true);
                            }
                            break;

                        case NandTasks.DumpNand:
                            hakchi.Shell.Execute("hakchi umount_base", null, splitStream, splitStream, 0, true);
                            Shared.ShellPipe("sntool sunxi_flash phy_read 0", null, file, throwOnNonZero: true);
                            break;
                        }
                        file.Close();
                    }

                    tasker.SetStatus(Resources.Done);
                    tasker.SetProgress(1, 1);
                    return Conclusion.Success;
                });
            });
        }
Esempio n. 3
0
        public MembootTasks(MembootTaskType type, string[] hmodsInstall = null, string[] hmodsUninstall = null, string dumpPath = null, bool forceRecoveryReload = false, bool ignoreBackupKernel = false, bool requireSD = false)
        {
            this.ignoreBackupKernel = ignoreBackupKernel;
            userRecovery            = (hakchi.Shell.IsOnline && hakchi.MinimalMemboot && hakchi.UserMinimalMemboot);

            fel = new Fel();
            List <TaskFunc> taskList = new List <TaskFunc>();

            if (!hakchi.MinimalMemboot || forceRecoveryReload)
            {
                taskList.Add(WaitForFelOrMembootableShell(requireSD));
                taskList.Add(TaskIf(() => { return(hakchi.Shell.IsOnline); }, Memboot, MembootFel));
                taskList.Add(WaitForShellCycle(-1));
                taskList.Add(ShellTasks.ShowSplashScreen);
            }

            switch (type)
            {
            case MembootTaskType.InstallHakchi:
                taskList.Add(CheckMdRootfs);
                taskList.AddRange(new GrowTask(true, true).Tasks);
                taskList.AddRange(new TaskFunc[]
                {
                    HandleHakchi(HakchiTasks.Install),
                    ModTasks.TransferBaseHmods("/hakchi/transfer"),
                    ModTasks.TransferHakchiHmod("/hakchi/transfer")
                });

                if (!userRecovery)
                {
                    taskList.Add(BootHakchi);
                    taskList.Add(WaitForShellCycle(-1));
                }

                break;

            case MembootTaskType.ResetHakchi:
                taskList.Add(CheckMdRootfs);
                taskList.AddRange(new GrowTask(true, true).Tasks);
                taskList.AddRange(new TaskFunc[]
                {
                    HandleHakchi(HakchiTasks.Reset),
                    ModTasks.TransferBaseHmods("/hakchi/transfer"),
                    ModTasks.TransferHakchiHmod("/hakchi/transfer")
                });

                if (!userRecovery)
                {
                    taskList.Add(BootHakchi);
                    taskList.Add(WaitForShellCycle(-1));
                }

                break;

            case MembootTaskType.UninstallHakchi:
            case MembootTaskType.FormatUserPartition:
            case MembootTaskType.FactoryReset:

                var reinstallHakchi = false;

                if (type == MembootTaskType.UninstallHakchi || type == MembootTaskType.FactoryReset)
                {
                    taskList.Add(TaskIf(() => hakchi.IsMdPartitioning, SuccessTask, GetStockKernel));

                    if (ignoreBackupKernel)
                    {
                        taskList.Add(TaskIf(() => hakchi.IsMdPartitioning, SuccessTask, EraseBackupKernel));
                    }

                    taskList.AddRange(new TaskFunc[] {
                        TaskIf(() => hakchi.IsMdPartitioning, SuccessTask, FlashKernel),
                        HandleHakchi(HakchiTasks.Uninstall)
                    });
                }

                if (type == MembootTaskType.FormatUserPartition || type == MembootTaskType.FactoryReset)
                {
                    if (type == MembootTaskType.FormatUserPartition)
                    {
                        taskList.AddRange(new TaskFunc[]
                        {
                            (Tasker tasker, object SyncObject) =>
                            {
                                hakchi.Shell.Execute("hakchi mount_base");
                                reinstallHakchi = hakchi.Shell.Execute("hakchi eval '[ -e \"$mountpoint/var/lib/hakchi/\" ]'") == 0;
                                hakchi.Shell.Execute("hakchi umount_base");
                                return(Conclusion.Success);
                            },
                        });
                    }

                    taskList.AddRange(new TaskFunc[]
                    {
                        ShellTasks.UnmountBase,
                        (Tasker tasker, Object syncObject) => ShellTasks.FormatDevice($"/dev/{Sunxi.NandInfo.GetNandInfo().GetDataPartition().Device}")(tasker, syncObject)
                    });

                    if (type == MembootTaskType.FormatUserPartition)
                    {
                        taskList.AddRange(new TaskFunc[]
                        {
                            TaskIf(() => reinstallHakchi, HandleHakchi(HakchiTasks.Install), SuccessTask),
                            TaskIf(() => reinstallHakchi, ModTasks.TransferBaseHmods("/hakchi/transfer"), SuccessTask),
                            TaskIf(() => reinstallHakchi, ModTasks.TransferHakchiHmod("/hakchi/transfer"), SuccessTask)
                        });
                    }
                }

                if (!userRecovery)
                {
                    taskList.Add(TaskIf(() => reinstallHakchi, BootHakchi, ShellTasks.Reboot));
                }

                break;

            case MembootTaskType.DumpNand:
                taskList.AddRange(new TaskFunc[]
                {
                    ProcessNand(dumpPath, NandTasks.DumpNand)
                });
                if (!userRecovery)
                {
                    taskList.Add(ShellTasks.Reboot);
                }

                break;

            case MembootTaskType.DumpSystemPartition:
                taskList.AddRange(new TaskFunc[]
                {
                    ProcessNand(dumpPath, NandTasks.DumpSystemPartition)
                });
                if (!userRecovery)
                {
                    taskList.Add(ShellTasks.Reboot);
                }

                break;

            case MembootTaskType.DumpUserPartition:
                taskList.AddRange(new TaskFunc[]
                {
                    ProcessNand(dumpPath, NandTasks.DumpUserPartition)
                });
                if (!userRecovery)
                {
                    taskList.Add(ShellTasks.Reboot);
                }

                break;

            case MembootTaskType.FlashSystemPartition:
                taskList.AddRange(new TaskFunc[]
                {
                    ProcessNand(dumpPath, NandTasks.FlashSystemPartition)
                });
                if (!userRecovery)
                {
                    taskList.Add(ShellTasks.Reboot);
                }

                break;

            case MembootTaskType.FlashUserPartition:
                taskList.AddRange(new TaskFunc[]
                {
                    ProcessNand(dumpPath, NandTasks.FlashUserPartition)
                });
                if (!userRecovery)
                {
                    taskList.Add(ShellTasks.Reboot);
                }

                break;

            case MembootTaskType.ProcessMods:
                bool unmountAfter = userRecovery && hakchi.Shell.Execute("hakchi eval 'mountpoint -q \"$mountpoint/var/lib/\"'") == 0;

                taskList.Add(ShellTasks.MountBase);
                taskList.AddRange(new ModTasks(hmodsInstall, hmodsUninstall).Tasks);

                if (!userRecovery)
                {
                    taskList.Add(BootHakchi);
                }

                if (unmountAfter)
                {
                    taskList.Add(ShellTasks.UnmountBase);
                }
                break;

            case MembootTaskType.FlashNormalUboot:
                taskList.AddRange(new TaskFunc[]
                {
                    FlashUboot(UbootType.Normal)
                });
                if (!userRecovery)
                {
                    taskList.Add(ShellTasks.Reboot);
                }

                break;

            case MembootTaskType.FlashSDUboot:
                taskList.AddRange(new TaskFunc[]
                {
                    FlashUboot(UbootType.SD)
                });
                if (!userRecovery)
                {
                    taskList.Add(ShellTasks.Reboot);
                }

                break;

            case MembootTaskType.Memboot:
                taskList.Add(BootHakchi);
                break;

            case MembootTaskType.MembootOriginal:
                taskList.Add(TaskIf(() => hakchi.IsMdPartitioning, ErrorTask(Resources.NotSupportedOnThisPlatform), SuccessTask));
                taskList.Add(BootBackup2);
                break;

            case MembootTaskType.MembootRecovery:
                break;

            case MembootTaskType.DumpStockKernel:
                taskList.AddRange(new TaskFunc[]
                {
                    TaskIf(() => hakchi.IsMdPartitioning, ErrorTask(Resources.NotSupportedOnThisPlatform), SuccessTask),
                    DumpStockKernel(dumpPath)
                });
                if (!userRecovery)
                {
                    taskList.Add(ShellTasks.Reboot);
                }

                break;
            }
            Tasks = taskList.ToArray();
        }