/* ** The engine() drives the main-loop of the program */ static void engine(void) { int i, j; struct sigaction sigact; static time_t timelimit; void getusr1(int), getusr2(int); /* ** reserve space for system-level statistics */ static struct sstat *cursstat; /* current */ static struct sstat *presstat; /* previous */ static struct sstat *devsstat; /* deviation */ static struct sstat *hlpsstat; /* ** reserve space for task-level statistics */ static struct tstat *curpact; /* current active list */ static int curplen; /* current active size */ struct tstat *curpexit; /* exited process list */ struct tstat *devtstat; /* deviation list */ struct tstat **devpstat; /* pointers to processes*/ /* in deviation list */ unsigned int ntask, nexit, nexitnet; unsigned int noverflow, ndeviat, nactproc; int totproc, totrun, totslpi, totslpu, totzombie; /* ** initialization: allocate required memory dynamically */ cursstat = calloc(1, sizeof(struct sstat)); presstat = calloc(1, sizeof(struct sstat)); devsstat = calloc(1, sizeof(struct sstat)); curplen = countprocs() * 3 / 2; /* add 50% for threads */ curpact = calloc(curplen, sizeof(struct tstat)); ptrverify(cursstat, "Malloc failed for current sysstats\n"); ptrverify(presstat, "Malloc failed for prev sysstats\n"); ptrverify(devsstat, "Malloc failed for deviate sysstats\n"); ptrverify(curpact, "Malloc failed for %d procstats\n", curplen); /* ** install the signal-handler for ALARM, USR1 and USR2 (triggers * for the next sample) */ memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr1; sigaction(SIGUSR1, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr2; sigaction(SIGUSR2, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getalarm; sigaction(SIGALRM, &sigact, (struct sigaction *)0); if (interval > 0) alarm(interval); if (midnightflag) { time_t timenow = time(0); struct tm *tp = localtime(&timenow); tp->tm_hour = 23; tp->tm_min = 59; tp->tm_sec = 59; timelimit = mktime(tp); } /* ** MAIN-LOOP: ** - Wait for the requested number of seconds or for other trigger ** ** - System-level counters ** get current counters ** calculate the differences with the previous sample ** ** - Process-level counters ** get current counters from running & exited processes ** calculate the differences with the previous sample ** ** - Call the print-function to visualize the differences */ for (sampcnt=0; sampcnt < nsamples; sampcnt++) { char lastcmd; /* ** if the limit-flag is specified: ** check if the next sample is expected before midnight; ** if not, stop atop now */ if (midnightflag && (curtime+interval) > timelimit) break; /* ** wait for alarm-signal to arrive (except first sample) ** or wait for SIGUSR1/SIGUSR2 */ if (sampcnt > 0 && awaittrigger) pause(); awaittrigger = 1; /* ** gather time info for this sample */ pretime = curtime; curtime = time(0); /* seconds since 1-1-1970 */ /* ** take a snapshot of the current system-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) */ hlpsstat = cursstat; /* swap current/prev. stats */ cursstat = presstat; presstat = hlpsstat; photosyst(cursstat); /* obtain new counters */ deviatsyst(cursstat, presstat, devsstat); /* ** take a snapshot of the current task-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) ** ** first register active tasks ** --> atop malloc's a minimal amount of space which is ** only extended when needed */ memset(curpact, 0, curplen * sizeof(struct tstat)); while ( (ntask = photoproc(curpact, curplen)) == curplen) { curplen += PROCCHUNK; curpact = realloc(curpact, curplen * sizeof(struct tstat)); ptrverify(curpact, "Realloc failed for %d tasks\n", curplen); memset(curpact, 0, curplen * sizeof(struct tstat)); } /* ** register processes that exited during last sample; ** first determine how many processes exited ** ** the number of exited processes is limited to avoid ** that atop explodes in memory and introduces OOM killing */ nexit = acctprocnt(); /* number of exited processes */ if (nexit > MAXACCTPROCS) { noverflow = nexit - MAXACCTPROCS; nexit = MAXACCTPROCS; } else noverflow = 0; /* ** determine how many processes have been exited ** for the netatop module (only processes that have ** used the network) */ if (nexit > 0 && (supportflags & NETATOPD)) nexitnet = netatop_exitstore(); else nexitnet = 0; /* ** reserve space for the exited processes and read them */ if (nexit > 0) { curpexit = malloc(nexit * sizeof(struct tstat)); ptrverify(curpexit, "Malloc failed for %d exited processes\n", nexit); memset(curpexit, 0, nexit * sizeof(struct tstat)); acctphotoproc(curpexit, nexit); /* ** reposition offset in accounting file when not ** all exited processes have been read (i.e. skip ** those processes) */ if (noverflow) acctrepos(noverflow); } else { curpexit = NULL; } /* ** calculate deviations */ devtstat = malloc((ntask+nexit) * sizeof(struct tstat)); ptrverify(devtstat, "Malloc failed for %d modified processes\n", ntask+nexit); ndeviat = deviatproc(curpact, ntask, curpexit, nexit, deviatonly, devtstat, devsstat, &nactproc, &totproc, &totrun, &totslpi, &totslpu, &totzombie); /* ** create list of pointers specifically to the process entries ** in the task list */ devpstat = malloc(sizeof (struct tstat *) * nactproc); ptrverify(devpstat, "Malloc failed for %d process ptrs\n", nactproc); for (i=0, j=0; i < ndeviat; i++) { if ( (devtstat+i)->gen.isproc) devpstat[j++] = devtstat+i; } /* ** activate the installed print-function to visualize ** the deviations */ lastcmd = (vis.show_samp)( curtime, curtime-pretime > 0 ? curtime-pretime : 1, devsstat, devtstat, devpstat, ndeviat, ntask, nactproc, totproc, totrun, totslpi, totslpu, totzombie, nexit, noverflow, sampcnt==0); /* ** release dynamically allocated memory */ if (nexit > 0) free(curpexit); if (nexitnet > 0) netatop_exiterase(); free(devtstat); free(devpstat); if (lastcmd == 'r') /* reset requested ? */ { sampcnt = -1; curtime = getboot() / hertz; // reset current time /* set current (will be 'previous') counters to 0 */ memset(cursstat, 0, sizeof(struct sstat)); memset(curpact, 0, curplen * sizeof(struct tstat)); /* remove all tasks in database */ pdb_makeresidue(); pdb_cleanresidue(); } } /* end of main-loop */ }
int main(int argc, char *argv[]) { register int i; int c; char *p; struct rlimit rlim; /* ** since priviliged actions will be done later on, at this stage ** the root-priviliges are dropped by switching effective user-id ** to real user-id (security reasons) */ if (! droprootprivs() ) { fprintf(stderr, "not possible to drop root privs\n"); exit(42); } /* ** preserve command arguments to allow restart of other version */ argvp = argv; /* ** read defaults-files /etc/atoprc en $HOME/.atoprc (if any) */ readrc("/etc/atoprc"); if ( (p = getenv("HOME")) ) { char path[1024]; snprintf(path, sizeof path, "%s/.atoprc", p); readrc(path); } /* ** check if we are supposed to behave as 'atopsar' ** i.e. system statistics only */ if ( (p = strrchr(argv[0], '/'))) p++; else p = argv[0]; if ( memcmp(p, "atopsar", 7) == 0) return atopsar(argc, argv); /* ** interpret command-line arguments & flags */ if (argc > 1) { /* ** gather all flags for visualization-functions ** ** generic flags will be handled here; ** unrecognized flags are passed to the print-routines */ i = 0; while (i < MAXFL-1 && (c=getopt(argc, argv, allflags)) != EOF) { switch (c) { case '?': /* usage wanted ? */ prusage(argv[0]); break; case 'V': /* version wanted ? */ printf("%s\n", getstrvers()); exit(0); case 'w': /* writing of raw data ? */ if (optind >= argc) prusage(argv[0]); strncpy(rawname, argv[optind++], RAWNAMESZ-1); vis.show_samp = rawwrite; break; case 'r': /* reading of raw data ? */ if (optind < argc && *(argv[optind]) != '-') strncpy(rawname, argv[optind++], RAWNAMESZ-1); rawreadflag++; break; case 'S': /* midnight limit ? */ midnightflag++; break; case 'a': /* all processes per sample ? */ deviatonly=0; break; case 'b': /* begin time ? */ if ( !hhmm2secs(optarg, &begintime) ) prusage(argv[0]); break; case 'e': /* end time ? */ if ( !hhmm2secs(optarg, &endtime) ) prusage(argv[0]); break; case 'j': /* show disk partitions statistics */ diskpartview = 1; break; case 'P': /* parseable output? */ if ( !parsedef(optarg) ) prusage(argv[0]); vis.show_samp = parseout; break; case 'L': /* line length */ if ( !numeric(optarg) ) prusage(argv[0]); linelen = atoi(optarg); break; default: /* gather other flags */ flaglist[i++] = c; } } /* ** get optional interval-value and optional number of samples */ if (optind < argc && optind < MAXFL) { if (!numeric(argv[optind])) prusage(argv[0]); interval = atoi(argv[optind]); optind++; if (optind < argc) { if (!numeric(argv[optind]) ) prusage(argv[0]); if ( (nsamples = atoi(argv[optind])) < 1) prusage(argv[0]); } } } /* ** determine the name of this node (without domain-name) ** and the kernel-version */ (void) uname(&utsname); if ( (p = strchr(utsname.nodename, '.')) ) *p = '\0'; utsnodenamelen = strlen(utsname.nodename); sscanf(utsname.release, "%d.%d.%d", &osrel, &osvers, &ossub); /* ** determine the clock rate and memory page size for this machine */ hertz = sysconf(_SC_CLK_TCK); pagesize = sysconf(_SC_PAGESIZE); /* ** check if raw data from a file must be viewed */ if (rawreadflag) { rawread(); cleanstop(0); } /* ** determine start-time for gathering current statistics */ curtime = getboot() / hertz; /* ** catch signals for proper close-down */ signal(SIGHUP, cleanstop); signal(SIGTERM, cleanstop); /* ** regain the root-priviliges that we dropped at the beginning ** to do some priviliged work */ regainrootprivs(); /* ** lock ATOP in memory to get reliable samples (also when ** memory is low); ** ignored if not running under superuser priviliges! */ rlim.rlim_cur = RLIM_INFINITY; rlim.rlim_max = RLIM_INFINITY; (void) setrlimit(RLIMIT_MEMLOCK, &rlim); (void) mlockall(MCL_CURRENT|MCL_FUTURE); /* ** increment CPU scheduling-priority to get reliable samples (also ** during heavy CPU load); ** ignored if not running under superuser priviliges! */ if ( nice(-20) == -1) ; /* ** switch-on the process-accounting mechanism to register the ** (remaining) resource-usage by processes which have finished */ acctreason = acctswon(); /* ** determine properties (like speed) of all interfaces */ initifprop(); /* ** open socket to the IP layer to issue getsockopt() calls later on */ netatop_ipopen(); /* ** since priviliged activities are finished now, there is no ** need to keep running under root-priviliges, so switch ** effective user-id to real user-id */ if (! droprootprivs() ) cleanstop(42); /* ** start the engine now ..... */ engine(); cleanstop(0); return 0; /* never reached */ }
/* * Install hard disk driver. * */ install() { int i, pdev, ldev; int maxsiz; char *s, *d, sdev, dvr[15]; char *lbuf; extern char rootstart, rootend; extern char bootstart, bootend; if ((ldev = glogdev()) < 0) return BAILOUT; /* final warning */ sdev = ldev + 'C'; (instfnl[INSTDRV].ob_spec)->te_ptext = &sdev; instfnl[INSTOK].ob_state = NORMAL; instfnl[INSTCN].ob_state = NORMAL; if (execform(instfnl) != INSTOK) return BAILOUT; /* find maximum sector size on system */ if (!vernum) /* new version of AHDI? */ maxsiz = 512; /* if not, sector size is always 512 bytes */ else maxsiz = *(vernum + 1); /* max sector size kept after version # */ if (!(lbuf = Malloc((long)maxsiz))) { err(nomemory); return ERROR; } /* find which physical unit the chosen logical drive belongs to */ pdev = physdev[ldev]; pdev &= 0x1f; /* mask off extra bits */ /* Remove old driver if there is one */ dvr[0] = sdev; strcpy(&dvr[1], OLDDVR); if (!(Fsfirst(dvr, 0x04))) /* 0x04 = system files */ Fdelete(dvr); /* copy driver to specified unit */ if (copydvr(sdev) != OK) return ERROR; /* read in the root sector */ if (getroot(pdev, lbuf) != 0) { err(rootread); goto argh; } /* copy boot code into root sector */ for (d = lbuf, s = &rootstart, i = &rootend - &rootstart; i--;) *d++ = *s++; /* if gemroot() is not successful, return with error */ if (gemroot(lbuf, 1) != 0) { err(cantinst); goto argh; } /* write installed root sector back to disk */ if (putroot(pdev, lbuf) != 0) { err(rootwrit); goto argh; } /* read boot sector from partition */ if (getboot(ldev, lbuf) != 0) { err(bootread); goto argh; } /* * copy boot code to boot sector, avoiding the BPB information * copy bytes 0..1 for BRA.S to code; * leave bytes 2..$1d unaltered (information for BPB); * copy bytes $1e..$1fe for code. */ s = &bootstart; d = lbuf; *d++ = *s++; *d++ = *s++; d += 0x1c; s += 0x1c; for (i = &bootend-&bootstart-0x1e; i--;) *d++ = *s++; /* make the image executable */ Protobt(lbuf, -1L, -1, 1); /* write the installed boot sector back to disk */ if (putboot(ldev, lbuf) != 0) { err(bootwrit); goto argh; } return; argh: dvr[0] = sdev; strcpy(&dvr[1], DVRNAME); Fdelete(dvr); }
int photoproc(struct tstat *tasklist, int maxtask) { static int firstcall = 1; static unsigned long long bootepoch; register struct tstat *curtask; FILE *fp; DIR *dirp; struct dirent *entp; char origdir[1024]; int tval=0; /* ** one-time initialization stuff */ if (firstcall) { /* ** check if this kernel offers io-statistics per task */ regainrootprivs(); if ( (fp = fopen("/proc/1/io", "r")) ) { supportflags |= IOSTAT; fclose(fp); } if (! droprootprivs()) cleanstop(42); /* ** find epoch time of boot moment */ bootepoch = getboot(); firstcall = 0; } /* ** probe if the netatop module and (optionally) the ** netatopd daemon are active */ regainrootprivs(); netatop_probe(); if (! droprootprivs()) cleanstop(42); /* ** read all subdirectory-names below the /proc directory */ if ( getcwd(origdir, sizeof origdir) == NULL) cleanstop(53); if ( chdir("/proc") == -1) cleanstop(53); dirp = opendir("."); while ( (entp = readdir(dirp)) && tval < maxtask ) { /* ** skip non-numerical names */ if (!isdigit(entp->d_name[0])) continue; /* ** change to the process' subdirectory */ if ( chdir(entp->d_name) != 0 ) continue; /* ** gather process-level information */ curtask = tasklist+tval; if ( !procstat(curtask, bootepoch, 1)) /* from /proc/pid/stat */ { if ( chdir("..") == -1); continue; } if ( !procstatus(curtask) ) /* from /proc/pid/status */ { if ( chdir("..") == -1); continue; } if ( !procio(curtask) ) /* from /proc/pid/io */ { if ( chdir("..") == -1); continue; } proccmd(curtask); /* from /proc/pid/cmdline */ // read network stats from netatop netatop_gettask(curtask->gen.tgid, 'g', curtask); tval++; /* increment for process-level info */ /* ** if needed (when number of threads is larger than 0): ** read and fill new entries with thread-level info */ if (curtask->gen.nthr > 1) { DIR *dirtask; struct dirent *tent; curtask->gen.nthrrun = 0; curtask->gen.nthrslpi = 0; curtask->gen.nthrslpu = 0; /* ** open underlying task directory */ if ( chdir("task") == 0 ) { dirtask = opendir("."); while ((tent=readdir(dirtask)) && tval<maxtask) { struct tstat *curthr = tasklist+tval; /* ** change to the thread's subdirectory */ if ( tent->d_name[0] == '.' || chdir(tent->d_name) != 0 ) continue; if ( !procstat(curthr, bootepoch, 0)) { if ( chdir("..") == -1); continue; } if ( !procstatus(curthr) ) { if ( chdir("..") == -1); continue; } if ( !procio(curthr) ) { if ( chdir("..") == -1); continue; } switch (curthr->gen.state) { case 'R': curtask->gen.nthrrun += 1; break; case 'S': curtask->gen.nthrslpi += 1; break; case 'D': curtask->gen.nthrslpu += 1; break; } curthr->gen.nthr = 1; // read network stats from netatop netatop_gettask(curthr->gen.pid, 't', curthr); // all stats read now tval++; /* increment thread-level */ if ( chdir("..") == -1); /* thread */ } closedir(dirtask); if ( chdir("..") == -1); /* leave task */ } } if ( chdir("..") == -1); /* leave process-level directry */ } closedir(dirp); if ( chdir(origdir) == -1) cleanstop(53); return tval; }
/* ** The engine() drives the main-loop of the program */ static void engine(void) { struct sigaction sigact; static time_t timelimit; void getusr1(int), getusr2(int); /* ** reserve space for system-level statistics */ static struct sstat *cursstat; /* current */ static struct sstat *presstat; /* previous */ static struct sstat *devsstat; /* deviation */ static struct sstat *hlpsstat; /* ** reserve space for process-level statistics */ static struct pstat *curpact; /* current active list */ static int curplen; /* current active size */ struct pstat *curpexit; /* exitted process list */ struct pstat *devpstat; /* deviation list */ int npresent, nexit, n; int ntrun, ntslpi, ntslpu, nzombie; /* ** initialization: allocate required memory dynamically */ cursstat = calloc(1, sizeof(struct sstat)); presstat = calloc(1, sizeof(struct sstat)); devsstat = calloc(1, sizeof(struct sstat)); curplen = countprocs() + PROCCHUNK; curpact = calloc(curplen, sizeof(struct pstat)); if (!cursstat || !presstat || !devsstat || !curpact) { fprintf(stderr, "unexpected calloc-failure...\n"); cleanstop(1); } /* ** install the signal-handler for ALARM, USR1 and USR2 (triggers * for the next sample) */ memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr1; sigaction(SIGUSR1, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getusr2; sigaction(SIGUSR2, &sigact, (struct sigaction *)0); memset(&sigact, 0, sizeof sigact); sigact.sa_handler = getalarm; sigaction(SIGALRM, &sigact, (struct sigaction *)0); if (interval > 0) alarm(interval); if (midnightflag) { time_t timenow = time(0); struct tm *tp = localtime(&timenow); tp->tm_hour = 23; tp->tm_min = 59; tp->tm_sec = 59; timelimit = mktime(tp); } /* ** MAIN-LOOP: ** - Wait for the requested number of seconds or for other trigger ** ** - System-level counters ** get current counters ** calculate the differences with the previous sample ** ** - Process-level counters ** get current counters from running & exited processes ** calculate the differences with the previous sample ** ** - Call the print-function to visualize the differences */ for (sampcnt=0; sampcnt < nsamples; sampcnt++) { char lastcmd; /* ** if the limit-flag is specified: ** check if the next sample is expected before midnight; ** if not, stop atop now */ if (midnightflag && (curtime+interval) > timelimit) break; /* ** wait for alarm-signal to arrive (except first sample) ** or wait for SIGUSR1/SIGUSR2 */ if (sampcnt > 0 && awaittrigger) pause(); awaittrigger = 1; /* ** gather time info for this sample */ pretime = curtime; curtime = time(0); /* seconds since 1-1-1970 */ /* ** take a snapshot of the current system-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) */ hlpsstat = cursstat; /* swap current/prev. stats */ cursstat = presstat; presstat = hlpsstat; photosyst(cursstat); /* obtain new counters */ deviatsyst(cursstat, presstat, devsstat); /* ** take a snapshot of the current process-level statistics ** and calculate the deviations (i.e. calculate the activity ** during the last sample) ** ** first register active processes ** --> atop malloc's a minimal amount of space which is ** only extended when needed */ memset(curpact, 0, curplen * sizeof(struct pstat)); while ( (npresent = photoproc(curpact, curplen)) == curplen) { curplen = countprocs() + PROCCHUNK; curpact = realloc(curpact, curplen * sizeof(struct pstat)); memset(curpact, 0, curplen * sizeof(struct pstat)); } /* ** register processes which exited during last sample; ** first determine how many processes exited and ** reserve space for them, and secondly obtain the info */ nexit = acctprocnt(); /* number of exited processes */ if (nexit > 0) { curpexit = malloc( nexit * sizeof(struct pstat)); memset(curpexit, 0, nexit * sizeof(struct pstat)); acctphotoproc(curpexit, nexit); } else curpexit = NULL; /* ** calculate deviations */ devpstat = malloc((npresent+nexit) * sizeof(struct pstat)); n = deviatproc(curpact, npresent, curpexit, nexit, deviatonly, devpstat, devsstat, &ntrun, &ntslpi, &ntslpu, &nzombie); /* ** activate the installed print-function to visualize ** the deviations */ lastcmd = (vis.show_samp)( curtime, curtime-pretime > 0 ? curtime-pretime : 1, devsstat, devpstat, n, npresent, ntrun, ntslpi, ntslpu, nzombie, nexit, sampcnt==0); /* ** release dynamically allocated memory */ if (nexit > 0) free(curpexit); free(devpstat); if (lastcmd == 'r') /* reset requested ? */ { sampcnt = -1; curtime = getboot(); /* reset current time */ /* set current (will be 'previous') counters to 0 */ memset(cursstat, 0, sizeof(struct sstat)); memset(curpact, 0, curplen * sizeof(struct pstat)); /* remove all processes in process database */ pdb_makeresidue(); pdb_cleanresidue(); } } /* end of main-loop */ }