inventory.dhover×67all
#!/usr/bin/env dub
/+ dub.sdl:
    name "android-research-device-inventory"
    targetPath "build"
+/
/**
 * Read-only Android inventory. No implicit device selection or permission grants.
 * Evidence and interpretation: ../index.md#reproduce-the-inventory.
 * CI invokes with no arguments and gets SKIP; use --serial SERIAL --adb PATH.
 */
import 
(package) std
std
.
(module) std.process

Functions for starting and interacting with other processes, and for working with the current process' execution environment.

Process handling

  • `spawnProcess` spawns a new `process`, optionally assigning it an
        

    arbitrary set of standard input, output, and error streams. The function returns immediately, leaving the child process to execute in parallel with its parent. All other functions in this module that spawn processes are built around spawnProcess.

  • `wait` makes the parent `process` wait for a child `process` to
        

    terminate. In general one should always do this, to avoid child processes becoming "zombies" when the parent process exits. Scope guards are perfect for this – see the spawnProcess documentation for examples. tryWait is similar to wait, but does not block if the process has not yet terminated.

  • `pipeProcess` also spawns a child `process` which runs
        

    in parallel with its parent. However, instead of taking arbitrary streams, it automatically creates a set of pipes that allow the parent to communicate with the child through the child's standard input, output, and/or error streams. This function corresponds roughly to C's popen function.

  • `execute` starts a new `process` and waits for it
        

    to complete before returning. Additionally, it captures the process' standard output and error streams and returns the output of these as a string.

  • `spawnShell`, `pipeShell` and `executeShell` work like
        

    spawnProcess, pipeProcess and execute, respectively, except that they take a single command string and run it through the current user's default command interpreter. executeShell corresponds roughly to C's system function.

  • `kill` attempts to terminate a running `process`.
    
    

The following table compactly summarises the different process creation functions and how they relate to each other:

Runs program directly
Runs shell command
Low-level process creation
spawnProcess
spawnShell
Automatic input/output redirection using pipes
pipeProcess
pipeShell
Execute and wait for completion, collect output
execute
executeShell

Other functionality

  • `pipe` is used to create unidirectional pipes.
    
  • `environment` is an interface through which the current `process`'
        

    environment variables can be read and manipulated.

  • `escapeShellCommand` and `escapeShellFileName` are useful
        

    for constructing shell command lines in a portable way.

Source

std/process.d

Note

Most of the functionality in this module is not available on iOS, tvOS and watchOS. The only functions available on those platforms are: environment, thisProcessID and thisThreadID.

@authorsLars Tandle Kyllingstad, Steven Schveighoffer, Vladimir Panteleev@copyrightCopyright (c) 2013, the authors. All rights reserved.@licenseBoost License 1.0.
process
:
(alias) inventory.execute = std.typecons.Tuple!(int, "status", string, "output") std.process.execute(scope const(char[])[] args, const(string[string]) env = cast(const(string[string]))null, std.process.Config config = Config(Flags.none, null, null), ulong maxOutput = 18446744073709551615LU, scope const(char)[] workDir = null) @safe

Executes the given program or shell command and returns its exit code and output.

execute and executeShell start a new process using spawnProcess and spawnShell, respectively, and wait for the process to complete before returning. The functions capture what the child process prints to both its standard output and standard error streams, and return this together with its exit code.

auto dmd = execute(["dmd", "myapp.d"]);
if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);

auto ls = executeShell("ls -l");
if (ls.status != 0) writeln("Failed to retrieve file listing");
else writeln(ls.output);

The args/program/command, env and config parameters are forwarded straight to the underlying spawn functions, and we refer to their documentation for details.

POSIX specific

If the process is terminated by a signal, the status field of the return value will contain a negative number whose absolute value is the signal number. (See wait for details.)

@paramargs An array which contains the program name as the zeroth element and any command-line arguments in the following elements. (See spawnProcess for details.)@paramprogram The program name, without command-line arguments. (See spawnProcess for details.)@paramcommand A shell command which is passed verbatim to the command interpreter. (See spawnShell for details.)@paramenv Additional environment variables for the child process. (See spawnProcess for details.)@paramconfig Flags that control process creation. See Config for an overview of available flags, and note that the retainStd... flags have no effect in this function.@parammaxOutput The maximum number of bytes of output that should be captured.@paramworkDir The working directory for the new process. By default the child process inherits the parent's working directory.@paramshellPath The path to the shell to use to run the specified program. By default this is nativeShell.@returnsAn std.typecons.Tuple!(int, "status", string, "output").@throws

ProcessException on failure to start the process.

StdioException on failure to capture output.

execute
;
import
(package) std
std
.
(module) std.stdio
Category Symbols
File handles _popen File isFileHandle openNetwork stderr stdin stdout
Reading chunks lines readf readfln readln
Writing toFile write writef writefln writeln
Misc KeepTerminator LockType StdioException

Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio is publically imported when importing std.stdio.

There are three layers of I/O:

  1. The lowest layer is the operating system layer. The two main schemes are Windows and Posix.

  2. C's stdio.h which unifies the two operating system schemes.

  3. std.stdio, this module, unifies the various stdio.h implementations into a high level package for D programs.

Source

std/stdio.d

@copyrightCopyright The D Language Foundation 2007-.@licenseBoost License 1.0.@authorsWalter Bright, Andrei Alexandrescu, Alex Rønne Petersen
stdio
:
(alias template) inventory.writeln = std.stdio.writeln(T...)(T args)

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
, stderr;
import
(package) std
std
.
(module) std.exception

This module defines functions related to exceptions and general error handling. It also defines functions intended to aid in unit testing.

Category Functions
Assumptions assertNotThrown assertThrown assumeUnique assumeWontThrow mayPointTo
Enforce doesPointTo enforce errnoEnforce
Handlers collectException collectExceptionMsg ifThrown handle
Other basicExceptionCtors emptyExceptionMsg ErrnoException RangePrimitive

Source

std/exception.d

Examples

Synopis

import core.stdc.stdlib : malloc, free;
import std.algorithm.comparison : equal;
import std.algorithm.iteration : map, splitter;
import std.algorithm.searching : endsWith;
import std.conv : ConvException, to;
import std.range : front, retro;

// use enforce like assert
int a = 3;
enforce(a > 2, "a needs to be higher than 2.");

// enforce can throw a custom exception
enforce!ConvException(a > 2, "a needs to be higher than 2.");

// enforce will return it's input
enum size = 42;
auto memory = enforce(malloc(size), "malloc failed")[0 .. size];
scope(exit) free(memory.ptr);

// collectException can be used to test for exceptions
Exception e = collectException("abc".to!int);
assert(e.file.endsWith("conv.d"));

// and just for the exception message
string msg = collectExceptionMsg("abc".to!int);
assert(msg == "Unexpected 'a' when converting from type string to type int");

// assertThrown can be used to assert that an exception is thrown
assertThrown!ConvException("abc".to!int);

// ifThrown can be used to provide a default value if an exception is thrown
assert("x".to!int().ifThrown(0) == 0);

// handle is a more advanced version of ifThrown for ranges
auto r = "12,1337z32,54".splitter(',').map!(a => to!int(a));
auto h = r.handle!(ConvException, RangePrimitive.front, (e, r) => 0);
assert(h.equal([12, 0, 54]));
assertThrown!ConvException(h.retro.equal([54, 0, 12]));

// basicExceptionCtors avoids the boilerplate when creating custom exceptions
static class MeaCulpa : Exception
{
    mixin basicExceptionCtors;
}
e = collectException((){throw new MeaCulpa("diagnostic message");}());
assert(e.msg == "diagnostic message");
assert(e.file == __FILE__);
assert(e.line == __LINE__ - 3);

// assumeWontThrow can be used to cast throwing code into `nothrow`
void exceptionFreeCode() nothrow
{
    // auto-decoding only throws if an invalid UTF char is given
    assumeWontThrow("abc".front);
}

// assumeUnique can be used to cast mutable instance to an `immutable` one
// use with care
char[] str = "  mutable".dup;
str[0 .. 2] = "im";
immutable res = assumeUnique(str);
assert(res == "immutable");
@copyrightCopyright Andrei Alexandrescu 2008-, Jonathan M Davis 2011-.@licenseBoost License 1.0@authorsAndrei Alexandrescu and Jonathan M Davis
exception
:
(alias template) inventory.enforce = std.exception.enforce(E : Throwable = Exception) if (is(typeof(new E("", string.init, size_t.init)) : Throwable) || is(typeof(new E(string.init, size_t.init)) : Throwable))

Enforces that the given value is true. If the given value is false, an exception is thrown. The

  • msg - error message as a string

  • dg - custom delegate that return a string and is only called if an exception occurred

  • ex - custom exception to be thrown. It is lazy and is only created if an exception occurred

@paramvalue The value to test.@paramE Exception type to throw if the value evaluates to false.@parammsg The error message to put in the exception if it is thrown.@paramdg The delegate to be called if the value evaluates to false.@paramex The exception to throw if the value evaluates to false.@paramfile The source file of the caller.@paramline The line number of the caller.@returns

value, if cast(bool) value is true. Otherwise, depending on the chosen overload, new Exception(msg), dg() or ex is thrown.

enforce is used to throw exceptions and is therefore intended to aid in error handling. It is not intended for verifying the logic of your program - that is what assert is for.

Do not use enforce inside of contracts (i.e. inside of in and out blocks and invariants), because contracts are compiled out when compiling with -release.

If a delegate is passed, the safety and purity of this function are inferred from Dg's safety and purity.

enforce
;
int
int D main(string[] args)
main
(
(alias) object.string = string
string
[]
(parameter) string[] args
args
)
{
(alias) object.string = string
string
(local variable) string serial
serial
;
(alias) object.string = string
string
(local variable) string adb
adb
= "adb";
foreach (
(local variable) ulong i
i
; 1 ..
(parameter) string[] args
args
.
(field) ulong string[].length
length
)
{ if (
(local variable) ulong i
i
> 1 && (
(parameter) string[] args
args
[
(local variable) ulong i
i
- 1] == "--serial" ||
(parameter) string[] args
args
[
(local variable) ulong i
i
- 1] == "--adb"))
continue;
bool std.exception.enforce!().enforce!bool(bool value, lazy const(char)[] msg = null, string file = __FILE__, ulong line = cast(ulong)__LINE__) pure @safe

Enforces that the given value is true. If the given value is false, an exception is thrown. The

  • msg - error message as a string

  • dg - custom delegate that return a string and is only called if an exception occurred

  • ex - custom exception to be thrown. It is lazy and is only created if an exception occurred

@paramvalue The value to test.@paramE Exception type to throw if the value evaluates to false.@parammsg The error message to put in the exception if it is thrown.@paramdg The delegate to be called if the value evaluates to false.@paramex The exception to throw if the value evaluates to false.@paramfile The source file of the caller.@paramline The line number of the caller.@returns

value, if cast(bool) value`` is true. Otherwise, depending on the chosen overload, new Exception(msg), dg() or ex is thrown.

enforce is used to throw exceptions and is therefore intended to aid in error handling. It is not intended for verifying the logic of your program - that is what assert is for.

Do not use enforce inside of contracts (i.e. inside of in and out blocks and invariants), because contracts are compiled out when compiling with -release.

If a delegate is passed, the safety and purity of this function are inferred from Dg's safety and purity.

enforce
(
(local variable) ulong i
i
+ 1 <
(parameter) string[] args
args
.
(field) ulong string[].length
length
, "expected --serial SERIAL or --adb PATH");
if (
(parameter) string[] args
args
[
(local variable) ulong i
i
] == "--serial")
(local variable) string serial
serial
=
(parameter) string[] args
args
[
(local variable) ulong i
i
+ 1];
else if (
(parameter) string[] args
args
[
(local variable) ulong i
i
] == "--adb")
(local variable) string adb
adb
=
(parameter) string[] args
args
[
(local variable) ulong i
i
+ 1];
else throw new
(class) object.Exception

The base class of all errors that are safe to catch and handle.

In principle, only thrown objects derived from this class are safe to catch inside a catch block. Thrown objects not derived from Exception represent runtime errors that should not be caught, as certain runtime guarantees may not hold, making it unsafe to continue program execution.

Examples

bool gotCaught;
try
{
    throw new Exception("msg");
}
catch (Exception e)
{
    gotCaught = true;
    assert(e.msg == "msg");
}
assert(gotCaught);
Exception
("unknown argument: " ~
(parameter) string[] args
args
[
(local variable) ulong i
i
]);
} if (!
(local variable) string serial
serial
.
(field) ulong string.length
length
)
{
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("SKIP: explicit --serial required; no Android device contacted");
return 0; } const
(local variable) const(string[][]) commands
commands
= [
["identity", "getprop ro.product.model; getprop ro.product.device; getprop ro.soc.model; " ~ "getprop ro.product.cpu.abilist; getprop ro.build.version.release; getprop ro.build.version.sdk; " ~ "getprop ro.build.fingerprint; getprop ro.build.type; uname -r"], ["security", "id; getenforce; getprop ro.boot.verifiedbootstate; getprop ro.boot.flash.locked; " ~ "cat /proc/self/attr/current; grep -E 'Seccomp:|NoNewPrivs:|CapEff:' /proc/self/status"], ["virtualization", "pm list features | grep virtualization; " ~ "for p in /dev/kvm /dev/gunyah /dev/gzvm /apex/com.android.virt/bin/vm " ~ "/proc/sys/kernel/seccomp_bypass_paths /proc/sys/user/max_user_namespaces; " ~ "do if test -e $p; then ls -l $p; else echo absent:$p; fi; done"], ["resources", "grep -E 'MemTotal:|MemAvailable:' /proc/meminfo; " ~ "dumpsys battery | grep -E 'level:|temperature:|status:'; df -h /data"], ["applications", "pm list packages | grep -E 'sparkles|termux|virtualization|shizuku'; " ~ "ps -A | grep -E 'sparkles|proot|nix|sshd'"], ]; int
(local variable) int failed
failed
;
foreach (
(parameter) const(string[]) command
command
;
(local variable) const(string[][]) commands
commands
)
{
void std.stdio.writeln!(string, string, string)(string __param_0, string __param_1, string __param_2) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("[",
(local variable) const(string[]) command
command
[0], "]");
try { const
(local variable) const(std.typecons.Tuple!(int, "status", string, "output")) result
result
=
std.typecons.Tuple!(int, "status", string, "output") std.process.execute(scope const(char[])[] args, const(string[string]) env = cast(const(string[string]))null, std.process.Config config = Config(Flags.none, null, null), ulong maxOutput = 18446744073709551615LU, scope const(char)[] workDir = null) @safe

Executes the given program or shell command and returns its exit code and output.

execute and executeShell start a new process using spawnProcess and spawnShell, respectively, and wait for the process to complete before returning. The functions capture what the child process prints to both its standard output and standard error streams, and return this together with its exit code.

auto dmd = execute(["dmd", "myapp.d"]);
if (dmd.status != 0) writeln("Compilation failed:\n", dmd.output);

auto ls = executeShell("ls -l");
if (ls.status != 0) writeln("Failed to retrieve file listing");
else writeln(ls.output);

The args/program/command, env and config parameters are forwarded straight to the underlying spawn functions, and we refer to their documentation for details.

POSIX specific

If the process is terminated by a signal, the status field of the return value will contain a negative number whose absolute value is the signal number. (See wait for details.)

@paramargs An array which contains the program name as the zeroth element and any command-line arguments in the following elements. (See spawnProcess for details.)@paramprogram The program name, without command-line arguments. (See spawnProcess for details.)@paramcommand A shell command which is passed verbatim to the command interpreter. (See spawnShell for details.)@paramenv Additional environment variables for the child process. (See spawnProcess for details.)@paramconfig Flags that control process creation. See Config for an overview of available flags, and note that the retainStd... flags have no effect in this function.@parammaxOutput The maximum number of bytes of output that should be captured.@paramworkDir The working directory for the new process. By default the child process inherits the parent's working directory.@paramshellPath The path to the shell to use to run the specified program. By default this is nativeShell.@returnsAn std.typecons.Tuple!(int, "status", string, "output").@throws

ProcessException on failure to start the process.

StdioException on failure to capture output.

execute
([
(local variable) string adb
adb
, "-s",
(local variable) string serial
serial
, "shell",
(local variable) const(string[]) command
command
[1]]);
void std.stdio.writeln!string(string __param_0) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
(
(local variable) const(std.typecons.Tuple!(int, "status", string, "output")) result
result
.output);
if (
(local variable) const(std.typecons.Tuple!(int, "status", string, "output")) result
result
.status)
{
void std.stdio.writeln!(string, const(int))(string __param_0, const(int) __param_1) @safe

Equivalent to write(args, '\n'). Calling writeln without arguments is valid and just prints a newline to the standard output.

Example

Reads stdin and writes it to stdout with an argument counter.

import std.stdio;

void main()
{
    string line;

    for (size_t count = 0; (line = readln) !is null; count++)
    {
         writeln("Input ", count, ": ", line);
    }
}
@paramargs the items to write to stdout@throwsIn case of an I/O error, throws an StdioException.
writeln
("probe exit status: ",
(local variable) const(std.typecons.Tuple!(int, "status", string, "output")) result
result
.status);
(local variable) int failed
failed
= 1;
} } catch (
(class) object.Exception

The base class of all errors that are safe to catch and handle.

In principle, only thrown objects derived from this class are safe to catch inside a catch block. Thrown objects not derived from Exception represent runtime errors that should not be caught, as certain runtime guarantees may not hold, making it unsafe to continue program execution.

Examples

bool gotCaught;
try
{
    throw new Exception("msg");
}
catch (Exception e)
{
    gotCaught = true;
    assert(e.msg == "msg");
}
assert(gotCaught);
Exception
(local variable) object.Exception e
e
)
{ stderr.
std.stdio.File std.stdio.makeGlobal!"core.stdc.stdio.stderr"() nothrow @nogc @property ref @system
writeln
("inventory failed: ",
(local variable) object.Exception e
e
.
(field) string object.Throwable.msg

A message describing the error.

msg
);
return 1; } } return
(local variable) int failed
failed
;
}