10c2a5bb5SAugustin Cavalier /* 20c2a5bb5SAugustin Cavalier * Copyright 2004, Axel Dörfler, axeld@pinc-software.de. All rights reserved. 30c2a5bb5SAugustin Cavalier * Copyright 2023, Haiku, Inc. All rights reserved. 40c2a5bb5SAugustin Cavalier * Distributed under the terms of the MIT License. 50c2a5bb5SAugustin Cavalier */ 60c2a5bb5SAugustin Cavalier 70c2a5bb5SAugustin Cavalier #include <new> 80c2a5bb5SAugustin Cavalier 90c2a5bb5SAugustin Cavalier #include <stdio.h> 100c2a5bb5SAugustin Cavalier #include <stdlib.h> 110c2a5bb5SAugustin Cavalier #include <string.h> 120c2a5bb5SAugustin Cavalier #include <errno.h> 130c2a5bb5SAugustin Cavalier 140c2a5bb5SAugustin Cavalier #include <util/AutoLock.h> 150c2a5bb5SAugustin Cavalier #include <Drivers.h> 160c2a5bb5SAugustin Cavalier 170c2a5bb5SAugustin Cavalier #include <team.h> 180c2a5bb5SAugustin Cavalier 190c2a5bb5SAugustin Cavalier extern "C" { 200c2a5bb5SAugustin Cavalier #include <drivers/tty.h> 210c2a5bb5SAugustin Cavalier #include <tty_module.h> 220c2a5bb5SAugustin Cavalier } 230c2a5bb5SAugustin Cavalier #include "tty_private.h" 240c2a5bb5SAugustin Cavalier 250c2a5bb5SAugustin Cavalier 260c2a5bb5SAugustin Cavalier //#define PTY_TRACE 270c2a5bb5SAugustin Cavalier #ifdef PTY_TRACE 280c2a5bb5SAugustin Cavalier # define TRACE(x) dprintf x 290c2a5bb5SAugustin Cavalier #else 300c2a5bb5SAugustin Cavalier # define TRACE(x) 310c2a5bb5SAugustin Cavalier #endif 320c2a5bb5SAugustin Cavalier 330c2a5bb5SAugustin Cavalier #define DRIVER_NAME "pty" 340c2a5bb5SAugustin Cavalier 350c2a5bb5SAugustin Cavalier 360c2a5bb5SAugustin Cavalier int32 api_version = B_CUR_DRIVER_API_VERSION; 370c2a5bb5SAugustin Cavalier tty_module_info *gTTYModule = NULL; 380c2a5bb5SAugustin Cavalier 390c2a5bb5SAugustin Cavalier struct mutex gGlobalTTYLock; 400c2a5bb5SAugustin Cavalier 410c2a5bb5SAugustin Cavalier static const uint32 kNumTTYs = 64; 420c2a5bb5SAugustin Cavalier char *gDeviceNames[kNumTTYs * 2 + 3]; 430c2a5bb5SAugustin Cavalier // reserve space for "pt/" and "tt/" entries, "ptmx", "tty", 440c2a5bb5SAugustin Cavalier // and the terminating NULL 450c2a5bb5SAugustin Cavalier 460c2a5bb5SAugustin Cavalier struct tty* gMasterTTYs[kNumTTYs]; 470c2a5bb5SAugustin Cavalier struct tty* gSlaveTTYs[kNumTTYs]; 480c2a5bb5SAugustin Cavalier 490c2a5bb5SAugustin Cavalier extern device_hooks gMasterPTYHooks, gSlavePTYHooks; 500c2a5bb5SAugustin Cavalier 510c2a5bb5SAugustin Cavalier 520c2a5bb5SAugustin Cavalier status_t 530c2a5bb5SAugustin Cavalier init_hardware(void) 540c2a5bb5SAugustin Cavalier { 550c2a5bb5SAugustin Cavalier TRACE((DRIVER_NAME ": init_hardware()\n")); 560c2a5bb5SAugustin Cavalier return B_OK; 570c2a5bb5SAugustin Cavalier } 580c2a5bb5SAugustin Cavalier 590c2a5bb5SAugustin Cavalier 600c2a5bb5SAugustin Cavalier status_t 610c2a5bb5SAugustin Cavalier init_driver(void) 620c2a5bb5SAugustin Cavalier { 630c2a5bb5SAugustin Cavalier status_t status = get_module(B_TTY_MODULE_NAME, (module_info **)&gTTYModule); 640c2a5bb5SAugustin Cavalier if (status < B_OK) 650c2a5bb5SAugustin Cavalier return status; 660c2a5bb5SAugustin Cavalier 670c2a5bb5SAugustin Cavalier TRACE((DRIVER_NAME ": init_driver()\n")); 680c2a5bb5SAugustin Cavalier 690c2a5bb5SAugustin Cavalier mutex_init(&gGlobalTTYLock, "tty global"); 700c2a5bb5SAugustin Cavalier memset(gDeviceNames, 0, sizeof(gDeviceNames)); 710c2a5bb5SAugustin Cavalier memset(gMasterTTYs, 0, sizeof(gMasterTTYs)); 720c2a5bb5SAugustin Cavalier memset(gSlaveTTYs, 0, sizeof(gSlaveTTYs)); 730c2a5bb5SAugustin Cavalier 740c2a5bb5SAugustin Cavalier // create driver name array 750c2a5bb5SAugustin Cavalier 760c2a5bb5SAugustin Cavalier char letter = 'p'; 770c2a5bb5SAugustin Cavalier int8 digit = 0; 780c2a5bb5SAugustin Cavalier 790c2a5bb5SAugustin Cavalier for (uint32 i = 0; i < kNumTTYs; i++) { 800c2a5bb5SAugustin Cavalier // For compatibility, we have to create the same mess in /dev/pt and 810c2a5bb5SAugustin Cavalier // /dev/tt as BeOS does: we publish devices p0, p1, ..., pf, r1, ..., 820c2a5bb5SAugustin Cavalier // sf. It would be nice if we could drop compatibility and create 830c2a5bb5SAugustin Cavalier // something better. In fact we already don't need the master devices 840c2a5bb5SAugustin Cavalier // anymore, since "/dev/ptmx" does the job. The slaves entries could 850c2a5bb5SAugustin Cavalier // be published on the fly when a master is opened (e.g via 860c2a5bb5SAugustin Cavalier // vfs_create_special_node()). 870c2a5bb5SAugustin Cavalier char buffer[64]; 880c2a5bb5SAugustin Cavalier 890c2a5bb5SAugustin Cavalier snprintf(buffer, sizeof(buffer), "pt/%c%x", letter, digit); 900c2a5bb5SAugustin Cavalier gDeviceNames[i] = strdup(buffer); 910c2a5bb5SAugustin Cavalier 920c2a5bb5SAugustin Cavalier snprintf(buffer, sizeof(buffer), "tt/%c%x", letter, digit); 930c2a5bb5SAugustin Cavalier gDeviceNames[i + kNumTTYs] = strdup(buffer); 940c2a5bb5SAugustin Cavalier 950c2a5bb5SAugustin Cavalier if (++digit > 15) 960c2a5bb5SAugustin Cavalier digit = 0, letter++; 970c2a5bb5SAugustin Cavalier 980c2a5bb5SAugustin Cavalier if (!gDeviceNames[i] || !gDeviceNames[i + kNumTTYs]) { 990c2a5bb5SAugustin Cavalier uninit_driver(); 1000c2a5bb5SAugustin Cavalier return B_NO_MEMORY; 1010c2a5bb5SAugustin Cavalier } 1020c2a5bb5SAugustin Cavalier } 1030c2a5bb5SAugustin Cavalier 1040c2a5bb5SAugustin Cavalier gDeviceNames[2 * kNumTTYs] = (char *)"ptmx"; 1050c2a5bb5SAugustin Cavalier gDeviceNames[2 * kNumTTYs + 1] = (char *)"tty"; 1060c2a5bb5SAugustin Cavalier 1070c2a5bb5SAugustin Cavalier return B_OK; 1080c2a5bb5SAugustin Cavalier } 1090c2a5bb5SAugustin Cavalier 1100c2a5bb5SAugustin Cavalier 1110c2a5bb5SAugustin Cavalier void 1120c2a5bb5SAugustin Cavalier uninit_driver(void) 1130c2a5bb5SAugustin Cavalier { 1140c2a5bb5SAugustin Cavalier TRACE((DRIVER_NAME ": uninit_driver()\n")); 1150c2a5bb5SAugustin Cavalier 1160c2a5bb5SAugustin Cavalier for (int32 i = 0; i < (int32)kNumTTYs * 2; i++) 1170c2a5bb5SAugustin Cavalier free(gDeviceNames[i]); 1180c2a5bb5SAugustin Cavalier 1190c2a5bb5SAugustin Cavalier mutex_destroy(&gGlobalTTYLock); 1200c2a5bb5SAugustin Cavalier 1210c2a5bb5SAugustin Cavalier put_module(B_TTY_MODULE_NAME); 1220c2a5bb5SAugustin Cavalier } 1230c2a5bb5SAugustin Cavalier 1240c2a5bb5SAugustin Cavalier 1250c2a5bb5SAugustin Cavalier const char ** 1260c2a5bb5SAugustin Cavalier publish_devices(void) 1270c2a5bb5SAugustin Cavalier { 1280c2a5bb5SAugustin Cavalier TRACE((DRIVER_NAME ": publish_devices()\n")); 1290c2a5bb5SAugustin Cavalier return const_cast<const char **>(gDeviceNames); 1300c2a5bb5SAugustin Cavalier } 1310c2a5bb5SAugustin Cavalier 1320c2a5bb5SAugustin Cavalier 1330c2a5bb5SAugustin Cavalier device_hooks * 1340c2a5bb5SAugustin Cavalier find_device(const char *name) 1350c2a5bb5SAugustin Cavalier { 1360c2a5bb5SAugustin Cavalier TRACE((DRIVER_NAME ": find_device(\"%s\")\n", name)); 1370c2a5bb5SAugustin Cavalier 1380c2a5bb5SAugustin Cavalier for (uint32 i = 0; gDeviceNames[i] != NULL; i++) { 1390c2a5bb5SAugustin Cavalier if (!strcmp(name, gDeviceNames[i])) { 1400c2a5bb5SAugustin Cavalier return i < kNumTTYs || i == (2 * kNumTTYs) 1410c2a5bb5SAugustin Cavalier ? &gMasterPTYHooks : &gSlavePTYHooks; 1420c2a5bb5SAugustin Cavalier } 1430c2a5bb5SAugustin Cavalier } 1440c2a5bb5SAugustin Cavalier 1450c2a5bb5SAugustin Cavalier return NULL; 1460c2a5bb5SAugustin Cavalier } 1470c2a5bb5SAugustin Cavalier 1480c2a5bb5SAugustin Cavalier 1490c2a5bb5SAugustin Cavalier static int32 1500c2a5bb5SAugustin Cavalier get_tty_index(const char *name) 1510c2a5bb5SAugustin Cavalier { 1520c2a5bb5SAugustin Cavalier // device names follow this form: "pt/%c%x" 1530c2a5bb5SAugustin Cavalier int8 digit = name[4]; 1540c2a5bb5SAugustin Cavalier if (digit >= 'a') { 1550c2a5bb5SAugustin Cavalier // hexadecimal digits 1560c2a5bb5SAugustin Cavalier digit -= 'a' - 10; 1570c2a5bb5SAugustin Cavalier } else 1580c2a5bb5SAugustin Cavalier digit -= '0'; 1590c2a5bb5SAugustin Cavalier 1600c2a5bb5SAugustin Cavalier return (name[3] - 'p') * 16 + digit; 1610c2a5bb5SAugustin Cavalier } 1620c2a5bb5SAugustin Cavalier 1630c2a5bb5SAugustin Cavalier 1640c2a5bb5SAugustin Cavalier static int32 1650c2a5bb5SAugustin Cavalier get_tty_index(struct tty *tty) 1660c2a5bb5SAugustin Cavalier { 1670c2a5bb5SAugustin Cavalier int32 index = -1; 1680c2a5bb5SAugustin Cavalier for (uint32 i = 0; i < kNumTTYs; i++) { 169*88306be9SAugustin Cavalier if (tty == gMasterTTYs[i] || tty == gSlaveTTYs[i]) { 1700c2a5bb5SAugustin Cavalier index = i; 1710c2a5bb5SAugustin Cavalier break; 1720c2a5bb5SAugustin Cavalier } 1730c2a5bb5SAugustin Cavalier } 1740c2a5bb5SAugustin Cavalier return index; 1750c2a5bb5SAugustin Cavalier } 1760c2a5bb5SAugustin Cavalier 1770c2a5bb5SAugustin Cavalier 1780c2a5bb5SAugustin Cavalier // #pragma mark - device hooks 1790c2a5bb5SAugustin Cavalier 1800c2a5bb5SAugustin Cavalier 1810c2a5bb5SAugustin Cavalier static bool 1820c2a5bb5SAugustin Cavalier master_service(struct tty *tty, uint32 op, void *buffer, size_t length) 1830c2a5bb5SAugustin Cavalier { 1840c2a5bb5SAugustin Cavalier // nothing here yet 1850c2a5bb5SAugustin Cavalier return false; 1860c2a5bb5SAugustin Cavalier } 1870c2a5bb5SAugustin Cavalier 1880c2a5bb5SAugustin Cavalier 1890c2a5bb5SAugustin Cavalier static bool 1900c2a5bb5SAugustin Cavalier slave_service(struct tty *tty, uint32 op, void *buffer, size_t length) 1910c2a5bb5SAugustin Cavalier { 1920c2a5bb5SAugustin Cavalier // nothing here yet 1930c2a5bb5SAugustin Cavalier return false; 1940c2a5bb5SAugustin Cavalier } 1950c2a5bb5SAugustin Cavalier 1960c2a5bb5SAugustin Cavalier 1970c2a5bb5SAugustin Cavalier static status_t 1980c2a5bb5SAugustin Cavalier master_open(const char *name, uint32 flags, void **_cookie) 1990c2a5bb5SAugustin Cavalier { 2000c2a5bb5SAugustin Cavalier bool findUnusedTTY = strcmp(name, "ptmx") == 0; 2010c2a5bb5SAugustin Cavalier 2020c2a5bb5SAugustin Cavalier int32 index = -1; 2030c2a5bb5SAugustin Cavalier if (!findUnusedTTY) { 2040c2a5bb5SAugustin Cavalier index = get_tty_index(name); 2050c2a5bb5SAugustin Cavalier if (index >= (int32)kNumTTYs) 2060c2a5bb5SAugustin Cavalier return B_ERROR; 2070c2a5bb5SAugustin Cavalier } 2080c2a5bb5SAugustin Cavalier 2090c2a5bb5SAugustin Cavalier TRACE(("pty_open: TTY index = %" B_PRId32 " (name = %s)\n", index, name)); 2100c2a5bb5SAugustin Cavalier 2110c2a5bb5SAugustin Cavalier MutexLocker globalLocker(gGlobalTTYLock); 2120c2a5bb5SAugustin Cavalier 2130c2a5bb5SAugustin Cavalier if (findUnusedTTY) { 2140c2a5bb5SAugustin Cavalier for (index = 0; index < (int32)kNumTTYs; index++) { 2150c2a5bb5SAugustin Cavalier if (gMasterTTYs[index] == NULL || gMasterTTYs[index]->ref_count == 0) 2160c2a5bb5SAugustin Cavalier break; 2170c2a5bb5SAugustin Cavalier } 2180c2a5bb5SAugustin Cavalier if (index >= (int32)kNumTTYs) 2190c2a5bb5SAugustin Cavalier return ENOENT; 2200c2a5bb5SAugustin Cavalier } else if (gMasterTTYs[index] != NULL && gMasterTTYs[index]->ref_count != 0) { 2210c2a5bb5SAugustin Cavalier // we're already open! 2220c2a5bb5SAugustin Cavalier return B_BUSY; 2230c2a5bb5SAugustin Cavalier } 2240c2a5bb5SAugustin Cavalier 2250c2a5bb5SAugustin Cavalier if (gMasterTTYs[index] == NULL) { 2260c2a5bb5SAugustin Cavalier gMasterTTYs[index] = gTTYModule->tty_create(master_service, NULL); 2270c2a5bb5SAugustin Cavalier if (gMasterTTYs[index] == NULL) 2280c2a5bb5SAugustin Cavalier return B_NO_MEMORY; 2290c2a5bb5SAugustin Cavalier } 2300c2a5bb5SAugustin Cavalier if (gSlaveTTYs[index] == NULL) { 2310c2a5bb5SAugustin Cavalier gSlaveTTYs[index] = gTTYModule->tty_create(slave_service, gMasterTTYs[index]); 2320c2a5bb5SAugustin Cavalier if (gSlaveTTYs[index] == NULL) 2330c2a5bb5SAugustin Cavalier return B_NO_MEMORY; 2340c2a5bb5SAugustin Cavalier } 2350c2a5bb5SAugustin Cavalier 2360c2a5bb5SAugustin Cavalier tty_cookie *cookie = gTTYModule->tty_create_cookie(gMasterTTYs[index], 2370c2a5bb5SAugustin Cavalier gSlaveTTYs[index], flags); 2380c2a5bb5SAugustin Cavalier if (cookie == NULL) 2390c2a5bb5SAugustin Cavalier return B_NO_MEMORY; 2400c2a5bb5SAugustin Cavalier 2410c2a5bb5SAugustin Cavalier *_cookie = cookie; 2420c2a5bb5SAugustin Cavalier return B_OK; 2430c2a5bb5SAugustin Cavalier } 2440c2a5bb5SAugustin Cavalier 2450c2a5bb5SAugustin Cavalier 2460c2a5bb5SAugustin Cavalier static status_t 2470c2a5bb5SAugustin Cavalier slave_open(const char *name, uint32 flags, void **_cookie) 2480c2a5bb5SAugustin Cavalier { 2490c2a5bb5SAugustin Cavalier // Get the tty index: Opening "/dev/tty" means opening the process' 2500c2a5bb5SAugustin Cavalier // controlling tty. 2510c2a5bb5SAugustin Cavalier int32 index = get_tty_index(name); 2520c2a5bb5SAugustin Cavalier if (strcmp(name, "tty") == 0) { 2530c2a5bb5SAugustin Cavalier struct tty *controllingTTY = (struct tty *)team_get_controlling_tty(); 2540c2a5bb5SAugustin Cavalier if (controllingTTY == NULL) 2550c2a5bb5SAugustin Cavalier return B_NOT_ALLOWED; 2560c2a5bb5SAugustin Cavalier 2570c2a5bb5SAugustin Cavalier index = get_tty_index(controllingTTY); 2580c2a5bb5SAugustin Cavalier if (index < 0) 2590c2a5bb5SAugustin Cavalier return B_NOT_ALLOWED; 2600c2a5bb5SAugustin Cavalier } else { 2610c2a5bb5SAugustin Cavalier index = get_tty_index(name); 2620c2a5bb5SAugustin Cavalier if (index >= (int32)kNumTTYs) 2630c2a5bb5SAugustin Cavalier return B_ERROR; 2640c2a5bb5SAugustin Cavalier } 2650c2a5bb5SAugustin Cavalier 2660c2a5bb5SAugustin Cavalier TRACE(("slave_open: TTY index = %" B_PRId32 " (name = %s)\n", index, 2670c2a5bb5SAugustin Cavalier name)); 2680c2a5bb5SAugustin Cavalier 2690c2a5bb5SAugustin Cavalier MutexLocker globalLocker(gGlobalTTYLock); 2700c2a5bb5SAugustin Cavalier 2710c2a5bb5SAugustin Cavalier // we may only be used if our master has already been opened 2720c2a5bb5SAugustin Cavalier if (gMasterTTYs[index] == NULL || gMasterTTYs[index]->open_count == 0 2730c2a5bb5SAugustin Cavalier || gSlaveTTYs[index] == NULL) { 2740c2a5bb5SAugustin Cavalier return B_IO_ERROR; 2750c2a5bb5SAugustin Cavalier } 2760c2a5bb5SAugustin Cavalier 2770c2a5bb5SAugustin Cavalier bool makeControllingTTY = (flags & O_NOCTTY) == 0; 2780c2a5bb5SAugustin Cavalier pid_t processID = getpid(); 2790c2a5bb5SAugustin Cavalier pid_t sessionID = getsid(processID); 2800c2a5bb5SAugustin Cavalier 2810c2a5bb5SAugustin Cavalier if (gSlaveTTYs[index]->open_count == 0) { 2820c2a5bb5SAugustin Cavalier // We only allow session leaders to open the tty initially. 2830c2a5bb5SAugustin Cavalier if (makeControllingTTY && processID != sessionID) 2840c2a5bb5SAugustin Cavalier return B_NOT_ALLOWED; 2850c2a5bb5SAugustin Cavalier } else if (makeControllingTTY) { 2860c2a5bb5SAugustin Cavalier // If already open, we allow only processes from the same session 2870c2a5bb5SAugustin Cavalier // to open the tty again while becoming controlling tty 2880c2a5bb5SAugustin Cavalier pid_t ttySession = gSlaveTTYs[index]->settings->session_id; 2890c2a5bb5SAugustin Cavalier if (ttySession >= 0) { 2900c2a5bb5SAugustin Cavalier makeControllingTTY = false; 2910c2a5bb5SAugustin Cavalier } else { 2920c2a5bb5SAugustin Cavalier // The tty is not associated with a session yet. The process needs 2930c2a5bb5SAugustin Cavalier // to be a session leader. 2940c2a5bb5SAugustin Cavalier if (makeControllingTTY && processID != sessionID) 2950c2a5bb5SAugustin Cavalier return B_NOT_ALLOWED; 2960c2a5bb5SAugustin Cavalier } 2970c2a5bb5SAugustin Cavalier } 2980c2a5bb5SAugustin Cavalier 2990c2a5bb5SAugustin Cavalier if (gSlaveTTYs[index]->open_count == 0) { 3000c2a5bb5SAugustin Cavalier gSlaveTTYs[index]->settings->session_id = -1; 3010c2a5bb5SAugustin Cavalier gSlaveTTYs[index]->settings->pgrp_id = -1; 3020c2a5bb5SAugustin Cavalier } 3030c2a5bb5SAugustin Cavalier 3040c2a5bb5SAugustin Cavalier tty_cookie *cookie = gTTYModule->tty_create_cookie(gSlaveTTYs[index], 3050c2a5bb5SAugustin Cavalier gMasterTTYs[index], flags); 3060c2a5bb5SAugustin Cavalier if (cookie == NULL) { 3070c2a5bb5SAugustin Cavalier gSlaveTTYs[index] = NULL; 3080c2a5bb5SAugustin Cavalier return B_NO_MEMORY; 3090c2a5bb5SAugustin Cavalier } 3100c2a5bb5SAugustin Cavalier 3110c2a5bb5SAugustin Cavalier if (makeControllingTTY) { 3120c2a5bb5SAugustin Cavalier gSlaveTTYs[index]->settings->session_id = sessionID; 3130c2a5bb5SAugustin Cavalier gSlaveTTYs[index]->settings->pgrp_id = sessionID; 3140c2a5bb5SAugustin Cavalier team_set_controlling_tty(gSlaveTTYs[index]); 3150c2a5bb5SAugustin Cavalier } 3160c2a5bb5SAugustin Cavalier 3170c2a5bb5SAugustin Cavalier *_cookie = cookie; 3180c2a5bb5SAugustin Cavalier return B_OK; 3190c2a5bb5SAugustin Cavalier } 3200c2a5bb5SAugustin Cavalier 3210c2a5bb5SAugustin Cavalier 3220c2a5bb5SAugustin Cavalier static status_t 3230c2a5bb5SAugustin Cavalier pty_close(void *_cookie) 3240c2a5bb5SAugustin Cavalier { 3250c2a5bb5SAugustin Cavalier tty_cookie *cookie = (tty_cookie *)_cookie; 3260c2a5bb5SAugustin Cavalier 3270c2a5bb5SAugustin Cavalier TRACE(("pty_close: cookie %p\n", _cookie)); 3280c2a5bb5SAugustin Cavalier 3290c2a5bb5SAugustin Cavalier MutexLocker globalLocker(gGlobalTTYLock); 3300c2a5bb5SAugustin Cavalier 3310c2a5bb5SAugustin Cavalier gTTYModule->tty_close_cookie(cookie); 3320c2a5bb5SAugustin Cavalier 3330c2a5bb5SAugustin Cavalier return B_OK; 3340c2a5bb5SAugustin Cavalier } 3350c2a5bb5SAugustin Cavalier 3360c2a5bb5SAugustin Cavalier 3370c2a5bb5SAugustin Cavalier static status_t 3380c2a5bb5SAugustin Cavalier pty_free_cookie(void *_cookie) 3390c2a5bb5SAugustin Cavalier { 3400c2a5bb5SAugustin Cavalier // The TTY is already closed. We only have to free the cookie. 3410c2a5bb5SAugustin Cavalier tty_cookie *cookie = (tty_cookie *)_cookie; 3420c2a5bb5SAugustin Cavalier 3430c2a5bb5SAugustin Cavalier gTTYModule->tty_destroy_cookie(cookie); 3440c2a5bb5SAugustin Cavalier 3450c2a5bb5SAugustin Cavalier return B_OK; 3460c2a5bb5SAugustin Cavalier } 3470c2a5bb5SAugustin Cavalier 3480c2a5bb5SAugustin Cavalier 3490c2a5bb5SAugustin Cavalier static status_t 3500c2a5bb5SAugustin Cavalier pty_ioctl(void *_cookie, uint32 op, void *buffer, size_t length) 3510c2a5bb5SAugustin Cavalier { 3520c2a5bb5SAugustin Cavalier tty_cookie *cookie = (tty_cookie *)_cookie; 3530c2a5bb5SAugustin Cavalier 3540c2a5bb5SAugustin Cavalier struct tty* tty = cookie->tty; 3550c2a5bb5SAugustin Cavalier RecursiveLocker locker(tty->lock); 3560c2a5bb5SAugustin Cavalier 3570c2a5bb5SAugustin Cavalier TRACE(("pty_ioctl: cookie %p, op %" B_PRIu32 ", buffer %p, length %lu" 3580c2a5bb5SAugustin Cavalier "\n", _cookie, op, buffer, length)); 3590c2a5bb5SAugustin Cavalier 3600c2a5bb5SAugustin Cavalier switch (op) { 3610c2a5bb5SAugustin Cavalier case B_IOCTL_GET_TTY_INDEX: 3620c2a5bb5SAugustin Cavalier { 3630c2a5bb5SAugustin Cavalier int32 ptyIndex = get_tty_index(cookie->tty); 3640c2a5bb5SAugustin Cavalier if (ptyIndex < 0) 3650c2a5bb5SAugustin Cavalier return B_BAD_VALUE; 3660c2a5bb5SAugustin Cavalier 3670c2a5bb5SAugustin Cavalier if (user_memcpy(buffer, &ptyIndex, sizeof(int32)) < B_OK) 3680c2a5bb5SAugustin Cavalier return B_BAD_ADDRESS; 3690c2a5bb5SAugustin Cavalier 3700c2a5bb5SAugustin Cavalier return B_OK; 3710c2a5bb5SAugustin Cavalier } 3720c2a5bb5SAugustin Cavalier 3730c2a5bb5SAugustin Cavalier case B_IOCTL_GRANT_TTY: 3740c2a5bb5SAugustin Cavalier { 3750c2a5bb5SAugustin Cavalier if (!cookie->tty->is_master) 3760c2a5bb5SAugustin Cavalier return B_BAD_VALUE; 3770c2a5bb5SAugustin Cavalier 3780c2a5bb5SAugustin Cavalier int32 ptyIndex = get_tty_index(cookie->tty); 3790c2a5bb5SAugustin Cavalier if (ptyIndex < 0) 3800c2a5bb5SAugustin Cavalier return B_BAD_VALUE; 3810c2a5bb5SAugustin Cavalier 3820c2a5bb5SAugustin Cavalier // get slave path 3830c2a5bb5SAugustin Cavalier char path[64]; 3840c2a5bb5SAugustin Cavalier snprintf(path, sizeof(path), "/dev/%s", 3850c2a5bb5SAugustin Cavalier gDeviceNames[kNumTTYs + ptyIndex]); 3860c2a5bb5SAugustin Cavalier 3870c2a5bb5SAugustin Cavalier // set owner and permissions respectively 3880c2a5bb5SAugustin Cavalier if (chown(path, getuid(), getgid()) != 0 3890c2a5bb5SAugustin Cavalier || chmod(path, S_IRUSR | S_IWUSR | S_IWGRP) != 0) { 3900c2a5bb5SAugustin Cavalier return errno; 3910c2a5bb5SAugustin Cavalier } 3920c2a5bb5SAugustin Cavalier 3930c2a5bb5SAugustin Cavalier return B_OK; 3940c2a5bb5SAugustin Cavalier } 3950c2a5bb5SAugustin Cavalier 3960c2a5bb5SAugustin Cavalier case 'pgid': // BeOS 3970c2a5bb5SAugustin Cavalier op = TIOCSPGRP; 3980c2a5bb5SAugustin Cavalier 3990c2a5bb5SAugustin Cavalier case 'wsiz': // BeOS 4000c2a5bb5SAugustin Cavalier op = TIOCSWINSZ; 4010c2a5bb5SAugustin Cavalier break; 4020c2a5bb5SAugustin Cavalier 4030c2a5bb5SAugustin Cavalier default: 4040c2a5bb5SAugustin Cavalier break; 4050c2a5bb5SAugustin Cavalier } 4060c2a5bb5SAugustin Cavalier 4070c2a5bb5SAugustin Cavalier return gTTYModule->tty_control(cookie, op, buffer, length); 4080c2a5bb5SAugustin Cavalier } 4090c2a5bb5SAugustin Cavalier 4100c2a5bb5SAugustin Cavalier 4110c2a5bb5SAugustin Cavalier static status_t 4120c2a5bb5SAugustin Cavalier pty_read(void *_cookie, off_t offset, void *buffer, size_t *_length) 4130c2a5bb5SAugustin Cavalier { 4140c2a5bb5SAugustin Cavalier tty_cookie *cookie = (tty_cookie *)_cookie; 4150c2a5bb5SAugustin Cavalier 4160c2a5bb5SAugustin Cavalier TRACE(("pty_read: cookie %p, offset %" B_PRIdOFF ", buffer %p, length " 4170c2a5bb5SAugustin Cavalier "%lu\n", _cookie, offset, buffer, *_length)); 4180c2a5bb5SAugustin Cavalier 4190c2a5bb5SAugustin Cavalier status_t result = gTTYModule->tty_read(cookie, buffer, _length); 4200c2a5bb5SAugustin Cavalier 4210c2a5bb5SAugustin Cavalier TRACE(("pty_read done: cookie %p, result: %" B_PRIx32 ", length %lu\n", 4220c2a5bb5SAugustin Cavalier _cookie, result, *_length)); 4230c2a5bb5SAugustin Cavalier 4240c2a5bb5SAugustin Cavalier return result; 4250c2a5bb5SAugustin Cavalier } 4260c2a5bb5SAugustin Cavalier 4270c2a5bb5SAugustin Cavalier 4280c2a5bb5SAugustin Cavalier static status_t 4290c2a5bb5SAugustin Cavalier pty_write(void *_cookie, off_t offset, const void *buffer, size_t *_length) 4300c2a5bb5SAugustin Cavalier { 4310c2a5bb5SAugustin Cavalier tty_cookie *cookie = (tty_cookie *)_cookie; 4320c2a5bb5SAugustin Cavalier 4330c2a5bb5SAugustin Cavalier TRACE(("pty_write: cookie %p, offset %" B_PRIdOFF ", buffer %p, length " 4340c2a5bb5SAugustin Cavalier "%lu\n", _cookie, offset, buffer, *_length)); 4350c2a5bb5SAugustin Cavalier 4360c2a5bb5SAugustin Cavalier status_t result = gTTYModule->tty_write(cookie, buffer, _length); 4370c2a5bb5SAugustin Cavalier 4380c2a5bb5SAugustin Cavalier TRACE(("pty_write done: cookie %p, result: %" B_PRIx32 ", length %lu\n", 4390c2a5bb5SAugustin Cavalier _cookie, result, *_length)); 4400c2a5bb5SAugustin Cavalier 4410c2a5bb5SAugustin Cavalier return result; 4420c2a5bb5SAugustin Cavalier } 4430c2a5bb5SAugustin Cavalier 4440c2a5bb5SAugustin Cavalier 4450c2a5bb5SAugustin Cavalier static status_t 4460c2a5bb5SAugustin Cavalier pty_select(void *_cookie, uint8 event, uint32 ref, selectsync *sync) 4470c2a5bb5SAugustin Cavalier { 4480c2a5bb5SAugustin Cavalier tty_cookie *cookie = (tty_cookie *)_cookie; 4490c2a5bb5SAugustin Cavalier 4500c2a5bb5SAugustin Cavalier return gTTYModule->tty_select(cookie, event, ref, sync); 4510c2a5bb5SAugustin Cavalier } 4520c2a5bb5SAugustin Cavalier 4530c2a5bb5SAugustin Cavalier 4540c2a5bb5SAugustin Cavalier static status_t 4550c2a5bb5SAugustin Cavalier pty_deselect(void *_cookie, uint8 event, selectsync *sync) 4560c2a5bb5SAugustin Cavalier { 4570c2a5bb5SAugustin Cavalier tty_cookie *cookie = (tty_cookie *)_cookie; 4580c2a5bb5SAugustin Cavalier 4590c2a5bb5SAugustin Cavalier return gTTYModule->tty_deselect(cookie, event, sync); 4600c2a5bb5SAugustin Cavalier } 4610c2a5bb5SAugustin Cavalier 4620c2a5bb5SAugustin Cavalier 4630c2a5bb5SAugustin Cavalier device_hooks gMasterPTYHooks = { 4640c2a5bb5SAugustin Cavalier &master_open, 4650c2a5bb5SAugustin Cavalier &pty_close, 4660c2a5bb5SAugustin Cavalier &pty_free_cookie, 4670c2a5bb5SAugustin Cavalier &pty_ioctl, 4680c2a5bb5SAugustin Cavalier &pty_read, 4690c2a5bb5SAugustin Cavalier &pty_write, 4700c2a5bb5SAugustin Cavalier &pty_select, 4710c2a5bb5SAugustin Cavalier &pty_deselect, 4720c2a5bb5SAugustin Cavalier NULL, // read_pages() 4730c2a5bb5SAugustin Cavalier NULL // write_pages() 4740c2a5bb5SAugustin Cavalier }; 4750c2a5bb5SAugustin Cavalier 4760c2a5bb5SAugustin Cavalier device_hooks gSlavePTYHooks = { 4770c2a5bb5SAugustin Cavalier &slave_open, 4780c2a5bb5SAugustin Cavalier &pty_close, 4790c2a5bb5SAugustin Cavalier &pty_free_cookie, 4800c2a5bb5SAugustin Cavalier &pty_ioctl, 4810c2a5bb5SAugustin Cavalier &pty_read, 4820c2a5bb5SAugustin Cavalier &pty_write, 4830c2a5bb5SAugustin Cavalier &pty_select, 4840c2a5bb5SAugustin Cavalier &pty_deselect, 4850c2a5bb5SAugustin Cavalier NULL, // read_pages() 4860c2a5bb5SAugustin Cavalier NULL // write_pages() 4870c2a5bb5SAugustin Cavalier }; 488