├── lib ├── src │ ├── utils.dart │ ├── socket.dart │ ├── env.dart │ ├── files.dart │ ├── core.dart │ └── system.dart ├── syscall.dart ├── utils.dart ├── opencv.dart ├── readline.dart ├── snappy.dart └── darwin.dart ├── example ├── header.dart ├── cwd.dart ├── hostname.dart ├── rlimit.dart ├── environment.dart ├── opencv.dart ├── setuid.dart ├── snappy.dart ├── fork.dart ├── chmod.dart ├── info.dart ├── uname.dart ├── chroot.dart ├── sysctl.dart ├── speed.dart └── shell.dart ├── .gitignore ├── pubspec.yaml ├── LICENSE.md └── README.md /lib/src/utils.dart: -------------------------------------------------------------------------------- 1 | part of syscall; 2 | -------------------------------------------------------------------------------- /example/header.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/utils.dart"; 2 | 3 | void main() { 4 | print(findHeader("syscall.h")); 5 | } -------------------------------------------------------------------------------- /example/cwd.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | void main() { 4 | print(getWorkingDirectory()); 5 | } 6 | -------------------------------------------------------------------------------- /example/hostname.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | void main() { 4 | var host = getHostname(); 5 | print(host); 6 | } 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | packages 3 | pubspec.lock 4 | .idea/ 5 | docs/ 6 | dartdoc-viewer/ 7 | .project 8 | .settings 9 | .buildlog 10 | .pub 11 | out/ 12 | *.iml 13 | .c9* 14 | test.sh 15 | .packages -------------------------------------------------------------------------------- /example/rlimit.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | void main() { 4 | var proc = getResourceLimit(ResourceLimit.NPROC).current; 5 | 6 | print("Maximum Number of Processes: ${proc}"); 7 | } 8 | -------------------------------------------------------------------------------- /example/environment.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | main() { 4 | var pairs = getEnvironment(); 5 | var map = getEnvironmentMap(); 6 | 7 | print("Pairs: ${pairs}"); 8 | print("Map: ${map}"); 9 | } 10 | -------------------------------------------------------------------------------- /example/opencv.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | import "package:syscall/opencv.dart"; 3 | 4 | void main() { 5 | LibraryManager.init(); 6 | LibOpenCV.init(); 7 | 8 | var cam = openCamera(0); 9 | cam.grab(); 10 | } 11 | -------------------------------------------------------------------------------- /example/setuid.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | void main() { 4 | print("Attempting to Gain Superuser."); 5 | try { 6 | setUserId(0); 7 | print("Success."); 8 | } catch (e) { 9 | print(e); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /example/snappy.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/snappy.dart"; 2 | 3 | void main() { 4 | var result = Snappy.compress("1234567890" * 10); 5 | print("Compressed: ${result}"); 6 | var original = Snappy.decompress(result); 7 | print("Decompressed: ${original}"); 8 | } 9 | -------------------------------------------------------------------------------- /example/fork.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | void main() { 4 | print("Current PID: ${getProcessId()}"); 5 | 6 | var pid = fork(); 7 | 8 | print("PID: ${getProcessId()}"); 9 | 10 | if (pid == 0) { 11 | wait(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /pubspec.yaml: -------------------------------------------------------------------------------- 1 | name: syscall 2 | author: Kenneth Endfinger 3 | homepage: https://github.com/DirectMyFile/syscall 4 | description: Make calls to native code 5 | version: 0.5.0 6 | dependencies: 7 | binary_interop: ">=0.0.19 <0.1.0" 8 | binary_marshalling: ">=0.0.2 <0.1.0" 9 | transformers: 10 | - $dart2js: 11 | $exclude: "**" 12 | -------------------------------------------------------------------------------- /example/chmod.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | void main() { 4 | var path = "test.sh"; 5 | var fd = open(path, OpenFlags.CREATE | OpenFlags.READ_WRITE); 6 | var b = write(fd, '#!/usr/bin/env bash\necho "Hello World"'); 7 | fsync(fd); 8 | close(fd); 9 | print("Wrote ${b} bytes."); 10 | chmod(path, FileModes.FULL_ANYONE); 11 | } 12 | -------------------------------------------------------------------------------- /example/info.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | void main() { 4 | print("pid: ${getProcessId()}"); 5 | print("ppid: ${getParentProcessId()}"); 6 | print("uid: ${getUserId()}"); 7 | print("gid: ${getGroupId()}"); 8 | print("group name: ${getGroupInfo(getGroupId()).name}"); 9 | print("ctermid: ${getControllingTerminal()}"); 10 | } 11 | -------------------------------------------------------------------------------- /example/uname.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | void main() { 4 | var info = getKernelInfo(); 5 | 6 | print("Operating System: ${info.operatingSystemName}"); 7 | print("Kernel Version: ${info.version}"); 8 | print("Kernel Release: ${info.release}"); 9 | print("Network Name: ${info.networkName}"); 10 | print("Machine: ${info.machine}"); 11 | } 12 | -------------------------------------------------------------------------------- /example/chroot.dart: -------------------------------------------------------------------------------- 1 | import "dart:io"; 2 | 3 | import "package:syscall/syscall.dart"; 4 | 5 | void main(List args) { 6 | if (args.length == 0) { 7 | print("usage: chroot [command]"); 8 | exit(1); 9 | } 10 | 11 | chroot(args[0]); 12 | 13 | var cmd = args.skip(1).join(" "); 14 | 15 | if (cmd.isEmpty) { 16 | cmd = "bash"; 17 | } 18 | 19 | executeSystem(cmd); 20 | } 21 | -------------------------------------------------------------------------------- /example/sysctl.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/darwin.dart"; 2 | 3 | main() { 4 | var version = getSysCtlValue("kern.version"); 5 | print("Kernel Version: ${version}"); 6 | 7 | var mib = [1, 8]; 8 | var maxArgs = getSysCtlValueFromMib(mib, type: "int"); 9 | print("Maximum Arguments: ${maxArgs}"); 10 | 11 | var result = setSysCtlValue("kern.maxproc", 2048, type: "int"); 12 | print("Old Maximum Processes: ${result}"); 13 | } 14 | -------------------------------------------------------------------------------- /lib/syscall.dart: -------------------------------------------------------------------------------- 1 | library syscall; 2 | 3 | import "dart:io"; 4 | 5 | import "package:binary_interop/binary_interop.dart"; 6 | import "package:binary_marshalling/binary_marshalling.dart"; 7 | import "package:binary_marshalling/annotations.dart"; 8 | 9 | import "package:system_info/system_info.dart"; 10 | 11 | import "darwin.dart" show getSysCtlValue; 12 | 13 | export "package:binary_types/binary_types.dart"; 14 | 15 | part "src/core.dart"; 16 | part "src/system.dart"; 17 | part "src/env.dart"; 18 | part "src/files.dart"; 19 | part "src/utils.dart"; 20 | part "src/socket.dart"; 21 | -------------------------------------------------------------------------------- /example/speed.dart: -------------------------------------------------------------------------------- 1 | import "package:syscall/syscall.dart"; 2 | 3 | main() async { 4 | LibraryManager.init(); 5 | for (var i = 1; i <= 500; i++) { 6 | printf("${i}\n"); 7 | } 8 | var watch = new Stopwatch(); 9 | watch.start(); 10 | for (var i = 1; i <= 500; i++) { 11 | printf("${i}\n"); 12 | } 13 | watch.stop(); 14 | var nt = watch.elapsedMilliseconds; 15 | watch.reset(); 16 | watch.start(); 17 | for (var i = 1; i <= 500; i++) { 18 | print("${i}"); 19 | } 20 | watch.stop(); 21 | var rt = watch.elapsedMilliseconds; 22 | print("Native Time: ${nt}, Dart Time: ${rt}"); 23 | } -------------------------------------------------------------------------------- /lib/utils.dart: -------------------------------------------------------------------------------- 1 | library syscall.utils; 2 | 3 | import "dart:io"; 4 | 5 | Directory _headerDir = _getHeaderDirectory(); 6 | 7 | Directory _getHeaderDirectory() { 8 | return new Directory("/usr/include"); 9 | } 10 | 11 | /// Get the content of a header with a given name. 12 | /// Returns null if the header was not found. 13 | String findHeader(String name) { 14 | var toTry = [ 15 | "i386-linux-gnu/${name}", 16 | "x86_64-linux-gnu/${name}", 17 | "i386-linux-gnu/sys/${name}", 18 | "i386-linux-gnu/bits/${name}", 19 | "x86_64-linux-gnu/bits/${name}", 20 | "x86_64-linux-gnu/sys/${name}", 21 | "sys/${name}", 22 | "linux/${name}", 23 | "${name}" 24 | ].map((it) => joinPath([_headerDir.path, it])).toList(); 25 | 26 | for (var p in toTry) { 27 | var file = new File(p); 28 | if (file.existsSync()) { 29 | return file.readAsStringSync(); 30 | } 31 | } 32 | 33 | return null; 34 | } 35 | 36 | /// Join every element in [parts] by [Platform.pathSeparator] 37 | String joinPath(List parts) => parts.join(Platform.pathSeparator); 38 | -------------------------------------------------------------------------------- /lib/src/socket.dart: -------------------------------------------------------------------------------- 1 | part of syscall; 2 | 3 | class AddressFamily { 4 | static const int UNIX = 1; 5 | static const int LOCAL = 1; 6 | static const int INET = 2; 7 | static const int INET6 = 30; 8 | } 9 | 10 | class SocketType { 11 | static const int STREAM = 1; 12 | static const int DGRAM = 2; 13 | static const int RAW = 3; 14 | static const int RDM = 4; 15 | static const int SEQPACKET = 5; 16 | } 17 | 18 | class SocketAddress { 19 | @NativeName("sa_len") 20 | int length; 21 | 22 | @NativeName("sa_family") 23 | int family; 24 | 25 | @NativeName("sa_data") 26 | List data; 27 | } 28 | 29 | int createSocket(int af, int type, int protocol) { 30 | return checkSysCallResult(invoke("socket", [af, type, protocol])); 31 | } 32 | 33 | int connectSocket(int fd, SocketAddress addr, int len) { 34 | var l = alloc("struct sockaddr"); 35 | var data = new List(14); 36 | data.setAll(0, addr.data); 37 | data.fillRange(addr.data.length, 14, 0); 38 | l.value = { 39 | "sa_len": addr.length, 40 | "sa_family": addr.family, 41 | "sa_data": data 42 | }; 43 | return checkSysCallResult(invoke("connect", [fd, l, len])); 44 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | ``` 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2014 DirectCode 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | ``` 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # System Calls 2 | 3 | Make System Calls in Dart. You can rewrite almost any C program now in Dart! 4 | 5 | Currently this library supports Linux and Mac OSX. 6 | In the future, there will be partial support for Windows. 7 | 8 | Note that the name is misleading. 9 | System Calls include both pure C functions and actual System Calls, as well as bindings to commonly-used libraries. 10 | 11 | ## Bindings 12 | 13 | - OpenCV (WIP) 14 | - Readline 15 | - Snappy 16 | 17 | ## Examples 18 | 19 | This is just a few examples of what is possible. 20 | 21 | ### fork 22 | 23 | ```dart 24 | import "package:syscall/syscall.dart"; 25 | 26 | void main() { 27 | print("Prepare to be forked!"); 28 | var pid = fork(); 29 | 30 | if (pid == 0) { 31 | print("I am the original process."); 32 | wait(); 33 | } else { 34 | print("I am the child process."); 35 | } 36 | } 37 | ``` 38 | 39 | ### chroot 40 | 41 | ```dart 42 | import "dart:io"; 43 | 44 | import "package:syscall/syscall.dart"; 45 | 46 | void main(List args) { 47 | if (args.length == 0) { 48 | print("usage: chroot [command]"); 49 | exit(1); 50 | } 51 | 52 | chroot(args[0]); 53 | 54 | var cmd = args.skip(1).join(" "); 55 | 56 | if (cmd.isEmpty) { 57 | cmd = "bash"; 58 | } 59 | 60 | system(cmd); 61 | } 62 | ``` 63 | 64 | ### setuid 65 | 66 | ```dart 67 | import "package:syscall/syscall.dart"; 68 | 69 | void main() { 70 | print("Attempting to Gain Superuser."); 71 | try { 72 | setUserId(0); 73 | print("Success."); 74 | } catch (e) { 75 | print(e); 76 | } 77 | } 78 | ``` 79 | -------------------------------------------------------------------------------- /lib/src/env.dart: -------------------------------------------------------------------------------- 1 | part of syscall; 2 | 3 | /// Get the Current Environment 4 | /// Returns a list of KEY=VALUE pairs 5 | List getEnvironment() { 6 | var data = getVariable("environ", "char**"); 7 | var x = []; 8 | var l; 9 | var i = 0; 10 | 11 | while (!(l = data.getElementValue(i)).isNullPtr) { 12 | x.add(readNativeString(l)); 13 | i++; 14 | } 15 | 16 | return x; 17 | } 18 | 19 | /// Gets the Current Environment as a Map 20 | /// Calls [getEnvironment] and then converts it into a map 21 | Map getEnvironmentMap() { 22 | var map = {}; 23 | for (var pair in getEnvironment()) { 24 | var key = pair.substring(0, pair.indexOf("=")); 25 | var value = pair.length > key.length + 1 ? pair.substring(key.length + 1) : ""; 26 | map[key] = value; 27 | } 28 | return map; 29 | } 30 | 31 | /// Gets the value of [name] from the environment. 32 | /// This is more efficient than using either [getEnvironment] or [getEnvironmentMap] when you only want one variable. 33 | String getEnvironmentVariable(String name, [String defaultValue]) { 34 | var value = invoke("getenv", [toNativeString(name)]); 35 | if (value.isNullPtr) { 36 | return defaultValue; 37 | } else { 38 | return readNativeString(value); 39 | } 40 | } 41 | 42 | /// Sets the value of [name] in the environment to the specified [value]. 43 | /// If [overwrite] is true, when the variable already exists, it will be overwritten, otherwise it will not be changed. 44 | void setEnvironmentVariable(String name, String value, {bool overwrite: true}) { 45 | checkSysCallResult(invoke("setenv", [toNativeString(name), toNativeString(value), overwrite ? 1 : 0])); 46 | } 47 | 48 | /// Remove the variable specified by [name] from the environment. 49 | void removeEnvironmentVariable(String name) { 50 | checkSysCallResult(invoke("unsetenv", [toNativeString(name)])); 51 | } 52 | -------------------------------------------------------------------------------- /lib/opencv.dart: -------------------------------------------------------------------------------- 1 | library syscall.opencv; 2 | 3 | import "dart:io"; 4 | 5 | import "package:syscall/syscall.dart"; 6 | import "package:binary_interop/binary_interop.dart"; 7 | 8 | const String _HEADER_CORE = """ 9 | """; 10 | 11 | const String _HEADER_HIGH = """ 12 | typedef struct CvCapture CvCapture; 13 | CvCapture* cvCreateCameraCapture(int device); 14 | void cvReleaseCapture(CvCapture** capture); 15 | int cvGrabFrame(CvCapture* capture); 16 | void cvReleaseCapture(CvCapture** capture); 17 | """; 18 | 19 | class LibOpenCV { 20 | static DynamicLibrary libcore; 21 | static DynamicLibrary libhigh; 22 | 23 | static void init() { 24 | libcore = DynamicLibrary.load(getLibName("core"), types: LibraryManager.types); 25 | LibraryManager.loadHeader("libopencv_core.h", _HEADER_CORE); 26 | libcore.link(["libopencv_core.h"]); 27 | LibraryManager.register("opencv_core", libcore); 28 | libhigh = DynamicLibrary.load(getLibName("highgui"), types: LibraryManager.types); 29 | LibraryManager.loadHeader("libopencv_highgui.h", _HEADER_HIGH); 30 | libhigh.link(["libopencv_highgui.h"]); 31 | LibraryManager.register("opencv_highgui", libhigh); 32 | } 33 | 34 | static String getLibName(String n) { 35 | if (Platform.isAndroid || Platform.isLinux) { 36 | return "libopencv_${n}.so"; 37 | } else if (Platform.isMacOS) { 38 | return "libopencv_${n}.dylib"; 39 | } else { 40 | throw new Exception("Your platform is not supported."); 41 | } 42 | } 43 | } 44 | 45 | VideoCapture openCamera(int id) { 46 | var box = invoke("opencv_highgui::cvCreateCameraCapture", [id]); 47 | return new VideoCapture(box); 48 | } 49 | 50 | class VideoCapture { 51 | final BinaryData blackBox; 52 | 53 | VideoCapture(this.blackBox); 54 | 55 | void grab() { 56 | checkSysCallResult(invoke("opencv_highgui::cvGrabFrame", [blackBox])); 57 | } 58 | 59 | void release() { 60 | invoke("opencv_highgui::cvReleaseCapture", [alloc("CvCapture*", blackBox)]); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /lib/readline.dart: -------------------------------------------------------------------------------- 1 | library syscall.readline; 2 | 3 | import "dart:io"; 4 | 5 | import "package:binary_interop/binary_interop.dart"; 6 | import "package:syscall/syscall.dart"; 7 | 8 | const String _HEADER = """ 9 | typedef int rl_command_func_t(int l, int z); 10 | 11 | char *readline(const char* prompt); 12 | int rl_initialize(void); 13 | void using_history(void); 14 | int add_history(const char* input); 15 | void clear_history(void); 16 | void rl_redisplay(void); 17 | int rl_set_prompt(const char *prompt); 18 | int rl_on_new_line(void); 19 | int rl_insert_text(const char *text); 20 | int rl_kill_text(int start, int end); 21 | int rl_read_key(void); 22 | int rl_bind_key(int key, rl_command_func_t *function); 23 | int rl_unbind_key(int key); 24 | int rl_catch_signals; 25 | """; 26 | 27 | class LibReadline { 28 | static DynamicLibrary libreadline; 29 | 30 | static void init() { 31 | if (libreadline != null) { 32 | return; 33 | } 34 | 35 | String name; 36 | bool isGnu = true; 37 | 38 | if (Platform.isLinux || Platform.isAndroid) { 39 | name = "libreadline.so"; 40 | } else if (Platform.isMacOS) { 41 | if (new File("/usr/local/lib/libreadline.dylib").existsSync()) { 42 | name = "/usr/local/lib/libreadline.dylib"; 43 | } else { 44 | name = "libreadline.dylib"; 45 | isGnu = false; 46 | } 47 | } else { 48 | throw new Exception("Your platform is not supported."); 49 | } 50 | 51 | libreadline = DynamicLibrary.load(name, types: LibraryManager.types); 52 | LibraryManager.register("readline", libreadline); 53 | var e = {}; 54 | if (isGnu) { 55 | e["__GNU__"] = "true"; 56 | } 57 | LibraryManager.loadHeader("libreadline.h", _HEADER, e); 58 | libreadline.link(["libreadline.h"]); 59 | 60 | checkSysCallResult(invoke("readline::rl_initialize")); 61 | } 62 | } 63 | 64 | class Readline { 65 | static String readLine(String prompt, {bool addToHistory: false}) { 66 | LibReadline.init(); 67 | 68 | var p = toNativeString(prompt); 69 | var result = readNativeString(invoke("readline::readline", [p])); 70 | if (addToHistory) { 71 | addLineToHistory(result); 72 | } 73 | return result; 74 | } 75 | 76 | static void clearHistory() { 77 | LibReadline.init(); 78 | 79 | invoke("readline::clear_history"); 80 | } 81 | 82 | static void addLineToHistory(String input) { 83 | LibReadline.init(); 84 | 85 | var r = toNativeString(input); 86 | checkSysCallResult(invoke("readline::add_history", [r])); 87 | } 88 | 89 | static void bindKey(key, Function handler) { 90 | LibReadline.init(); 91 | 92 | var functionType = getBinaryType("rl_command_func_t"); 93 | 94 | var callback = new BinaryCallback(functionType, (args) { 95 | if (handler is ReadlineCommandRegularFunction) { 96 | return handler(args[0], args[1]); 97 | } else { 98 | return handler(); 99 | } 100 | }); 101 | 102 | checkSysCallResult(invoke("readline::rl_bind_key", [key is String ? key.codeUnitAt(0) : key, callback.functionCode])); 103 | } 104 | 105 | static void unbindKey(key) { 106 | LibReadline.init(); 107 | 108 | checkSysCallResult(invoke("readline::rl_unbind_key", [key is String ? key.codeUnitAt(0) : key])); 109 | } 110 | } 111 | 112 | typedef int ReadlineCommandRegularFunction(int x, int y); 113 | -------------------------------------------------------------------------------- /lib/snappy.dart: -------------------------------------------------------------------------------- 1 | library syscall.snappy; 2 | 3 | import "dart:io"; 4 | 5 | import "package:binary_interop/binary_interop.dart"; 6 | import "package:syscall/syscall.dart"; 7 | 8 | const String _HEADER = """ 9 | size_t snappy_max_compressed_length(size_t source_length); 10 | 11 | int snappy_compress(const char* input, 12 | size_t input_length, 13 | char* compressed, 14 | size_t* compressed_length); 15 | 16 | int snappy_uncompress(const char* compressed, 17 | size_t compressed_length, 18 | char* uncompressed, 19 | size_t* uncompressed_length); 20 | 21 | int snappy_uncompressed_length(const char* compressed, 22 | size_t compressed_length, 23 | size_t* result); 24 | """; 25 | 26 | class LibSnappy { 27 | static DynamicLibrary libsnappy; 28 | 29 | static void init() { 30 | if (libsnappy != null) { 31 | return; 32 | } 33 | 34 | String name; 35 | 36 | if (Platform.isLinux || Platform.isAndroid) { 37 | name = "libsnappy.so"; 38 | } else if (Platform.isMacOS) { 39 | name = "libsnappy.dylib"; 40 | } else { 41 | throw new Exception("Your platform is not supported."); 42 | } 43 | 44 | libsnappy = DynamicLibrary.load(name, types: LibraryManager.types); 45 | LibraryManager.register("snappy", libsnappy); 46 | LibraryManager.loadHeader("libsnappy.h", _HEADER); 47 | libsnappy.link(["libsnappy.h"]); 48 | } 49 | } 50 | 51 | enum SnappyStatus { 52 | OK, 53 | INVALID_INPUT, 54 | BUFFER_TOO_SMALL 55 | } 56 | 57 | class Snappy { 58 | static String compress(String input) { 59 | LibSnappy.init(); 60 | 61 | var inputString = toNativeString(input); 62 | var maxOutputSize = alloc("size_t", getMaxCompressedLength(inputString.type.size)); 63 | var rs = allocArray("char", maxOutputSize.value); 64 | var status = getStatus(invoke("snappy::snappy_compress", [inputString, inputString.type.size, rs, maxOutputSize])); 65 | if (status != SnappyStatus.OK) { 66 | throw new SnappyException(status); 67 | } 68 | var bytes = rs.value.take(maxOutputSize.value).toList(); 69 | rs = allocArray("char", maxOutputSize.value, bytes); 70 | return readNativeString(rs); 71 | } 72 | 73 | static String decompress(String input) { 74 | LibSnappy.init(); 75 | 76 | var inputString = toNativeString(input); 77 | var uncompressedSize = alloc("size_t", getUncompressedLength(inputString)); 78 | var rs = allocArray("char", uncompressedSize.value); 79 | var status = getStatus(invoke("snappy::snappy_uncompress", [inputString, inputString.type.size, rs, uncompressedSize])); 80 | if (status != SnappyStatus.OK) { 81 | throw new SnappyException(status); 82 | } 83 | return readNativeString(rs); 84 | } 85 | 86 | static SnappyStatus getStatus(int id) { 87 | if (id == 0) { 88 | return SnappyStatus.OK; 89 | } else if (id == 1) { 90 | return SnappyStatus.INVALID_INPUT; 91 | } else if (id == 2) { 92 | return SnappyStatus.BUFFER_TOO_SMALL; 93 | } 94 | return null; 95 | } 96 | 97 | static int getUncompressedLength(BinaryData input) { 98 | LibSnappy.init(); 99 | 100 | var result = alloc("size_t"); 101 | var status = getStatus(invoke("snappy::snappy_uncompressed_length", [input, input.type.size, result])); 102 | if (status != SnappyStatus.OK) { 103 | throw new SnappyException(status); 104 | } 105 | return result.value; 106 | } 107 | 108 | static int getMaxCompressedLength(int size) { 109 | LibSnappy.init(); 110 | 111 | return invoke("snappy::snappy_max_compressed_length", [size]); 112 | } 113 | } 114 | 115 | class SnappyException { 116 | final SnappyStatus status; 117 | 118 | SnappyException(this.status); 119 | 120 | @override 121 | String toString() => status.toString(); 122 | } 123 | -------------------------------------------------------------------------------- /lib/darwin.dart: -------------------------------------------------------------------------------- 1 | /// Darwin Specific Functions 2 | @Compatibility("Mac Only") 3 | library syscall.darwin; 4 | 5 | import "package:syscall/syscall.dart"; 6 | import "package:binary_interop/binary_interop.dart"; 7 | 8 | const String _HEADER = """ 9 | typedef unsigned int u_int; 10 | 11 | int sysctlbyname(const char *name, void *oldp, size_t *oldlenp, void *newp, size_t newlen); 12 | int sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, size_t newlen); 13 | """; 14 | 15 | bool _initialized = false; 16 | 17 | void _init() { 18 | if (!_initialized) { 19 | if (!LibraryManager.loaded) { 20 | LibraryManager.init(); 21 | } 22 | LibraryManager.typeHelper.addHeader("libc_darwin.h", _HEADER); 23 | LibraryManager.typeHelper.declare("libc_darwin.h"); 24 | LibraryManager.libc.link(["libc_darwin.h"]); 25 | _initialized = true; 26 | } 27 | } 28 | 29 | /// Sets the value of [name] in the sysctl database. 30 | /// [type] specifies the type of the value. 31 | /// If [dtype] is specified, the value will be unmarshalled into this type. 32 | /// 33 | /// Returns the old value. 34 | dynamic setSysCtlValue(String name, value, {type: "char[]", Type dtype}) { 35 | BinaryData val; 36 | if (value is BinaryData) { 37 | val = value; 38 | } else if (value is String) { 39 | val = toNativeString(value); 40 | } else if (value is int) { 41 | val = alloc("int", value); 42 | } else if (value is double) { 43 | val = alloc("double", value); 44 | } 45 | var old = getSysCtlValue(name, type: type, dtype: dtype); 46 | checkSysCallResult(invoke("sysctlbyname", [toNativeString(name), getType("void*").nullPtr, alloc("size_t", 0), val, val.type.size])); 47 | return old; 48 | } 49 | 50 | /// Gets the value of [name] in the sysctl database. 51 | /// [type] specifies the type of the value. 52 | /// If [dtype] is specified, the value will be unmarshalled into this type. 53 | dynamic getSysCtlValue(String name, {type: "char[]", Type dtype, bool raw: true}) { 54 | if (type == "char[]" && dtype == null) { 55 | dtype = String; 56 | } 57 | 58 | _init(); 59 | var len = alloc("size_t"); 60 | var n = toNativeString(name); 61 | 62 | checkSysCallResult(invoke("sysctlbyname", [n, getType("void*").nullPtr, len, getType("void*").nullPtr, 0])); 63 | 64 | if (type.toString().endsWith("[]")) { 65 | type = getType(type.toString().substring(0, type.length - 2) + "[${len.value}]"); 66 | } else { 67 | type = getBinaryType(type); 68 | } 69 | 70 | var value = alloc(type); 71 | 72 | checkSysCallResult(invoke("sysctlbyname", [n, value, len, getType("void*").nullPtr, 0])); 73 | 74 | if (dtype != null) { 75 | if (dtype == String) { 76 | return readNativeString(value); 77 | } 78 | 79 | return LibraryManager.unmarshall(value, dtype); 80 | } else { 81 | if (type.toString() == "int") { 82 | return value.value; 83 | } 84 | 85 | return value; 86 | } 87 | } 88 | 89 | /// Gets the value of [mib] in the sysctl database. 90 | /// [type] specifies the type of the value. 91 | /// If [dtype] is specified, the value will be unmarshalled into this type. 92 | dynamic getSysCtlValueFromMib(List mib, {type: "char[]", Type dtype, bool raw: true}) { 93 | if (type == "char[]") { 94 | dtype = String; 95 | } 96 | 97 | _init(); 98 | 99 | var len = alloc("size_t"); 100 | var m = alloc("int[${mib.length}]"); 101 | m.value = mib; 102 | 103 | checkSysCallResult(invoke("sysctl", [m, mib.length, getType("void*").nullPtr, len, getType("void*").nullPtr, 0])); 104 | 105 | if (type.toString().endsWith("[]")) { 106 | type = getType(type.toString().substring(0, type.length - 2) + "[${len.value}]"); 107 | } else { 108 | type = getBinaryType(type); 109 | } 110 | 111 | var value = alloc(type); 112 | 113 | checkSysCallResult(invoke("sysctl", [m, mib.length, value, len, getType("void*").nullPtr, 0])); 114 | 115 | if (dtype != null) { 116 | if (dtype == String) { 117 | return readNativeString(value); 118 | } 119 | 120 | return LibraryManager.unmarshall(value, dtype); 121 | } else { 122 | if (type.toString() == "int") { 123 | return value.value; 124 | } 125 | 126 | return value; 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /lib/src/files.dart: -------------------------------------------------------------------------------- 1 | part of syscall; 2 | 3 | int toOctal(x) { 4 | return int.parse("${x}", radix: 8); 5 | } 6 | 7 | class FileModes { 8 | static final int SET_UID = toOctal("4000"); 9 | static final int SET_GID = toOctal(Platform.isMacOS ? "0002000" : "02000"); 10 | static final int READ_BY_OWNER = toOctal(Platform.isMacOS ? "0000400" : "00400"); 11 | static final int WRITE_BY_OWNER = toOctal(Platform.isMacOS ? "0000200" : "00200"); 12 | static final int EXECUTE_BY_OWNER = toOctal(Platform.isMacOS ? "0000100" : "00100"); 13 | static final int READ_BY_GROUP = toOctal(Platform.isMacOS ? "0000040" : "00040"); 14 | static final int WRITE_BY_GROUP = toOctal(Platform.isMacOS ? "0000020" : "00020"); 15 | static final int EXECUTE_BY_GROUP = toOctal(Platform.isMacOS ? "0000010" : "00010"); 16 | static final int READ_BY_OTHERS = toOctal(Platform.isMacOS ? "0000004" : "00004"); 17 | static final int WRITE_BY_OTHERS = toOctal(Platform.isMacOS ? "0000002" : "00002"); 18 | static final int EXECUTE_BY_OTHERS = toOctal(Platform.isMacOS ? "0000001" : "00001"); 19 | 20 | static final int FULL_OWNER = toOctal(Platform.isMacOS ? "0000700" : "00700"); 21 | static final int FULL_GROUP = toOctal(Platform.isMacOS ? "0000070" : "00070"); 22 | static final int FULL_OTHERS = toOctal(Platform.isMacOS ? "0000007" : "00007"); 23 | static final int FULL_ANYONE = FULL_OWNER | FULL_GROUP | FULL_OTHERS; 24 | static final int ANYONE_READ = READ_BY_OWNER | READ_BY_GROUP | READ_BY_OTHERS; 25 | static final int ANYONE_WRITE = WRITE_BY_OWNER | WRITE_BY_GROUP | WRITE_BY_OTHERS; 26 | static final int ANYONE_EXECUTE = EXECUTE_BY_OWNER | EXECUTE_BY_GROUP | EXECUTE_BY_OTHERS; 27 | } 28 | 29 | /// Change the mode of the file specified by [path] to [mode]. 30 | /// See [this page](http://man7.org/linux/man-pages/man2/chmod.2.html) to get an idea of how to create the [mode]. 31 | void chmod(String path, int mode) { 32 | var p = toNativeString(path); 33 | checkSysCallResult(invoke("chmod", [p, mode])); 34 | } 35 | 36 | /// Change the mode of the file specified by the file descriptor to [mode]. 37 | void fchmod(int fd, int mode) { 38 | checkSysCallResult(invoke("fchmod", [fd, mode])); 39 | } 40 | 41 | /// Change Ownership of a file 42 | void chown(String path, int uid, int gid) { 43 | checkSysCallResult(invoke("chown", [toNativeString(path), uid, gid])); 44 | } 45 | 46 | /// Change Ownership of a file 47 | void fchown(int fd, int uid, int gid) { 48 | checkSysCallResult(invoke("fchown", [fd, uid, gid])); 49 | } 50 | 51 | /// Change the current working directory. 52 | void chdir(String path) { 53 | checkSysCallResult(invoke("chdir", [toNativeString(path)])); 54 | } 55 | 56 | /// Change the root directory of this process. 57 | /// This will change the working directory as well. 58 | void chroot(String path) { 59 | chdir(path); 60 | checkSysCallResult(invoke("chroot", [toNativeString(path)])); 61 | } 62 | 63 | /// Commits the buffer cache to disk. 64 | void sync() { 65 | invoke("sync"); 66 | } 67 | 68 | /// Get File Stats 69 | Stat stat(String path) { 70 | var p = toNativeString(path); 71 | var d = alloc("struct stat"); 72 | checkSysCallResult(invoke("stat", [p, d])); 73 | return LibraryManager.unmarshall(d, Stat); 74 | } 75 | 76 | /// Get File Stats 77 | Stat fstat(int fd) { 78 | var d = alloc("struct stat"); 79 | checkSysCallResult(invoke("fstat", [fd, d])); 80 | return LibraryManager.unmarshall(d, Stat); 81 | } 82 | 83 | /// File Stats 84 | class Stat { 85 | @NativeName("st_dev") 86 | int deviceId; 87 | @NativeName("st_ino") 88 | int inode; 89 | @NativeName("st_mode") 90 | int mode; 91 | @NativeName("st_nlink") 92 | int hardLinkCount; 93 | @NativeName("st_uid") 94 | int uid; 95 | @NativeName("st_gid") 96 | int gid; 97 | @NativeName("st_rdev") 98 | int specialDeviceFile; 99 | @NativeName("st_size") 100 | int size; 101 | @NativeName("st_blksize") 102 | int blockSize; 103 | @NativeName("st_blocks") 104 | int blocks; 105 | } 106 | 107 | /// Open the file at [path] with the specified [flags]. 108 | /// Returns a file descriptor. 109 | int open(String path, int flags, [int mode]) { 110 | var p = toNativeString(path); 111 | return checkSysCallResult( 112 | invoke("open", mode != null ? [p, flags, mode] : [p, flags], mode != null ? [getType("mode_t")] : []) 113 | ); 114 | } 115 | 116 | /// Close the specified file descriptor. 117 | void close(int fd) { 118 | checkSysCallResult(invoke("close", [fd])); 119 | } 120 | 121 | /// Sync the Kernel Buffer for the file descriptor. 122 | void fsync(int fd) { 123 | checkSysCallResult(invoke("fsync", [fd])); 124 | } 125 | 126 | /// Change the working directory to the directory specified by the file descriptor [fd]. 127 | void fchdir(int fd) { 128 | checkSysCallResult(invoke("fchdir", [fd])); 129 | } 130 | 131 | /// Checks if the specified file descriptor is a terminal. 132 | bool isATty(int fd) { 133 | return invoke("isatty", [fd]) == 1; 134 | } 135 | 136 | /// Writes the data by [data] to the file descriptor specified by [fd]. 137 | /// [data] can be a List or a String. 138 | /// If [count] is specified, then only that amount of data will be written. 139 | int write(int fd, data, [int count]) { 140 | BinaryData d; 141 | int fc; 142 | 143 | if (data is String) { 144 | d = toNativeString(data); 145 | fc = d.type.size; 146 | } else if (data is List) { 147 | d = allocArray("int", data.length, data); 148 | fc = data.length; 149 | } else { 150 | throw new ArgumentError.value(data, "data", "should be a String or a List"); 151 | } 152 | 153 | if (count == null) { 154 | count = fc; 155 | } 156 | 157 | return checkSysCallResult(invoke("write", [fd, d, count])); 158 | } 159 | 160 | /// Get Working Directory 161 | String getWorkingDirectory() { 162 | return readNativeString(invoke("getcwd", [getType("char").nullPtr, 0])); 163 | } 164 | 165 | class OpenFlags { 166 | static final int APPEND = Platform.isMacOS ? 0x0008 : toOctal("00002000"); 167 | static final int READ = 0x0000; 168 | static final int WRITE = 0x0001; 169 | static final int READ_WRITE = 0x0002; 170 | static final int NONBLOCK = Platform.isMacOS ? 0x0004 : toOctal("00004000"); 171 | static final int CREATE = Platform.isMacOS ? 0x0200 : toOctal("00000100"); 172 | static final int TRUNCATE = Platform.isMacOS ? 0x0400 : toOctal("00001000"); 173 | static final int NOFOLLOW = Platform.isMacOS ? 0x0100 : toOctal("00400000"); 174 | static final int CLOSE_ON_EXEC = Platform.isMacOS ? 0x1000000 : toOctal("02000000"); 175 | static final int NO_CTTY = Platform.isMacOS ? 0x20000 : toOctal("00000400"); 176 | static final int DIRECTORY = Platform.isMacOS ? 0x100000 : toOctal("00200000"); 177 | static final int ERROR_IF_EXISTS = Platform.isMacOS ? 0x0800 : toOctal("00000200"); 178 | static final int SYNC = Platform.isMacOS ? 0x400000 : toOctal("00010000"); 179 | static final int ASYNC = Platform.isMacOS ? 0x0040 : toOctal("020000"); 180 | } 181 | -------------------------------------------------------------------------------- /example/shell.dart: -------------------------------------------------------------------------------- 1 | import "dart:async"; 2 | import "dart:convert"; 3 | import "dart:io"; 4 | 5 | import "package:syscall/readline.dart"; 6 | import "package:syscall/syscall.dart" as syscall; 7 | import "dart:isolate"; 8 | 9 | worker(SendPort port) async { 10 | LibReadline.init(); 11 | var receiver = new ReceivePort(); 12 | port.send(receiver.sendPort); 13 | 14 | await for (Map msg in receiver) { 15 | if (msg["method"] == "readline") { 16 | var prompt = msg["prompt"]; 17 | var result = Readline.readLine(prompt); 18 | port.send({ 19 | "type": "read", 20 | "data": result 21 | }); 22 | } else if (msg["method"] == "addLineToHistory") { 23 | var line = msg["line"]; 24 | Readline.addLineToHistory(line); 25 | } else if (msg["method"] == "clearHistory") { 26 | Readline.clearHistory(); 27 | } else if (msg["method"] == "bulkLoadHistory") { 28 | var history = msg["history"]; 29 | for (var line in history) { 30 | Readline.addLineToHistory(line); 31 | } 32 | } else if (msg["method"] == "bindKey") { 33 | var key = msg["key"]; 34 | var handler = msg["handler"]; 35 | 36 | Readline.bindKey(key, handler); 37 | } 38 | } 39 | } 40 | 41 | String prompt = r"$ "; 42 | 43 | SendPort mainPort; 44 | 45 | main() async { 46 | await loadStorage(); 47 | await loadSystemCommands(); 48 | 49 | commands.addAll(builtInCommands); 50 | 51 | if (storage["prompt"] != null) { 52 | prompt = storage["prompt"]; 53 | } 54 | 55 | if (storage["aliases"] != null) { 56 | for (var a in storage["aliases"].keys) { 57 | addAlias(a, storage["aliases"][a]); 58 | } 59 | await saveStorage(); 60 | } 61 | 62 | env.addAll(Platform.environment); 63 | env["BULLET_VERSION"] = "1.0"; 64 | 65 | var receiver = new ReceivePort(); 66 | var msgs = receiver.asBroadcastStream(); 67 | var isolate = await Isolate.spawn(worker, receiver.sendPort); 68 | mainPort = await msgs.first; 69 | 70 | if (storage["history"] != null) { 71 | /// Load History 72 | mainPort.send({ 73 | "method": "bulkLoadHistory", 74 | "history": storage["history"] 75 | }); 76 | } 77 | 78 | while (true) { 79 | mainPort.send({ 80 | "method": "readline", 81 | "prompt": prompt 82 | }); 83 | var msg = await msgs.first; 84 | await handleMessage(msg); 85 | } 86 | } 87 | 88 | handleMessage(Map msg) async { 89 | if (msg["type"] == "read") { 90 | await handleLine(msg["data"]); 91 | } 92 | } 93 | 94 | RegExp VAR_REGEX = new RegExp(r"\$\{(.+)\}"); 95 | 96 | String processEnvironmentVars(String input) { 97 | if (!VAR_REGEX.hasMatch(input)) { 98 | return input; 99 | } 100 | 101 | return input.replaceAllMapped(VAR_REGEX, (match) { 102 | var name = match.group(1); 103 | if (env.containsKey(name)) { 104 | return env[name]; 105 | } else { 106 | return ""; 107 | } 108 | }); 109 | } 110 | 111 | Map env = {}; 112 | 113 | handleLine(String line) async { 114 | if (line == null) { 115 | exit(1); 116 | } 117 | 118 | line = line.trimLeft(); 119 | 120 | if (line.trim().isEmpty) { 121 | return; 122 | } 123 | 124 | line = processEnvironmentVars(line); 125 | 126 | mainPort.send({ 127 | "method": "addLineToHistory", 128 | "line": line 129 | }); 130 | 131 | var history = storage["history"]; 132 | 133 | if (history == null) { 134 | history = storage["history"] = []; 135 | } 136 | 137 | history.add(line); 138 | 139 | await saveStorage(); 140 | 141 | var split = line.split(" "); 142 | if (split.length == 0) { 143 | return; 144 | } 145 | var cmd = split[0]; 146 | var args = split.skip(1).toList(); 147 | 148 | await handleCommand(cmd, args); 149 | } 150 | 151 | loadSystemCommands() async { 152 | var c = {}; 153 | var paths = Platform.environment["PATH"].split(Platform.isWindows ? ";" : ":"); 154 | for (var path in paths) { 155 | var dir = new Directory(path); 156 | if (!(await dir.exists())) { 157 | continue; 158 | } 159 | 160 | await for (File file in dir.list().where((it) => it is File)) { 161 | FileStat stat = await file.stat(); 162 | if (hasPermission(stat.mode, FilePermission.EXECUTE)) { 163 | var z = file.path; 164 | var name = z.split(Platform.pathSeparator).last; 165 | c[name] = z; 166 | } 167 | } 168 | } 169 | 170 | for (var name in c.keys) { 171 | commands[name] = (List args) async { 172 | if (storage["spawn_using_syscall"] == false) { 173 | var result = await exec(c[name], args: args, inherit: true); 174 | return result.exitCode; 175 | } else { 176 | var result = syscall.executeSystem(([name]..addAll(args)).join(" ")); 177 | return syscall.getExitCodeFromStatus(result); 178 | } 179 | }; 180 | } 181 | } 182 | 183 | handleCommand(String cmd, List args) async { 184 | if (commands.containsKey(cmd)) { 185 | var c = commands[cmd]; 186 | if (c is String) { 187 | return await handleCommand(c, args); 188 | } 189 | var result = await c(args); 190 | if (result is int) { 191 | env["?"] = result.toString(); 192 | } else { 193 | env["?"] = "0"; 194 | } 195 | } else { 196 | print("Unknown Command: ${cmd}"); 197 | env["?"] = "1"; 198 | } 199 | } 200 | 201 | Map commands = {}; 202 | 203 | Map builtInCommands = { 204 | "exit": (List args) { 205 | int code = 0; 206 | if (args.length > 1) { 207 | print("Usage: exit [code = 0]"); 208 | return 1; 209 | } else { 210 | if (args.length == 1) { 211 | var m = int.parse(args[0], onError: (source) => null); 212 | if (m == null) { 213 | print("Invalid Exit Code"); 214 | return 1; 215 | } 216 | code = m; 217 | } 218 | } 219 | exit(code); 220 | }, 221 | "clear-history": (List args) async { 222 | mainPort.send({ 223 | "method": "clearHistory" 224 | }); 225 | storage["history"] = []; 226 | await saveStorage(); 227 | }, 228 | "print": (List args) { 229 | print(args.join(" ")); 230 | }, 231 | "echo": "print", 232 | "alias": (List args) async { 233 | if (args.length <= 1) { 234 | print("Usage: alias {your command} {target command}"); 235 | } 236 | 237 | var m = args[0]; 238 | var l = args.skip(1).toList(); 239 | 240 | addAlias(m, l); 241 | await saveStorage(); 242 | }, 243 | "set": (List args) { 244 | if (args.length < 2) { 245 | print("Usage: set {variable} {value}"); 246 | return 1; 247 | } 248 | 249 | var n = args[0]; 250 | var v = args.skip(1).join(" "); 251 | env[n] = v; 252 | }, 253 | "unset": (List args) { 254 | for (var n in args) { 255 | env.remove(n); 256 | } 257 | } 258 | }; 259 | 260 | void addAlias(String m, List l) { 261 | commands[m] = (List a) { 262 | var t = l[0]; 263 | var r = l.skip(1).toList(); 264 | var q = new List.from(r)..addAll(a); 265 | return handleCommand(t, q); 266 | }; 267 | 268 | if (!storage.containsKey("aliases")) { 269 | storage["aliases"] = {}; 270 | } 271 | 272 | storage["aliases"][m] = l; 273 | } 274 | 275 | loadStorage() async { 276 | var file = new File("${Platform.environment["HOME"]}/.bullet/storage.json"); 277 | if (!(await file.exists())) { 278 | await file.create(recursive: true); 279 | await file.writeAsString("{}\n"); 280 | } 281 | var content = await file.readAsString(); 282 | storage = JSON.decode(content); 283 | } 284 | 285 | saveStorage() async { 286 | var file = new File("${Platform.environment["HOME"]}/.bullet/storage.json"); 287 | if (!(await file.exists())) { 288 | await file.create(recursive: true); 289 | } 290 | await file.writeAsString(jsonEncoder.convert(storage) + "\n"); 291 | } 292 | 293 | JsonEncoder jsonEncoder = new JsonEncoder.withIndent(" "); 294 | 295 | Map storage = {}; 296 | 297 | typedef CommandHandler(List args); 298 | 299 | class FilePermission { 300 | 301 | final int index; 302 | final String _name; 303 | 304 | const FilePermission._(this.index, this._name); 305 | 306 | static const EXECUTE = const FilePermission._(0, 'EXECUTE'); 307 | static const WRITE = const FilePermission._(1, 'WRITE'); 308 | static const READ = const FilePermission._(2, 'READ'); 309 | static const SET_UID = const FilePermission._(3, 'SET_UID'); 310 | static const SET_GID = const FilePermission._(4, 'SET_GID'); 311 | static const STICKY = const FilePermission._(5, 'STICKY'); 312 | 313 | static const List values = const [EXECUTE, WRITE, READ, SET_UID, SET_GID, STICKY]; 314 | 315 | String toString() => 'FilePermission.$_name'; 316 | } 317 | 318 | class FilePermissionRole { 319 | final int index; 320 | final String _name; 321 | 322 | const FilePermissionRole._(this.index, this._name); 323 | 324 | static const WORLD = const FilePermissionRole._(0, 'WORLD'); 325 | static const GROUP = const FilePermissionRole._(1, 'GROUP'); 326 | static const OWNER = const FilePermissionRole._(2, 'OWNER'); 327 | 328 | static const List values = const [WORLD, GROUP, OWNER]; 329 | 330 | String toString() => 'FilePermissionRole.$_name'; 331 | } 332 | 333 | bool hasPermission(int fileStatMode, FilePermission permission, {FilePermissionRole role: FilePermissionRole.WORLD}) { 334 | var bitIndex = _getPermissionBitIndex(permission, role); 335 | return (fileStatMode & (1 << bitIndex)) != 0; 336 | } 337 | 338 | int _getPermissionBitIndex(FilePermission permission, FilePermissionRole role) { 339 | switch (permission) { 340 | case FilePermission.SET_UID: 341 | return 11; 342 | case FilePermission.SET_GID: 343 | return 10; 344 | case FilePermission.STICKY: 345 | return 9; 346 | default: 347 | return (role.index * 3) + permission.index; 348 | } 349 | } 350 | 351 | typedef void ProcessHandler(Process process); 352 | typedef void OutputHandler(String str); 353 | 354 | Stdin get _stdin => stdin; 355 | 356 | class BetterProcessResult extends ProcessResult { 357 | final String output; 358 | 359 | BetterProcessResult(int pid, int exitCode, stdout, stderr, this.output) : 360 | super(pid, exitCode, stdout, stderr); 361 | } 362 | 363 | Future exec( 364 | String executable, 365 | { 366 | List args: const [], 367 | String workingDirectory, 368 | Map environment, 369 | bool includeParentEnvironment: true, 370 | bool runInShell: false, 371 | stdin, 372 | ProcessHandler handler, 373 | OutputHandler stdoutHandler, 374 | OutputHandler stderrHandler, 375 | OutputHandler outputHandler, 376 | bool inherit: false 377 | }) async { 378 | Process process = await Process.start( 379 | executable, 380 | args, 381 | workingDirectory: workingDirectory, 382 | environment: environment, 383 | includeParentEnvironment: includeParentEnvironment, 384 | runInShell: runInShell 385 | ); 386 | 387 | var buff = new StringBuffer(); 388 | var ob = new StringBuffer(); 389 | var eb = new StringBuffer(); 390 | 391 | process.stdout.transform(UTF8.decoder).listen((str) { 392 | ob.write(str); 393 | buff.write(str); 394 | 395 | if (stdoutHandler != null) { 396 | stdoutHandler(str); 397 | } 398 | 399 | if (outputHandler != null) { 400 | outputHandler(str); 401 | } 402 | 403 | if (inherit) { 404 | stdout.write(str); 405 | } 406 | }); 407 | 408 | process.stderr.transform(UTF8.decoder).listen((str) { 409 | eb.write(str); 410 | buff.write(str); 411 | 412 | if (stderrHandler != null) { 413 | stderrHandler(str); 414 | } 415 | 416 | if (outputHandler != null) { 417 | outputHandler(str); 418 | } 419 | 420 | if (inherit) { 421 | stderr.write(str); 422 | } 423 | }); 424 | 425 | if (handler != null) { 426 | handler(process); 427 | } 428 | 429 | if (stdin != null) { 430 | if (stdin is Stream) { 431 | stdin.listen(process.stdin.add, onDone: process.stdin.close); 432 | } else if (stdin is List) { 433 | process.stdin.add(stdin); 434 | } else { 435 | process.stdin.write(stdin); 436 | await process.stdin.close(); 437 | } 438 | } else if (inherit) { 439 | Stream> a = await new File("/dev/stdin").openRead(); 440 | a.listen(process.stdin.add, onDone: process.stdin.close); 441 | } 442 | 443 | var code = await process.exitCode; 444 | var pid = process.pid; 445 | 446 | return new BetterProcessResult( 447 | pid, 448 | code, 449 | ob.toString(), 450 | eb.toString(), 451 | buff.toString() 452 | ); 453 | } 454 | -------------------------------------------------------------------------------- /lib/src/core.dart: -------------------------------------------------------------------------------- 1 | part of syscall; 2 | 3 | /// Initial Header 4 | const String HEADER = """ 5 | typedef unsigned int size_t; 6 | typedef unsigned int mode_t; 7 | typedef unsigned int pid_t; 8 | typedef unsigned int uid_t; 9 | typedef unsigned int gid_t; 10 | typedef unsigned int suseconds_t; 11 | typedef unsigned int time_t; 12 | typedef unsigned int rlim_t; 13 | typedef unsigned int ssize_t; 14 | typedef unsigned int dev_t; 15 | typedef unsigned int ino_t; 16 | typedef unsigned int nlink_t; 17 | typedef unsigned int off_t; 18 | typedef unsigned int blksize_t; 19 | typedef unsigned int blkcnt_t; 20 | typedef unsigned int socklen_t; 21 | typedef unsigned int sa_family_t; 22 | typedef unsigned int uint8_t; 23 | typedef unsigned int uint32_t; 24 | 25 | int errno; 26 | char *strerror(int errnum); 27 | 28 | int ioctl(int fd, unsigned long request, ...); 29 | 30 | pid_t getpid(void); 31 | pid_t getppid(void); 32 | pid_t getpgrp(void); 33 | int setpgid(pid_t pid, pid_t pgid); 34 | 35 | pid_t getsid(pid_t pid); 36 | pid_t setsid(void); 37 | 38 | void sync(void); 39 | 40 | void syslog(int priority, const char *message, ...); 41 | void closelog(void); 42 | void openlog(const char *ident, int logopt, int facility); 43 | int setlogmask(int maskpri); 44 | 45 | uid_t getuid(void); 46 | uid_t geteuid(void); 47 | int seteuid(uid_t uid); 48 | int setuid(uid_t uid); 49 | gid_t getgid(void); 50 | int setgid(gid_t gid); 51 | gid_t getegid(void); 52 | int setegid(gid_t gid); 53 | 54 | pid_t fork(void); 55 | pid_t vfork(void); 56 | pid_t wait(int *status); 57 | pid_t waitpid(pid_t pid, int *status, int options); 58 | int kill(pid_t pid, int sig); 59 | 60 | int isatty(int fildes); 61 | int ttyslot(void); 62 | 63 | typedef void (*sighandler_t)(int); 64 | sighandler_t signal(int signum, sighandler_t handler); 65 | 66 | time_t time(time_t *t); 67 | 68 | char *getlogin(void); 69 | struct group *getgrnam(const char *name); 70 | struct group *getgrgid(gid_t gid); 71 | int getgrnam_r(const char *name, struct group *grp, char *buf, size_t buflen, struct group **result); 72 | int getgrgid_r(gid_t gid, struct group *grp, char *buf, size_t buflen, struct group **result); 73 | struct group { 74 | char *gr_name; 75 | char *gr_passwd; 76 | gid_t gr_gid; 77 | char **gr_mem; 78 | }; 79 | 80 | void* malloc(size_t size); 81 | 82 | int getloadavg(double loadavg[], int nelem); 83 | 84 | char *getenv(const char *name); 85 | int setenv(const char *name, const char *value, int overwrite); 86 | int unsetenv(const char *name); 87 | 88 | char **environ; 89 | char *ttyname(int fd); 90 | 91 | int getgrouplist(const char *user, gid_t group, gid_t *groups, int *ngroups); 92 | struct passwd *getpwnam(const char *name); 93 | 94 | int chmod(const char *path, mode_t mode); 95 | int fchmod(int fd, mode_t mode); 96 | int chown(const char *pathname, uid_t owner, gid_t group); 97 | int fchown(int fd, uid_t owner, gid_t group); 98 | int lchown(const char *pathname, uid_t owner, gid_t group); 99 | char *getcwd(char *buf, size_t size); 100 | char *getwd(char *buf); 101 | int chdir(const char *path); 102 | int fchdir(int fd); 103 | int chroot(const char *path); 104 | 105 | int gethostname(char *name, size_t len); 106 | int sethostname(const char *name, size_t len); 107 | int system(const char *command); 108 | 109 | size_t strlen(const char *str); 110 | char *strcpy(char *destination, const char *source); 111 | 112 | 113 | struct sockaddr { 114 | unsigned int sa_len; 115 | sa_family_t sa_family; 116 | char sa_data[14]; 117 | }; 118 | 119 | void *memcpy(void *dest, const void *src, size_t n); 120 | 121 | struct hostent { 122 | char *h_name; 123 | char **h_aliases; 124 | int h_addrtype; 125 | int h_length; 126 | struct in_addr **h_addr_list; 127 | }; 128 | 129 | struct in_addr { 130 | uint32_t s_addr; 131 | }; 132 | 133 | int printf(const char *format, ...); 134 | 135 | struct hostent *gethostbyname(const char *name); 136 | int socket(int domain, int type, int protocol); 137 | int connect(int sockfd, const struct sockaddr *addr, 138 | socklen_t addrlen); 139 | 140 | struct stat { 141 | dev_t st_dev; 142 | ino_t st_ino; 143 | mode_t st_mode; 144 | nlink_t st_nlink; 145 | uid_t st_uid; 146 | gid_t st_gid; 147 | dev_t st_rdev; 148 | off_t st_size; 149 | blksize_t st_blksize; 150 | blkcnt_t st_blocks; 151 | }; 152 | 153 | int fsync(int fd); 154 | 155 | #if !defined(__ARM__) && !defined(__DEBIAN__) 156 | int stat(const char *pathname, struct stat *buf); 157 | int fstat(int fd, struct stat *buf); 158 | int lstat(const char *pathname, struct stat *buf); 159 | #endif 160 | 161 | struct rlimit { 162 | rlim_t rlim_cur; 163 | rlim_t rlim_max; 164 | }; 165 | 166 | int getrlimit(int resource, struct rlimit *rlim); 167 | int setrlimit(int resource, const struct rlimit *rlim); 168 | 169 | struct timeval { 170 | time_t tv_sec; 171 | suseconds_t tv_usec; 172 | }; 173 | 174 | int open(const char *pathname, int flags); 175 | int creat(const char *pathname, mode_t mode); 176 | int close(int fd); 177 | int pipe(int pipefd[2]); 178 | char *ptsname(int fd); 179 | 180 | int chdir(const char *path); 181 | int fchdir(int fd); 182 | 183 | ssize_t write(int fd, const void *buf, size_t count); 184 | ssize_t read(int fd, void *buf, size_t count); 185 | 186 | int uname(void *buf); 187 | char *ctermid(char *s); 188 | 189 | struct utsname { 190 | char sysname[256]; 191 | char nodename[256]; 192 | char release[256]; 193 | char version[256]; 194 | char machine[256]; 195 | }; 196 | 197 | #ifdef __LINUX__ 198 | int sysinfo(struct sysinfo *info); 199 | 200 | struct sysinfo { 201 | long uptime; 202 | unsigned long loads[3]; 203 | unsigned long totalram; 204 | unsigned long freeram; 205 | unsigned long sharedram; 206 | unsigned long bufferram; 207 | unsigned long totalswap; 208 | unsigned long freeswap; 209 | unsigned short procs; 210 | unsigned long totalhigh; 211 | unsigned long freehigh; 212 | unsigned int mem_unit; 213 | char _f[20-2*sizeof(long)-sizeof(int)]; 214 | }; 215 | 216 | struct passwd { 217 | char *pw_name; 218 | char *pw_passwd; 219 | uid_t pw_uid; 220 | gid_t pw_gid; 221 | char *pw_gecos; 222 | char *pw_dir; 223 | char *pw_shell; 224 | }; 225 | #endif 226 | 227 | #ifdef __MAC__ 228 | struct passwd { 229 | char *pw_name; 230 | char *pw_passwd; 231 | uid_t pw_uid; 232 | gid_t pw_gid; 233 | time_t pw_change; 234 | char *pw_class; 235 | char *pw_gecos; 236 | char *pw_dir; 237 | char *pw_shell; 238 | time_t pw_expire; 239 | int pw_fields; 240 | }; 241 | #endif 242 | """; 243 | 244 | void _ensure() { 245 | if (LibraryManager._libc == null) { 246 | LibraryManager.init(); 247 | } 248 | } 249 | 250 | /// Library Manager 251 | /// This also loads the C Library 252 | class LibraryManager { 253 | static BinaryTypeHelper typeHelper; 254 | 255 | static BinaryTypes get types => libc.types; 256 | 257 | static DynamicLibrary _libc; 258 | static DynamicLibrary get libc { 259 | if (_libc == null) { 260 | init(); 261 | } 262 | return _libc; 263 | } 264 | 265 | static bool loaded = false; 266 | 267 | static void init() { 268 | loaded = true; 269 | String name; 270 | 271 | if (Platform.isAndroid || Platform.isLinux) { 272 | name = "libc.so.6"; 273 | } else if (Platform.isMacOS) { 274 | name = "libSystem.dylib"; 275 | } else { 276 | throw new Exception("Your platform is not supported."); 277 | } 278 | 279 | _libc = DynamicLibrary.load(name, types: new BinaryTypes()); 280 | typeHelper = new BinaryTypeHelper(_libc.types); 281 | var env = {}; 282 | 283 | if (Platform.isMacOS) { 284 | env["__MAC__"] = "true"; 285 | } 286 | 287 | if (Platform.isAndroid || Platform.isLinux) { 288 | env["__LINUX__"] = "true"; 289 | } 290 | 291 | if (SysInfo.kernelArchitecture.startsWith("arm")) { 292 | env["__ARM__"] = "true"; 293 | } 294 | 295 | var os = SysInfo.operatingSystemName.toLowerCase(); 296 | 297 | if (os.contains("ubuntu") || os.contains("debian")) { 298 | env["__DEBIAN__"] = "true"; 299 | } 300 | 301 | _env = env; 302 | 303 | typeHelper.addHeader("libc.h", HEADER); 304 | typeHelper.declare("libc.h", environment: env); 305 | libc.link(["libc.h"]); 306 | } 307 | 308 | static void loadHeader(String name, String content, [Map env]) { 309 | _ensure(); 310 | Map e = new Map.from(_env); 311 | if (env != null) { 312 | e.addAll(env); 313 | } 314 | 315 | typeHelper.addHeader(name, content); 316 | typeHelper.declare(name, environment: e); 317 | } 318 | 319 | static Map _env; 320 | 321 | static BinaryUnmarshaller unmarshaller = (() { 322 | return new BinaryUnmarshaller(); 323 | })(); 324 | 325 | static Map _libs = {}; 326 | 327 | static void register(String name, DynamicLibrary lib) { 328 | _ensure(); 329 | _libs[name] = lib; 330 | } 331 | 332 | static dynamic invoke(String name, [List args = const [], List vartypes]) { 333 | _ensure(); 334 | var lib = libc; 335 | if (name.contains("::")) { 336 | var libname = name.substring(0, name.indexOf("::")); 337 | name = name.substring(libname.length + 2); 338 | if (_libs.containsKey(libname)) { 339 | lib = _libs[libname]; 340 | } else { 341 | throw new LibraryException("Library not found: ${libname}"); 342 | } 343 | } 344 | return lib.invokeEx(name, args, vartypes); 345 | } 346 | 347 | static dynamic unmarshall(BinaryData data, Type type) { 348 | _ensure(); 349 | return unmarshaller.unmarshall(data, type); 350 | } 351 | 352 | static dynamic getVariable(String name, type) { 353 | _ensure(); 354 | type = getBinaryType(type); 355 | return type.extern(libc.symbol(name)); 356 | } 357 | } 358 | 359 | /// Documents Compatibility of APIs 360 | class Compatibility { 361 | final String message; 362 | 363 | const Compatibility(this.message); 364 | } 365 | 366 | BinaryType getBinaryType(type) { 367 | if (type is String) { 368 | type = LibraryManager.types[type]; 369 | } 370 | 371 | if (type is! BinaryType) { 372 | throw new ArgumentError.value(type, "type", "should be either a String or a BinaryType"); 373 | } 374 | 375 | return type; 376 | } 377 | 378 | /// Allocate an object specified by [type] using the initial value specified by [value]. 379 | BinaryData alloc(type, [value]) { 380 | _ensure(); 381 | BinaryType bt = getBinaryType(type); 382 | return bt.alloc(value); 383 | } 384 | 385 | /// Gets a binary array type for the type 386 | /// specified by [type] with a size specified by [size]. 387 | BinaryType getArrayType(type, int size) { 388 | _ensure(); 389 | BinaryType bt = getBinaryType(type); 390 | return bt.array(size); 391 | } 392 | 393 | /// Allocate an array of objects specified by [type] 394 | /// with the size specified by [size] 395 | /// using the initial value specified by [value]. 396 | BinaryData allocArray(type, int size, [value]) { 397 | _ensure(); 398 | var bt = getArrayType(type, size); 399 | return bt.alloc(value); 400 | } 401 | 402 | /// Gets the binary type for [name]. 403 | BinaryType getType(String name) { 404 | _ensure(); 405 | return LibraryManager.types[name]; 406 | } 407 | 408 | /// Turns the object specified by [input] into a native string. 409 | BinaryData toNativeString(input) { 410 | _ensure(); 411 | String str; 412 | 413 | if (input == null) { 414 | return toNativeString("").type.nullPtr; 415 | } else { 416 | str = input.toString(); 417 | } 418 | 419 | return LibraryManager.typeHelper.allocString(str); 420 | } 421 | 422 | class SystemCallException { 423 | final int code; 424 | 425 | SystemCallException(this.code); 426 | 427 | @override 428 | String toString() => "System Call Failed! ${getErrorInfo(code)}"; 429 | } 430 | 431 | class LibraryException { 432 | final String message; 433 | 434 | LibraryException(this.message); 435 | 436 | @override 437 | String toString() => message; 438 | } 439 | 440 | /// Gets the error number 441 | int getErrorNumber() { 442 | _ensure(); 443 | return getVariable("errno", "int").value; 444 | } 445 | 446 | String getErrorInfo([int errno]) { 447 | if (errno == null) { 448 | errno = getErrorNumber(); 449 | } 450 | 451 | return readNativeString(invoke("strerror", [errno])); 452 | } 453 | 454 | int checkSysCallResult(int result) { 455 | if (result == -1) { 456 | throw new SystemCallException(getErrorNumber()); 457 | } 458 | return result; 459 | } 460 | 461 | /// Gets the variable specified by [name] with the type specified by [type]. 462 | BinaryData getVariable(String name, type) { 463 | return LibraryManager.getVariable(name, type); 464 | } 465 | 466 | /// Read a string from [input]. 467 | String readNativeString(input) { 468 | _ensure(); 469 | if (input is String) { 470 | return input; 471 | } 472 | 473 | if (input is! BinaryData) { 474 | throw new ArgumentError.value(input, "input", "should be an instance of BinaryData"); 475 | } 476 | 477 | if (input.isNullPtr) { 478 | return null; 479 | } 480 | 481 | return LibraryManager.typeHelper.readString(input); 482 | } 483 | 484 | /// Invoke the system calls specified by [name] with the arguments specified by [args]. 485 | dynamic invoke(String name, [List args = const [], List vartypes]) { 486 | _ensure(); 487 | return LibraryManager.invoke(name, args, vartypes); 488 | } 489 | 490 | /// Allocate an empty string. 491 | BinaryData allocEmptyString() => toNativeString(""); 492 | 493 | /// Gets the length of the string specified by [input]. 494 | int strlen(String input) { 495 | return invoke("strlen", [toNativeString(input)]); 496 | } 497 | -------------------------------------------------------------------------------- /lib/src/system.dart: -------------------------------------------------------------------------------- 1 | part of syscall; 2 | 3 | /// Open System Log 4 | void openSystemLog(String ident, int logopt, int facility) { 5 | var lident = toNativeString(ident); 6 | invoke("openlog", [lident, logopt, facility]); 7 | } 8 | 9 | /// Close System Log 10 | void closeSystemLog() { 11 | invoke("closelog"); 12 | } 13 | 14 | /// Write a message to the system log. 15 | void writeToSystemLog(int priority, String message) { 16 | invoke("syslog", [priority, toNativeString(message)]); 17 | } 18 | 19 | /// Get System Information 20 | @Compatibility("Linux Only") 21 | LinuxSysInfo getSysInfo() { 22 | var instance = alloc("sysinfo"); 23 | invoke("getsysinfo", [instance]); 24 | return instance; 25 | } 26 | 27 | /// Time Value 28 | class TimeVal { 29 | @NativeName("tv_sec") 30 | int seconds; 31 | 32 | @NativeName("tv_usec") 33 | int milliseconds; 34 | } 35 | 36 | /// Linux System Information 37 | @Compatibility("Linux Only") 38 | class LinuxSysInfo { 39 | /// Uptime in Seconds 40 | int uptime; 41 | 42 | /// Load Times 43 | /// This is a list of 3 doubles. 44 | List loads; 45 | 46 | /// Total Memory 47 | @NativeName("totalram") 48 | int totalMemory; 49 | 50 | /// Free Memory 51 | @NativeName("freeram") 52 | int freeMemory; 53 | 54 | /// Shared Memory 55 | @NativeName("sharedram") 56 | int sharedMemory; 57 | 58 | /// Buffer RAM 59 | @NativeName("bufferram") 60 | int bufferMemory; 61 | 62 | /// Total Swap 63 | @NativeName("totalswap") 64 | int totalSwap; 65 | 66 | /// Free Swap 67 | @NativeName("freeswap") 68 | int freeSwap; 69 | 70 | /// Number of Processes 71 | @NativeName("procs") 72 | int processCount; 73 | 74 | /// Total High Memory 75 | @NativeName("totalhigh") 76 | int totalHighMemory; 77 | 78 | /// Free High Memory 79 | @NativeName("freehigh") 80 | int freeHighMemory; 81 | 82 | /// Memory Unit 83 | @NativeName("mem_unit") 84 | int memoryUnit; 85 | } 86 | 87 | /// Represents a User 88 | class User { 89 | /// Username 90 | String name; 91 | 92 | /// Full User Name 93 | String fullName; 94 | 95 | /// Home Directory 96 | String home; 97 | 98 | /// Shell 99 | String shell; 100 | 101 | /// Password 102 | String password; 103 | 104 | /// User ID 105 | int uid; 106 | 107 | /// Group ID 108 | int gid; 109 | 110 | /// Get Group IDs 111 | List get groups => getUserGroups(name); 112 | } 113 | 114 | /// uname information 115 | class KernelInfo { 116 | /// Operating System Name 117 | @NativeName("sysname") 118 | String operatingSystemName; 119 | 120 | /// Network Name (Probably Hostname) 121 | @NativeName("nodename") 122 | String networkName; 123 | 124 | /// Kernel Release 125 | @NativeName("release") 126 | String release; 127 | 128 | /// Kernel Version 129 | @NativeName("version") 130 | String version; 131 | 132 | /// Machine 133 | @NativeName("machine") 134 | String machine; 135 | } 136 | 137 | /// Gets the System Uptime 138 | Duration getSystemUptime() { 139 | int seconds; 140 | 141 | if (Platform.isMacOS) { 142 | var sse = new DateTime.now().millisecondsSinceEpoch ~/ 1000; 143 | seconds = sse - getSysCtlValue("kern.boottime", type: "struct timeval", dtype: TimeVal).tv_sec; 144 | } else { 145 | seconds = getSysInfo().uptime; 146 | } 147 | 148 | return new Duration(seconds: seconds); 149 | } 150 | 151 | /// Get load averages for the system. 152 | /// [count] specifies how many averages to get. 153 | /// [count] defaults to 3, and should always be between 0 and 3 154 | List getLoadAverages([int count = 3]) { 155 | var averages = allocArray("double", 3); 156 | checkSysCallResult(invoke("getloadavg", [averages, count])); 157 | return averages.value.toList(); 158 | } 159 | 160 | /// Gets the Current User ID (uid) 161 | int getUserId() { 162 | return invoke("getuid"); 163 | } 164 | 165 | /// Gets the Effective User ID (euid) 166 | int getEffectiveUserId() { 167 | return invoke("geteuid"); 168 | } 169 | 170 | /// Sets the Current User ID (uid) 171 | void setUserId(int id) { 172 | checkSysCallResult(invoke("setuid", [id])); 173 | } 174 | 175 | /// Sets the Effective User ID (euid) 176 | void setEffectiveUserId(int id) { 177 | checkSysCallResult(invoke("seteuid", [id])); 178 | } 179 | 180 | /// Gets the Current Group ID (gid) 181 | int getGroupId() { 182 | return invoke("getgid"); 183 | } 184 | 185 | /// Sets the Current Group ID (gid) 186 | void setGroupId(int id) { 187 | checkSysCallResult(invoke("setgid", [id])); 188 | } 189 | 190 | /// Gets the Effective Group ID (egid) 191 | int getEffectiveGroupId() { 192 | return invoke("getegid"); 193 | } 194 | 195 | /// Sets the Effective Group ID (egid) 196 | void setEffectiveGroupId(int id) { 197 | checkSysCallResult(invoke("setegid", [id])); 198 | } 199 | 200 | /// Gets the password file entry for [user]. 201 | Map getPasswordFileEntry(String user) { 202 | var u = toNativeString(user); 203 | var result = invoke("getpwnam", [u]); 204 | 205 | if (result.isNullPtr) { 206 | throw new ArgumentError.value(user, "user", "Unknown User"); 207 | } 208 | 209 | var it = result.value; 210 | 211 | var map = { 212 | "name": readNativeString(it["pw_name"]), 213 | "password": readNativeString(it["pw_passwd"]), 214 | "uid": it["pw_uid"], 215 | "gid": it["pw_gid"], 216 | "full name": it["pw_gecos"].isNullPtr ? null : readNativeString(it["pw_gecos"]), 217 | "home": readNativeString(it["pw_dir"]), 218 | "shell": readNativeString(it["pw_shell"]) 219 | }; 220 | 221 | if (Platform.isMacOS) { 222 | map["class"] = readNativeString(it["pw_class"]); 223 | map["password changed"] = it["pw_change"]; 224 | map["expiration"] = it["pw_expire"]; 225 | } 226 | 227 | return map; 228 | } 229 | 230 | /// Get a User 231 | User getUser(String name) { 232 | var info = getPasswordFileEntry(name); 233 | var user = new User(); 234 | user.name = info["name"]; 235 | user.password = info["password"]; 236 | user.uid = info["uid"]; 237 | user.fullName = info["full name"]; 238 | user.home = info["home"]; 239 | user.shell = info["shell"]; 240 | return user; 241 | } 242 | 243 | /// Gets the Current Username 244 | String getCurrentUsername() => 245 | readNativeString(invoke("getlogin")); 246 | 247 | /// Gets the Current User 248 | User getCurrentUser() => getUser(getCurrentUsername()); 249 | 250 | /// Get a list of users on the system. 251 | /// If [showHidden] is true, then users with a _ in front of their name will be shown. 252 | List getUsernames({bool showHidden: false}) { 253 | if (Platform.isMacOS) { 254 | String out = Process.runSync("dscacheutil", ["q", "user"]).stdout.toString().trim(); 255 | return out 256 | .split("\n") 257 | .where((it) => it.startsWith("name: ") && (showHidden ? true : !it.startsWith("name: _"))) 258 | .map((it) => it.substring(6)) 259 | .toList(); 260 | } else { 261 | var passwd = new File("/etc/passwd").readAsLinesSync().where((it) => !it.startsWith("#")).toList(); 262 | var users = []; 263 | for (var line in passwd) { 264 | if (!showHidden && line.startsWith("_")) { 265 | continue; 266 | } 267 | users.add(line.split(":").first); 268 | } 269 | return users; 270 | } 271 | } 272 | 273 | /// Gets the group ids for all the groups that the user specified by [name] is in. 274 | List getUserGroups(String name) { 275 | var n = toNativeString(name); 276 | var gid = getPasswordFileEntry(name)["gid"]; 277 | var lastn = 10; 278 | var count = alloc("int", lastn); 279 | var results = allocArray("gid_t", lastn); 280 | var times = 0; 281 | 282 | while (true) { 283 | var c = invoke("getgrouplist", [n, gid, results, count]); 284 | 285 | if (c == -1 || lastn != count.value) { 286 | if (times >= 8) { 287 | throw new Exception("Failed to get groups."); 288 | } else { 289 | count.value = count.value * 2; 290 | results = allocArray("gid_t", count.value); 291 | lastn = count.value; 292 | } 293 | } else { 294 | break; 295 | } 296 | 297 | times++; 298 | } 299 | 300 | return results.value; 301 | } 302 | 303 | /// Gets information for the group specified by [gid]. 304 | Group getGroupInfo(int gid) { 305 | return LibraryManager.unmarshall(invoke("getgrgid", [gid]), Group); 306 | } 307 | 308 | /// Represents a Group 309 | class Group { 310 | /// Group Name 311 | @NativeName("gr_name") 312 | String name; 313 | 314 | /// Group Password 315 | @NativeName("gr_passwd") 316 | String password; 317 | 318 | /// Group ID 319 | @NativeName("gr_gid") 320 | int gid; 321 | 322 | /// Group Members 323 | @NativeName("gr_mem") 324 | List members; 325 | } 326 | 327 | /// Gets the current process id. 328 | int getProcessId() { 329 | return invoke("getpid"); 330 | } 331 | 332 | /// Gets the parent process id. 333 | int getParentProcessId() { 334 | return invoke("getppid"); 335 | } 336 | 337 | /// Gets the Process Group ID for the process specified by [pid]. 338 | /// If [pid] is not specified, then it returns the process group id for the current process. 339 | int getProcessGroupId([int pid]) { 340 | if (pid == null) { 341 | pid = getProcessId(); 342 | } 343 | 344 | return invoke("getpgid", [pid]); 345 | } 346 | 347 | /// Gets the Session ID for the specified [pid]. 348 | /// If [pid] is not specified, it defaults to the current 349 | int getSessionId([int pid]) { 350 | if (pid == null) { 351 | pid = getProcessId(); 352 | } 353 | 354 | return invoke("getsid", [pid]); 355 | } 356 | 357 | /// Gets the System Hostname 358 | String getHostname() { 359 | // TODO(kaendfinger): Currently we use a workaround with uname, since gethostname acts weird. 360 | return getKernelInfo().networkName; 361 | // var name = allocEmptyString(); 362 | // checkSysCallResult(invoke("gethostname", [name, 255])); 363 | // return readNativeString(name); 364 | } 365 | 366 | /// Sets the System Hostname 367 | void setHostname(String host) { 368 | checkSysCallResult(invoke("sethostname", [toNativeString(host), host.length])); 369 | } 370 | 371 | /// Gets the TTY Name 372 | String getTtyName([int fd = 0]) => 373 | readNativeString(invoke("ttyname", [fd])); 374 | 375 | /// Gets the PTS name for the file descriptor [fd]. 376 | String getPtsName(int fd) => 377 | readNativeString(invoke("ptsname", [fd])); 378 | 379 | /// Fork this Process 380 | /// Not Recommended, but it seems to work. 381 | int fork() { 382 | return invoke("fork"); 383 | } 384 | 385 | /// Fork this Process while Copying Memory 386 | int vfork() { 387 | return invoke("vfork"); 388 | } 389 | 390 | /// Wait for a child process to terminate. 391 | WaitResult wait() { 392 | var status = alloc("int"); 393 | var pid = invoke("wait", [status]); 394 | return new WaitResult(pid, status.value); 395 | } 396 | 397 | /// Wait for a process. 398 | WaitResult waitpid(int pid, [int options = 0]) { 399 | var status = alloc("int"); 400 | var rp = invoke("waitpid", [pid, status, options]); 401 | return new WaitResult(rp, status.value); 402 | } 403 | 404 | /// Results for [wait] and [waitpid] 405 | class WaitResult { 406 | /// PID of Process that Exited 407 | final int pid; 408 | 409 | /// Exit Status 410 | final int status; 411 | 412 | WaitResult(this.pid, this.status); 413 | } 414 | 415 | /// Kill a Process 416 | void kill(int pid, int signal) { 417 | checkSysCallResult(invoke("kill", [pid, signal])); 418 | } 419 | 420 | /// Resource Limit 421 | class ResourceLimit { 422 | static final int CPU = 0; 423 | static final int FSIZE = 1; 424 | static final int DATA = 2; 425 | static final int STACK = 3; 426 | static final int CORE = 4; 427 | static final int NPROC = Platform.isMacOS ? 7 : 6; 428 | static final int NOFILE = Platform.isMacOS ? 8 : 7; 429 | static final int MEMLOCK = Platform.isMacOS ? 6 : 8; 430 | static final int AS = Platform.isMacOS ? 5 : 9; 431 | 432 | @NativeName("rlim_cur") 433 | int current; 434 | @NativeName("rlim_max") 435 | int max; 436 | 437 | ResourceLimit([this.current, this.max]); 438 | 439 | BinaryData asNative() { 440 | var l = alloc("struct rlimit"); 441 | l["rlim_cur"] = current; 442 | l["rlim_max"] = max; 443 | return l; 444 | } 445 | } 446 | 447 | /// Gets the resource limit specified by [resource]. 448 | ResourceLimit getResourceLimit(int resource) { 449 | var l = alloc("struct rlimit"); 450 | checkSysCallResult(invoke("getrlimit", [resource, l])); 451 | return LibraryManager.unmarshall(l, ResourceLimit); 452 | } 453 | 454 | /// Sets the resource limit specified by [resource]. 455 | void setResourceLimit(int resource, ResourceLimit limit) { 456 | checkSysCallResult(invoke("setrlimit", [resource, limit])); 457 | } 458 | 459 | /// Get the System Time in Milliseconds since the Epoch 460 | int getSystemTime() { 461 | return invoke("time", [getType("time_t").nullPtr]); 462 | } 463 | 464 | /// Sets the System Time using Milliseconds since the Epoch 465 | void setSystemTime(int time) { 466 | checkSysCallResult(invoke("stime", [time])); 467 | } 468 | 469 | /// Execute the Given Command 470 | int executeSystem(String command) { 471 | return checkSysCallResult(invoke("system", [toNativeString(command)])); 472 | } 473 | 474 | int getExitCodeFromStatus(int status) { 475 | return (status >> 8) & 0x000000ff; 476 | } 477 | 478 | /// Gets the path to the controlling terminal. 479 | String getControllingTerminal() { 480 | return readNativeString(invoke("ctermid", [getType("char").nullPtr])); 481 | } 482 | 483 | /// Manipulate Device Specific Parameters 484 | void ioctl(int fd, int request, msg) { 485 | var x = alloc("int", fd); 486 | var y = alloc("int", request); 487 | if (msg is String) { 488 | msg = toNativeString(msg); 489 | } else if (msg is int) { 490 | msg = alloc("int", msg); 491 | } else if (msg is double) { 492 | msg = alloc("double", msg); 493 | } else if (msg is bool) { 494 | msg = alloc("bool", msg); 495 | } 496 | checkSysCallResult(invoke("ioctl", [x, y, msg])); 497 | } 498 | 499 | /// Get Kernel Information (uname) 500 | KernelInfo getKernelInfo() { 501 | var l = alloc("struct utsname"); 502 | checkSysCallResult(invoke("uname", [l])); 503 | return LibraryManager.unmarshall(l, KernelInfo); 504 | } 505 | 506 | int printf(String format) { 507 | var frmt = toNativeString(format); 508 | var ins = [frmt]; 509 | return checkSysCallResult(invoke("printf", ins)); 510 | } 511 | --------------------------------------------------------------------------------