environ.ha (3646B)
1 // License: MPL-2.0 2 // (c) 2021 Drew DeVault <sir@cmpwn.com> 3 // (c) 2021 Ember Sawady <ecs@d2evs.net> 4 use bytes; 5 use errors; 6 use rt; 7 use strings; 8 use types::c; 9 10 // The command line arguments provided to the program. By convention, the first 11 // member is usually the name of the program. 12 export let args: []str = []; 13 14 // Statically allocate arg strings if there are few enough arguments, saves a 15 // syscall if we don't need it. 16 let args_static: [32]str = [""...]; 17 18 @init fn init_environ() void = { 19 if (rt::argc < len(args_static)) { 20 args = args_static[..rt::argc]; 21 for (let i = 0z; i < rt::argc; i += 1) { 22 args[i] = c::tostr(rt::argv[i]: *const c::char)!; 23 }; 24 } else { 25 args = alloc([], rt::argc); 26 for (let i = 0z; i < rt::argc; i += 1) { 27 append(args, c::tostr(rt::argv[i]: *const c::char)!); 28 }; 29 }; 30 31 }; 32 33 @fini fn fini_environ() void = { 34 if (rt::argc >= len(args_static)) { 35 free(args); 36 }; 37 free(envp); 38 }; 39 40 // Looks up an environment variable and returns its value, or void if unset. 41 export fn getenv(name: const str) (str | void) = { 42 const name_b = strings::toutf8(name); 43 for (let i = 0z; rt::envp[i] != null; i += 1) { 44 const item = rt::envp[i]: *[*]u8; 45 const ln = c::strlen(item: *c::char); 46 const eq: size = match (bytes::index(item[..ln], '=')) { 47 case void => 48 abort("Environment violates System-V invariants"); 49 case let i: size => 50 yield i; 51 }; 52 if (bytes::equal(name_b, item[..eq])) { 53 const ln = c::strlen(item: *const c::char); 54 return strings::fromutf8(item[eq+1..ln])!; 55 }; 56 }; 57 }; 58 59 // Looks up an environment variable and returns its value, or a default value if 60 // unset. 61 export fn tryenv(name: const str, default: str) str = match (getenv(name)) { 62 case let s: str => 63 yield s; 64 case void => 65 yield default; 66 }; 67 68 let envp: []str = []; 69 70 // Returns a slice of the environment strings in the form KEY=VALUE. 71 export fn getenvs() []str = { 72 if (len(envp) != 0) { 73 return envp; 74 }; 75 for (let i = 0z; rt::envp[i] != null; i += 1) { 76 append(envp, c::tostr(rt::envp[i]: *const c::char)!); 77 }; 78 return envp; 79 }; 80 81 // Returns the host kernel name 82 export fn sysname() const str = { 83 static let buf: [512]u8 = [0...]; 84 let sz: size = len(buf); 85 rt::sysctlbyname("kern.ostype", &buf, &sz, null, 0)!; 86 return strings::fromutf8(buf[..(sz - 1)])!; 87 }; 88 89 // Returns the host system hostname 90 export fn hostname() const str = { 91 static let buf: [512]u8 = [0...]; 92 let sz: size = len(buf); 93 rt::sysctlbyname("kern.hostname", &buf, &sz, null, 0)!; 94 return strings::fromutf8(buf[..(sz - 1)])!; 95 }; 96 97 // Returns the host kernel version 98 export fn release() const str = { 99 static let buf: [512]u8 = [0...]; 100 let sz: size = len(buf); 101 rt::sysctlbyname("kern.osrelease", &buf, &sz, null, 0)!; 102 return strings::fromutf8(buf[..(sz - 1)])!; 103 }; 104 105 // Returns the host operating system version 106 export fn version() const str = { 107 static let buf: [512]u8 = [0...]; 108 let sz: size = len(buf); 109 rt::sysctlbyname("kern.version", &buf, &sz, null, 0)!; 110 return strings::fromutf8(buf[..(sz - 1)])!; 111 }; 112 113 // Returns the host CPU architecture 114 export fn machine() const str = { 115 static let buf: [512]u8 = [0...]; 116 let sz: size = len(buf); 117 rt::sysctlbyname("hw.machine", &buf, &sz, null, 0)!; 118 const mach = strings::fromutf8(buf[..(sz - 1)])!; 119 // Translate to Hare names 120 switch (mach) { 121 case "amd64" => 122 return "x86_64"; 123 case => 124 return mach; 125 }; 126 }; 127 128 // Returns the number of usable CPUs. 129 export fn cpucount() (int | errors::error) = { 130 let count = 0; 131 let length = size(int); 132 match (rt::sysctlbyname("hw.ncpu", &count, &length, null, 0)) { 133 case void => void; 134 case let err: rt::errno => 135 return errors::errno(err); 136 }; 137 return count; 138 };