1 Star 0 Fork 0

lurenchina/atop

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
showgeneric.c 88.23 KB
一键复制 编辑 原始数据 按行查看 历史
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141
/*
** ATOP - System & Process Monitor
**
** The program 'atop' offers the possibility to view the activity of
** the system on system-level as well as process-level.
**
** This source-file contains the print-functions to visualize the calculated
** figures.
** ==========================================================================
** Author: Gerlof Langeveld
** E-mail: gerlof.langeveld@atoptool.nl
** Date: November 1996
** LINUX-port: June 2000
** --------------------------------------------------------------------------
** Copyright (C) 2000-2010 Gerlof Langeveld
**
** This program is free software; you can redistribute it and/or modify it
** under the terms of the GNU General Public License as published by the
** Free Software Foundation; either version 2, or (at your option) any
** later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program; if not, write to the Free Software
** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
** --------------------------------------------------------------------------
*/
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/utsname.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdarg.h>
#include <curses.h>
#include <pwd.h>
#include <grp.h>
#include <regex.h>
#include <locale.h>
#include <unistd.h>
#include <sys/select.h>
#include "atop.h"
#include "photoproc.h"
#include "photosyst.h"
#include "cgroups.h"
#include "showgeneric.h"
#include "showlinux.h"
static struct pselection procsel = {"", {USERSTUB, }, {0,},
"", 0, { 0, }, "", 0, { 0, }, "", "" };
static struct sselection syssel;
static void showhelp(int);
static int fixedhead; /* boolean: fixate header-lines */
static int sysnosort; /* boolean: suppress sort of resources */
static int threadsort; /* boolean: sort threads per process */
static int avgval; /* boolean: average values i.s.o. total */
static int suppressexit; /* boolean: suppress terminated processes */
static char showtype = MPROCGEN;
static char showorder = MSORTCPU;
static int maxcpulines = 999; /* maximum cpu lines */
static int maxgpulines = 999; /* maximum gpu lines */
static int maxdsklines = 999; /* maximum disk lines */
static int maxmddlines = 999; /* maximum MDD lines */
static int maxlvmlines = 999; /* maximum LVM lines */
static int maxintlines = 999; /* maximum interface lines */
static int maxifblines = 999; /* maximum infinibnd lines */
static int maxnfslines = 999; /* maximum nfs mount lines */
static int maxcontlines = 999; /* maximum container lines */
static int maxnumalines = 999; /* maximum numa lines */
static int maxllclines = 999; /* maximum llc lines */
static short colorinfo = COLOR_GREEN;
static short coloralmost = COLOR_CYAN;
static short colorcrit = COLOR_RED;
static short colorthread = COLOR_YELLOW;
static char winchange;
static char keywaiting; // set after key has been pushed back
int paused; // boolean: currently in pause-mode
int cgroupdepth = 7; // default: cgroups without processes
static int cumusers(struct tstat **, struct tstat *, int);
static int cumprogs(struct tstat **, struct tstat *, int);
static int cumconts(struct tstat **, struct tstat *, int);
static void accumulate(struct tstat *, struct tstat *);
static int procsuppress(struct tstat *, struct pselection *);
static void limitedlines(void);
static long getnumval(char *, long, int);
static void getsigwinch(int);
static void generic_init(void);
static char text_samp(time_t, int, struct devtstat *, struct sstat *,
struct cgchainer *, int, int, unsigned int, char);
static int (*procsort[])(const void *, const void *) = {
[MSORTCPU&0x1f]=compcpu,
[MSORTMEM&0x1f]=compmem,
[MSORTDSK&0x1f]=compdsk,
[MSORTNET&0x1f]=compnet,
[MSORTGPU&0x1f]=compgpu,
};
extern detail_printpair ownprocs[];
/*
** global: incremented by -> key and decremented by <- key
*/
int startoffset;
/*
** main function to handle sample generically
** to show flat text, full screen text or bar graphs
*/
char
generic_samp(time_t curtime, int nsecs,
struct devtstat *devtstat, struct sstat *sstat,
struct cgchainer *cstats, int ncgroups, int npids,
int nexit, unsigned int noverflow, char flag)
{
static char firstcall = 1;
char retval, sorted = 0;
if (firstcall)
{
generic_init();
firstcall = 0;
}
while (1)
{
if (displaymode == 'T') // text mode?
{
// show sample and wait for input or timer expiration
//
switch (retval = text_samp(curtime, nsecs,
devtstat, sstat, cstats, ncgroups,
nexit, noverflow, flag))
{
case MBARGRAPH:
displaymode = 'D';
break;
default:
return retval;
}
sorted = 1; // resources have been sorted by text mode
}
if (displaymode == 'D') // draw mode?
{
// show sample and wait for input or timer expiration
//
switch (retval = draw_samp(curtime, nsecs, sstat, flag, sorted))
{
case MBARGRAPH: // just switch to text mode
displaymode = 'T';
break;
case MCGROUPS: // switch to text mode: cgroups
if (supportflags & CGROUPV2)
showtype = MCGROUPS;
else
showtype = MPROCGEN;
displaymode = 'T';
break;
case MPROCGEN: // switch to text mode: generic
showtype = MPROCGEN;
if (showorder != MSORTAUTO)
showorder = MSORTCPU;
displaymode = 'T';
break;
case MPROCMEM: // switch to text mode: memory
showtype = MPROCMEM;
if (showorder != MSORTAUTO)
showorder = MSORTMEM;
displaymode = 'T';
break;
case MPROCDSK: // switch to text mode: disk
showtype = MPROCDSK;
if (showorder != MSORTAUTO)
showorder = MSORTDSK;
displaymode = 'T';
break;
case MPROCNET: // switch to text mode: network
if (supportflags & NETATOP || supportflags & NETATOPBPF)
{
showtype = MPROCNET;
if (showorder != MSORTAUTO)
showorder = MSORTNET;
}
else
{
showtype = MPROCGEN;
showorder = MSORTCPU;
}
displaymode = 'T';
break;
case MPROCGPU: // switch to text mode: GPU
if (supportflags & GPUSTAT)
{
showtype = MPROCGPU;
if (showorder != MSORTAUTO)
showorder = MSORTGPU;
}
else
{
showtype = MPROCGEN;
showorder = MSORTCPU;
}
displaymode = 'T';
break;
case MPROCSCH: // switch to text mode: scheduling
showtype = MPROCSCH;
if (showorder != MSORTAUTO)
showorder = MSORTCPU;
displaymode = 'T';
break;
case MPROCVAR: // switch to text mode: various
showtype = MPROCVAR;
displaymode = 'T';
break;
case MPROCARG: // switch to text mode: arguments
showtype = MPROCARG;
displaymode = 'T';
break;
default:
return retval;
}
}
}
}
/*
** print the deviation-counters on process level, cgroups level and
** system level in text mode
*/
static char
text_samp(time_t curtime, int nsecs,
struct devtstat *devtstat, struct sstat *sstat,
struct cgchainer *cgchainers, int ncgroups,
int nexit, unsigned int noverflow, char flag)
{
register int i, curline, statline, nproc;
int firstitem=0, slistsz, alistsz, killpid, killsig;
int lastchar;
char format1[16], format2[16], branchtime[32];
char *statmsg = NULL, statbuf[80], genline[80];
char *lastsortp, curorder, autoorder;
char buf[33];
struct passwd *pwd;
struct syscap syscap;
fd_set readfds;
char eventbuf[1024];
int nrfds;
/*
** number of entries in the active list of cgroups/tasks
** to be displayed
*/
int ncurlist = 0;
/*
** cgroupsel points to the merged list of cgchainer pointers (to cgroups)
** and tstat pointers (to processes), representing the cgroups information
** to be displayed (for cgroups visualization);
** ncurlist indicates the number of entries in this list
**
** this list will only be allocated 'lazy' only when
** cgroups visualization is requested
**
** cgroupsort refers to a list with cgchainer pointers in
** sorted order according to the current showorder
*/
struct cglinesel *cgroupsel = 0;
struct cgchainer **cgroupsort = 0;
char cstatdeviate = ' ', cstatdepth = ' ', cstatorder = ' ';
/*
** curlist points to the active list of tstat pointers that
** should be displayed; ncurlist indicates the number of entries in
** this list
*/
struct tstat **curlist;
/*
** tXcumlist is a list of tstat structs holding one entry
** per accumulated (per user or per program) group of processes
**
** Xcumlist contains the pointers to all structs in tXcumlist
**
** these lists will only be allocated 'lazy'
** only when accumulation is requested
*/
struct tstat *tpcumlist = 0; // per program accumulation
struct tstat **pcumlist = 0;
int npcum = 0;
char plastorder = 0;
struct tstat *tucumlist = 0; // per user accumulation
struct tstat **ucumlist = 0;
int nucum = 0;
char ulastorder = 0;
struct tstat *tccumlist = 0; // per container/pod accumulation
struct tstat **ccumlist = 0;
int nccum = 0;
char clastorder = 0;
/*
** tsklist contains the pointers to all structs in tstat
** sorted on process with the related threads immediately
** following the process
**
** this list will be allocated 'lazy'
*/
struct tstat **tsklist = 0;
int ntsk = 0;
char tlastorder = 0;
char zipagain = 0;
char tdeviate = 0;
/*
** sellist contains the pointers to the structs in tstat
** that are currently selected on basis of a particular
** username (regexp), program name (regexp), container/pod name
** or suppressed terminated procs
**
** this list will be allocated 'lazy'
*/
struct tstat **sellist = 0;
int nsel = 0;
char slastorder = 0;
char threadallowed = 0;
startoffset = 0;
/*
** compute the total capacity of this system for the
** four main resources
*/
totalcap(&syscap, sstat, devtstat->procactive, devtstat->nprocactive);
/*
** sort per-cpu statistics on busy percentage
** sort per-logical-volume statistics on busy percentage
** sort per-multiple-device statistics on busy percentage
** sort per-disk statistics on busy percentage
** sort per-interface statistics on busy percentage (if known)
*/
if (!sysnosort)
{
if (sstat->cpu.nrcpu > 1 && maxcpulines > 0)
qsort(sstat->cpu.cpu, sstat->cpu.nrcpu,
sizeof sstat->cpu.cpu[0], cpucompar);
if (sstat->gpu.nrgpus > 1 && maxgpulines > 0)
qsort(sstat->gpu.gpu, sstat->gpu.nrgpus,
sizeof sstat->gpu.gpu[0], gpucompar);
if (sstat->dsk.nlvm > 1 && maxlvmlines > 0)
qsort(sstat->dsk.lvm, sstat->dsk.nlvm,
sizeof sstat->dsk.lvm[0], diskcompar);
if (sstat->dsk.nmdd > 1 && maxmddlines > 0)
qsort(sstat->dsk.mdd, sstat->dsk.nmdd,
sizeof sstat->dsk.mdd[0], diskcompar);
if (sstat->dsk.ndsk > 1 && maxdsklines > 0)
qsort(sstat->dsk.dsk, sstat->dsk.ndsk,
sizeof sstat->dsk.dsk[0], diskcompar);
if (sstat->intf.nrintf > 1 && maxintlines > 0)
qsort(sstat->intf.intf, sstat->intf.nrintf,
sizeof sstat->intf.intf[0], intfcompar);
if (sstat->ifb.nrports > 1 && maxifblines > 0)
qsort(sstat->ifb.ifb, sstat->ifb.nrports,
sizeof sstat->ifb.ifb[0], ifbcompar);
if (sstat->nfs.nfsmounts.nrmounts > 1 && maxnfslines > 0)
qsort(sstat->nfs.nfsmounts.nfsmnt,
sstat->nfs.nfsmounts.nrmounts,
sizeof sstat->nfs.nfsmounts.nfsmnt[0],
nfsmcompar);
if (sstat->cfs.nrcontainer > 1 && maxcontlines > 0)
qsort(sstat->cfs.cont, sstat->cfs.nrcontainer,
sizeof sstat->cfs.cont[0], contcompar);
if (sstat->memnuma.nrnuma > 1 && maxnumalines > 0)
qsort(sstat->memnuma.numa, sstat->memnuma.nrnuma,
sizeof sstat->memnuma.numa[0], memnumacompar);
if (sstat->cpunuma.nrnuma > 1 && maxnumalines > 0)
qsort(sstat->cpunuma.numa, sstat->cpunuma.nrnuma,
sizeof sstat->cpunuma.numa[0], cpunumacompar);
if (sstat->llc.nrllcs > 1 && maxllclines > 0)
qsort(sstat->llc.perllc, sstat->llc.nrllcs,
sizeof sstat->llc.perllc[0], llccompar);
}
/*
** loop in which the system resources and the list of active
** processes are shown; the loop will be preempted by receiving
** a timer-signal or when the trigger-button is pressed.
*/
while (1)
{
curline = 1;
genline[0] = '\0';
/*
** prepare screen or file output for new sample
*/
if (screen)
werase(stdscr);
else
printf("\n\n");
/*
** print general headerlines
*/
convdate(curtime, format1); /* date to ascii string */
convtime(curtime, format2); /* time to ascii string */
if (screen)
attron(A_REVERSE);
int seclen = val2elapstr(nsecs, buf);
int lenavail = (screen ? COLS : linelen) -
60 - seclen - utsnodenamelen;
int len1 = lenavail / 3;
if (len1 <= 0)
len1 = 1;
int len2 = lenavail - len1 - len1;
printg("ATOP - %s%*s%s %s %s %*s"
"%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%*s%s elapsed",
utsname.nodename, len1, "",
format1, format2, " ", len1, "",
threadview ? MTHREAD : '-',
threadsort ? MTHRSORT : '-',
fixedhead ? MSYSFIXED : '-',
sysnosort ? MSYSNOSORT : '-',
deviatonly ? '-' : MALLACTIVE,
usecolors ? '-' : MCOLORS,
avgval ? MAVGVAL : '-',
calcpss ? MCALCPSS : '-',
getwchan ? MGETWCHAN : '-',
suppressexit ? MSUPEXITS : '-',
procsel.userid[0] != USERSTUB ? MSELUSER : '-',
procsel.prognamesz ? MSELPROC : '-',
procsel.utsname[0] ? MSELCONT : '-',
procsel.pid[0] != 0 ? MSELPID : '-',
procsel.argnamesz ? MSELARG : '-',
procsel.states[0] ? MSELSTATE : '-',
syssel.lvmnamesz +
syssel.dsknamesz +
syssel.itfnamesz ? MSELSYS : '-',
cgroupdepth+0x30,
len2, "", buf);
if (screen)
attroff(A_REVERSE);
else
printg("\n");
if (screen && paused)
{
if (usecolors)
attron(COLOR_PAIR(FGCOLORBORDER));
attron(A_REVERSE);
mvprintw(0, 27 + utsnodenamelen + len1, "PAUSED");
attroff(A_REVERSE);
if (usecolors)
attroff(COLOR_PAIR(FGCOLORBORDER));
}
/*
** print cumulative system- and user-time for all processes
*/
pricumproc(sstat, devtstat, nexit, noverflow, avgval, nsecs);
if (noverflow)
{
snprintf(statbuf, sizeof statbuf,
"Only %d terminated processes handled "
"-- %u skipped!", nexit, noverflow);
statmsg = statbuf;
}
curline=2;
/*
** print other lines of system-wide statistics
*/
if (showorder == MSORTAUTO)
autoorder = MSORTCPU;
else
autoorder = showorder;
curline = prisyst(sstat, curline, nsecs, avgval,
fixedhead, &syssel, &autoorder,
maxcpulines, maxgpulines, maxdsklines,
maxmddlines, maxlvmlines,
maxintlines, maxifblines, maxnfslines,
maxcontlines, maxnumalines, maxllclines);
/*
** if system-wide statistics do not fit,
** limit the number of variable resource lines
** and try again
*/
if (screen && curline+2 > LINES)
{
curline = 2;
move(curline, 0);
clrtobot();
move(curline, 0);
limitedlines();
curline = prisyst(sstat, curline, nsecs, avgval,
fixedhead, &syssel, &autoorder,
maxcpulines, maxgpulines,
maxdsklines, maxmddlines,
maxlvmlines, maxintlines,
maxifblines, maxnfslines,
maxcontlines, maxnumalines,
maxllclines);
/*
** if system-wide statistics still do not fit,
** the window is really to small
*/
if (curline+2 > LINES)
{
endwin(); // finish curses interface
fprintf(stderr,
"Not enough screen-lines available "
"(need at least %d lines)\n", curline+2);
fprintf(stderr, "Please resize window....\n");
cleanstop(1);
}
else
{
statmsg = "Number of variable resources"
" limited to fit in this window";
}
}
statline = curline;
if (screen)
move(curline, 0);
if (statmsg)
{
if (screen)
{
clrtoeol();
if (usecolors)
attron(COLOR_PAIR(FGCOLORINFO));
}
printg(statmsg);
if (screen)
{
if (usecolors)
attroff(COLOR_PAIR(FGCOLORINFO));
}
statmsg = NULL;
}
else
{
if (flag&RRBOOT)
{
char *initmsg = "*** System and Process Activity since Boot ***";
char *viewmsg;
if (rawreadflag)
{
if (twinpid)
viewmsg = "Twin mode";
else
viewmsg = "Rawfile view";
}
else
{
if (rootprivs())
viewmsg = "Unrestricted view (privileged)";
else
viewmsg = "Restricted view (unprivileged)";
}
if (screen)
{
if (usecolors)
attron(COLOR_PAIR(FGCOLORINFO));
}
printg(initmsg);
if (screen)
{
if (usecolors)
attroff(COLOR_PAIR(FGCOLORINFO));
printg("%*s", COLS - strlen(initmsg)
- strlen(viewmsg),
" ");
}
else
{
printg("%*s", 80 - strlen(initmsg)
- strlen(viewmsg),
" ");
}
if (screen)
{
if (usecolors)
attron(COLOR_PAIR(FGCOLORALMOST));
}
printg(viewmsg);
if (screen)
{
if (usecolors)
attroff(COLOR_PAIR(FGCOLORALMOST));
}
}
}
if (showtype != MCGROUPS)
{
/*
** select the required list with tasks to be shown
**
** if cumulative figures required, accumulate resource
** consumption of all processes in the current list
*/
switch (showtype)
{
case MCUMUSER:
threadallowed = 0;
if (ucumlist) /* previous list still available? */
{
free(ucumlist);
free(tucumlist);
ulastorder = 0;
}
if (deviatonly)
nproc = devtstat->nprocactive;
else
nproc = devtstat->nprocall;
/*
** allocate space for new (temporary) list with
** one entry per user (list has worst-case size)
*/
tucumlist = calloc(sizeof(struct tstat), nproc);
ucumlist = malloc(sizeof(struct tstat *) * nproc);
ptrverify(tucumlist,
"Malloc failed for %d ucum procs\n", nproc);
ptrverify(ucumlist,
"Malloc failed for %d ucum ptrs\n", nproc);
for (i=0; i < nproc; i++)
{
/* fill pointers */
ucumlist[i] = tucumlist+i;
}
nucum = cumusers(deviatonly ?
devtstat->procactive :
devtstat->procall,
tucumlist, nproc);
curlist = ucumlist;
ncurlist = nucum;
lastsortp = &ulastorder;
break;
case MCUMPROC:
threadallowed = 0;
if (pcumlist) /* previous list still available? */
{
free(pcumlist);
free(tpcumlist);
plastorder = 0;
}
if (deviatonly)
nproc = devtstat->nprocactive;
else
nproc = devtstat->nprocall;
/*
** allocate space for new (temporary) list with
** one entry per program (list has worst-case size)
*/
tpcumlist = calloc(sizeof(struct tstat), nproc);
pcumlist = malloc(sizeof(struct tstat *) * nproc);
ptrverify(tpcumlist,
"Malloc failed for %d pcum procs\n", nproc);
ptrverify(pcumlist,
"Malloc failed for %d pcum ptrs\n", nproc);
for (i=0; i < nproc; i++)
{
/* fill pointers */
pcumlist[i] = tpcumlist+i;
}
npcum = cumprogs(deviatonly ?
devtstat->procactive :
devtstat->procall,
tpcumlist, nproc);
curlist = pcumlist;
ncurlist = npcum;
lastsortp = &plastorder;
break;
case MCUMCONT:
threadallowed = 0;
if (ccumlist) /* previous list still available? */
{
free(ccumlist);
free(tccumlist);
clastorder = 0;
}
if (deviatonly)
nproc = devtstat->nprocactive;
else
nproc = devtstat->nprocall;
/*
** allocate space for new (temporary) list with
** one entry per user (list has worst-case size)
*/
tccumlist = calloc(sizeof(struct tstat), nproc);
ccumlist = malloc(sizeof(struct tstat *) * nproc);
ptrverify(tccumlist,
"Malloc failed for %d ccum procs\n", nproc);
ptrverify(ccumlist,
"Malloc failed for %d ccum ptrs\n", nproc);
for (i=0; i < nproc; i++)
{
/* fill pointers */
ccumlist[i] = tccumlist+i;
}
nccum = cumconts(deviatonly ?
devtstat->procactive :
devtstat->procall,
tccumlist, nproc);
curlist = ccumlist;
ncurlist = nccum;
lastsortp = &clastorder;
break;
default:
threadallowed = 1;
if (deviatonly && showtype != MPROCMEM &&
showorder != MSORTMEM )
{
curlist = devtstat->procactive;
ncurlist = devtstat->nprocactive;
}
else
{
curlist = devtstat->procall;
ncurlist = devtstat->nprocall;
}
lastsortp = &tlastorder;
if ( procsel.userid[0] == USERSTUB &&
!procsel.prognamesz &&
!procsel.utsname[0] &&
!procsel.states[0] &&
!procsel.argnamesz &&
!procsel.pid[0] &&
!suppressexit )
/* no selection wanted */
break;
/*
** selection specified for tasks:
** create new (worst case) pointer list if needed
*/
if (sellist) // remove previous list if needed
free(sellist);
sellist = malloc(sizeof(struct tstat *) * ncurlist);
ptrverify(sellist,
"Malloc failed for %d select ptrs\n", ncurlist);
for (i=nsel=0; i < ncurlist; i++)
{
if (procsuppress(*(curlist+i), &procsel))
continue;
if (curlist[i]->gen.state == 'E' &&
suppressexit )
continue;
sellist[nsel++] = curlist[i];
}
curlist = sellist;
ncurlist = nsel;
tlastorder = 0; /* new sort and zip normal view */
slastorder = 0; /* new sort and zip now */
lastsortp = &slastorder;
}
/*
** sort the list in required order
** (default CPU-consumption) and print the list
*/
if (showorder == MSORTAUTO)
curorder = autoorder;
else
curorder = showorder;
/*
** determine size of list to be displayed
*/
if (screen)
slistsz = LINES-curline-2;
else
if (threadview && threadallowed)
slistsz = devtstat->ntaskactive;
else
slistsz = ncurlist;
if (ncurlist > 0 && slistsz > 0)
{
/*
** if sorting order is changed, sort again
*/
if (*lastsortp != curorder)
{
qsort(curlist, ncurlist,
sizeof(struct tstat *),
procsort[(int)curorder&0x1f]);
*lastsortp = curorder;
zipagain = 1;
}
if (threadview && threadallowed)
{
int ntotal, j, t;
if (deviatonly && showtype != MPROCMEM &&
showorder != MSORTMEM )
ntotal = devtstat->ntaskactive;
else
ntotal = devtstat->ntaskall;
/*
** check if existing pointer list still usable
** if not, allocate new pointer list to be able
** to zip process list with references to threads
*/
if (!tsklist || ntsk != ntotal ||
tdeviate != deviatonly)
{
if (tsklist)
free(tsklist); // remove current
tsklist = malloc(sizeof(struct tstat *)
* ntotal);
ptrverify(tsklist,
"Malloc failed for %d taskptrs\n",
ntotal);
ntsk = ntotal;
tdeviate = deviatonly;
zipagain = 1;
}
else
j = ntotal;
/*
** zip process list with thread list
*/
if (zipagain)
{
struct tstat *tall = devtstat->taskall;
struct tstat *pcur;
long int n;
for (i=j=0; i < ncurlist; i++)
{
pcur = curlist[i];
tsklist[j++] = pcur; // take process
n = j; // start index of threads
for (t = pcur - tall + 1;
t < devtstat->ntaskall &&
pcur->gen.tgid &&
pcur->gen.tgid ==
(tall+t)->gen.tgid;
t++)
{
if (procsuppress(tall+t, &procsel))
continue;
if (deviatonly &&
showtype != MPROCMEM &&
showorder != MSORTMEM )
{
if (!(tall+t)->gen.wasinactive)
tsklist[j++] = tall+t;
}
else
{
tsklist[j++] = tall+t;
}
}
if (threadsort && j-n > 0 &&
curorder != MSORTMEM)
{
qsort(&tsklist[n], j-n,
sizeof(struct tstat *),
procsort[(int)curorder&0x1f]);
}
}
zipagain = 0;
}
curlist = tsklist;
ncurlist = j;
}
/*
** print the header
** first determine the column-header for the current
** sorting order of processes
*/
if (screen)
{
attron(A_REVERSE);
move(curline+1, 0);
}
prihead(firstitem/slistsz+1, (ncurlist-1)/slistsz+1,
&showtype, &curorder,
showorder == MSORTAUTO ? 1 : 0,
sstat->cpu.nrcpu);
if (screen)
{
attroff(A_REVERSE);
clrtobot();
}
/*
** print the list
*/
priproc(curlist, firstitem, ncurlist, curline+2,
firstitem/slistsz+1, (ncurlist-1)/slistsz+1,
showtype, curorder, &syscap, nsecs, avgval);
}
}
else // MCGROUPS: print cgroups
{
/*
** sort the list in required order
** (default CPU-consumption) and print the list
*/
if (showorder == MSORTAUTO)
curorder = autoorder;
else
curorder = showorder;
/*
** make new list with a selection (if needed) of cgroups
** merged with processes related to those cgroups
*/
if (cgroupsel == NULL || // not created yet
cstatdeviate != deviatonly || // or not the right contents?
cstatdepth != cgroupdepth ||
cstatorder != curorder )
{
struct tstat **tp;
/*
** get sorted list of pointers to the cgchainer structs
**
** when a list has been created already that is
** not suitable, first remove it
*/
if (cgroupsort)
free(cgroupsort);
cgroupsort = cgsort(cgchainers, ncgroups, curorder);
/*
** determine required list of processes (all or active)
** for memory usage even non-active processes are taken
*/
if (deviatonly && curorder != MSORTMEM)
{
nproc = devtstat->nprocactive;
tp = devtstat->procactive;
}
else
{
nproc = devtstat->nprocall;
tp = devtstat->procall;
}
/*
** when a selection list has been created
** already that is not suitable, first remove it
*/
if (cgroupsel)
free(cgroupsel);
/*
** create new merged list of cgroups and processes
*/
ncurlist = mergecgrouplist(&cgroupsel, cgroupdepth,
cgroupsort, ncgroups, tp, nproc, curorder);
/*
** preserve list characteristics
*/
cstatdeviate = deviatonly;
cstatdepth = cgroupdepth;
cstatorder = curorder;
}
/*
** determine size of list to be displayed
*/
if (screen)
slistsz = LINES-curline-2;
else
slistsz = ncurlist;
if (ncurlist > 0 && slistsz > 0)
{
/*
** print the header
*/
if (screen)
{
attron(A_REVERSE);
move(curline+1, 0);
}
prihead(firstitem/slistsz+1, (ncurlist-1)/slistsz+1,
&showtype, &curorder,
curorder == MSORTAUTO ? 1 : 0,
sstat->cpu.nrcpu);
if (screen)
{
attroff(A_REVERSE);
clrtobot();
}
/*
** print the list of cgroups
*/
pricgroup(cgroupsel, firstitem, ncurlist, curline+2,
firstitem/slistsz+1, (ncurlist-1)/slistsz+1,
&syscap, nsecs, avgval);
}
}
alistsz = ncurlist; /* preserve size of active list */
/*
** in case of writing to a terminal, the user can also enter
** a character to switch options, etc
*/
if (screen)
{
/*
** refresh screen output generated sofar
*/
move(statline, 0);
refresh();
if (twinpid && !keywaiting) // twin mode?
{
struct sigaction sigact, sigold;
/*
** catch window size changes while in select
*/
memset(&sigact, 0, sizeof sigact);
sigact.sa_handler = getsigwinch;
sigaction(SIGWINCH, &sigact, &sigold);
winchange = 0;
/*
** await input character from keyboard, or
** inotify trigger in case of twin mode, or
** interval timer expiration
*/
FD_ZERO(&readfds);
FD_SET(0, &readfds);
if (!paused && fdinotify != -1) // twin mode?
{
FD_SET(fdinotify, &readfds);
nrfds = fdinotify + 1;
}
else
{
nrfds = 1;
}
switch (select(nrfds, &readfds, (fd_set *)0,
(fd_set *)0, (struct timeval *)0))
{
case -1:
/*
** window change or timer expiration?
*/
if (winchange)
{
// window change: set new dimensions
struct winsize w;
ioctl(0, TIOCGWINSZ, &w);
resizeterm(w.ws_row, w.ws_col);
lastchar = KEY_RESIZE;
}
else
{
// time interrupt
lastchar = 0;
}
break;
default:
/*
** inotify trigger that new sample has been written?
** pretend as if the 't' key has been pressed
** to read that sample
**
** otherwise: read keystroke from keyboard
*/
if (FD_ISSET(fdinotify, &readfds))
{
read(fdinotify, eventbuf, sizeof eventbuf);
lastchar = MSAMPNEXT;
}
else
{
lastchar = getch();
}
}
sigaction(SIGWINCH, &sigold, (struct sigaction *)0);
}
else // no twin mode: neutral state is getch()
{
lastchar = getch();
keywaiting = 0;
}
switch (lastchar)
{
/*
** timer expired
*/
case ERR:
case 0:
timeout(0);
(void) getch();
timeout(-1);
goto free_and_return;
/*
** stop it
*/
case MQUIT:
move(LINES-1, 0);
clrtoeol();
refresh();
cleanstop(0);
/*
** switch to bar graph mode
*/
case MBARGRAPH:
erase();
refresh();
goto free_and_return;
/*
** manual trigger for next sample
*/
case MSAMPNEXT:
if (paused && !twinpid)
{
beep();
break;
}
getalarm(0);
goto free_and_return;
/*
** manual trigger for previous sample
*/
case MSAMPPREV:
if (!rawreadflag)
{
statmsg = "Only allowed in twin mode or "
"when viewing raw file!";
beep();
break;
}
if (!paused && twinpid)
{
paused=1; // implicit pause in twin mode
clrtoeol();
refresh();
}
goto free_and_return;
/*
** branch to certain time stamp
*/
case MSAMPBRANCH:
if (!rawreadflag)
{
statmsg = "Only allowed in twin mode or "
"when viewing raw file!";
beep();
break;
}
if (!paused && twinpid)
{
paused=1; // implicit pause in twin mode
clrtoeol();
refresh();
}
echo();
move(statline, 0);
clrtoeol();
printw("Enter new time "
"(format [YYYYMMDD]hhmm[ss]): ");
branchtime[0] = '\0';
scanw("%31s\n", branchtime);
noecho();
begintime = cursortime;
if ( !getbranchtime(branchtime, &begintime) )
{
move(statline, 0);
clrtoeol();
statmsg = "Wrong time format!";
beep();
begintime = 0;
break;
}
goto free_and_return;
/*
** sort order automatically depending on
** most busy resource
*/
case MSORTAUTO:
showorder = MSORTAUTO;
firstitem = 0;
break;
/*
** sort in cpu-activity order
*/
case MSORTCPU:
showorder = MSORTCPU;
firstitem = 0;
break;
/*
** sort in memory-consumption order
*/
case MSORTMEM:
showorder = MSORTMEM;
firstitem = 0;
break;
/*
** sort in disk-activity order
*/
case MSORTDSK:
showorder = MSORTDSK;
firstitem = 0;
break;
/*
** sort in network-activity order
*/
case MSORTNET:
if ( !(supportflags & NETATOP || supportflags & NETATOPBPF))
{
statmsg = "Module 'netatop' or 'netatop-bpf' not "
"active or no root privs";
break;
}
showorder = MSORTNET;
firstitem = 0;
break;
/*
** sort in gpu-activity order
*/
case MSORTGPU:
if ( !(supportflags & GPUSTAT) )
{
statmsg = "No GPU activity figures "
"available; request ignored!";
break;
}
showorder = MSORTGPU;
firstitem = 0;
break;
/*
** general figures per process
*/
case MPROCGEN:
showtype = MPROCGEN;
if (showorder != MSORTAUTO)
showorder = MSORTCPU;
firstitem = 0;
break;
/*
** memory-specific figures per process
*/
case MPROCMEM:
showtype = MPROCMEM;
if (showorder != MSORTAUTO)
showorder = MSORTMEM;
firstitem = 0;
break;
/*
** disk-specific figures per process
*/
case MPROCDSK:
showtype = MPROCDSK;
if (showorder != MSORTAUTO)
showorder = MSORTDSK;
firstitem = 0;
break;
/*
** network-specific figures per process
*/
case MPROCNET:
if ( !(supportflags & NETATOP || supportflags & NETATOPBPF) )
{
statmsg = "Module 'netatop' or 'netatop-bpf' not "
"active or no root privs; "
"request ignored!";
break;
}
showtype = MPROCNET;
if (showorder != MSORTAUTO)
showorder = MSORTNET;
firstitem = 0;
break;
/*
** GPU-specific figures per process
*/
case MPROCGPU:
if ( !(supportflags & GPUSTAT) )
{
statmsg = "No GPU activity figures "
"available (atopgpud might "
"not be running); "
"request ignored!";
break;
}
showtype = MPROCGPU;
if (showorder != MSORTAUTO)
showorder = MSORTGPU;
firstitem = 0;
break;
/*
** various info per process
*/
case MPROCVAR:
showtype = MPROCVAR;
firstitem = 0;
break;
/*
** command line per process
*/
case MPROCARG:
showtype = MPROCARG;
firstitem = 0;
break;
/*
** cgroup v2 info per process
*/
case MCGROUPS:
if ( !(supportflags & CGROUPV2) )
{
statmsg = "No cgroup v2 metrics "
"available; request ignored!";
break;
}
showtype = MCGROUPS;
firstitem = 0;
break;
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
cgroupdepth = lastchar - 0x30;
firstitem = 0;
break;
/*
** own defined output per process
*/
case MPROCOWN:
if (! ownprocs[0].pf)
{
statmsg = "Own process line is not "
"configured in rc-file; "
"request ignored";
break;
}
showtype = MPROCOWN;
firstitem = 0;
break;
/*
** scheduling-values per process
*/
case MPROCSCH:
showtype = MPROCSCH;
if (showorder != MSORTAUTO)
showorder = MSORTCPU;
firstitem = 0;
break;
/*
** accumulated resource consumption per user
*/
case MCUMUSER:
statmsg = "Consumption per user; use 'a' to "
"toggle between all/active processes";
showtype = MCUMUSER;
firstitem = 0;
break;
/*
** accumulated resource consumption per program
*/
case MCUMPROC:
statmsg = "Consumption per program; use 'a' to "
"toggle between all/active processes";
showtype = MCUMPROC;
firstitem = 0;
break;
/*
** accumulated resource consumption per container/pod
*/
case MCUMCONT:
if (!rawreadflag && !rootprivs())
{
statmsg = "No privileges to get "
"container/pod identity!";
break;
}
statmsg = "Consumption per container/pod; use 'a' to "
"toggle between all/active processes";
showtype = MCUMCONT;
firstitem = 0;
break;
/*
** help wanted?
*/
case MHELP1:
case MHELP2:
alarm(0); /* stop the clock */
move(1, 0);
clrtobot(); /* blank the screen */
refresh();
showhelp(2);
move(statline, 0);
if (interval && !paused && !rawreadflag)
alarm(1); /* force new sample */
firstitem = 0;
if (twinpid) // twin mode?
{
// jump to last sample after awaiting input
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** send signal to process
*/
case MKILLPROC:
if (rawreadflag && !twinpid)
{
statmsg = "Not possible when viewing "
"raw file!";
beep();
break;
}
alarm(0); /* stop the clock */
killpid = getnumval("Pid of process: ",
0, statline);
switch (killpid)
{
case 0:
case -1:
break;
case 1:
statmsg = "Sending signal to pid 1 not "
"allowed!";
beep();
break;
default:
clrtoeol();
killsig = getnumval("Signal [%d]: ",
15, statline);
if ( kill(killpid, killsig) == -1)
{
statmsg = "Not possible to "
"send signal to this pid!";
beep();
}
}
if (!paused && !twinpid)
alarm(3); /* set short timer */
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** change interval timeout
*/
case MINTERVAL:
if (rawreadflag)
{
statmsg = "Not possible in twin mode or "
"when viewing raw file!";
beep();
break;
}
alarm(0); /* stop the clock */
interval = getnumval("New interval in seconds "
"(now %d): ",
interval, statline);
if (interval)
{
if (!paused)
alarm(1); /* set short timer */
}
else
{
statmsg = "No timer set; waiting for "
"manual trigger ('t').....";
}
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** focus on specific user
*/
case MSELUSER:
alarm(0); /* stop the clock */
echo();
move(statline, 0);
clrtoeol();
printw("Username as regular expression "
"(enter=all users): ");
procsel.username[0] = '\0';
scanw("%255s\n", procsel.username);
noecho();
if (procsel.username[0]) /* data entered ? */
{
regex_t userregex;
int u = 0;
if ( regcomp(&userregex,
procsel.username, REG_NOSUB))
{
statmsg = "Invalid regular "
"expression!";
beep();
procsel.username[0] = '\0';
}
else
{
while ( (pwd = getpwent()))
{
if (regexec(&userregex,
pwd->pw_name, 0,
NULL, 0))
continue;
if (u < MAXUSERSEL-1)
{
procsel.userid[u] =
pwd->pw_uid;
u++;
}
}
endpwent();
procsel.userid[u] = USERSTUB;
if (u == 0)
{
/*
** possibly a numerical
** value specified?
*/
if (numeric(
procsel.username))
{
procsel.userid[0] =
atoi(procsel.username);
procsel.userid[1] =
USERSTUB;
}
else
{
statmsg =
"No user-names "
"match this "
"pattern!";
beep();
}
}
}
}
else
{
procsel.userid[0] = USERSTUB;
}
if (interval && !paused && !rawreadflag)
alarm(3); /* set short timer */
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** focus on specific process-name
*/
case MSELPROC:
alarm(0); /* stop the clock */
echo();
move(statline, 0);
clrtoeol();
printw("Process-name as regular "
"expression (enter=no regex): ");
procsel.prognamesz = 0;
procsel.progname[0] = '\0';
scanw("%63s\n", procsel.progname);
procsel.prognamesz = strlen(procsel.progname);
if (procsel.prognamesz)
{
if (regcomp(&procsel.progregex,
procsel.progname, REG_NOSUB))
{
statmsg = "Invalid regular "
"expression!";
beep();
procsel.prognamesz = 0;
procsel.progname[0] = '\0';
}
}
noecho();
move(statline, 0);
if (interval && !paused && !rawreadflag)
alarm(3); /* set short timer */
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** focus on specific container/pod id
*/
case MSELCONT:
if (!rawreadflag && !rootprivs())
{
statmsg = "No privileges to get "
"container/pod identity!";
beep();
break;
}
alarm(0); /* stop the clock */
echo();
move(statline, 0);
clrtoeol();
printw("Container or pod name (enter=all, "
"'host'=host processes): ");
procsel.utsname[0] = '\0';
scanw("%15s", procsel.utsname);
procsel.utsname[UTSLEN] = '\0';
switch (strlen(procsel.utsname))
{
case 0:
break; // enter key pressed
case 4: // host?
if (strcmp(procsel.utsname, "host") == 0)
{
procsel.utsname[0] = 'H';
procsel.utsname[1] = '\0';
}
break;
}
noecho();
move(statline, 0);
if (interval && !paused && !rawreadflag)
alarm(3); /* set short timer */
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** focus on specific PIDs
*/
case MSELPID:
alarm(0); /* stop the clock */
echo();
move(statline, 0);
clrtoeol();
printw("Comma-separated PIDs of processes "
"(enter=no selection): ");
scanw("%79s\n", genline);
int id = 0;
char *pidp = strtok(genline, ",");
while (pidp)
{
char *ep;
if (id >= MAXPID-1)
{
procsel.pid[id] = 0; // stub
statmsg = "Maximum number of"
"PIDs reached!";
beep();
break;
}
procsel.pid[id] = strtol(pidp, &ep, 10);
if (*ep)
{
statmsg = "Non-numerical PID!";
beep();
procsel.pid[0] = 0; // stub
break;
}
id++;
pidp = strtok(NULL, ",");
}
procsel.pid[id] = 0; // stub
noecho();
move(statline, 0);
if (interval && !paused && !rawreadflag)
alarm(3); /* set short timer */
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** focus on specific process/thread state
*/
case MSELSTATE:
alarm(0); /* stop the clock */
echo();
move(statline, 0);
clrtoeol();
/* Linux fs/proc/array.c - task_state_array */
printw("Comma-separated thread states within process "
"(R|S|D|I|T|t|X|Z|P): ");
memset(procsel.states, 0, sizeof procsel.states);
scanw("%15s\n", genline);
char *sp = strtok(genline, ",");
while (sp && *sp)
{
if (isspace(*sp))
{
sp++;
continue;
}
if (strlen(sp) > 1)
{
statmsg = "Invalid state!";
memset(procsel.states, 0,
sizeof procsel.states);
break;
}
int needed = 0;
switch (*sp)
{
case 'R': /* running */
case 'S': /* sleeping */
case 'D': /* disk sleep */
case 'I': /* idle */
case 'T': /* stopped */
case 't': /* tracing stop */
case 'X': /* dead */
case 'Z': /* zombie */
case 'P': /* parked */
if (!strchr(procsel.states, *sp))
needed = 1;
break;
default:
statmsg = "Invalid state!";
memset(procsel.states,
0, sizeof procsel.states);
beep();
break;
}
if (needed)
procsel.states[strlen(procsel.states)] = *sp;
sp = strtok(NULL, ",");
}
noecho();
move(statline, 0);
if (interval && !paused && !rawreadflag)
alarm(3); /* set short timer */
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** focus on specific command line arguments
*/
case MSELARG:
alarm(0); /* stop the clock */
echo();
move(statline, 0);
clrtoeol();
printw("Command line string as regular "
"expression (enter=no regex): ");
procsel.argnamesz = 0;
procsel.argname[0] = '\0';
scanw("%63s\n", procsel.argname);
procsel.argnamesz = strlen(procsel.argname);
if (procsel.argnamesz)
{
if (regcomp(&procsel.argregex,
procsel.argname, REG_NOSUB))
{
statmsg = "Invalid regular "
"expression!";
beep();
procsel.argnamesz = 0;
procsel.argname[0] = '\0';
}
}
noecho();
move(statline, 0);
if (interval && !paused && !rawreadflag)
alarm(3); /* set short timer */
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** focus on specific system resource
*/
case MSELSYS:
alarm(0); /* stop the clock */
echo();
move(statline, 0);
clrtoeol();
printw("Logical volume name as regular "
"expression (enter=no specific name): ");
syssel.lvmnamesz = 0;
syssel.lvmname[0] = '\0';
scanw("%63s\n", syssel.lvmname);
syssel.lvmnamesz = strlen(syssel.lvmname);
if (syssel.lvmnamesz)
{
if (regcomp(&syssel.lvmregex,
syssel.lvmname, REG_NOSUB))
{
statmsg = "Invalid regular "
"expression!";
beep();
syssel.lvmnamesz = 0;
syssel.lvmname[0] = '\0';
}
}
move(statline, 0);
clrtoeol();
printw("Disk name as regular "
"expression (enter=no specific name): ");
syssel.dsknamesz = 0;
syssel.dskname[0] = '\0';
scanw("%63s\n", syssel.dskname);
syssel.dsknamesz = strlen(syssel.dskname);
if (syssel.dsknamesz)
{
if (regcomp(&syssel.dskregex,
syssel.dskname, REG_NOSUB))
{
statmsg = "Invalid regular "
"expression!";
beep();
syssel.dsknamesz = 0;
syssel.dskname[0] = '\0';
}
}
move(statline, 0);
clrtoeol();
printw("Interface name as regular "
"expression (enter=no specific name): ");
syssel.itfnamesz = 0;
syssel.itfname[0] = '\0';
scanw("%63s\n", syssel.itfname);
syssel.itfnamesz = strlen(syssel.itfname);
if (syssel.itfnamesz)
{
if (regcomp(&syssel.itfregex,
syssel.itfname, REG_NOSUB))
{
statmsg = "Invalid regular "
"expression!";
beep();
syssel.itfnamesz = 0;
syssel.itfname[0] = '\0';
}
}
noecho();
move(statline, 0);
if (interval && !paused && !rawreadflag)
alarm(3); /* set short timer */
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** toggle pause-state
*/
case MPAUSE:
if (rawreadflag && !twinpid)
{
statmsg = "Just use 'T' and 't' to browse...";
break;
}
if (paused)
{
paused=0;
clrtoeol();
refresh();
if (!rawreadflag)
{
alarm(1); /* start the clock */
}
else
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
}
else
{
paused=1;
clrtoeol();
refresh();
alarm(0); /* stop the clock */
}
break;
/*
** toggle between modified processes and
** all processes, or between used cgroups and
** all cgroups
*/
case MALLACTIVE:
if (deviatonly)
{
deviatonly=0;
statmsg = "All processes/threads/cgroups will be "
"shown/accumulated...";
}
else
{
deviatonly=1;
statmsg = "Only active processes/threads/cgroups "
"will be shown/accumulated...";
}
tlastorder = 0;
firstitem = 0;
break;
/*
** toggle average or total values
*/
case MAVGVAL:
if (avgval)
avgval=0;
else
avgval=1;
break;
/*
** system-statistics lines:
** toggle fixed or variable
*/
case MSYSFIXED:
if (fixedhead)
{
fixedhead=0;
statmsg = "Only active system-resources"
" will be shown ......";
}
else
{
fixedhead=1;
statmsg = "Also inactive "
"system-resources will be shown.....";
}
firstitem = 0;
break;
/*
** system-statistics lines:
** toggle fixed or variable
*/
case MSYSNOSORT:
if (sysnosort)
{
sysnosort=0;
statmsg = "System resources will be "
"sorted on utilization...";
}
else
{
sysnosort=1;
statmsg = "System resources will not "
"be sorted on utilization...";
}
firstitem = 0;
break;
/*
** per-thread view wanted with sorting on
** process level
*/
case MTHREAD:
if (threadview)
{
threadview = 0;
statmsg = "Thread view disabled";
firstitem = 0;
}
else
{
threadview = 1;
statmsg = "Thread view enabled";
firstitem = 0;
}
break;
/*
** sorting on thread level as well (threadview)
*/
case MTHRSORT:
if (threadsort)
{
threadsort = 0;
statmsg = "Thread sorting disabled for thread view";
firstitem = 0;
}
else
{
threadsort = 1;
statmsg = "Thread sorting enabled for thread view";
firstitem = 0;
}
break;
/*
** per-process PSS calculation wanted
*/
case MCALCPSS:
if (rawreadflag)
{
statmsg = "PSIZE gathering depends "
"on rawfile";
break;
}
if (calcpss)
{
calcpss = 0;
statmsg = "PSIZE gathering disabled";
}
else
{
calcpss = 1;
if (rootprivs())
statmsg = "PSIZE gathering enabled";
else
statmsg = "PSIZE gathering only "
"for own processes";
}
break;
/*
** per-thread WCHAN definition
*/
case MGETWCHAN:
if (getwchan)
{
getwchan = 0;
statmsg = "WCHAN gathering disabled";
}
else
{
getwchan = 1;
statmsg = "WCHAN gathering enabled";
}
break;
/*
** suppression of terminated processes in output
*/
case MSUPEXITS:
if (suppressexit)
{
suppressexit = 0;
statmsg = "Exited processes will "
"be shown/accumulated";
firstitem = 0;
}
else
{
suppressexit = 1;
statmsg = "Exited processes will "
"not be shown/accumulated";
firstitem = 0;
}
break;
/*
** screen lines:
** toggle for colors
*/
case MCOLORS:
if (usecolors)
{
usecolors=0;
statmsg = "No colors will be used...";
}
else
{
if (screen && has_colors())
{
usecolors=1;
statmsg =
"Colors will be used...";
}
else
{
statmsg="No colors supported!";
}
}
firstitem = 0;
break;
/*
** system-statistics lines:
** toggle no or all active disk
*/
case MSYSLIMIT:
alarm(0); /* stop the clock */
maxcpulines =
getnumval("Maximum lines for per-cpu "
"statistics (now %d): ",
maxcpulines, statline);
maxgpulines =
getnumval("Maximum lines for per-gpu "
"statistics (now %d): ",
maxgpulines, statline);
if (sstat->dsk.nlvm > 0)
{
maxlvmlines =
getnumval("Maximum lines for LVM "
"statistics (now %d): ",
maxlvmlines, statline);
}
if (sstat->dsk.nmdd > 0)
{
maxmddlines =
getnumval("Maximum lines for MD "
"device statistics (now %d): ",
maxmddlines, statline);
}
maxdsklines =
getnumval("Maximum lines for disk "
"statistics (now %d): ",
maxdsklines, statline);
maxintlines =
getnumval("Maximum lines for interface "
"statistics (now %d): ",
maxintlines, statline);
maxifblines =
getnumval("Maximum lines for infiniband "
"port statistics (now %d): ",
maxifblines, statline);
maxnfslines =
getnumval("Maximum lines for NFS mount "
"statistics (now %d): ",
maxnfslines, statline);
maxcontlines =
getnumval("Maximum lines for container "
"statistics (now %d): ",
maxcontlines, statline);
maxnumalines =
getnumval("Maximum lines for numa "
"statistics (now %d): ",
maxnumalines, statline);
maxllclines =
getnumval("Maximum lines for LLC "
"statistics (now %d): ",
maxllclines, statline);
if (interval && !paused && !rawreadflag)
alarm(1); /* set short timer */
firstitem = 0;
if (twinpid) // twin mode?
{
begintime = 0x7fffffff;
lastchar = MSAMPBRANCH;
goto free_and_return;
}
break;
/*
** reset counters
*/
case MRESET:
getalarm(0); /* restart the clock */
paused = 0;
if (twinpid)
{
paused=1; // implicit pause in twin mode
clrtoeol();
refresh();
}
goto free_and_return;
/*
** show version info
*/
case MVERSION:
statmsg = getstrvers();
break;
/*
** handle redraw request
*/
case MREDRAW:
wclear(stdscr);
break;
/*
** handle arrow right for command line
*/
case KEY_RIGHT:
startoffset++;
break;
/*
** handle arrow left for command line
*/
case KEY_LEFT:
if (startoffset > 0)
startoffset--;
break;
/*
** handle arrow down to go one line down
*/
case KEY_DOWN:
if (firstitem < alistsz-1)
firstitem += 1;
break;
/*
** handle arrow up to go one line up
*/
case KEY_UP:
if (firstitem > 0)
firstitem -= 1;
break;
/*
** handle forward
*/
case KEY_NPAGE:
case MLISTFW:
if (alistsz-firstitem > slistsz)
firstitem += slistsz;
break;
/*
** handle backward
*/
case KEY_PPAGE:
case MLISTBW:
if (firstitem >= slistsz)
firstitem -= slistsz;
else
firstitem = 0;
break;
/*
** handle screen resize
*/
case KEY_RESIZE:
snprintf(statbuf, sizeof statbuf,
"Window resized to %dx%d...",
COLS, LINES);
statmsg = statbuf;
timeout(0);
(void) getch();
timeout(-1);
break;
/*
** unknown key-stroke
*/
default:
beep();
}
}
else /* no screen */
{
lastchar = '\0';
goto free_and_return;
}
}
free_and_return:
if (tpcumlist) free(tpcumlist);
if (pcumlist) free(pcumlist);
if (tucumlist) free(tucumlist);
if (ucumlist) free(ucumlist);
if (tccumlist) free(tccumlist);
if (ccumlist) free(ccumlist);
if (tsklist) free(tsklist);
if (sellist) free(sellist);
if (cgroupsort) free(cgroupsort);
if (cgroupsel) free(cgroupsel);
return lastchar;
}
/*
** accumulate all processes per user in new list
*/
static int
cumusers(struct tstat **curprocs, struct tstat *curusers, int numprocs)
{
register int i, numusers;
/*
** sort list of active processes in order of uid (increasing)
*/
qsort(curprocs, numprocs, sizeof(struct tstat *), compusr);
/*
** accumulate all processes per user in the new list
*/
for (numusers=i=0; i < numprocs; i++, curprocs++)
{
if (procsuppress(*curprocs, &procsel))
continue;
if ((*curprocs)->gen.state == 'E' && suppressexit)
continue;
if ( curusers->gen.ruid != (*curprocs)->gen.ruid )
{
if (curusers->gen.pid)
{
numusers++;
curusers++;
}
curusers->gen.ruid = (*curprocs)->gen.ruid;
}
accumulate(*curprocs, curusers);
}
if (curusers->gen.pid)
numusers++;
return numusers;
}
/*
** accumulate all processes with the same name (i.e. same program)
** into a new list
*/
static int
cumprogs(struct tstat **curprocs, struct tstat *curprogs, int numprocs)
{
register int i, numprogs;
/*
** sort list of active processes in order of process-name
*/
qsort(curprocs, numprocs, sizeof(struct tstat *), compnam);
/*
** accumulate all processes with same name in the new list
*/
for (numprogs=i=0; i < numprocs; i++, curprocs++)
{
if (procsuppress(*curprocs, &procsel))
continue;
if ((*curprocs)->gen.state == 'E' && suppressexit)
continue;
if ( strcmp(curprogs->gen.name, (*curprocs)->gen.name) != 0)
{
if (curprogs->gen.pid)
{
numprogs++;
curprogs++;
}
strcpy(curprogs->gen.name, (*curprocs)->gen.name);
}
accumulate(*curprocs, curprogs);
}
if (curprogs->gen.pid)
numprogs++;
return numprogs;
}
/*
** accumulate all processes per container/pod in new list
*/
static int
cumconts(struct tstat **curprocs, struct tstat *curconts, int numprocs)
{
register int i, numconts;
/*
** sort list of active processes in order of container/pod (increasing)
*/
qsort(curprocs, numprocs, sizeof(struct tstat *), compcon);
/*
** accumulate all processes per container/pod in the new list
*/
for (numconts=i=0; i < numprocs; i++, curprocs++)
{
if (procsuppress(*curprocs, &procsel))
continue;
if ((*curprocs)->gen.state == 'E' && suppressexit)
continue;
if ( strcmp(curconts->gen.utsname,
(*curprocs)->gen.utsname) != 0)
{
if (curconts->gen.pid)
{
numconts++;
curconts++;
}
strcpy(curconts->gen.utsname,
(*curprocs)->gen.utsname);
}
accumulate(*curprocs, curconts);
}
if (curconts->gen.pid)
numconts++;
return numconts;
}
/*
** accumulate relevant counters from individual task to
** combined task
*/
static void
accumulate(struct tstat *curproc, struct tstat *curstat)
{
count_t nett_wsz;
curstat->gen.pid++; /* misuse as counter */
curstat->gen.isproc = 1;
curstat->gen.nthr += curproc->gen.nthr;
curstat->cpu.utime += curproc->cpu.utime;
curstat->cpu.stime += curproc->cpu.stime;
curstat->cpu.nvcsw += curproc->cpu.nvcsw;
curstat->cpu.nivcsw += curproc->cpu.nivcsw;
curstat->cpu.rundelay += curproc->cpu.rundelay;
curstat->cpu.blkdelay += curproc->cpu.blkdelay;
if (curproc->dsk.wsz > curproc->dsk.cwsz)
nett_wsz = curproc->dsk.wsz -curproc->dsk.cwsz;
else
nett_wsz = 0;
curstat->dsk.rio += curproc->dsk.rsz;
curstat->dsk.wio += nett_wsz;
curstat->dsk.rsz = curstat->dsk.rio;
curstat->dsk.wsz = curstat->dsk.wio;
curstat->net.tcpsnd += curproc->net.tcpsnd;
curstat->net.tcprcv += curproc->net.tcprcv;
curstat->net.udpsnd += curproc->net.udpsnd;
curstat->net.udprcv += curproc->net.udprcv;
curstat->net.tcpssz += curproc->net.tcpssz;
curstat->net.tcprsz += curproc->net.tcprsz;
curstat->net.udpssz += curproc->net.udpssz;
curstat->net.udprsz += curproc->net.udprsz;
if (curproc->gen.state != 'E')
{
if (curproc->mem.pmem != -1) // no errors?
curstat->mem.pmem += curproc->mem.pmem;
curstat->mem.vmem += curproc->mem.vmem;
curstat->mem.rmem += curproc->mem.rmem;
curstat->mem.vlibs += curproc->mem.vlibs;
curstat->mem.vdata += curproc->mem.vdata;
curstat->mem.vstack += curproc->mem.vstack;
curstat->mem.vswap += curproc->mem.vswap;
curstat->mem.vlock += curproc->mem.vlock;
curstat->mem.rgrow += curproc->mem.rgrow;
curstat->mem.vgrow += curproc->mem.vgrow;
if (curproc->gpu.state) // GPU is use?
{
int i;
curstat->gpu.state = 'A';
if (curproc->gpu.gpubusy == -1)
curstat->gpu.gpubusy = -1;
else
curstat->gpu.gpubusy += curproc->gpu.gpubusy;
if (curproc->gpu.membusy == -1)
curstat->gpu.membusy = -1;
else
curstat->gpu.membusy += curproc->gpu.membusy;
curstat->gpu.memnow += curproc->gpu.memnow;
curstat->gpu.gpulist |= curproc->gpu.gpulist;
curstat->gpu.nrgpus = 0;
for (i=0; i < MAXGPU; i++)
{
if (curstat->gpu.gpulist & 1<<i)
curstat->gpu.nrgpus++;
}
}
}
}
/*
** function that checks if the current process or thread must be
** selected or suppressed
**
** returns 1 (suppress) or 0 (do not suppress)
*/
static int
procsuppress(struct tstat *curstat, struct pselection *sel)
{
/*
** check if only processes of a particular user
** should be shown
*/
if (sel->userid[0] != USERSTUB)
{
int u = 0;
while (sel->userid[u] != USERSTUB)
{
if (sel->userid[u] == curstat->gen.ruid)
break;
u++;
}
if (sel->userid[u] != curstat->gen.ruid)
return 1;
}
/*
** check if only processes with particular PIDs
** should be shown
*/
if (sel->pid[0])
{
int i = 0;
while (sel->pid[i])
{
if (sel->pid[i] == curstat->gen.tgid)
break;
i++;
}
if (sel->pid[i] != curstat->gen.tgid)
return 1;
}
/*
** check if only processes with a particular name
** should be shown
*/
if (sel->prognamesz &&
regexec(&(sel->progregex), curstat->gen.name, 0, NULL, 0))
return 1;
/*
** check if only processes with a particular command line string
** should be shown
*/
if (sel->argnamesz)
{
if (curstat->gen.cmdline[0])
{
if (regexec(&(sel->argregex), curstat->gen.cmdline,
0, NULL, 0))
return 1;
}
else
{
if (regexec(&(sel->argregex), curstat->gen.name,
0, NULL, 0))
return 1;
}
}
/*
** check if only processes related to a particular container/pod
** should be shown (container/pod 'H' stands for native host processes)
*/
if (sel->utsname[0])
{
if (sel->utsname[0] == 'H') // only host processes
{
if (curstat->gen.utsname[0])
return 1;
}
else
{
if (memcmp(sel->utsname, curstat->gen.utsname, 12))
return 1;
}
}
/*
** check if only processes in specific states should be shown
**
** notice that the state of a process (i.e. the main thread)
** may be 'S' while a thread in the process might have state 'R'
** --> still show the process in that case!
*/
if (sel->states[0])
{
// check the states of the threads of this process
//
if (strchr(sel->states, 'R') && curstat->gen.nthrrun)
return 0;
if (strchr(sel->states, 'S') && curstat->gen.nthrslpi)
return 0;
if (strchr(sel->states, 'D') && curstat->gen.nthrslpu)
return 0;
if (strchr(sel->states, 'I') && curstat->gen.nthridle)
return 0;
// check the state of the process itself
//
if (strchr(sel->states, curstat->gen.state) == NULL)
return 1;
}
return 0;
}
static void
limitedlines(void)
{
if (maxcpulines == 999) // default?
maxcpulines = 0;
if (maxgpulines == 999) // default?
maxgpulines = 2;
if (maxdsklines == 999) // default?
maxdsklines = 3;
if (maxmddlines == 999) // default?
maxmddlines = 3;
if (maxlvmlines == 999) // default?
maxlvmlines = 4;
if (maxintlines == 999) // default?
maxintlines = 2;
if (maxifblines == 999) // default?
maxifblines = 2;
if (maxnfslines == 999) // default?
maxnfslines = 2;
if (maxcontlines == 999) // default?
maxcontlines = 1;
if (maxnumalines == 999) // default?
maxnumalines = 0;
if (maxllclines == 999) // default?
maxllclines = 0;
}
/*
** get a numerical value from the user and verify
*/
static long
getnumval(char *ask, long valuenow, int statline)
{
char numval[16];
long retval;
echo();
move(statline, 0);
clrtoeol();
printw(ask, valuenow);
numval[0] = 0;
scanw("%15s", numval);
move(statline, 0);
noecho();
if (numval[0]) /* data entered ? */
{
if ( numeric(numval) )
{
retval = atol(numval);
}
else
{
beep();
clrtoeol();
printw("Value not numeric (current value kept)!");
refresh();
sleep(2);
retval = valuenow;
}
}
else
{
retval = valuenow;
}
return retval;
}
/*
** generic print-function which checks if printf should be used
** (to file or pipe) or curses (to screen)
*/
void
printg(const char *format, ...)
{
va_list args;
va_start(args, format);
if (screen)
vw_printw(stdscr, (char *) format, args);
else
vprintf(format, args);
va_end(args);
}
/*
** initialize generic sample output functions
*/
static void
generic_init(void)
{
int i;
/*
** check if default sort order and/or showtype are overruled
** by command-line flags
*/
for (i=0; flaglist[i]; i++)
{
switch (flaglist[i])
{
case MSORTAUTO:
showorder = MSORTAUTO;
break;
case MSORTCPU:
showorder = MSORTCPU;
break;
case MSORTGPU:
showorder = MSORTGPU;
break;
case MSORTMEM:
showorder = MSORTMEM;
break;
case MSORTDSK:
showorder = MSORTDSK;
break;
case MSORTNET:
showorder = MSORTNET;
break;
case MPROCGEN:
showtype = MPROCGEN;
showorder = MSORTCPU;
break;
case MPROCGPU:
showtype = MPROCGPU;
showorder = MSORTGPU;
break;
case MPROCMEM:
showtype = MPROCMEM;
showorder = MSORTMEM;
break;
case MPROCSCH:
showtype = MPROCSCH;
showorder = MSORTCPU;
break;
case MPROCDSK:
showtype = MPROCDSK;
showorder = MSORTDSK;
break;
case MPROCNET:
if ( !(supportflags & NETATOP || supportflags & NETATOPBPF) )
{
fprintf(stderr, "Module 'netatop' or 'netatop-bpf' not "
"active; request ignored!");
sleep(3);
break;
}
showtype = MPROCNET;
showorder = MSORTNET;
break;
case MPROCVAR:
showtype = MPROCVAR;
break;
case MPROCARG:
showtype = MPROCARG;
break;
case MCGROUPS:
if ( !(supportflags & CGROUPV2) )
{
fprintf(stderr, "No cgroup v2 metrics "
"available; request ignored!\n");
sleep(3);
break;
}
showtype = MCGROUPS;
break;
case MPROCOWN:
showtype = MPROCOWN;
break;
case MAVGVAL:
if (avgval)
avgval=0;
else
avgval=1;
break;
case MCUMUSER:
showtype = MCUMUSER;
break;
case MCUMPROC:
showtype = MCUMPROC;
break;
case MCUMCONT:
if (!rawreadflag && !rootprivs())
{
fprintf(stderr, "No privileges to get "
"container/pod identity!\n");
sleep(3);
break;
}
showtype = MCUMCONT;
break;
case MSYSFIXED:
if (fixedhead)
fixedhead=0;
else
fixedhead=1;
break;
case MSYSNOSORT:
if (sysnosort)
sysnosort=0;
else
sysnosort=1;
break;
case MTHREAD:
if (threadview)
threadview = 0;
else
threadview = 1;
break;
case MTHRSORT:
if (threadsort)
threadsort = 0;
else
threadsort = 1;
break;
case MCALCPSS:
if (rawreadflag)
{
fprintf(stderr,
"PSIZE gathering depends on rawfile\n");
sleep(3);
break;
}
if (calcpss)
{
calcpss = 0;
}
else
{
calcpss = 1;
if (!rootprivs())
{
fprintf(stderr,
"PSIZE gathering only for own "
"processes\n");
sleep(3);
}
}
break;
case MGETWCHAN:
if (getwchan)
getwchan = 0;
else
getwchan = 1;
break;
case MSUPEXITS:
if (suppressexit)
suppressexit = 0;
else
suppressexit = 1;
break;
case MCOLORS:
if (usecolors)
usecolors=0;
else
usecolors=1;
break;
case MSYSLIMIT:
limitedlines();
break;
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
cgroupdepth = flaglist[i] - 0x30;
break;
default:
prusage("atop");
}
}
/*
** set stdout output on line-basis
*/
setvbuf(stdout, (char *)0, _IOLBF, BUFSIZ);
/*
** check if STDOUT is related to a tty or
** something else (file, pipe)
*/
if ( isatty(fileno(stdout)) )
screen = 1;
else
screen = 0;
/*
** install catch-routine to finish in a controlled way
** and activate cbreak mode
*/
if (screen)
{
/*
** if stdin is not connected to a tty (might be redirected
** to pipe or file), close it and duplicate stdout (tty)
** to stdin
*/
if ( !isatty(fileno(stdin)) )
{
(void) dup2(fileno(stdout), fileno(stdin));
}
/*
** initialize screen-handling via curses
*/
setlocale(LC_ALL, "");
setlocale(LC_NUMERIC, "C");
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
/*
** verify minimal dimensions
*/
if (COLS < MINCOLUMNS || LINES < MINLINES)
{
endwin(); // finish ncurses interface
fprintf(stderr,
"Terminal size should be at least "
"%d columns by %d lines\n",
MINCOLUMNS, MINLINES);
cleanstop(1);
}
if (has_colors())
{
use_default_colors();
start_color();
// color definitions
//
init_color(COLOR_MYORANGE, 675, 500, 50);
init_color(COLOR_MYGREEN, 0, 600, 100);
init_color(COLOR_MYGREY, 240, 240, 240);
init_color(COLOR_MYBROWN1, 420, 160, 160);
init_color(COLOR_MYBROWN2, 735, 280, 280);
init_color(COLOR_MYBLUE0, 50, 50, 300);
init_color(COLOR_MYBLUE1, 50, 300, 500);
init_color(COLOR_MYBLUE2, 50, 500, 800);
init_color(COLOR_MYBLUE3, 100, 350, 600);
init_color(COLOR_MYBLUE4, 150, 500, 700);
init_color(COLOR_MYBLUE5, 200, 650, 800);
init_color(COLOR_MYGREEN0, 90, 300, 0);
init_color(COLOR_MYGREEN1, 90, 400, 100);
init_color(COLOR_MYGREEN2, 90, 600, 100);
// color pair definitions (foreground/background)
//
init_pair(FGCOLORINFO, colorinfo, -1);
init_pair(FGCOLORALMOST, coloralmost, -1);
init_pair(FGCOLORCRIT, colorcrit, -1);
init_pair(FGCOLORTHR, colorthread, -1);
init_pair(FGCOLORBORDER, COLOR_CYAN, -1);
init_pair(WHITE_GREEN, COLOR_WHITE, COLOR_MYGREEN);
init_pair(WHITE_ORANGE, COLOR_WHITE, COLOR_MYORANGE);
init_pair(WHITE_RED, COLOR_WHITE, COLOR_RED);
init_pair(WHITE_GREY, COLOR_WHITE, COLOR_MYGREY);
init_pair(WHITE_BLUE, COLOR_WHITE, COLOR_BLUE);
init_pair(WHITE_MAGENTA, COLOR_WHITE, COLOR_MAGENTA);
init_pair(WHITE_BROWN1, COLOR_WHITE, COLOR_MYBROWN1);
init_pair(WHITE_BROWN2, COLOR_WHITE, COLOR_MYBROWN2);
init_pair(WHITE_BLUE0, COLOR_WHITE, COLOR_MYBLUE0);
init_pair(WHITE_BLUE1, COLOR_WHITE, COLOR_MYBLUE1);
init_pair(WHITE_BLUE2, COLOR_WHITE, COLOR_MYBLUE2);
init_pair(WHITE_BLUE3, COLOR_WHITE, COLOR_MYBLUE3);
init_pair(WHITE_BLUE4, COLOR_WHITE, COLOR_MYBLUE4);
init_pair(WHITE_BLUE5, COLOR_WHITE, COLOR_MYBLUE5);
init_pair(WHITE_GREEN0, COLOR_WHITE, COLOR_MYGREEN0);
init_pair(WHITE_GREEN1, COLOR_WHITE, COLOR_MYGREEN1);
init_pair(WHITE_GREEN2, COLOR_WHITE, COLOR_MYGREEN2);
}
else
{
usecolors = 0;
}
}
signal(SIGINT, cleanstop);
signal(SIGTERM, cleanstop);
}
/*
** show help information in interactive mode
*/
static struct helptext {
char *helpline;
char helparg;
char mode; // 'l' - live, 'r' - rawlog, 'a' - all
} helptext[] = {
{"Display mode:\n", ' ', 'a'},
{"\t'%c' - show bar graphs for system utilization (toggle)\n",
MBARGRAPH, 'a'},
{"\n", ' ', 'a'},
{"Information in text mode about cgroups v2:\n", ' ', 'a'},
{"\t'%c' - cgroups v2 metrics\n", MCGROUPS, 'a'},
{"\t 2-7 - cgroups tree level selection (default 7)\n", ' ', 'a'},
{"\t 8 - cgroups with related processes, except kernel processes\n", ' ', 'a'},
{"\t 9 - cgroups with related processes\n", ' ', 'a'},
{"\t'%c' - show all cgroups/processes i.s.o. only active ones (toggle)\n",
MALLACTIVE, 'a'},
{"\t'%c' - sort on cpu activity\n", MSORTCPU, 'a'},
{"\t'%c' - sort on memory utilization\n", MSORTMEM, 'a'},
{"\t'%c' - sort on disk transfer rate\n", MSORTDSK, 'a'},
{"\n", ' ', 'a'},
{"Information in text mode about processes:\n", ' ', 'a'},
{"\t'%c' - generic info (default)\n", MPROCGEN, 'a'},
{"\t'%c' - memory details\n", MPROCMEM, 'a'},
{"\t'%c' - disk details\n", MPROCDSK, 'a'},
{"\t'%c' - network details\n", MPROCNET, 'a'},
{"\t'%c' - scheduling and thread-group info\n", MPROCSCH, 'a'},
{"\t'%c' - GPU details\n", MPROCGPU, 'a'},
{"\t'%c' - various info (ppid, user/group, date/time, status, "
"exitcode)\n", MPROCVAR, 'a'},
{"\t'%c' - full command line per process\n", MPROCARG, 'a'},
{"\t'%c' - use own output line definition\n", MPROCOWN, 'a'},
{"\n", ' ', 'a'},
{"Sort list of processes in order of:\n", ' ', 'a'},
{"\t'%c' - cpu activity\n", MSORTCPU, 'a'},
{"\t'%c' - memory consumption\n", MSORTMEM, 'a'},
{"\t'%c' - disk activity\n", MSORTDSK, 'a'},
{"\t'%c' - network activity\n", MSORTNET, 'a'},
{"\t'%c' - GPU activity\n", MSORTGPU, 'a'},
{"\t'%c' - most active system resource (auto mode)\n", MSORTAUTO, 'a'},
{"\n", ' ', 'a'},
{"Raw file viewing and twin mode:\n", ' ', 'r'},
{"\t'%c' - show next sample\n", MSAMPNEXT, 'r'},
{"\t'%c' - show previous sample\n", MSAMPPREV, 'r'},
{"\t'%c' - branch to certain time\n", MSAMPBRANCH, 'r'},
{"\t'%c' - rewind to begin\n", MRESET, 'r'},
{"\t'%c' - pause button to freeze or continue (twin mode)\n",
MPAUSE, 'r'},
{"\n", ' ', 'r'},
{"Accumulated process figures:\n", ' ', 'a'},
{"\t'%c' - total resource consumption per user\n", MCUMUSER, 'a'},
{"\t'%c' - total resource consumption per program (i.e. same "
"process name)\n", MCUMPROC, 'a'},
{"\t'%c' - total resource consumption per container/pod\n",MCUMCONT, 'a'},
{"\n", ' ', 'a'},
{"Process selections (keys shown in header line):\n", ' ', 'a'},
{"\t'%c' - focus on specific user name "
"(regular expression)\n", MSELUSER, 'a'},
{"\t'%c' - focus on specific program name "
"(regular expression)\n", MSELPROC, 'a'},
{"\t'%c' - focus on specific container/pod name\n", MSELCONT, 'a'},
{"\t'%c' - focus on specific command line string "
"(regular expression)\n", MSELARG, 'a'},
{"\t'%c' - focus on specific process id (PID)\n", MSELPID, 'a'},
{"\t'%c' - focus on specific process/thread state(s)\n", MSELSTATE, 'a'},
{"\n", ' ', 'a'},
{"System resource selections (keys shown in header line):\n",' ', 'a'},
{"\t'%c' - focus on specific system resources "
"(regular expression)\n", MSELSYS, 'a'},
{"\n", ' ', 'a'},
{"Screen handling:\n", ' ', 'a'},
{"\t^L - redraw the screen \n", ' ', 'a'},
{"\tPgDn - show next page in the process list (or ^F)\n", ' ', 'a'},
{"\tPgUp - show previous page in the process list (or ^B)\n", ' ', 'a'},
{"\tArDn - arrow-down for next line in process list\n", ' ', 'a'},
{"\tArUp arrow-up for previous line in process list\n", ' ', 'a'},
{"\tArRt - arrow-right for next character in full command line\n", ' ', 'a'},
{"\tArLt - arrow-left for previous character in full command line\n",
' ', 'a'},
{"\n", ' ', 'a'},
{"Presentation (keys shown in header line):\n", ' ', 'a'},
{"\t'%c' - show threads within process (thread view) (toggle)\n",
MTHREAD, 'a'},
{"\t'%c' - sort threads (when combined with thread view) (toggle)\n",
MTHRSORT, 'a'},
{"\t'%c' - show all processes/threads (i.s.o. active) (toggle)\n",
MALLACTIVE, 'a'},
{"\t'%c' - show fixed number of header lines (toggle)\n",
MSYSFIXED, 'a'},
{"\t'%c' - suppress sorting system resources (toggle)\n",
MSYSNOSORT, 'a'},
{"\t'%c' - suppress terminateed processes in output (toggle)\n",
MSUPEXITS, 'a'},
{"\t'%c' - no colors to indicate high occupation (toggle)\n",
MCOLORS, 'a'},
{"\t'%c' - show average-per-second i.s.o. total values (toggle)\n",
MAVGVAL, 'a'},
{"\t'%c' - calculate proportional set size (PSIZE) (toggle)\n",
MCALCPSS, 'a'},
{"\t'%c' - determine WCHAN per thread (toggle)\n",
MGETWCHAN, 'a'},
{"\n", ' '},
{"Miscellaneous commands:\n", ' '},
{"\t'%c' - change interval timer (0 = only manual trigger)\n",
MINTERVAL, 'l'},
{"\t'%c' - manual trigger to force next sample\n", MSAMPNEXT, 'l'},
{"\t'%c' - reset counters to boot time values\n", MRESET, 'l'},
{"\t'%c' - pause button to freeze current sample (toggle)\n",
MPAUSE, 'l'},
{"\n", ' ', 'l'},
{"\t'%c' - limit lines for per-cpu, disk and interface resources\n",
MSYSLIMIT, 'a'},
{"\t'%c' - kill a process (i.e. send a signal)\n", MKILLPROC, 'a'},
{"\n", ' '},
{"\t'%c' - version information\n", MVERSION, 'a'},
{"\t'%c' - help information\n", MHELP1, 'a'},
{"\t'%c' - help information\n", MHELP2, 'a'},
{"\t'%c' - quit this program\n", MQUIT, 'a'},
};
static int helplines = sizeof(helptext)/sizeof(struct helptext);
static void
showhelp(int helpline)
{
int winlines = LINES-helpline, shown, tobeshown=1, i, lines;
WINDOW *helpwin;
/*
** create a new window for the help-info in which scrolling is
** allowed
*/
helpwin = newwin(winlines, COLS, helpline, 0);
scrollok(helpwin, 1);
/*
** show help-lines
*/
for (i=0, lines=0, shown=0; i < helplines; i++)
{
if (rawreadflag) // implies twin mode
{
if (helptext[i].mode == 'l')
continue;
}
else
{
if (helptext[i].mode == 'r')
continue;
}
wprintw(helpwin, helptext[i].helpline, helptext[i].helparg);
/*
** when the window is full, start paging interactively
*/
if (lines >= winlines-2 && shown >= tobeshown)
{
int inputkey;
wmove(helpwin, winlines-1, 0);
wclrtoeol(helpwin);
wprintw(helpwin, "Press q (leave help), "
"space (next page), "
"Enter (next line) or select key...");
keypad(helpwin, 1); // recognize keypad keys
switch (inputkey = wgetch(helpwin))
{
case KEY_NPAGE:
case KEY_PPAGE:
case KEY_UP:
case KEY_DOWN:
case KEY_LEFT:
case KEY_RIGHT:
break; // ignore keypad keys
case 'q':
delwin(helpwin);
return;
case ' ':
shown = 0;
tobeshown = winlines-1;
break;
case '\n':
shown = 0;
tobeshown = 1;
break;
default:
ungetch(inputkey);
keywaiting = 1;
delwin(helpwin);
return;
}
wmove(helpwin, winlines-1, 0);
}
lines++;
shown++;
}
wmove(helpwin, winlines-1, 0);
wclrtoeol(helpwin);
wprintw(helpwin, "End of help - press 'q' to leave help...");
while (wgetch(helpwin) != 'q');
delwin(helpwin);
}
/*
** function to be called to print error-messages
*/
void
generic_error(const char *format, ...)
{
va_list args;
va_start(args, format);
vfprintf(stderr, format, args);
va_end (args);
}
/*
** function to be called when the program stops
*/
void
generic_end(void)
{
endwin();
}
/*
** function to be called when usage-info is required
*/
void
generic_usage(void)
{
printf("\t -%c show fixed number of lines with system statistics\n",
MSYSFIXED);
printf("\t -%c suppress sorting of system resources\n",
MSYSNOSORT);
printf("\t -%c suppress terminated processes in output\n",
MSUPEXITS);
printf("\t -%c show limited number of lines for certain resources\n",
MSYSLIMIT);
printf("\t -%c show threads within process\n", MTHREAD);
printf("\t -%c sort threads (when combined with '%c')\n", MTHRSORT, MTHREAD);
printf("\t -%c show average-per-second i.s.o. total values\n\n",
MAVGVAL);
printf("\t -%c no colors in case of high occupation\n",
MCOLORS);
printf("\t -%c show general process-info (default)\n",
MPROCGEN);
printf("\t -%c show memory-related process-info\n",
MPROCMEM);
printf("\t -%c show disk-related process-info\n",
MPROCDSK);
printf("\t -%c show network-related process-info\n",
MPROCNET);
printf("\t -%c show scheduling-related process-info\n",
MPROCSCH);
printf("\t -%c show various process-info (ppid, user/group, "
"date/time)\n", MPROCVAR);
printf("\t -%c show command line per process\n",
MPROCARG);
printf("\t -%c show own defined process-info\n",
MPROCOWN);
printf("\t -%c show cumulated process-info per user\n",
MCUMUSER);
printf("\t -%c show cumulated process-info per program "
"(i.e. same name)\n",
MCUMPROC);
printf("\t -%c show cumulated process-info per container/pod\n\n",
MCUMCONT);
printf("\t -%c sort processes in order of cpu consumption "
"(default)\n",
MSORTCPU);
printf("\t -%c sort processes in order of memory consumption\n",
MSORTMEM);
printf("\t -%c sort processes in order of disk activity\n",
MSORTDSK);
printf("\t -%c sort processes in order of network activity\n",
MSORTNET);
printf("\t -%c sort processes in order of GPU activity\n",
MSORTGPU);
printf("\t -%c sort processes in order of most active resource "
"(auto mode)\n",
MSORTAUTO);
}
/*
** functions to handle a particular tag in the /etc/atoprc and .atoprc file
*/
void
do_username(char *name, char *val)
{
struct passwd *pwd;
strncpy(procsel.username, val, sizeof procsel.username -1);
procsel.username[sizeof procsel.username -1] = 0;
if (procsel.username[0])
{
regex_t userregex;
int u = 0;
if (regcomp(&userregex, procsel.username, REG_NOSUB))
{
fprintf(stderr,
"atoprc - %s: invalid regular expression %s\n",
name, val);
exit(1);
}
while ( (pwd = getpwent()))
{
if (regexec(&userregex, pwd->pw_name, 0, NULL, 0))
continue;
if (u < MAXUSERSEL-1)
{
procsel.userid[u] = pwd->pw_uid;
u++;
}
}
endpwent();
procsel.userid[u] = USERSTUB;
if (u == 0)
{
/*
** possibly a numerical value has been specified
*/
if (numeric(procsel.username))
{
procsel.userid[0] = atoi(procsel.username);
procsel.userid[1] = USERSTUB;
}
else
{
fprintf(stderr,
"atoprc - %s: user-names matching %s "
"do not exist\n", name, val);
exit(1);
}
}
}
else
{
procsel.userid[0] = USERSTUB;
}
}
void
do_procname(char *name, char *val)
{
strncpy(procsel.progname, val, sizeof procsel.progname -1);
procsel.prognamesz = strlen(procsel.progname);
if (procsel.prognamesz)
{
if (regcomp(&procsel.progregex, procsel.progname, REG_NOSUB))
{
fprintf(stderr,
"atoprc - %s: invalid regular expression %s\n",
name, val);
exit(1);
}
}
}
void
do_maxcpu(char *name, char *val)
{
maxcpulines = get_posval(name, val);
}
void
do_maxgpu(char *name, char *val)
{
maxgpulines = get_posval(name, val);
}
void
do_maxdisk(char *name, char *val)
{
maxdsklines = get_posval(name, val);
}
void
do_maxmdd(char *name, char *val)
{
maxmddlines = get_posval(name, val);
}
void
do_maxlvm(char *name, char *val)
{
maxlvmlines = get_posval(name, val);
}
void
do_maxintf(char *name, char *val)
{
maxintlines = get_posval(name, val);
}
void
do_maxifb(char *name, char *val)
{
maxifblines = get_posval(name, val);
}
void
do_maxnfsm(char *name, char *val)
{
maxnfslines = get_posval(name, val);
}
void
do_maxcont(char *name, char *val)
{
maxcontlines = get_posval(name, val);
}
void
do_maxnuma(char *name, char *val)
{
maxnumalines = get_posval(name, val);
}
void
do_maxllc(char *name, char *val)
{
maxllclines = get_posval(name, val);
}
struct colmap {
char *colname;
short colval;
} colormap[] = {
{ "red", COLOR_RED, },
{ "green", COLOR_GREEN, },
{ "yellow", COLOR_YELLOW, },
{ "blue", COLOR_BLUE, },
{ "magenta", COLOR_MAGENTA, },
{ "cyan", COLOR_CYAN, },
{ "black", COLOR_BLACK, },
{ "white", COLOR_WHITE, },
};
static short
modify_color(char *colorname)
{
int i;
for (i=0; i < sizeof colormap/sizeof colormap[0]; i++)
{
if ( strcmp(colorname, colormap[i].colname) == 0)
return colormap[i].colval;
}
// required color not found
fprintf(stderr, "atoprc - invalid color used: %s\n", colorname);
fprintf(stderr, "supported colors:");
for (i=0; i < sizeof colormap/sizeof colormap[0]; i++)
fprintf(stderr, " %s", colormap[i].colname);
fprintf(stderr, "\n");
exit(1);
}
void
do_colinfo(char *name, char *val)
{
colorinfo = modify_color(val);
}
void
do_colalmost(char *name, char *val)
{
coloralmost = modify_color(val);
}
void
do_colcrit(char *name, char *val)
{
colorcrit = modify_color(val);
}
void
do_colthread(char *name, char *val)
{
colorthread = modify_color(val);
}
void
do_twindir(char *name, char *val)
{
extern char twindir[];
strncpy(twindir, val, RAWNAMESZ-1);
}
void
do_flags(char *name, char *val)
{
int i;
extern char twinmodeflag;
for (i=0; val[i]; i++)
{
switch (val[i])
{
case '-':
break;
case MBARGRAPH:
displaymode = 'D';
break;
case MBARMONO:
barmono = 1;
break;
case MSORTCPU:
showorder = MSORTCPU;
break;
case MSORTGPU:
showorder = MSORTGPU;
break;
case MSORTMEM:
showorder = MSORTMEM;
break;
case MSORTDSK:
showorder = MSORTDSK;
break;
case MSORTNET:
showorder = MSORTNET;
break;
case MSORTAUTO:
showorder = MSORTAUTO;
break;
case MPROCGEN:
showtype = MPROCGEN;
showorder = MSORTCPU;
break;
case MPROCGPU:
showtype = MPROCGPU;
showorder = MSORTGPU;
break;
case MPROCMEM:
showtype = MPROCMEM;
showorder = MSORTMEM;
break;
case MPROCDSK:
showtype = MPROCDSK;
showorder = MSORTDSK;
break;
case MPROCNET:
showtype = MPROCNET;
showorder = MSORTNET;
break;
case MPROCVAR:
showtype = MPROCVAR;
break;
case MPROCSCH:
showtype = MPROCSCH;
showorder = MSORTCPU;
break;
case MPROCARG:
showtype = MPROCARG;
break;
case MPROCOWN:
showtype = MPROCOWN;
break;
case MCUMUSER:
showtype = MCUMUSER;
break;
case MCUMPROC:
showtype = MCUMPROC;
break;
case MCUMCONT:
showtype = MCUMCONT;
break;
case MCGROUPS:
showtype = MCGROUPS;
break;
case MALLACTIVE:
deviatonly = 0;
break;
case MAVGVAL:
avgval=1;
break;
case MSYSFIXED:
fixedhead = 1;
break;
case MSYSNOSORT:
sysnosort = 1;
break;
case MTHREAD:
threadview = 1;
break;
case MTHRSORT:
threadsort = 1;
break;
case MCOLORS:
usecolors = 0;
break;
case MCALCPSS:
calcpss = 1;
break;
case MGETWCHAN:
getwchan = 1;
break;
case MSUPEXITS:
suppressexit = 1;
break;
case '2': // cgroup level
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
cgroupdepth = val[i] - 0x30;
break;
case 't':
twinmodeflag++;
break;
}
}
}
static void
getsigwinch(int signr)
{
winchange = 1;
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/lurenchina/atop.git
git@gitee.com:lurenchina/atop.git
lurenchina
atop
atop
master

搜索帮助

0d507c66 1850385 C8b1a773 1850385