1 //------------------------------------------------------------------------------
3 // System.Environment.cs
5 // Copyright (C) 2001 Moonlight Enterprises, All Rights Reserved
7 // Author: Jim Richardson, develop@wtfo-guru.com
8 // Dan Lewis (dihlewis@yahoo.co.uk)
9 // Created: Saturday, August 11, 2001
11 //------------------------------------------------------------------------------
13 // Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 using System.Collections;
37 using System.Runtime.CompilerServices;
38 using System.Security;
39 using System.Security.Permissions;
45 public static class Environment {
47 public sealed class Environment {
49 private Environment ()
54 * This is the version number of the corlib-runtime interface. When
55 * making changes to this interface (by changing the layout
56 * of classes the runtime knows about, changing icall signature or
57 * semantics etc), increment this variable. Also increment the
58 * pair of this variable in the runtime in metadata/appdomain.c.
59 * Changes which are already detected at runtime, like the addition
60 * of icalls, do not require an increment.
62 private const int mono_corlib_version = 54;
64 public enum SpecialFolder
65 { // TODO: Determine if these windoze style folder identifiers
66 // have unix/linux counterparts
82 DesktopDirectory = 0x10,
84 ApplicationData = 0x1a,
85 LocalApplicationData = 0x1c,
89 CommonApplicationData = 0x23,
93 CommonProgramFiles = 0x2b,
97 /// Gets the command line for this process
99 public static string CommandLine {
100 // note: security demand inherited from calling GetCommandLineArgs
102 // FIXME: we may need to quote, but any sane person
103 // should use GetCommandLineArgs () instead.
104 return String.Join (" ", GetCommandLineArgs ());
109 /// Gets or sets the current directory. Actually this is supposed to get
110 /// and/or set the process start directory acording to the documentation
111 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
113 public static string CurrentDirectory
116 return Directory.GetCurrentDirectory ();
119 Directory.SetCurrentDirectory (value);
124 /// Gets or sets the exit code of this process
126 public extern static int ExitCode
128 [MethodImplAttribute (MethodImplOptions.InternalCall)]
130 [MethodImplAttribute (MethodImplOptions.InternalCall)]
137 public extern bool HasShutdownStarted
139 [MethodImplAttribute (MethodImplOptions.InternalCall)]
145 /// Gets the name of the local computer
147 public extern static string MachineName {
148 [MethodImplAttribute (MethodImplOptions.InternalCall)]
149 [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
150 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
155 /// Gets the standard new line value
157 public extern static string NewLine {
158 [MethodImplAttribute (MethodImplOptions.InternalCall)]
163 // Support methods and fields for OSVersion property
165 static OperatingSystem os;
167 internal static extern PlatformID Platform {
168 [MethodImplAttribute (MethodImplOptions.InternalCall)]
172 [MethodImplAttribute (MethodImplOptions.InternalCall)]
173 internal static extern string GetOSVersionString ();
176 /// Gets the current OS version information
178 public static OperatingSystem OSVersion {
181 Version v = Version.CreateFromString (GetOSVersionString ());
182 PlatformID p = Platform;
187 os = new OperatingSystem (p, v);
196 public static string StackTrace {
197 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
199 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (1, true);
200 return trace.ToString ();
205 /// Get a fully qualified path to the system directory
207 public static string SystemDirectory {
209 return GetFolderPath (SpecialFolder.System);
214 /// Get the number of milliseconds that have elapsed since the system was booted
216 public extern static int TickCount {
217 [MethodImplAttribute (MethodImplOptions.InternalCall)]
222 /// Get UserDomainName
224 public static string UserDomainName {
225 // FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
226 [EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
233 /// Gets a flag indicating whether the process is in interactive mode
235 [MonoTODO ("Currently always returns false, regardless of interactive state")]
236 public static bool UserInteractive {
243 /// Get the user name of current process is running under
245 public extern static string UserName {
246 [MethodImplAttribute (MethodImplOptions.InternalCall)]
247 [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
252 /// Get the version of the common language runtime
254 public static Version Version {
256 return new Version (Consts.FxFileVersion);
261 /// Get the amount of physical memory mapped to process
263 [MonoTODO ("Currently always returns zero")]
264 public static long WorkingSet {
265 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
269 [MethodImplAttribute (MethodImplOptions.InternalCall)]
270 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
271 public extern static void Exit (int exitCode);
274 /// Substitute environment variables in the argument "name"
276 public static string ExpandEnvironmentVariables (string name)
279 throw new ArgumentNullException ("name");
281 int off1 = name.IndexOf ('%');
285 int len = name.Length;
287 if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
290 StringBuilder result = new StringBuilder ();
291 result.Append (name, 0, off1);
292 Hashtable tbl = null;
294 string var = name.Substring (off1 + 1, off2 - off1 - 1);
295 string value = GetEnvironmentVariable (var);
296 if (value == null && Environment.IsRunningOnWindows) {
297 // On windows, env. vars. are case insensitive
299 tbl = GetEnvironmentVariablesNoCase ();
301 value = tbl [var] as string;
304 // If value not found, add %FOO to stream,
305 // and use the closing % for the next iteration.
306 // If value found, expand it in place of %FOO%
312 result.Append (value);
315 off1 = name.IndexOf ('%', off2 + 1);
316 // If no % found for off1, don't look for one for off2
317 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
318 // textLen is the length of text between the closing % of current iteration
319 // and the starting % of the next iteration if any. This text is added to output
321 // If no new % found, use all the remaining text
322 if (off1 == -1 || off2 == -1)
323 textLen = len - oldOff2 - 1;
324 // If value found in current iteration, use text after current closing % and next %
325 else if(value != null)
326 textLen = off1 - oldOff2 - 1;
327 // If value not found in current iteration, but a % was found for next iteration,
328 // use text from current closing % to the next %.
330 textLen = off1 - oldOff2;
331 if(off1 >= oldOff2 || off1 == -1)
332 result.Append (name, oldOff2+1, textLen);
333 } while (off2 > -1 && off2 < len);
335 return result.ToString ();
340 /// Return an array of the command line arguments of the current process
342 [MethodImplAttribute (MethodImplOptions.InternalCall)]
343 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
344 public extern static string[] GetCommandLineArgs ();
346 [MethodImplAttribute (MethodImplOptions.InternalCall)]
347 internal extern static string internalGetEnvironmentVariable (string name);
350 /// Return a string containing the value of the environment
351 /// variable identifed by parameter "variable"
353 public static string GetEnvironmentVariable (string name)
355 if (SecurityManager.SecurityEnabled) {
356 new EnvironmentPermission (EnvironmentPermissionAccess.Read, name).Demand ();
358 return internalGetEnvironmentVariable (name);
361 static Hashtable GetEnvironmentVariablesNoCase ()
363 Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
364 CaseInsensitiveComparer.Default);
366 foreach (string name in GetEnvironmentVariableNames ()) {
367 vars [name] = internalGetEnvironmentVariable (name);
374 /// Return a set of all environment variables and their values
377 public static IDictionary GetEnvironmentVariables ()
379 StringBuilder sb = null;
380 if (SecurityManager.SecurityEnabled) {
381 // we must have access to each variable to get the lot
382 sb = new StringBuilder ();
383 // but (performance-wise) we do not want a stack-walk
384 // for each of them so we concatenate them
387 Hashtable vars = new Hashtable ();
388 foreach (string name in GetEnvironmentVariableNames ()) {
389 vars [name] = internalGetEnvironmentVariable (name);
397 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
402 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
403 public static IDictionary GetEnvironmentVariables ()
405 Hashtable vars = new Hashtable ();
406 foreach (string name in GetEnvironmentVariableNames ()) {
407 vars [name] = internalGetEnvironmentVariable (name);
413 [MethodImplAttribute (MethodImplOptions.InternalCall)]
414 private extern static string GetWindowsFolderPath (int folder);
417 /// Returns the fully qualified path of the
418 /// folder specified by the "folder" parameter
420 public static string GetFolderPath (SpecialFolder folder)
424 if (Environment.IsRunningOnWindows) {
425 dir = GetWindowsFolderPath ((int) folder);
427 dir = InternalGetFolderPath (folder);
430 if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
431 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
436 // the security runtime (and maybe other parts of corlib) needs the
437 // information to initialize themselves before permissions can be checked
438 internal static string InternalGetFolderPath (SpecialFolder folder)
440 string home = internalGetHome ();
442 // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
444 // note: skip security check for environment variables
445 string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
446 if ((data == null) || (data == String.Empty)) {
447 data = Path.Combine (home, ".local");
448 data = Path.Combine (data, "share");
451 // note: skip security check for environment variables
452 string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
453 if ((config == null) || (config == String.Empty)) {
454 config = Path.Combine (home, ".config");
459 // MyComputer is a virtual directory
460 case SpecialFolder.MyComputer:
464 case SpecialFolder.Personal:
466 // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
467 case SpecialFolder.ApplicationData:
469 //use FDO's DATA_HOME. This is *NOT* synced
470 case SpecialFolder.LocalApplicationData:
473 case SpecialFolder.Desktop:
475 case SpecialFolder.DesktopDirectory:
476 return Path.Combine (home, "Desktop");
478 case SpecialFolder.MyMusic:
479 return Path.Combine (home, "Music");
481 // these simply dont exist on Linux
482 // The spec says if a folder doesnt exist, we
484 case SpecialFolder.Favorites:
485 case SpecialFolder.Programs:
486 case SpecialFolder.SendTo:
487 case SpecialFolder.StartMenu:
488 case SpecialFolder.Startup:
489 case SpecialFolder.MyPictures:
490 case SpecialFolder.Templates:
491 case SpecialFolder.Cookies:
492 case SpecialFolder.History:
493 case SpecialFolder.InternetCache:
494 case SpecialFolder.Recent:
495 case SpecialFolder.CommonProgramFiles:
496 case SpecialFolder.ProgramFiles:
497 case SpecialFolder.System:
499 // This is where data common to all users goes
500 case SpecialFolder.CommonApplicationData:
503 throw new ArgumentException ("Invalid SpecialFolder");
507 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
508 public static string[] GetLogicalDrives ()
510 return GetLogicalDrivesInternal ();
513 // FIXME: Anyone using this anywhere ?
514 static internal string GetResourceString (string s) { return String.Empty; }
518 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
521 case EnvironmentVariableTarget.Process:
522 return GetEnvironmentVariable (variable);
523 case EnvironmentVariableTarget.Machine:
524 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
525 if (!IsRunningOnWindows)
527 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
528 return env.GetValue (variable).ToString ();
530 case EnvironmentVariableTarget.User:
531 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
532 if (!IsRunningOnWindows)
534 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", false)) {
535 return env.GetValue (variable).ToString ();
538 throw new ArgumentException ("target");
542 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
544 IDictionary variables = (IDictionary)new Hashtable ();
546 case EnvironmentVariableTarget.Process:
547 variables = GetEnvironmentVariables ();
549 case EnvironmentVariableTarget.Machine:
550 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
551 if (IsRunningOnWindows) {
552 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment")) {
553 string[] value_names = env.GetValueNames ();
554 foreach (string value_name in value_names)
555 variables.Add (value_name, env.GetValue (value_name));
559 case EnvironmentVariableTarget.User:
560 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
561 if (IsRunningOnWindows) {
562 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment")) {
563 string[] value_names = env.GetValueNames ();
564 foreach (string value_name in value_names)
565 variables.Add (value_name, env.GetValue (value_name));
570 throw new ArgumentException ("target");
575 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
576 public static void SetEnvironmentVariable (string variable, string value)
578 SetEnvironmentVariable (variable, value, EnvironmentVariableTarget.Process);
581 [EnvironmentPermission (SecurityAction.Demand, Unrestricted = true)]
582 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
584 if (variable == null)
585 throw new ArgumentNullException ("variable");
586 if (variable == String.Empty)
587 throw new ArgumentException ("String cannot be of zero length.", "variable");
588 if (variable.IndexOf ('=') != -1)
589 throw new ArgumentException ("Environment variable name cannot contain an equal character.", "variable");
590 if (variable[0] == '\0')
591 throw new ArgumentException ("The first char in the string is the null character.", "variable");
594 case EnvironmentVariableTarget.Process:
595 InternalSetEnvironmentVariable (variable, value);
597 case EnvironmentVariableTarget.Machine:
598 if (!IsRunningOnWindows)
600 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.LocalMachine.OpenSubKey (@"SYSTEM\CurrentControlSet\Control\Session Manager\Environment", true)) {
601 if (value == null || value.Length == 0)
602 env.DeleteValue (variable, false);
604 env.SetValue (variable, value);
607 case EnvironmentVariableTarget.User:
608 if (!IsRunningOnWindows)
610 using (Microsoft.Win32.RegistryKey env = Microsoft.Win32.Registry.CurrentUser.OpenSubKey ("Environment", true)) {
611 if (value == null || value.Length == 0)
612 env.DeleteValue (variable, false);
614 env.SetValue (variable, value);
618 throw new ArgumentException ("target");
622 [MethodImplAttribute (MethodImplOptions.InternalCall)]
623 internal static extern void InternalSetEnvironmentVariable (string variable, string value);
625 public static extern int ProcessorCount {
626 [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
627 [MethodImplAttribute (MethodImplOptions.InternalCall)]
631 [MonoTODO ("Not implemented")]
632 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
633 public static void FailFast (string message)
635 throw new NotImplementedException ();
641 internal static bool IsRunningOnWindows {
642 get { return ((int) Platform != 128); }
645 private static string GacPath {
647 if (Environment.IsRunningOnWindows) {
648 /* On windows, we don't know the path where mscorlib.dll will be installed */
649 string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
650 return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
653 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
657 [MethodImplAttribute (MethodImplOptions.InternalCall)]
658 private extern static string [] GetLogicalDrivesInternal ();
660 [MethodImplAttribute (MethodImplOptions.InternalCall)]
661 private extern static string [] GetEnvironmentVariableNames ();
663 [MethodImplAttribute (MethodImplOptions.InternalCall)]
664 internal extern static string GetMachineConfigPath ();
666 [MethodImplAttribute (MethodImplOptions.InternalCall)]
667 internal extern static string internalGetGacPath ();
669 [MethodImplAttribute (MethodImplOptions.InternalCall)]
670 internal extern static string internalGetHome ();