func (s *HTestSuite) TestSnapRunSnapExecEnv(c *C) { info, err := snap.InfoFromSnapYaml(mockYaml) c.Assert(err, IsNil) info.SideInfo.Revision = snap.R(42) usr, err := user.Current() c.Assert(err, IsNil) homeEnv := os.Getenv("HOME") defer os.Setenv("HOME", homeEnv) for _, withHomeEnv := range []bool{true, false} { if !withHomeEnv { os.Setenv("HOME", "") } env := snapEnv(info) c.Check(env, DeepEquals, map[string]string{ "HOME": fmt.Sprintf("%s/snap/snapname/42", usr.HomeDir), "SNAP": fmt.Sprintf("%s/snapname/42", dirs.SnapMountDir), "SNAP_ARCH": arch.UbuntuArchitecture(), "SNAP_COMMON": "/var/snap/snapname/common", "SNAP_DATA": "/var/snap/snapname/42", "SNAP_LIBRARY_PATH": "/var/lib/snapd/lib/gl:", "SNAP_NAME": "snapname", "SNAP_REEXEC": "", "SNAP_REVISION": "42", "SNAP_USER_COMMON": fmt.Sprintf("%s/snap/snapname/common", usr.HomeDir), "SNAP_USER_DATA": fmt.Sprintf("%s/snap/snapname/42", usr.HomeDir), "SNAP_VERSION": "1.0", "XDG_RUNTIME_DIR": fmt.Sprintf("/run/user/%d/snap.snapname", os.Geteuid()), }) } }
// basicEnv returns the app-level environment variables for a snap. // Despite this being a bit snap-specific, this is in helpers.go because it's // used by so many other modules, we run into circular dependencies if it's // somewhere more reasonable like the snappy module. func basicEnv(info *snap.Info) map[string]string { return map[string]string{ "SNAP": info.MountDir(), "SNAP_COMMON": info.CommonDataDir(), "SNAP_DATA": info.DataDir(), "SNAP_NAME": info.Name(), "SNAP_VERSION": info.Version, "SNAP_REVISION": info.Revision.String(), "SNAP_ARCH": arch.UbuntuArchitecture(), "SNAP_LIBRARY_PATH": "/var/lib/snapd/lib/gl:", "SNAP_REEXEC": os.Getenv("SNAP_REEXEC"), } }
func (ts *HTestSuite) TestBasic(c *C) { env := basicEnv(mockSnapInfo) c.Assert(env, DeepEquals, map[string]string{ "SNAP": fmt.Sprintf("%s/foo/17", dirs.SnapMountDir), "SNAP_ARCH": arch.UbuntuArchitecture(), "SNAP_COMMON": "/var/snap/foo/common", "SNAP_DATA": "/var/snap/foo/17", "SNAP_LIBRARY_PATH": "/var/lib/snapd/lib/gl:", "SNAP_NAME": "foo", "SNAP_REEXEC": "", "SNAP_REVISION": "17", "SNAP_VERSION": "1.0", }) }
func (s *checkSnapSuite) TestCheckSnapErrorOnUnsupportedArchitecture(c *C) { const yaml = `name: hello version: 1.10 architectures: - yadayada - blahblah ` info, err := snap.InfoFromSnapYaml([]byte(yaml)) c.Assert(err, IsNil) var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) { c.Check(path, Equals, "snap-path") c.Check(si, IsNil) return info, nil, nil } restore := snapstate.MockOpenSnapFile(openSnapFile) defer restore() err = snapstate.CheckSnap(s.st, "snap-path", nil, nil, snapstate.Flags{}) errorMsg := fmt.Sprintf(`snap "hello" supported architectures (yadayada, blahblah) are incompatible with this system (%s)`, arch.UbuntuArchitecture()) c.Assert(err.Error(), Equals, errorMsg) }
// checkSnap ensures that the snap can be installed. func checkSnap(st *state.State, snapFilePath string, curInfo *snap.Info, flags Flags) error { // This assumes that the snap was already verified or --dangerous was used. s, _, err := openSnapFile(snapFilePath, nil) if err != nil { return err } if s.NeedsDevMode() && !flags.DevModeAllowed() { return fmt.Errorf("snap %q requires devmode or confinement override", s.Name()) } // verify we have a valid architecture if !arch.IsSupportedArchitecture(s.Architectures) { return fmt.Errorf("snap %q supported architectures (%s) are incompatible with this system (%s)", s.Name(), strings.Join(s.Architectures, ", "), arch.UbuntuArchitecture()) } // check assumes err = checkAssumes(s) if err != nil { return err } if s.Type != snap.TypeGadget { return nil } // gadget specific checks if release.OnClassic { // for the time being return fmt.Errorf("cannot install a gadget snap on classic") } st.Lock() defer st.Unlock() currentGadget, err := GadgetInfo(st) // in firstboot we have no gadget yet - that is ok if err == state.ErrNoState && !firstboot.HasRun() { return nil } if err != nil { return fmt.Errorf("cannot find original gadget snap") } // TODO: actually compare snap ids, from current gadget and candidate if currentGadget.Name() != s.Name() { return fmt.Errorf("cannot replace gadget snap with a different one") } return nil }
func SetUserAgentFromVersion(version string) { extras := make([]string, 1, 3) extras[0] = "series " + release.Series if release.OnClassic { extras = append(extras, "classic") } if release.ReleaseInfo.ForceDevMode() { extras = append(extras, "devmode") } // xxx this assumes ReleaseInfo's ID and VersionID don't have weird characters // (see rfc 7231 for values of weird) // assumption checks out in practice, q.v. https://github.com/zyga/os-release-zoo userAgent = fmt.Sprintf("snapd/%v (%s) %s/%s (%s)", version, strings.Join(extras, "; "), release.ReleaseInfo.ID, release.ReleaseInfo.VersionID, string(arch.UbuntuArchitecture())) }
// New creates a new Store with the given access configuration and for given the store id. func New(cfg *Config, authContext auth.AuthContext) *Store { if cfg == nil { cfg = &defaultConfig } fields := cfg.DetailFields if fields == nil { fields = detailFields } rawQuery := "" if len(fields) > 0 { v := url.Values{} v.Set("fields", strings.Join(fields, ",")) rawQuery = v.Encode() } var searchURI *url.URL if cfg.SearchURI != nil { uri := *cfg.SearchURI uri.RawQuery = rawQuery searchURI = &uri } var detailsURI *url.URL if cfg.DetailsURI != nil { uri := *cfg.DetailsURI uri.RawQuery = rawQuery detailsURI = &uri } var sectionsURI *url.URL if cfg.SectionsURI != nil { uri := *cfg.SectionsURI uri.RawQuery = rawQuery sectionsURI = &uri } architecture := arch.UbuntuArchitecture() if cfg.Architecture != "" { architecture = cfg.Architecture } series := release.Series if cfg.Series != "" { series = cfg.Series } deltaFormat := cfg.DeltaFormat if deltaFormat == "" { deltaFormat = defaultSupportedDeltaFormat } // see https://wiki.ubuntu.com/AppStore/Interfaces/ClickPackageIndex return &Store{ searchURI: searchURI, detailsURI: detailsURI, bulkURI: cfg.BulkURI, assertionsURI: cfg.AssertionsURI, ordersURI: cfg.OrdersURI, customersMeURI: cfg.CustomersMeURI, sectionsURI: sectionsURI, series: series, architecture: architecture, fallbackStoreID: cfg.StoreID, detailFields: fields, authContext: authContext, deltaFormat: deltaFormat, client: newHTTPClient(&httpClientOpts{ Timeout: 10 * time.Second, MayLogBody: true, }), } }
// New creates a new Store with the given access configuration and for given the store id. func New(cfg *Config, authContext auth.AuthContext) *Store { deltaDirs, _ := filepath.Glob(filepath.Join(dirs.SnapPartialBlobDir, "deltas-*")) for _, dir := range deltaDirs { os.RemoveAll(dir) } if cfg == nil { cfg = &defaultConfig } fields := cfg.DetailFields if fields == nil { fields = detailFields } rawQuery := "" if len(fields) > 0 { v := url.Values{} v.Set("fields", strings.Join(fields, ",")) rawQuery = v.Encode() } var searchURI *url.URL if cfg.SearchURI != nil { uri := *cfg.SearchURI uri.RawQuery = rawQuery searchURI = &uri } var detailsURI *url.URL if cfg.DetailsURI != nil { uri := *cfg.DetailsURI uri.RawQuery = rawQuery detailsURI = &uri } architecture := arch.UbuntuArchitecture() if cfg.Architecture != "" { architecture = cfg.Architecture } series := release.Series if cfg.Series != "" { series = cfg.Series } deltaFormat := cfg.DeltaFormat if deltaFormat == "" { deltaFormat = defaultSupportedDeltaFormat } // see https://wiki.ubuntu.com/AppStore/Interfaces/ClickPackageIndex return &Store{ searchURI: searchURI, detailsURI: detailsURI, bulkURI: cfg.BulkURI, assertionsURI: cfg.AssertionsURI, ordersURI: cfg.OrdersURI, customersMeURI: cfg.CustomersMeURI, series: series, architecture: architecture, fallbackStoreID: cfg.StoreID, detailFields: fields, client: newHTTPClient(), authContext: authContext, deltaFormat: deltaFormat, } }
[Service] ExecStart=/usr/bin/snap run snap.app Restart=on-failure WorkingDirectory=/var/snap/snap/44 ExecStop=/usr/bin/snap run --command=stop snap.app ExecStopPost=/usr/bin/snap run --command=post-stop snap.app TimeoutStopSec=10 %[2]s [Install] WantedBy=multi-user.target ` var ( expectedAppService = fmt.Sprintf(expectedServiceFmt, "After=snapd.frameworks.target\nRequires=snapd.frameworks.target", "Type=simple\n", arch.UbuntuArchitecture(), dirs.SnapMountDir) expectedDbusService = fmt.Sprintf(expectedServiceFmt, "After=snapd.frameworks.target\nRequires=snapd.frameworks.target", "Type=dbus\nBusName=foo.bar.baz", arch.UbuntuArchitecture(), dirs.SnapMountDir) ) var ( expectedServiceWrapperFmt = `[Unit] # Auto-generated, DO NO EDIT Description=Service for snap application xkcd-webserver.xkcd-webserver %s X-Snappy=yes [Service] ExecStart=/usr/bin/snap run xkcd-webserver Restart=on-failure WorkingDirectory=/var/snap/xkcd-webserver/44 ExecStop=/usr/bin/snap run --command=stop xkcd-webserver
// checkSnap ensures that the snap can be installed. func checkSnap(st *state.State, snapFilePath string, si *snap.SideInfo, curInfo *snap.Info, flags Flags) error { // This assumes that the snap was already verified or --dangerous was used. s, _, err := openSnapFile(snapFilePath, si) if err != nil { return err } if s.NeedsDevMode() && !flags.DevModeAllowed() { return fmt.Errorf("snap %q requires devmode or confinement override", s.Name()) } if s.NeedsClassic() { if !release.OnClassic { return fmt.Errorf("snap %q requires classic confinement which is only available on classic systems", s.Name()) } if !flags.Classic { return fmt.Errorf("snap %q requires consent to use classic confinement", s.Name()) } } // verify we have a valid architecture if !arch.IsSupportedArchitecture(s.Architectures) { return fmt.Errorf("snap %q supported architectures (%s) are incompatible with this system (%s)", s.Name(), strings.Join(s.Architectures, ", "), arch.UbuntuArchitecture()) } // check assumes err = checkAssumes(s) if err != nil { return err } st.Lock() defer st.Unlock() for _, check := range checkSnapCallbacks { err := check(st, s, curInfo, flags) if err != nil { return err } } return nil }
func archWithBrokenDevPtmx() error { if ubuArch := arch.UbuntuArchitecture(); ubuArch == "ppc64el" || ubuArch == "powerpc" { return fmt.Errorf("/dev/ptmx ioctl not working on %s", ubuArch) } return nil }