├── .gitignore ├── .travis.yml ├── posix.ipkg └── src ├── System └── Posix │ ├── Directory.idr │ ├── Signal.idr │ ├── Syslog.idr │ ├── Test │ ├── Signal.idr │ └── Syslog.idr │ └── Time.idr ├── create_dir_wrappers.c ├── dirent_accessors.c ├── getcwd_wrapper.c ├── signal_wrappers.c ├── stat_wrappers.c ├── syslog_wrappers.c └── time_wrappers.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.ibc 2 | *~ 3 | *# 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | os: osx 2 | cache: 3 | directories: 4 | - $HOME/Library/Caches/Homebrew 5 | install: 6 | - brew install idris 7 | script: 8 | - idris --testpkg posix.ipkg 9 | -------------------------------------------------------------------------------- /posix.ipkg: -------------------------------------------------------------------------------- 1 | package posix 2 | 3 | sourcedir = src 4 | modules = System.Posix.Directory 5 | , System.Posix.Time 6 | , System.Posix.Signal 7 | , System.Posix.Syslog 8 | , System.Posix.Test.Signal 9 | , System.Posix.Test.Syslog 10 | objs = dirent_accessors.c 11 | , stat_wrappers.c 12 | , time_wrappers.c 13 | , signal_wrappers.c 14 | , syslog_wrappers.c 15 | , getcwd_wrapper.c 16 | , create_dir_wrappers.c 17 | 18 | tests = System.Posix.Test.Syslog.test_syslog 19 | , System.Posix.Test.Signal.test_install_handler -- keep this test last 20 | -------------------------------------------------------------------------------- /src/System/Posix/Directory.idr: -------------------------------------------------------------------------------- 1 | module System.Posix.Directory 2 | 3 | %include C "dirent_accessors.c" 4 | %include C "stat_wrappers.c" 5 | %include C "getcwd_wrapper.c" 6 | %include C "create_dir_wrappers.c" 7 | 8 | opendir : String -> IO Ptr 9 | opendir s = foreign FFI_C "opendir" (String -> IO Ptr) s 10 | 11 | closedir : Ptr -> IO () 12 | closedir p = foreign FFI_C "closedir" (Ptr -> IO Unit) p 13 | 14 | readdir : Ptr -> IO Ptr 15 | readdir p = foreign FFI_C "readdir" (Ptr -> IO Ptr) p 16 | 17 | dirent_d_name : Ptr -> IO String 18 | dirent_d_name p = foreign FFI_C "idris_posix_dirent_d_name" (Ptr -> IO String) p 19 | 20 | getDirectoryContents : String -> IO (List String) 21 | getDirectoryContents s = do 22 | d <- opendir s 23 | c <- f d [] 24 | closedir d 25 | pure (reverse c) 26 | where f : Ptr -> List String -> IO (List String) 27 | f d xs = do 28 | c <- readdir d 29 | n <- nullPtr c 30 | if n 31 | then pure xs 32 | else do 33 | n <- dirent_d_name c 34 | f d (n :: xs) 35 | 36 | export 37 | doesFileExist : String -> IO Bool 38 | doesFileExist s = map (/= 0) (foreign FFI_C "idris_posix_is_file" (String -> IO Int) s) 39 | 40 | export 41 | doesDirectoryExist : String -> IO Bool 42 | doesDirectoryExist s = map (/= 0) (foreign FFI_C "idris_posix_is_directory" (String -> IO Int) s) 43 | 44 | ||| Calls `getcwd` to get the current directory 45 | export 46 | getCurrentDirectory : IO String 47 | getCurrentDirectory = foreign FFI_C "idris_getcwd" (IO String) 48 | 49 | ||| Create a new directory at this path 50 | ||| NOTE that this currently does not perform error checking! 51 | export 52 | createDirectory : String -> IO () 53 | createDirectory str = foreign FFI_C "idris_create_dir" (String -> IO Int) str *> pure () 54 | -------------------------------------------------------------------------------- /src/System/Posix/Signal.idr: -------------------------------------------------------------------------------- 1 | module System.Posix.Signal 2 | 3 | %include C "signal_wrappers.c" 4 | 5 | ||| Type of signal handlers 6 | ||| 7 | ||| The actual implementation should be of the form unsafePerformIO $ do ... 8 | ||| if it needs to do any IO actions (as always for Idris functions used as C callbacks) 9 | public export 10 | Signal_handler : Type 11 | Signal_handler = (sig_num : Int) -> () 12 | 13 | install_handler : Int -> Ptr -> IO Int 14 | install_handler signum handler = foreign FFI_C "install_handler" (Int -> Ptr -> IO Int) signum handler 15 | 16 | ||| Install a new signal handler for @sig_num 17 | ||| 18 | ||| @sig_num - the signal to be handled 19 | ||| @handler - the wrapper for the Idris handler function (define as foreign FFI_C "%wrapper" ((CfnPtr Signal_handler) -> IO Ptr) (MkCFnPtr name-of-idris-routine) 20 | ||| Returns -1 on error and 0 on success 21 | export 22 | install_signal_handler : (sig_num : Int) -> (handler: IO Ptr) -> IO Int 23 | install_signal_handler sig_num handler = do 24 | wr <- handler 25 | install_handler sig_num wr 26 | 27 | export 28 | SIGHUP : Int 29 | SIGHUP = 1 30 | 31 | export 32 | SIGINT : Int 33 | SIGINT = 2 34 | 35 | export 36 | SIGQUIT : Int 37 | SIGQUIT = 3 38 | 39 | export 40 | SIGILL : Int 41 | SIGILL = 4 42 | 43 | export 44 | SIGTRAP : Int 45 | SIGTRAP = 5 46 | 47 | export 48 | SIGABORT : Int 49 | SIGABORT = 6 50 | 51 | export 52 | SIGIOT : Int 53 | SIGIOT = 6 54 | 55 | export 56 | SIGBUS : Int 57 | SIGBUS = 7 58 | 59 | export 60 | SIGFPE : Int 61 | SIGFPE = 8 62 | 63 | export 64 | SIGKILL : Int 65 | SIGKILL = 9 66 | 67 | export 68 | SIGUSR1 : Int 69 | SIGUSR1 = 10 70 | 71 | export 72 | SIGSEGV : Int 73 | SIGSEGV = 11 74 | 75 | export 76 | SIGUSR2 : Int 77 | SIGUSR2 = 12 78 | 79 | export 80 | SIGPIPE : Int 81 | SIGPIPE = 13 82 | 83 | export 84 | SIGALRM : Int 85 | SIGALRM = 14 86 | 87 | export 88 | SIGTERM : Int 89 | SIGTERM = 15 90 | 91 | export 92 | SIGSTKFLT : Int 93 | SIGSTKFLT = 16 94 | 95 | export 96 | SIGCHLD : Int 97 | SIGCHLD = 17 98 | 99 | export 100 | SIGCLD : Int 101 | SIGCLD = 17 102 | 103 | export 104 | SIGCONT : Int 105 | SIGCONT = 18 106 | 107 | export 108 | SIGSTOP : Int 109 | SIGSTOP = 19 110 | 111 | export 112 | SIGTSTP : Int 113 | SIGTSTP = 20 114 | 115 | export 116 | SIGTTIN : Int 117 | SIGTTIN = 21 118 | 119 | export 120 | SIGTTOU : Int 121 | SIGTTOU = 22 122 | 123 | export 124 | SIGURG : Int 125 | SIGURG = 23 126 | 127 | export 128 | SIGXCPU : Int 129 | SIGXCPU = 24 130 | 131 | export 132 | SIGXFSZ : Int 133 | SIGXFSZ = 25 134 | 135 | export 136 | SIGVTALRM : Int 137 | SIGVTALRM = 26 138 | 139 | export 140 | SIGPROF : Int 141 | SIGPROF = 27 142 | 143 | export 144 | SIGWINCH : Int 145 | SIGWINCH = 28 146 | 147 | export 148 | SIGPOLL : Int 149 | SIGPOLL = 29 150 | 151 | export 152 | SIGIO : Int 153 | SIGIO = 29 154 | 155 | export 156 | SIGPWR : Int 157 | SIGPWR = 30 158 | 159 | export 160 | SIGSYS : Int 161 | SIGSYS = 31 162 | -------------------------------------------------------------------------------- /src/System/Posix/Syslog.idr: -------------------------------------------------------------------------------- 1 | module System.Posix.Syslog 2 | 3 | %include C "syslog_wrappers.c" 4 | 5 | %access export 6 | 7 | ||| Close the descriptor used to write to the system logger 8 | close_log : IO () 9 | close_log = foreign FFI_C "closelog" (IO ()) 10 | 11 | ||| Open system logger, prepending @ident to every message subsequently issued by syslog 12 | ||| 13 | ||| @ident - message prefix 14 | ||| @option - bitwise OR of options 15 | ||| @facility - type of program/messages that are being logged (default value if not specified in calls to log) 16 | open_log : (ident : String) -> (option : Int) -> (facility : Int) -> IO () 17 | open_log ident option facility = foreign FFI_C "openlog" (String -> Int -> Int -> IO ()) ident option facility 18 | 19 | ||| Write a message to the system logger 20 | ||| 21 | ||| @priority - bitwise OR of facility and level 22 | ||| @message - message to log. %m within the string gets replaced by the error message string interpretation of errno 23 | log : (priority : Int) -> (message : String) -> IO () 24 | log priority message = foreign FFI_C "syslog" (Int -> String -> IO ()) priority message 25 | -- Options follow 26 | 27 | ||| Include Process ID with each message. 28 | LOG_PID : Int 29 | LOG_PID = 1 30 | 31 | ||| Write directly to system console if there is an error while sending to system logger. 32 | LOG_CONS : Int 33 | LOG_CONS = 2 34 | 35 | ||| Open the connection immediately (normally, the connection is opened when the first message is logged). 36 | LOG_NDELAY : Int 37 | LOG_NDELAY = 8 38 | 39 | ||| Default - converse of LOG_NDELAY 40 | LOG_ODELAY : Int 41 | LOG_ODELAY = 4 42 | 43 | ||| Don't wait for child processes that may have been created while logging the message. (The GNU C library does not create a child process, so this option has no effect on Linux.) 44 | LOG_NOWAIT : Int 45 | LOG_NOWAIT = 16 46 | 47 | ||| (Not in POSIX.1-2001 or POSIX.1-2008.) Print to stderr as well. 48 | LOG_PERROR : Int 49 | LOG_PERROR = 32 50 | 51 | -- Facilities follow 52 | 53 | ||| security/authorization messages 54 | LOG_AUTH : Int 55 | LOG_AUTH = 32 56 | 57 | ||| security/authorization messages (private) 58 | LOG_AUTHPRIV : Int 59 | LOG_AUTHPRIV = 80 60 | 61 | ||| clock daemon (cron and at) 62 | LOG_CRON : Int 63 | LOG_CRON = 72 64 | 65 | ||| system daemons without separate facility value 66 | LOG_DAEMON : Int 67 | LOG_DAEMON = 24 68 | 69 | ||| ftp daemon 70 | LOG_FTP : Int 71 | LOG_FTP = 88 72 | 73 | ||| kernel messages (these can't be generated from user processes) 74 | LOG_KERN : Int 75 | LOG_KERN = 0 76 | 77 | ||| reserved for local use 78 | LOG_LOCAL0 : Int 79 | LOG_LOCAL0 = 128 80 | 81 | ||| reserved for local use 82 | LOG_LOCAL1 : Int 83 | LOG_LOCAL1 = 136 84 | 85 | ||| reserved for local use 86 | LOG_LOCAL2 : Int 87 | LOG_LOCAL2 = 144 88 | 89 | ||| reserved for local use 90 | LOG_LOCAL3 : Int 91 | LOG_LOCAL3 = 152 92 | 93 | ||| reserved for local use 94 | LOG_LOCAL4 : Int 95 | LOG_LOCAL4 = 160 96 | 97 | ||| reserved for local use 98 | LOG_LOCAL5 : Int 99 | LOG_LOCAL5 = 168 100 | 101 | ||| reserved for local use 102 | LOG_LOCAL6 : Int 103 | LOG_LOCAL6 = 176 104 | 105 | ||| reserved for local use 106 | LOG_LOCAL7 : Int 107 | LOG_LOCAL7 = 184 108 | 109 | ||| line printer subsystem 110 | LOG_LPR : Int 111 | LOG_LPR = 48 112 | 113 | ||| mail subsystem 114 | LOG_MAIL : Int 115 | LOG_MAIL = 16 116 | 117 | ||| USENET news subsystem 118 | LOG_NEWS : Int 119 | LOG_NEWS = 56 120 | 121 | ||| messages generated internally by syslogd(8) 122 | LOG_SYSLOG : Int 123 | LOG_SYSLOG = 40 124 | 125 | ||| generic user-level messages (default) 126 | LOG_USER : Int 127 | LOG_USER = 8 128 | 129 | ||| UUCP subsystem 130 | LOG_UUCP : Int 131 | LOG_UUCP = 64 132 | 133 | -- Levels follow 134 | 135 | ||| system is unusable 136 | LOG_EMERG : Int 137 | LOG_EMERG = 0 138 | 139 | ||| action must be taken immediately 140 | LOG_ALERT : Int 141 | LOG_ALERT = 1 142 | 143 | ||| critical conditions 144 | LOG_CRIT : Int 145 | LOG_CRIT = 2 146 | 147 | ||| error conditions 148 | LOG_ERR : Int 149 | LOG_ERR = 3 150 | 151 | ||| warning conditions 152 | LOG_WARNING : Int 153 | LOG_WARNING = 4 154 | 155 | ||| normal, but significant, condition 156 | LOG_NOTICE : Int 157 | LOG_NOTICE = 5 158 | 159 | ||| informational message 160 | LOG_INFO : Int 161 | LOG_INFO = 6 162 | 163 | ||| debug-level message 164 | LOG_DEBUG : Int 165 | LOG_DEBUG = 7 166 | 167 | -------------------------------------------------------------------------------- /src/System/Posix/Test/Signal.idr: -------------------------------------------------------------------------------- 1 | ||| Tests for System.Posix.Signal 2 | module System.Posix.Test.Signal 3 | 4 | import System.Posix.Signal 5 | import System 6 | 7 | my_handler : Signal_handler 8 | my_handler sig_num = unsafePerformIO $ do 9 | putStrLn $ "Signal handler running after receiving signal number " ++ (show sig_num) 10 | 11 | my_handler_wrapper : IO Ptr 12 | my_handler_wrapper = foreign FFI_C "%wrapper" ((CFnPtr Signal_handler) -> IO Ptr) 13 | (MkCFnPtr my_handler) 14 | 15 | export 16 | test_install_handler : IO () 17 | test_install_handler = do 18 | rc <- install_signal_handler SIGINT my_handler_wrapper 19 | putStrLn "Now press Ctrl-C to interrupt" 20 | usleep 1000000 21 | putStrLn "Test completed. Did you see a message indicating signal 2 was handled?" 22 | 23 | -------------------------------------------------------------------------------- /src/System/Posix/Test/Syslog.idr: -------------------------------------------------------------------------------- 1 | ||| Tests for System.Posix.Syslog 2 | module System.Posix.Test.Syslog 3 | 4 | import System.Posix.Syslog 5 | 6 | export 7 | test_syslog : IO () 8 | test_syslog = do 9 | open_log "Idris test" (LOG_PID + LOG_CONS + LOG_PERROR) LOG_USER 10 | log LOG_INFO "This message should appear in syslog as well as on your console. Errno is currently %m" 11 | close_log 12 | 13 | -------------------------------------------------------------------------------- /src/System/Posix/Time.idr: -------------------------------------------------------------------------------- 1 | module System.Posix.Time 2 | 3 | %include C "time_wrappers.c" 4 | 5 | Time : Type 6 | Time = Bits64 7 | 8 | time : IO Time 9 | time = foreign FFI_C "idris_posix_time" (IO Time) 10 | 11 | strftime : String -> Time -> IO String 12 | strftime s = foreign FFI_C "idris_posix_strftime" (String -> Time -> IO String) s 13 | -------------------------------------------------------------------------------- /src/create_dir_wrappers.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int idris_create_dir(const char* filename) { 4 | // For now we simply assign all the permissions 5 | // More fine grained control may be subject of future work 6 | return mkdir(filename, S_IRWXO | S_IRWXG | S_IRWXU); 7 | } 8 | -------------------------------------------------------------------------------- /src/dirent_accessors.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | inline char *idris_posix_dirent_d_name(struct dirent* d) { 4 | return d->d_name; 5 | } 6 | -------------------------------------------------------------------------------- /src/getcwd_wrapper.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | 4 | // Used to avoid recomputing the buffer size for the `getcwd` call 5 | long int _idris_getcwd_pmax = 0; 6 | 7 | char *idris_getcwd() { 8 | if (_idris_getcwd_pmax == 0) { 9 | _idris_getcwd_pmax = pathconf("/", _PC_PATH_MAX); 10 | } 11 | // Passing NULL here is part of the extended POSIX interface. 12 | // It means `getcwd` allocates the buffer itself. 13 | // Should it transpire that too few platforms support this 14 | // we may have to allocate the buffer ourselves. 15 | return getcwd(NULL, _idris_getcwd_pmax); 16 | } 17 | -------------------------------------------------------------------------------- /src/signal_wrappers.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | inline int install_handler (int signum, void (*handler)(int)) 4 | { 5 | int rc; 6 | struct sigaction *act; 7 | act = calloc (1, sizeof (struct sigaction)); 8 | if (act == NULL) 9 | return -1; 10 | act->sa_handler = handler; 11 | rc = sigaction (signum, act, NULL); 12 | free (act); 13 | return rc; 14 | } 15 | -------------------------------------------------------------------------------- /src/stat_wrappers.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | inline int idris_posix_stat_file_type(char *filename) { 4 | struct stat buffer; 5 | stat(filename, &buffer); 6 | return buffer.st_mode & S_IFMT; 7 | } 8 | 9 | inline int idris_posix_is_directory(char *filename) { 10 | return idris_posix_stat_file_type(filename) == S_IFDIR; 11 | } 12 | 13 | inline int idris_posix_is_file(char *filename) { 14 | return idris_posix_stat_file_type(filename) == S_IFREG; 15 | } 16 | -------------------------------------------------------------------------------- /src/syslog_wrappers.c: -------------------------------------------------------------------------------- 1 | #include 2 | -------------------------------------------------------------------------------- /src/time_wrappers.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define IDRIS_POSIX_STRFTIME_LENGTH 256 5 | 6 | inline time_t idris_posix_time() { 7 | time_t timer; 8 | time(&timer); 9 | return timer; 10 | } 11 | 12 | inline char *idris_posix_strftime(char *format, time_t timer) { 13 | char *buffer = malloc(sizeof(char) * IDRIS_POSIX_STRFTIME_LENGTH); 14 | struct tm *tp = localtime(&timer); 15 | strftime(buffer, IDRIS_POSIX_STRFTIME_LENGTH - 2, format, tp); 16 | return buffer; 17 | } 18 | --------------------------------------------------------------------------------