mod.rs 26 KB

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