hare

[hare] The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

pty.ha (2116B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use errors;
      5 use fmt;
      6 use fs;
      7 use io;
      8 use os;
      9 use rt;
     10 
     11 // Opens an available pseudoterminal and returns the file descriptors of the
     12 // master and slave.
     13 export fn openpty() ((io::file, io::file) | fs::error) = {
     14 	let master = open_master()?;
     15 	let slave = match (get_slave(master)) {
     16 	case let e: fs::error =>
     17 		io::close(master)!;
     18 		return e;
     19 	case let s: io::file =>
     20 		yield s;
     21 	};
     22 	return (master, slave);
     23 };
     24 
     25 // Opens an available pseudoterminal master.
     26 fn open_master() (io::file | fs::error) = {
     27 	return os::open("/dev/ptmx", fs::flag::RDWR);
     28 };
     29 
     30 // Returns a file descriptor referring to the pseudoterminal slave for a
     31 // pseudoterminal master.
     32 fn get_slave(master: io::file) (io::file | fs::error) = {
     33 	// Unlock the pseudoterminal slave
     34 	match (rt::ioctl(master, rt::TIOCSPTLCK, &0)) {
     35 	case rt::errno =>
     36 		return errors::invalid;
     37 	case => void;
     38 	};
     39 
     40 	let ioctl = rt::ioctl(
     41 		master, rt::TIOCGPTPEER,
     42 		(rt::O_RDWR | rt::O_NOCTTY): u64);
     43 	match (ioctl) {
     44 	case let e: rt::errno =>
     45 		return errors::errno(e);
     46 	case let fd: int =>
     47 		return io::fdopen(fd);
     48 	};
     49 };
     50 
     51 // Returns the filename of the pseudoterminal slave.
     52 export fn ptsname(master: io::file) (str | error) = {
     53 	let pty = 0;
     54 	match (rt::ioctl(master, rt::TIOCGPTN, &pty)) {
     55 	case let e: rt::errno =>
     56 		switch (e) {
     57 		case rt::EBADF =>
     58 			return errors::invalid;
     59 		case rt::ENOTTY =>
     60 			return errors::unsupported;
     61 		case =>
     62 			abort("Unexpected error from ioctl");
     63 		};
     64 	case =>
     65 		static let buf: [9 + 20]u8 = [0...];
     66 		return fmt::bsprintf(buf[..len(buf)], "/dev/pts/{}", pty);
     67 	};
     68 };
     69 
     70 // Sets the dimensions of the underlying pseudoterminal for an [[io::file]].
     71 export fn set_winsize(pty: io::file, sz: ttysize) (void | error) = {
     72 	let wsz = rt::winsize { ws_row = sz.rows, ws_col = sz.columns, ... };
     73 	match (rt::ioctl(pty, rt::TIOCSWINSZ, &wsz)) {
     74 	case let e: rt::errno =>
     75 		switch (e) {
     76 		case rt::EBADF =>
     77 			return errors::invalid;
     78 		case rt::ENOTTY =>
     79 			return errors::unsupported;
     80 		case =>
     81 			abort("Unexpected error from ioctl");
     82 		};
     83 	case => void;
     84 	};
     85 };