Exemple #1
0
func (x *cmdShell) Execute(args []string) error {
	if len(args) > 0 {
		return ErrExtraArgs
	}

	shellType := x.Positional.ShellType

	// FIXME: make this generic so that all snaps can provide a
	//        shell
	if shellType == "classic" {
		if !osutil.FileExists("/snap/classic/current") {
			return fmt.Errorf(i18n.G(`Classic dimension disabled on this system.
Use "sudo snap install --devmode classic && sudo classic.create" to enable it.`))
		}

		// we need to re-exec if we do not run as root
		if os.Getuid() != 0 {
			if err := reexecWithSudo(); err != nil {
				return err
			}
		}

		fmt.Fprintln(Stdout, i18n.G(`Entering classic dimension`))
		fmt.Fprintln(Stdout, i18n.G(`

The home directory is shared between snappy and the classic dimension.
Run "exit" to leave the classic shell.
`))
		args := []string{"/snap/bin/classic.shell"}
		return syscall.Exec(args[0], args, os.Environ())
	}

	return fmt.Errorf(i18n.G("unsupported shell %v"), shellType)
}
Exemple #2
0
func snapUpdateMany(inst *snapInstruction, st *state.State) (msg string, updated []string, tasksets []*state.TaskSet, err error) {
	// we need refreshed snap-declarations to enforce refresh-control as best as we can, this also ensures that snap-declarations and their prerequisite assertions are updated regularly
	if err := assertstateRefreshSnapDeclarations(st, inst.userID); err != nil {
		return "", nil, nil, err
	}

	updated, tasksets, err = snapstateUpdateMany(st, inst.Snaps, inst.userID)
	if err != nil {
		return "", nil, nil, err
	}

	switch len(inst.Snaps) {
	case 0:
		// all snaps
		msg = i18n.G("Refresh all snaps in the system")
	case 1:
		msg = fmt.Sprintf(i18n.G("Refresh snap %q"), inst.Snaps[0])
	default:
		quoted := make([]string, len(inst.Snaps))
		for i, name := range inst.Snaps {
			quoted[i] = strconv.Quote(name)
		}
		// TRANSLATORS: the %s is a comma-separated list of quoted snap names
		msg = fmt.Sprintf(i18n.G("Refresh snaps %s"), strings.Join(quoted, ", "))
	}

	return msg, updated, tasksets, nil
}
Exemple #3
0
func main() {
	cmd.ExecInCoreSnap()

	// magic \o/
	snapApp := filepath.Base(os.Args[0])
	if osutil.IsSymlink(filepath.Join(dirs.SnapBinariesDir, snapApp)) {
		cmd := &cmdRun{}
		args := []string{snapApp}
		args = append(args, os.Args[1:]...)
		// this will call syscall.Exec() so it does not return
		// *unless* there is an error, i.e. we setup a wrong
		// symlink (or syscall.Exec() fails for strange reasons)
		err := cmd.Execute(args)
		fmt.Fprintf(Stderr, i18n.G("internal error, please report: running %q failed: %v\n"), snapApp, err)
		os.Exit(46)
	}

	defer func() {
		if v := recover(); v != nil {
			if e, ok := v.(*exitStatus); ok {
				os.Exit(e.code)
			}
			panic(v)
		}
	}()

	// no magic /o\
	if err := run(); err != nil {
		fmt.Fprintf(Stderr, i18n.G("error: %v\n"), err)
		os.Exit(1)
	}
}
Exemple #4
0
func (x *cmdRun) Execute(args []string) error {
	if len(args) == 0 {
		return fmt.Errorf(i18n.G("need the application to run as argument"))
	}
	snapApp := args[0]
	args = args[1:]

	// Catch some invalid parameter combinations, provide helpful errors
	if x.Hook != "" && x.Command != "" {
		return fmt.Errorf(i18n.G("cannot use --hook and --command together"))
	}
	if x.Revision != "unset" && x.Revision != "" && x.Hook == "" {
		return fmt.Errorf(i18n.G("-r can only be used with --hook"))
	}
	if x.Hook != "" && len(args) > 0 {
		// TRANSLATORS: %q is the hook name; %s a space-separated list of extra arguments
		return fmt.Errorf(i18n.G("too many arguments for hook %q: %s"), x.Hook, strings.Join(args, " "))
	}

	// Now actually handle the dispatching
	if x.Hook != "" {
		return snapRunHook(snapApp, x.Revision, x.Hook)
	}

	// pass shell as a special command to snap-exec
	if x.Shell {
		x.Command = "shell"
	}

	return snapRunApp(snapApp, x.Command, args)
}
Exemple #5
0
func (x *cmdBooted) Execute(args []string) error {
	if len(args) > 0 {
		return ErrExtraArgs
	}

	if release.OnClassic {
		fmt.Fprintf(Stdout, i18n.G("Ignoring 'booted' on classic"))
		return nil
	}

	bootloader, err := partition.FindBootloader()
	if err != nil {
		return fmt.Errorf(i18n.G("cannot mark boot successful: %s"), err)
	}

	if err := partition.MarkBootSuccessful(bootloader); err != nil {
		return err
	}

	ovld, err := overlord.New()
	if err != nil {
		return err
	}
	return boot.UpdateRevisions(ovld)
}
Exemple #6
0
// Disable sets a snap to the inactive state
func Disable(s *state.State, name string) (*state.TaskSet, error) {
	var snapst SnapState
	err := Get(s, name, &snapst)
	if err == state.ErrNoState {
		return nil, fmt.Errorf("cannot find snap %q", name)
	}
	if err != nil {
		return nil, err
	}
	if !snapst.Active {
		return nil, fmt.Errorf("snap %q already disabled", name)
	}

	if err := checkChangeConflict(s, name, nil); err != nil {
		return nil, err
	}

	ss := &SnapSetup{
		SideInfo: &snap.SideInfo{
			RealName: name,
			Revision: snapst.Current,
		},
	}

	stopSnapServices := s.NewTask("stop-snap-services", fmt.Sprintf(i18n.G("Stop snap %q (%s) services"), ss.Name(), snapst.Current))
	stopSnapServices.Set("snap-setup", &ss)
	unlinkSnap := s.NewTask("unlink-snap", fmt.Sprintf(i18n.G("Make snap %q (%s) unavailable to the system"), ss.Name(), snapst.Current))
	unlinkSnap.Set("snap-setup-task", stopSnapServices.ID())
	unlinkSnap.WaitFor(stopSnapServices)

	return state.NewTaskSet(stopSnapServices, unlinkSnap), nil
}
Exemple #7
0
func listSnaps(names []string, all bool) error {
	cli := Client()
	snaps, err := cli.List(names, &client.ListOptions{All: all})
	if err != nil {
		if err == client.ErrNoSnapsInstalled {
			fmt.Fprintln(Stderr, i18n.G("No snaps are installed yet. Try \"snap install hello-world\"."))
			return nil
		}
		return err
	} else if len(snaps) == 0 {
		return errors.New(i18n.G("no matching snaps installed"))
	}
	sort.Sort(snapsByName(snaps))

	w := tabWriter()
	defer w.Flush()

	fmt.Fprintln(w, i18n.G("Name\tVersion\tRev\tDeveloper\tNotes"))

	for _, snap := range snaps {
		// TODO: make JailMode a flag in the snap itself
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", snap.Name, snap.Version, snap.Revision, snap.Developer, NotesFromLocal(snap))
	}

	return nil
}
Exemple #8
0
func init() {
	addCommand("find", shortFindHelp, longFindHelp, func() flags.Commander {
		return &cmdFind{}
	}, map[string]string{
		"private": i18n.G("Search private snaps"),
	}, []argDesc{{name: i18n.G("<query>")}})
}
Exemple #9
0
func (x *cmdRefresh) Execute([]string) error {
	if err := x.setChannelFromCommandline(); err != nil {
		return err
	}
	if err := x.validateMode(); err != nil {
		return err
	}

	if x.List {
		if x.asksForMode() || x.asksForChannel() {
			return errors.New(i18n.G("--list does not take mode nor channel flags"))
		}

		return listRefresh()
	}
	if len(x.Positional.Snaps) == 1 {
		opts := &client.SnapOptions{
			Channel:  x.Channel,
			DevMode:  x.DevMode,
			JailMode: x.JailMode,
			Revision: x.Revision,
		}
		return refreshOne(x.Positional.Snaps[0], opts)
	}

	if x.asksForMode() || x.asksForChannel() {
		return errors.New(i18n.G("a single snap name is needed to specify mode or channel flags"))
	}

	return refreshMany(x.Positional.Snaps, nil)
}
Exemple #10
0
// show what has been done
func showDone(names []string, op string) error {
	cli := Client()
	snaps, err := cli.List(names, nil)
	if err != nil {
		return err
	}

	for _, snap := range snaps {
		channelStr := ""
		if snap.Channel != "" && snap.Channel != "stable" {
			channelStr = fmt.Sprintf(" (%s)", snap.Channel)
		}
		switch op {
		case "install":
			if snap.Developer != "" {
				fmt.Fprintf(Stdout, i18n.G("%s%s %s from '%s' installed\n"), snap.Name, channelStr, snap.Version, snap.Developer)
			} else {
				fmt.Fprintf(Stdout, i18n.G("%s%s %s installed\n"), snap.Name, channelStr, snap.Version)
			}
		case "refresh":
			if snap.Developer != "" {
				fmt.Fprintf(Stdout, i18n.G("%s%s %s from '%s' refreshed\n"), snap.Name, channelStr, snap.Version, snap.Developer)
			} else {
				fmt.Fprintf(Stdout, i18n.G("%s%s %s refreshed\n"), snap.Name, channelStr, snap.Version)
			}
		default:
			fmt.Fprintf(Stdout, "internal error, unknown op %q", op)
		}
	}
	return nil
}
Exemple #11
0
func requestLoginWith2faRetry(email, password string) error {
	var otp []byte
	var err error

	var msgs = [3]string{
		i18n.G("Two-factor code: "),
		i18n.G("Bad code. Try again: "),
		i18n.G("Wrong again. Once more: "),
	}

	cli := Client()
	reader := bufio.NewReader(nil)

	for i := 0; ; i++ {
		// first try is without otp
		_, err = cli.Login(email, password, string(otp))
		if i >= len(msgs) || !client.IsTwoFactorError(err) {
			return err
		}

		reader.Reset(Stdin)
		fmt.Fprint(Stdout, msgs[i])
		// the browser shows it as well (and Sergio wants to see it ;)
		otp, _, err = reader.ReadLine()
		if err != nil {
			return err
		}
	}
}
Exemple #12
0
// Enable sets a snap to the active state
func Enable(s *state.State, name string) (*state.TaskSet, error) {
	var snapst SnapState
	err := Get(s, name, &snapst)
	if err == state.ErrNoState {
		return nil, fmt.Errorf("cannot find snap %q", name)
	}
	if err != nil {
		return nil, err
	}

	if snapst.Active {
		return nil, fmt.Errorf("snap %q already enabled", name)
	}

	if err := checkChangeConflict(s, name, nil); err != nil {
		return nil, err
	}

	ss := &SnapSetup{
		SideInfo: snapst.CurrentSideInfo(),
	}

	prepareSnap := s.NewTask("prepare-snap", fmt.Sprintf(i18n.G("Prepare snap %q (%s)"), ss.Name(), snapst.Current))
	prepareSnap.Set("snap-setup", &ss)

	linkSnap := s.NewTask("link-snap", fmt.Sprintf(i18n.G("Make snap %q (%s) available to the system"), ss.Name(), snapst.Current))
	linkSnap.Set("snap-setup", &ss)
	linkSnap.WaitFor(prepareSnap)

	startSnapServices := s.NewTask("start-snap-services", fmt.Sprintf(i18n.G("Start snap %q (%s) services"), ss.Name(), snapst.Current))
	startSnapServices.Set("snap-setup", &ss)
	startSnapServices.WaitFor(linkSnap)

	return state.NewTaskSet(prepareSnap, linkSnap, startSnapServices), nil
}
Exemple #13
0
func listRefresh() error {
	cli := Client()
	snaps, _, err := cli.Find(&client.FindOptions{
		Refresh: true,
	})
	if err != nil {
		return err
	}
	if len(snaps) == 0 {
		fmt.Fprintln(Stderr, i18n.G("All snaps up to date."))
		return nil
	}

	sort.Sort(snapsByName(snaps))

	w := tabWriter()
	defer w.Flush()

	fmt.Fprintln(w, i18n.G("Name\tVersion\tRev\tDeveloper\tNotes"))
	for _, snap := range snaps {
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", snap.Name, snap.Version, snap.Revision, snap.Developer, NotesFromRemote(snap, nil))
	}

	return nil
}
Exemple #14
0
func (x *cmdRevert) Execute(args []string) error {
	if len(args) > 0 {
		return ErrExtraArgs
	}

	if err := x.validateMode(); err != nil {
		return err
	}

	cli := Client()
	name := string(x.Positional.Snap)
	opts := &client.SnapOptions{DevMode: x.DevMode, JailMode: x.JailMode, Revision: x.Revision}
	changeID, err := cli.Revert(name, opts)
	if err != nil {
		return err
	}

	if _, err := wait(cli, changeID); err != nil {
		return err
	}

	// show output as speced
	snaps, err := cli.List([]string{name}, nil)
	if err != nil {
		return err
	}
	if len(snaps) != 1 {
		// TRANSLATORS: %q gets the snap name, %v the list of things found when trying to list it
		return fmt.Errorf(i18n.G("cannot get data for %q: %v"), name, snaps)
	}
	snap := snaps[0]
	fmt.Fprintf(Stdout, i18n.G("%s reverted to %s\n"), name, snap.Version)
	return nil
}
Exemple #15
0
func run() error {
	parser := Parser()
	_, err := parser.Parse()
	if err != nil {
		if e, ok := err.(*flags.Error); ok {
			if e.Type == flags.ErrHelp {
				if parser.Command.Active != nil && parser.Command.Active.Name == "help" {
					parser.Command.Active = nil
				}
				parser.WriteHelp(Stdout)
				return nil
			}
			if e.Type == flags.ErrUnknownCommand {
				return fmt.Errorf(i18n.G(`unknown command %q, see "snap --help"`), os.Args[1])
			}
		}
		if e, ok := err.(*client.Error); ok && e.Kind == client.ErrorKindLoginRequired {
			u, _ := user.Current()
			if u != nil && u.Username == "root" {
				return fmt.Errorf(i18n.G(`%s (see "snap login --help")`), e.Message)
			}

			// TRANSLATORS: %s will be a message along the lines of "login required"
			return fmt.Errorf(i18n.G(`%s (try with sudo)`), e.Message)
		}
	}

	return err
}
Exemple #16
0
func findSnaps(opts *client.FindOptions) error {
	cli := Client()
	snaps, resInfo, err := cli.Find(opts)
	if err != nil {
		return err
	}

	if len(snaps) == 0 {
		// TRANSLATORS: the %q is the (quoted) query the user entered
		return fmt.Errorf(i18n.G("no snaps found for %q"), opts.Query)
	}

	w := tabWriter()
	defer w.Flush()

	fmt.Fprintln(w, i18n.G("Name\tVersion\tDeveloper\tNotes\tSummary"))

	for _, snap := range snaps {
		notes := &Notes{
			Private: snap.Private,
			DevMode: snap.Confinement != client.StrictConfinement,
			Price:   getPriceString(snap.Prices, resInfo.SuggestedCurrency, snap.Status),
		}
		// TODO: get snap.Publisher, so we can only show snap.Developer if it's different
		fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\n", snap.Name, snap.Version, snap.Developer, notes, snap.Summary)
	}

	return nil
}
Exemple #17
0
func (x *cmdCreateKey) Execute(args []string) error {
	if len(args) > 0 {
		return ErrExtraArgs
	}

	keyName := x.Positional.KeyName
	if keyName == "" {
		keyName = "default"
	}
	if !asserts.IsValidAccountKeyName(keyName) {
		return fmt.Errorf(i18n.G("key name %q is not valid; only ASCII letters, digits, and hyphens are allowed"), keyName)
	}

	fmt.Fprint(Stdout, i18n.G("Passphrase: "))
	passphrase, err := terminal.ReadPassword(0)
	fmt.Fprint(Stdout, "\n")
	if err != nil {
		return err
	}
	fmt.Fprint(Stdout, i18n.G("Confirm passphrase: "))
	confirmPassphrase, err := terminal.ReadPassword(0)
	fmt.Fprint(Stdout, "\n")
	if err != nil {
		return err
	}
	if string(passphrase) != string(confirmPassphrase) {
		return errors.New("passphrases do not match")
	}
	if err != nil {
		return err
	}

	manager := asserts.NewGPGKeypairManager()
	return manager.Generate(string(passphrase), keyName)
}
Exemple #18
0
// patch3:
// - migrates pending tasks and add {start,stop}-snap-services tasks
func patch3(s *state.State) error {

	// migrate all pending tasks and insert "{start,stop}-snap-server"
	for _, t := range s.Tasks() {
		if t.Status().Ready() {
			continue
		}

		if t.Kind() == "link-snap" {
			startSnapServices := s.NewTask("start-snap-services", fmt.Sprintf(i18n.G("Start snap services")))
			startSnapServices.Set("snap-setup-task", t.ID())
			startSnapServices.WaitFor(t)

			chg := t.Change()
			chg.AddTask(startSnapServices)
		}

		if t.Kind() == "unlink-snap" || t.Kind() == "unlink-current-snap" {
			stopSnapServices := s.NewTask("stop-snap-services", fmt.Sprintf(i18n.G("Stop snap services")))
			stopSnapServices.Set("snap-setup-task", t.ID())
			t.WaitFor(stopSnapServices)

			chg := t.Change()
			chg.AddTask(stopSnapServices)
		}
	}

	return nil
}
Exemple #19
0
func init() {
	addCommand("disconnect", shortDisconnectHelp, longDisconnectHelp, func() flags.Commander {
		return &cmdDisconnect{}
	}, nil, []argDesc{
		{name: i18n.G("<snap>:<plug>")},
		{name: i18n.G("<snap>:<slot>")},
	})
}
Exemple #20
0
func init() {
	addCommand("ack", shortAckHelp, longAckHelp, func() flags.Commander {
		return &cmdAck{}
	}, nil, []argDesc{{
		name: i18n.G("<assertion file>"),
		desc: i18n.G("Assertion file"),
	}})
}
Exemple #21
0
func init() {
	addCommand("alias", shortAliasHelp, longAliasHelp, func() flags.Commander {
		return &cmdAlias{}
	}, nil, []argDesc{
		{name: i18n.G("<snap>")},
		{name: i18n.G("<alias>")},
	})
}
Exemple #22
0
func init() {
	cmd := addCommand("keys",
		i18n.G("List cryptographic keys"),
		i18n.G("List cryptographic keys that can be used for signing assertions."),
		func() flags.Commander {
			return &cmdKeys{}
		}, map[string]string{"json": i18n.G("Output results in JSON format")}, nil)
	cmd.hidden = true
}
Exemple #23
0
func init() {
	addCommand("download", shortDownloadHelp, longDownloadHelp, func() flags.Commander {
		return &cmdDownload{}
	}, channelDescs.also(map[string]string{
		"revision": i18n.G("Download the given revision of a snap, to which you must have developer access"),
	}), []argDesc{{
		name: "<snap>",
		desc: i18n.G("Snap name"),
	}})
}
Exemple #24
0
func init() {
	addCommand("interfaces", shortInterfacesHelp, longInterfacesHelp, func() flags.Commander {
		return &cmdInterfaces{}
	}, map[string]string{
		"i": i18n.G("Constrain listing to specific interfaces"),
	}, []argDesc{{
		name: i18n.G("<snap>:<slot or plug>"),
		desc: i18n.G("Constrain listing to a specific snap or snap:name"),
	}})
}
Exemple #25
0
func init() {
	addCommand("alias", shortAliasHelp, longAliasHelp, func() flags.Commander {
		return &cmdAlias{}
	}, map[string]string{
		"reset": i18n.G("Reset the aliases to their default state, enabled for automatic aliases, disabled otherwise"),
	}, []argDesc{
		{name: "<snap>"},
		{name: i18n.G("<alias>")},
	})
}
Exemple #26
0
func init() {
	addCommand("buy", shortBuyHelp, longBuyHelp, func() flags.Commander {
		return &cmdBuy{}
	}, map[string]string{
		"currency": i18n.G("ISO 4217 code for currency (https://en.wikipedia.org/wiki/ISO_4217)"),
	}, []argDesc{{
		name: "<snap>",
		desc: i18n.G("Snap name"),
	}})
}
Exemple #27
0
func init() {
	addCommand("set", shortSetHelp, longSetHelp, func() flags.Commander { return &cmdSet{} }, nil, []argDesc{
		{
			name: "<snap>",
			desc: i18n.G("The snap to configure (e.g. hello-world)"),
		}, {
			name: i18n.G("<conf value>"),
			desc: i18n.G("Configuration value (key=value)"),
		},
	})
}
Exemple #28
0
func init() {
	cmd := addCommand("delete-key",
		i18n.G("Delete cryptographic key pair"),
		i18n.G("Delete the local cryptographic key pair with the given name."),
		func() flags.Commander {
			return &cmdDeleteKey{}
		}, nil, []argDesc{{
			name: i18n.G("<key-name>"),
			desc: i18n.G("Name of key to delete"),
		}})
	cmd.hidden = true
}
Exemple #29
0
func init() {
	cmd := addCommand("auto-import",
		shortAutoImportHelp,
		longAutoImportHelp,
		func() flags.Commander {
			return &cmdAutoImport{}
		}, map[string]string{
			"mount":         i18n.G("Temporarily mount device before inspecting"),
			"force-classic": i18n.G("Force import on classic systems"),
		}, nil)
	cmd.hidden = true
}
Exemple #30
0
func init() {
	addCommand("login",
		shortLoginHelp,
		longLoginHelp,
		func() flags.Commander {
			return &cmdLogin{}
		}, nil, []argDesc{{
			// TRANSLATORS: noun
			name: i18n.G("<email>"),
			desc: i18n.G("The login.ubuntu.com email to login as"),
		}})
}