ADDED: library(os), reasoning about environment variables.

Together with library(files), this addresses #511.
This commit is contained in:
Markus Triska
2020-07-11 18:41:18 +02:00
parent 5fd78320dd
commit eb872f8fca
5 changed files with 99 additions and 0 deletions

View File

@@ -442,6 +442,8 @@ The modules that ship with Scryer Prolog are also called
Predicates for opening and accepting TCP connections as streams. Predicates for opening and accepting TCP connections as streams.
TLS negotiation is performed via the option `tls(true)` in TLS negotiation is performed via the option `tls(true)` in
`socket_client_open/3`, yielding secure encrypted connections. `socket_client_open/3`, yielding secure encrypted connections.
* [`os`](src/lib/os.pl)
Predicates for reasoning about environment variables.
* [`crypto`](src/lib/crypto.pl) * [`crypto`](src/lib/crypto.pl)
Cryptographically secure random numbers and hashes, HMAC-based Cryptographically secure random numbers and hashes, HMAC-based
key derivation (HKDF), password-based key derivation (PBKDF2), key derivation (HKDF), password-based key derivation (PBKDF2),

View File

@@ -306,6 +306,9 @@ pub enum SystemClauseType {
Ed25519KeyPairPublicKey, Ed25519KeyPairPublicKey,
LoadHTML, LoadHTML,
LoadXML, LoadXML,
GetEnv,
SetEnv,
UnsetEnv,
} }
impl SystemClauseType { impl SystemClauseType {
@@ -510,6 +513,9 @@ impl SystemClauseType {
&SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"), &SystemClauseType::Ed25519KeyPairPublicKey => clause_name!("$ed25519_keypair_public_key"),
&SystemClauseType::LoadHTML => clause_name!("$load_html"), &SystemClauseType::LoadHTML => clause_name!("$load_html"),
&SystemClauseType::LoadXML => clause_name!("$load_xml"), &SystemClauseType::LoadXML => clause_name!("$load_xml"),
&SystemClauseType::GetEnv => clause_name!("$getenv"),
&SystemClauseType::SetEnv => clause_name!("$setenv"),
&SystemClauseType::UnsetEnv => clause_name!("$unsetenv"),
} }
} }
@@ -694,6 +700,9 @@ impl SystemClauseType {
("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey), ("$ed25519_keypair_public_key", 2) => Some(SystemClauseType::Ed25519KeyPairPublicKey),
("$load_html", 3) => Some(SystemClauseType::LoadHTML), ("$load_html", 3) => Some(SystemClauseType::LoadHTML),
("$load_xml", 3) => Some(SystemClauseType::LoadXML), ("$load_xml", 3) => Some(SystemClauseType::LoadXML),
("$getenv", 2) => Some(SystemClauseType::GetEnv),
("$setenv", 2) => Some(SystemClauseType::SetEnv),
("$unsetenv", 1) => Some(SystemClauseType::UnsetEnv),
_ => None, _ => None,
} }
} }

View File

@@ -44,6 +44,7 @@ must_be_(var, Term) :-
). ).
must_be_(integer, Term) :- check_(integer, integer, Term). must_be_(integer, Term) :- check_(integer, integer, Term).
must_be_(atom, Term) :- check_(atom, atom, Term). must_be_(atom, Term) :- check_(atom, atom, Term).
must_be_(character, T) :- check_(character, character, T).
must_be_(list, Term) :- check_(ilist, list, Term). must_be_(list, Term) :- check_(ilist, list, Term).
must_be_(type, Term) :- check_(type, type, Term). must_be_(type, Term) :- check_(type, type, Term).
must_be_(boolean, Term) :- check_(boolean, boolean, Term). must_be_(boolean, Term) :- check_(boolean, boolean, Term).
@@ -56,6 +57,10 @@ check_(Pred, Type, Term) :-
boolean(B) :- ( B == true ; B == false ). boolean(B) :- ( B == true ; B == false ).
character(C) :-
atom(C),
atom_length(C, 1).
ilist(V) :- var(V), instantiation_error(must_be/2). ilist(V) :- var(V), instantiation_error(must_be/2).
ilist([]). ilist([]).
ilist([_|Ls]) :- ilist(Ls). ilist([_|Ls]) :- ilist(Ls).
@@ -63,6 +68,7 @@ ilist([_|Ls]) :- ilist(Ls).
type(type). type(type).
type(integer). type(integer).
type(atom). type(atom).
type(character).
type(list). type(list).
type(var). type(var).
type(boolean). type(boolean).
@@ -90,6 +96,7 @@ can_be(Type, Term) :-
can_(integer, Term) :- integer(Term). can_(integer, Term) :- integer(Term).
can_(atom, Term) :- atom(Term). can_(atom, Term) :- atom(Term).
can_(character, T) :- character(T).
can_(list, Term) :- list_or_partial_list(Term). can_(list, Term) :- list_or_partial_list(Term).
can_(boolean, Term) :- boolean(Term). can_(boolean, Term) :- boolean(Term).

58
src/lib/os.pl Normal file
View File

@@ -0,0 +1,58 @@
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Predicates for reasoning about the operating system (OS) environment.
Written July 2020 by Markus Triska (triska@metalevel.at).
Lists of characters are used throughout to represent keys and values.
Example:
?- getenv("LANG", Ls).
Ls = "en_US.UTF-8"
; false.
Public domain code.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
:- module(os, [getenv/2,
setenv/2,
unsetenv/1]).
:- use_module(library(error)).
:- use_module(library(charsio)).
:- use_module(library(lists)).
getenv(Key, Value) :-
must_be_env_var(Key),
'$getenv'(Key, Value).
setenv(Key, Value) :-
must_be_env_var(Key),
must_be_chars(Value),
'$setenv'(Key, Value).
unsetenv(Key) :-
must_be_env_var(Key),
'$unsetenv'(Key).
/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
For now, we only support a restricted subset of variable names.
The reason is that Rust may panic if a key is empty, contains an
ASCII equals sign '=' or the NUL character '\0', or when the value
contains the NUL character.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
must_be_env_var(Cs) :-
must_be_chars(Cs),
Cs = [_|_],
( maplist(permitted, Cs) -> true
; domain_error(env_var, Cs, os)
).
permitted(C) :- char_type(C, alnum).
permitted(C) :- char_type(C, ascii_punctuation).
permitted('_').
must_be_chars(Cs) :-
must_be(list, Cs),
maplist(must_be(character), Cs).

View File

@@ -32,6 +32,7 @@ use std::net::{TcpListener, TcpStream};
use std::ops::Sub; use std::ops::Sub;
use std::rc::Rc; use std::rc::Rc;
use std::num::NonZeroU32; use std::num::NonZeroU32;
use std::env;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use crate::cpu_time::ProcessTime; use crate::cpu_time::ProcessTime;
@@ -5637,6 +5638,28 @@ impl MachineState {
} }
} }
} }
&SystemClauseType::GetEnv => {
let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
match env::var(key) {
Ok(value) => {
let cstr = self.heap.put_complete_string(&value);
self.unify(self[temp_v!(2)], cstr);
}
_ => {
self.fail = true;
return Ok(());
}
}
}
&SystemClauseType::SetEnv => {
let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
let value = self.heap_pstr_iter(self[temp_v!(2)]).to_string();
env::set_var(key, value);
}
&SystemClauseType::UnsetEnv => {
let key = self.heap_pstr_iter(self[temp_v!(1)]).to_string();
env::remove_var(key);
}
}; };
return_from_clause!(self.last_call, self) return_from_clause!(self.last_call, self)