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 = 35;
65 public enum SpecialFolder
66 { // TODO: Determine if these windoze style folder identifiers
67 // have unix/linux counterparts
83 DesktopDirectory = 0x10,
85 ApplicationData = 0x1a,
86 LocalApplicationData = 0x1c,
90 CommonApplicationData = 0x23,
94 CommonProgramFiles = 0x2b,
98 /// Gets the command line for this process
100 public static string CommandLine {
101 // note: security demand inherited from calling GetCommandLineArgs
103 // FIXME: we may need to quote, but any sane person
104 // should use GetCommandLineArgs () instead.
105 return String.Join (" ", GetCommandLineArgs ());
110 /// Gets or sets the current directory. Actually this is supposed to get
111 /// and/or set the process start directory acording to the documentation
112 /// but actually test revealed at beta2 it is just Getting/Setting the CurrentDirectory
114 public static string CurrentDirectory
117 return Directory.GetCurrentDirectory ();
120 Directory.SetCurrentDirectory (value);
125 /// Gets or sets the exit code of this process
127 public extern static int ExitCode
129 [MethodImplAttribute (MethodImplOptions.InternalCall)]
131 [MethodImplAttribute (MethodImplOptions.InternalCall)]
138 public extern bool HasShutdownStarted
140 [MethodImplAttribute (MethodImplOptions.InternalCall)]
146 /// Gets the name of the local computer
148 public extern static string MachineName {
149 [MethodImplAttribute (MethodImplOptions.InternalCall)]
150 [EnvironmentPermission (SecurityAction.Demand, Read="COMPUTERNAME")]
151 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
156 /// Gets the standard new line value
158 public extern static string NewLine {
159 [MethodImplAttribute (MethodImplOptions.InternalCall)]
164 // Support methods and fields for OSVersion property
166 static OperatingSystem os;
168 internal static extern PlatformID Platform {
169 [MethodImplAttribute (MethodImplOptions.InternalCall)]
173 [MethodImplAttribute (MethodImplOptions.InternalCall)]
174 internal static extern string GetOSVersionString ();
177 /// Gets the current OS version information
179 public static OperatingSystem OSVersion {
182 Version v = Version.CreateFromString (GetOSVersionString ());
183 PlatformID p = Platform;
188 os = new OperatingSystem (p, v);
197 public static string StackTrace {
198 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
200 System.Diagnostics.StackTrace trace = new System.Diagnostics.StackTrace (1);
201 return trace.ToString ();
206 /// Get a fully qualified path to the system directory
208 public static string SystemDirectory {
210 return GetFolderPath (SpecialFolder.System);
215 /// Get the number of milliseconds that have elapsed since the system was booted
217 public extern static int TickCount {
218 [MethodImplAttribute (MethodImplOptions.InternalCall)]
223 /// Get UserDomainName
225 public static string UserDomainName {
226 // FIXME: this variable doesn't exist (at least not on WinXP) - reported to MS as FDBK20562
227 [EnvironmentPermission (SecurityAction.Demand, Read="USERDOMAINNAME")]
234 /// Gets a flag indicating whether the process is in interactive mode
237 public static bool UserInteractive {
244 /// Get the user name of current process is running under
246 public extern static string UserName {
247 [MethodImplAttribute (MethodImplOptions.InternalCall)]
248 [EnvironmentPermission (SecurityAction.Demand, Read="USERNAME;USER")]
253 /// Get the version of the common language runtime
255 public static Version Version {
258 // FIXME: this is the version number for MS.NET 2.0 beta1.
259 // It must be changed when the final version is released.
260 return new Version (2, 0, 50215, 16);
262 return new Version (1, 1, 4322, 573);
264 return new Version (1, 0, 3705, 288);
270 /// Get the amount of physical memory mapped to process
273 public static long WorkingSet {
274 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
278 [MethodImplAttribute (MethodImplOptions.InternalCall)]
279 [SecurityPermission (SecurityAction.Demand, UnmanagedCode=true)]
280 public extern static void Exit (int exitCode);
283 /// Substitute environment variables in the argument "name"
285 public static string ExpandEnvironmentVariables (string name)
288 throw new ArgumentNullException ("name");
290 int off1 = name.IndexOf ('%');
294 int len = name.Length;
296 if (off1 == len - 1 || (off2 = name.IndexOf ('%', off1 + 1)) == -1)
299 StringBuilder result = new StringBuilder ();
300 result.Append (name, 0, off1);
301 Hashtable tbl = null;
303 string var = name.Substring (off1 + 1, off2 - off1 - 1);
304 string value = GetEnvironmentVariable (var);
305 if (value == null && Environment.IsRunningOnWindows) {
306 // On windows, env. vars. are case insensitive
308 tbl = GetEnvironmentVariablesNoCase ();
310 value = tbl [var] as string;
313 // If value not found, add %FOO to stream,
314 // and use the closing % for the next iteration.
315 // If value found, expand it in place of %FOO%
321 result.Append (value);
324 off1 = name.IndexOf ('%', off2 + 1);
325 // If no % found for off1, don't look for one for off2
326 off2 = (off1 == -1 || off2 > len-1)? -1 :name.IndexOf ('%', off1 + 1);
327 // textLen is the length of text between the closing % of current iteration
328 // and the starting % of the next iteration if any. This text is added to output
330 // If no new % found, use all the remaining text
331 if (off1 == -1 || off2 == -1)
332 textLen = len - oldOff2 - 1;
333 // If value found in current iteration, use text after current closing % and next %
334 else if(value != null)
335 textLen = off1 - oldOff2 - 1;
336 // If value not found in current iteration, but a % was found for next iteration,
337 // use text from current closing % to the next %.
339 textLen = off1 - oldOff2;
340 if(off1 >= oldOff2 || off1 == -1)
341 result.Append (name.Substring (oldOff2+1, textLen));
342 } while (off2 > -1 && off2 < len);
344 return result.ToString ();
349 /// Return an array of the command line arguments of the current process
351 [MethodImplAttribute (MethodImplOptions.InternalCall)]
352 [EnvironmentPermissionAttribute (SecurityAction.Demand, Read = "PATH")]
353 public extern static string[] GetCommandLineArgs ();
355 [MethodImplAttribute (MethodImplOptions.InternalCall)]
356 internal extern static string internalGetEnvironmentVariable (string name);
359 /// Return a string containing the value of the environment
360 /// variable identifed by parameter "variable"
362 public static string GetEnvironmentVariable (string name)
364 if (SecurityManager.SecurityEnabled) {
365 new EnvironmentPermission (EnvironmentPermissionAccess.Read, name).Demand ();
367 return internalGetEnvironmentVariable (name);
370 static Hashtable GetEnvironmentVariablesNoCase ()
372 Hashtable vars = new Hashtable (CaseInsensitiveHashCodeProvider.Default,
373 CaseInsensitiveComparer.Default);
375 foreach (string name in GetEnvironmentVariableNames ()) {
376 vars [name] = internalGetEnvironmentVariable (name);
383 /// Return a set of all environment variables and their values
386 public static IDictionary GetEnvironmentVariables ()
388 StringBuilder sb = null;
389 if (SecurityManager.SecurityEnabled) {
390 // we must have access to each variable to get the lot
391 sb = new StringBuilder ();
392 // but (performance-wise) we do not want a stack-walk
393 // for each of them so we concatenate them
396 Hashtable vars = new Hashtable ();
397 foreach (string name in GetEnvironmentVariableNames ()) {
398 vars [name] = internalGetEnvironmentVariable (name);
406 new EnvironmentPermission (EnvironmentPermissionAccess.Read, sb.ToString ()).Demand ();
411 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
412 public static IDictionary GetEnvironmentVariables ()
414 Hashtable vars = new Hashtable ();
415 foreach (string name in GetEnvironmentVariableNames ()) {
416 vars [name] = internalGetEnvironmentVariable (name);
422 [MethodImplAttribute (MethodImplOptions.InternalCall)]
423 private extern static string GetWindowsFolderPath (int folder);
426 /// Returns the fully qualified path of the
427 /// folder specified by the "folder" parameter
429 public static string GetFolderPath (SpecialFolder folder)
433 if (Environment.IsRunningOnWindows) {
434 dir = GetWindowsFolderPath ((int) folder);
436 dir = InternalGetFolderPath (folder);
439 if ((dir != null) && (dir.Length > 0) && SecurityManager.SecurityEnabled) {
440 new FileIOPermission (FileIOPermissionAccess.PathDiscovery, dir).Demand ();
445 // the security runtime (and maybe other parts of corlib) needs the
446 // information to initialize themselves before permissions can be checked
447 internal static string InternalGetFolderPath (SpecialFolder folder)
449 string home = internalGetHome ();
451 // http://freedesktop.org/Standards/basedir-spec/basedir-spec-0.6.html
453 // note: skip security check for environment variables
454 string data = internalGetEnvironmentVariable ("XDG_DATA_HOME");
455 if ((data == null) || (data == String.Empty)) {
456 data = Path.Combine (home, ".local");
457 data = Path.Combine (data, "share");
460 // note: skip security check for environment variables
461 string config = internalGetEnvironmentVariable ("XDG_CONFIG_HOME");
462 if ((config == null) || (config == String.Empty)) {
463 config = Path.Combine (home, ".config");
468 // MyComputer is a virtual directory
469 case SpecialFolder.MyComputer:
473 case SpecialFolder.Personal:
475 // use FDO's CONFIG_HOME. This data will be synced across a network like the windows counterpart.
476 case SpecialFolder.ApplicationData:
478 //use FDO's DATA_HOME. This is *NOT* synced
479 case SpecialFolder.LocalApplicationData:
482 case SpecialFolder.Desktop:
484 case SpecialFolder.DesktopDirectory:
485 return Path.Combine (home, "Desktop");
487 // these simply dont exist on Linux
488 // The spec says if a folder doesnt exist, we
490 case SpecialFolder.Favorites:
491 case SpecialFolder.Programs:
492 case SpecialFolder.SendTo:
493 case SpecialFolder.StartMenu:
494 case SpecialFolder.Startup:
495 case SpecialFolder.MyMusic:
496 case SpecialFolder.MyPictures:
497 case SpecialFolder.Templates:
498 case SpecialFolder.Cookies:
499 case SpecialFolder.History:
500 case SpecialFolder.InternetCache:
501 case SpecialFolder.Recent:
502 case SpecialFolder.CommonProgramFiles:
503 case SpecialFolder.ProgramFiles:
504 case SpecialFolder.System:
506 // This is where data common to all users goes
507 case SpecialFolder.CommonApplicationData:
510 throw new ArgumentException ("Invalid SpecialFolder");
514 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
515 public static string[] GetLogicalDrives ()
517 return GetLogicalDrivesInternal ();
520 // FIXME: Anyone using this anywhere ?
521 static internal string GetResourceString (string s) { return ""; }
525 [MonoTODO ("Machine and User targets aren't supported")]
526 public static string GetEnvironmentVariable (string variable, EnvironmentVariableTarget target)
529 case EnvironmentVariableTarget.Process:
530 return GetEnvironmentVariable (variable);
531 case EnvironmentVariableTarget.Machine:
532 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
533 // under Windows this reads the LOCAL_MACHINE registry key for env vars
534 throw new NotImplementedException ();
535 case EnvironmentVariableTarget.User:
536 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
537 // under Windows this reads the CURRENT_USER registry key for env vars
538 throw new NotImplementedException ();
540 throw new ArgumentException ("target");
544 [MonoTODO ("Machine and User targets aren't supported")]
545 public static IDictionary GetEnvironmentVariables (EnvironmentVariableTarget target)
548 case EnvironmentVariableTarget.Process:
549 return GetEnvironmentVariables ();
550 case EnvironmentVariableTarget.Machine:
551 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
552 // under Windows this reads the LOCAL_MACHINE registry key for env vars
553 throw new NotImplementedException ();
554 case EnvironmentVariableTarget.User:
555 new EnvironmentPermission (PermissionState.Unrestricted).Demand ();
556 // under Windows this reads the CURRENT_USER registry key for env vars
557 throw new NotImplementedException ();
559 throw new ArgumentException ("target");
564 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
565 public static void SetEnvironmentVariable (string variable, string value)
567 InternalSetEnvironmentVariable (variable, value);
571 [EnvironmentPermission (SecurityAction.Demand, Unrestricted=true)]
572 public static void SetEnvironmentVariable (string variable, string value, EnvironmentVariableTarget target)
575 case EnvironmentVariableTarget.Process:
576 InternalSetEnvironmentVariable (variable, value);
578 case EnvironmentVariableTarget.Machine:
579 // under Windows this reads the LOCAL_MACHINE registry key for env vars
580 throw new NotImplementedException ();
581 case EnvironmentVariableTarget.User:
582 // under Windows this reads the CURRENT_USER registry key for env vars
583 throw new NotImplementedException ();
585 throw new ArgumentException ("target");
589 // FIXME: to be changed as an icall when implemented
590 internal static void InternalSetEnvironmentVariable (string variable, string value)
592 throw new NotImplementedException ();
596 public static int ProcessorCount {
597 [EnvironmentPermission (SecurityAction.Demand, Read="NUMBER_OF_PROCESSORS")]
599 // note: Changes to the NUMBER_OF_PROCESSORS environment variable
600 // under Windows doesn't affect the (good) value returned.
601 throw new NotImplementedException ();
605 [MonoTODO ("not much documented")]
606 [SecurityPermission (SecurityAction.LinkDemand, UnmanagedCode=true)]
607 public static void FailFast (string message)
609 throw new NotImplementedException ();
615 internal static bool IsRunningOnWindows {
616 get { return ((int) Platform != 128); }
619 private static string GacPath {
621 if (Environment.IsRunningOnWindows) {
622 /* On windows, we don't know the path where mscorlib.dll will be installed */
623 string corlibDir = new DirectoryInfo (Path.GetDirectoryName (typeof (int).Assembly.Location)).Parent.Parent.FullName;
624 return Path.Combine (Path.Combine (corlibDir, "mono"), "gac");
627 return Path.Combine (Path.Combine (internalGetGacPath (), "mono"), "gac");
631 [MethodImplAttribute (MethodImplOptions.InternalCall)]
632 private extern static string [] GetLogicalDrivesInternal ();
634 [MethodImplAttribute (MethodImplOptions.InternalCall)]
635 private extern static string [] GetEnvironmentVariableNames ();
637 [MethodImplAttribute (MethodImplOptions.InternalCall)]
638 internal extern static string GetMachineConfigPath ();
640 [MethodImplAttribute (MethodImplOptions.InternalCall)]
641 internal extern static string internalGetGacPath ();
643 [MethodImplAttribute (MethodImplOptions.InternalCall)]
644 internal extern static string internalGetHome ();