NetBSD/sbin/fsck/progress.c

176 lines
4.9 KiB
C

/* $NetBSD: progress.c,v 1.3 2006/11/14 21:01:46 apb Exp $ */
/*-
* Copyright (c) 1997-2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn; by Chris Gilbert; and by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SMALL
#include <sys/cdefs.h>
__RCSID("$NetBSD: progress.c,v 1.3 2006/11/14 21:01:46 apb Exp $");
/*
* File system independent fsck progress bar routines.
*/
#include <sys/param.h>
#include <sys/tty.h>
#include <sys/ioctl.h>
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "progress.h"
static int ttywidth = 80;
static int progress_onoff;
static int progress_lowlim;
static int progress_highlim;
#define BUFLEFT (sizeof(buf) - len)
void
progress_switch(int onoff)
{
progress_onoff = onoff;
}
void
progress_init(void)
{
progress_setrange(0, 100);
}
/* Set both low and high limit. */
void
progress_setrange(int lowlim, int highlim)
{
progress_lowlim = lowlim;
progress_highlim = highlim;
}
/* Previous high limit becomes new low limit; set new high limit. */
void
progress_sethighlim(int highlim)
{
progress_setrange(progress_highlim, highlim);
}
/*
* Display a progress bar, assuming that current/total represents a
* percentage in the range [progress_lowlim .. progress_highlim].
*/
void
progress_bar(const char *dev, const char *label, off_t current, off_t total)
{
static int lastpercentage = -1;
char buf[256];
int len, percentage;
int barlength;
int i;
int lengthextras;
#define BAROVERHEAD 10 /* non-* portion of progress bar */
/*
* stars should contain at least sizeof(buf) - BAROVERHEAD
* entries.
*/
static const char stars[] =
"*****************************************************************************"
"*****************************************************************************"
"*****************************************************************************";
if (progress_onoff == 0)
return;
len = 0;
lengthextras = strlen(dev) + (label != NULL ? strlen(label) : 0);
percentage = progress_lowlim +
(current * (progress_highlim - progress_lowlim)) / total;
percentage = MAX(percentage, 0);
percentage = MIN(percentage, 100);
if (percentage == lastpercentage)
return;
lastpercentage = percentage;
len += snprintf(buf + len, BUFLEFT, "%s: ", dev);
if (label != NULL)
len += snprintf(buf + len, BUFLEFT, "%s ", label);
barlength = MIN(sizeof(buf) - 1, ttywidth) - BAROVERHEAD - lengthextras;
if (barlength > 0) {
i = barlength * percentage / 100;
len += snprintf(buf + len, BUFLEFT,
"|%.*s%*s| ", i, stars, barlength - i, "");
}
len += snprintf(buf + len, BUFLEFT, "%3d%%\r", percentage);
write(fileno(stdout), buf, len);
}
void
progress_done(void)
{
char buf[256];
int len;
if (progress_onoff == 0)
return;
len = MIN(sizeof(buf) - 2, ttywidth);
memset(buf, ' ', len);
buf[len] = '\r';
buf[len + 1] = '\0';
write(fileno(stdout), buf, len + 1);
}
void
progress_ttywidth(int a)
{
struct winsize winsize;
int oerrno = errno;
if (ioctl(fileno(stdout), TIOCGWINSZ, &winsize) != -1 &&
winsize.ws_col != 0)
ttywidth = winsize.ws_col;
else
ttywidth = 80;
errno = oerrno;
}
#endif /* ! SMALL */