/*
 * readproc - interface to process table
 *
 * Copyright © 2002-2023 Craig Small <csmall@dropbear.xyz>
 * Copyright © 2011-2023 Jim Warner <james.warner@comcast.net>
 * Copyright © 1998-2010 Albert Cahalan
 * Copyright © 1998      Michael K. Johnson
 * Copyright © 1996      Charles L. Blake.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef PROCPS_PROC_READPROC_H
#define PROCPS_PROC_READPROC_H

#include <sys/types.h>
#include <dirent.h>
#include <unistd.h>
#include "misc.h"

// the following is development only, forcing display of "[ duplicate ENUM ]" strings
// for the supgid and supgrp fields when displaying threads ...
//#define FALSE_THREADS


// This is to help document a transition from pid to tgid/tid caused
// by the introduction of thread support. It is used in cases where
// neither tgid nor tid seemed correct. (in other words, FIXME)
#define XXXID tid

// Basic data structure which holds all information we can get about a process.
// (unless otherwise specified, fields are read from /proc/#/stat)
//
// Most of it comes from task_struct in linux/sched.h
//
typedef struct proc_t {
    int
        tid,            // (special)       task id, the POSIX thread ID (see also: tgid)
        ppid;           // stat,status     pid of parent process
    char
        state,          // stat,status     single-char code for process state (S=sleeping)
        pad_1,          // n/a             padding
        pad_2,          // n/a             padding
        pad_3;          // n/a             padding
    unsigned long long
        utime,          // stat            user-mode CPU time accumulated by process
        stime,          // stat            kernel-mode CPU time accumulated by process
        cutime,         // stat            cumulative utime of process and reaped children
        cstime,         // stat            cumulative stime of process and reaped children
        start_time,     // stat            start time of process -- seconds since system boot
        blkio_tics,     // stat            time spent waiting for block IO
        gtime,          // stat            guest time of the task in jiffies
        cgtime;         // stat            guest time of the task children in jiffies
    int                 // next 3 fields are NOT filled in by readproc
        pcpu,           // stat (special)  elapsed tics for %CPU usage calculation
        maj_delta,      // stat (special)  major page faults since last update
        min_delta;      // stat (special)  minor page faults since last update
    char
        // Linux 2.1.7x and up have 64 signals. Allow 64, plus '\0' and padding.
        signal[18],     // status          mask of pending signals
        blocked[18],    // status          mask of blocked signals
        sigignore[18],  // status          mask of ignored signals
        sigcatch[18],   // status          mask of caught  signals
        _sigpnd[18];    // status          mask of PER TASK pending signals
    char
        // Capabilities
        capprm[18];     // status          Permitted Capabilities
    unsigned long
        start_code,     // stat            address of beginning of code segment
        end_code,       // stat            address of end of code segment
        start_stack,    // stat            address of the bottom of stack for the process
        kstk_esp,       // stat            kernel stack pointer
        kstk_eip,       // stat            kernel instruction pointer
        wchan,          // stat (special)  address of kernel wait channel proc is sleeping in
        rss,            // stat            identical to 'resident'
        alarm;          // stat            ?
    int
        priority,       // stat            kernel scheduling priority
        nice;           // stat            standard unix nice level of process
    unsigned long
    // the next 7 members come from /proc/#/statm
        size,           // statm           total virtual memory (as # pages)
        resident,       // statm           resident non-swapped memory (as # pages)
        share,          // statm           shared (mmap'd) memory (as # pages)
        trs,            // statm           text (exe) resident set (as # pages)
        lrs,            // statm           library resident set (always 0 w/ 2.6)
        drs,            // statm           data+stack resident set (as # pages)
        dt;             // statm           dirty pages (always 0 w/ 2.6)
    unsigned long
        vm_size,        // status          equals 'size' (as kb)
        vm_lock,        // status          locked pages (as kb)
        vm_rss,         // status          equals 'rss' and/or 'resident' (as kb)
        vm_rss_anon,    // status          the 'anonymous' portion of vm_rss (as kb)
        vm_rss_file,    // status          the 'file-backed' portion of vm_rss (as kb)
        vm_rss_shared,  // status          the 'shared' portion of vm_rss (as kb)
        vm_data,        // status          data only size (as kb)
        vm_stack,       // status          stack only size (as kb)
        vm_swap,        // status          based on linux-2.6.34 "swap ents" (as kb)
        vm_exe,         // status          equals 'trs' (as kb)
        vm_lib,         // status          total, not just used, library pages (as kb)
        vsize,          // stat            number of pages of virtual memory ...
        rss_rlim,       // stat            resident set size limit?
        flags,          // stat            kernel flags for the process
        min_flt,        // stat            number of minor page faults since process start
        maj_flt,        // stat            number of major page faults since process start
        cmin_flt,       // stat            cumulative min_flt of process and child processes
        cmaj_flt,       // stat            cumulative maj_flt of process and child processes
        rchar,          // io              characters read
        wchar,          // io              characters written
        syscr,          // io              number of read I/O operations
        syscw,          // io              number of write I/O operations
        read_bytes,     // io              number of bytes fetched from the storage layer
        write_bytes,    // io              number of bytes sent to the storage layer
        cancelled_write_bytes, // io       number of bytes truncating pagecache
        smap_Rss,              // smaps_rollup  mapping currently resident in RAM
        smap_Pss,              //    "     Rss divided by total processes sharing it
        smap_Pss_Anon,         //    "     proportional share of 'anonymous' memory
        smap_Pss_File,         //    "     proportional share of 'file' memory
        smap_Pss_Shmem,        //    "     proportional share of 'shmem' memory
        smap_Shared_Clean,     //    "     unmodified shared memory
        smap_Shared_Dirty,     //    "     altered shared memory
        smap_Private_Clean,    //    "     unmodified private memory
        smap_Private_Dirty,    //    "     altered private memory
        smap_Referenced,       //    "     memory marked as referenced/accessed
        smap_Anonymous,        //    "     memory not belonging to any file
        smap_LazyFree,         //    "     memory marked by madvise(MADV_FREE)
        smap_AnonHugePages,    //    "     memory backed by transparent huge pages
        smap_ShmemPmdMapped,   //    "     shmem/tmpfs memory backed by huge pages
        smap_FilePmdMapped,    //    "     file memory backed by huge pages
        smap_Shared_Hugetlb,   //    "     hugetlbfs backed memory *not* counted in Rss/Pss
        smap_Private_Hugetlb,  //    "     hugetlbfs backed memory *not* counted in Rss/Pss
        smap_Swap,             //    "     swapped would-be-anonymous memory (includes swapped out shmem)
        smap_SwapPss,          //    "     the proportional share of 'Swap' (excludes swapped out shmem)
        smap_Locked;           //    "     memory amount locked to RAM
    char
        *environ,       // (special)       environment as string (/proc/#/environ)
        *cmdline,       // (special)       command line as string (/proc/#/cmdline)
        *cgroup,        // (special)       cgroup as string (/proc/#/cgroup)
        *cgname,        // (special)       name portion of above (if possible)
        *supgid,        // status          supplementary gids as comma delimited str
        *supgrp,        // supp grp names as comma delimited str, derived from supgid
       **environ_v,     // (special)       environment string vectors (/proc/#/environ)
       **cmdline_v,     // (special)       command line string vectors (/proc/#/cmdline)
       **cgroup_v;      // (special)       cgroup string vectors (/proc/#/cgroup)
    char
        *euser,         // stat(),status   effective user name
        *ruser,         // status          real user name
        *suser,         // status          saved user name
        *fuser,         // status          filesystem user name
        *rgroup,        // status          real group name
        *egroup,        // status          effective group name
        *sgroup,        // status          saved group name
        *fgroup,        // status          filesystem group name
        *cmd;           // stat,status     basename of executable file in call to exec(2)
    int
        rtprio,         // stat            real-time priority
        sched,          // stat            scheduling class
        pgrp,           // stat            process group id
        session,        // stat            session id
        nlwp,           // stat,status     number of threads, or 0 if no clue
        tgid,           // (special)       thread group ID, the POSIX PID (see also: tid)
        tty;            // stat            full device number of controlling terminal
        /* FIXME: int uids & gids should be uid_t or gid_t from pwd.h */
        uid_t euid; gid_t egid; // stat(),status effective
        uid_t ruid; gid_t rgid; // status        real
        uid_t suid; gid_t sgid; // status        saved
        uid_t fuid; gid_t fgid; // status        fs (used for file access only)
    int
        tpgid,          // stat            terminal process group id
        exit_signal,    // stat            might not be SIGCHLD
        processor;      // stat            current (or most recent?) CPU
    int
        oom_score,      // oom_score       (badness for OOM killer)
        oom_adj;        // oom_adj         (adjustment to OOM score)
    struct procps_ns ns; // (ns subdir)    inode number of namespaces
    char
        *sd_mach,       // n/a             systemd vm/container name
        *sd_ouid,       // n/a             systemd session owner uid
        *sd_seat,       // n/a             systemd login session seat
        *sd_sess,       // n/a             systemd login session id
        *sd_slice,      // n/a             systemd slice unit
        *sd_unit,       // n/a             systemd system unit id
        *sd_uunit;      // n/a             systemd user unit id
    char
        *dockerid,      // n/a             docker container id, abbreviated
        *dockerid_64,   // n/a             docker container id, full
        *lxcname,       // n/a             lxc container name
        *exe;           // exe             executable path + name
    int
        luid,           // loginuid        user id at login
        autogrp_id,     // autogroup       autogroup number (id)
        autogrp_nice,   // autogroup       autogroup nice value
        fds;            // fd              number of open files
} proc_t;

// PROCTAB: data structure holding the persistent information readproc needs
// from openproc().  The setup is intentionally similar to the dirent interface
// and other system table interfaces (utmp+wtmp come to mind).

#define PROCPATHLEN 64  // must hold /proc/2000222000/task/2000222000/cmdline

typedef struct PROCTAB {
    int         pidfd;          // FD for the /proc/<pid> directory
    int         taskfd;         // FD for the /proc/<pid>/tasks/<tid> directory
    DIR        *procfs;
//    char deBug0[64];
    DIR        *taskdir;  // for threads
//    char deBug1[64];
    pid_t       taskdir_user;  // for threads
    int(*finder)(struct PROCTAB *__restrict const, proc_t *__restrict const);
    proc_t*(*reader)(struct PROCTAB *__restrict const, proc_t *__restrict const);
    int(*taskfinder)(struct PROCTAB *__restrict const, const proc_t *__restrict const, proc_t *__restrict const);
    proc_t*(*taskreader)(struct PROCTAB *__restrict const, proc_t *__restrict const);
    pid_t      *pids;   // pids of the procs
    uid_t      *uids;   // uids of procs
    int         nuid;   // cannot really sentinel-terminate unsigned short[]
    int         i;  // generic
    int         hide_kernel;  // getenv LIBPROC_HIDE_KERNEL was set
    unsigned    flags;
} PROCTAB;


// openproc/readproctab:
//
// Return PROCTAB* / *proc_t[] or NULL on error ((probably) "/proc" cannot be
// opened.)  By default readproc will consider all processes as valid to parse
// and return, but not actually fill in the cmdline, environ, and /proc/#/statm
// derived memory fields.
//
// `flags' (a bitwise-or of PROC_* below) modifies the default behavior.  The
// "fill" options will cause more of the proc_t to be filled in.  The "filter"
// options all use the second argument as the pointer to a list of objects:
// process status', process id's, user id's.  The third
// argument is the length of the list (currently only used for lists of user
// id's since uid_t supports no convenient termination sentinel.)

#define PROC_FILLMEM         0x00000001 // read statm
#define PROC_FILLARG         0x00000002 // alloc and fill in `cmdline' vectors
#define PROC_FILLENV         0x00000004 // alloc and fill in `environ' vectors
#define PROC_FILLUSR         0x00000008 // resolve user id number -> user name
#define PROC_FILLGRP         0x00000010 // resolve group id number -> group name
#define PROC_FILLSTATUS      0x00000020 // read status
#define PROC_FILLSTAT        0x00000040 // read stat
#define PROC_FILLCGROUP      0x00000080 // alloc and fill in `cgroup` vectors
#define PROC_FILLOOM         0x00000100 // fill in proc_t oom_score and oom_adj
#define PROC_FILLNS          0x00000200 // fill in proc_t namespace information
#define PROC_FILLSYSTEMD     0x00000400 // fill in proc_t systemd information
#define PROC_FILL_LXC        0x00000800 // fill in proc_t lxcname, if possible
#define PROC_FILL_LUID       0x00001000 // fill in proc_t luid (login user id)
#define PROC_FILL_EXE        0x00002000 // fill in proc_t exe path + pgm name
#define PROC_FILLIO          0x00004000 // fill in proc_t io information
#define PROC_FILLSMAPS       0x00008000 // fill in proc_t smaps_rollup stuff

// consider only processes with one of the passed:
#define PROC_PID             0x00010000  // process id numbers ( 0 terminated  )
#define PROC_UID             0x00020000  // user id numbers    ( length needed )
// Note: the above 2 values must NOT change without also changing pids.h !!!

#define PROC_EDITCGRPCVT     0x00040000 // edit `cgroup' as regular string
#define PROC_EDITCMDLCVT     0x00080000 // edit `cmdline' as regular string
#define PROC_EDITENVRCVT     0x00100000 // edit `environ' as regular string

// these three also require the PROC_FILLSTATUS flag
#define PROC_FILL_OUSERS   ( 0x00200000 | PROC_FILLSTATUS ) // obtain other user names
#define PROC_FILL_OGROUPS  ( 0x00400000 | PROC_FILLSTATUS ) // obtain other group names
#define PROC_FILL_SUPGRP   ( 0x00800000 | PROC_FILLSTATUS ) // obtain supplementary group names

// and let's put new flags here ...
#define PROC_FILLAUTOGRP     0x01000000 // fill in proc_t autogroup stuff
#define PROC_FILL_DOCKER     0x02000000 // fill in proc_t dockerid, if possible
#define PROC_FILL_FDS        0x04000000 // fill in proc_t fds

// it helps to give app code a few spare bits
#define PROC_SPARE_1         0x10000000
#define PROC_SPARE_2         0x20000000
#define PROC_SPARE_3         0x40000000
#define PROC_SPARE_4         0x80000000

/* available PROC bits ...   0x.8......
   ( when this one is used, we'll need a 'flags2' addition to PROCTAB ) */

// Function definitions
// Initialize a PROCTAB structure holding needed call-to-call persistent data
PROCTAB *openproc(unsigned flags, ... /* pid_t *| uid_t *| dev_t *| char *[, int n] */ );
// Retrieve the next process or task matching the criteria set by the openproc().
//
// Note: When NULL is used as the readproc 'p' or readeither 'x'
//       parameter, the library will allocate the necessary proc_t storage.
//
//       Alternatively, you may provide your own reusable buffer address
//       in which case that buffer *MUST* be initialized to zero one time
//       only before first use.  Thereafter, the library will manage such
//       a passed proc_t, freeing any additional acquired memory associated
//       with the previous process or thread.
proc_t *readproc(PROCTAB *__restrict const PT, proc_t *__restrict p);
proc_t *readeither(PROCTAB *__restrict const PT, proc_t *__restrict x);
int look_up_our_self(void);
void closeproc(PROCTAB *PT);
char **vectorize_this_str(const char *src);

struct utlbuf_s;
struct docker_ids;
char *lxc_containers(struct utlbuf_s *ub);
struct docker_ids *docker_containers(struct utlbuf_s *ub);

#endif
