mod.rs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966
  1. //! stdio implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/stdio.h.html
  2. use alloc::borrow::{Borrow, BorrowMut};
  3. use alloc::boxed::Box;
  4. use alloc::vec::Vec;
  5. use core::fmt;
  6. use core::fmt::Write as WriteFmt;
  7. use core::ops::{Deref, DerefMut};
  8. use core::{ptr, slice, str};
  9. use va_list::VaList as va_list;
  10. use c_str::CStr;
  11. use fs::File;
  12. use header::errno::{self, STR_ERROR};
  13. use header::string::strlen;
  14. use header::{fcntl, stdlib, unistd};
  15. use io::{self, BufRead, LineWriter, Read, Write};
  16. use mutex::Mutex;
  17. use platform;
  18. use platform::types::*;
  19. use platform::{errno, WriteByte};
  20. use platform::{Pal, Sys};
  21. pub use self::constants::*;
  22. mod constants;
  23. pub use self::default::*;
  24. mod default;
  25. pub use self::getdelim::*;
  26. mod getdelim;
  27. mod ext;
  28. mod helpers;
  29. mod printf;
  30. mod scanf;
  31. enum Buffer<'a> {
  32. Borrowed(&'a mut [u8]),
  33. Owned(Vec<u8>),
  34. }
  35. impl<'a> Deref for Buffer<'a> {
  36. type Target = [u8];
  37. fn deref(&self) -> &Self::Target {
  38. match self {
  39. Buffer::Borrowed(inner) => inner,
  40. Buffer::Owned(inner) => inner.borrow(),
  41. }
  42. }
  43. }
  44. impl<'a> DerefMut for Buffer<'a> {
  45. fn deref_mut(&mut self) -> &mut Self::Target {
  46. match self {
  47. Buffer::Borrowed(inner) => inner,
  48. Buffer::Owned(inner) => inner.borrow_mut(),
  49. }
  50. }
  51. }
  52. /// This struct gets exposed to the C API.
  53. pub struct FILE {
  54. // Can't use spin crate because *_unlocked functions are things in C :(
  55. lock: Mutex<()>,
  56. file: File,
  57. // pub for stdio_ext
  58. pub(crate) flags: c_int,
  59. read_buf: Buffer<'static>,
  60. read_pos: usize,
  61. read_size: usize,
  62. unget: Option<u8>,
  63. // pub for stdio_ext
  64. pub(crate) writer: LineWriter<File>,
  65. // Optional pid for use with popen/pclose
  66. pid: Option<c_int>,
  67. }
  68. impl Read for FILE {
  69. fn read(&mut self, out: &mut [u8]) -> io::Result<usize> {
  70. if !out.is_empty() {
  71. if let Some(c) = self.unget.take() {
  72. out[0] = c;
  73. return Ok(1);
  74. }
  75. }
  76. let len = {
  77. let buf = self.fill_buf()?;
  78. let len = buf.len().min(out.len());
  79. out[..len].copy_from_slice(&buf[..len]);
  80. len
  81. };
  82. self.consume(len);
  83. Ok(len)
  84. }
  85. }
  86. impl BufRead for FILE {
  87. fn fill_buf(&mut self) -> io::Result<&[u8]> {
  88. if self.read_pos == self.read_size {
  89. self.read_size = match self.file.read(&mut self.read_buf) {
  90. Ok(0) => {
  91. self.flags |= F_EOF;
  92. 0
  93. }
  94. Ok(n) => n,
  95. Err(err) => {
  96. self.flags |= F_ERR;
  97. return Err(err);
  98. }
  99. };
  100. self.read_pos = 0;
  101. }
  102. Ok(&self.read_buf[self.read_pos..self.read_size])
  103. }
  104. fn consume(&mut self, i: usize) {
  105. self.read_pos = (self.read_pos + i).min(self.read_size);
  106. }
  107. }
  108. impl Write for FILE {
  109. fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
  110. match self.writer.write(buf) {
  111. Ok(n) => Ok(n),
  112. Err(err) => {
  113. self.flags |= F_ERR;
  114. Err(err)
  115. }
  116. }
  117. }
  118. fn flush(&mut self) -> io::Result<()> {
  119. match self.writer.flush() {
  120. Ok(()) => Ok(()),
  121. Err(err) => {
  122. self.flags |= F_ERR;
  123. Err(err)
  124. }
  125. }
  126. }
  127. }
  128. impl WriteFmt for FILE {
  129. fn write_str(&mut self, s: &str) -> fmt::Result {
  130. self.write_all(s.as_bytes())
  131. .map(|_| ())
  132. .map_err(|_| fmt::Error)
  133. }
  134. }
  135. impl WriteByte for FILE {
  136. fn write_u8(&mut self, c: u8) -> fmt::Result {
  137. self.write_all(&[c]).map(|_| ()).map_err(|_| fmt::Error)
  138. }
  139. }
  140. impl FILE {
  141. pub fn lock(&mut self) -> LockGuard {
  142. unsafe {
  143. flockfile(self);
  144. }
  145. LockGuard(self)
  146. }
  147. }
  148. pub struct LockGuard<'a>(&'a mut FILE);
  149. impl<'a> Deref for LockGuard<'a> {
  150. type Target = FILE;
  151. fn deref(&self) -> &Self::Target {
  152. &self.0
  153. }
  154. }
  155. impl<'a> DerefMut for LockGuard<'a> {
  156. fn deref_mut(&mut self) -> &mut Self::Target {
  157. self.0
  158. }
  159. }
  160. impl<'a> Drop for LockGuard<'a> {
  161. fn drop(&mut self) {
  162. unsafe {
  163. funlockfile(self.0);
  164. }
  165. }
  166. }
  167. /// Clears EOF and ERR indicators on a stream
  168. #[no_mangle]
  169. pub extern "C" fn clearerr(stream: *mut FILE) {
  170. let mut stream = unsafe { &mut *stream }.lock();
  171. stream.flags &= !(F_EOF | F_ERR);
  172. }
  173. // #[no_mangle]
  174. pub extern "C" fn ctermid(_s: *mut c_char) -> *mut c_char {
  175. unimplemented!();
  176. }
  177. // #[no_mangle]
  178. pub extern "C" fn cuserid(_s: *mut c_char) -> *mut c_char {
  179. unimplemented!();
  180. }
  181. /// Close a file
  182. /// This function does not guarentee that the file buffer will be flushed or that the file
  183. /// descriptor will be closed, so if it is important that the file be written to, use `fflush()`
  184. /// prior to using this function.
  185. #[no_mangle]
  186. pub extern "C" fn fclose(stream: *mut FILE) -> c_int {
  187. let stream = unsafe { &mut *stream };
  188. unsafe {
  189. flockfile(stream);
  190. }
  191. let mut r = stream.flush().is_err();
  192. let close = Sys::close(*stream.file) < 0;
  193. r = r || close;
  194. if stream.flags & constants::F_PERM == 0 {
  195. // Not one of stdin, stdout or stderr
  196. let mut stream = unsafe { Box::from_raw(stream) };
  197. // Reference files aren't closed on drop, so pretend to be a reference
  198. stream.file.reference = true;
  199. } else {
  200. unsafe {
  201. funlockfile(stream);
  202. }
  203. }
  204. r as c_int
  205. }
  206. /// Open a file from a file descriptor
  207. #[no_mangle]
  208. pub extern "C" fn fdopen(fildes: c_int, mode: *const c_char) -> *mut FILE {
  209. use core::ptr;
  210. if let Some(f) = unsafe { helpers::_fdopen(fildes, mode) } {
  211. f
  212. } else {
  213. ptr::null_mut()
  214. }
  215. }
  216. /// Check for EOF
  217. #[no_mangle]
  218. pub extern "C" fn feof(stream: *mut FILE) -> c_int {
  219. let stream = unsafe { &mut *stream }.lock();
  220. stream.flags & F_EOF
  221. }
  222. /// Check for ERR
  223. #[no_mangle]
  224. pub extern "C" fn ferror(stream: *mut FILE) -> c_int {
  225. let stream = unsafe { &mut *stream }.lock();
  226. stream.flags & F_ERR
  227. }
  228. /// Flush output to stream, or sync read position
  229. /// Ensure the file is unlocked before calling this function, as it will attempt to lock the file
  230. /// itself.
  231. #[no_mangle]
  232. pub extern "C" fn fflush(stream: *mut FILE) -> c_int {
  233. let mut stream = unsafe { &mut *stream }.lock();
  234. stream.flush().is_err() as c_int
  235. }
  236. /// Get a single char from a stream
  237. #[no_mangle]
  238. pub extern "C" fn fgetc(stream: *mut FILE) -> c_int {
  239. let mut stream = unsafe { &mut *stream }.lock();
  240. getc_unlocked(&mut *stream)
  241. }
  242. /// Get the position of the stream and store it in pos
  243. #[no_mangle]
  244. pub extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int {
  245. let off = ftello(stream);
  246. if off < 0 {
  247. return -1;
  248. }
  249. unsafe {
  250. *pos = off;
  251. }
  252. 0
  253. }
  254. /// Get a string from the stream
  255. #[no_mangle]
  256. pub extern "C" fn fgets(original: *mut c_char, max: c_int, stream: *mut FILE) -> *mut c_char {
  257. let mut stream = unsafe { &mut *stream }.lock();
  258. let mut out = original;
  259. let max = max as usize;
  260. let mut left = max.saturating_sub(1); // Make space for the terminating NUL-byte
  261. let mut wrote = false;
  262. if left >= 1 {
  263. if let Some(c) = stream.unget.take() {
  264. unsafe {
  265. *out = c as c_char;
  266. out = out.offset(1);
  267. }
  268. left -= 1;
  269. }
  270. }
  271. loop {
  272. if left == 0 {
  273. break;
  274. }
  275. // TODO: When NLL is a thing, this block can be flattened out
  276. let (read, exit) = {
  277. let mut buf = match stream.fill_buf() {
  278. Ok(buf) => buf,
  279. Err(_) => return ptr::null_mut(),
  280. };
  281. if buf.is_empty() {
  282. break;
  283. }
  284. wrote = true;
  285. let len = buf.len().min(left);
  286. let newline = buf[..len].iter().position(|&c| c == b'\n');
  287. let len = newline.map(|i| i + 1).unwrap_or(len);
  288. unsafe {
  289. ptr::copy_nonoverlapping(buf.as_ptr(), out as *mut u8, len);
  290. }
  291. (len, newline.is_some())
  292. };
  293. stream.consume(read);
  294. out = unsafe { out.offset(read as isize) };
  295. left -= read;
  296. if exit {
  297. break;
  298. }
  299. }
  300. if max >= 1 {
  301. // Write the NUL byte
  302. unsafe {
  303. *out = 0;
  304. }
  305. }
  306. if wrote {
  307. original
  308. } else {
  309. ptr::null_mut()
  310. }
  311. }
  312. /// Get the underlying file descriptor
  313. #[no_mangle]
  314. pub extern "C" fn fileno(stream: *mut FILE) -> c_int {
  315. let stream = unsafe { &mut *stream }.lock();
  316. *stream.file
  317. }
  318. /// Lock the file
  319. /// Do not call any functions other than those with the `_unlocked` postfix while the file is
  320. /// locked
  321. #[no_mangle]
  322. pub unsafe extern "C" fn flockfile(file: *mut FILE) {
  323. (*file).lock.manual_lock();
  324. }
  325. /// Open the file in mode `mode`
  326. #[no_mangle]
  327. pub extern "C" fn fopen(filename: *const c_char, mode: *const c_char) -> *mut FILE {
  328. use core::ptr;
  329. let initial_mode = unsafe { *mode };
  330. if initial_mode != b'r' as i8 && initial_mode != b'w' as i8 && initial_mode != b'a' as i8 {
  331. unsafe { platform::errno = errno::EINVAL };
  332. return ptr::null_mut();
  333. }
  334. let flags = unsafe { helpers::parse_mode_flags(mode) };
  335. let new_mode = if flags & fcntl::O_CREAT == fcntl::O_CREAT {
  336. 0o666
  337. } else {
  338. 0
  339. };
  340. let fd = fcntl::sys_open(filename, flags, new_mode);
  341. if fd < 0 {
  342. return ptr::null_mut();
  343. }
  344. if flags & fcntl::O_CLOEXEC > 0 {
  345. fcntl::sys_fcntl(fd, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
  346. }
  347. if let Some(f) = unsafe { helpers::_fdopen(fd, mode) } {
  348. f
  349. } else {
  350. Sys::close(fd);
  351. ptr::null_mut()
  352. }
  353. }
  354. /// Insert a character into the stream
  355. #[no_mangle]
  356. pub extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int {
  357. let mut stream = unsafe { &mut *stream }.lock();
  358. putc_unlocked(c, &mut *stream)
  359. }
  360. /// Insert a string into a stream
  361. #[no_mangle]
  362. pub extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int {
  363. let len = unsafe { strlen(s) };
  364. (fwrite(s as *const c_void, 1, len, stream) == len) as c_int - 1
  365. }
  366. /// Read `nitems` of size `size` into `ptr` from `stream`
  367. #[no_mangle]
  368. pub extern "C" fn fread(
  369. ptr: *mut c_void,
  370. size: size_t,
  371. count: size_t,
  372. stream: *mut FILE,
  373. ) -> size_t {
  374. let mut stream = unsafe { &mut *stream }.lock();
  375. let buf = unsafe { slice::from_raw_parts_mut(ptr as *mut u8, size as usize * count as usize) };
  376. let mut read = 0;
  377. while read < buf.len() {
  378. match stream.read(&mut buf[read..]) {
  379. Ok(0) | Err(_) => break,
  380. Ok(n) => read += n,
  381. }
  382. }
  383. (read / size as usize) as size_t
  384. }
  385. #[no_mangle]
  386. pub extern "C" fn freopen(
  387. filename: *const c_char,
  388. mode: *const c_char,
  389. stream: &mut FILE,
  390. ) -> *mut FILE {
  391. let mut flags = unsafe { helpers::parse_mode_flags(mode) };
  392. unsafe {
  393. flockfile(stream);
  394. }
  395. let _ = stream.flush();
  396. if filename.is_null() {
  397. // Reopen stream in new mode
  398. if flags & fcntl::O_CLOEXEC > 0 {
  399. fcntl::sys_fcntl(*stream.file, fcntl::F_SETFD, fcntl::FD_CLOEXEC);
  400. }
  401. flags &= !(fcntl::O_CREAT | fcntl::O_EXCL | fcntl::O_CLOEXEC);
  402. if fcntl::sys_fcntl(*stream.file, fcntl::F_SETFL, flags) < 0 {
  403. unsafe {
  404. funlockfile(stream);
  405. }
  406. fclose(stream);
  407. return ptr::null_mut();
  408. }
  409. } else {
  410. let new = fopen(filename, mode);
  411. if new.is_null() {
  412. unsafe {
  413. funlockfile(stream);
  414. }
  415. fclose(stream);
  416. return ptr::null_mut();
  417. }
  418. let new = unsafe { &mut *new }; // Should be safe, new is not null
  419. if *new.file == *stream.file {
  420. new.file.fd = -1;
  421. } else if Sys::dup2(*new.file, *stream.file) < 0
  422. || fcntl::sys_fcntl(*stream.file, fcntl::F_SETFL, flags & fcntl::O_CLOEXEC) < 0
  423. {
  424. unsafe {
  425. funlockfile(stream);
  426. }
  427. fclose(new);
  428. fclose(stream);
  429. return ptr::null_mut();
  430. }
  431. stream.flags = (stream.flags & constants::F_PERM) | new.flags;
  432. fclose(new);
  433. }
  434. unsafe {
  435. funlockfile(stream);
  436. }
  437. stream
  438. }
  439. /// Seek to an offset `offset` from `whence`
  440. #[no_mangle]
  441. pub extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int {
  442. fseeko(stream, offset as off_t, whence)
  443. }
  444. /// Seek to an offset `offset` from `whence`
  445. #[no_mangle]
  446. pub extern "C" fn fseeko(stream: *mut FILE, mut off: off_t, whence: c_int) -> c_int {
  447. let mut stream = unsafe { &mut *stream }.lock();
  448. if whence == SEEK_CUR {
  449. // Since it's a buffered writer, our actual cursor isn't where the user
  450. // thinks
  451. off -= (stream.read_size - stream.read_pos) as off_t;
  452. }
  453. let err = Sys::lseek(*stream.file, off, whence);
  454. if err < 0 {
  455. return err as c_int;
  456. }
  457. stream.flags &= !(F_EOF | F_ERR);
  458. stream.read_pos = 0;
  459. stream.read_size = 0;
  460. stream.unget = None;
  461. 0
  462. }
  463. /// Seek to a position `pos` in the file from the beginning of the file
  464. #[no_mangle]
  465. pub unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const fpos_t) -> c_int {
  466. fseek(stream, *pos, SEEK_SET)
  467. }
  468. /// Get the current position of the cursor in the file
  469. #[no_mangle]
  470. pub extern "C" fn ftell(stream: *mut FILE) -> c_long {
  471. ftello(stream) as c_long
  472. }
  473. /// Get the current position of the cursor in the file
  474. #[no_mangle]
  475. pub extern "C" fn ftello(stream: *mut FILE) -> off_t {
  476. let stream = unsafe { &mut *stream }.lock();
  477. let pos = Sys::lseek(*stream.file, 0, SEEK_CUR);
  478. if pos < 0 {
  479. return -1;
  480. }
  481. pos - (stream.read_size - stream.read_pos) as off_t
  482. }
  483. /// Try to lock the file. Returns 0 for success, 1 for failure
  484. #[no_mangle]
  485. pub unsafe extern "C" fn ftrylockfile(file: *mut FILE) -> c_int {
  486. if (*file).lock.manual_try_lock().is_ok() {
  487. 0
  488. } else {
  489. 1
  490. }
  491. }
  492. /// Unlock the file
  493. #[no_mangle]
  494. pub unsafe extern "C" fn funlockfile(file: *mut FILE) {
  495. (*file).lock.manual_unlock();
  496. }
  497. /// Write `nitems` of size `size` from `ptr` to `stream`
  498. #[no_mangle]
  499. pub extern "C" fn fwrite(
  500. ptr: *const c_void,
  501. size: size_t,
  502. count: size_t,
  503. stream: *mut FILE,
  504. ) -> size_t {
  505. let mut stream = unsafe { &mut *stream }.lock();
  506. let buf = unsafe { slice::from_raw_parts_mut(ptr as *mut u8, size as usize * count as usize) };
  507. let mut written = 0;
  508. while written < buf.len() {
  509. match stream.write(&mut buf[written..]) {
  510. Ok(0) | Err(_) => break,
  511. Ok(n) => written += n,
  512. }
  513. }
  514. (written / size as usize) as size_t
  515. }
  516. /// Get a single char from a stream
  517. #[no_mangle]
  518. pub extern "C" fn getc(stream: *mut FILE) -> c_int {
  519. let mut stream = unsafe { &mut *stream }.lock();
  520. getc_unlocked(&mut *stream)
  521. }
  522. /// Get a single char from `stdin`
  523. #[no_mangle]
  524. pub extern "C" fn getchar() -> c_int {
  525. fgetc(unsafe { &mut *stdin })
  526. }
  527. /// Get a char from a stream without locking the stream
  528. #[no_mangle]
  529. pub extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int {
  530. let mut buf = [0];
  531. match unsafe { &mut *stream }.read(&mut buf) {
  532. Ok(0) | Err(_) => EOF,
  533. Ok(_) => buf[0] as c_int,
  534. }
  535. }
  536. /// Get a char from `stdin` without locking `stdin`
  537. #[no_mangle]
  538. pub extern "C" fn getchar_unlocked() -> c_int {
  539. getc_unlocked(unsafe { &mut *stdin })
  540. }
  541. /// Get a string from `stdin`
  542. #[no_mangle]
  543. pub extern "C" fn gets(s: *mut c_char) -> *mut c_char {
  544. fgets(s, c_int::max_value(), unsafe { &mut *stdin })
  545. }
  546. /// Get an integer from `stream`
  547. #[no_mangle]
  548. pub extern "C" fn getw(stream: *mut FILE) -> c_int {
  549. use core::mem;
  550. let mut ret: c_int = 0;
  551. if fread(
  552. &mut ret as *mut _ as *mut c_void,
  553. mem::size_of_val(&ret),
  554. 1,
  555. stream,
  556. ) > 0
  557. {
  558. ret
  559. } else {
  560. -1
  561. }
  562. }
  563. #[no_mangle]
  564. pub extern "C" fn pclose(stream: *mut FILE) -> c_int {
  565. let pid = {
  566. let mut stream = unsafe { &mut *stream }.lock();
  567. if let Some(pid) = stream.pid.take() {
  568. pid
  569. } else {
  570. unsafe { errno = errno::ECHILD };
  571. return -1;
  572. }
  573. };
  574. fclose(stream);
  575. let mut wstatus = 0;
  576. if Sys::waitpid(pid, &mut wstatus, 0) < 0 {
  577. return -1;
  578. }
  579. wstatus
  580. }
  581. #[no_mangle]
  582. pub unsafe extern "C" fn perror(s: *const c_char) {
  583. let s_cstr = CStr::from_ptr(s);
  584. let s_str = str::from_utf8_unchecked(s_cstr.to_bytes());
  585. let mut w = platform::FileWriter(2);
  586. if errno >= 0 && errno < STR_ERROR.len() as c_int {
  587. w.write_fmt(format_args!("{}: {}\n", s_str, STR_ERROR[errno as usize]))
  588. .unwrap();
  589. } else {
  590. w.write_fmt(format_args!("{}: Unknown error {}\n", s_str, errno))
  591. .unwrap();
  592. }
  593. }
  594. #[no_mangle]
  595. pub unsafe extern "C" fn popen(command: *const c_char, mode: *const c_char) -> *mut FILE {
  596. //TODO: share code with system
  597. let mode = CStr::from_ptr(mode);
  598. let mut cloexec = false;
  599. let mut write_opt = None;
  600. for b in mode.to_bytes().iter() {
  601. match b {
  602. b'e' => cloexec = true,
  603. b'r' if write_opt.is_none() => write_opt = Some(false),
  604. b'w' if write_opt.is_none() => write_opt = Some(true),
  605. _ => {
  606. errno = errno::EINVAL;
  607. return ptr::null_mut();
  608. }
  609. }
  610. }
  611. let write = match write_opt {
  612. Some(some) => some,
  613. None => {
  614. errno = errno::EINVAL;
  615. return ptr::null_mut();
  616. }
  617. };
  618. let mut pipes = [-1, -1];
  619. if unistd::pipe(pipes.as_mut_ptr()) != 0 {
  620. return ptr::null_mut();
  621. }
  622. let child_pid = unistd::fork();
  623. if child_pid == 0 {
  624. let command_nonnull = if command.is_null() {
  625. "exit 0\0".as_ptr()
  626. } else {
  627. command as *const u8
  628. };
  629. let shell = "/bin/sh\0".as_ptr();
  630. let args = [
  631. "sh\0".as_ptr(),
  632. "-c\0".as_ptr(),
  633. command_nonnull,
  634. ptr::null(),
  635. ];
  636. // Setup up stdin or stdout
  637. //TODO: dup errors are ignored, should they be?
  638. {
  639. if write {
  640. unistd::dup2(0, pipes[0]);
  641. } else {
  642. unistd::dup2(1, pipes[1]);
  643. }
  644. unistd::close(pipes[0]);
  645. unistd::close(pipes[1]);
  646. }
  647. unistd::execv(shell as *const c_char, args.as_ptr() as *const *mut c_char);
  648. stdlib::exit(127);
  649. unreachable!();
  650. } else if child_pid > 0 {
  651. let (fd, fd_mode) = if write {
  652. unistd::close(pipes[0]);
  653. (pipes[1], if cloexec { c_str!("we") } else { c_str!("w") })
  654. } else {
  655. unistd::close(pipes[1]);
  656. (pipes[0], if cloexec { c_str!("re") } else { c_str!("r") })
  657. };
  658. if let Some(f) = helpers::_fdopen(fd, fd_mode.as_ptr()) {
  659. (*f).pid = Some(child_pid);
  660. f
  661. } else {
  662. ptr::null_mut()
  663. }
  664. } else {
  665. ptr::null_mut()
  666. }
  667. }
  668. /// Put a character `c` into `stream`
  669. #[no_mangle]
  670. pub extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int {
  671. let mut stream = unsafe { &mut *stream }.lock();
  672. putc_unlocked(c, &mut *stream)
  673. }
  674. /// Put a character `c` into `stdout`
  675. #[no_mangle]
  676. pub extern "C" fn putchar(c: c_int) -> c_int {
  677. fputc(c, unsafe { &mut *stdout })
  678. }
  679. /// Put a character `c` into `stream` without locking `stream`
  680. #[no_mangle]
  681. pub extern "C" fn putc_unlocked(c: c_int, stream: *mut FILE) -> c_int {
  682. match unsafe { &mut *stream }.write(&[c as u8]) {
  683. Ok(0) | Err(_) => EOF,
  684. Ok(_) => c,
  685. }
  686. }
  687. /// Put a character `c` into `stdout` without locking `stdout`
  688. #[no_mangle]
  689. pub extern "C" fn putchar_unlocked(c: c_int) -> c_int {
  690. putc_unlocked(c, unsafe { stdout })
  691. }
  692. /// Put a string `s` into `stdout`
  693. #[no_mangle]
  694. pub extern "C" fn puts(s: *const c_char) -> c_int {
  695. let ret = (fputs(s, unsafe { stdout }) > 0) || (putchar_unlocked(b'\n' as c_int) > 0);
  696. if ret {
  697. 0
  698. } else {
  699. -1
  700. }
  701. }
  702. /// Put an integer `w` into `stream`
  703. #[no_mangle]
  704. pub extern "C" fn putw(w: c_int, stream: *mut FILE) -> c_int {
  705. use core::mem;
  706. fwrite(&w as *const c_int as _, mem::size_of_val(&w), 1, stream) as i32 - 1
  707. }
  708. /// Delete file or directory `path`
  709. #[no_mangle]
  710. pub extern "C" fn remove(path: *const c_char) -> c_int {
  711. let path = unsafe { CStr::from_ptr(path) };
  712. let r = Sys::unlink(path);
  713. if r == -errno::EISDIR {
  714. Sys::rmdir(path)
  715. } else {
  716. r
  717. }
  718. }
  719. #[no_mangle]
  720. pub extern "C" fn rename(oldpath: *const c_char, newpath: *const c_char) -> c_int {
  721. let oldpath = unsafe { CStr::from_ptr(oldpath) };
  722. let newpath = unsafe { CStr::from_ptr(newpath) };
  723. Sys::rename(oldpath, newpath)
  724. }
  725. /// Rewind `stream` back to the beginning of it
  726. #[no_mangle]
  727. pub extern "C" fn rewind(stream: *mut FILE) {
  728. fseeko(stream, 0, SEEK_SET);
  729. }
  730. /// Reset `stream` to use buffer `buf`. Buffer must be `BUFSIZ` in length
  731. #[no_mangle]
  732. pub extern "C" fn setbuf(stream: *mut FILE, buf: *mut c_char) {
  733. setvbuf(
  734. stream,
  735. buf,
  736. if buf.is_null() { _IONBF } else { _IOFBF },
  737. BUFSIZ as usize,
  738. );
  739. }
  740. /// Reset `stream` to use buffer `buf` of size `size`
  741. /// If this isn't the meaning of unsafe, idk what is
  742. #[no_mangle]
  743. pub extern "C" fn setvbuf(
  744. stream: *mut FILE,
  745. buf: *mut c_char,
  746. mode: c_int,
  747. mut size: size_t,
  748. ) -> c_int {
  749. let mut stream = unsafe { &mut *stream }.lock();
  750. // Set a buffer of size `size` if no buffer is given
  751. stream.read_buf = if buf.is_null() || size == 0 {
  752. if size == 0 {
  753. size = BUFSIZ as usize;
  754. }
  755. // TODO: Make it unbuffered if _IONBF
  756. // if mode == _IONBF {
  757. // } else {
  758. Buffer::Owned(vec![0; size as usize])
  759. // }
  760. } else {
  761. unsafe { Buffer::Borrowed(slice::from_raw_parts_mut(buf as *mut u8, size)) }
  762. };
  763. stream.flags |= F_SVB;
  764. 0
  765. }
  766. // #[no_mangle]
  767. pub extern "C" fn tempnam(_dir: *const c_char, _pfx: *const c_char) -> *mut c_char {
  768. unimplemented!();
  769. }
  770. #[no_mangle]
  771. pub extern "C" fn tmpfile() -> *mut FILE {
  772. let mut file_name = *b"/tmp/tmpfileXXXXXX";
  773. let file_name = file_name.as_mut_ptr() as *mut c_char;
  774. let fd = stdlib::mkstemp(file_name);
  775. if fd < 0 {
  776. return ptr::null_mut();
  777. }
  778. let fp = fdopen(fd, b"w+".as_ptr() as *const i8);
  779. {
  780. let file_name = unsafe { CStr::from_ptr(file_name) };
  781. Sys::unlink(file_name);
  782. }
  783. if fp == ptr::null_mut() {
  784. Sys::close(fd);
  785. }
  786. fp
  787. }
  788. // #[no_mangle]
  789. pub extern "C" fn tmpnam(_s: *mut c_char) -> *mut c_char {
  790. unimplemented!();
  791. }
  792. /// Push character `c` back onto `stream` so it'll be read next
  793. #[no_mangle]
  794. pub extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int {
  795. let mut stream = unsafe { &mut *stream }.lock();
  796. if stream.unget.is_some() {
  797. unsafe {
  798. platform::errno = errno::EIO;
  799. return EOF;
  800. }
  801. }
  802. stream.unget = Some(c as u8);
  803. c
  804. }
  805. #[no_mangle]
  806. pub unsafe extern "C" fn vfprintf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int {
  807. let mut file = (*file).lock();
  808. printf::printf(&mut *file, format, ap)
  809. }
  810. #[no_mangle]
  811. pub unsafe extern "C" fn vprintf(format: *const c_char, ap: va_list) -> c_int {
  812. vfprintf(&mut *stdout, format, ap)
  813. }
  814. #[no_mangle]
  815. pub unsafe extern "C" fn vsnprintf(
  816. s: *mut c_char,
  817. n: size_t,
  818. format: *const c_char,
  819. ap: va_list,
  820. ) -> c_int {
  821. printf::printf(
  822. &mut platform::StringWriter(s as *mut u8, n as usize),
  823. format,
  824. ap,
  825. )
  826. }
  827. #[no_mangle]
  828. pub unsafe extern "C" fn vsprintf(s: *mut c_char, format: *const c_char, ap: va_list) -> c_int {
  829. printf::printf(&mut platform::UnsafeStringWriter(s as *mut u8), format, ap)
  830. }
  831. #[no_mangle]
  832. pub unsafe extern "C" fn vfscanf(file: *mut FILE, format: *const c_char, ap: va_list) -> c_int {
  833. let mut file = (*file).lock();
  834. scanf::scanf(&mut *file, format, ap)
  835. }
  836. #[no_mangle]
  837. pub unsafe extern "C" fn vscanf(format: *const c_char, ap: va_list) -> c_int {
  838. vfscanf(&mut *stdin, format, ap)
  839. }
  840. #[no_mangle]
  841. pub unsafe extern "C" fn vsscanf(s: *const c_char, format: *const c_char, ap: va_list) -> c_int {
  842. scanf::scanf(
  843. &mut platform::UnsafeStringReader(s as *const u8),
  844. format,
  845. ap,
  846. )
  847. }