diff -Nru goget-ubuntu-touch-0.10/debian/changelog goget-ubuntu-touch-0.16/debian/changelog --- goget-ubuntu-touch-0.10/debian/changelog 2015-02-17 20:11:14.000000000 +0000 +++ goget-ubuntu-touch-0.16/debian/changelog 2015-02-17 20:11:14.000000000 +0000 @@ -1,3 +1,59 @@ +goget-ubuntu-touch (0.16-0ubuntu1) vivid; urgency=medium + + * ubuntu-device-flash: oem part to allow for dtb overrides. + * debian/control: dep on fakeroot for ubuntu-device-flash. + + -- Sergio Schvezov Thu, 29 Jan 2015 15:23:27 -0300 + +goget-ubuntu-touch (0.15-0ubuntu1) vivid; urgency=medium + + [ Loïc Minier ] + * ubuntu-device-flash: fixed ftdfile -> fdtfile typo. + + [ Sergio Schvezov ] + * ubuntu-device-flash: + - future proof efi support for grub and provisioning boot partition. + - using test instead of load in snappy-commands.txt + + -- Sergio Schvezov Wed, 28 Jan 2015 19:53:33 -0300 + +goget-ubuntu-touch (0.14-0ubuntu1) vivid; urgency=medium + + * Partition sizing multiplier matters for the emulator disk. (LP: #1412495) + + -- Sergio Schvezov Wed, 21 Jan 2015 20:23:14 -0300 + +goget-ubuntu-touch (0.13-0ubuntu1) vivid; urgency=medium + + * Setting a fixed set of ssh host keys to create. + * Updating ubuntu-device-flash's manpage and code to generate it. + + -- Sergio Schvezov Mon, 19 Jan 2015 18:45:29 -0300 + +goget-ubuntu-touch (0.12-0ubuntu1) vivid; urgency=medium + + * ubuntu-device-flash: + - replicating system-a into system-b for slow devices. + - setting the cloud-init password to ubuntu. + - updating to a new snappy-system.txt. + - bug fixes to relax requirements for devices. + + -- Sergio Schvezov Fri, 16 Jan 2015 13:17:27 -0300 + +goget-ubuntu-touch (0.11-0ubuntu0) vivid; urgency=medium + + [ Sergio Schvezov ] + * ubuntu-devce-flash: + - add fixrtc to cmdline. + - use msdos for core when appropriate. + - relax rules for the device tarball. + - fix provisioning errors when not overriding the device part. + + [ Jani Monoses ] + * ubuntu-device-flash: allow overriding custom for touch. + + -- Sergio Schvezov Thu, 15 Jan 2015 23:20:52 -0300 + goget-ubuntu-touch (0.10-0ubuntu1) vivid; urgency=medium [ Sergio Schvezov ] diff -Nru goget-ubuntu-touch-0.10/debian/control goget-ubuntu-touch-0.16/debian/control --- goget-ubuntu-touch-0.10/debian/control 2015-02-17 20:11:14.000000000 +0000 +++ goget-ubuntu-touch-0.16/debian/control 2015-02-17 20:11:14.000000000 +0000 @@ -19,7 +19,9 @@ Architecture: any Depends: android-tools-adb, android-tools-fastboot, + fakeroot, kpartx, + qemu-user-static, ${misc:Depends}, ${shlibs:Depends}, Built-Using: ${misc:Built-Using} diff -Nru goget-ubuntu-touch-0.10/debian/ubuntu-device-flash.1 goget-ubuntu-touch-0.16/debian/ubuntu-device-flash.1 --- goget-ubuntu-touch-0.10/debian/ubuntu-device-flash.1 2015-02-17 20:11:14.000000000 +0000 +++ goget-ubuntu-touch-0.16/debian/ubuntu-device-flash.1 2015-02-17 20:11:14.000000000 +0000 @@ -1,68 +1,125 @@ -.TH UBUNTU-DEVICE-FLASH 1 - +.TH ubuntu-device-flash 1 "19 January 2015" .SH NAME -ubuntu-device-flash \- provision supported Nexus devices with Ubuntu - +ubuntu-device-flash \- .SH SYNOPSIS -.B ubuntu-device-flash -[OPTIONS] - +\fBubuntu-device-flash\fP [OPTIONS] .SH DESCRIPTION -.B ubuntu-device-flash -Use this tool to flash a suported device with Ubuntu by either -bootstrapping from fastboot or reflashing from an already -supported device. .SH OPTIONS -\fB\-bootstrap\fR=\fIfalse\fR: Bootstrap the system, do this from fastboot -.HP -\fB\-channel=\fR"stable": Select channel to flash -.HP -\fB\-device=\fR"": Select device to flash -.HP -\fB\-list\-channels\fR=\fIfalse\fR: List available channels -.HP -\fB\-revision\fR=\fI0\fR: Revision to flash, 0 is current, use explicit version number or negative relative ones to current -.HP -\fB\-serial=\fR"": Serial of the device to operate -.HP -\fB\-server=\fR"https://system\-image.ubuntu.com": Select image server -.HP -\fB\-wipe\fR=\fIfalse\fR: Clear all data after flashing - -.SH EXAMPLES -To list the available channels on the server for the connected device -.PP -.nf -.RS -ubuntu-device-flash --list-channels -.RE -.fi -.PP - -To flash a full image over an existing Ubuntu Touch install with a different -channel -.PP -.nf -.RS -ubuntu-device-flash --channel [channel] -.RE -.fi -.PP - -To flash a full image over a non Ubuntu Touch install with the default -channel, do the following from fastboot -.PP -.nf -.RS -ubuntu-device-flash --bootstrap -.RE -.fi -.PP - -.SH ENVIRONMENT -.IP XDG_CACHE_HOME -If set, downloads take place in XDG_CACHE_HOME/ubuntuimages - -.SH AUTHOR -Sergio Schvezov +.TP +\fB--revision\fP +revision to use, absolute or relative allowed +.TP +\fB--download-only\fP +Only download. +.TP +\fB--server\fP +Use a different image server +.TP +\fB--clean-cache\fP +Cleans up cache with all downloaded bits +.TP +\fB--tls-skip-verify\fP +Skip TLS certificate validation +.TP +\fB-v, --verbose\fP +More messages will be printed out +.SH COMMANDS +.SS core +Creates ubuntu core images + +\fBUsage\fP: ubuntu-device-flash [OPTIONS] core [core-OPTIONS] + +.TP +\fB--channel\fP +Specify the channel to use +.TP +\fB--device\fP +Specify the device to use +.TP +\fB--keyboard-layout\fP +Specify the keyboard layout +.TP +\fB-o, --output\fP +Name of the image file to create +.TP +\fB-s, --size\fP +Size of image file to create in GB (min 4) +.TP +\fB--developer-mode\fP +Finds the latest public key in your ~/.ssh and sets it up using cloud-init +.TP +\fB--enable-ssh\fP +Enable ssh on the image through cloud-init(not needed with developer mode) +.TP +\fB--cloud\fP +Generate a pure cloud image without setting up cloud-init +.TP +\fB--platform\fP +specify the boards platform +.TP +\fB--install\fP +install additional packages (can be called multiple times) +.TP +\fB--device-part\fP +Specify a local device part to override the one from the server +.SS query +Run queries against the image server + +Choose from the list of query options to retrieve information from the server + +\fBUsage\fP: ubuntu-device-flash [OPTIONS] query [query-OPTIONS] + +.TP +\fB--list-channels\fP +List available channels +.TP +\fB--list-images\fP +List available images for a channel +.TP +\fB--show-image\fP +Show information for an image in the given channel +.TP +\fB--channel\fP +Specify an alternate channel +.TP +\fB--device\fP +Specify the device to use as a base for querying +.SS touch +Flashes ubuntu touch images + +\fBUsage\fP: ubuntu-device-flash [OPTIONS] touch [touch-OPTIONS] + +.TP +\fB--bootstrap\fP +bootstrap the system, do this from the bootloader +.TP +\fB--wipe\fP +Clear all data after flashing +.TP +\fB--serial\fP +Serial of the device to operate +.TP +\fB--developer-mode\fP +Enables developer mode after the factory reset, this is meant for automation and makes the device insecure by default (requires --password) +.TP +\fB--device-tarball\fP +Specify a local device tarball to override the one from the server (using official Ubuntu images with different device tarballs) +.TP +\fB--custom-tarball\fP +Specify a local custom tarball to override the one from the server (using official Ubuntu images with different custom tarballs) +.TP +\fB--run-script\fP +Run a script given by path to finish the flashing process, instead of rebooting to recovery (mostly used during development to work around quirky or incomplete recovery images) +.TP +\fB--password\fP +This sets up the default password for the phablet user. This option is meant for CI and not general use +.TP +\fB--channel\fP +Specify the channel to use +.TP +\fB--device\fP +Specify the device to flash +.TP +\fB--recovery-image\fP +Specify the recovery image file to use when flashing, overriding the one from the device tarball (useful if the latter has no adb enabled) diff -Nru goget-ubuntu-touch-0.10/diskimage/common.go goget-ubuntu-touch-0.16/diskimage/common.go --- goget-ubuntu-touch-0.10/diskimage/common.go 2015-01-12 20:12:00.000000000 +0000 +++ goget-ubuntu-touch-0.16/diskimage/common.go 2015-01-29 14:26:00.000000000 +0000 @@ -9,7 +9,9 @@ import ( "fmt" + "os" "os/exec" + "path/filepath" "strings" ) @@ -25,6 +27,14 @@ // You should have received a copy of the GNU General Public License along // with this program. If not, see . +var debugPrint bool + +func init() { + if debug := os.Getenv("DEBUG_DISK"); debug != "" { + debugPrint = true + } +} + type Image interface { Mount() error Unmount() error @@ -43,7 +53,7 @@ type CoreImage interface { Image SystemImage - SetupBoot() error + SetupBoot(OemDescription) error FlashExtra(string) error } @@ -55,6 +65,18 @@ Bootloader string `yaml:"bootloader"` } +type OemDescription struct { + Name string `yaml:"name"` + Version string `yaml:"version"` + Hardware struct { + Dtb string `yaml:"dtb,omitempty"` + } `yaml:"hardware,omitempty"` +} + +func (o OemDescription) InstallPath() string { + return filepath.Join("/oem", o.Name, o.Version) +} + func sectorSize(dev string) (string, error) { out, err := exec.Command("blockdev", "--getss", dev).CombinedOutput() if err != nil { @@ -63,3 +85,9 @@ return strings.TrimSpace(string(out)), err } + +func printOut(args ...interface{}) { + if debugPrint { + fmt.Println(args...) + } +} diff -Nru goget-ubuntu-touch-0.10/diskimage/core_grub.go goget-ubuntu-touch-0.16/diskimage/core_grub.go --- goget-ubuntu-touch-0.10/diskimage/core_grub.go 2015-01-12 20:12:00.000000000 +0000 +++ goget-ubuntu-touch-0.16/diskimage/core_grub.go 2015-01-29 14:26:00.000000000 +0000 @@ -114,7 +114,7 @@ //Partition creates a partitioned image from an img func (img *CoreGrubImage) Partition() error { - if err := sysutils.CreateEmptyFile(img.location, img.size); err != nil { + if err := sysutils.CreateEmptyFile(img.location, img.size, sysutils.GB); err != nil { return err } @@ -247,6 +247,19 @@ return filepath.Join(img.baseMount, string(writableDir)) } +// Boot returns the system-boot path +func (img CoreGrubImage) Boot() string { + if img.parts == nil { + panic("img is not setup with partitions") + } + + if img.baseMount == "" { + panic("img not mounted") + } + + return filepath.Join(img.baseMount, string(bootDir)) +} + //System returns the system path func (img CoreGrubImage) System() string { if img.parts == nil { @@ -268,7 +281,7 @@ return img.baseMount } -func (img *CoreGrubImage) SetupBoot() error { +func (img *CoreGrubImage) SetupBoot(oem OemDescription) error { for _, dev := range []string{"dev", "proc", "sys"} { src := filepath.Join("/", dev) dst := filepath.Join(img.System(), dev) @@ -303,6 +316,30 @@ } defer unmount(rootDevPath) + efiDir := filepath.Join(img.System(), "boot", "efi") + if err := os.MkdirAll(efiDir, 0755); err != nil { + return fmt.Errorf("unable to create %s dir: %s", efiDir, err) + } + + if err := bindMount(img.Boot(), efiDir); err != nil { + return err + } + defer unmount(efiDir) + + // create efi layout + efiGrubDir := filepath.Join(img.System(), "boot", "efi", "EFI", "ubuntu", "grub") + if err := os.MkdirAll(efiGrubDir, 0755); err != nil { + return fmt.Errorf("unable to create %s dir: %s", efiGrubDir, err) + } + + bootGrubDir := filepath.Join(img.System(), "boot", "grub") + + if err := bindMount(efiGrubDir, bootGrubDir); err != nil { + return err + } + defer unmount(bootGrubDir) + + // install grub if out, err := exec.Command("chroot", img.System(), "grub-install", "/root_dev").CombinedOutput(); err != nil { return fmt.Errorf("unable to install grub: %s", out) } diff -Nru goget-ubuntu-touch-0.10/diskimage/core_uboot.go goget-ubuntu-touch-0.16/diskimage/core_uboot.go --- goget-ubuntu-touch-0.10/diskimage/core_uboot.go 2015-01-12 20:12:00.000000000 +0000 +++ goget-ubuntu-touch-0.16/diskimage/core_uboot.go 2015-01-29 14:26:00.000000000 +0000 @@ -46,8 +46,8 @@ platform string } -const snappySystemTemplate = `# This is a snappy variables and boot logic file and is entirely generated and managed by Snappy -# Modification can break boot +const snappySystemTemplate = `# This is a snappy variables and boot logic file and is entirely generated and +# managed by Snappy. Modifications may break boot ###### # functions to load kernel, initrd and fdt from various env values loadfiles=run loadkernel; run loadinitrd; run loadfdt @@ -55,11 +55,14 @@ loadinitrd=load mmc ${mmcdev}:${mmcpart} ${initrd_addr} ${snappy_ab}/${initrd_file}; setenv initrd_size ${filesize} loadfdt=load mmc ${mmcdev}:${mmcpart} ${fdtaddr} ${snappy_ab}/dtbs/${fdtfile} -# standard kernel and initrd file names; NB: ftdfile is set early from bootcmd +# standard kernel and initrd file names; NB: fdtfile is set early from bootcmd kernel_file=vmlinuz initrd_file=initrd.img {{ . }} +# extra kernel cmdline args, set via mmcroot +snappy_cmdline=init=/lib/systemd/systemd ro panic=-1 fixrtc + # boot logic # either "a" or "b"; target partition we want to boot snappy_ab=a @@ -69,7 +72,7 @@ snappy_mode=regular # if we're trying a new version, check if stamp file is already there to revert # to other version -snappy_boot=if test "${snappy_mode}" = "try"; then if fatsize ${snappy_stamp}; then if test "${snappy_ab}" = "a"; then setenv snappy_ab "b"; else setenv snappy_ab "a"; fi; else fatwrite mmc ${mmcdev}:${mmcpart} 0x0 ${snappy_stamp} 0; fi; fi; run loadfiles; setenv mmcroot /dev/disk/by-label/system-${snappy_ab} init=/lib/systemd/systemd ro panic=-1; run mmcargs; bootz ${loadaddr} ${initrd_addr}:${initrd_size} ${fdtaddr} +snappy_boot=if test "${snappy_mode}" = "try"; then if test -e mmc ${bootpart} ${snappy_stamp}; then if test "${snappy_ab}" = "a"; then setenv snappy_ab "b"; else setenv snappy_ab "a"; fi; else fatwrite mmc ${mmcdev}:${mmcpart} 0x0 ${snappy_stamp} 0; fi; fi; run loadfiles; setenv mmcroot /dev/disk/by-label/system-${snappy_ab} ${snappy_cmdline}; run mmcargs; bootz ${loadaddr} ${initrd_addr}:${initrd_size} ${fdtaddr} ` type FlashInstructions struct { @@ -114,7 +117,10 @@ if img.baseMount == "" { panic("No base mountpoint set") } - defer os.Remove(img.baseMount) + defer func() { + os.Remove(img.baseMount) + img.baseMount = "" + }() if out, err := exec.Command("sync").CombinedOutput(); err != nil { return fmt.Errorf("Failed to sync filesystems before unmounting: %s", out) @@ -123,22 +129,20 @@ for _, part := range img.parts { mountpoint := filepath.Join(img.baseMount, string(part.dir)) if out, err := exec.Command("umount", mountpoint).CombinedOutput(); err != nil { - return fmt.Errorf("unable to unmount dir for image: %s", out) + panic(fmt.Sprintf("unable to unmount dir for image: %s", out)) } } - img.baseMount = "" - return nil } //Partition creates a partitioned image from an img func (img *CoreUBootImage) Partition() error { - if err := sysutils.CreateEmptyFile(img.location, img.size); err != nil { + if err := sysutils.CreateEmptyFile(img.location, img.size, sysutils.GB); err != nil { return err } - parted, err := newParted(mkLabelGpt) + parted, err := newParted(mkLabelMsdos) if err != nil { return err } @@ -286,10 +290,11 @@ return img.baseMount } -func (img CoreUBootImage) SetupBoot() error { +func (img CoreUBootImage) SetupBoot(oem OemDescription) error { // destinations bootPath := filepath.Join(img.baseMount, string(bootDir)) bootAPath := filepath.Join(bootPath, "a") + bootBPath := filepath.Join(bootPath, "b") bootDtbPath := filepath.Join(bootAPath, "dtbs") bootuEnvPath := filepath.Join(bootPath, "uEnv.txt") bootSnappySystemPath := filepath.Join(bootPath, "snappy-system.txt") @@ -298,51 +303,38 @@ hardwareYamlPath := filepath.Join(img.baseMount, "hardware.yaml") kernelPath := filepath.Join(img.baseMount, img.hardware.Kernel) initrdPath := filepath.Join(img.baseMount, img.hardware.Initrd) - dtbsPath := filepath.Join(img.baseMount, img.hardware.Dtbs) - flashAssetsPath := filepath.Join(img.baseMount, "flashtool-assets", img.platform) // create layout if err := os.MkdirAll(bootDtbPath, 0755); err != nil { return err } - if err := move(hardwareYamlPath, filepath.Join(bootAPath, "hardware.yaml")); err != nil { + if err := os.MkdirAll(bootBPath, 0755); err != nil { return err } - if err := move(kernelPath, filepath.Join(bootAPath, "vmlinuz")); err != nil { + if err := copyFile(hardwareYamlPath, filepath.Join(bootAPath, "hardware.yaml")); err != nil { return err } - if err := move(initrdPath, filepath.Join(bootAPath, "initrd.img")); err != nil { + if err := copyFile(kernelPath, filepath.Join(bootAPath, filepath.Base(kernelPath))); err != nil { return err } - dtbFis, err := ioutil.ReadDir(dtbsPath) - if err != nil { + if err := copyFile(initrdPath, filepath.Join(bootAPath, filepath.Base(initrdPath))); err != nil { return err } - dtb := filepath.Join(dtbsPath, fmt.Sprintf("%s.dtb", img.platform)) + if err := img.provisionDtbs(oem, bootDtbPath); err != nil { + return err + } - // if there is a specific dtb for the platform, copy it. - if _, err := os.Stat(dtb); err == nil { - dst := filepath.Join(bootDtbPath, filepath.Base(dtb)) - if err := move(dtb, dst); err != nil { - return err - } - } else { - for _, dtbFi := range dtbFis { - src := filepath.Join(dtbsPath, dtbFi.Name()) - dst := filepath.Join(bootDtbPath, dtbFi.Name()) - if err := move(src, dst); err != nil { - return err - } - } + if err := img.provisionUenv(bootuEnvPath); err != nil { + return err } // create /boot/uboot - if os.MkdirAll(filepath.Join(img.System(), "boot", "uboot"), 755); err != nil { + if err := os.MkdirAll(filepath.Join(img.System(), "boot", "uboot"), 755); err != nil { return err } @@ -352,20 +344,80 @@ } defer snappySystemFile.Close() - var ftdfile string + var fdtfile string if img.platform != "" { - ftdfile = fmt.Sprintf("ftdfile=%s.dtb", img.platform) + fdtfile = fmt.Sprintf("fdtfile=%s.dtb", img.platform) } t := template.Must(template.New("snappy-system").Parse(snappySystemTemplate)) - t.Execute(snappySystemFile, ftdfile) + t.Execute(snappySystemFile, fdtfile) - if img.platform != "" { - uEnvPath := filepath.Join(flashAssetsPath, "uEnv.txt") + return nil +} + +func (img CoreUBootImage) provisionUenv(bootuEnvPath string) error { + if img.platform == "" { + printOut("No platform select, not searching for uEnv.txt") + return nil + } + + flashAssetsPath := filepath.Join(img.baseMount, "flashtool-assets", img.platform) + uEnvPath := filepath.Join(flashAssetsPath, "uEnv.txt") + + if _, err := os.Stat(flashAssetsPath); os.IsNotExist(err) { + printOut("No flash assets path available") + return nil + } else if err != nil { + return err + } - // if a uEnv.txt is provided in the bootloader-assets, use it - if _, err := os.Stat(uEnvPath); err == nil { - if err := move(uEnvPath, bootuEnvPath); err != nil { + // if a uEnv.txt is provided in the flashtool-assets, use it + if _, err := os.Stat(uEnvPath); err == nil { + printOut("Adding uEnv.txt to", bootuEnvPath) + if err := copyFile(uEnvPath, bootuEnvPath); err != nil { + return err + } + } else { + printOut("Can't copy", uEnvPath, "to", bootuEnvPath, "due to:", err) + } + + return nil +} + +func (img CoreUBootImage) provisionDtbs(oem OemDescription, bootDtbPath string) error { + dtbsPath := filepath.Join(img.baseMount, img.hardware.Dtbs) + + if _, err := os.Stat(dtbsPath); os.IsNotExist(err) { + return nil + } else if err != nil { + return err + } + + dtbFis, err := ioutil.ReadDir(dtbsPath) + if err != nil { + return err + } + + dtb := filepath.Join(dtbsPath, fmt.Sprintf("%s.dtb", img.platform)) + + // if there is a specific dtb for the platform, copy it. + // First look in oem and then in device. + if oem.Hardware.Dtb != "" && img.platform != "" { + oemDtb := filepath.Join(img.System(), oem.InstallPath(), oem.Hardware.Dtb) + dst := filepath.Join(bootDtbPath, filepath.Base(dtb)) + if err := copyFile(oemDtb, dst); err != nil { + return err + } + } else if _, err := os.Stat(dtb); err == nil { + dst := filepath.Join(bootDtbPath, filepath.Base(dtb)) + if err := copyFile(dtb, dst); err != nil { + return err + } + } else { + for _, dtbFi := range dtbFis { + src := filepath.Join(dtbsPath, dtbFi.Name()) + dst := filepath.Join(bootDtbPath, dtbFi.Name()) + if err := copyFile(src, dst); err != nil { return err } } @@ -386,7 +438,13 @@ defer os.RemoveAll(tmpdir) if out, err := exec.Command("tar", "xf", devicePart, "-C", tmpdir, "flashtool-assets").CombinedOutput(); err != nil { - return fmt.Errorf("failed to extract the flashtool-assets from the device part: %s", out) + fmt.Println("No flashtool-assets found, skipping...") + if debugPrint { + fmt.Println("device part:", devicePart) + fmt.Println("command output:", string(out)) + } + + return nil } flashAssetsPath := filepath.Join(tmpdir, "flashtool-assets", img.platform) @@ -424,7 +482,7 @@ return nil } -func move(src, dst string) error { +func copyFile(src, dst string) error { dstFile, err := os.Create(dst) if err != nil { return err @@ -435,7 +493,6 @@ if err != nil { return err } - defer os.Remove(src) defer srcFile.Close() reader := bufio.NewReader(srcFile) diff -Nru goget-ubuntu-touch-0.10/diskimage/image.go goget-ubuntu-touch-0.16/diskimage/image.go --- goget-ubuntu-touch-0.10/diskimage/image.go 2015-01-12 20:12:00.000000000 +0000 +++ goget-ubuntu-touch-0.16/diskimage/image.go 2015-01-28 22:44:25.000000000 +0000 @@ -155,7 +155,7 @@ panic("creating ext4 on images with multiple parts not supported") } - if err := sysutils.CreateEmptyFile(img.path, img.size); err != nil { + if err := sysutils.CreateEmptyFile(img.path, img.size, sysutils.GiB); err != nil { return err } @@ -164,7 +164,7 @@ //CreateVFat returns a vfat partition for a given file func (img DiskImage) CreateVFat() error { - if err := sysutils.CreateEmptyFile(img.path, img.size); err != nil { + if err := sysutils.CreateEmptyFile(img.path, img.size, sysutils.GiB); err != nil { return err } return exec.Command("mkfs.vfat", "-n", img.label, img.path).Run() diff -Nru goget-ubuntu-touch-0.10/diskimage/partition.go goget-ubuntu-touch-0.16/diskimage/partition.go --- goget-ubuntu-touch-0.10/diskimage/partition.go 2015-01-12 20:12:00.000000000 +0000 +++ goget-ubuntu-touch-0.16/diskimage/partition.go 2015-01-16 04:09:04.000000000 +0000 @@ -10,6 +10,8 @@ import ( "errors" "fmt" + "io" + "os" "os/exec" ) @@ -46,7 +48,10 @@ writableDir directory = "writable" ) -const mkLabelGpt mklabelType = "gpt" +const ( + mkLabelGpt mklabelType = "gpt" + mkLabelMsdos mklabelType = "msdos" +) const ( fsFat32 fsType = "fat32" @@ -73,7 +78,7 @@ } func newParted(mklabel mklabelType) (*parted, error) { - if mklabel != mkLabelGpt { + if mklabel != mkLabelGpt && mklabel != mkLabelMsdos { return nil, errUnsupportedPartitioning } @@ -115,18 +120,44 @@ return err } + stdout, err := partedCmd.StdoutPipe() + if err != nil { + return err + } + + stderr, err := partedCmd.StderrPipe() + if err != nil { + return err + } + if err := partedCmd.Start(); err != nil { return err } stdin.Write([]byte(fmt.Sprintf("mklabel %s\n", p.mklabel))) - for _, parts := range p.parts { - if parts.end != -1 { - stdin.Write([]byte(fmt.Sprintf("mkpart %s %s %ds %ds\n", parts.label, parts.fs, parts.begin, parts.end))) - } else { - stdin.Write([]byte(fmt.Sprintf("mkpart %s %s %ds %dM\n", parts.label, parts.fs, parts.begin, parts.end))) + if p.mklabel == mkLabelGpt { + for _, parts := range p.parts { + if parts.end != -1 { + stdin.Write([]byte(fmt.Sprintf("mkpart %s %s %ds %ds\n", parts.label, parts.fs, parts.begin, parts.end))) + } else { + stdin.Write([]byte(fmt.Sprintf("mkpart %s %s %ds %dM\n", parts.label, parts.fs, parts.begin, parts.end))) + } + } + } else if p.mklabel == mkLabelMsdos { + if len(p.parts) > 4 { + panic("invalid amount of partitions for msdos") + } + + for _, parts := range p.parts { + if parts.end != -1 { + stdin.Write([]byte(fmt.Sprintf("mkpart primary %s %ds %ds\n", parts.fs, parts.begin, parts.end))) + } else { + stdin.Write([]byte(fmt.Sprintf("mkpart primary %s %ds %dM\n", parts.fs, parts.begin, parts.end))) + } } + } else { + panic("unsupported mklabel for partitioning") } if p.bootPartition != 0 { @@ -139,6 +170,11 @@ stdin.Write([]byte("quit\n")) + if debugPrint { + go io.Copy(os.Stdout, stdout) + go io.Copy(os.Stderr, stderr) + } + if err := partedCmd.Wait(); err != nil { return errors.New("issues while partitioning") } diff -Nru goget-ubuntu-touch-0.10/sysutils/utils.go goget-ubuntu-touch-0.16/sysutils/utils.go --- goget-ubuntu-touch-0.10/sysutils/utils.go 2015-01-14 14:34:39.000000000 +0000 +++ goget-ubuntu-touch-0.16/sysutils/utils.go 2015-01-28 22:44:25.000000000 +0000 @@ -27,7 +27,14 @@ "syscall" ) -func CreateEmptyFile(path string, size int64) (err error) { +type unit int64 + +const ( + GiB unit = 1024 + GB unit = 1000 +) + +func CreateEmptyFile(path string, size int64, u unit) (err error) { file, err := os.Create(path) if err != nil { return err @@ -38,7 +45,16 @@ os.Remove(path) } }() - size = size * 1024 * 1024 * 1024 + + switch u { + case GiB: + size = size * 1024 * 1024 * 1024 + case GB: + size = size * 1000 * 1000 * 1000 + default: + panic("improper sizing unit used") + } + if err := file.Truncate(size); err != nil { return errors.New(fmt.Sprintf("Error creating %s of size %d to stage image onto", path, size)) } diff -Nru goget-ubuntu-touch-0.10/ubuntu-device-flash/common.go goget-ubuntu-touch-0.16/ubuntu-device-flash/common.go --- goget-ubuntu-touch-0.10/ubuntu-device-flash/common.go 2015-01-12 20:12:00.000000000 +0000 +++ goget-ubuntu-touch-0.16/ubuntu-device-flash/common.go 2015-01-16 04:09:04.000000000 +0000 @@ -86,6 +86,11 @@ return strings.Contains(path, "device") } +// isCustomPart checks if the file corresponds to the custom part. +func isCustomPart(path string) bool { + return strings.Contains(path, "custom") +} + func copyFile(src, dst string) error { dstFile, err := os.Create(dst) if err != nil { diff -Nru goget-ubuntu-touch-0.10/ubuntu-device-flash/core.go goget-ubuntu-touch-0.16/ubuntu-device-flash/core.go --- goget-ubuntu-touch-0.10/ubuntu-device-flash/core.go 2015-01-14 14:34:39.000000000 +0000 +++ goget-ubuntu-touch-0.16/ubuntu-device-flash/core.go 2015-01-29 14:26:00.000000000 +0000 @@ -55,7 +55,7 @@ Output string `long:"output" short:"o" description:"Name of the image file to create" required:"true"` Size int64 `long:"size" short:"s" description:"Size of image file to create in GB (min 4)" default:"20"` DeveloperMode bool `long:"developer-mode" description:"Finds the latest public key in your ~/.ssh and sets it up using cloud-init"` - EnableSsh bool `long:"enable-ssh" description:"Enable ssh on the image through cloud-init(not need with developer mode)"` + EnableSsh bool `long:"enable-ssh" description:"Enable ssh on the image through cloud-init(not needed with developer mode)"` Cloud bool `long:"cloud" description:"Generate a pure cloud image without setting up cloud-init"` Platform string `long:"platform" description:"specify the boards platform"` Install []string `long:"install" description:"install additional packages (can be called multiple times)"` @@ -73,9 +73,10 @@ ` const cloudInitUserData = `#cloud-config -password: passw0rd +password: ubuntu chpasswd: { expire: False } ssh_pwauth: True +ssh_genkeytypes: ['rsa', 'dsa', 'ecdsa', 'ed25519'] ` func (coreCmd *CoreCmd) Execute(args []string) error { @@ -144,6 +145,8 @@ f := <-filesChan if isDevicePart(f.FilePath) { + devicePart = f.FilePath + if hardware, err := extractHWDescription(f.FilePath); err != nil { fmt.Println("Failed to read harware.yaml from device part, provisioning may fail:", err) } else { @@ -316,15 +319,21 @@ systemPath := img.System() - if err := img.SetupBoot(); err != nil { + if err := coreCmd.install(systemPath); err != nil { return err } - if err := coreCmd.setupKeyboardLayout(systemPath); err != nil { + // check if we installed an oem snap + oem, err := loadOem(systemPath) + if err != nil { return err } - if err := coreCmd.install(systemPath); err != nil { + if err := img.SetupBoot(oem); err != nil { + return err + } + + if err := coreCmd.setupKeyboardLayout(systemPath); err != nil { return err } @@ -340,6 +349,20 @@ } } + // if the device is armhf, we can't to make this copy here since it's faster + // than on the device. + if coreCmd.Device == "generic_armhf" && coreCmd.hardware.PartitionLayout == "system-AB" { + printOut("Replicating system-a into system-b") + + src := fmt.Sprintf("%s/.", systemPath) + dst := fmt.Sprintf("%s/system-b", img.BaseMount()) + + cmd := exec.Command("cp", "-r", "--preserve=all", src, dst) + if out, err := cmd.CombinedOutput(); err != nil { + return fmt.Errorf("failed to replicate image contents: %s", out) + } + } + return nil } @@ -477,6 +500,31 @@ return string(pubKey), err } +func loadOem(systemPath string) (oem diskimage.OemDescription, err error) { + pkgs, err := filepath.Glob(filepath.Join(systemPath, "/oem/*/*/meta/package.yaml")) + if err != nil { + return oem, err + } + + // checking for len(pkgs) > 2 due to the 'current' symlink + if len(pkgs) == 0 { + return oem, nil + } else if len(pkgs) > 2 || err != nil { + return oem, errors.New("too many oem packages installed") + } + + f, err := ioutil.ReadFile(pkgs[0]) + if err != nil { + return oem, errors.New("failed to read oem yaml") + } + + if err := goyaml.Unmarshal([]byte(f), &oem); err != nil { + return oem, errors.New("cannot decode oem yaml") + } + + return oem, nil +} + func extractHWDescription(path string) (hw diskimage.HardwareDescription, err error) { // hack to circumvent https://code.google.com/p/go/issues/detail?id=1435 if syscall.Getuid() == 0 { diff -Nru goget-ubuntu-touch-0.10/ubuntu-device-flash/main.go goget-ubuntu-touch-0.16/ubuntu-device-flash/main.go --- goget-ubuntu-touch-0.10/ubuntu-device-flash/main.go 2014-12-06 01:18:19.000000000 +0000 +++ goget-ubuntu-touch-0.16/ubuntu-device-flash/main.go 2015-01-28 22:44:25.000000000 +0000 @@ -45,6 +45,20 @@ func main() { args := os.Args + if v := os.Getenv("MANPAGE"); v != "" { + manpagePath := "/tmp/ubuntu-device-flash.manpage" + w, err := os.Create(manpagePath) + if err != nil { + fmt.Println(err) + return + } + + parser.WriteManPage(w) + fmt.Println("Created manpage at", manpagePath) + + return + } + if _, err := parser.ParseArgs(args); err != nil && parser.Active == nil { if e, ok := err.(*flags.Error); ok { if e.Type == flags.ErrHelp { diff -Nru goget-ubuntu-touch-0.10/ubuntu-device-flash/touch.go goget-ubuntu-touch-0.16/ubuntu-device-flash/touch.go --- goget-ubuntu-touch-0.10/ubuntu-device-flash/touch.go 2015-02-17 20:11:14.000000000 +0000 +++ goget-ubuntu-touch-0.16/ubuntu-device-flash/touch.go 2015-01-16 04:09:04.000000000 +0000 @@ -36,7 +36,8 @@ Wipe bool `long:"wipe" description:"Clear all data after flashing"` Serial string `long:"serial" description:"Serial of the device to operate"` DeveloperMode bool `long:"developer-mode" description:"Enables developer mode after the factory reset, this is meant for automation and makes the device insecure by default (requires --password)"` - DeviceTarball string `long:"device-tarball" description:"Specify a local device tarball to override the one from the server (using official Ubuntu images with custom device tarballs)"` + DeviceTarball string `long:"device-tarball" description:"Specify a local device tarball to override the one from the server (using official Ubuntu images with different device tarballs)"` + CustomTarball string `long:"custom-tarball" description:"Specify a local custom tarball to override the one from the server (using official Ubuntu images with different custom tarballs)"` RunScript string `long:"run-script" description:"Run a script given by path to finish the flashing process, instead of rebooting to recovery (mostly used during development to work around quirky or incomplete recovery images)"` Password string `long:"password" description:"This sets up the default password for the phablet user. This option is meant for CI and not general use"` Channel string `long:"channel" description:"Specify the channel to use" default:"ubuntu-touch/stable"` @@ -86,14 +87,24 @@ fmt.Println("WARNING --developer-mode and --password are dangerous as they remove security features from your device") } - var tarballPath string + var deviceTarballPath string if touchCmd.DeviceTarball != "" { p, err := expandFile(touchCmd.DeviceTarball) if err != nil { log.Fatalln("Issues while replacing the device tarball:", err) } - tarballPath = p + deviceTarballPath = p + } + + var customTarballPath string + if touchCmd.CustomTarball != "" { + p, err := expandFile(touchCmd.CustomTarball) + if err != nil { + log.Fatalln("Issues while replacing the custom tarball:", err) + } + + customTarballPath = p } channels, err := ubuntuimage.NewChannels(globalArgs.Server) @@ -131,10 +142,15 @@ done := make(chan bool, totalFiles) for i, file := range image.Files { - if tarballPath != "" && isDevicePart(file.Path) { + if deviceTarballPath != "" && isDevicePart(file.Path) { + //change the file paths so they are correctly picked up by bitPusher later on + image.Files[i].Path = deviceTarballPath + image.Files[i].Signature = deviceTarballPath + ".asc" + useLocalTarball(image.Files[i], files) + } else if customTarballPath != "" && isCustomPart(file.Path) { //change the file paths so they are correctly picked up by bitPusher later on - image.Files[i].Path = tarballPath - image.Files[i].Signature = tarballPath + ".asc" + image.Files[i].Path = customTarballPath + image.Files[i].Signature = customTarballPath + ".asc" useLocalTarball(image.Files[i], files) } else { go bitDownloader(file, files, globalArgs.Server, cacheDir)