dockapps/wmfsm/wmfsm/wmfsm.c
Doug Torrance 2be3432290 wmfsm: Handle errors related to the HOME environment variable.
In particular, if HOME is undefined, then a segmentation fault will occur.
Also, if HOME is at least 245 characters, then a buffer overflow will occur.
We check for these conditions and exit with an error message instead.

Patch obtained from Debian package [1].

[1] https://sources.debian.net/src/wmfsm/0.35-1/debian/patches/handle_HOME_errors.patch/
2015-08-21 08:24:26 +01:00

651 lines
14 KiB
C

/*
*
* wmfsm (C) 1999 Stefan Eilemann (Stefan.Eilemann@dlr.de)
*
* - Shows file system usage ala mfsm
*
*
*
*
* 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 (see the file COPYING); if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA
*
*
*
* Changes: #include "../ChangeLog"
*
*/
/*
* Includes
*/
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <X11/X.h>
#include <X11/xpm.h>
#include <libdockapp/wmgeneral.h>
#include "wmfsm_master.xpm"
#include "wmfsm_mask.xbm"
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef SVR4
#include <netdb.h>
#include <sys/systeminfo.h>
#endif /* SVR4 */
#ifdef HAVE_SYS_VFS_H
#include <sys/vfs.h>
#endif
#ifdef HAVE_SYS_STATFS_H
#include <sys/statfs.h>
#endif
#ifdef HAVE_SYS_MOUNT_H
#include <sys/mount.h>
#endif
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef STATFS_2_ARGUMENTS
# define STATFS(a,b) statfs(a,b)
#elif defined STATFS_4_ARGUMENTS
# define STATFS(a,b) statfs(a,b,sizeof(struct statfs),0)
#else
# define STATFS(a,b) statfs(a,b) /* Maybe configure got messed up */
#endif
/*
#if defined IRIX64
# include <sys/types.h>
# define STATFS(a,b) statfs(a,b,sizeof(struct statfs),0)
#elif defined linux
# define STATFS(a,b) statfs(a,b)
#elif defined(SunOS)
# define STATFS(a,b) statfs(a,b,sizeof(struct statfs),0)
#elif defined(__OpenBSD__) || defined(__FreeBSD__)
# define STATFS(a,b) statfs(a,b)
# include <sys/param.h>
#endif
*/
#define _GNU_SOURCE
#include <getopt.h>
/*
* Delay between refreshes (in microseconds), uses the 10*DELAY_10
* coz irix has max of 100000L :(.
*/
#define DELAY_10 99999L
#define LENMP 5 /*max 10, number char for mountpoint */
/*modes for drawing*/
#define NORMAL 0
#define FIRE 1
void ParseCMDLine(int argc, char *argv[]);
void pressEvent(XButtonEvent * xev);
void readFileSystems(void);
void excludeFileSystems(void);
void print_usage(void);
int UpToDate = 0;
int ForceUpdate = 1;
char *mp[100];
int per[9];
int numberfs;
int mode = FIRE;
int blink = 1;
int blinkper = 95;
char dummy[4096];
char *myName;
int delay = DELAY_10;
char appearance[256] = "";
int xpos[] = { 66, 71, 76, 81, 86, 91, /* A B C D E F */
66, 71, 76, 81, 86, 91, /* G H I J K L */
66, 71, 76, 81, 86, 91, /* M N O P Q R */
66, 71, 76, 81, 86, 91, /* S T U V W X */
66, 71, 76, 81, 86, 91, /* Y Z / _ - . */
96, 101, /* 0 1 */
96, 101, /* 2 3 */
96, 101, /* 4 5 */
96, 101, /* 6 7 */
96, 101
}; /* 8 9 */
int ypos[] = { 4, 4, 4, 4, 4, 4,
9, 9, 9, 9, 9, 9,
14, 14, 14, 14, 14, 14,
19, 19, 19, 19, 19, 19,
24, 24, 24, 24, 24, 24,
4, 4,
9, 9,
14, 14,
19, 19,
24, 24
};
/*
* main
*/
int
main(int argc, char *argv[])
{
XEvent event;
int dx, dy;
char hostname[100];
int i, j, k;
int xpm_free = 0;
int c, on[9] = { 1, 1, 1, 1, 1, 1, 1, 1, 1 };
struct statfs buffer;
char **pixmap;
/*
* Parse any command line arguments.
*/
myName = strdup(argv[0]);
ParseCMDLine(argc, argv);
if (appearance[0] == 0) {
pixmap = wmfsm_master_xpm;
} else {
if (XpmReadFileToData(appearance, &pixmap) != XpmSuccess) {
fprintf(stderr, "warning: could not read appearance file; using default.\n");
pixmap = wmfsm_master_xpm;
} else {
xpm_free = 1;
}
}
openXwindow(argc, argv, pixmap, wmfsm_mask_bits, wmfsm_mask_width, wmfsm_mask_height);
if (xpm_free)
XpmFree(pixmap);
#ifndef SVR4
if (gethostname(hostname, 100) != 0) {
perror("gethostname");
exit(10);
}
#else
if (sysinfo(SI_HOSTNAME, hostname, 100) < 0) {
perror("sysinfo(SI_HOSTNAME)");
exit(20);
}
#endif
while (1) {
readFileSystems ();
usleep (100);
/*
* Process any pending X events.
*/
while (XPending(display)) {
XNextEvent(display, &event);
switch (event.type) {
case Expose:
RedrawWindow();
break;
case ButtonPress:
pressEvent(&event.xbutton);
mode = (mode + 1) % 2;
break;
case ButtonRelease:
break;
}
}
/*! Here read data
*/
for (i = 0; i < numberfs; i++) {
if (STATFS(mp[i], &buffer) != -1) {
per[i] = 100 - (int) ((float) buffer.f_bfree / (float) buffer.f_blocks * 100.0);
}
}
/*!
* Draw window.
*/
/*
* Clear window.
*/
copyXPMArea(5, 69, 54, 54, 5, 5);
/*! here draw values
* void copyXPMArea(int x, int y, int sx, int sy, int dx, int dy)
*/
if (numberfs > 4) {
for (i = 0, dy = 0; i < numberfs; i++) {
for (j = 0, dx = 0; j < LENMP && (unsigned int)j < strlen(mp[i]); j++) {
k = j + (strlen(mp[i]) > LENMP ? strlen(mp[i]) - LENMP : 0);
c = (int) mp[i][k];
switch (c) {
case '/':
c = 123;
break;
case '_':
c = 124;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
c += 79;
break;
default:
c = tolower(c);
break;
}
copyXPMArea(xpos[c - 97], ypos[c - 97], 5, 5, 6 + dx, 5 + dy);
dx += 5;
}
c = (int) ((float) per[i] * 0.52 + 66.0);
k = (10 - LENMP) * 5 + 2;
k = (float) per[i] / 100.0 * k;
k = LENMP * 5 + k;
k = k < LENMP * 5 + 1 ? LENMP * 5 + 1 : k;
c = c > 66 ? c : 66;
c = c > 117 ? 117 : c;
if (blink) {
if ((int) per[i] >= blinkper)
on[i] = !on[i];
else
on[i] = 1;
}
else
on[i] = 1;
for (j = LENMP * 5; j < k; j++) {
if (mode == FIRE && on[i])
copyXPMArea(66 + (float) (j - LENMP * 5) * 52.0 / (float) ((10 - LENMP) * 5), 29, 1, 5, 6 + j, 5 + dy);
else if (mode == NORMAL && on[i])
copyXPMArea(c, 29, 1, 5, 6 + j, 5 + dy);
}
dy += 6;
}
}
else { /*one fs in two lines */
for (i = 0, dy = 0; i < numberfs; i++) {
for (j = 0, dx = 0; j < 10 && (unsigned int)j < strlen(mp[i]); j++) {
c = (int) mp[i][j + (strlen(mp[i]) > 10 ? strlen(mp[i]) - 10 : 0)];
switch (c) {
case '/':
c = 123;
break;
case '_':
c = 124;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
c += 79;
break;
default:
c = tolower(c);
break;
}
copyXPMArea(xpos[c - 97], ypos[c - 97], 5, 5, 6 + dx, 5 + dy);
dx += 5;
}
dy += 6;
c = (int) ((float) per[i] * 0.52 + 66.0);
k = (float) per[i] / 100.0 * 52;
k = k < 1 ? 1 : k;
c = c > 66 ? c : 66;
c = c > 117 ? 117 : c;
if (blink) {
if ((int) per[i] >= blinkper)
on[i] = !on[i];
else
on[i] = 1;
}
else
on[i] = 1;
for (j = 0; j < k; j++) {
if (mode == FIRE && on[i])
copyXPMArea(66 + (float) (j) * 52.0 / 50.0, 29, 1, 5, 6 + j, 5 + dy);
else if (mode == NORMAL && on[i])
copyXPMArea(c, 29, 1, 5, 6 + j, 5 + dy);
}
dy += 6;
}
}
if (numberfs < 9) {
for (j = 0, dx = 0, dy = 47; j < 10 && (unsigned int)j < strlen(hostname); j++) {
c = (int) hostname[j];
switch (c) {
case '/':
c = 123;
break;
case '_':
c = 124;
break;
case '-':
c = 125;
break;
case '.':
c = 126;
break;
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
c += 79;
break;
default:
c = tolower(c);
break;
}
copyXPMArea(xpos[c - 97], ypos[c - 97], 5, 5, 6 + dx, 6 + dy);
dx += 5;
}
}
RedrawWindow();
/*
* Wait for next update
*/
i = 0;
while (i < 10) {
usleep(delay);
i++;
}
}
}
/*
* ParseCMDLine()
*/
void
ParseCMDLine(int argc, char *argv[])
{
int c, option_index;
static struct option long_options[] = {
{"fire", no_argument, 0, 'f'},
{"normal", no_argument, 0, 'n'},
{"blink", no_argument, &blink, 1},
{"noblink", no_argument, &blink, 0},
{"delay", required_argument, 0, 'd'},
{"appearance", required_argument, 0, 'a'},
{"help", no_argument, 0, 'h'},
{"version", no_argument, 0, 'v'},
{0, 0, 0, 0}
};
while (1) {
c = getopt_long(argc, argv, "a:bd:fhnv", long_options, &option_index);
if (c == -1)
break;
switch (c) {
case 0: /* If blink or noblink was toggled */
break;
case 'a':
strcpy(appearance, optarg);
break;
case 'b':
blink = 1;
break;
case 'd':
delay = atoi(optarg);
break;
case 'f':
mode = FIRE;
break;
case 'h':
print_usage();
exit(0);
case 'n':
mode = NORMAL;
break;
case 'v':
printf("wmfsm version: %s\n", PACKAGE_VERSION);
exit(0);
case '?':
break;
default:
print_usage();
exit(1);
}
}
}
void
print_usage()
{
printf("usage: wmfsm \n");
printf("\t--normal, -n\t\tDraw bars in normal mode.\n");
printf("\t--fire, -f\t\tDraw bars in fire mode.\n");
printf("\t--[no]blink\t\tBlinks if a filesystem is 95 percent full.\n");
printf("\t-display <Display>\tUse alternate X display.\n");
printf("\t--delay <number>, -d\tUse a delay that is not the default.\n");
printf("\t--appearance <file>, -a\tSelect an appearance file.\n");
printf("\t-h\t\t\tDisplay help screen.\n");
}
void
pressEvent(XButtonEvent * xev)
{
(void)xev;
ForceUpdate = 1;
return;
}
void
readFileSystems()
{
/* Wipe mp[] */
int i;
for (i = 0; i < 100; i++)
if (mp[i]) {
free(mp[i]);
mp[i]=0;
}
/* Look for the goods between #if defined(__OpenBSD__) -- tschroed */
#if defined(__OpenBSD__) || defined(__FreeBSD__)
#define MAXMOUNT 32
struct statfs sfs[MAXMOUNT];
int fscount;
/* OpenBSD has no /etc/mtab, we use getfsstat instead -- tschroed */
if ((fscount = getfsstat(sfs, sizeof(sfs), 0)) == -1) {
perror("getfsstat");
exit(1);
}
for (numberfs = 0; numberfs < fscount; numberfs++)
/* We won't watch RO mounts. */
if (sfs[numberfs].f_flags & MNT_RDONLY) {
numberfs--;
fscount--;
}
else
mp[numberfs] = strdup(sfs[numberfs].f_mntonname);
#else /* __OpenBSD__ || __FreeBSD__ */
FILE *fp;
char mountPoint[255], dummy[255], fstype[255], options[512];
#if defined(SunOS)
/* Solaris uses /etc/mnttab */
fp = fopen("/etc/mnttab", "r");
if (!fp) {
fprintf(stderr, "%s:Can't open /etc/mnttab for reading\n", myName);
exit(1);
}
#else
fp = fopen("/etc/mtab", "r");
if (!fp) {
fprintf(stderr, "%s:Can't open /etc/mtab for reading\n", myName);
exit(1);
}
#endif
numberfs = 0;
while (!feof(fp) && numberfs < 100) {
#if defined(SunOS)
/* only five entries per row in /etc/mnttab */
if (fscanf(fp, "%s %s %s %s %s\n", dummy, mountPoint, fstype, options, dummy) < 5)
fprintf(stderr, "%s:/etc/mnttab not in expected format\n", myName);
#else
if (fscanf(fp, "%s %s %s %s %s %s\n", dummy, mountPoint, fstype, options, dummy, dummy) < 6)
fprintf(stderr, "%s:/etc/mtab not in expected format\n", myName);
#endif
if (
#if defined IRIX64 || defined(SunOS)
strcmp(fstype, "hwgfs") && strcmp(fstype, "autofs") && strcmp(fstype, "proc") && strcmp(fstype, "fd") && !strstr(options, "ignore")
#elif defined linux
strcmp(fstype, "proc") && strcmp(fstype, "tmpfs") && strcmp(fstype, "devfs") && strcmp(fstype, "ramfs") && strcmp(fstype, "sysfs") && strcmp(fstype, "devpts") && strcmp(fstype, "usbfs")
#else
1
#endif
) {
if (mp[numberfs]) free(mp[numberfs]);
mp[numberfs++] = strdup(mountPoint);
}
}
#endif /* __OpenBSD__ || __FreeBSD__ */
fclose (fp);
excludeFileSystems();
}
void
excludeFileSystems()
{
char confFileName[255];
char workString[255];
char *home;
int i, j, exnumberfs = 0;
int excluded, finalnumberfs = 0;
char *mount_points[100];
FILE *confFile;
int include = -1;
int included = 0;
home = getenv("HOME");
if (home == NULL) {
fprintf(stderr, "error: HOME must be defined\n");
exit(1);
}
if (strlen(home) > 244) {
fprintf(stderr,
"error: HOME may not be longer than 244 characters\n");
exit(1);
}
strncpy(confFileName, home, 245);
strcat(confFileName, "/.wmfsmrc");
confFile = fopen(confFileName, "r");
if (confFile) {
while (!feof(confFile)) {
if (fgets(workString, 255, confFile)) {
if(strstr(workString, "\n")){
/* This is probably dangerous, but easy */
*(strstr(workString, "\n")) = '\0';
}
if (!strcmp(workString, "[include]")) {
include = 1;
}
else if (!strcmp(workString, "[exclude]")) {
include = 0;
}
else {
mount_points[exnumberfs] = strdup(workString);
exnumberfs++;
}
}
}
if (include < 0) {
printf("wmfsm: Please specify either to include or exclude filesystems.\n");
exit(1);
}
fclose(confFile);
}
else {
numberfs = numberfs > 9 ? 9 : numberfs;
goto CLEANUP;
}
if (!exnumberfs) {
numberfs = numberfs > 9 ? 9 : numberfs;
goto CLEANUP;
}
excluded = 0;
for (i = 0; i < numberfs; i++) {
for (j = 0, excluded = 0; j < exnumberfs; j++) {
if (!strcmp(mp[i], mount_points[j]) && !include) {
excluded = 1;
} else if (!strcmp(mp[i], mount_points[j]) && include) {
included = 1;
}
}
if ((!excluded && !include) || (included && include)) {
if (finalnumberfs == i) {
finalnumberfs++;
} else {
if (mp[finalnumberfs]) free(mp[finalnumberfs]);
mp[finalnumberfs++] = strdup(mp[i]);
}
}
included = excluded = 0;
}
numberfs = finalnumberfs > 9 ? 9 : finalnumberfs;
CLEANUP:
for (j = 0; j < exnumberfs; j++)
if (mount_points[j]) {
free(mount_points[j]);
mount_points[j]=0;
}
}