mod.rs 24 KB

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