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 nameAndRevnoFromSnap(sn string) (string, snap.Revision, error) { l := strings.Split(sn, "_") if len(l) < 2 { return "", snap.Revision{}, fmt.Errorf("input %q has invalid format (not enough '_')", sn) } name := l[0] revnoNSuffix := l[1] rev, err := snap.ParseRevision(strings.Split(revnoNSuffix, ".snap")[0]) if err != nil { return "", snap.Revision{}, err } return name, rev, nil }
func (x *cmdDownload) Execute(args []string) error { if err := x.setChannelFromCommandline(); err != nil { return err } if len(args) > 0 { return ErrExtraArgs } var revision snap.Revision if x.Revision == "" { revision = snap.R(0) } else { var err error revision, err = snap.ParseRevision(x.Revision) if err != nil { return err } } snapName := string(x.Positional.Snap) // FIXME: set auth context var authContext auth.AuthContext var user *auth.UserState sto := store.New(nil, authContext) // we always allow devmode for downloads devMode := true dlOpts := image.DownloadOptions{ TargetDir: "", // cwd DevMode: devMode, Channel: x.Channel, User: user, } fmt.Fprintf(Stderr, i18n.G("Fetching snap %q\n"), snapName) snapPath, snapInfo, err := image.DownloadSnap(sto, snapName, revision, &dlOpts) if err != nil { return err } fmt.Fprintf(Stderr, i18n.G("Fetching assertions for %q\n"), snapName) err = fetchSnapAssertions(sto, snapPath, snapInfo, &dlOpts) if err != nil { return err } return nil }
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 snapRunHook(snapName, snapRevision, hookName string) error { revision, err := snap.ParseRevision(snapRevision) if err != nil { return err } info, err := getSnapInfo(snapName, revision) if err != nil { return err } hook := info.Hooks[hookName] if hook == nil { return fmt.Errorf(i18n.G("cannot find hook %q in %q"), hookName, snapName) } return runSnapConfine(info, hook.SecurityTag(), snapName, "", hook.Name, nil) }
func snapRunHook(snapName, snapRevision, hookName string) error { revision, err := snap.ParseRevision(snapRevision) if err != nil { return err } info, err := getSnapInfo(snapName, revision) if err != nil { return err } hook := info.Hooks[hookName] // Make sure this hook is valid for this snap. If not, don't run it. This // isn't an error, e.g. it will happen if a snap doesn't ship a system hook. if hook == nil { return nil } return runSnapConfine(info, hook.SecurityTag(), snapName, "", hook.Name, nil) }
func (s revisionSuite) ParseRevision(c *C) { type testItem struct { s string n int e string } var tests = []testItem{{ s: "unset", n: 0, }, { s: "x1", n: -1, }, { s: "1", n: 1, }, { s: "x-1", e: `invalid snap revision: "x-1"`, }, { s: "x0", e: `invalid snap revision: "x0"`, }, { s: "-1", e: `invalid snap revision: "-1"`, }, { s: "0", e: `invalid snap revision: "0"`, }} for _, test := range tests { r, err := snap.ParseRevision(test.s) if test.e != "" { c.Assert(err.Error(), Equals, test.e) continue } c.Assert(r, Equals, snap.R(test.n)) } }
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 }
func copySnap(snapName, targetDir string) (*info, error) { baseDir := filepath.Join(dirs.SnapMountDir, snapName) if _, err := os.Stat(baseDir); err != nil { return nil, err } sourceDir := filepath.Join(baseDir, "current") files, err := filepath.Glob(filepath.Join(sourceDir, "*")) if err != nil { return nil, err } revnoDir, err := filepath.EvalSymlinks(sourceDir) if err != nil { return nil, err } origRevision := filepath.Base(revnoDir) for _, m := range files { if err = exec.Command("sudo", "cp", "-a", m, targetDir).Run(); err != nil { return nil, err } } rev, err := snap.ParseRevision(origRevision) if err != nil { return nil, err } place := snap.MinimalPlaceInfo(snapName, rev) origDigest, origSize, err := asserts.SnapFileSHA3_384(place.MountFile()) if err != nil { return nil, err } return &info{revision: origRevision, size: origSize, digest: origDigest}, nil }