Example #1
0
        public static Conclusion BootHakchi(Tasker tasker, Object syncObject = null)
        {
            // Continue the hakchi boot process
            tasker.SetStatus(Resources.BootingHakchi);
            MemoryStream hakchiLogStream = new MemoryStream();
            var          splitStream     = new SplitterStream(hakchiLogStream).AddStreams(Program.debugStreams);

            tasker.PushState(State.Waiting);
            try
            {
                hakchi.Shell.Execute("boot", null, splitStream, splitStream, 0, true);
            }
            catch { }
            tasker.PopState();

            hakchiLogStream.Seek(0, SeekOrigin.Begin);
            string hakchiLog;

            using (StreamReader sr = new StreamReader(hakchiLogStream))
            {
                hakchiLog = sr.ReadToEnd();
            }
            foreach (string line in hakchiLog.Split(Convert.ToChar(0x0A)))
            {
                if (line.StartsWith("flash md5 mismatch! "))
                {
                    throw new Exception(line);
                }
            }

            return(Conclusion.Success);
        }
Example #2
0
        public static TaskFunc FlashUboot(Fel.UbootType type)
        {
            return((Tasker tasker, Object syncObject) =>
            {
                tasker.SetStatus(Resources.FlashingUboot);
                TrackableStream uboot;
                if (type == Fel.UbootType.Normal)
                {
                    uboot = new TrackableStream(Resources.uboot);
                }
                else
                {
                    uboot = new TrackableStream(Resources.ubootSD);
                }

                if (uboot.Length > 655360)
                {
                    throw new Exception(Resources.InvalidUbootSize + " " + uboot.Length);
                }

                uboot.OnProgress += tasker.OnProgress;

                hakchi.Shell.Execute("cat > /uboot.bin", uboot, null, null, 0, true);
                MemoryStream flashLog = new MemoryStream();
                var splitStream = new SplitterStream(flashLog).AddStreams(Program.debugStreams);
                if (hakchi.Shell.Execute("hakchi flashBoot2 /uboot.bin 8 5", null, splitStream) != 0)
                {
                    using (var sr = new StreamReader(flashLog))
                    {
                        throw new Exception(sr.ReadToEnd());
                    }
                }
                return Conclusion.Success;
            });
        }
Example #3
0
        public TaskFunc InstallHmods(string transferPath = "/tmp/hmods")
        {
            return((Tasker tasker, Object syncObject) =>
            {
                tasker.SetStatus(Resources.InstallingMods);
                bool commandSucceeded = false;

                var splitStream = new SplitterStream(Program.debugStreams);
                commandSucceeded = hakchi.Shell.Execute($"hakchi packs_install {Shared.EscapeShellArgument(transferPath)}", null, splitStream, splitStream) == 0;

                return commandSucceeded ? Conclusion.Success : Conclusion.Error;
            });
        }
Example #4
0
        public static TaskFunc FlashUboot(UbootType type)
        {
            return((Tasker tasker, Object syncObject) =>
            {
                tasker.SetStatus(Resources.FlashingUboot);

                MemoryStream flashLog = new MemoryStream();
                var splitStream = new SplitterStream(flashLog).AddStreams(Program.debugStreams);
                if (hakchi.Shell.Execute($"sntool sd {(type == UbootType.SD ? "enable" : "disable")}", null, splitStream, splitStream) != 0)
                {
                    flashLog.Seek(0, SeekOrigin.Begin);
                    using (var sr = new StreamReader(flashLog))
                    {
                        throw new Exception(sr.ReadToEnd());
                    }
                }
                return Conclusion.Success;
            });
        }
Example #5
0
        public static TaskFunc FormatDevice(string device)
        {
            Regex mke2fsHeaderRegex   = new Regex(@"(Allocating group tables|Writing inode tables|Creating journal \(\d+ blocks\)|Writing superblocks and filesystem accounting information)", RegexOptions.Compiled);
            Regex mke2fsProgressRegex = new Regex(@"(\d+/\d+|done)", RegexOptions.Compiled);

            return((Tasker tasker, Object sync) =>
            {
                using (EventStream formatProgress = new EventStream())
                    using (var splitStream = new SplitterStream(Program.debugStreams))
                    {
                        splitStream.AddStreams(formatProgress);
                        string currentHeading = null;
                        formatProgress.OnData += (byte[] buffer) =>
                        {
                            string data = Encoding.ASCII.GetString(buffer);
                            MatchCollection matches = mke2fsHeaderRegex.Matches(data);
                            if (matches.Count > 0)
                            {
                                currentHeading = matches[matches.Count - 1].Value;
                                tasker?.SetStatus(currentHeading);
                            }

                            matches = mke2fsProgressRegex.Matches(data);

                            if (matches.Count > 0 && currentHeading != null && currentHeading != "Writing superblocks and filesystem accounting information")
                            {
                                tasker?.SetStatus($"{currentHeading}: {matches[matches.Count - 1].Value}");
                                if (currentHeading == "Writing inode tables")
                                {
                                    var inodes = matches[matches.Count - 1].Value.Split("/"[0]);
                                    tasker?.SetProgress(long.Parse(inodes[0]), long.Parse(inodes[1]));
                                }
                            }
                        };

                        hakchi.Shell.Execute($"yes | mke2fs -t ext4 -L data -b 4K -m 0 -J size=4 -E stripe-width=32 -O ^huge_file,^metadata_csum {Shared.EscapeShellArgument(device)}", null, splitStream, splitStream, 0, true);

                        splitStream.RemoveStream(formatProgress);

                        return Conclusion.Success;
                    }
            });
        }
Example #6
0
        public static Conclusion CheckExternalStorage(Tasker tasker = null, Object syncObject = null)
        {
            tasker?.SetStatus("hakchi checkExtStorage");

            using (var eventStream = new EventStream())
                using (var splitStream = new SplitterStream())
                {
                    eventStream.OnData += (byte[] buffer) =>
                    {
                        tasker.SetStatus(Encoding.UTF8.GetString(buffer));
                    };

                    splitStream.AddStreams(Program.debugStreams);
                    splitStream.AddStreams(eventStream);

                    hakchi.Shell.Execute("hakchi checkExtStorage", null, splitStream, splitStream);

                    return(Conclusion.Success);
                }

            return(Conclusion.Error);
        }
Example #7
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;
                });
            });
        }
Example #8
0
        public static TaskFunc ProcessNand(string nandDump, NandTasks task)
        {
            return((Tasker tasker, Object sync) =>
            {
                NandTasks[] validTasks = { NandTasks.DumpNand, NandTasks.DumpNandB, NandTasks.DumpNandC, NandTasks.FlashNandB, NandTasks.FlashNandC, NandTasks.FormatNandC };
                if (!validTasks.Contains(task))
                {
                    throw new ArgumentOutOfRangeException("task");
                }

                if (task == NandTasks.FlashNandB && !Files.CheckFileType.IsSquashFs(nandDump))
                {
                    throw new Exception(Properties.Resources.InvalidHsqs);
                }


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

                long partitionSize = 300 * 1024 * 1024;
                var splitStream = new SplitterStream(Program.debugStreams);
                switch (task)
                {
                case NandTasks.DumpNandB:
                case NandTasks.FlashNandB:
                    hakchi.Shell.Execute("umount /newroot");
                    hakchi.Shell.Execute("cryptsetup close root-crypt");
                    hakchi.Shell.ExecuteSimple("cryptsetup open /dev/nandb root-crypt --type plain --cipher aes-xts-plain --key-file /key-file", 2000, true);

                    if (task == NandTasks.DumpNandB)
                    {
                        partitionSize = long.Parse(hakchi.Shell.ExecuteSimple("echo $((($(hexdump -e '1/4 \"%u\"' -s $((0x28)) -n 4 /dev/mapper/root-crypt)+0xfff)/0x1000))", throwOnNonZero: true).Trim()) * 4 * 1024;
                    }

                    if (task == NandTasks.FlashNandB)
                    {
                        partitionSize = long.Parse(hakchi.Shell.ExecuteSimple("blockdev --getsize64 /dev/mapper/root-crypt", throwOnNonZero: true));
                    }

                    break;

                case NandTasks.DumpNandC:
                    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.FlashNandC:
                    partitionSize = long.Parse(hakchi.Shell.ExecuteSimple("blockdev --getsize64 /dev/nandc", throwOnNonZero: true));
                    break;

                case NandTasks.DumpNand:
                    partitionSize = 536870912;
                    break;

                case NandTasks.FormatNandC:
                    hakchi.Shell.Execute("cat > /bin/mke2fs; chmod +x /bin/mke2fs", File.OpenRead(Shared.PathCombine(Program.BaseDirectoryInternal, "tools", "arm", "mke2fs.static")), null, null, 0, true);
                    hakchi.Shell.Execute("hakchi umount_base", null, splitStream, splitStream);
                    hakchi.Shell.Execute("yes | mke2fs -t ext4 -L data -b 4K -E stripe-width=32 -O ^huge_file,^metadata_csum /dev/nandc", null, splitStream, splitStream, 0, true);
                    hakchi.Shell.Execute("rm /bin/mke2fs");
                    return Conclusion.Success;
                }

                FileMode mode = FileMode.Create;

                if (task == NandTasks.FlashNandC || task == NandTasks.FlashNandB)
                {
                    mode = FileMode.Open;
                }

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

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

                    if (task == NandTasks.DumpNandC)
                    {
                        file.OnProgress += (long position, long length) =>
                        {
                            tasker.OnProgress(Math.Min(position, partitionSize), partitionSize);
                        };
                    }
                    else
                    {
                        file.OnProgress += tasker.OnProgress;
                    }

                    switch (task)
                    {
                    case NandTasks.DumpNandB:
                        Shared.ShellPipe($"dd if=/dev/mapper/root-crypt bs=128K count={(partitionSize / 1024) / 4 }", null, file, throwOnNonZero: true);
                        break;

                    case NandTasks.FlashNandB:
                        Shared.ShellPipe("dd of=/dev/mapper/root-crypt bs=128K", file, throwOnNonZero: true);
                        hakchi.Shell.Execute("cryptsetup close root-crypt", throwOnNonZero: true);
                        break;

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

                    case NandTasks.FlashNandC:
                        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=/dev/nandc bs=128K", file, throwOnNonZero: true);
                        }
                        break;

                    case NandTasks.DumpNand:
                        Shared.ShellPipe("sntool sunxi_flash phy_read 0 1000", null, file, throwOnNonZero: true);
                        break;
                    }
                    file.Close();
                }

                tasker.SetStatus(Resources.Done);
                tasker.SetProgress(1, 1);
                return Conclusion.Success;
            });
        }
Example #9
0
        private Tasker.Conclusion InstallSDPart2(Tasker tasker, Object sync)
        {
            var splitStream = new SplitterStream(Program.debugStreams);

            tasker.SetStatus(Resources.MountingSDCard);
            if (DialogOptions.MakeBootable)
            {
                hakchi.Shell.Execute("sh /tmp/init mount", null, splitStream, splitStream, 0, true);
            }
            else
            {
                hakchi.Shell.Execute("mkdir -p /data/", null, null, null, 0, true);
                hakchi.Shell.Execute("mount /dev/mmcblk0p1 /data/", null, null, null, 0, true);
            }

            hakchi.Shell.Execute("mkdir -p /data/hakchi/games/", null, null, null, 0, true);

            if (!DialogOptions.MakeBootable && DialogOptions.StoreSaves)
            {
                hakchi.Shell.Execute("mkdir -p /data/hakchi/saves/", null, null, null, 0, true);
            }

            if (DialogOptions.CopyType != SDFormatResult.CopyTypes.None)
            {
                using (EventStream copyDataProgress = new EventStream())
                {
                    var userDataDeviceName = Sunxi.NandInfo.GetNandInfo().GetDataPartition().Device;
                    splitStream.AddStreams(copyDataProgress);
                    copyDataProgress.OnData += (byte[] buffer) =>
                    {
                        tasker.SetStatus(System.Text.Encoding.ASCII.GetString(buffer));
                    };
                    tasker.SetStatus(Resources.CopyingNandDataToSDCard);
                    hakchi.Shell.Execute($"mkdir -p /{userDataDeviceName} && mount /dev/{userDataDeviceName} /{userDataDeviceName}", null, null, null, 0, true);

                    if (DialogOptions.CopyType == SDFormatResult.CopyTypes.Everything)
                    {
                        hakchi.Shell.Execute($"rsync -avc /{userDataDeviceName}/ /data/", null, splitStream, splitStream, 0, true);
                    }
                    else
                    {
                        var nandPath = DialogOptions.MakeBootable ? $"/{userDataDeviceName}/clover" : $"/{userDataDeviceName}/clover/profiles/0";
                        var dataPath = DialogOptions.MakeBootable ? "/data/clover" : "/data/hakchi/saves";

                        if (hakchi.Shell.Execute($"[ -d {nandPath} ]") == 0)
                        {
                            hakchi.Shell.Execute($"rsync -avc {nandPath} {dataPath}", null, splitStream, splitStream, 0, true);
                        }
                    }

                    hakchi.Shell.Execute($"umount /{userDataDeviceName}/ && rmdir /{userDataDeviceName}/", null, null, null, 0, true);
                    splitStream.RemoveStream(copyDataProgress);
                    copyDataProgress.Dispose();
                }
            }

            if (DialogOptions.MakeBootable)
            {
                tasker.SetStatus(Resources.CopyingHakchiToSDCard);
                hakchi.Shell.Execute("sh /tmp/init copy", null, splitStream, splitStream, 0, true);
                tasker.SetStatus(Resources.UnmountingSDCard);
                hakchi.Shell.Execute("sh /tmp/init unmount", null, splitStream, splitStream, 0, true);
            }

            return(Tasker.Conclusion.Success);
        }
Example #10
0
        private Tasker.Conclusion InstallSDPart1(Tasker tasker, Object sync)
        {
            tasker.SetStatus(Resources.InstallingHakchi);

            if (hakchi.Shell.Execute("[ -b /dev/mmcblk0 ]") != 0)
            {
                throw new Exception(Resources.NoSDCard);
            }

            var splitStream = new SplitterStream(Program.debugStreams);

            hakchi.Shell.Execute("mkdir -p /squashtools /tmp", null, null, null, 0, true);
            hakchi.Shell.Execute("umount /newroot");
            hakchi.Shell.Execute("losetup -d /dev/loop2");
            hakchi.Shell.Execute("umount /firmware");
            hakchi.Shell.Execute("mkdir -p /sd-temp/", null, null, null, 0, true);
            tasker.SetStatus(Resources.ExtractingHakchiToTemporaryFolder);
            hakchi.Shell.Execute("tar -xzvf - -C /sd-temp/", hakchi.Hmod.GetHmodStream(), null, null, 0, true); // 16
            tasker.SetProgress(16, 161);
            tasker.SetStatus(Resources.ClearingTheFirst32MBOfSDCard);
            hakchi.Shell.Execute("dd if=/dev/zero of=/dev/mmcblk0 bs=1M count=32", null, null, null, 0, true); // 32
            tasker.SetProgress(48, 161);
            if (DialogOptions.MakeBootable)
            {
                tasker.SetStatus(Resources.AddingHakchiMBR);
                hakchi.Shell.Execute("printf \"hakchi\\n%s\\n\" \"$(cat \"/sd-temp/var/version\")\" | dd \"of=/dev/mmcblk0\"", null, null, null, 0, true);
                tasker.SetProgress(49, 161);
                tasker.SetStatus(Resources.WritingFATFilesystem);
                hakchi.Shell.Execute("gunzip -c /sd-temp/sd/data.vfat.gz | dd of=/dev/mmcblk0 bs=1M seek=32", null, null, null, 0, true); // 96
                tasker.SetProgress(145, 161);
                tasker.SetStatus(Resources.WritingBoot0);
                hakchi.Shell.Execute("dd if=/sd-temp/sd/boot0.bin of=/dev/mmcblk0 bs=1K seek=8", null, null, null, 0, true); // 1
                tasker.SetProgress(146, 161);
                tasker.SetStatus(Resources.WritingUboot);
                hakchi.Shell.Execute("dd if=/sd-temp/sd/uboot.bin of=/dev/mmcblk0 bs=1K seek=19096", null, null, null, 0, true); // 1
                tasker.SetProgress(147, 161);
                tasker.SetStatus(Resources.WritingKernel);
                hakchi.Shell.Execute("dd if=/sd-temp/sd/kernel.img of=/dev/mmcblk0 bs=1K seek=20480", null, null, null, 0, true); // 4
                tasker.SetProgress(151, 161);

                tasker.SetStatus(Resources.WritingSquashFS);
                hakchi.Shell.Execute("dd \"if=/sd-temp/sd/squash.hsqs\" of=/dev/mmcblk0 bs=1K seek=40", null, null, null, 0, true); // 10
                tasker.SetProgress(161, 161);

                tasker.SetStatus(Resources.MountingSquashFS);

                hakchi.Shell.Execute($"losetup -o {1024 * 40} /dev/loop1 /dev/mmcblk0", null, null, null, 0, true);
                hakchi.Shell.Execute("mount /dev/loop1 /squashtools", null, null, null, 0, true);
                hakchi.Shell.Execute("cp /squashtools/init /tmp/init", null, null, null, 0, true);

                hakchi.Shell.Execute("sh /tmp/init partition", null, splitStream, splitStream, 0, true);
            }
            else
            {
                hakchi.Shell.Execute("echo sdprep | dd \"of=/dev/mmcblk0\"", null, null, null, 0, true);
                hakchi.Shell.Execute("mount /sd-temp/sd/squash.hsqs /squashtools", null, null, null, 0, true);
                hakchi.Shell.Execute("/squashtools/sfdisk /dev/mmcblk0", new MemoryStream(Encoding.ASCII.GetBytes("128M,,L\n")), splitStream, splitStream, 0, true);
            }

            return(Tasker.Conclusion.Success);
        }