/* * Copyright (c) 2015, 2016, 2022 Jonas 'Sortie' Termansen. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * psctl.cpp * Process control interface. */ #include #include #include #include #include #if !defined(TTY_NAME_MAX) #include #endif #include #include #include #include #include #include #include #include #include #include #include namespace Sortix { int sys_psctl(pid_t pid, int request, void* ptr) { ScopedLock lock(&process_family_lock); Ref ptable = CurrentProcess()->GetPTable(); if ( request == PSCTL_PREV_PID ) { struct psctl_prev_pid resp; memset(&resp, 0, sizeof(resp)); resp.prev_pid = ptable->Prev(pid); return CopyToUser(ptr, &resp, sizeof(resp)) ? 0 : -1; } else if ( request == PSCTL_NEXT_PID ) { struct psctl_next_pid resp; memset(&resp, 0, sizeof(resp)); resp.next_pid = ptable->Next(pid); return CopyToUser(ptr, &resp, sizeof(resp)) ? 0 : -1; } Process* process = ptable->Get(pid); if ( !process ) return errno = ESRCH, -1; if ( request == PSCTL_STAT ) { struct psctl_stat psst; memset(&psst, 0, sizeof(psst)); psst.pid = pid; if ( process->parent ) { Process* parent = process->parent; psst.ppid = parent->pid; psst.ppid_prev = process->prevsibling ? process->prevsibling->pid : -1; psst.ppid_next = process->nextsibling ? process->nextsibling->pid : -1; } else { psst.ppid = -1; psst.ppid_prev = -1; psst.ppid_next = -1; } psst.ppid_first = process->firstchild ? process->firstchild->pid : -1; if ( process->group ) { Process* group = process->group; psst.pgid = group->pid; psst.pgid_prev = process->groupprev ? process->groupprev->pid : -1; psst.pgid_next = process->groupnext ? process->groupnext->pid : -1; } else { psst.pgid = -1; psst.pgid_prev = -1; psst.pgid_next = -1; } psst.pgid_first = process->groupfirst ? process->groupfirst->pid : -1; if ( process->session ) { Process* session = process->session; psst.sid = session->pid; psst.sid_prev = process->sessionprev ? process->sessionprev->pid : -1; psst.sid_next = process->sessionnext ? process->sessionnext->pid : -1; } else { psst.sid = -1; psst.sid_prev = -1; psst.sid_next = -1; } psst.sid_first = process->sessionfirst ? process->sessionfirst->pid : -1; // TODO: Implement init groupings. psst.init = 1; psst.init_prev = ptable->Prev(pid); psst.init_next = ptable->Next(pid); psst.init_first = pid == 1 ? 1 : -1; kthread_mutex_lock(&process->idlock); psst.uid = process->uid; psst.euid = process->euid; psst.gid = process->gid; psst.egid = process->egid; kthread_mutex_unlock(&process->idlock); kthread_mutex_lock(&process->threadlock); psst.status = process->exit_code; kthread_mutex_unlock(&process->threadlock); kthread_mutex_lock(&process->nicelock); psst.nice = process->nice; kthread_mutex_unlock(&process->nicelock); kthread_mutex_lock(&process->segment_lock); // TODO: Cache these. for ( size_t i = 0; i < process->segments_used; i++ ) { const struct segment* segment = &process->segments[i]; psst.pss += segment->size; psst.rss += segment->size; psst.uss += segment->size; psst.vms += segment->size; } kthread_mutex_unlock(&process->segment_lock); // Note: It is safe to access the clocks in this manner as each of them // are locked by disabling interrupts. This is perhaps not // SMP-ready, but it will do for now. Interrupt::Disable(); psst.tmns.tmns_utime = process->execute_clock.current_time; psst.tmns.tmns_stime = process->system_clock.current_time; psst.tmns.tmns_cutime = process->child_execute_clock.current_time; psst.tmns.tmns_cstime = process->child_system_clock.current_time; Interrupt::Enable(); return CopyToUser(ptr, &psst, sizeof(psst)) ? 0 : -1; } else if ( request == PSCTL_PROGRAM_PATH ) { struct psctl_program_path ctl; if ( !CopyFromUser(&ctl, ptr, sizeof(ctl)) ) return -1; // TODO: program_image_path is not properly protected at this time. const char* path = process->program_image_path; if ( !path ) path = ""; size_t size = strlen(path) + 1; struct psctl_program_path resp = ctl; resp.size = size; if ( !CopyToUser(ptr, &resp, sizeof(resp)) ) return -1; if ( ctl.buffer ) { if ( ctl.size < size ) return errno = ERANGE, -1; if ( !CopyToUser(ctl.buffer, path, size) ) return -1; } return 0; } else if ( request == PSCTL_TTYNAME ) { struct psctl_ttyname ctl; if ( !CopyFromUser(&ctl, ptr, sizeof(ctl)) ) return -1; ioctx_t kctx; SetupKernelIOCtx(&kctx); if ( !process->session ) return errno = ENOTTY, -1; Ref tty = process->session->GetTTY(); if ( !tty ) return errno = ENOTTY, -1; char ttyname[TTY_NAME_MAX-5+1]; if ( tty->ioctl(&kctx, TIOCGNAME, (uintptr_t) ttyname) < 0 ) return -1; size_t size = strlen(ttyname) + 1; struct psctl_ttyname resp = ctl; resp.size = size; if ( !CopyToUser(ptr, &resp, sizeof(resp)) ) return -1; if ( ctl.buffer ) { if ( ctl.size < size ) return errno = ERANGE, -1; if ( !CopyToUser(ctl.buffer, ttyname, size) ) return -1; } return 0; } return errno = EINVAL, -1; } } // namespace Sortix