os_linux.odin 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. // #import "fmt.odin";
  2. #import "strings.odin";
  3. Handle :: i32;
  4. FileTime :: u64;
  5. Errno :: i32;
  6. // INVALID_HANDLE: Handle : -1;
  7. O_RDONLY :: 0x00000;
  8. O_WRONLY :: 0x00001;
  9. O_RDWR :: 0x00002;
  10. O_CREAT :: 0x00040;
  11. O_EXCL :: 0x00080;
  12. O_NOCTTY :: 0x00100;
  13. O_TRUNC :: 0x00200;
  14. O_NONBLOCK :: 0x00800;
  15. O_APPEND :: 0x00400;
  16. O_SYNC :: 0x01000;
  17. O_ASYNC :: 0x02000;
  18. O_CLOEXEC :: 0x80000;
  19. SEEK_SET :: 0;
  20. SEEK_CUR :: 1;
  21. SEEK_END :: 2;
  22. SEEK_DATA :: 3;
  23. SEEK_HOLE :: 4;
  24. SEEK_MAX :: SEEK_HOLE;
  25. // NOTE(zangent): These are OS specific!
  26. // Do not mix these up!
  27. RTLD_LAZY :: 0x001;
  28. RTLD_NOW :: 0x002;
  29. RTLD_BINDING_MASK :: 0x3;
  30. RTLD_GLOBAL :: 0x100;
  31. // "Argv" arguments converted to Odin strings
  32. immutable args := _alloc_command_line_arguments();
  33. _FileTime :: struct #ordered {
  34. seconds: i64,
  35. nanoseconds: i32,
  36. reserved: i32,
  37. }
  38. // Translated from
  39. // https://android.googlesource.com/platform/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.7-4.6/+/jb-dev/sysroot/usr/include/bits/stat.h
  40. // Validity is not guaranteed.
  41. Stat :: struct #ordered {
  42. device_id: u64, // ID of device containing file
  43. serial: u64, // File serial number
  44. nlink: u32, // Number of hard links
  45. mode: u32, // Mode of the file
  46. uid: u32, // User ID of the file's owner
  47. gid: u32, // Group ID of the file's group
  48. _padding: i32, // 32 bits of padding
  49. rdev: u64, // Device ID, if device
  50. size: i64, // Size of the file, in bytes
  51. block_size: i64, // Optimal bllocksize for I/O
  52. blocks: i64, // Number of 512-byte blocks allocated
  53. last_access: _FileTime, // Time of last access
  54. modified: _FileTime, // Time of last modification
  55. status_change: _FileTime, // Time of last status change
  56. _reserve1,
  57. _reserve2,
  58. _reserve3: i64,
  59. serial_numbe: u64, // File serial number...? Maybe.
  60. _reserve4: i64,
  61. };
  62. // File type
  63. S_IFMT :: 0170000; // Type of file mask
  64. S_IFIFO :: 0010000; // Named pipe (fifo)
  65. S_IFCHR :: 0020000; // Character special
  66. S_IFDIR :: 0040000; // Directory
  67. S_IFBLK :: 0060000; // Block special
  68. S_IFREG :: 0100000; // Regular
  69. S_IFLNK :: 0120000; // Symbolic link
  70. S_IFSOCK :: 0140000; // Socket
  71. // File mode
  72. // Read, write, execute/search by owner
  73. S_IRWXU :: 0000700; // RWX mask for owner
  74. S_IRUSR :: 0000400; // R for owner
  75. S_IWUSR :: 0000200; // W for owner
  76. S_IXUSR :: 0000100; // X for owner
  77. // Read, write, execute/search by group
  78. S_IRWXG :: 0000070; // RWX mask for group
  79. S_IRGRP :: 0000040; // R for group
  80. S_IWGRP :: 0000020; // W for group
  81. S_IXGRP :: 0000010; // X for group
  82. // Read, write, execute/search by others
  83. S_IRWXO :: 0000007; // RWX mask for other
  84. S_IROTH :: 0000004; // R for other
  85. S_IWOTH :: 0000002; // W for other
  86. S_IXOTH :: 0000001; // X for other
  87. S_ISUID :: 0004000; // Set user id on execution
  88. S_ISGID :: 0002000; // Set group id on execution
  89. S_ISVTX :: 0001000; // Directory restrcted delete
  90. S_ISLNK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFLNK; }
  91. S_ISREG :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFREG; }
  92. S_ISDIR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFDIR; }
  93. S_ISCHR :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFCHR; }
  94. S_ISBLK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFBLK; }
  95. S_ISFIFO :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFIFO; }
  96. S_ISSOCK :: proc(m: u32) -> bool #inline {return ((m) & S_IFMT) == S_IFSOCK;}
  97. R_OK :: 4; // Test for read permission
  98. W_OK :: 2; // Test for write permission
  99. X_OK :: 1; // Test for execute permission
  100. F_OK :: 0; // Test for file existance
  101. #foreign_system_library dl "dl";
  102. #foreign_system_library libc "c";
  103. _unix_open :: proc(path: ^u8, mode: int) -> Handle #foreign libc "open";
  104. _unix_close :: proc(fd: Handle) -> i32 #foreign libc "close";
  105. _unix_read :: proc(fd: Handle, buf: rawptr, size: int) -> int #foreign libc "read";
  106. _unix_write :: proc(fd: Handle, buf: rawptr, size: int) -> int #foreign libc "write";
  107. _unix_seek :: proc(fd: Handle, offset: i64, whence: i32) -> i64 #foreign libc "lseek64";
  108. _unix_gettid :: proc() -> u64 #foreign libc "gettid";
  109. _unix_stat :: proc(path: ^u8, stat: ^Stat) -> i32 #foreign libc "stat";
  110. _unix_access :: proc(path: ^u8, mask: int) -> i32 #foreign libc "access";
  111. _unix_malloc :: proc(size: int) -> rawptr #foreign libc "malloc";
  112. _unix_free :: proc(ptr: rawptr) #foreign libc "free";
  113. _unix_realloc :: proc(ptr: rawptr, size: int) -> rawptr #foreign libc "realloc";
  114. _unix_getenv :: proc(^u8) -> ^u8 #foreign libc "getenv";
  115. _unix_exit :: proc(status: int) #foreign libc "exit";
  116. _unix_dlopen :: proc(filename: ^u8, flags: int) -> rawptr #foreign dl "dlopen";
  117. _unix_dlsym :: proc(handle: rawptr, symbol: ^u8) -> (proc() #cc_c) #foreign dl "dlsym";
  118. _unix_dlclose :: proc(handle: rawptr) -> int #foreign dl "dlclose";
  119. _unix_dlerror :: proc() -> ^u8 #foreign dl "dlerror";
  120. // TODO(zangent): Change this to just `open` when Bill fixes overloading.
  121. open_simple :: proc(path: string, mode: int) -> (Handle, Errno) {
  122. cstr := strings.new_c_string(path);
  123. handle := _unix_open(cstr, mode);
  124. free(cstr);
  125. if(handle == -1) {
  126. return 0, 1;
  127. }
  128. return handle, 0;
  129. }
  130. // NOTE(zangent): This is here for compatability reasons. Should this be here?
  131. open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
  132. return open_simple(path, mode);
  133. }
  134. close :: proc(fd: Handle) {
  135. _unix_close(fd);
  136. }
  137. read :: proc(fd: Handle, data: []u8) -> (int, Errno) {
  138. sz := _unix_read(fd, &data[0], len(data));
  139. return sz, 0;
  140. }
  141. write :: proc(fd: Handle, data: []u8) -> (int, Errno) {
  142. sz := _unix_write(fd, &data[0], len(data));
  143. return sz, 0;
  144. }
  145. seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
  146. res := _unix_seek(fd, offset, i32(whence));
  147. return res, 0;
  148. }
  149. file_size :: proc(fd: Handle) -> (i64, Errno) {
  150. prev, _ := seek(fd, 0, SEEK_CUR);
  151. size, err := seek(fd, 0, SEEK_END);
  152. seek(fd, prev, SEEK_SET);
  153. return size, err;
  154. }
  155. // NOTE(bill): Uses startup to initialize it
  156. stdin: Handle = 0;
  157. stdout: Handle = 1;
  158. stderr: Handle = 2;
  159. /* TODO(zangent): Implement these!
  160. last_write_time :: proc(fd: Handle) -> FileTime {}
  161. last_write_time_by_name :: proc(name: string) -> FileTime {}
  162. */
  163. stat :: proc(path: string) -> (Stat, int) #inline {
  164. s: Stat;
  165. cstr := strings.new_c_string(path);
  166. defer free(cstr);
  167. ret_int := _unix_stat(cstr, &s);
  168. return s, int(ret_int);
  169. }
  170. access :: proc(path: string, mask: int) -> bool #inline {
  171. cstr := strings.new_c_string(path);
  172. defer free(cstr);
  173. return _unix_access(cstr, mask) == 0;
  174. }
  175. // read_entire_file :: proc(name: string) -> ([]u8, bool) {
  176. // fd: Handle;
  177. // err: Errno;
  178. // size: i64;
  179. // fd, err = open_simple(name, O_RDONLY);
  180. // if(err != 0) {
  181. // fmt.println("Failed to open file.");
  182. // return nil, false;
  183. // }
  184. // defer close(fd);
  185. // // We have a file
  186. // size, err = seek(fd, 0, SEEK_END);
  187. // if(err != 0) {
  188. // fmt.println("Failed to seek to end of file.");
  189. // return nil, false;
  190. // }
  191. // _, err = seek(fd, 0, SEEK_SET);
  192. // if(err != 0) {
  193. // fmt.println("Failed to seek to beginning of file.");
  194. // return nil, false;
  195. // }
  196. // // We have a file size!
  197. // data := make([]u8, size+1);
  198. // if data == nil {
  199. // fmt.println("Failed to allocate file buffer.");
  200. // return nil, false;
  201. // }
  202. // read(fd, data);
  203. // data[size] = 0;
  204. // return data, true;
  205. // }
  206. heap_alloc :: proc(size: int) -> rawptr {
  207. assert(size > 0);
  208. return _unix_malloc(size);
  209. }
  210. heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
  211. return _unix_realloc(ptr, new_size);
  212. }
  213. heap_free :: proc(ptr: rawptr) {
  214. _unix_free(ptr);
  215. }
  216. getenv :: proc(name: string) -> (string, bool) {
  217. path_str := strings.new_c_string(name);
  218. cstr: ^u8 = _unix_getenv(path_str);
  219. free(path_str);
  220. if(cstr == nil) {
  221. return "", false;
  222. }
  223. return strings.to_odin_string(cstr), true;
  224. }
  225. exit :: proc(code: int) {
  226. _unix_exit(code);
  227. }
  228. current_thread_id :: proc() -> int {
  229. // return int(_unix_gettid());
  230. return 0;
  231. }
  232. dlopen :: proc(filename: string, flags: int) -> rawptr #inline {
  233. cstr := strings.new_c_string(filename);
  234. handle := _unix_dlopen(cstr, flags);
  235. free(cstr);
  236. return handle;
  237. }
  238. dlsym :: proc(handle: rawptr, symbol: string) -> (proc() #cc_c) #inline {
  239. assert(handle != nil);
  240. cstr := strings.new_c_string(symbol);
  241. proc_handle := _unix_dlsym(handle, cstr);
  242. free(cstr);
  243. return proc_handle;
  244. }
  245. dlclose :: proc(handle: rawptr) -> bool #inline {
  246. assert(handle != nil);
  247. return _unix_dlclose(handle) == 0;
  248. }
  249. dlerror :: proc() -> string {
  250. return strings.to_odin_string(_unix_dlerror());
  251. }
  252. _alloc_command_line_arguments :: proc() -> []string {
  253. // TODO(bill):
  254. return nil;
  255. }