hare

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

pty.ha (2287B)


      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 use types::c;
     11 
     12 // Opens an available pseudoterminal and returns the file descriptors of the
     13 // master and slave.
     14 export fn openpty() ((io::file, io::file) | fs::error) = {
     15 	let master = open_master()?;
     16 	let slave = match (get_slave(master)) {
     17 	case let e: fs::error =>
     18 		io::close(master)!;
     19 		return e;
     20 	case let s: io::file =>
     21 		yield s;
     22 	};
     23 	return (master, slave);
     24 };
     25 
     26 // Opens an available pseudoterminal master.
     27 fn open_master() (io::file | fs::error) = {
     28 	match (rt::posix_openpt(rt::O_RDWR | rt::O_NOCTTY)) {
     29 	case let e: rt::errno =>
     30 		return errors::errno(e);
     31 	case let i: int =>
     32 		return io::fdopen(i);
     33 	};
     34 };
     35 
     36 // Returns a file descriptor referring to the pseudoterminal slave for a
     37 // pseudoterminal master.
     38 fn get_slave(master: io::file) (io::file | fs::error) =
     39 	os::open(ptsname(master)?, fs::flag::RDWR);
     40 
     41 // Returns the filename of the pseudoterminal slave.
     42 export fn ptsname(master: io::file) (str | error) = {
     43 	// Ensure that the file descriptor refers to a master
     44 	match (rt::ioctl(master, rt::TIOCPTMASTER, null)) {
     45 	case let e: rt::errno =>
     46 		if (e == rt::EBADF) return errors::invalid
     47 		else return errors::unsupported;
     48 	case => void;
     49 	};
     50 
     51 	let name: [rt::PATH_MAX]u8 = [0...];
     52 	let fiodgname_arg = (len(name), &name);
     53 	match (rt::ioctl(master, rt::FIODGNAME, &fiodgname_arg)) {
     54 	case let e: rt::errno =>
     55 		switch (e) {
     56 		case rt::EBADF =>
     57 			return errors::invalid;
     58 		case rt::EINVAL, rt::ENOTTY =>
     59 			return errors::unsupported;
     60 		case =>
     61 			abort("Unexpected error from ioctl");
     62 		};
     63 	case =>
     64 		static let path_buf: [rt::PATH_MAX]u8 = [0...];
     65 		return fmt::bsprintf(path_buf,
     66 			"/dev/{}", c::tostr(&name: *const c::char)!);
     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, rt::EINVAL =>
     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 };