// setNextBoot will schedule the given os or kernel snap to be used in // the next boot func setNextBoot(s *SnapPart) error { if s.m.Type != snap.TypeOS && s.m.Type != snap.TypeKernel { return nil } bootloader, err := findBootloader() if err != nil { return fmt.Errorf("can not set next boot: %s", err) } var bootvar string switch s.m.Type { case snap.TypeOS: bootvar = "snappy_os" case snap.TypeKernel: bootvar = "snappy_kernel" } blobName := filepath.Base(squashfs.BlobPath(s.basedir)) if err := bootloader.SetBootVar(bootvar, blobName); err != nil { return err } if err := bootloader.SetBootVar("snappy_mode", "try"); err != nil { return err } return nil }
func (s *SnapPart) remove(inter interacter) (err error) { if err := s.deactivate(false, inter); err != nil && err != ErrSnapNotActive { return err } // ensure mount unit stops if err := s.m.removeSquashfsMount(s.basedir, inter); err != nil { return err } err = os.RemoveAll(s.basedir) if err != nil { return err } // best effort(?) os.Remove(filepath.Dir(s.basedir)) // remove the snap if err := os.RemoveAll(squashfs.BlobPath(s.basedir)); err != nil { return err } // remove the kernel assets (if any) if s.m.Type == snap.TypeKernel { if err := removeKernelAssets(s, inter); err != nil { logger.Noticef("removing kernel assets failed with %s", err) } } return nil }
// extractKernelAssets extracts kernel/initrd/dtb data from the given // SnapPart to a versionized bootloader directory so that the bootloader // can use it. func extractKernelAssets(s *SnapFile, inter progress.Meter, flags InstallFlags) error { if s.m.Type != snap.TypeKernel { return fmt.Errorf("can not extract kernel assets from snap type %q", s.Type()) } bootloader, err := findBootloader() if err != nil { return fmt.Errorf("can not extract kernel assets: %s", err) } // check if we are on a "grub" system. if so, no need to unpack // the kernel if oem, err := getGadget(); err == nil { if oem.Gadget.Hardware.Bootloader == "grub" { return nil } } // FIXME: feels wrong to use the instdir here, need something better // // now do the kernel specific bits blobName := filepath.Base(squashfs.BlobPath(s.instdir)) dstDir := filepath.Join(bootloader.Dir(), blobName) if err := os.MkdirAll(dstDir, 0755); err != nil { return err } dir, err := os.Open(dstDir) if err != nil { return err } defer dir.Close() for _, src := range []string{s.m.Kernel, s.m.Initrd} { if src == "" { continue } if err := s.deb.Unpack(src, dstDir); err != nil { return err } src = filepath.Join(dstDir, src) dst := filepath.Join(dstDir, dropVersionSuffix(src)) if err := os.Rename(src, dst); err != nil { return err } if err := dir.Sync(); err != nil { return err } } if s.m.Dtbs != "" { src := filepath.Join(s.m.Dtbs, "*") dst := dstDir if err := s.deb.Unpack(src, dst); err != nil { return err } } return dir.Sync() }
// Uninstall removes the given local snap from the system. // // It returns an error on failure func (o *Overlord) Uninstall(s *SnapPart, meter progress.Meter) error { // Gadget snaps should not be removed as they are a key // building block for Gadgets. Prunning non active ones // is acceptible. if s.m.Type == snap.TypeGadget && s.IsActive() { return ErrPackageNotRemovable } // You never want to remove an active kernel or OS if (s.m.Type == snap.TypeKernel || s.m.Type == snap.TypeOS) && s.IsActive() { return ErrPackageNotRemovable } if IsBuiltInSoftware(s.Name()) && s.IsActive() { return ErrPackageNotRemovable } deps, err := s.DependentNames() if err != nil { return err } if len(deps) != 0 { return ErrFrameworkInUse(deps) } if err := s.deactivate(false, meter); err != nil && err != ErrSnapNotActive { return err } // ensure mount unit stops if err := removeSquashfsMount(s.m, s.basedir, meter); err != nil { return err } err = os.RemoveAll(s.basedir) if err != nil { return err } // best effort(?) os.Remove(filepath.Dir(s.basedir)) // remove the snap if err := os.RemoveAll(squashfs.BlobPath(s.basedir)); err != nil { return err } // remove the kernel assets (if any) if s.m.Type == snap.TypeKernel { if err := removeKernelAssets(s, meter); err != nil { logger.Noticef("removing kernel assets failed with %s", err) } } return RemoveAllHWAccess(QualifiedName(s)) }
// removeKernelAssets removes the unpacked kernel/initrd for the given // kernel snap func removeKernelAssets(s *SnapPart, inter interacter) error { if s.m.Type != snap.TypeKernel { return fmt.Errorf("can not remove kernel assets from snap type %q", s.Type()) } bootloader, err := findBootloader() if err != nil { return fmt.Errorf("no not remove kernel assests: %s", err) } // remove the kernel blob blobName := filepath.Base(squashfs.BlobPath(s.basedir)) dstDir := filepath.Join(bootloader.Dir(), blobName) if err := os.RemoveAll(dstDir); err != nil { return err } return nil }
func (m *packageYaml) addSquashfsMount(baseDir string, inhibitHooks bool, inter interacter) error { squashfsPath := stripGlobalRootDir(squashfs.BlobPath(baseDir)) whereDir := stripGlobalRootDir(baseDir) sysd := systemd.New(dirs.GlobalRootDir, inter) mountUnitName, err := sysd.WriteMountUnitFile(m.Name, squashfsPath, whereDir) if err != nil { return err } // we always enable the mount unit even in inhibit hooks if err := sysd.Enable(mountUnitName); err != nil { return err } if !inhibitHooks { return sysd.Start(mountUnitName) } return nil }
func kernelOrOsRebootRequired(s *SnapPart) bool { if s.m.Type != snap.TypeKernel && s.m.Type != snap.TypeOS { return false } bootloader, err := findBootloader() if err != nil { logger.Noticef("can not get boot settings: %s", err) return false } var nextBoot, goodBoot string switch s.m.Type { case snap.TypeKernel: nextBoot = "snappy_kernel" goodBoot = "snappy_good_kernel" case snap.TypeOS: nextBoot = "snappy_os" goodBoot = "snappy_good_os" } nextBootVer, err := bootloader.GetBootVar(nextBoot) if err != nil { return false } goodBootVer, err := bootloader.GetBootVar(goodBoot) if err != nil { return false } squashfsName := filepath.Base(stripGlobalRootDir(squashfs.BlobPath(s.basedir))) if nextBootVer == squashfsName && goodBootVer != nextBootVer { return true } return false }