gitee.com/mysnapcore/mysnapd@v0.1.0/snap/snapenv/snapenv.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2014-2015 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package snapenv
    21  
    22  import (
    23  	"os"
    24  	"os/user"
    25  	"path/filepath"
    26  
    27  	"gitee.com/mysnapcore/mysnapd/arch"
    28  	"gitee.com/mysnapcore/mysnapd/dirs"
    29  	"gitee.com/mysnapcore/mysnapd/features"
    30  	"gitee.com/mysnapcore/mysnapd/logger"
    31  	"gitee.com/mysnapcore/mysnapd/osutil"
    32  	"gitee.com/mysnapcore/mysnapd/osutil/sys"
    33  	"gitee.com/mysnapcore/mysnapd/snap"
    34  )
    35  
    36  // PreservedUnsafePrefix is used to escape env variables that are
    37  // usually stripped out by ld.so when starting a setuid process, to preserve
    38  // them through snap-confine (for classic confined snaps).
    39  const PreservedUnsafePrefix = "SNAP_SAVED_"
    40  
    41  var userCurrent = user.Current
    42  
    43  // ExtendEnvForRun extends the given environment with what is is
    44  // required for snap-{confine,exec}, that means SNAP_{NAME,REVISION}
    45  // etc are all set.
    46  //
    47  // It ensures all SNAP_* override any pre-existing environment
    48  // variables.
    49  func ExtendEnvForRun(env osutil.Environment, info *snap.Info, opts *dirs.SnapDirOptions) {
    50  	// Set various SNAP_ environment variables as well as some non-SNAP variables,
    51  	// depending on snap confinement mode. Note that this does not include environment
    52  	// set by snap-exec.
    53  	for k, v := range snapEnv(info, opts) {
    54  		env[k] = v
    55  	}
    56  }
    57  
    58  func snapEnv(info *snap.Info, opts *dirs.SnapDirOptions) osutil.Environment {
    59  	// Environment variables with basic properties of a snap.
    60  	env := basicEnv(info)
    61  	if usr, err := userCurrent(); err == nil && usr.HomeDir != "" {
    62  		// Environment variables with values specific to the calling user.
    63  		for k, v := range userEnv(info, usr.HomeDir, opts) {
    64  			env[k] = v
    65  		}
    66  	}
    67  	return env
    68  }
    69  
    70  // basicEnv returns the app-level environment variables for a snap.
    71  // Despite this being a bit snap-specific, this is in helpers.go because it's
    72  // used by so many other modules, we run into circular dependencies if it's
    73  // somewhere more reasonable like the snappy module.
    74  func basicEnv(info *snap.Info) osutil.Environment {
    75  	env := osutil.Environment{
    76  		// This uses CoreSnapMountDir because the computed environment
    77  		// variables are conveyed to the started application process which
    78  		// shall *either* execute with the new mount namespace where snaps are
    79  		// always mounted on /snap OR it is a classically confined snap where
    80  		// /snap is a part of the distribution package.
    81  		//
    82  		// For parallel-installs the mount namespace setup is making the
    83  		// environment of each snap instance appear as if it's the only
    84  		// snap, i.e. SNAP paths point to the same locations within the
    85  		// mount namespace
    86  		"SNAP":               filepath.Join(dirs.CoreSnapMountDir, info.SnapName(), info.Revision.String()),
    87  		"SNAP_COMMON":        snap.CommonDataDir(info.SnapName()),
    88  		"SNAP_DATA":          snap.DataDir(info.SnapName(), info.Revision),
    89  		"SNAP_NAME":          info.SnapName(),
    90  		"SNAP_INSTANCE_NAME": info.InstanceName(),
    91  		"SNAP_INSTANCE_KEY":  info.InstanceKey,
    92  		"SNAP_VERSION":       info.Version,
    93  		"SNAP_REVISION":      info.Revision.String(),
    94  		"SNAP_ARCH":          arch.DpkgArchitecture(),
    95  		// see https://github.com/snapcore/snapd/pull/2732#pullrequestreview-18827193
    96  		"SNAP_LIBRARY_PATH": "/var/lib/snapd/lib/gl:/var/lib/snapd/lib/gl32:/var/lib/snapd/void",
    97  		"SNAP_REEXEC":       os.Getenv("SNAP_REEXEC"),
    98  	}
    99  
   100  	// Add the ubuntu-save specific environment variable if
   101  	// the snap folder exists in the save directory.
   102  	if exists, isDir, err := osutil.DirExists(snap.CommonDataSaveDir(info.InstanceName())); err == nil && exists && isDir {
   103  		env["SNAP_SAVE_DATA"] = snap.CommonDataSaveDir(info.InstanceName())
   104  	} else if err != nil {
   105  		logger.Noticef("cannot determine existence of save data directory for snap %q: %v",
   106  			info.InstanceName(), err)
   107  	}
   108  	return env
   109  }
   110  
   111  // userEnv returns the user-level environment variables for a snap.
   112  // Despite this being a bit snap-specific, this is in helpers.go because it's
   113  // used by so many other modules, we run into circular dependencies if it's
   114  // somewhere more reasonable like the snappy module.
   115  func userEnv(info *snap.Info, home string, opts *dirs.SnapDirOptions) osutil.Environment {
   116  	if opts == nil {
   117  		opts = &dirs.SnapDirOptions{}
   118  	}
   119  
   120  	// To keep things simple the user variables always point to the
   121  	// instance-specific directories.
   122  	env := osutil.Environment{
   123  		"SNAP_USER_COMMON": info.UserCommonDataDir(home, opts),
   124  		"SNAP_USER_DATA":   info.UserDataDir(home, opts),
   125  	}
   126  	if info.NeedsClassic() {
   127  		// Snaps using classic confinement don't have an override for
   128  		// HOME but may have an override for XDG_RUNTIME_DIR.
   129  		if !features.ClassicPreservesXdgRuntimeDir.IsEnabled() {
   130  			env["XDG_RUNTIME_DIR"] = info.UserXdgRuntimeDir(sys.Geteuid())
   131  		}
   132  	} else {
   133  		// Snaps using strict or devmode confinement get an override for both
   134  		// HOME and XDG_RUNTIME_DIR.
   135  		env["HOME"] = info.UserDataDir(home, opts)
   136  		env["XDG_RUNTIME_DIR"] = info.UserXdgRuntimeDir(sys.Geteuid())
   137  	}
   138  	// Provide the location of the real home directory.
   139  	env["SNAP_REAL_HOME"] = home
   140  
   141  	if opts.MigratedToExposedHome {
   142  		env["XDG_DATA_HOME"] = filepath.Join(info.UserDataDir(home, opts), "xdg-data")
   143  		env["XDG_CONFIG_HOME"] = filepath.Join(info.UserDataDir(home, opts), "xdg-config")
   144  		env["XDG_CACHE_HOME"] = filepath.Join(info.UserDataDir(home, opts), "xdg-cache")
   145  
   146  		env["SNAP_USER_HOME"] = info.UserExposedHomeDir(home)
   147  		env["HOME"] = info.UserExposedHomeDir(home)
   148  	}
   149  	return env
   150  }