func (m *InterfaceManager) undoSetupProfiles(task *state.Task, tomb *tomb.Tomb) error { st := task.State() st.Lock() defer st.Unlock() ss, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapName := ss.Name() // Get the name from SnapSetup and use it to find the current SideInfo // about the snap, if there is one. var snapst snapstate.SnapState err = snapstate.Get(st, snapName, &snapst) if err != nil && err != state.ErrNoState { return err } sideInfo := snapst.CurrentSideInfo() if sideInfo == nil { // The snap was not installed before so undo should remove security profiles. return m.removeProfilesForSnap(task, tomb, snapName) } else { // The snap was installed before so undo should setup the old security profiles. snapInfo, err := snap.ReadInfo(snapName, sideInfo) if err != nil { return err } return m.setupProfilesForSnap(task, tomb, snapInfo, snapst.DevMode) } }
func snapExecHook(snapName, revision, hookName string) error { rev, err := snap.ParseRevision(revision) if err != nil { return err } info, err := snap.ReadInfo(snapName, &snap.SideInfo{ Revision: rev, }) if err != nil { return err } hook := info.Hooks[hookName] if hook == nil { return fmt.Errorf("cannot find hook %q in %q", hookName, snapName) } // build the environment env := append(os.Environ(), hook.Env()...) // run the hook hookPath := filepath.Join(hook.Snap.HooksDir(), hook.Name) return syscallExec(hookPath, []string{hookPath}, env) }
func getSnapInfo(snapName string, revision snap.Revision) (*snap.Info, error) { if revision.Unset() { // User didn't supply a revision, so we need to get it via the snapd API // here because once we're inside the confinement it may be unavailable. snaps, err := Client().List([]string{snapName}) if err != nil { return nil, err } if len(snaps) == 0 { return nil, fmt.Errorf("cannot find snap %q", snapName) } if len(snaps) > 1 { return nil, fmt.Errorf(i18n.G("multiple snaps for %q: %d"), snapName, len(snaps)) } revision = snaps[0].Revision } info, err := snap.ReadInfo(snapName, &snap.SideInfo{ Revision: revision, }) if err != nil { return nil, err } return info, nil }
func (m *InterfaceManager) doSetupProfiles(task *state.Task, _ *tomb.Tomb) error { task.State().Lock() defer task.State().Unlock() // Get snap.Info from bits handed by the snap manager. ss, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapInfo, err := snap.ReadInfo(ss.Name(), ss.SideInfo) if err != nil { return err } snap.AddImplicitSlots(snapInfo) snapName := snapInfo.Name() // The snap may have been updated so perform the following operation to // ensure that we are always working on the correct state: // // - disconnect all connections to/from the given snap // - remembering the snaps that were affected by this operation // - remove the (old) snap from the interfaces repository // - add the (new) snap to the interfaces repository // - restore connections based on what is kept in the state // - if a connection cannot be restored then remove it from the state // - setup the security of all the affected snaps affectedSnaps, err := m.repo.DisconnectSnap(snapName) if err != nil { return err } // XXX: what about snap renames? We should remove the old name (or switch // to IDs in the interfaces repository) if err := m.repo.RemoveSnap(snapName); err != nil { return err } if err := m.repo.AddSnap(snapInfo); err != nil { if _, ok := err.(*interfaces.BadInterfacesError); ok { logger.Noticef("%s", err) } else { return err } } if err := m.reloadConnections(snapName); err != nil { return err } // FIXME: here we should not reconnect auto-connect plug/slot // pairs that were explicitly disconnected by the user if err := m.autoConnect(task, snapName, nil); err != nil { return err } if err := setupSnapSecurity(task, snapInfo, ss.DevModeAllowed(), m.repo); err != nil { return err } return m.setupAffectedSnaps(task, snapName, affectedSnaps) }
func snapExecApp(snapApp, revision, command string, args []string) error { rev, err := snap.ParseRevision(revision) if err != nil { return fmt.Errorf("cannot parse revision %q: %s", revision, err) } snapName, appName := snap.SplitSnapApp(snapApp) info, err := snap.ReadInfo(snapName, &snap.SideInfo{ Revision: rev, }) if err != nil { return fmt.Errorf("cannot read info for %q: %s", snapName, err) } app := info.Apps[appName] if app == nil { return fmt.Errorf("cannot find app %q in %q", appName, snapName) } cmdAndArgs, err := findCommand(app, command) if err != nil { return err } // strings.Split() is ok here because we validate all app fields // and the whitelist is pretty strict (see // snap/validate.go:appContentWhitelist) cmdArgv := strings.Split(cmdAndArgs, " ") cmd := cmdArgv[0] cmdArgs := cmdArgv[1:] // build the environment from the yaml env := append(os.Environ(), app.Env()...) // run the command fullCmd := filepath.Join(app.Snap.MountDir(), cmd) if command == "shell" { fullCmd = "/bin/bash" cmdArgs = nil } fullCmdArgs := []string{fullCmd} fullCmdArgs = append(fullCmdArgs, cmdArgs...) fullCmdArgs = append(fullCmdArgs, args...) if err := syscallExec(fullCmd, fullCmdArgs, env); err != nil { return fmt.Errorf("cannot exec %q: %s", fullCmd, err) } // this is never reached except in tests return nil }
func readInfoAnyway(name string, si *snap.SideInfo) (*snap.Info, error) { info, err := snap.ReadInfo(name, si) if _, ok := err.(*snap.NotFoundError); ok { reason := fmt.Sprintf("cannot read snap %q: %s", name, err) info := &snap.Info{ SuggestedName: name, Broken: reason, } info.Apps = snap.GuessAppsForBroken(info) if si != nil { info.SideInfo = *si } return info, nil } return info, err }
func (m *InterfaceManager) doSetupProfiles(task *state.Task, tomb *tomb.Tomb) error { task.State().Lock() defer task.State().Unlock() // Get snap.Info from bits handed by the snap manager. ss, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapInfo, err := snap.ReadInfo(ss.Name(), ss.SideInfo) if err != nil { return err } return m.setupProfilesForSnap(task, tomb, snapInfo, ss.DevModeAllowed()) }
func (s *infoSuite) TestReadInfo(c *C) { si := &snap.SideInfo{Revision: snap.R(42), EditedSummary: "esummary"} snapInfo1 := snaptest.MockSnap(c, sampleYaml, sampleContents, si) snapInfo2, err := snap.ReadInfo("sample", si) c.Assert(err, IsNil) c.Check(snapInfo2.Name(), Equals, "sample") c.Check(snapInfo2.Revision, Equals, snap.R(42)) c.Check(snapInfo2.Summary(), Equals, "esummary") c.Check(snapInfo2.Apps["app"].Command, Equals, "foo") c.Check(snapInfo2, DeepEquals, snapInfo1) }
func (s *infoSuite) checkInstalledSnapAndSnapFile(c *C, yaml string, contents string, hooks []string, checker func(c *C, info *snap.Info)) { // First check installed snap sideInfo := &snap.SideInfo{Revision: snap.R(42)} info0 := snaptest.MockSnap(c, yaml, contents, sideInfo) snaptest.PopulateDir(info0.MountDir(), emptyHooks(hooks...)) info, err := snap.ReadInfo(info0.Name(), sideInfo) c.Check(err, IsNil) checker(c, info) // Now check snap file snapPath := snaptest.MakeTestSnapWithFiles(c, yaml, emptyHooks(hooks...)) snapf, err := snap.Open(snapPath) c.Assert(err, IsNil) info, err = snap.ReadInfoFromSnapFile(snapf, nil) c.Check(err, IsNil) checker(c, info) }
func (m *InterfaceManager) doSetupProfiles(task *state.Task, tomb *tomb.Tomb) error { task.State().Lock() defer task.State().Unlock() // Get snap.Info from bits handed by the snap manager. snapsup, err := snapstate.TaskSnapSetup(task) if err != nil { return err } snapInfo, err := snap.ReadInfo(snapsup.Name(), snapsup.SideInfo) if err != nil { return err } opts := confinementOptions(snapsup.Flags) return m.setupProfilesForSnap(task, tomb, snapInfo, opts) }
// allLocalSnapInfos returns the information about the all current snaps and their SnapStates. func allLocalSnapInfos(st *state.State, all bool) ([]aboutSnap, error) { st.Lock() defer st.Unlock() snapStates, err := snapstate.All(st) if err != nil { return nil, err } about := make([]aboutSnap, 0, len(snapStates)) var firstErr error for _, snapst := range snapStates { var infos []*snap.Info var info *snap.Info var err error if all { for _, seq := range snapst.Sequence { info, err = snap.ReadInfo(seq.RealName, seq) if err != nil { break } infos = append(infos, info) } } else { info, err = snapst.CurrentInfo() infos = append(infos, info) } if err != nil { // XXX: aggregate instead? if firstErr == nil { firstErr = err } continue } for _, info := range infos { about = append(about, aboutSnap{info, snapst}) } } return about, firstErr }
func getSnapInfo(snapName string, revision snap.Revision) (*snap.Info, error) { if revision.Unset() { curFn := filepath.Join(dirs.SnapMountDir, snapName, "current") realFn, err := os.Readlink(curFn) if err != nil { return nil, fmt.Errorf("cannot find current revision for snap %s: %s", snapName, err) } rev := filepath.Base(realFn) revision, err = snap.ParseRevision(rev) if err != nil { return nil, fmt.Errorf("cannot read revision %s: %s", rev, err) } } info, err := snap.ReadInfo(snapName, &snap.SideInfo{ Revision: revision, }) if err != nil { return nil, err } return info, nil }