Sync to HEAD@r274297.

This commit is contained in:
Alexander V. Chernikov 2014-11-08 18:13:35 +00:00
commit a9413f6ca0
221 changed files with 11026 additions and 3257 deletions

View File

@ -1537,6 +1537,7 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} \
${_kerberos5_lib_libwind} \
lib/libbz2 ${_libcom_err} lib/libcrypt \
lib/libelf lib/libexpat \
lib/libfigpar \
${_lib_libgssapi} \
lib/libkiconv lib/libkvm lib/liblzma lib/libmd lib/libnv \
${_lib_libcapsicum} \
@ -1551,7 +1552,8 @@ _prebuild_libs= ${_kerberos5_lib_libasn1} \
${_cddl_lib_libctf} \
lib/libutil lib/libpjdlog ${_lib_libypclnt} lib/libz lib/msun \
${_secure_lib_libcrypto} ${_lib_libldns} \
${_secure_lib_libssh} ${_secure_lib_libssl}
${_secure_lib_libssh} ${_secure_lib_libssl} \
gnu/lib/libdialog
.if ${MK_GNUCXX} != "no"
_prebuild_libs+= gnu/lib/libstdc++ gnu/lib/libsupc++
gnu/lib/libstdc++__L: lib/msun__L
@ -1669,6 +1671,8 @@ _lib_libypclnt= lib/libypclnt
lib/libradius__L: lib/libmd__L
.endif
gnu/lib/libdialog__L: lib/msun__L lib/ncurses/ncursesw__L
.for _lib in ${_prereq_libs}
${_lib}__PL: .PHONY .MAKE
.if exists(${.CURDIR}/${_lib})

View File

@ -9,7 +9,7 @@ SRCS= df.c vfslist.c
CFLAGS+= -I${MOUNT}
DPADD= ${LIBUTIL}
LDADD= -lutil
DPADD= ${LIBUTIL} ${LIBXO}
LDADD= -lutil -lxo
.include <bsd.prog.mk>

View File

@ -29,7 +29,7 @@
.\" @(#)df.1 8.3 (Berkeley) 5/8/95
.\" $FreeBSD$
.\"
.Dd January 16, 2014
.Dd November 6, 2014
.Dt DF 1
.Os
.Sh NAME
@ -37,6 +37,7 @@
.Nd display free disk space
.Sh SYNOPSIS
.Nm
.Op Fl -libxo
.Op Fl b | g | H | h | k | m | P
.Op Fl acilnT
.Op Fl \&,
@ -193,7 +194,9 @@ If the value is outside, it will be set to the appropriate limit.
.Xr statfs 2 ,
.Xr getbsize 3 ,
.Xr getmntinfo 3 ,
.Xr libxo 3 ,
.Xr localeconv 3 ,
.Xr xo_parse_args 3 ,
.Xr fstab 5 ,
.Xr mount 8 ,
.Xr pstat 8 ,

View File

@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#include <sysexits.h>
#include <unistd.h>
#include <libxo/xo.h>
#include "extern.h"
@ -82,7 +83,7 @@ static char *getmntpt(const char *);
static int int64width(int64_t);
static char *makenetvfslist(void);
static void prthuman(const struct statfs *, int64_t);
static void prthumanval(int64_t);
static void prthumanval(const char *, int64_t);
static intmax_t fsbtoblk(int64_t, uint64_t, u_long);
static void prtstat(struct statfs *, struct maxwidths *);
static size_t regetmntinfo(struct statfs **, long, const char **);
@ -119,6 +120,11 @@ main(int argc, char *argv[])
totalbuf.f_bsize = DEV_BSIZE;
strlcpy(totalbuf.f_mntfromname, "total", MNAMELEN);
vfslist = NULL;
argc = xo_parse_args(argc, argv);
if (argc < 0)
exit(1);
while ((ch = getopt(argc, argv, "abcgHhiklmnPt:T,")) != -1)
switch (ch) {
case 'a':
@ -161,7 +167,7 @@ main(int argc, char *argv[])
break;
case 'l':
if (vfslist != NULL)
errx(1, "-l and -t are mutually exclusive.");
xo_errx(1, "-l and -t are mutually exclusive.");
vfslist = makevfslist(makenetvfslist());
lflag = 1;
break;
@ -174,9 +180,9 @@ main(int argc, char *argv[])
break;
case 't':
if (lflag)
errx(1, "-l and -t are mutually exclusive.");
xo_errx(1, "-l and -t are mutually exclusive.");
if (vfslist != NULL)
errx(1, "only one -t option may be specified");
xo_errx(1, "only one -t option may be specified");
fstype = optarg;
vfslist = makevfslist(optarg);
break;
@ -202,16 +208,19 @@ main(int argc, char *argv[])
/* just the filesystems specified on the command line */
mntbuf = malloc(argc * sizeof(*mntbuf));
if (mntbuf == NULL)
err(1, "malloc()");
xo_err(1, "malloc()");
mntsize = 0;
/* continued in for loop below */
}
xo_open_container("storage-system-information");
xo_open_list("filesystem");
/* iterate through specified filesystems */
for (; *argv; argv++) {
if (stat(*argv, &stbuf) < 0) {
if ((mntpt = getmntpt(*argv)) == NULL) {
warn("%s", *argv);
xo_warn("%s", *argv);
rv = 1;
continue;
}
@ -220,20 +229,20 @@ main(int argc, char *argv[])
mdev.fspec = *argv;
mntpath = strdup("/tmp/df.XXXXXX");
if (mntpath == NULL) {
warn("strdup failed");
xo_warn("strdup failed");
rv = 1;
continue;
}
mntpt = mkdtemp(mntpath);
if (mntpt == NULL) {
warn("mkdtemp(\"%s\") failed", mntpath);
xo_warn("mkdtemp(\"%s\") failed", mntpath);
rv = 1;
free(mntpath);
continue;
}
if (mount(fstype, mntpt, MNT_RDONLY,
&mdev) != 0) {
warn("%s", *argv);
xo_warn("%s", *argv);
rv = 1;
(void)rmdir(mntpt);
free(mntpath);
@ -244,7 +253,7 @@ main(int argc, char *argv[])
if (cflag)
addstat(&totalbuf, &statfsbuf);
} else {
warn("%s", *argv);
xo_warn("%s", *argv);
rv = 1;
}
(void)unmount(mntpt, 0);
@ -260,7 +269,7 @@ main(int argc, char *argv[])
* implement nflag here.
*/
if (statfs(mntpt, &statfsbuf) < 0) {
warn("%s", mntpt);
xo_warn("%s", mntpt);
rv = 1;
continue;
}
@ -294,8 +303,14 @@ main(int argc, char *argv[])
for (i = 0; i < mntsize; i++)
if (aflag || (mntbuf[i].f_flags & MNT_IGNORE) == 0)
prtstat(&mntbuf[i], &maxwidths);
xo_close_list("filesystem");
if (cflag)
prtstat(&totalbuf, &maxwidths);
xo_close_container("storage-system-information");
xo_finish();
return (rv);
}
@ -341,7 +356,7 @@ regetmntinfo(struct statfs **mntbufp, long mntsize, const char **vfslist)
if (nflag || error < 0)
if (i != j) {
if (error < 0)
warnx("%s stats possibly stale",
xo_warnx("%s stats possibly stale",
mntbuf[i].f_mntonname);
mntbuf[j] = mntbuf[i];
}
@ -354,13 +369,13 @@ static void
prthuman(const struct statfs *sfsp, int64_t used)
{
prthumanval(sfsp->f_blocks * sfsp->f_bsize);
prthumanval(used * sfsp->f_bsize);
prthumanval(sfsp->f_bavail * sfsp->f_bsize);
prthumanval(" {:blocks/%6s}", sfsp->f_blocks * sfsp->f_bsize);
prthumanval(" {:used/%6s}", used * sfsp->f_bsize);
prthumanval(" {:available/%6s}", sfsp->f_bavail * sfsp->f_bsize);
}
static void
prthumanval(int64_t bytes)
prthumanval(const char *fmt, int64_t bytes)
{
char buf[6];
int flags;
@ -372,14 +387,15 @@ prthumanval(int64_t bytes)
humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
bytes, "", HN_AUTOSCALE, flags);
(void)printf(" %6s", buf);
xo_attr("value", "%lld", (long long) bytes);
xo_emit(fmt, buf);
}
/*
* Print an inode count in "human-readable" format.
*/
static void
prthumanvalinode(int64_t bytes)
prthumanvalinode(const char *fmt, int64_t bytes)
{
char buf[6];
int flags;
@ -389,7 +405,8 @@ prthumanvalinode(int64_t bytes)
humanize_number(buf, sizeof(buf) - (bytes < 0 ? 0 : 1),
bytes, "", HN_AUTOSCALE, flags);
(void)printf(" %5s", buf);
xo_attr("value", "%lld", (long long) bytes);
xo_emit(fmt, buf);
}
/*
@ -434,70 +451,77 @@ prtstat(struct statfs *sfsp, struct maxwidths *mwp)
mwp->used = imax(mwp->used, (int)strlen("Used"));
mwp->avail = imax(mwp->avail, (int)strlen("Avail"));
(void)printf("%-*s", mwp->mntfrom, "Filesystem");
xo_emit("{T:/%-*s}", mwp->mntfrom, "Filesystem");
if (Tflag)
(void)printf(" %-*s", mwp->fstype, "Type");
(void)printf(" %*s %*s %*s Capacity", mwp->total, header,
mwp->used, "Used", mwp->avail, "Avail");
xo_emit(" {T:/%-*s}", mwp->fstype, "Type");
xo_emit(" {T:/%*s} {T:/%*s} {T:/%*s} Capacity",
mwp->total, header,
mwp->used, "Used", mwp->avail, "Avail");
if (iflag) {
mwp->iused = imax(hflag ? 0 : mwp->iused,
(int)strlen(" iused"));
mwp->ifree = imax(hflag ? 0 : mwp->ifree,
(int)strlen("ifree"));
(void)printf(" %*s %*s %%iused",
xo_emit(" {T:/%*s} {T:/%*s} {T:\%iused}",
mwp->iused - 2, "iused", mwp->ifree, "ifree");
}
(void)printf(" Mounted on\n");
xo_emit(" {T:Mounted on}\n");
}
xo_open_instance("filesystem");
/* Check for 0 block size. Can this happen? */
if (sfsp->f_bsize == 0) {
warnx ("File system %s does not have a block size, assuming 512.",
xo_warnx ("File system %s does not have a block size, assuming 512.",
sfsp->f_mntonname);
sfsp->f_bsize = 512;
}
(void)printf("%-*s", mwp->mntfrom, sfsp->f_mntfromname);
xo_emit("{tk:name/%-*s}", mwp->mntfrom, sfsp->f_mntfromname);
if (Tflag)
(void)printf(" %-*s", mwp->fstype, sfsp->f_fstypename);
xo_emit(" {:type/%-*s}", mwp->fstype, sfsp->f_fstypename);
used = sfsp->f_blocks - sfsp->f_bfree;
availblks = sfsp->f_bavail + used;
if (hflag) {
prthuman(sfsp, used);
} else {
if (thousands)
format = " %*j'd %*j'd %*j'd";
format = " {t:total-blocks/%*j'd} {t:used-blocks/%*j'd} "
"{t:available-blocks/%*j'd}";
else
format = " %*jd %*jd %*jd";
(void)printf(format,
format = " {t:total-blocks/%*jd} {t:used-blocks/%*jd} "
"{t:available-blocks/%*jd}";
xo_emit(format,
mwp->total, fsbtoblk(sfsp->f_blocks,
sfsp->f_bsize, blocksize),
mwp->used, fsbtoblk(used, sfsp->f_bsize, blocksize),
mwp->avail, fsbtoblk(sfsp->f_bavail,
sfsp->f_bsize, blocksize));
}
(void)printf(" %5.0f%%",
xo_emit(" {:used-percent/%5.0f}{U:%%}",
availblks == 0 ? 100.0 : (double)used / (double)availblks * 100.0);
if (iflag) {
inodes = sfsp->f_files;
used = inodes - sfsp->f_ffree;
if (hflag) {
(void)printf(" ");
prthumanvalinode(used);
prthumanvalinode(sfsp->f_ffree);
xo_emit(" ");
prthumanvalinode(" {:inodes-used/%5s}", used);
prthumanvalinode(" {:inodes-free/%5s}", sfsp->f_ffree);
} else {
if (thousands)
format = " %*j'd %*j'd";
format = " {:inodes-used/%*j'd} {:inodes-free/%*j'd}";
else
format = " %*jd %*jd";
(void)printf(format, mwp->iused, (intmax_t)used,
format = " {:inodes-used/%*jd} {:inodes-free/%*jd}";
xo_emit(format, mwp->iused, (intmax_t)used,
mwp->ifree, (intmax_t)sfsp->f_ffree);
}
(void)printf(" %4.0f%% ", inodes == 0 ? 100.0 :
(double)used / (double)inodes * 100.0);
xo_emit(" {:inodes-used-percent/%4.0f}{U:%%} ",
inodes == 0 ? 100.0 :
(double)used / (double)inodes * 100.0);
} else
(void)printf(" ");
xo_emit(" ");
if (strncmp(sfsp->f_mntfromname, "total", MNAMELEN) != 0)
(void)printf(" %s", sfsp->f_mntonname);
(void)printf("\n");
xo_emit(" {:mounted-on}", sfsp->f_mntonname);
xo_emit("\n");
xo_close_instance("filesystem");
}
static void
@ -564,7 +588,7 @@ static void
usage(void)
{
(void)fprintf(stderr,
xo_error(
"usage: df [-b | -g | -H | -h | -k | -m | -P] [-acilnT] [-t type] [-,]\n"
" [file | filesystem ...]\n");
exit(EX_USAGE);
@ -579,24 +603,24 @@ makenetvfslist(void)
int cnt, i, maxvfsconf;
if (sysctlbyname("vfs.conflist", NULL, &buflen, NULL, 0) < 0) {
warn("sysctl(vfs.conflist)");
xo_warn("sysctl(vfs.conflist)");
return (NULL);
}
xvfsp = malloc(buflen);
if (xvfsp == NULL) {
warnx("malloc failed");
xo_warnx("malloc failed");
return (NULL);
}
keep_xvfsp = xvfsp;
if (sysctlbyname("vfs.conflist", xvfsp, &buflen, NULL, 0) < 0) {
warn("sysctl(vfs.conflist)");
xo_warn("sysctl(vfs.conflist)");
free(keep_xvfsp);
return (NULL);
}
maxvfsconf = buflen / sizeof(struct xvfsconf);
if ((listptr = malloc(sizeof(char*) * maxvfsconf)) == NULL) {
warnx("malloc failed");
xo_warnx("malloc failed");
free(keep_xvfsp);
return (NULL);
}
@ -605,7 +629,7 @@ makenetvfslist(void)
if (xvfsp->vfc_flags & VFCF_NETWORK) {
listptr[cnt++] = strdup(xvfsp->vfc_name);
if (listptr[cnt-1] == NULL) {
warnx("malloc failed");
xo_warnx("malloc failed");
free(listptr);
free(keep_xvfsp);
return (NULL);
@ -617,7 +641,7 @@ makenetvfslist(void)
if (cnt == 0 ||
(str = malloc(sizeof(char) * (32 * cnt + cnt + 2))) == NULL) {
if (cnt > 0)
warnx("malloc failed");
xo_warnx("malloc failed");
free(listptr);
free(keep_xvfsp);
return (NULL);

View File

@ -32,7 +32,7 @@
.\" from: @(#)sh.1 8.6 (Berkeley) 5/4/95
.\" $FreeBSD$
.\"
.Dd September 21, 2014
.Dd November 7, 2014
.Dt SH 1
.Os
.Sh NAME
@ -2522,7 +2522,8 @@ and so on,
decreasing the value of
.Li $#
by one.
If there are zero positional parameters, shifting does not do anything.
For portability, shifting if there are zero positional parameters
should be avoided, since the shell may abort.
.It Ic test
A built-in equivalent of
.Xr test 1 .

View File

@ -77,9 +77,11 @@
#ifndef lint
extern boolean_t zfs_recover;
extern uint64_t zfs_arc_max, zfs_arc_meta_limit;
extern int zfs_vdev_async_read_max_active;
#else
boolean_t zfs_recover;
uint64_t zfs_arc_max, zfs_arc_meta_limit;
int zfs_vdev_async_read_max_active;
#endif
const char cmdname[] = "zdb";
@ -2384,8 +2386,14 @@ zdb_blkptr_cb(spa_t *spa, zilog_t *zilog, const blkptr_t *bp,
zcb->zcb_readfails = 0;
if (dump_opt['b'] < 5 &&
gethrtime() > zcb->zcb_lastprint + NANOSEC) {
/* only call gethrtime() every 100 blocks */
static int iters;
if (++iters > 100)
iters = 0;
else
return (0);
if (dump_opt['b'] < 5 && gethrtime() > zcb->zcb_lastprint + NANOSEC) {
uint64_t now = gethrtime();
char buf[10];
uint64_t bytes = zcb->zcb_type[ZB_TOTAL][ZDB_OT_TOTAL].zb_asize;
@ -2494,6 +2502,14 @@ zdb_leak_init(spa_t *spa, zdb_cb_t *zcb)
(longlong_t)vd->vdev_ms_count);
msp->ms_ops = &zdb_metaslab_ops;
/*
* We don't want to spend the CPU
* manipulating the size-ordered
* tree, so clear the range_tree
* ops.
*/
msp->ms_tree->rt_ops = NULL;
VERIFY0(space_map_load(msp->ms_sm,
msp->ms_tree, SM_ALLOC));
msp->ms_loaded = B_TRUE;
@ -3508,6 +3524,13 @@ main(int argc, char **argv)
*/
zfs_arc_max = zfs_arc_meta_limit = 256 * 1024 * 1024;
/*
* "zdb -c" uses checksum-verifying scrub i/os which are async reads.
* "zdb -b" uses traversal prefetch which uses async reads.
* For good performance, let several of them be active at once.
*/
zfs_vdev_async_read_max_active = 10;
kernel_init(FREAD);
g_zfs = libzfs_init();
ASSERT(g_zfs != NULL);

View File

@ -1695,7 +1695,7 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
const MCAsmMacroParameters &Parameters,
const MCAsmMacroArguments &A, const SMLoc &L) {
unsigned NParameters = Parameters.size();
if (NParameters != 0 && NParameters != A.size())
if ((!IsDarwin || NParameters != 0) && NParameters != A.size())
return Error(L, "Wrong number of arguments");
// A macro without parameters is handled differently on Darwin:
@ -1705,7 +1705,7 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
std::size_t End = Body.size(), Pos = 0;
for (; Pos != End; ++Pos) {
// Check for a substitution or escape.
if (!NParameters) {
if (IsDarwin && !NParameters) {
// This macro has no parameters, look for $0, $1, etc.
if (Body[Pos] != '$' || Pos + 1 == End)
continue;
@ -1728,7 +1728,7 @@ bool AsmParser::expandMacro(raw_svector_ostream &OS, StringRef Body,
if (Pos == End)
break;
if (!NParameters) {
if (IsDarwin && !NParameters) {
switch (Body[Pos + 1]) {
// $$ => $
case '$':

View File

@ -0,0 +1,55 @@
Pull in r201784 from upstream llvm trunk (by Benjamin Kramer):
AsmParser: Disable Darwin-style macro argument expansion on non-darwin targets.
There is code in the wild that relies on $0 not being expanded.
This fixes some cases of using $ signs in literals being incorrectly
assembled.
Reported by: Richard Henderson
Upstream PR: http://llvm.org/PR21500
Introduced here: http://svnweb.freebsd.org/changeset/base/274286
Index: lib/MC/MCParser/AsmParser.cpp
===================================================================
--- lib/MC/MCParser/AsmParser.cpp
+++ lib/MC/MCParser/AsmParser.cpp
@@ -1695,7 +1695,7 @@ bool AsmParser::expandMacro(raw_svector_ostream &O
const MCAsmMacroParameters &Parameters,
const MCAsmMacroArguments &A, const SMLoc &L) {
unsigned NParameters = Parameters.size();
- if (NParameters != 0 && NParameters != A.size())
+ if ((!IsDarwin || NParameters != 0) && NParameters != A.size())
return Error(L, "Wrong number of arguments");
// A macro without parameters is handled differently on Darwin:
@@ -1705,7 +1705,7 @@ bool AsmParser::expandMacro(raw_svector_ostream &O
std::size_t End = Body.size(), Pos = 0;
for (; Pos != End; ++Pos) {
// Check for a substitution or escape.
- if (!NParameters) {
+ if (IsDarwin && !NParameters) {
// This macro has no parameters, look for $0, $1, etc.
if (Body[Pos] != '$' || Pos + 1 == End)
continue;
@@ -1728,7 +1728,7 @@ bool AsmParser::expandMacro(raw_svector_ostream &O
if (Pos == End)
break;
- if (!NParameters) {
+ if (IsDarwin && !NParameters) {
switch (Body[Pos + 1]) {
// $$ => $
case '$':
Index: test/MC/AsmParser/exprs.s
===================================================================
--- test/MC/AsmParser/exprs.s
+++ test/MC/AsmParser/exprs.s
@@ -1,4 +1,4 @@
-// RUN: llvm-mc -triple i386-unknown-unknown %s > %t
+// RUN: llvm-mc -triple i386-apple-darwin %s
.macro check_expr
.if ($0) != ($1)

View File

@ -101,6 +101,13 @@ ATF_TC_BODY(setcontext_link, tc)
ucontext_t save;
volatile int i = 0; /* avoid longjmp clobbering */
#ifdef __FreeBSD__
#ifdef __amd64__
atf_tc_expect_fail("setcontext in this testcase fails on "
"FreeBSD/amd64 with rc == -1/errno == EINVAL; see PR # 194828");
#endif
#endif
for (i = 0; i < DEPTH; ++i) {
ATF_REQUIRE_EQ(getcontext(&uc[i]), 0);
@ -114,8 +121,15 @@ ATF_TC_BODY(setcontext_link, tc)
ATF_REQUIRE_EQ(getcontext(&save), 0);
#ifdef __FreeBSD__
if (calls == 0) {
int rc = setcontext(&uc[DEPTH-1]);
ATF_REQUIRE_EQ_MSG(rc, 0, "%d != 0; (errno = %d)", rc, errno);
}
#else
if (calls == 0)
ATF_REQUIRE_EQ(setcontext(&uc[DEPTH-1]), 0);
#endif
}
ATF_TP_ADD_TCS(tp)

View File

@ -206,9 +206,6 @@ ATF_TC_BODY(mincore_resid, tc)
"might be low on memory");
#ifdef __FreeBSD__
atf_tc_expect_fail("the following calls fail; this seems to be a new "
"issue (didn't occur in 07/2014)");
ATF_REQUIRE(mlock(addr, npgs * page) == 0);
#endif
ATF_REQUIRE(check_residency(addr, npgs) == npgs);

View File

@ -94,7 +94,7 @@ T_OC(pfcs)
* Boilerplate
*/
const struct t_test *t_plan[] = {
static const struct t_test *t_plan[] = {
T(t_oc_digit),
T(t_oc_xdigit),
T(t_oc_upper),

View File

@ -255,7 +255,7 @@ T_FUNC(unterminated_line, "unterminated line")
* Boilerplate
*/
const struct t_test *t_plan[] = {
static const struct t_test *t_plan[] = {
T(empty_input),
T(empty_line),
T(unterminated_empty_line),

View File

@ -823,7 +823,7 @@ T_FUNC(escaped_double_quote_within_double_quotes,
* Boilerplate
*/
const struct t_test *t_plan[] = {
static const struct t_test *t_plan[] = {
T(empty_input),
T(empty_line),
T(single_whitespace),

View File

@ -547,7 +547,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
url_decode(decodedpath);
if (outfile)
savefile = ftp_strdup(outfile);
savefile = outfile;
else {
cp = strrchr(decodedpath, '/'); /* find savefile */
if (cp != NULL)
@ -571,8 +571,7 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
rangestart = rangeend = entitylen = -1;
mtime = -1;
if (restartautofetch) {
if (strcmp(savefile, "-") != 0 && *savefile != '|' &&
stat(savefile, &sb) == 0)
if (stat(savefile, &sb) == 0)
restart_point = sb.st_size;
}
if (urltype == FILE_URL_T) { /* file:// URLs */
@ -1098,17 +1097,25 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
} /* end of ftp:// or http:// specific setup */
/* Open the output file. */
if (strcmp(savefile, "-") == 0) {
fout = stdout;
} else if (*savefile == '|') {
oldintp = xsignal(SIGPIPE, SIG_IGN);
fout = popen(savefile + 1, "w");
if (fout == NULL) {
warn("Can't execute `%s'", savefile + 1);
goto cleanup_fetch_url;
/*
* Only trust filenames with special meaning if they came from
* the command line
*/
if (outfile == savefile) {
if (strcmp(savefile, "-") == 0) {
fout = stdout;
} else if (*savefile == '|') {
oldintp = xsignal(SIGPIPE, SIG_IGN);
fout = popen(savefile + 1, "w");
if (fout == NULL) {
warn("Can't execute `%s'", savefile + 1);
goto cleanup_fetch_url;
}
closefunc = pclose;
}
closefunc = pclose;
} else {
}
if (fout == NULL) {
if ((rangeend != -1 && rangeend <= restart_point) ||
(rangestart == -1 && filesize != -1 && filesize <= restart_point)) {
/* already done */
@ -1318,7 +1325,8 @@ fetch_url(const char *url, const char *proxyenv, char *proxyauth, char *wwwauth)
(*closefunc)(fout);
if (res0)
freeaddrinfo(res0);
FREEPTR(savefile);
if (savefile != outfile)
FREEPTR(savefile);
FREEPTR(uuser);
if (pass != NULL)
memset(pass, 0, strlen(pass));

View File

@ -145,6 +145,8 @@
..
libnv
..
libpam
..
libproc
..
libutil

View File

@ -2,6 +2,8 @@
.include <src.opts.mk>
FILESGROUPS= FILES DATA
FILES= 100.chksetuid \
110.neggrpperm \
200.chkmounts \
@ -10,8 +12,8 @@ FILES= 100.chksetuid \
410.logincheck \
700.kernelmsg \
800.loginfail \
900.tcpwrap \
security.functions
900.tcpwrap
DATA= security.functions
# NB: keep these sorted by MK_* knobs

View File

@ -35,9 +35,7 @@
# and have it work on essentially any size drive.
#
# TODO: Figure out where this should really be ordered.
# I suspect it should go just after fsck but before mountcritlocal
# but it's hard to tell for sure because of the bug described
# below.
# I suspect it should go just after fsck but before mountcritlocal.
#
. /etc/rc.subr

View File

@ -13,6 +13,9 @@ SRCS= argv.c arrows.c buildlist.c buttons.c calendar.c checklist.c \
INCS= dialog.h dlg_colors.h dlg_config.h dlg_keys.h
MAN= dialog.3
DPADD= ${LIBNCURSESW} ${LIBM}
LDADD= -lncursesw -lm
CFLAGS+= -I${.CURDIR} -I${DIALOG} -D_XOPEN_SOURCE_EXTENDED -DGCC_UNUSED=__unused
.PATH: ${DIALOG}
WARNS?= 1

View File

@ -42,12 +42,14 @@ SUBDIR= ${SUBDIR_ORDERED} \
libcrypt \
libdevinfo \
libdevstat \
libdpv \
libdwarf \
libedit \
${_libevent} \
libexecinfo \
libexpat \
libfetch \
libfigpar \
libgeom \
${_libgpib} \
${_libgssapi} \
@ -129,7 +131,7 @@ SUBDIR_DEPEND_libcam= libsbuf
SUBDIR_DEPEND_libcapsicum= libnv
SUBDIR_DEPEND_libcasper= libcapsicum libnv libpjdlog
SUBDIR_DEPEND_libdevstat= libkvm
SUBDIR_DEPEND_libdiaglog= ncurses
SUBDIR_DEPEND_libdpv= libfigpar ncurses libutil
SUBDIR_DEPEND_libedit= ncurses
SUBDIR_DEPEND_libg++= msun
SUBDIR_DEPEND_libgeom= libexpat libsbuf

18
lib/libdpv/Makefile Normal file
View File

@ -0,0 +1,18 @@
# $FreeBSD$
LIB= dpv
SHLIB_MAJOR= 1
INCS= dpv.h
MAN= dpv.3
MLINKS= dpv.3 dpv_free.3
DPADD= ${LIBDIALOG} ${LIBFIGPAR} ${LIBNCURSESW} ${LIBUTIL}
LDADD= -ldialog -lfigpar -lncursesw -lutil
SRCS= dialog_util.c dialogrc.c dprompt.c dpv.c status.c util.c
CFLAGS+= -I${.CURDIR}
WARNS?= 6
.include <bsd.lib.mk>

633
lib/libdpv/dialog_util.c Normal file
View File

@ -0,0 +1,633 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/ioctl.h>
#include <ctype.h>
#include <err.h>
#include <fcntl.h>
#include <limits.h>
#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include "dialog_util.h"
#include "dpv.h"
#include "dpv_private.h"
extern char **environ;
#define TTY_DEFAULT_ROWS 24
#define TTY_DEFAULT_COLS 80
/* [X]dialog(1) characteristics */
uint8_t dialog_test = 0;
uint8_t use_dialog = 0;
uint8_t use_libdialog = 1;
uint8_t use_xdialog = 0;
uint8_t use_color = 1;
char dialog[PATH_MAX] = DIALOG;
/* [X]dialog(1) functionality */
char *title = NULL;
char *backtitle = NULL;
int dheight = 0;
int dwidth = 0;
static char *dargv[64] = { NULL };
/* TTY/Screen characteristics */
static struct winsize *maxsize = NULL;
/* Function prototypes */
static void tty_maxsize_update(void);
static void x11_maxsize_update(void);
/*
* Update row/column fields of `maxsize' global (used by dialog_maxrows() and
* dialog_maxcols()). If the `maxsize' pointer is NULL, it will be initialized.
* The `ws_row' and `ws_col' fields of `maxsize' are updated to hold current
* maximum height and width (respectively) for a dialog(1) widget based on the
* active TTY size.
*
* This function is called automatically by dialog_maxrows/cols() to reflect
* changes in terminal size in-between calls.
*/
static void
tty_maxsize_update(void)
{
int fd = STDIN_FILENO;
struct termios t;
if (maxsize == NULL) {
if ((maxsize = malloc(sizeof(struct winsize))) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
memset((void *)maxsize, '\0', sizeof(struct winsize));
}
if (!isatty(fd))
fd = open("/dev/tty", O_RDONLY);
if ((tcgetattr(fd, &t) < 0) || (ioctl(fd, TIOCGWINSZ, maxsize) < 0)) {
maxsize->ws_row = TTY_DEFAULT_ROWS;
maxsize->ws_col = TTY_DEFAULT_COLS;
}
}
/*
* Update row/column fields of `maxsize' global (used by dialog_maxrows() and
* dialog_maxcols()). If the `maxsize' pointer is NULL, it will be initialized.
* The `ws_row' and `ws_col' fields of `maxsize' are updated to hold current
* maximum height and width (respectively) for an Xdialog(1) widget based on
* the active video resolution of the X11 environment.
*
* This function is called automatically by dialog_maxrows/cols() to initialize
* `maxsize'. Since video resolution changes are less common and more obtrusive
* than changes to terminal size, the dialog_maxrows/cols() functions only call
* this function when `maxsize' is set to NULL.
*/
static void
x11_maxsize_update(void)
{
FILE *f = NULL;
char *cols;
char *cp;
char *rows;
char cmdbuf[LINE_MAX];
char rbuf[LINE_MAX];
if (maxsize == NULL) {
if ((maxsize = malloc(sizeof(struct winsize))) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
memset((void *)maxsize, '\0', sizeof(struct winsize));
}
/* Assemble the command necessary to get X11 sizes */
snprintf(cmdbuf, LINE_MAX, "%s --print-maxsize 2>&1", dialog);
fflush(STDIN_FILENO); /* prevent popen(3) from seeking on stdin */
if ((f = popen(cmdbuf, "r")) == NULL) {
if (debug)
warnx("WARNING! Command `%s' failed", cmdbuf);
return;
}
/* Read in the line returned from Xdialog(1) */
if ((fgets(rbuf, LINE_MAX, f) == NULL) || (pclose(f) < 0))
return;
/* Check for X11-related errors */
if (strncmp(rbuf, "Xdialog: Error", 14) == 0)
return;
/* Parse expected output: MaxSize: YY, XXX */
if ((rows = strchr(rbuf, ' ')) == NULL)
return;
if ((cols = strchr(rows, ',')) != NULL) {
/* strtonum(3) doesn't like trailing junk */
*(cols++) = '\0';
if ((cp = strchr(cols, '\n')) != NULL)
*cp = '\0';
}
/* Convert to unsigned short */
maxsize->ws_row = (unsigned short)strtonum(
rows, 0, USHRT_MAX, (const char **)NULL);
maxsize->ws_col = (unsigned short)strtonum(
cols, 0, USHRT_MAX, (const char **)NULL);
}
/*
* Return the current maximum height (rows) for an [X]dialog(1) widget.
*/
int
dialog_maxrows(void)
{
if (use_xdialog && maxsize == NULL)
x11_maxsize_update(); /* initialize maxsize for GUI */
else if (!use_xdialog)
tty_maxsize_update(); /* update maxsize for TTY */
return (maxsize->ws_row);
}
/*
* Return the current maximum width (cols) for an [X]dialog(1) widget.
*/
int
dialog_maxcols(void)
{
if (use_xdialog && maxsize == NULL)
x11_maxsize_update(); /* initialize maxsize for GUI */
else if (!use_xdialog)
tty_maxsize_update(); /* update maxsize for TTY */
if (use_dialog || use_libdialog) {
if (use_shadow)
return (maxsize->ws_col - 2);
else
return (maxsize->ws_col);
} else
return (maxsize->ws_col);
}
/*
* Return the current maximum width (cols) for the terminal.
*/
int
tty_maxcols(void)
{
if (use_xdialog && maxsize == NULL)
x11_maxsize_update(); /* initialize maxsize for GUI */
else if (!use_xdialog)
tty_maxsize_update(); /* update maxsize for TTY */
return (maxsize->ws_col);
}
/*
* Spawn an [X]dialog(1) `--gauge' box with a `--prompt' value of init_prompt.
* Writes the resulting process ID to the pid_t pointed at by `pid'. Returns a
* file descriptor (int) suitable for writing data to the [X]dialog(1) instance
* (data written to the file descriptor is seen as standard-in by the spawned
* [X]dialog(1) process).
*/
int
dialog_spawn_gauge(char *init_prompt, pid_t *pid)
{
char dummy_init[2] = "";
char *cp;
int height;
int width;
int error;
posix_spawn_file_actions_t action;
#if DIALOG_SPAWN_DEBUG
unsigned int i;
#endif
unsigned int n = 0;
int stdin_pipe[2] = { -1, -1 };
/* Override `dialog' with a path from ENV_DIALOG if provided */
if ((cp = getenv(ENV_DIALOG)) != NULL)
snprintf(dialog, PATH_MAX, "%s", cp);
/* For Xdialog(1), set ENV_XDIALOG_HIGH_DIALOG_COMPAT */
setenv(ENV_XDIALOG_HIGH_DIALOG_COMPAT, "1", 1);
/* Constrain the height/width */
height = dialog_maxrows();
if (backtitle != NULL)
height -= use_shadow ? 5 : 4;
if (dheight < height)
height = dheight;
width = dialog_maxcols();
if (dwidth < width)
width = dwidth;
/* Populate argument array */
dargv[n++] = dialog;
if (title != NULL) {
if ((dargv[n] = malloc(8)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
sprintf(dargv[n++], "--title");
dargv[n++] = title;
}
if (backtitle != NULL) {
if ((dargv[n] = malloc(12)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
sprintf(dargv[n++], "--backtitle");
dargv[n++] = backtitle;
}
if (use_color) {
if ((dargv[n] = malloc(11)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
sprintf(dargv[n++], "--colors");
}
if (use_xdialog) {
if ((dargv[n] = malloc(7)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
sprintf(dargv[n++], "--left");
/*
* NOTE: Xdialog(1)'s `--wrap' appears to be broken for the
* `--gauge' widget prompt-updates. Add it anyway (in-case it
* gets fixed in some later release).
*/
if ((dargv[n] = malloc(7)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
sprintf(dargv[n++], "--wrap");
}
if ((dargv[n] = malloc(8)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
sprintf(dargv[n++], "--gauge");
dargv[n++] = use_xdialog ? dummy_init : init_prompt;
if ((dargv[n] = malloc(40)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
snprintf(dargv[n++], 40, "%u", height);
if ((dargv[n] = malloc(40)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
snprintf(dargv[n++], 40, "%u", width);
dargv[n] = NULL;
/* Open a pipe(2) to communicate with [X]dialog(1) */
if (pipe(stdin_pipe) < 0)
err(EXIT_FAILURE, "%s: pipe(2)", __func__);
/* Fork [X]dialog(1) process */
#if DIALOG_SPAWN_DEBUG
fprintf(stderr, "%s: spawning `", __func__);
for (i = 0; i < n; i++) {
if (i == 0)
fprintf(stderr, "%s", dargv[i]);
else if (*dargv[i] == '-' && *(dargv[i] + 1) == '-')
fprintf(stderr, " %s", dargv[i]);
else
fprintf(stderr, " \"%s\"", dargv[i]);
}
fprintf(stderr, "'\n");
#endif
posix_spawn_file_actions_init(&action);
posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
error = posix_spawnp(pid, dialog, &action,
(const posix_spawnattr_t *)NULL, dargv, environ);
if (error != 0)
err(EXIT_FAILURE, "%s: posix_spawnp(3)", __func__);
/* NB: Do not free(3) *dargv[], else SIGSEGV */
return (stdin_pipe[1]);
}
/*
* Returns the number of lines in buffer pointed to by `prompt'. Takes both
* newlines and escaped-newlines into account.
*/
unsigned int
dialog_prompt_numlines(const char *prompt, uint8_t nlstate)
{
uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
const char *cp = prompt;
unsigned int nlines = 1;
if (prompt == NULL || *prompt == '\0')
return (0);
while (*cp != '\0') {
if (use_dialog) {
if (strncmp(cp, "\\n", 2) == 0) {
cp++;
nlines++;
nls = TRUE; /* See declaration comment */
} else if (*cp == '\n') {
if (!nls)
nlines++;
nls = FALSE; /* See declaration comment */
}
} else if (use_libdialog) {
if (*cp == '\n')
nlines++;
} else if (strncmp(cp, "\\n", 2) == 0) {
cp++;
nlines++;
}
cp++;
}
return (nlines);
}
/*
* Returns the length in bytes of the longest line in buffer pointed to by
* `prompt'. Takes newlines and escaped newlines into account. Also discounts
* dialog(1) color escape codes if enabled (via `use_color' global).
*/
unsigned int
dialog_prompt_longestline(const char *prompt, uint8_t nlstate)
{
uint8_t backslash = 0;
uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
const char *p = prompt;
int longest = 0;
int n = 0;
/* `prompt' parameter is required */
if (prompt == NULL)
return (0);
if (*prompt == '\0')
return (0); /* shortcut */
/* Loop until the end of the string */
while (*p != '\0') {
/* dialog(1) and dialog(3) will render literal newlines */
if (use_dialog || use_libdialog) {
if (*p == '\n') {
if (!use_libdialog && nls)
n++;
else {
if (n > longest)
longest = n;
n = 0;
}
nls = FALSE; /* See declaration comment */
p++;
continue;
}
}
/* Check for backslash character */
if (*p == '\\') {
/* If second backslash, count as a single-char */
if ((backslash ^= 1) == 0)
n++;
} else if (backslash) {
if (*p == 'n' && !use_libdialog) { /* new line */
/* NB: dialog(3) ignores escaped newlines */
nls = TRUE; /* See declaration comment */
if (n > longest)
longest = n;
n = 0;
} else if (use_color && *p == 'Z') {
if (*++p != '\0')
p++;
backslash = 0;
continue;
} else /* [X]dialog(1)/dialog(3) only expand those */
n += 2;
backslash = 0;
} else
n++;
p++;
}
if (n > longest)
longest = n;
return (longest);
}
/*
* Returns a pointer to the last line in buffer pointed to by `prompt'. Takes
* both newlines (if using dialog(1) versus Xdialog(1)) and escaped newlines
* into account. If no newlines (escaped or otherwise) appear in the buffer,
* `prompt' is returned. If passed a NULL pointer, returns NULL.
*/
char *
dialog_prompt_lastline(char *prompt, uint8_t nlstate)
{
uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
char *lastline;
char *p;
if (prompt == NULL)
return (NULL);
if (*prompt == '\0')
return (prompt); /* shortcut */
lastline = p = prompt;
while (*p != '\0') {
/* dialog(1) and dialog(3) will render literal newlines */
if (use_dialog || use_libdialog) {
if (*p == '\n') {
if (use_libdialog || !nls)
lastline = p + 1;
nls = FALSE; /* See declaration comment */
}
}
/* dialog(3) does not expand escaped newlines */
if (use_libdialog) {
p++;
continue;
}
if (*p == '\\' && *(p + 1) != '\0' && *(++p) == 'n') {
nls = TRUE; /* See declaration comment */
lastline = p + 1;
}
p++;
}
return (lastline);
}
/*
* Returns the number of extra lines generated by wrapping the text in buffer
* pointed to by `prompt' within `ncols' columns (for prompts, this should be
* dwidth - 4). Also discounts dialog(1) color escape codes if enabled (via
* `use_color' global).
*/
int
dialog_prompt_wrappedlines(char *prompt, int ncols, uint8_t nlstate)
{
uint8_t backslash = 0;
uint8_t nls = nlstate; /* See dialog_prompt_nlstate() */
char *cp;
char *p = prompt;
int n = 0;
int wlines = 0;
/* `prompt' parameter is required */
if (p == NULL)
return (0);
if (*p == '\0')
return (0); /* shortcut */
/* Loop until the end of the string */
while (*p != '\0') {
/* dialog(1) and dialog(3) will render literal newlines */
if (use_dialog || use_libdialog) {
if (*p == '\n') {
if (use_dialog || !nls)
n = 0;
nls = FALSE; /* See declaration comment */
}
}
/* Check for backslash character */
if (*p == '\\') {
/* If second backslash, count as a single-char */
if ((backslash ^= 1) == 0)
n++;
} else if (backslash) {
if (*p == 'n' && !use_libdialog) { /* new line */
/* NB: dialog(3) ignores escaped newlines */
nls = TRUE; /* See declaration comment */
n = 0;
} else if (use_color && *p == 'Z') {
if (*++p != '\0')
p++;
backslash = 0;
continue;
} else /* [X]dialog(1)/dialog(3) only expand those */
n += 2;
backslash = 0;
} else
n++;
/* Did we pass the width barrier? */
if (n > ncols) {
/*
* Work backward to find the first whitespace on-which
* dialog(1) will wrap the line (but don't go before
* the start of this line).
*/
cp = p;
while (n > 1 && !isspace(*cp)) {
cp--;
n--;
}
if (n > 0 && isspace(*cp))
p = cp;
wlines++;
n = 1;
}
p++;
}
return (wlines);
}
/*
* Returns zero if the buffer pointed to by `prompt' contains an escaped
* newline but only if appearing after any/all literal newlines. This is
* specific to dialog(1) and does not apply to Xdialog(1).
*
* As an attempt to make shell scripts easier to read, dialog(1) will "eat"
* the first literal newline after an escaped newline. This however has a bug
* in its implementation in that rather than allowing `\\n\n' to be treated
* similar to `\\n' or `\n', dialog(1) expands the `\\n' and then translates
* the following literal newline (with or without characters between [!]) into
* a single space.
*
* If you want to be compatible with Xdialog(1), it is suggested that you not
* use literal newlines (they aren't supported); but if you have to use them,
* go right ahead. But be forewarned... if you set $DIALOG in your environment
* to something other than `cdialog' (our current dialog(1)), then it should
* do the same thing w/respect to how to handle a literal newline after an
* escaped newline (you could do no wrong by translating every literal newline
* into a space but only when you've previously encountered an escaped one;
* this is what dialog(1) is doing).
*
* The ``newline state'' (or nlstate for short; as I'm calling it) is helpful
* if you plan to combine multiple strings into a single prompt text. In lead-
* up to this procedure, a common task is to calculate and utilize the widths
* and heights of each piece of prompt text to later be combined. However, if
* (for example) the first string ends in a positive newline state (has an
* escaped newline without trailing literal), the first literal newline in the
* second string will be mangled.
*
* The return value of this function should be used as the `nlstate' argument
* to dialog_*() functions that require it to allow accurate calculations in
* the event such information is needed.
*/
uint8_t
dialog_prompt_nlstate(const char *prompt)
{
const char *cp;
if (prompt == NULL)
return 0;
/*
* Work our way backward from the end of the string for efficiency.
*/
cp = prompt + strlen(prompt);
while (--cp >= prompt) {
/*
* If we get to a literal newline first, this prompt ends in a
* clean state for rendering with dialog(1). Otherwise, if we
* get to an escaped newline first, this prompt ends in an un-
* clean state (following literal will be mangled; see above).
*/
if (*cp == '\n')
return (0);
else if (*cp == 'n' && --cp > prompt && *cp == '\\')
return (1);
}
return (0); /* no newlines (escaped or otherwise) */
}
/*
* Free allocated items initialized by tty_maxsize_update() and
* x11_maxsize_update()
*/
void
dialog_maxsize_free(void)
{
if (maxsize != NULL) {
free(maxsize);
maxsize = NULL;
}
}

73
lib/libdpv/dialog_util.h Normal file
View File

@ -0,0 +1,73 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _DIALOG_UTIL_H_
#define _DIALOG_UTIL_H_
#include <sys/types.h>
#include "dialogrc.h"
#define DIALOG_SPAWN_DEBUG 0 /* Debug spawning of [X]dialog(1) */
/* dialog(3) and [X]dialog(1) characteristics */
#define DIALOG "dialog"
#define XDIALOG "Xdialog"
#define PROMPT_MAX 16384
#define ENV_DIALOG "DIALOG"
#define ENV_USE_COLOR "USE_COLOR"
#define ENV_XDIALOG_HIGH_DIALOG_COMPAT "XDIALOG_HIGH_DIALOG_COMPAT"
extern uint8_t dialog_test;
extern uint8_t use_libdialog;
extern uint8_t use_dialog;
extern uint8_t use_xdialog;
extern uint8_t use_color;
extern char dialog[];
/* dialog(3) and [X]dialog(1) functionality */
extern char *title, *backtitle;
extern int dheight, dwidth;
__BEGIN_DECLS
uint8_t dialog_prompt_nlstate(const char *_prompt);
void dialog_gauge_free(void);
void dialog_maxsize_free(void);
char *dialog_prompt_lastline(char *_prompt, uint8_t _nlstate);
int dialog_maxcols(void);
int dialog_maxrows(void);
int dialog_prompt_wrappedlines(char *_prompt, int _ncols,
uint8_t _nlstate);
int dialog_spawn_gauge(char *_init_prompt, pid_t *_pid);
int tty_maxcols(void);
#define tty_maxrows() dialog_maxrows()
unsigned int dialog_prompt_longestline(const char *_prompt,
uint8_t _nlstate);
unsigned int dialog_prompt_numlines(const char *_prompt, uint8_t _nlstate);
__END_DECLS
#endif /* !_DIALOG_UTIL_H_ */

359
lib/libdpv/dialogrc.c Normal file
View File

@ -0,0 +1,359 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <err.h>
#include <errno.h>
#include <figpar.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string_m.h>
#include "dialogrc.h"
#define STR_BUFSIZE 255
/* dialog(1) `.dialogrc' characteristics */
uint8_t use_colors = 1;
uint8_t use_shadow = 1;
char gauge_color[STR_BUFSIZE] = "47b"; /* (BLUE,WHITE,ON) */
char separator[STR_BUFSIZE] = "";
/* Function prototypes */
static int setattr(struct fp_config *, uint32_t, char *, char *);
static int setbool(struct fp_config *, uint32_t, char *, char *);
static int setnum(struct fp_config *, uint32_t, char *, char *);
static int setstr(struct fp_config *, uint32_t, char *, char *);
/*
* Anatomy of DIALOGRC (~/.dialogrc by default)
* NOTE: Must appear after private function prototypes (above)
* NB: Brace-initialization of union requires cast to *first* member of union
*/
static struct fp_config dialogrc_config[] = {
/* TYPE Directive DEFAULT HANDLER */
{FP_TYPE_INT, "aspect", {(void *)0}, &setnum},
{FP_TYPE_STR, "separate_widget", {separator}, &setstr},
{FP_TYPE_INT, "tab_len", {(void *)0}, &setnum},
{FP_TYPE_BOOL, "visit_items", {(void *)0}, &setbool},
{FP_TYPE_BOOL, "use_shadow", {(void *)1}, &setbool},
{FP_TYPE_BOOL, "use_colors", {(void *)1}, &setbool},
{FP_TYPE_STR, "screen_color", {NULL}, &setattr},
{FP_TYPE_STR, "shadow_color", {NULL}, &setattr},
{FP_TYPE_STR, "dialog_color", {NULL}, &setattr},
{FP_TYPE_STR, "title_color", {NULL}, &setattr},
{FP_TYPE_STR, "border_color", {NULL}, &setattr},
{FP_TYPE_STR, "button_active_color", {NULL}, &setattr},
{FP_TYPE_STR, "button_inactive_color", {NULL}, &setattr},
{FP_TYPE_STR, "button_key_active_color", {NULL}, &setattr},
{FP_TYPE_STR, "button_key_inactive_color", {NULL}, &setattr},
{FP_TYPE_STR, "button_label_active_color", {NULL}, &setattr},
{FP_TYPE_STR, "button_label_inactive_color",{NULL}, &setattr},
{FP_TYPE_STR, "inputbox_color", {NULL}, &setattr},
{FP_TYPE_STR, "inputbox_border_color", {NULL}, &setattr},
{FP_TYPE_STR, "searchbox_color", {NULL}, &setattr},
{FP_TYPE_STR, "searchbox_title_color", {NULL}, &setattr},
{FP_TYPE_STR, "searchbox_border_color", {NULL}, &setattr},
{FP_TYPE_STR, "position_indicator_color", {NULL}, &setattr},
{FP_TYPE_STR, "menubox_color", {NULL}, &setattr},
{FP_TYPE_STR, "menubox_border_color", {NULL}, &setattr},
{FP_TYPE_STR, "item_color", {NULL}, &setattr},
{FP_TYPE_STR, "item_selected_color", {NULL}, &setattr},
{FP_TYPE_STR, "tag_color", {NULL}, &setattr},
{FP_TYPE_STR, "tag_selected_color", {NULL}, &setattr},
{FP_TYPE_STR, "tag_key_color", {NULL}, &setattr},
{FP_TYPE_STR, "tag_key_selected_color", {NULL}, &setattr},
{FP_TYPE_STR, "check_color", {NULL}, &setattr},
{FP_TYPE_STR, "check_selected_color", {NULL}, &setattr},
{FP_TYPE_STR, "uarrow_color", {NULL}, &setattr},
{FP_TYPE_STR, "darrow_color", {NULL}, &setattr},
{FP_TYPE_STR, "itemhelp_color", {NULL}, &setattr},
{FP_TYPE_STR, "form_active_text_color", {NULL}, &setattr},
{FP_TYPE_STR, "form_text_color", {NULL}, &setattr},
{FP_TYPE_STR, "form_item_readonly_color", {NULL}, &setattr},
{FP_TYPE_STR, "gauge_color", {gauge_color}, &setattr},
{0, NULL, {0}, NULL}
};
/*
* figpar call-back for interpreting value as .dialogrc `Attribute'
*/
static int
setattr(struct fp_config *option, uint32_t line __unused,
char *directive __unused, char *value)
{
char *cp = value;
char *val;
size_t len;
char attrbuf[4];
if (option == NULL) {
warnx("%s:%d:%s: Missing callback parameter", __FILE__,
__LINE__, __func__);
return (-1); /* Abort processing */
}
/* Allocate memory for the data if not already done */
if (option->value.str == NULL) {
if ((option->value.str = malloc(STR_BUFSIZE)) == NULL)
return (-1);
}
/*
* If the first character is left-parenthesis, the format is
* `(background,foreground,highlight)' otherwise, we should take it
* as a reference to another color.
*/
if (*cp != '(') {
/* Copy the [current] value from the referenced color */
val = dialogrc_config_option(cp)->value.str;
if (val != NULL)
snprintf(option->value.str, STR_BUFSIZE, "%s", val);
return (0);
} else
cp++;
strtolower(cp);
/* Initialize the attrbuf (fg,bg,hi,NUL) */
attrbuf[0] = '0';
attrbuf[1] = '0';
attrbuf[2] = 'B'; /* \ZB = disable; \Zb = enable (see dialog(1)) */
attrbuf[3] = '\0';
/* Interpret the foreground color */
if (strncmp(cp, "red,", 4) == 0) attrbuf[0] = '1';
else if (strncmp(cp, "green,", 6) == 0) attrbuf[0] = '2';
else if (strncmp(cp, "yellow,", 7) == 0) attrbuf[0] = '3';
else if (strncmp(cp, "blue,", 5) == 0) attrbuf[0] = '4';
else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[0] = '5';
else if (strncmp(cp, "cyan,", 5) == 0) attrbuf[0] = '6';
else if (strncmp(cp, "white,", 6) == 0) attrbuf[0] = '7';
else if (strncmp(cp, "black,", 6) == 0) attrbuf[0] = '8';
/* Advance to the background color */
cp = strchr(cp, ',');
if (cp == NULL)
goto write_attrbuf;
else
cp++;
/* Interpret the background color */
if (strncmp(cp, "red,", 4) == 0) attrbuf[1] = '1';
else if (strncmp(cp, "green,", 6) == 0) attrbuf[1] = '2';
else if (strncmp(cp, "yellow,", 7) == 0) attrbuf[1] = '3';
else if (strncmp(cp, "blue,", 5) == 0) attrbuf[1] = '4';
else if (strncmp(cp, "magenta,", 8) == 0) attrbuf[1] = '5';
else if (strncmp(cp, "cyan,", 5) == 0) attrbuf[1] = '6';
else if (strncmp(cp, "white,", 6) == 0) attrbuf[1] = '7';
else if (strncmp(cp, "black,", 6) == 0) attrbuf[1] = '8';
/* Advance to the highlight */
cp = strchr(cp, ',');
if (cp == NULL)
goto write_attrbuf;
else
cp++;
/* Trim trailing parenthesis */
len = strlen(cp);
if (cp[len - 1] == ')')
cp[len - 1] = '\0';
/* Interpret the highlight (initialized to off above) */
if (strcmp(cp, "on") == 0 || strncmp(cp, "on,", 3) == 0)
attrbuf[2] = 'b'; /* \Zb = enable bold (see dialog(1)) */
write_attrbuf:
sprintf(option->value.str, "%s", attrbuf);
return (0);
}
/*
* figpar call-back for interpreting value as .dialogrc `Boolean'
*/
static int
setbool(struct fp_config *option, uint32_t line __unused,
char *directive __unused, char *value)
{
if (option == NULL) {
warnx("%s:%d:%s: Missing callback parameter", __FILE__,
__LINE__, __func__);
return (-1); /* Abort processing */
}
/* Assume ON, check for OFF (case-insensitive) */
option->value.boolean = 1;
strtolower(value);
if (strcmp(value, "off") == 0)
option->value.boolean = 0;
return (0);
}
/*
* figpar call-back for interpreting value as .dialogrc `Number'
*/
static int
setnum(struct fp_config *option, uint32_t line __unused,
char *directive __unused, char *value)
{
if (option == NULL) {
warnx("%s:%d:%s: Missing callback parameter", __FILE__,
__LINE__, __func__);
return (-1); /* Abort processing */
}
/* Convert the string to a 32-bit signed integer */
option->value.num = (int32_t)strtol(value, (char **)NULL, 10);
return (0);
}
/*
* figpar call-back for interpreting value as .dialogrc `String'
*/
static int
setstr(struct fp_config *option, uint32_t line __unused,
char *directive __unused, char *value)
{
size_t len;
if (option == NULL) {
warnx("%s:%d:%s: Missing callback parameter", __FILE__,
__LINE__, __func__);
return (-1); /* Abort processing */
}
/* Allocate memory for the data if not already done */
if (option->value.str == NULL) {
if ((option->value.str = malloc(STR_BUFSIZE)) == NULL)
return (-1);
}
/* Trim leading quote */
if (*value == '"')
value++;
/* Write the data into the buffer */
snprintf(option->value.str, STR_BUFSIZE, "%s", value);
/* Trim trailing quote */
len = strlen(option->value.str);
if (option->value.str[len - 1] == '"')
option->value.str[len - 1] = '\0';
return (0);
}
/*
* Parse (in order of preference) $DIALOGRC or `$HOME/.dialogrc'. Returns zero
* on success, -1 on failure (and errno should be consulted).
*/
int
parse_dialogrc(void)
{
char *cp;
int res;
size_t len;
char path[PATH_MAX];
/* Allow $DIALOGRC to override `$HOME/.dialogrc' default */
if ((cp = getenv(ENV_DIALOGRC)) != NULL && *cp != '\0')
snprintf(path, PATH_MAX, "%s", cp);
else if ((cp = getenv(ENV_HOME)) != NULL) {
/* Copy $HOME into buffer and append trailing `/' if missing */
snprintf(path, PATH_MAX, "%s", cp);
len = strlen(path);
cp = path + len;
if (len > 0 && len < (PATH_MAX - 1) && *(cp - 1) != '/') {
*cp++ = '/';
*cp = '\0';
len++;
}
/* If we still have room, shove in the name of rc file */
if (len < (PATH_MAX - 1))
snprintf(cp, PATH_MAX - len, "%s", DIALOGRC);
} else {
/* Like dialog(1), don't process a file if $HOME is unset */
errno = ENOENT;
return (-1);
}
/* Process file (either $DIALOGRC if set, or `$HOME/.dialogrc') */
res = parse_config(dialogrc_config, path, NULL, FP_BREAK_ON_EQUALS);
/* Set some globals based on what we parsed */
use_shadow = dialogrc_config_option("use_shadow")->value.boolean;
use_colors = dialogrc_config_option("use_colors")->value.boolean;
snprintf(gauge_color, STR_BUFSIZE, "%s",
dialogrc_config_option("gauge_color")->value.str);
return (res);
}
/*
* Return a pointer to the `.dialogrc' config option specific to `directive' or
* static fp_dummy_config (full of NULLs) if none found (see
* get_config_option(3); part of figpar(3)).
*/
struct fp_config *
dialogrc_config_option(const char *directive)
{
return (get_config_option(dialogrc_config, directive));
}
/*
* Free allocated items initialized by setattr() (via parse_config() callback
* matrix [dialogrc_config] used in parse_dialogrc() above).
*/
void
dialogrc_free(void)
{
char *value;
uint32_t n;
for (n = 0; dialogrc_config[n].directive != NULL; n++) {
if (dialogrc_config[n].action != &setattr)
continue;
value = dialogrc_config[n].value.str;
if (value != NULL && value != gauge_color) {
free(dialogrc_config[n].value.str);
dialogrc_config[n].value.str = NULL;
}
}
}

56
lib/libdpv/dialogrc.h Normal file
View File

@ -0,0 +1,56 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _DIALOGRC_H_
#define _DIALOGRC_H_
#include <sys/types.h>
#include <figpar.h>
/* dialog(3) dlg_color_table[] attributes */
#define GAUGE_ATTR 33 /* entry used for gauge_color */
/* dialog(1) characteristics */
#define DIALOGRC ".dialogrc"
#define ENV_DIALOGRC "DIALOGRC"
#define ENV_HOME "HOME"
/* dialog(1) `.dialogrc' characteristics */
extern uint8_t use_colors;
extern uint8_t use_shadow;
extern char gauge_color[];
extern char separator[];
__BEGIN_DECLS
void dialogrc_free(void);
int parse_dialogrc(void);
struct fp_config *dialogrc_config_option(const char *_directive);
__END_DECLS
#endif /* !_DIALOGRC_H_ */

770
lib/libdpv/dprompt.c Normal file
View File

@ -0,0 +1,770 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#define _BSD_SOURCE /* to get dprintf() prototype in stdio.h below */
#include <dialog.h>
#include <err.h>
#include <libutil.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string_m.h>
#include <unistd.h>
#include "dialog_util.h"
#include "dialogrc.h"
#include "dprompt.h"
#include "dpv.h"
#include "dpv_private.h"
#define FLABEL_MAX 1024
static int fheight = 0; /* initialized by dprompt_init() */
static char dprompt[PROMPT_MAX + 1] = "";
static char *dprompt_pos = (char *)(0); /* treated numerically */
/* Display characteristics */
#define FM_DONE 0x01
#define FM_FAIL 0x02
#define FM_PEND 0x04
static uint8_t dprompt_free_mask;
static char *done = NULL;
static char *fail = NULL;
static char *pend = NULL;
int display_limit = DISPLAY_LIMIT_DEFAULT; /* Max entries to show */
int label_size = LABEL_SIZE_DEFAULT; /* Max width for labels */
int pbar_size = PBAR_SIZE_DEFAULT; /* Mini-progressbar size */
static int gauge_percent = 0;
static int done_size, done_lsize, done_rsize;
static int fail_size, fail_lsize, fail_rsize;
static int mesg_size, mesg_lsize, mesg_rsize;
static int pend_size, pend_lsize, pend_rsize;
static int pct_lsize, pct_rsize;
static void *gauge = NULL;
#define SPIN_SIZE 4
static char spin[SPIN_SIZE + 1] = "/-\\|";
static char msg[PROMPT_MAX + 1];
static char *spin_cp = spin;
/* Function prototypes */
static char spin_char(void);
static int dprompt_add_files(struct dpv_file_node *file_list,
struct dpv_file_node *curfile, int pct);
/*
* Returns a pointer to the current spin character in the spin string and
* advances the global position to the next character for the next call.
*/
static char
spin_char(void)
{
char ch;
if (spin_cp == '\0')
spin_cp = spin;
ch = *spin_cp;
/* Advance the spinner to the next char */
if (++spin_cp >= (spin + SPIN_SIZE))
spin_cp = spin;
return (ch);
}
/*
* Initialize heights and widths based on various strings and environment
* variables (such as ENV_USE_COLOR).
*/
void
dprompt_init(struct dpv_file_node *file_list)
{
uint8_t nls = 0;
int len;
int max_cols;
int max_rows;
int nthfile;
int numlines;
struct dpv_file_node *curfile;
/*
* Initialize dialog(3) `colors' support and draw backtitle
*/
if (use_libdialog && !debug) {
init_dialog(stdin, stdout);
dialog_vars.colors = 1;
if (backtitle != NULL) {
dialog_vars.backtitle = (char *)backtitle;
dlg_put_backtitle();
}
}
/* Calculate width of dialog(3) or [X]dialog(1) --gauge box */
dwidth = label_size + pbar_size + 9;
/*
* Calculate height of dialog(3) or [X]dialog(1) --gauge box
*/
dheight = 5;
max_rows = dialog_maxrows();
/* adjust max_rows for backtitle and/or dialog(3) statusLine */
if (backtitle != NULL)
max_rows -= use_shadow ? 3 : 2;
if (use_libdialog && use_shadow)
max_rows -= 2;
/* add lines for `-p text' */
numlines = dialog_prompt_numlines(pprompt, 0);
if (debug)
warnx("`-p text' is %i line%s long", numlines,
numlines == 1 ? "" : "s");
dheight += numlines;
/* adjust dheight for various implementations */
if (use_dialog) {
dheight -= dialog_prompt_nlstate(pprompt);
nls = dialog_prompt_nlstate(pprompt);
} else if (use_xdialog) {
if (pprompt == NULL || *pprompt == '\0')
dheight++;
} else if (use_libdialog) {
if (pprompt != NULL && *pprompt != '\0')
dheight--;
}
/* limit the number of display items (necessary per dialog(1,3)) */
if (display_limit == 0 || display_limit > DPV_DISPLAY_LIMIT)
display_limit = DPV_DISPLAY_LIMIT;
/* verify fheight will fit (stop if we hit 1) */
for (; display_limit > 0; display_limit--) {
nthfile = numlines = 0;
fheight = (int)dpv_nfiles > display_limit ?
(unsigned int)display_limit : dpv_nfiles;
for (curfile = file_list; curfile != NULL;
curfile = curfile->next) {
nthfile++;
numlines += dialog_prompt_numlines(curfile->name, nls);
if ((nthfile % display_limit) == 0) {
if (numlines > fheight)
fheight = numlines;
numlines = nthfile = 0;
}
}
if (numlines > fheight)
fheight = numlines;
if ((dheight + fheight +
(int)dialog_prompt_numlines(aprompt, use_dialog) -
(use_dialog ? (int)dialog_prompt_nlstate(aprompt) : 0))
<= max_rows)
break;
}
/* don't show any items if we run the risk of hitting a blank set */
if ((max_rows - (use_shadow ? 5 : 4)) >= fheight)
dheight += fheight;
else
fheight = 0;
/* add lines for `-a text' */
numlines = dialog_prompt_numlines(aprompt, use_dialog);
if (debug)
warnx("`-a text' is %i line%s long", numlines,
numlines == 1 ? "" : "s");
dheight += numlines;
/* If using Xdialog(1), adjust accordingly (based on testing) */
if (use_xdialog)
dheight += dheight / 4;
/* For wide mode, long prefix (`pprompt') or append (`aprompt')
* strings will bump width */
if (wide) {
len = (int)dialog_prompt_longestline(pprompt, 0); /* !nls */
if ((len + 4) > dwidth)
dwidth = len + 4;
len = (int)dialog_prompt_longestline(aprompt, 1); /* nls */
if ((len + 4) > dwidth)
dwidth = len + 4;
}
/* Enforce width constraints to maximum values */
max_cols = dialog_maxcols();
if (max_cols > 0 && dwidth > max_cols)
dwidth = max_cols;
/* Optimize widths to sane values*/
if (pbar_size > dwidth - 9) {
pbar_size = dwidth - 9;
label_size = 0;
/* -9 = "| - [" ... "] |" */
}
if (pbar_size < 0)
label_size = dwidth - 8;
/* -8 = "| " ... " - |" */
else if (label_size > (dwidth - pbar_size - 9) || wide)
label_size = no_labels ? 0 : dwidth - pbar_size - 9;
/* -9 = "| " ... " - [" ... "] |" */
/* Hide labels if requested */
if (no_labels)
label_size = 0;
/* Touch up the height (now that we know dwidth) */
dheight += dialog_prompt_wrappedlines(pprompt, dwidth - 4, 0);
dheight += dialog_prompt_wrappedlines(aprompt, dwidth - 4, 1);
if (debug)
warnx("dheight = %i dwidth = %i fheight = %i",
dheight, dwidth, fheight);
/* Calculate left/right portions of % */
pct_lsize = (pbar_size - 4) / 2; /* -4 == printf("%-3s%%", pct) */
pct_rsize = pct_lsize;
/* If not evenly divisible by 2, increment the right-side */
if ((pct_rsize + pct_rsize + 4) != pbar_size)
pct_rsize++;
/* Initialize "Done" text */
if (done == NULL && (done = msg_done) == NULL) {
if ((done = getenv(ENV_MSG_DONE)) != NULL)
done_size = strlen(done);
else {
done_size = strlen(DPV_DONE_DEFAULT);
if ((done = malloc(done_size + 1)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
dprompt_free_mask |= FM_DONE;
snprintf(done, done_size + 1, DPV_DONE_DEFAULT);
}
}
if (pbar_size < done_size) {
done_lsize = done_rsize = 0;
*(done + pbar_size) = '\0';
done_size = pbar_size;
} else {
/* Calculate left/right portions for mini-progressbar */
done_lsize = (pbar_size - done_size) / 2;
done_rsize = done_lsize;
/* If not evenly divisible by 2, increment the right-side */
if ((done_rsize + done_size + done_lsize) != pbar_size)
done_rsize++;
}
/* Initialize "Fail" text */
if (fail == NULL && (fail = msg_fail) == NULL) {
if ((fail = getenv(ENV_MSG_FAIL)) != NULL)
fail_size = strlen(fail);
else {
fail_size = strlen(DPV_FAIL_DEFAULT);
if ((fail = malloc(fail_size + 1)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
dprompt_free_mask |= FM_FAIL;
snprintf(fail, fail_size + 1, DPV_FAIL_DEFAULT);
}
}
if (pbar_size < fail_size) {
fail_lsize = fail_rsize = 0;
*(fail + pbar_size) = '\0';
fail_size = pbar_size;
} else {
/* Calculate left/right portions for mini-progressbar */
fail_lsize = (pbar_size - fail_size) / 2;
fail_rsize = fail_lsize;
/* If not evenly divisible by 2, increment the right-side */
if ((fail_rsize + fail_size + fail_lsize) != pbar_size)
fail_rsize++;
}
/* Initialize "Pending" text */
if (pend == NULL && (pend = msg_pending) == NULL) {
if ((pend = getenv(ENV_MSG_PENDING)) != NULL)
pend_size = strlen(pend);
else {
pend_size = strlen(DPV_PENDING_DEFAULT);
if ((pend = malloc(pend_size + 1)) == NULL)
errx(EXIT_FAILURE, "Out of memory?!");
dprompt_free_mask |= FM_PEND;
snprintf(pend, pend_size + 1, DPV_PENDING_DEFAULT);
}
}
if (pbar_size < pend_size) {
pend_lsize = pend_rsize = 0;
*(pend + pbar_size) = '\0';
pend_size = pbar_size;
} else {
/* Calculate left/right portions for mini-progressbar */
pend_lsize = (pbar_size - pend_size) / 2;
pend_rsize = pend_lsize;
/* If not evenly divisible by 2, increment the right-side */
if ((pend_rsize + pend_lsize + pend_size) != pbar_size)
pend_rsize++;
}
if (debug)
warnx("label_size = %i pbar_size = %i", label_size, pbar_size);
dprompt_clear();
}
/*
* Clear the [X]dialog(1) `--gauge' prompt buffer.
*/
void
dprompt_clear(void)
{
*dprompt = '\0';
dprompt_pos = dprompt;
}
/*
* Append to the [X]dialog(1) `--gauge' prompt buffer. Syntax is like printf(3)
* and returns the number of bytes appended to the buffer.
*/
int
dprompt_add(const char *format, ...)
{
int len;
va_list ap;
if (dprompt_pos >= (dprompt + PROMPT_MAX))
return (0);
va_start(ap, format);
len = vsnprintf(dprompt_pos, (size_t)(PROMPT_MAX -
(dprompt_pos - dprompt)), format, ap);
va_end(ap);
if (len == -1)
errx(EXIT_FAILURE, "%s: Oops, dprompt buffer overflow",
__func__);
if ((dprompt_pos + len) < (dprompt + PROMPT_MAX))
dprompt_pos += len;
else
dprompt_pos = dprompt + PROMPT_MAX;
return (len);
}
/*
* Append active files to the [X]dialog(1) `--gauge' prompt buffer. Syntax
* requires a pointer to the head of the dpv_file_node linked-list. Returns the
* number of files processed successfully.
*/
static int
dprompt_add_files(struct dpv_file_node *file_list,
struct dpv_file_node *curfile, int pct)
{
char c;
char bold_code = 'b'; /* default: enabled */
char color_code = '4'; /* default: blue */
uint8_t after_curfile = curfile != NULL ? FALSE : TRUE;
uint8_t nls = 0;
char *cp;
char *lastline;
char *name;
const char *bg_code;
const char *estext;
const char *format;
enum dprompt_state dstate;
int estext_lsize;
int estext_rsize;
int estext_size;
int flabel_size;
int hlen;
int lsize;
int nlines = 0;
int nthfile = 0;
int pwidth;
int rsize;
struct dpv_file_node *fp;
char flabel[FLABEL_MAX + 1];
char human[32];
char pbar[pbar_size + 16]; /* +15 for optional color */
char pbar_cap[sizeof(pbar)];
char pbar_fill[sizeof(pbar)];
/* Override color defaults with that of main progress bar */
if (use_colors || use_shadow) { /* NB: shadow enables color */
color_code = gauge_color[0];
/* NB: str[1] aka bg is unused */
bold_code = gauge_color[2];
}
/*
* Create mini-progressbar for current file (if applicable)
*/
*pbar = '\0';
if (pbar_size >= 0 && pct >= 0 && curfile != NULL &&
(curfile->length >= 0 || dialog_test)) {
snprintf(pbar, pbar_size + 1, "%*s%3u%%%*s", pct_lsize, "",
pct, pct_rsize, "");
if (use_color) {
/* Calculate the fill-width of progressbar */
pwidth = pct * pbar_size / 100;
/* Round up based on one-tenth of a percent */
if ((pct * pbar_size % 100) > 50)
pwidth++;
/*
* Make two copies of pbar. Make one represent the fill
* and the other the remainder (cap). We'll insert the
* ANSI delimiter in between.
*/
*pbar_fill = '\0';
*pbar_cap = '\0';
strncat(pbar_fill, (const char *)(pbar), dwidth);
*(pbar_fill + pwidth) = '\0';
strncat(pbar_cap, (const char *)(pbar+pwidth), dwidth);
/* Finalize the mini [color] progressbar */
snprintf(pbar, sizeof(pbar),
"\\Z%c\\Zr\\Z%c%s%s%s\\Zn", bold_code, color_code,
pbar_fill, "\\ZR", pbar_cap);
}
}
for (fp = file_list; fp != NULL; fp = fp->next) {
flabel_size = label_size;
name = fp->name;
nthfile++;
/*
* Support multiline filenames (where the filename is taken as
* the last line and the text leading up to the last line can
* be used as (for example) a heading/separator between files.
*/
if (use_dialog)
nls = dialog_prompt_nlstate(pprompt);
nlines += dialog_prompt_numlines(name, nls);
lastline = dialog_prompt_lastline(name, 1);
if (name != lastline) {
c = *lastline;
*lastline = '\0';
dprompt_add("%s", name);
*lastline = c;
name = lastline;
}
/* Support color codes (for dialog(1,3)) in file names */
if ((use_dialog || use_libdialog) && use_color) {
cp = name;
while (*cp != '\0') {
if (*cp == '\\' && *(cp + 1) != '\0' &&
*(++cp) == 'Z' && *(cp + 1) != '\0') {
cp++;
flabel_size += 3;
}
cp++;
}
if (flabel_size > FLABEL_MAX)
flabel_size = FLABEL_MAX;
}
/* If no mini-progressbar, increase label width */
if (pbar_size < 0 && flabel_size <= FLABEL_MAX - 2 &&
no_labels == FALSE)
flabel_size += 2;
/* If name is too long, add an ellipsis */
if (snprintf(flabel, flabel_size + 1, "%s", name) >
flabel_size) sprintf(flabel + flabel_size - 3, "...");
/*
* Append the label (processing the current file differently)
*/
if (fp == curfile && pct < 100) {
/*
* Add an ellipsis to current file name if it will fit.
* There may be an ellipsis already from truncating the
* label (in which case, we already have one).
*/
cp = flabel + strlen(flabel);
if (cp < (flabel + flabel_size))
snprintf(cp, flabel_size -
(cp - flabel) + 1, "...");
/* Append label (with spinner and optional color) */
dprompt_add("%s%-*s%s %c", use_color ? "\\Zb" : "",
flabel_size, flabel, use_color ? "\\Zn" : "",
spin_char());
} else
dprompt_add("%-*s%s %s", flabel_size,
flabel, use_color ? "\\Zn" : "", " ");
/*
* Append pbar/status (processing the current file differently)
*/
dstate = DPROMPT_NONE;
if (fp->msg != NULL)
dstate = DPROMPT_CUSTOM_MSG;
else if (pbar_size < 0)
dstate = DPROMPT_NONE;
else if (pbar_size < 4)
dstate = DPROMPT_MINIMAL;
else if (after_curfile)
dstate = DPROMPT_PENDING;
else if (fp == curfile) {
if (*pbar == '\0') {
if (fp->length < 0)
dstate = DPROMPT_DETAILS;
else if (fp->status == DPV_STATUS_RUNNING)
dstate = DPROMPT_DETAILS;
else
dstate = DPROMPT_END_STATE;
}
else if (dialog_test) /* status/length ignored */
dstate = pct < 100 ?
DPROMPT_PBAR : DPROMPT_END_STATE;
else if (fp->status == DPV_STATUS_RUNNING)
dstate = fp->length < 0 ?
DPROMPT_DETAILS : DPROMPT_PBAR;
else /* not running */
dstate = fp->length < 0 ?
DPROMPT_DETAILS : DPROMPT_END_STATE;
} else { /* before curfile */
if (dialog_test)
dstate = DPROMPT_END_STATE;
else
dstate = fp->length < 0 ?
DPROMPT_DETAILS : DPROMPT_END_STATE;
}
format = use_color ?
" [\\Z%c%s%-*s%s%-*s\\Zn]\\n" :
" [%-*s%s%-*s]\\n";
if (fp->status == DPV_STATUS_FAILED) {
bg_code = "\\Zr\\Z1"; /* Red */
estext_lsize = fail_lsize;
estext_rsize = fail_rsize;
estext_size = fail_size;
estext = fail;
} else { /* e.g., DPV_STATUS_DONE */
bg_code = "\\Zr\\Z2"; /* Green */
estext_lsize = done_lsize;
estext_rsize = done_rsize;
estext_size = done_size;
estext = done;
}
switch (dstate) {
case DPROMPT_PENDING: /* Future file(s) */
dprompt_add(" [%-*s%s%-*s]\\n",
pend_lsize, "", pend, pend_rsize, "");
break;
case DPROMPT_PBAR: /* Current file */
dprompt_add(" [%s]\\n", pbar);
break;
case DPROMPT_END_STATE: /* Past/Current file(s) */
if (use_color)
dprompt_add(format, bold_code, bg_code,
estext_lsize, "", estext,
estext_rsize, "");
else
dprompt_add(format,
estext_lsize, "", estext,
estext_rsize, "");
break;
case DPROMPT_DETAILS: /* Past/Current file(s) */
humanize_number(human, pbar_size + 2, fp->read, "",
HN_AUTOSCALE, HN_NOSPACE | HN_DIVISOR_1000);
/* Calculate center alignment */
hlen = (int)strlen(human);
lsize = (pbar_size - hlen) / 2;
rsize = lsize;
if ((lsize+hlen+rsize) != pbar_size)
rsize++;
if (use_color)
dprompt_add(format, bold_code, bg_code,
lsize, "", human, rsize, "");
else
dprompt_add(format,
lsize, "", human, rsize, "");
break;
case DPROMPT_CUSTOM_MSG: /* File-specific message override */
snprintf(msg, PROMPT_MAX + 1, "%s", fp->msg);
if (pbar_size < (mesg_size = strlen(msg))) {
mesg_lsize = mesg_rsize = 0;
*(msg + pbar_size) = '\0';
mesg_size = pbar_size;
} else {
mesg_lsize = (pbar_size - mesg_size) / 2;
mesg_rsize = mesg_lsize;
if ((mesg_rsize + mesg_size + mesg_lsize)
!= pbar_size)
mesg_rsize++;
}
if (use_color)
dprompt_add(format, bold_code, bg_code,
mesg_lsize, "", msg, mesg_rsize, "");
else
dprompt_add(format, mesg_lsize, "", msg,
mesg_rsize, "");
break;
case DPROMPT_MINIMAL: /* Short progress bar, minimal room */
if (use_color)
dprompt_add(format, bold_code, bg_code,
pbar_size, "", "", 0, "");
else
dprompt_add(format, pbar_size, "", "", 0, "");
break;
case DPROMPT_NONE: /* pbar_size < 0 */
/* FALLTHROUGH */
default:
dprompt_add(" \\n");
/*
* NB: Leading space required for the case when
* spin_char() returns a single backslash [\] which
* without the space, changes the meaning of `\n'
*/
}
/* Stop building if we've hit the internal limit */
if (nthfile >= display_limit)
break;
/* If this is the current file, all others are pending */
if (fp == curfile)
after_curfile = TRUE;
}
/*
* Since we cannot change the height/width of the [X]dialog(1) widget
* after spawn, to make things look nice let's pad the height so that
* the `-a text' always appears in the same spot.
*
* NOTE: fheight is calculated in dprompt_init(). It represents the
* maximum height required to display the set of items (broken up into
* pieces of display_limit chunks) whose names contain the most
* newlines for any given set.
*/
while (nlines < fheight) {
dprompt_add("\n");
nlines++;
}
return (nthfile);
}
/*
* Process the dpv_file_node linked-list of named files, re-generating the
* [X]dialog(1) `--gauge' prompt text for the current state of transfers.
*/
void
dprompt_recreate(struct dpv_file_node *file_list,
struct dpv_file_node *curfile, int pct)
{
size_t len;
/*
* Re-Build the prompt text
*/
dprompt_clear();
if (display_limit > 0)
dprompt_add_files(file_list, curfile, pct);
/* Xdialog(1) requires newlines (a) escaped and (b) in triplicate */
if (use_xdialog) {
/* Replace `\n' with `\n\\n\n' in dprompt */
len = strlen(dprompt);
len += strcount(dprompt, "\\n") * 5; /* +5 chars per count */
if (len > PROMPT_MAX)
errx(EXIT_FAILURE, "%s: Oops, dprompt buffer overflow "
"(%zu > %i)", __func__, len, PROMPT_MAX);
if (replaceall(dprompt, "\\n", "\n\\n\n") < 0)
err(EXIT_FAILURE, "%s: replaceall()", __func__);
}
else if (use_libdialog)
strexpandnl(dprompt);
}
/*
* Print the [X]dialog(1) `--gauge' prompt text to a buffer.
*/
int
dprompt_sprint(char * restrict str, const char *prefix, const char *append)
{
return (snprintf(str, PROMPT_MAX, "%s%s%s%s", use_color ? "\\Zn" : "",
prefix ? prefix : "", dprompt, append ? append : ""));
}
/*
* Print the [X]dialog(1) `--gauge' prompt text to file descriptor fd (could
* be STDOUT_FILENO or a pipe(2) file descriptor to actual [X]dialog(1)).
*/
void
dprompt_dprint(int fd, const char *prefix, const char *append, int overall)
{
int percent = gauge_percent;
if (overall >= 0 && overall <= 100)
gauge_percent = percent = overall;
dprintf(fd, "XXX\n%s%s%s%s\nXXX\n%i\n", use_color ? "\\Zn" : "",
prefix ? prefix : "", dprompt, append ? append : "", percent);
fsync(fd);
}
/*
* Print the dialog(3) `gauge' prompt text using libdialog.
*/
void
dprompt_libprint(const char *prefix, const char *append, int overall)
{
int percent = gauge_percent;
char buf[DPV_PPROMPT_MAX + DPV_APROMPT_MAX + DPV_DISPLAY_LIMIT * 1024];
dprompt_sprint(buf, prefix, append);
if (overall >= 0 && overall <= 100)
gauge_percent = percent = overall;
gauge = dlg_reallocate_gauge(gauge, title == NULL ? "" : title,
buf, dheight, dwidth, percent);
dlg_update_gauge(gauge, percent);
}
/*
* Free allocated items initialized by dprompt_init()
*/
void
dprompt_free(void)
{
if ((dprompt_free_mask & FM_DONE) != 0) {
dprompt_free_mask ^= FM_DONE;
free(done);
done = NULL;
}
if ((dprompt_free_mask & FM_FAIL) != 0) {
dprompt_free_mask ^= FM_FAIL;
free(fail);
fail = NULL;
}
if ((dprompt_free_mask & FM_PEND) != 0) {
dprompt_free_mask ^= FM_PEND;
free(pend);
pend = NULL;
}
}

59
lib/libdpv/dprompt.h Normal file
View File

@ -0,0 +1,59 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _DPROMPT_H_
#define _DPROMPT_H_
#include <sys/cdefs.h>
#include "dpv.h"
/* Display characteristics */
#define ENV_MSG_DONE "msg_done"
#define ENV_MSG_FAIL "msg_fail"
#define ENV_MSG_PENDING "msg_pending"
extern int display_limit;
extern int label_size;
extern int pbar_size;
__BEGIN_DECLS
void dprompt_clear(void);
void dprompt_dprint(int _fd, const char *_prefix, const char *_append,
int _overall);
void dprompt_free(void);
void dprompt_init(struct dpv_file_node *_file_list);
void dprompt_libprint(const char *_prefix, const char *_append,
int _overall);
void dprompt_recreate(struct dpv_file_node *_file_list,
struct dpv_file_node *_curfile, int _pct);
int dprompt_add(const char *_format, ...);
int dprompt_sprint(char * restrict _str, const char *_prefix,
const char *_append);
__END_DECLS
#endif /* !_DPROMPT_H_ */

510
lib/libdpv/dpv.3 Normal file
View File

@ -0,0 +1,510 @@
.\" Copyright (c) 2013-2014 Devin Teske
.\" All rights reserved.
.\"
.\" 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.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
.\"
.\" $FreeBSD$
.\"
.Dd Oct 24, 2014
.Dt DPV 3
.Os
.Sh NAME
.Nm dpv
.Nd dialog progress view library
.Sh LIBRARY
.Lb libdpv
.Sh SYNOPSIS
.In dpv.h
.Ft int
.Fo dpv
.Fa "struct dpv_config *config, struct dpv_file_node *file_list"
.Fc
.Ft void
.Fo dpv_free
.Fa "void"
.Fc
.Sh DESCRIPTION
The
.Nm
library provides an interface for creating complex
.Dq gauge
widgets for displaying progress on various actions.
The
.Nm
library can display progress with one of
.Xr dialog 3 ,
.Xr dialog 1 ,
or
.Xr Xdialog 1
.Pq x11/xdialog from the ports tree .
.Pp
The
.Fn dpv
.Fa config
argument contains the following properties for configuring global display
features:
.Bd -literal -offset indent
struct dpv_config {
enum dpv_display display_type; /* Def. DPV_DISPLAY_LIBDIALOG */
enum dpv_output output_type; /* Default DPV_OUTPUT_NONE */
int debug; /* Enable debug on stderr */
int display_limit; /* Files/page. Default -1 */
int label_size; /* Label size. Default 28 */
int pbar_size; /* Mini-progress size */
int dialog_updates_per_second; /* Default 16 */
int status_updates_per_second; /* Default 2 */
uint16_t options; /* Default 0 (none) */
char *title; /* Widget title */
char *backtitle; /* Widget backtitle */
char *aprompt; /* Append. Default NULL */
char *pprompt; /* Prefix. Default NULL */
char *msg_done; /* Default `Done' */
char *msg_fail; /* Default `Fail' */
char *msg_pending; /* Default `Pending' */
char *output; /* Output format string */
const char *status_solo; /* dialog(3) solo-status format.
* Default DPV_STATUS_SOLO */
const char *status_many; /* dialog(3) many-status format.
* Default DPV_STATUS_MANY */
/*
* Function pointer; action to perform data transfer
*/
int (*action)(struct dpv_file_node *file, int out);
};
enum dpv_display {
DPV_DISPLAY_LIBDIALOG = 0, /* Use dialog(3) (default) */
DPV_DISPLAY_STDOUT, /* Use stdout */
DPV_DISPLAY_DIALOG, /* Use spawned dialog(1) */
DPV_DISPLAY_XDIALOG, /* Use spawned Xdialog(1) */
};
enum dpv_output {
DPV_OUTPUT_NONE = 0, /* No output (default) */
DPV_OUTPUT_FILE, /* Read `output' member as file path */
DPV_OUTPUT_SHELL, /* Read `output' member as shell cmd */
};
.Ed
.Pp
The
.Va options
member of the
.Fn dpv
.Fa config
argument is a mask of bit fields indicating various processing options.
Possible flags are as follows:
.Bl -tag -width DPV_NO_OVERRUN
.It Dv DPV_TEST_MODE
Enable test mode.
In test mode, the
.Fn action
callback of the
.Fa config
argument is not called but instead simulated-data is used to drive progress.
Appends
.Dq [TEST MODE]
to the status line
.Po
to override, set the
.Va status_format
member of the
.Fn dpv
.Fa config
argument;
e.g., to
.Dv DPV_STATUS_DEFAULT
.Pc .
.It Dv DPV_WIDE_MODE
Enable wide mode.
In wide mode, the length of the
.Va aprompt
and
.Va pprompt
members of the
.Fn dpv
.Fa config
argument will bump the width of the gauge widget.
Prompts wider than the maximum width will wrap
.Po
unless using
.Xr Xdialog 1 ;
see BUGS section below
.Pc .
.It Dv DPV_NO_LABELS
Disables the display of labels associated with each transfer
.Po
.Va label_size
member of
.Fn dpv
.Fa config
argument is ignored
.Pc .
.It Dv DPV_USE_COLOR
Force the use of color even if the
.Va display_type
does not support color
.Po
.Ev USE_COLOR
environment variable is ignored
.Pc .
.It Dv DPV_NO_OVERRUN
When enabled, callbacks for the current
.Vt dpv_file_node
are terminated when
.Fn action
returns 100 or greater
.Po
alleviates the need to change the
.Va status
of the current
.Vt dpv_file_node
but may also cause file truncation if the stream exceeds expected length
.Pc .
.El
.Pp
The
.Fa file_list
argument to
.Fn dpv
is a pointer to a
.Dq linked-list ,
described as follows in
.In dpv.h :
.Bd -literal -offset indent
struct dpv_file_node {
enum dpv_status status; /* status of read operation */
char *msg; /* display instead of "Done/Fail" */
char *name; /* name of file to read */
char *path; /* path to file */
long long length; /* expected size */
long long read; /* number units read (e.g., bytes) */
struct dpv_file_node *next;/* pointer to next (end with NULL) */
};
.Ed
.Pp
For each of the items in the
.Fa file_list
.Dq linked-list
argument, the
.Fn action
callback member of the
.Fn dpv
.Fa config
argument is called.
The
.Fn action
function should perform a
.Dq nominal
action on the file and return.
The return value of
.Vt int
represents the current progress percentage
.Pq 0-100
for the current file.
.Pp
The
.Fn action
callback provides two variables for each call.
.Fa file
provides a reference to the current
.Vt dpv_file_node
being processed.
.Fa out
provides a file descriptor where the data should go.
.Pp
If the
.Va output
member of the
.Fn dpv
.Fa config
argument was set to DPV_OUTPUT_NONE
.Pq default ; when invoking Fn dpv ,
the
.Fa out
file descriptor of
.Fn action
will be zero and should be ignored.
If
.Fa output
was set to DPV_OUTPUT_FILE,
.Fa out
will be an open file descriptor to a file.
If
.Fa output
was set to DPV_OUTPUT_SHELL,
.Fa out
will be an open file descriptor to a pipe for a spawned shell program.
When
.Fa out
is greater than zero, you should write any data you have read back to
.Fa out .
.Pp
To abort
.Fn dpv ,
either from the
.Fn action
callback or asynchronously from a signal handler, two globals are provided via
.In dpv.h :
.Bd -literal -offset indent
extern int dpv_interrupt; /* Set to TRUE in interrupt handler */
extern int dpv_abort; /* Set to true in callback to abort */
.Ed
.Pp
These globals are not automatically reset and must be manually maintained.
Don't forget to reset these globals before subsequent invocations of
.Fn dpv
when making multiple calls from the same program.
.Pp
In addition, the
.Va status
member of the
.Fn action
.Fa file
argument can be used to control callbacks for the current file.
The
.Va status
member can be set to any of the following from
.In dpv.h :
.Bd -literal -offset indent
enum dpv_status {
DPV_STATUS_RUNNING = 0, /* Running (default) */
DPV_STATUS_DONE, /* Completed */
DPV_STATUS_FAILED, /* Oops, something went wrong */
};
.Ed
.Pp
The default
.Fa status
is zero, DPV_STATUS_RUNING, which keeps the callbacks coming for the current
.Fn file .
Setting
.Ql file->status
to anything other than DPV_STATUS_RUNNING will cause
.Fn dpv
to loop to the next file, effecting the next callback, if any.
.Pp
The
.Fn action
callback is responsible for calculating percentages and
.Pq recommended
maintaining a
.Nm
global counter so
.Fn dpv
can display throughput statistics.
Percentages are reported through the
.Vt int
return value of the
.Fn action
callback.
Throughput statistics are calculated from the following global
.Vt int
in
.In dpv.h :
.Bd -literal -offset indent
extern int dpv_overall_read;
.Ed
.Pp
This should be set to the number of bytes that have been read for all files.
Throughput information is displayed in the status line
.Pq only available when using Xr dialog 3
at the bottom of the screen.
See DPV_DISPLAY_LIBDIALOG above.
.Pp
Note that
.Va dpv_overall_read
does not have to represent bytes.
For example, you can change the
.Va status_format
to display something other than
.Dq Li bytes
and increment
.Va dpv_overall_read
accordingly
.Pq e.g., counting lines .
.Pp
When
.Fn dpv
is processing the current file, the
.Va length
and
.Va read
members of the
.Fn action
.Fa file
argument are used for calculating the display of mini progress bars
.Po
if enabled; see
.Va pbar_size
above
.Pc .
If the
.Va length
member of the current
.Fa file
is less than zero
.Pq indicating an unknown file length ,
a
.Xr humanize_number 3
version of the
.Va read
member is used instead of a traditional progress bar.
Otherwise a progress bar is calculated as percentage read to file length.
.Fn action
callback must maintain these member values for mini-progress bars.
.Pp
The
.Fn dpv_free
function performs
.Xr free 3
on private global variables initialized by
.Fn dpv .
.Sh ENVIRONMENT
The following environment variables are referenced by
.Nm :
.Bl -tag -width ".Ev USE_COLOR"
.It Ev DIALOG
Override command string used to launch
.Xr dialog 1
.Pq requires Dv DPV_DISPLAY_DIALOG
or
.Xr Xdialog 1
.Pq requires Dv DPV_DISPLAY_XDIALOG ;
default is either
.Ql dialog
.Pq for Dv DPV_DISPLAY_DIALOG
or
.Ql Xdialog
.Pq for Dv DPV_DISPLAY_XDIALOG .
.It Ev DIALOGRC
If set and non-NULL, path to
.Ql .dialogrc
file.
.It Ev HOME
If
.Ql Ev $DIALOGRC
is either not set or NULL, used as a prefix to
.Ql .dialogrc
.Pq i.e., Ql $HOME/.dialogrc .
.It Ev USE_COLOR
If set and NULL, disables the use of color when using
.Xr dialog 1
.Pq does not apply to Xr Xdialog 1 .
.It Ev msg_done Ev msg_fail Ev msg_pending
Internationalization strings for overriding the default English strings
.Ql Done ,
.Ql Fail ,
and
.Ql Pending
respectively.
To prevent their usage, explicitly set the
.Va msg_done ,
.Va msg_fail ,
and
.Va msg_pending
members of
.Fn dpv
.Fa config
argument to default macros
.Pq DPV_DONE_DEFAULT, DPV_FAIL_DEFAULT, and DPV_PENDING_DEFAULT
or desired values.
.El
.Sh FILES
.Bl -tag -width ".Pa $HOME/.dialogrc" -compact
.It Pa $HOME/.dialogrc
.El
.Sh SEE ALSO
.Xr dialog 1 ,
.Xr dialog 3 ,
.Xr Xdialog 1
.Sh HISTORY
The
.Nm
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.An Devin Teske Aq dteske@FreeBSD.org
.Sh BUGS
.Xr Xdialog 1 ,
when given both
.Ql Fl -title Ar title
.Po
see above
.Ql Va title
member of
.Va struct dpv_config
.Pc
and
.Ql Fl -backtitle Ar backtitle
.Po
see above
.Ql Va backtitle
member of
.Va struct dpv_config
.Pc ,
displays the backtitle in place of the title and vice-versa.
.Pp
.Xr Xdialog 1
does not wrap long prompt texts received after initial launch.
This is a known issue with the
.Ql --gauge
widget in
.Xr Xdialog 1 .
Embed escaped newlines within prompt text(s) to force line breaks.
.Pp
.Xr dialog 1
does not display the first character after a series of escaped escape-sequences
(e.g., ``\\\\n'' produces ``\\'' instead of ``\\n'').
This is a known issue with
.Xr dialog 1
and does not affect
.Xr dialog 3
or
.Xr Xdialog 1 .
.Pp
If your application ignores
.Ev USE_COLOR
when set and NULL before calling
.Xr dpv 3
with color escape sequences anyway,
.Xr dialog 3
and
.Xr dialog 1
may not render properly.
Workaround is to detect when
.Ev USE_COLOR
is set and NULL and either not use color escape sequences at that time or use
.Xr unsetenv 3
to unset
.Ev USE_COLOR ,
forcing interpretation of color sequences.
This does not effect
.Xr Xdialog 1 ,
which renders the color escape sequences as plain text.
See
.Do Li
embedded "\\Z" sequences
.Dc
in
.Xr dialog 1
for additional information.

721
lib/libdpv/dpv.c Normal file
View File

@ -0,0 +1,721 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <ctype.h>
#include <dialog.h>
#include <err.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string_m.h>
#include <unistd.h>
#include "dialog_util.h"
#include "dialogrc.h"
#include "dprompt.h"
#include "dpv.h"
#include "dpv_private.h"
#include "status.h"
#include "util.h"
/* Test Mechanics (Only used when dpv_config.options |= DPV_TEST_MODE) */
#define INCREMENT 1 /* Increment % per-pass test-mode */
#define XDIALOG_INCREMENT 15 /* different for slower Xdialog(1) */
static uint8_t increment = INCREMENT;
/* Debugging */
uint8_t debug = FALSE;
/* Data to process */
int dpv_interrupt = FALSE;
int dpv_abort = FALSE;
unsigned int dpv_nfiles = 0;
/* Data processing */
long long dpv_overall_read = 0;
static char pathbuf[PATH_MAX];
/* Extra display information */
uint8_t no_labels = FALSE; /* dpv_config.options & DPV_NO_LABELS */
uint8_t wide = FALSE; /* dpv_config.options & DPV_WIDE_MODE */
char *aprompt = NULL; /* dpv_config.aprompt */
char *msg_done = NULL; /* dpv_config.msg_done */
char *msg_fail = NULL; /* dpv_config.msg_fail */
char *msg_pending = NULL; /* dpv_config.msg_pending */
char *pprompt = NULL; /* dpv_config.pprompt */
/* Status-Line format for when using dialog(3) */
static const char *status_format_custom = NULL;
static char status_format_default[DPV_STATUS_FORMAT_MAX];
/*
* Takes a pointer to a dpv_config structure containing layout details and
* pointer to initial element in a linked-list of dpv_file_node structures,
* each presenting a file to process. Executes the `action' function passed-in
* as a member to the `config' structure argument.
*/
int
dpv(struct dpv_config *config, struct dpv_file_node *file_list)
{
char c;
uint8_t keep_going;
uint8_t nls = FALSE; /* See dialog_prompt_nlstate() */
uint8_t no_overrun = FALSE;
uint8_t pprompt_nls = FALSE; /* See dialog_prompt_nlstate() */
uint8_t shrink_label_size = FALSE;
mode_t mask;
uint16_t options;
char *cp;
char *fc;
char *last;
char *name;
char *output;
const char *status_fmt;
const char *path_fmt;
enum dpv_display display_type;
enum dpv_output output_type;
enum dpv_status status;
int (*action)(struct dpv_file_node *file, int out);
int backslash;
int dialog_last_update = 0;
int dialog_old_nthfile = 0;
int dialog_old_seconds = -1;
int dialog_out = STDOUT_FILENO;
int dialog_update_usec = 0;
int dialog_updates_per_second;
int files_left;
int max_cols;
int nthfile = 0;
int output_out;
int overall = 0;
int pct;
int res;
int seconds;
int status_last_update = 0;
int status_old_nthfile = 0;
int status_old_seconds = -1;
int status_update_usec = 0;
int status_updates_per_second;
pid_t output_pid;
pid_t pid;
size_t len;
struct dpv_file_node *curfile;
struct dpv_file_node *first_file;
struct dpv_file_node *list_head;
struct timeval now;
struct timeval start;
char init_prompt[PROMPT_MAX + 1] = "";
/* Initialize globals to default values */
aprompt = NULL;
pprompt = NULL;
options = 0;
action = NULL;
backtitle = NULL;
debug = FALSE;
dialog_test = FALSE;
dialog_updates_per_second = DIALOG_UPDATES_PER_SEC;
display_limit = DISPLAY_LIMIT_DEFAULT;
display_type = DPV_DISPLAY_LIBDIALOG;
label_size = LABEL_SIZE_DEFAULT;
msg_done = NULL;
msg_fail = NULL;
msg_pending = NULL;
no_labels = FALSE;
output = NULL;
output_type = DPV_OUTPUT_NONE;
pbar_size = PBAR_SIZE_DEFAULT;
status_format_custom = NULL;
status_updates_per_second = STATUS_UPDATES_PER_SEC;
title = NULL;
wide = FALSE;
/* Process config options (overriding defaults) */
if (config != NULL) {
if (config->aprompt != NULL) {
if (aprompt == NULL) {
aprompt = malloc(DPV_APROMPT_MAX);
if (aprompt == NULL)
return (-1);
}
snprintf(aprompt, DPV_APROMPT_MAX, "%s",
config->aprompt);
}
if (config->pprompt != NULL) {
if (pprompt == NULL) {
pprompt = malloc(DPV_PPROMPT_MAX + 2);
/* +2 is for implicit "\n" appended later */
if (pprompt == NULL)
return (-1);
}
snprintf(pprompt, DPV_APROMPT_MAX, "%s",
config->pprompt);
}
options = config->options;
action = config->action;
backtitle = config->backtitle;
debug = config->debug;
dialog_test = ((options & DPV_TEST_MODE) != 0);
dialog_updates_per_second = config->dialog_updates_per_second;
display_limit = config->display_limit;
display_type = config->display_type;
label_size = config->label_size;
msg_done = (char *)config->msg_done;
msg_fail = (char *)config->msg_fail;
msg_pending = (char *)config->msg_pending;
no_labels = ((options & DPV_NO_LABELS) != 0);
no_overrun = ((options & DPV_NO_OVERRUN) != 0);
output = config->output;
output_type = config->output_type;
pbar_size = config->pbar_size;
status_updates_per_second = config->status_updates_per_second;
title = config->title;
wide = ((options & DPV_WIDE_MODE) != 0);
/* Enforce some minimums (pedantic) */
if (display_limit < -1)
display_limit = -1;
if (label_size < -1)
label_size = -1;
if (pbar_size < -1)
pbar_size = -1;
/* For the mini-pbar, -1 means hide, zero is invalid unless
* only one file is given */
if (pbar_size == 0) {
if (file_list == NULL || file_list->next == NULL)
pbar_size = -1;
else
pbar_size = PBAR_SIZE_DEFAULT;
}
/* For the label, -1 means auto-size, zero is invalid unless
* specifically requested through the use of options flag */
if (label_size == 0 && no_labels == FALSE)
label_size = LABEL_SIZE_DEFAULT;
/* Status update should not be zero */
if (status_updates_per_second == 0)
status_updates_per_second = STATUS_UPDATES_PER_SEC;
} /* config != NULL */
/* Process the type of display we've been requested to produce */
switch (display_type) {
case DPV_DISPLAY_STDOUT:
debug = TRUE;
use_color = FALSE;
use_dialog = FALSE;
use_libdialog = FALSE;
use_xdialog = FALSE;
break;
case DPV_DISPLAY_DIALOG:
use_color = TRUE;
use_dialog = TRUE;
use_libdialog = FALSE;
use_xdialog = FALSE;
break;
case DPV_DISPLAY_XDIALOG:
snprintf(dialog, PATH_MAX, XDIALOG);
use_color = FALSE;
use_dialog = FALSE;
use_libdialog = FALSE;
use_xdialog = TRUE;
break;
default:
use_color = TRUE;
use_dialog = FALSE;
use_libdialog = TRUE;
use_xdialog = FALSE;
break;
} /* display_type */
/* Enforce additional minimums that require knowing our display type */
if (dialog_updates_per_second == 0)
dialog_updates_per_second = use_xdialog ?
XDIALOG_UPDATES_PER_SEC : DIALOG_UPDATES_PER_SEC;
/* Allow forceful override of use_color */
if (config != NULL && (config->options & DPV_USE_COLOR) != 0)
use_color = TRUE;
/* Count the number of files in provided list of dpv_file_node's */
if (use_dialog && pprompt != NULL && *pprompt != '\0')
pprompt_nls = dialog_prompt_nlstate(pprompt);
max_cols = dialog_maxcols();
if (label_size == -1)
shrink_label_size = TRUE;
/* Process file arguments */
for (curfile = file_list; curfile != NULL; curfile = curfile->next) {
dpv_nfiles++;
/* dialog(3) only expands literal newlines */
if (use_libdialog) strexpandnl(curfile->name);
/* Optionally calculate label size for file */
if (shrink_label_size) {
nls = FALSE;
name = curfile->name;
if (curfile == file_list)
nls = pprompt_nls;
last = (char *)dialog_prompt_lastline(name, nls);
if (use_dialog) {
c = *last;
*last = '\0';
nls = dialog_prompt_nlstate(name);
*last = c;
}
len = dialog_prompt_longestline(last, nls);
if ((int)len > (label_size - 3)) {
if (label_size > 0)
label_size += 3;
label_size = len;
/* Room for ellipsis (unless NULL) */
if (label_size > 0)
label_size += 3;
}
if (max_cols > 0 && label_size > (max_cols - pbar_size
- 9))
label_size = max_cols - pbar_size - 9;
}
if (debug)
warnx("label=[%s] path=[%s] size=%lli",
curfile->name, curfile->path, curfile->length);
} /* file_list */
/* Optionally process the contents of DIALOGRC (~/.dialogrc) */
if (use_dialog) {
res = parse_dialogrc();
if (debug && res == 0) {
warnx("Successfully read `%s' config file", DIALOGRC);
warnx("use_shadow = %i (Boolean)", use_shadow);
warnx("use_colors = %i (Boolean)", use_colors);
warnx("gauge_color=[%s] (FBH)", gauge_color);
}
} else if (use_libdialog) {
init_dialog(stdin, stdout);
use_shadow = dialog_state.use_shadow;
use_colors = dialog_state.use_colors;
gauge_color[0] = 48 + dlg_color_table[GAUGE_ATTR].fg;
gauge_color[1] = 48 + dlg_color_table[GAUGE_ATTR].bg;
gauge_color[2] = dlg_color_table[GAUGE_ATTR].hilite ?
'b' : 'B';
gauge_color[3] = '\0';
end_dialog();
if (debug) {
warnx("Finished initializing dialog(3) library");
warnx("use_shadow = %i (Boolean)", use_shadow);
warnx("use_colors = %i (Boolean)", use_colors);
warnx("gauge_color=[%s] (FBH)", gauge_color);
}
}
/* Enable mini progress bar automatically for stdin streams if unable
* to calculate progress (missing `lines:' syntax). */
if (dpv_nfiles <= 1 && file_list != NULL && file_list->length < 0 &&
!dialog_test)
pbar_size = PBAR_SIZE_DEFAULT;
/* If $USE_COLOR is set and non-NULL enable color; otherwise disable */
if ((cp = getenv(ENV_USE_COLOR)) != 0)
use_color = *cp != '\0' ? 1 : 0;
/* Print error and return `-1' if not given at least one name */
if (dpv_nfiles == 0) {
warnx("%s: no labels provided", __func__);
return (-1);
} else if (debug)
warnx("%s: %u label%s provided", __func__, dpv_nfiles,
dpv_nfiles == 1 ? "" : "s");
/* If only one file and pbar size is zero, default to `-1' */
if (dpv_nfiles <= 1 && pbar_size == 0)
pbar_size = -1;
/* Print some debugging information */
if (debug) {
warnx("%s: %s(%i) max rows x cols = %i x %i",
__func__, use_xdialog ? XDIALOG : DIALOG,
use_libdialog ? 3 : 1, dialog_maxrows(),
dialog_maxcols());
}
/* Xdialog(1) updates a lot slower than dialog(1) */
if (dialog_test && use_xdialog)
increment = XDIALOG_INCREMENT;
/* Always add implicit newline to pprompt (when specified) */
if (pprompt != NULL && *pprompt != '\0') {
len = strlen(pprompt);
/*
* NOTE: pprompt = malloc(PPROMPT_MAX + 2)
* NOTE: (see getopt(2) section above for pprompt allocation)
*/
pprompt[len++] = '\\';
pprompt[len++] = 'n';
pprompt[len++] = '\0';
}
/* Xdialog(1) requires newlines (a) escaped and (b) in triplicate */
if (use_xdialog && pprompt != NULL) {
/* Replace `\n' with `\n\\n\n' in pprompt */
len = strlen(pprompt);
len += strcount(pprompt, "\\n") * 2;
if (len > DPV_PPROMPT_MAX)
errx(EXIT_FAILURE, "%s: Oops, pprompt buffer overflow "
"(%zu > %i)", __func__, len, DPV_PPROMPT_MAX);
if (replaceall(pprompt, "\\n", "\n\\n\n") < 0)
err(EXIT_FAILURE, "%s: replaceall()", __func__);
}
/* libdialog requires literal newlines */
else if (use_libdialog && pprompt != NULL)
strexpandnl(pprompt);
/* Xdialog(1) requires newlines (a) escaped and (b) in triplicate */
if (use_xdialog && aprompt != NULL) {
/* Replace `\n' with `\n\\n\n' in aprompt */
len = strlen(aprompt);
len += strcount(aprompt, "\\n") * 2;
if (len > DPV_APROMPT_MAX)
errx(EXIT_FAILURE, "%s: Oops, aprompt buffer overflow "
" (%zu > %i)", __func__, len, DPV_APROMPT_MAX);
if (replaceall(aprompt, "\\n", "\n\\n\n") < 0)
err(EXIT_FAILURE, "%s: replaceall()", __func__);
}
/* libdialog requires literal newlines */
else if (use_libdialog && aprompt != NULL)
strexpandnl(aprompt);
/*
* Warn user about an obscure dialog(1) bug (neither Xdialog(1) nor
* libdialog are affected) in the `--gauge' widget. If the first non-
* whitespace letter of "{new_prompt}" in "XXX\n{new_prompt}\nXXX\n"
* is a number, the number can sometimes be mistaken for a percentage
* to the overall progressbar. Other nasty side-effects such as the
* entire prompt not displaying or displaying improperly are caused by
* this bug too.
*
* NOTE: When we can use color, we have a work-around... prefix the
* output with `\Zn' (used to terminate ANSI and reset to normal).
*/
if (use_dialog && !use_color) {
backslash = 0;
/* First, check pprompt (falls through if NULL) */
fc = pprompt;
while (fc != NULL && *fc != '\0') {
if (*fc == '\n') /* leading literal newline OK */
break;
if (!isspace(*fc) && *fc != '\\' && backslash == 0)
break;
else if (backslash > 0 && *fc != 'n')
break;
else if (*fc == '\\') {
backslash++;
if (backslash > 2)
break; /* we're safe */
}
fc++;
}
/* First non-whitespace character that dialog(1) will see */
if (fc != NULL && *fc >= '0' && *fc <= '9')
warnx("%s: WARNING! text argument to `-p' begins with "
"a number (not recommended)", __func__);
else if (fc > pprompt)
warnx("%s: WARNING! text argument to `-p' begins with "
"whitespace (not recommended)", __func__);
/*
* If no pprompt or pprompt is all whitespace, check the first
* file name provided to make sure it is alright too.
*/
if ((pprompt == NULL || *fc == '\0') && file_list != NULL) {
first_file = file_list;
fc = first_file->name;
while (fc != NULL && *fc != '\0' && isspace(*fc))
fc++;
/* First non-whitespace char that dialog(1) will see */
if (fc != NULL && *fc >= '0' && *fc <= '9')
warnx("%s: WARNING! File name `%s' begins "
"with a number (use `-p text' for safety)",
__func__, first_file->name);
}
}
dprompt_init(file_list);
/* Reads: label_size pbar_size pprompt aprompt dpv_nfiles */
/* Inits: dheight and dwidth */
if (!debug) {
/* Internally create the initial `--gauge' prompt text */
dprompt_recreate(file_list, (struct dpv_file_node *)NULL, 0);
/* Spawn [X]dialog(1) `--gauge', returning pipe descriptor */
if (use_libdialog) {
status_printf("");
dprompt_libprint(pprompt, aprompt, 0);
} else {
dprompt_sprint(init_prompt, pprompt, aprompt);
dialog_out = dialog_spawn_gauge(init_prompt, &pid);
dprompt_dprint(dialog_out, pprompt, aprompt, 0);
}
} /* !debug */
/* Seed the random(3) generator */
if (dialog_test)
srandom(0xf1eeface);
/* Set default/custom status line format */
if (dpv_nfiles > 1) {
snprintf(status_format_default, DPV_STATUS_FORMAT_MAX, "%s",
DPV_STATUS_MANY);
status_format_custom = config->status_many;
} else {
snprintf(status_format_default, DPV_STATUS_FORMAT_MAX, "%s",
DPV_STATUS_SOLO);
status_format_custom = config->status_solo;
}
/* Add test mode identifier to default status line if enabled */
if (dialog_test && (strlen(status_format_default) + 12) <
DPV_STATUS_FORMAT_MAX)
strcat(status_format_default, " [TEST MODE]");
/* Verify custom status format */
status_fmt = fmtcheck(status_format_custom, status_format_default);
if (status_format_custom != NULL &&
status_fmt == status_format_default) {
warnx("WARNING! Invalid status_format configuration `%s'",
status_format_custom);
warnx("Default status_format `%s'", status_format_default);
}
/* Record when we started (used to prevent updating too quickly) */
(void)gettimeofday(&start, (struct timezone *)NULL);
/* Calculate number of microseconds in-between sub-second updates */
if (status_updates_per_second != 0)
status_update_usec = 1000000 / status_updates_per_second;
if (dialog_updates_per_second != 0)
dialog_update_usec = 1000000 / dialog_updates_per_second;
/*
* Process the file list [serially] (one for each argument passed)
*/
files_left = dpv_nfiles;
list_head = file_list;
for (curfile = file_list; curfile != NULL; curfile = curfile->next) {
keep_going = TRUE;
output_out = -1;
pct = 0;
nthfile++;
files_left--;
if (dpv_interrupt)
break;
if (dialog_test)
pct = 0 - increment;
/* Attempt to spawn output program for this file */
if (!dialog_test && output != NULL) {
mask = umask(0022);
(void)umask(mask);
switch (output_type) {
case DPV_OUTPUT_SHELL:
output_out = shell_spawn_pipecmd(output,
curfile->name, &output_pid);
break;
case DPV_OUTPUT_FILE:
path_fmt = fmtcheck(output, "%s");
if (path_fmt == output)
len = snprintf(pathbuf,
PATH_MAX, output, curfile->name);
else
len = snprintf(pathbuf,
PATH_MAX, "%s", output);
if (len >= PATH_MAX) {
warnx("%s:%d:%s: pathbuf[%u] too small"
"to hold output argument",
__FILE__, __LINE__, __func__,
PATH_MAX);
return (-1);
}
if ((output_out = open(pathbuf,
O_CREAT|O_WRONLY, DEFFILEMODE & ~mask))
< 0) {
warn("%s", pathbuf);
return (-1);
}
break;
default:
break;
}
}
while (!dpv_interrupt && keep_going) {
if (dialog_test) {
usleep(50000);
pct += increment;
dpv_overall_read +=
(int)(random() / 512 / dpv_nfiles);
/* 512 limits fake readout to Megabytes */
} else if (action != NULL)
pct = action(curfile, output_out);
if (no_overrun || dialog_test)
keep_going = (pct < 100);
else {
status = curfile->status;
keep_going = (status == DPV_STATUS_RUNNING);
}
/* Get current time and calculate seconds elapsed */
gettimeofday(&now, (struct timezone *)NULL);
now.tv_sec = now.tv_sec - start.tv_sec;
now.tv_usec = now.tv_usec - start.tv_usec;
if (now.tv_usec < 0)
now.tv_sec--, now.tv_usec += 1000000;
seconds = now.tv_sec + (now.tv_usec / 1000000.0);
/* Update dialog (be it dialog(3), dialog(1), etc.) */
if ((dialog_updates_per_second != 0 &&
(
seconds != dialog_old_seconds ||
now.tv_usec - dialog_last_update >=
dialog_update_usec ||
nthfile != dialog_old_nthfile
)) || pct == 100
) {
/* Calculate overall progress (rounding up) */
overall = (100 * nthfile - 100 + pct) /
dpv_nfiles;
if (((100 * nthfile - 100 + pct) * 10 /
dpv_nfiles % 100) > 50)
overall++;
dprompt_recreate(list_head, curfile, pct);
if (use_libdialog && !debug) {
/* Update dialog(3) widget */
dprompt_libprint(pprompt, aprompt,
overall);
} else {
/* stdout, dialog(1), or Xdialog(1) */
dprompt_dprint(dialog_out, pprompt,
aprompt, overall);
fsync(dialog_out);
}
dialog_old_seconds = seconds;
dialog_old_nthfile = nthfile;
dialog_last_update = now.tv_usec;
}
/* Update the status line */
if ((use_libdialog && !debug) &&
status_updates_per_second != 0 &&
(
keep_going != TRUE ||
seconds != status_old_seconds ||
now.tv_usec - status_last_update >=
status_update_usec ||
nthfile != status_old_nthfile
)
) {
status_printf(status_fmt, dpv_overall_read,
(dpv_overall_read / (seconds == 0 ? 1 :
seconds) * 1.0),
1, /* XXX until we add parallelism XXX */
files_left);
status_old_seconds = seconds;
status_old_nthfile = nthfile;
status_last_update = now.tv_usec;
}
}
if (!dialog_test && output_out >= 0) {
close(output_out);
waitpid(output_pid, (int *)NULL, 0);
}
if (dpv_abort)
break;
/* Advance head of list when we hit the max display lines */
if (display_limit > 0 && nthfile % display_limit == 0)
list_head = curfile->next;
}
if (!debug) {
if (use_libdialog)
end_dialog();
else {
close(dialog_out);
waitpid(pid, (int *)NULL, 0);
}
if (!dpv_interrupt)
printf("\n");
} else
warnx("%s: %lli lines read", __func__, dpv_overall_read);
if (dpv_interrupt || dpv_abort)
return (-1);
else
return (0);
}
/*
* Free allocated items initialized by dpv()
*/
void
dpv_free(void)
{
dialogrc_free();
dprompt_free();
dialog_maxsize_free();
if (aprompt != NULL) {
free(aprompt);
aprompt = NULL;
}
if (pprompt != NULL) {
free(pprompt);
pprompt = NULL;
}
status_free();
}

161
lib/libdpv/dpv.h Normal file
View File

@ -0,0 +1,161 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _DPV_H_
#define _DPV_H_
#include <sys/types.h>
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
/* Data to process */
extern long long dpv_overall_read;
/* Interrupt flag */
extern int dpv_interrupt; /* Set to TRUE in interrupt handler */
extern int dpv_abort; /* Set to true in callback to abort */
/*
* Display types for use with display_type member of dpv_config structure
*/
enum dpv_display {
DPV_DISPLAY_LIBDIALOG = 0, /* Display using dialog(3) (default) */
DPV_DISPLAY_STDOUT, /* Display on stdout */
DPV_DISPLAY_DIALOG, /* Display using spawned dialog(1) */
DPV_DISPLAY_XDIALOG, /* Display using spawned Xdialog(1) */
};
/*
* Output types for use with output_type member of dpv_config structure
*/
enum dpv_output {
DPV_OUTPUT_NONE = 0, /* No output (default) */
DPV_OUTPUT_FILE, /* Read `output' member as file path */
DPV_OUTPUT_SHELL, /* Read `output' member as shell cmd */
};
/*
* Activity types for use with status member of dpv_file_node structure.
* If you set a status other than DPV_STATUS_RUNNING on the current file in the
* action callback of dpv_config structure, you'll end callbacks for that
* dpv_file_node.
*/
enum dpv_status {
DPV_STATUS_RUNNING = 0, /* Running (default) */
DPV_STATUS_DONE, /* Completed */
DPV_STATUS_FAILED, /* Oops, something went wrong */
};
/*
* Anatomy of file option; pass an array of these as dpv() file_list argument
* terminated with a NULL pointer.
*/
struct dpv_file_node {
enum dpv_status status; /* status of read operation */
char *msg; /* display instead of "Done/Fail" */
char *name; /* name of file to read */
char *path; /* path to file */
long long length; /* expected size */
long long read; /* number units read (e.g., bytes) */
struct dpv_file_node *next; /* pointer to next (end with NULL) */
};
/*
* Anatomy of config option to pass as dpv() config argument
*/
struct dpv_config {
enum dpv_display display_type; /* Display (default TYPE_LIBDIALOG) */
enum dpv_output output_type; /* Output (default TYPE_NONE) */
int debug; /* Enable debugging output on stderr */
int display_limit; /* Files per `page'. Default -1 */
int label_size; /* Label size. Default 28 */
int pbar_size; /* Mini-progress size. See dpv(3) */
int dialog_updates_per_second; /* Progress updates/s. Default 16 */
int status_updates_per_second; /* dialog(3) status updates/second.
* Default 2 */
uint16_t options; /* Special options. Default 0 */
char *title; /* widget title */
char *backtitle; /* Widget backtitle */
char *aprompt; /* Prompt append. Default NULL */
char *pprompt; /* Prompt prefix. Default NULL */
char *msg_done; /* Progress text. Default `Done' */
char *msg_fail; /* Progress text. Default `Fail' */
char *msg_pending; /* Progress text. Default `Pending' */
char *output; /* Output format string; see dpv(3) */
const char *status_solo; /* dialog(3) solo-status format.
* Default DPV_STATUS_SOLO */
const char *status_many; /* dialog(3) many-status format.
* Default DPV_STATUS_MANY */
/*
* Function pointer; action to perform data transfer
*/
int (*action)(struct dpv_file_node *file, int out);
};
/*
* Macros for dpv() options bitmask argument
*/
#define DPV_TEST_MODE 0x0001 /* Test mode (fake reading data) */
#define DPV_WIDE_MODE 0x0002 /* prefix/append bump dialog width */
#define DPV_NO_LABELS 0x0004 /* Hide file_node.name labels */
#define DPV_USE_COLOR 0x0008 /* Override to force color output */
#define DPV_NO_OVERRUN 0x0010 /* Stop transfers when they hit 100% */
/*
* Limits (modify with extreme care)
*/
#define DPV_APROMPT_MAX 4096 /* Buffer size for `-a text' */
#define DPV_DISPLAY_LIMIT 10 /* Max file progress lines */
#define DPV_PPROMPT_MAX 4096 /* Buffer size for `-p text' */
#define DPV_STATUS_FORMAT_MAX 80 /* Buffer size for `-u format' */
/*
* Extra display information
*/
#define DPV_STATUS_SOLO "%'10lli bytes read @ %'9.1f bytes/sec."
#define DPV_STATUS_MANY (DPV_STATUS_SOLO " [%i/%i busy/wait]")
/*
* Strings
*/
#define DPV_DONE_DEFAULT "Done"
#define DPV_FAIL_DEFAULT "Fail"
#define DPV_PENDING_DEFAULT "Pending"
__BEGIN_DECLS
void dpv_free(void);
int dpv(struct dpv_config *_config, struct dpv_file_node *_file_list);
__END_DECLS
#endif /* !_DPV_H_ */

66
lib/libdpv/dpv_private.h Normal file
View File

@ -0,0 +1,66 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _DPV_PRIVATE_H_
#define _DPV_PRIVATE_H_
#include <sys/types.h>
/* Debugging */
extern uint8_t debug;
/* Data to process */
extern unsigned int dpv_nfiles;
/* Extra display information */
extern uint8_t no_labels;
extern uint8_t wide;
extern char *msg_done, *msg_fail, *msg_pending;
extern char *pprompt, *aprompt;
extern const char status_format[];
/* Defaults */
#define DIALOG_UPDATES_PER_SEC 16
#define XDIALOG_UPDATES_PER_SEC 4
#define DISPLAY_LIMIT_DEFAULT 0 /* Auto-calculate */
#define LABEL_SIZE_DEFAULT 28
#define PBAR_SIZE_DEFAULT 17
#define STATUS_UPDATES_PER_SEC 2
/* states for dprompt_add_files() of dprompt.c */
enum dprompt_state {
DPROMPT_NONE = 0, /* Default */
DPROMPT_PENDING, /* Pending */
DPROMPT_PBAR, /* Progress bar */
DPROMPT_END_STATE, /* Done/Fail */
DPROMPT_DETAILS, /* dpv_file_node->read */
DPROMPT_CUSTOM_MSG, /* dpv_file_node->msg */
DPROMPT_MINIMAL, /* whitespace */
};
#endif /* !_DPV_PRIVATE_H_ */

111
lib/libdpv/status.c Normal file
View File

@ -0,0 +1,111 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <curses.h>
#include <dialog.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include "dialog_util.h"
#include "status.h"
/* static globals */
static char *status_buf = NULL;
static int status_bufsize = -1;
static int status_row;
static int status_width;
/*
* Print a `one-liner' status message at the bottom of the screen. Messages are
* trimmed to fit within the console length (ANSI coloring not accounted for).
*/
void
status_printf(const char *fmt, ...)
{
int n, attrs;
chtype color = dlg_color_pair(dlg_color_table[BUTTON_ACTIVE_ATTR].fg,
dlg_color_table[SCREEN_ATTR].bg) | A_BOLD;
va_list args;
status_row = tty_maxrows() - 1;
status_width = tty_maxcols();
/* NULL is a special convention meaning "erase the old stuff" */
if (fmt == NULL) {
move(status_row, 0);
clrtoeol();
return;
}
/* Resize buffer if terminal width is greater */
if ((status_width + 1) > status_bufsize) {
status_buf = realloc(status_buf, status_width + 1);
if (status_buf == NULL) {
status_bufsize = -1;
return;
}
status_bufsize = status_width + 1;
}
/* Print the message within a space-filled buffer */
memset(status_buf, ' ', status_width);
va_start(args, fmt);
n = vsnprintf(status_buf, status_width + 1, fmt, args);
va_end(args);
/* If vsnprintf(3) produced less bytes than the maximum, change the
* implicitly-added NUL-terminator into a space and terminate at max */
if (n < status_width) {
status_buf[n] = ' ';
status_buf[status_width] = '\0';
}
/* Print text in screen bg, button active fg, and bold */
attrs = getattrs(stdscr);
attrset(color);
mvaddstr(status_row, 0, status_buf);
attrset(attrs);
/* Seat the cursor over the last character at absolute lower-right */
move(status_row, status_width - 1);
refresh();
}
/*
* Free allocated items initialized by status_printf()
*/
void
status_free(void)
{
if (status_buf != NULL) {
free(status_buf);
status_buf = NULL;
}
}

43
lib/libdpv/status.h Normal file
View File

@ -0,0 +1,43 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _STATUS_H_
#define _STATUS_H_
#include <sys/cdefs.h>
/* dialog(3) dlg_color_table[] attributes */
#define SCREEN_ATTR 0 /* entry used for status line bg */
#define BUTTON_ACTIVE_ATTR 5 /* entry used for status line fg */
__BEGIN_DECLS
void status_free(void);
void status_printf(const char *_format, ...);
__END_DECLS
#endif /* !_STATUS_H_ */

107
lib/libdpv/util.c Normal file
View File

@ -0,0 +1,107 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <err.h>
#include <limits.h>
#include <spawn.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "util.h"
extern char **environ;
static char cmdbuf[CMDBUFMAX] = "";
static char shellcmd[PATH_MAX] = PATH_SHELL;
static char *shellcmd_argv[6] = {
shellcmd,
__DECONST(char *, "-c"),
cmdbuf,
__DECONST(char *, "--"),
shellcmd,
NULL,
};
/*
* Spawn a sh(1) command. Writes the resulting process ID to the pid_t pointed
* at by `pid'. Returns a file descriptor (int) suitable for writing data to
* the spawned command (data written to file descriptor is seen as standard-in
* by the spawned sh(1) command). Returns `-1' if unable to spawn command.
*
* If cmd contains a single "%s" sequence, replace it with label if non-NULL.
*/
int
shell_spawn_pipecmd(const char *cmd, const char *label, pid_t *pid)
{
int error;
int len;
posix_spawn_file_actions_t action;
#if SHELL_SPAWN_DEBUG
unsigned int i;
#endif
int stdin_pipe[2] = { -1, -1 };
/* Populate argument array */
if (label != NULL && fmtcheck(cmd, "%s") == cmd)
len = snprintf(cmdbuf, CMDBUFMAX, cmd, label);
else
len = snprintf(cmdbuf, CMDBUFMAX, "%s", cmd);
if (len >= CMDBUFMAX) {
warnx("%s:%d:%s: cmdbuf[%u] too small to hold cmd argument",
__FILE__, __LINE__, __func__, CMDBUFMAX);
return (-1);
}
/* Open a pipe to communicate with [X]dialog(1) */
if (pipe(stdin_pipe) < 0)
err(EXIT_FAILURE, "%s: pipe(2)", __func__);
/* Fork sh(1) process */
#if SHELL_SPAWN_DEBUG
fprintf(stderr, "%s: spawning `", __func__);
for (i = 0; shellcmd_argv[i] != NULL; i++) {
if (i == 0)
fprintf(stderr, "%s", shellcmd_argv[i]);
else if (i == 2)
fprintf(stderr, " '%s'", shellcmd_argv[i]);
else
fprintf(stderr, " %s", shellcmd_argv[i]);
}
fprintf(stderr, "'\n");
#endif
posix_spawn_file_actions_init(&action);
posix_spawn_file_actions_adddup2(&action, stdin_pipe[0], STDIN_FILENO);
posix_spawn_file_actions_addclose(&action, stdin_pipe[1]);
error = posix_spawnp(pid, shellcmd, &action,
(const posix_spawnattr_t *)NULL, shellcmd_argv, environ);
if (error != 0)
err(EXIT_FAILURE, "%s: posix_spawnp(3)", __func__);
return stdin_pipe[1];
}

50
lib/libdpv/util.h Normal file
View File

@ -0,0 +1,50 @@
/*-
* Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _UTIL_H_
#define _UTIL_H_
#include <sys/types.h>
#include <paths.h>
#define SHELL_SPAWN_DEBUG 0 /* Debug spawning of sh(1) commands */
#ifdef _PATH_BSHELL
#define PATH_SHELL _PATH_BSHELL
#else
#define PATH_SHELL "/bin/sh"
#endif
#define CMDBUFMAX 4096
__BEGIN_DECLS
int shell_spawn_pipecmd(const char *_cmd, const char *_label, pid_t *_pid);
__END_DECLS
#endif /* !_UTIL_H_ */

21
lib/libfigpar/Makefile Normal file
View File

@ -0,0 +1,21 @@
# $FreeBSD$
LIB= figpar
SHLIB_MAJOR= 0
INCS= figpar.h string_m.h
MAN= figpar.3
MLINKS= figpar.3 get_config_option.3 \
figpar.3 parse_config.3 \
figpar.3 replaceall.3 \
figpar.3 strcount.3 \
figpar.3 strexpand.3 \
figpar.3 strexpandnl.3 \
figpar.3 strtolower.3
CFLAGS+= -I${.CURDIR}
SRCS= figpar.c string_m.c
WARNS?= 6
.include <bsd.lib.mk>

251
lib/libfigpar/figpar.3 Normal file
View File

@ -0,0 +1,251 @@
.\" Copyright (c) 2013-2014 Devin Teske <dteske@FreeBSD.org>
.\" All rights reserved.
.\"
.\" 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.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
.\"
.\" $FreeBSD$
.\"
.Dd Oct 24, 2014
.Dt FIGPAR 3
.Os
.Sh NAME
.Nm figpar ,
.Nm parse_config ,
.Nm get_config_option
.Nd configuration file parsing library
.Sh LIBRARY
.Lb libfigpar
.Sh SYNOPSIS
.In figpar.h
.Ft int
.Fo parse_config
.Fa "struct fp_config options[], const char *path"
.Fa "int \*[lp]*unknown\*[rp]\*[lp]struct fp_config *option, uint32_t line"
.Fa "char *directive, char *value\*[rp], uint8_t processing_options"
.Fc
.Ft "struct fp_config *"
.Fo get_config_option
.Fa "struct fp_config options[], const char *directive"
.Fc
.In string_m.h
.Ft int
.Fo replaceall
.Fa "char *source, const char *find, const char *replace"
.Fc
.Ft unsigned int
.Fo strcount
.Fa "const char *source, const char *find"
.Fc
.Ft void
.Fo strexpand
.Fa "char *source"
.Fc
.Ft void
.Fo strexpandnl
.Fa "char *source"
.Fc
.Ft void
.Fo strtolower
.Fa "char *source"
.Fc
.Sh DESCRIPTION
The
.Nm
library provides a light-weight, portable framework for parsing configuration
files.
The library uses
.Xr open 2 ,
.Xr read 2 ,
and
.Xr lseek 2
within the file pointed to by
.Fa path
to find directives and values which are then made available to the application.
.Pp
Due to the fact that configuration files may have basic syntax differences,
the library does not attempt to impose any structure on the data but instead
provides raw data to a set of callback functions.
These callback functions can in-turn initiate abort through their return value,
allowing custom syntax validation during parsing.
.Pp
Configuration directives, types, and callback functions are provided through
data structures defined in
.In figpar.h :
.Bd -literal -offset indent
struct fp_config {
enum fp_cfgtype type; /* value type */
const char *directive; /* keyword */
union fp_cfgvalue value; /* value */
/* Pointer to function used when directive is found */
int (*action)(struct fp_config *option, uint32_t line,
char *directive, char *value);
};
enum fp_cfgtype {
FP_TYPE_NONE = 0x0000, /* for directives with no value */
FP_TYPE_BOOL = 0x0001, /* boolean */
FP_TYPE_INT = 0x0002, /* signed 32 bit integer */
FP_TYPE_UINT = 0x0004, /* unsigned 32 bit integer */
FP_TYPE_STR = 0x0008, /* string pointer */
FP_TYPE_STRARRAY = 0x0010, /* string array pointer */
FP_TYPE_DATA1 = 0x0020, /* void data type-1 (whatever) */
FP_TYPE_DATA2 = 0x0040, /* void data type-2 (whatever) */
FP_TYPE_DATA3 = 0x0080, /* void data type-3 (whatever) */
FP_TYPE_RESERVED1 = 0x0100, /* reserved data type-1 (future) */
FP_TYPE_RESERVED2 = 0x0200, /* reserved data type-2 (future) */
FP_TYPE_RESERVED3 = 0x0400, /* reserved data type-3 (future) */
};
union fp_cfgvalue {
void *data; /* Pointer to NUL-terminated string */
char *str; /* Pointer to NUL-terminated string */
char **strarray; /* Pointer to an array of strings */
int32_t num; /* Signed 32-bit integer value */
uint32_t u_num; /* Unsigned 32-bit integer value */
uint32_t boolean:1; /* Boolean integer value (0 or 1) */
};
.Ed
.Pp
The
.Fa processing_options
argument to
.Fn parse_config
is a mask of bit fields which indicate various
processing options.
The possible flags are as follows:
.Bl -tag -width FP_BREAK_ON_SEMICOLON
.It Dv FP_BREAK_ON_EQUALS
An equals sign
.Pq Ql Li =
is normally considered part of the directive.
This flag enables terminating the directive at the equals sign.
Also makes equals sign optional and transient.
.It Dv FP_BREAK_ON_SEMICOLON
A semicolon
.Pq Ql Li \;
is normally considered part of the value.
This flag enables terminating the value at the semicolon.
Also allows multiple statements on a single line separated by semicolon.
.It Dv FP_CASE_SENSITIVE
Normally directives are matched case insensitively using
.Xr fnmatch 3 .
This flag enables directive matching to be case sensitive.
.It Dv FP_REQUIRE_EQUALS
If a directive is not followed by an equals, processing is aborted.
.It Dv FP_STRICT_EQUALS
Equals must be part of the directive to be considered a delimiter between
directive and value.
.El
.Pp
The
.Fa options
struct array pointer can be NULL and every directive will invoke the
.Fn unknown
function argument.
.Pp
The directive for each fp_config item in the
.Fn parse_config
options argument is matched against each parsed directive using
.Xr fnmatch 3
until a match is found.
If a match is found, the
.Fn action
function for that fp_config directive is invoked with the line number,
directive, and value.
Otherwise if no match, the
.Fn unknown
function is invoked
.Pq with the same arguments .
.Pp
If either
.Fa action
or
.Fa unknown
return non-zero,
.Fn parse_config
aborts reading the file and returns the error value to its caller.
.Pp
.Fn get_config_option
traverses the options-array and returns the option that matches via
.Xr strcmp 3 ,
or if no match a pointer to a static dummy struct is returned
.Pq whose values are all zero or NULL .
.Pp
The use of
.Fa "struct fp_config"
is entirely optional as-is the use of
.Fa "enum fp_cfgtype"
or
.Fa "union fp_cfgvalue" .
For example, you could choose to pass a NULL pointer to
.Fn parse_config
for the first argument and then provide a simple
.Fa unknown
function based on
.Xr queue 3
that populates a singly-linked list of your own struct containing the
.Fa directive
and
.Fa value .
.Pp
In addition, the following miscellaneous string manipulation routines are
provided by
.In string_m.h :
.Bl -tag -width strexpandnl()
.It Fn replaceall
Replace all occurrences of
.Fa find
in
.Fa source
with
.Fa replace .
.It Fn strcount
Count the number of occurrences of one string that appear in the
.Fa source
string.
Return value is the total count.
An example use would be if you need to know how large a block of memory needs
to be for a
.Fn replaceall
series.
.It Fn strexpand
Expand escape sequences in a buffer pointed to by
.Fa source .
.It Fn strexpandnl
Expand only the escaped newlines in a buffer pointed to by
.Fa source .
.It Fn strtolower
Convert a string to lower case.
.El
.Sh SEE ALSO
.Xr queue 3
.Sh HISTORY
The
.Nm
library first appeared in
.Fx 11.0 .
.Sh AUTHORS
.An Devin Teske Aq dteske@FreeBSD.org
.Sh BUGS
This is the first implementation of the library,
and the interface may be subject to refinement.

469
lib/libfigpar/figpar.c Normal file
View File

@ -0,0 +1,469 @@
/*-
* Copyright (c) 2002-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "figpar.h"
#include "string_m.h"
struct fp_config fp_dummy_config = {0, NULL, {0}, NULL};
/*
* Search for config option (struct fp_config) in the array of config options,
* returning the struct whose directive matches the given parameter. If no
* match is found, a pointer to the static dummy array (above) is returned.
*
* This is to eliminate dependency on the index position of an item in the
* array, since the index position is more apt to be changed as code grows.
*/
struct fp_config *
get_config_option(struct fp_config options[], const char *directive)
{
uint32_t n;
/* Check arguments */
if (options == NULL || directive == NULL)
return (&fp_dummy_config);
/* Loop through the array, return the index of the first match */
for (n = 0; options[n].directive != NULL; n++)
if (strcmp(options[n].directive, directive) == 0)
return (&(options[n]));
/* Re-initialize the dummy variable in case it was written to */
fp_dummy_config.directive = NULL;
fp_dummy_config.type = 0;
fp_dummy_config.action = NULL;
fp_dummy_config.value.u_num = 0;
return (&fp_dummy_config);
}
/*
* Parse the configuration file at `path' and execute the `action' call-back
* functions for any directives defined by the array of config options (first
* argument).
*
* For unknown directives that are encountered, you can optionally pass a
* call-back function for the third argument to be called for unknowns.
*
* Returns zero on success; otherwise returns -1 and errno should be consulted.
*/
int
parse_config(struct fp_config options[], const char *path,
int (*unknown)(struct fp_config *option, uint32_t line, char *directive,
char *value), uint16_t processing_options)
{
uint8_t bequals;
uint8_t bsemicolon;
uint8_t case_sensitive;
uint8_t comment = 0;
uint8_t end;
uint8_t found;
uint8_t have_equals = 0;
uint8_t quote;
uint8_t require_equals;
uint8_t strict_equals;
char p[2];
char *directive;
char *t;
char *value;
int error;
int fd;
ssize_t r = 1;
uint32_t dsize;
uint32_t line = 1;
uint32_t n;
uint32_t vsize;
uint32_t x;
off_t charpos;
off_t curpos;
char rpath[PATH_MAX];
/* Sanity check: if no options and no unknown function, return */
if (options == NULL && unknown == NULL)
return (-1);
/* Processing options */
bequals = (processing_options & FP_BREAK_ON_EQUALS) == 0 ? 0 : 1;
bsemicolon = (processing_options & FP_BREAK_ON_SEMICOLON) == 0 ? 0 : 1;
case_sensitive = (processing_options & FP_CASE_SENSITIVE) == 0 ? 0 : 1;
require_equals = (processing_options & FP_REQUIRE_EQUALS) == 0 ? 0 : 1;
strict_equals = (processing_options & FP_STRICT_EQUALS) == 0 ? 0 : 1;
/* Initialize strings */
directive = value = 0;
vsize = dsize = 0;
/* Resolve the file path */
if (realpath(path, rpath) == 0)
return (-1);
/* Open the file */
if ((fd = open(rpath, O_RDONLY)) < 0)
return (-1);
/* Read the file until EOF */
while (r != 0) {
r = read(fd, p, 1);
/* skip to the beginning of a directive */
while (r != 0 && (isspace(*p) || *p == '#' || comment ||
(bsemicolon && *p == ';'))) {
if (*p == '#')
comment = 1;
else if (*p == '\n') {
comment = 0;
line++;
}
r = read(fd, p, 1);
}
/* Test for EOF; if EOF then no directive was found */
if (r == 0) {
close(fd);
return (0);
}
/* Get the current offset */
curpos = lseek(fd, 0, SEEK_CUR) - 1;
if (curpos == -1) {
close(fd);
return (-1);
}
/* Find the length of the directive */
for (n = 0; r != 0; n++) {
if (isspace(*p))
break;
if (bequals && *p == '=') {
have_equals = 1;
break;
}
if (bsemicolon && *p == ';')
break;
r = read(fd, p, 1);
}
/* Test for EOF, if EOF then no directive was found */
if (n == 0 && r == 0) {
close(fd);
return (0);
}
/* Go back to the beginning of the directive */
error = (int)lseek(fd, curpos, SEEK_SET);
if (error == (curpos - 1)) {
close(fd);
return (-1);
}
/* Allocate and read the directive into memory */
if (n > dsize) {
if ((directive = realloc(directive, n + 1)) == NULL) {
close(fd);
return (-1);
}
dsize = n;
}
r = read(fd, directive, n);
/* Advance beyond the equals sign if appropriate/desired */
if (bequals && *p == '=') {
if (lseek(fd, 1, SEEK_CUR) != -1)
r = read(fd, p, 1);
if (strict_equals && isspace(*p))
*p = '\n';
}
/* Terminate the string */
directive[n] = '\0';
/* Convert directive to lower case before comparison */
if (!case_sensitive)
strtolower(directive);
/* Move to what may be the start of the value */
if (!(bsemicolon && *p == ';') &&
!(strict_equals && *p == '=')) {
while (r != 0 && isspace(*p) && *p != '\n')
r = read(fd, p, 1);
}
/* An equals sign may have stopped us, should we eat it? */
if (r != 0 && bequals && *p == '=' && !strict_equals) {
have_equals = 1;
r = read(fd, p, 1);
while (r != 0 && isspace(*p) && *p != '\n')
r = read(fd, p, 1);
}
/* If no value, allocate a dummy value and jump to action */
if (r == 0 || *p == '\n' || *p == '#' ||
(bsemicolon && *p == ';')) {
/* Initialize the value if not already done */
if (value == NULL && (value = malloc(1)) == NULL) {
close(fd);
return (-1);
}
value[0] = '\0';
goto call_function;
}
/* Get the current offset */
curpos = lseek(fd, 0, SEEK_CUR) - 1;
if (curpos == -1) {
close(fd);
return (-1);
}
/* Find the end of the value */
quote = 0;
end = 0;
while (r != 0 && end == 0) {
/* Advance to the next character if we know we can */
if (*p != '\"' && *p != '#' && *p != '\n' &&
(!bsemicolon || *p != ';')) {
r = read(fd, p, 1);
continue;
}
/*
* If we get this far, we've hit an end-key
*/
/* Get the current offset */
charpos = lseek(fd, 0, SEEK_CUR) - 1;
if (charpos == -1) {
close(fd);
return (-1);
}
/*
* Go back so we can read the character before the key
* to check if the character is escaped (which means we
* should continue).
*/
error = (int)lseek(fd, -2, SEEK_CUR);
if (error == -3) {
close(fd);
return (-1);
}
r = read(fd, p, 1);
/*
* Count how many backslashes there are (an odd number
* means the key is escaped, even means otherwise).
*/
for (n = 1; *p == '\\'; n++) {
/* Move back another offset to read */
error = (int)lseek(fd, -2, SEEK_CUR);
if (error == -3) {
close(fd);
return (-1);
}
r = read(fd, p, 1);
}
/* Move offset back to the key and read it */
error = (int)lseek(fd, charpos, SEEK_SET);
if (error == (charpos - 1)) {
close(fd);
return (-1);
}
r = read(fd, p, 1);
/*
* If an even number of backslashes was counted meaning
* key is not escaped, we should evaluate what to do.
*/
if ((n & 1) == 1) {
switch (*p) {
case '\"':
/*
* Flag current sequence of characters
* to follow as being quoted (hashes
* are not considered comments).
*/
quote = !quote;
break;
case '#':
/*
* If we aren't in a quoted series, we
* just hit an inline comment and have
* found the end of the value.
*/
if (!quote)
end = 1;
break;
case '\n':
/*
* Newline characters must always be
* escaped, whether inside a quoted
* series or not, otherwise they
* terminate the value.
*/
end = 1;
case ';':
if (!quote && bsemicolon)
end = 1;
break;
}
} else if (*p == '\n')
/* Escaped newline character. increment */
line++;
/* Advance to the next character */
r = read(fd, p, 1);
}
/* Get the current offset */
charpos = lseek(fd, 0, SEEK_CUR) - 1;
if (charpos == -1) {
close(fd);
return (-1);
}
/* Get the length of the value */
n = (uint32_t)(charpos - curpos);
if (r != 0) /* more to read, but don't read ending key */
n--;
/* Move offset back to the beginning of the value */
error = (int)lseek(fd, curpos, SEEK_SET);
if (error == (curpos - 1)) {
close(fd);
return (-1);
}
/* Allocate and read the value into memory */
if (n > vsize) {
if ((value = realloc(value, n + 1)) == NULL) {
close(fd);
return (-1);
}
vsize = n;
}
r = read(fd, value, n);
/* Terminate the string */
value[n] = '\0';
/* Cut trailing whitespace off by termination */
t = value + n;
while (isspace(*--t))
*t = '\0';
/* Escape the escaped quotes (replaceall is in string_m.c) */
x = strcount(value, "\\\""); /* in string_m.c */
if (x != 0 && (n + x) > vsize) {
if ((value = realloc(value, n + x + 1)) == NULL) {
close(fd);
return (-1);
}
vsize = n + x;
}
if (replaceall(value, "\\\"", "\\\\\"") < 0) {
/* Replace operation failed for some unknown reason */
close(fd);
return (-1);
}
/* Remove all new line characters */
if (replaceall(value, "\\\n", "") < 0) {
/* Replace operation failed for some unknown reason */
close(fd);
return (-1);
}
/* Resolve escape sequences */
strexpand(value); /* in string_m.c */
call_function:
/* Abort if we're seeking only assignments */
if (require_equals && !have_equals)
return (-1);
found = have_equals = 0; /* reset */
/* If there are no options defined, call unknown and loop */
if (options == NULL && unknown != NULL) {
error = unknown(NULL, line, directive, value);
if (error != 0) {
close(fd);
return (error);
}
continue;
}
/* Loop through the array looking for a match for the value */
for (n = 0; options[n].directive != NULL; n++) {
error = fnmatch(options[n].directive, directive,
FNM_NOESCAPE);
if (error == 0) {
found = 1;
/* Call function for array index item */
if (options[n].action != NULL) {
error = options[n].action(
&options[n],
line, directive, value);
if (error != 0) {
close(fd);
return (error);
}
}
} else if (error != FNM_NOMATCH) {
/* An error has occurred */
close(fd);
return (-1);
}
}
if (!found && unknown != NULL) {
/*
* No match was found for the value we read from the
* file; call function designated for unknown values.
*/
error = unknown(NULL, line, directive, value);
if (error != 0) {
close(fd);
return (error);
}
}
}
close(fd);
return (0);
}

99
lib/libfigpar/figpar.h Normal file
View File

@ -0,0 +1,99 @@
/*-
* Copyright (c) 2002-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _FIGPAR_H_
#define _FIGPAR_H_
#include <sys/types.h>
/*
* Union for storing various types of data in a single common container.
*/
union fp_cfgvalue {
void *data; /* Pointer to NUL-terminated string */
char *str; /* Pointer to NUL-terminated string */
char **strarray; /* Pointer to an array of strings */
int32_t num; /* Signed 32-bit integer value */
uint32_t u_num; /* Unsigned 32-bit integer value */
uint32_t boolean:1; /* Boolean integer value (0 or 1) */
};
/*
* Option types (based on above cfgvalue union)
*/
enum fp_cfgtype {
FP_TYPE_NONE = 0x0000, /* for directives with no value */
FP_TYPE_BOOL = 0x0001, /* boolean */
FP_TYPE_INT = 0x0002, /* signed 32 bit integer */
FP_TYPE_UINT = 0x0004, /* unsigned 32 bit integer */
FP_TYPE_STR = 0x0008, /* string pointer */
FP_TYPE_STRARRAY = 0x0010, /* string array pointer */
FP_TYPE_DATA1 = 0x0020, /* void data type-1 (whatever) */
FP_TYPE_DATA2 = 0x0040, /* void data type-2 (whatever) */
FP_TYPE_DATA3 = 0x0080, /* void data type-3 (whatever) */
FP_TYPE_RESERVED1 = 0x0100, /* reserved data type-1 (future) */
FP_TYPE_RESERVED2 = 0x0200, /* reserved data type-2 (future) */
FP_TYPE_RESERVED3 = 0x0400, /* reserved data type-3 (future) */
};
/*
* Options to parse_config() for processing_options bitmask
*/
#define FP_BREAK_ON_EQUALS 0x0001 /* stop reading directive at `=' */
#define FP_BREAK_ON_SEMICOLON 0x0002 /* `;' starts a new line */
#define FP_CASE_SENSITIVE 0x0004 /* directives are case sensitive */
#define FP_REQUIRE_EQUALS 0x0008 /* assignment directives only */
#define FP_STRICT_EQUALS 0x0010 /* `=' must be part of directive */
/*
* Anatomy of a config file option
*/
struct fp_config {
enum fp_cfgtype type; /* Option value type */
const char *directive; /* config file keyword */
union fp_cfgvalue value; /* NB: set by action */
/*
* Function pointer; action to be taken when the directive is found
*/
int (*action)(struct fp_config *option, uint32_t line, char *directive,
char *value);
};
extern struct fp_config fp_dummy_config;
__BEGIN_DECLS
int parse_config(struct fp_config _options[],
const char *_path,
int (*_unknown)(struct fp_config *_option,
uint32_t _line, char *_directive, char *_value),
uint16_t _processing_options);
struct fp_config *get_config_option(struct fp_config _options[],
const char *_directive);
__END_DECLS
#endif /* _FIGPAR_H_ */

309
lib/libfigpar/string_m.c Normal file
View File

@ -0,0 +1,309 @@
/*-
* Copyright (c) 2001-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/types.h>
#include <ctype.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "string_m.h"
/*
* Counts the number of occurrences of one string that appear in the source
* string. Return value is the total count.
*
* An example use would be if you need to know how large a block of memory
* needs to be for a replaceall() series.
*/
unsigned int
strcount(const char *source, const char *find)
{
const char *p = source;
size_t flen;
unsigned int n = 0;
/* Both parameters are required */
if (source == NULL || find == NULL)
return (0);
/* Cache the length of find element */
flen = strlen(find);
if (strlen(source) == 0 || flen == 0)
return (0);
/* Loop until the end of the string */
while (*p != '\0') {
if (strncmp(p, find, flen) == 0) { /* found an instance */
p += flen;
n++;
} else
p++;
}
return (n);
}
/*
* Replaces all occurrences of `find' in `source' with `replace'.
*
* You should not pass a string constant as the first parameter, it needs to be
* a pointer to an allocated block of memory. The block of memory that source
* points to should be large enough to hold the result. If the length of the
* replacement string is greater than the length of the find string, the result
* will be larger than the original source string. To allocate enough space for
* the result, use the function strcount() declared above to determine the
* number of occurrences and how much larger the block size needs to be.
*
* If source is not large enough, the application will crash. The return value
* is the length (in bytes) of the result.
*
* When an error occurs, -1 is returned and the global variable errno is set
* accordingly. Returns zero on success.
*/
int
replaceall(char *source, const char *find, const char *replace)
{
char *p;
char *t;
char *temp;
size_t flen;
size_t rlen;
size_t slen;
uint32_t n = 0;
errno = 0; /* reset global error number */
/* Check that we have non-null parameters */
if (source == NULL)
return (0);
if (find == NULL)
return (strlen(source));
/* Cache the length of the strings */
slen = strlen(source);
flen = strlen(find);
rlen = replace ? strlen(replace) : 0;
/* Cases where no replacements need to be made */
if (slen == 0 || flen == 0 || slen < flen)
return (slen);
/* If replace is longer than find, we'll need to create a temp copy */
if (rlen > flen) {
temp = malloc(slen + 1);
if (errno != 0) /* could not allocate memory */
return (-1);
strcpy(temp, source);
} else
temp = source;
/* Reconstruct the string with the replacements */
p = source; t = temp; /* position elements */
while (*t != '\0') {
if (strncmp(t, find, flen) == 0) {
/* found an occurrence */
for (n = 0; replace && replace[n]; n++)
*p++ = replace[n];
t += flen;
} else
*p++ = *t++; /* copy character and increment */
}
/* Terminate the string */
*p = '\0';
/* Free the temporary allocated memory */
if (temp != source)
free(temp);
/* Return the length of the completed string */
return (strlen(source));
}
/*
* Expands escape sequences in a buffer pointed to by `source'. This function
* steps through each character, and converts escape sequences such as "\n",
* "\r", "\t" and others into their respective meanings.
*
* You should not pass a string constant or literal to this function or the
* program will likely segmentation fault when it tries to modify the data.
*
* The string length will either shorten or stay the same depending on whether
* any escape sequences were converted but the amount of memory allocated does
* not change.
*
* Interpreted sequences are:
*
* \0NNN character with octal value NNN (0 to 3 digits)
* \N character with octal value N (0 thru 7)
* \a alert (BEL)
* \b backslash
* \f form feed
* \n new line
* \r carriage return
* \t horizontal tab
* \v vertical tab
* \xNN byte with hexadecimal value NN (1 to 2 digits)
*
* All other sequences are unescaped (ie. '\"' and '\#').
*/
void strexpand(char *source)
{
uint8_t c;
char *chr;
char *pos;
char d[4];
/* Initialize position elements */
pos = chr = source;
/* Loop until we hit the end of the string */
while (*pos != '\0') {
if (*chr != '\\') {
*pos = *chr; /* copy character to current offset */
pos++;
chr++;
continue;
}
/* Replace the backslash with the correct character */
switch (*++chr) {
case 'a': *pos = '\a'; break; /* bell/alert (BEL) */
case 'b': *pos = '\b'; break; /* backspace */
case 'f': *pos = '\f'; break; /* form feed */
case 'n': *pos = '\n'; break; /* new line */
case 'r': *pos = '\r'; break; /* carriage return */
case 't': *pos = '\t'; break; /* horizontal tab */
case 'v': *pos = '\v'; break; /* vertical tab */
case 'x': /* hex value (1 to 2 digits)(\xNN) */
d[2] = '\0'; /* pre-terminate the string */
/* verify next two characters are hex */
d[0] = isxdigit(*(chr+1)) ? *++chr : '\0';
if (d[0] != '\0')
d[1] = isxdigit(*(chr+1)) ? *++chr : '\0';
/* convert the characters to decimal */
c = (uint8_t)strtoul(d, 0, 16);
/* assign the converted value */
*pos = (c != 0 || d[0] == '0') ? c : *++chr;
break;
case '0': /* octal value (0 to 3 digits)(\0NNN) */
d[3] = '\0'; /* pre-terminate the string */
/* verify next three characters are octal */
d[0] = (isdigit(*(chr+1)) && *(chr+1) < '8') ?
*++chr : '\0';
if (d[0] != '\0')
d[1] = (isdigit(*(chr+1)) && *(chr+1) < '8') ?
*++chr : '\0';
if (d[1] != '\0')
d[2] = (isdigit(*(chr+1)) && *(chr+1) < '8') ?
*++chr : '\0';
/* convert the characters to decimal */
c = (uint8_t)strtoul(d, 0, 8);
/* assign the converted value */
*pos = c;
break;
default: /* single octal (\0..7) or unknown sequence */
if (isdigit(*chr) && *chr < '8') {
d[0] = *chr;
d[1] = '\0';
*pos = (uint8_t)strtoul(d, 0, 8);
} else
*pos = *chr;
}
/* Increment to next offset, possible next escape sequence */
pos++;
chr++;
}
}
/*
* Expand only the escaped newlines in a buffer pointed to by `source'. This
* function steps through each character, and converts the "\n" sequence into
* a literal newline and the "\\n" sequence into "\n".
*
* You should not pass a string constant or literal to this function or the
* program will likely segmentation fault when it tries to modify the data.
*
* The string length will either shorten or stay the same depending on whether
* any escaped newlines were converted but the amount of memory allocated does
* not change.
*/
void strexpandnl(char *source)
{
uint8_t backslash = 0;
char *cp1;
char *cp2;
/* Replace '\n' with literal in dprompt */
cp1 = cp2 = source;
while (*cp2 != '\0') {
*cp1 = *cp2;
if (*cp2 == '\\')
backslash++;
else if (*cp2 != 'n')
backslash = 0;
else if (backslash > 0) {
*(--cp1) = (backslash & 1) == 1 ? '\n' : 'n';
backslash = 0;
}
cp1++;
cp2++;
}
*cp1 = *cp2;
}
/*
* Convert a string to lower case. You should not pass a string constant to
* this function. Only pass pointers to allocated memory with null terminated
* string data.
*/
void
strtolower(char *source)
{
char *p = source;
if (source == NULL)
return;
while (*p != '\0') {
*p = tolower(*p);
p++; /* would have just used `*p++' but gcc 3.x warns */
}
}

43
lib/libfigpar/string_m.h Normal file
View File

@ -0,0 +1,43 @@
/*-
* Copyright (c) 2001-2014 Devin Teske <dteske@FreeBSD.org>
* All rights reserved.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
*
* $FreeBSD$
*/
#ifndef _STRING_M_H_
#define _STRING_M_H_
#include <sys/cdefs.h>
__BEGIN_DECLS
void strexpand(char *_source);
void strexpandnl(char *_source);
void strtolower(char *_source);
int replaceall(char *_source, const char *_find,
const char *_replace);
unsigned int strcount(const char *_source, const char *_find);
__END_DECLS
#endif /* !_STRING_M_H_ */

View File

@ -199,4 +199,8 @@ DPSRCS= openpam_static.c
INCS= ${HEADERS} ${ADD_HEADERS}
INCSDIR= ${INCLUDEDIR}/security
.if ${MK_TESTS} != "no"
SUBDIR+= tests
.endif
.include <bsd.lib.mk>

View File

@ -0,0 +1,19 @@
# $FreeBSD$
OPENPAM = ${.CURDIR}/../../../../contrib/openpam
.PATH: ${OPENPAM}/t
TESTSDIR = ${TESTSBASE}/lib/libpam
COMMONSRC = t_file.c t_main.c
.for test in t_openpam_ctype t_openpam_readlinev t_openpam_readword
TAP_TESTS_C += ${test}
SRCS.${test} = ${test}.c ${COMMONSRC}
.endfor
CFLAGS +=-I${OPENPAM}/include -I${OPENPAM}/lib/libpam -I${OPENPAM}/t
WARNS ?= 6
DPADD = ${LIBPAM}
LDADD = ${MINUSLPAM}
.include <bsd.test.mk>

View File

@ -52,7 +52,7 @@ CRUNCH_SRCDIRS+= bin
CRUNCH_PROGS_bin= cat chflags chio chmod cp date dd df echo \
ed expr getfacl hostname kenv kill ln ls mkdir mv \
pkill ps pwd realpath rm rmdir setfacl sh stty sync test
CRUNCH_LIBS+= -lcrypt -ledit -ljail -lkvm -ll -ltermcapw -lutil
CRUNCH_LIBS+= -lcrypt -ledit -ljail -lkvm -ll -ltermcapw -lutil -lxo
CRUNCH_BUILDTOOLS+= bin/sh
# Additional options for specific programs

View File

@ -4,7 +4,5 @@
PROG= fsirand
MAN= fsirand.8
WARNS?= 3
DPADD= ${LIBUTIL}
LDADD= -lutil
.include <bsd.prog.mk>

View File

@ -23,52 +23,50 @@
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/sockio.h>
#include <stdlib.h>
#include <unistd.h>
#include <net/ethernet.h>
#include <net/if.h>
#include <net/if_gre.h>
#include <net/route.h>
#include <ctype.h>
#include <limits.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <err.h>
#include <errno.h>
#include "ifconfig.h"
#define GREBITS "\020\01ENABLE_CSUM\02ENABLE_SEQ"
static void gre_status(int s);
static void
gre_status(int s)
{
int grekey = 0;
uint32_t opts = 0;
ifr.ifr_data = (caddr_t)&grekey;
ifr.ifr_data = (caddr_t)&opts;
if (ioctl(s, GREGKEY, &ifr) == 0)
if (grekey != 0)
printf("\tgrekey: %d\n", grekey);
if (opts != 0)
printf("\tgrekey: 0x%x (%u)\n", opts, opts);
opts = 0;
if (ioctl(s, GREGOPTS, &ifr) != 0 || opts == 0)
return;
printb("\toptions", opts, GREBITS);
putchar('\n');
}
static void
setifgrekey(const char *val, int dummy __unused, int s,
const struct afswtch *afp)
{
uint32_t grekey = atol(val);
uint32_t grekey = strtol(val, NULL, 0);
strncpy(ifr.ifr_name, name, sizeof (ifr.ifr_name));
ifr.ifr_data = (caddr_t)&grekey;
@ -76,8 +74,35 @@ setifgrekey(const char *val, int dummy __unused, int s,
warn("ioctl (set grekey)");
}
static void
setifgreopts(const char *val, int d, int s, const struct afswtch *afp)
{
uint32_t opts;
ifr.ifr_data = (caddr_t)&opts;
if (ioctl(s, GREGOPTS, &ifr) == -1) {
warn("ioctl(GREGOPTS)");
return;
}
if (d < 0)
opts &= ~(-d);
else
opts |= d;
if (ioctl(s, GRESOPTS, &ifr) == -1) {
warn("ioctl(GIFSOPTS)");
return;
}
}
static struct cmd gre_cmds[] = {
DEF_CMD_ARG("grekey", setifgrekey),
DEF_CMD("enable_csum", GRE_ENABLE_CSUM, setifgreopts),
DEF_CMD("-enable_csum",-GRE_ENABLE_CSUM,setifgreopts),
DEF_CMD("enable_seq", GRE_ENABLE_SEQ, setifgreopts),
DEF_CMD("-enable_seq",-GRE_ENABLE_SEQ, setifgreopts),
};
static struct afswtch af_gre = {
.af_name = "af_gre",

View File

@ -252,6 +252,7 @@ MAN= aac.4 \
malo.4 \
mcd.4 \
md.4 \
me.4 \
mem.4 \
meteor.4 \
mfi.4 \

View File

@ -29,7 +29,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd June 20, 2008
.Dd November 7, 2014
.Dt GRE 4
.Os
.Sh NAME
@ -68,162 +68,30 @@ and
.Cm destroy
subcommands.
.Pp
This driver currently supports the following modes of operation:
.Bl -tag -width indent
.It "GRE encapsulation (IP protocol number 47)"
Encapsulated datagrams are
prepended an outer datagram and a GRE header.
This driver corresponds to RFC 2784.
Encapsulated datagrams are prepended an outer datagram and a GRE header.
The GRE header specifies
the type of the encapsulated datagram and thus allows for tunneling other
protocols than IP.
GRE mode is also the default tunnel mode on Cisco routers.
This is also the default mode of operation of the
.Nm
interfaces.
As part of the GRE mode,
.Nm
also supports Cisco WCCP protocol, both version 1 and version 2.
Since there is no reliable way to distinguish between WCCP versions, it
should be configured manually using the
.Cm link2
flag.
If the
.Cm link2
flag is not set (default), then WCCP version 1 is selected.
.It "MOBILE encapsulation (IP protocol number 55)"
Datagrams are
encapsulated into IP, but with a shorter encapsulation.
The original
IP header is modified and the modifications are inserted between the
so modified header and the original payload.
Like
.Xr gif 4 ,
only for IP-in-IP encapsulation.
.El
.Pp
The
.Nm
interfaces support a number of
.Xr ioctl 2 Ns s ,
such as:
.Bl -tag -width ".Dv GRESADDRS"
.It Dv GRESADDRS
Set the IP address of the local tunnel end.
This is the source address
set by or displayed by
.Xr ifconfig 8
for the
.Nm
interface.
.It Dv GRESADDRD
Set the IP address of the remote tunnel end.
This is the destination address
set by or displayed by
.Xr ifconfig 8
for the
.Nm
interface.
.It Dv GREGADDRS
Query the IP address that is set for the local tunnel end.
This is the
address the encapsulation header carries as local address (i.e., the real
address of the tunnel start point).
.It Dv GREGADDRD
Query the IP address that is set for the remote tunnel end.
This is the
address the encapsulated packets are sent to (i.e., the real address of
the remote tunnel endpoint).
.It Dv GRESPROTO
Set the operation mode to the specified IP protocol value.
The
protocol is passed to the interface in
.Po Vt "struct ifreq" Pc Ns Li -> Ns Va ifr_flags .
The operation mode can also be given as
.Pp
.Bl -tag -width ".Cm -link0" -compact
.It Cm link0
.Dv IPPROTO_GRE
.It Cm -link0
.Dv IPPROTO_MOBILE
.El
.Pp
to
.Xr ifconfig 8 .
.Pp
The
.Cm link1
flag is not used to choose encapsulation, but to modify the
internal route search for the remote tunnel endpoint, see the
.Sx BUGS
section below.
.It Dv GREGPROTO
Query operation mode.
.It Dv GRESKEY
interfaces support a number of additional parameters to the
.Xr ifconfig 8 :
.Bl -tag -width "enable_csum"
.It Ar grekey
Set the GRE key used for outgoing packets.
A value of 0 disables the key option.
.It Dv GREGKEY
Get the GRE key currently used for outgoing packets.
0 means no outgoing key.
.It Ar enable_csum
Enables checksum calculation for outgoing packets.
.It Ar enable_seq
Enables use of sequence number field in the GRE header for outgoing packets.
.El
.Pp
Note that the IP addresses of the tunnel endpoints may be the same as the
ones defined with
.Xr ifconfig 8
for the interface (as if IP is encapsulated), but need not be.
.Sh EXAMPLES
Configuration example:
.Bd -literal
Host X-- Host A ----------------tunnel---------- Cisco D------Host E
\\ |
\\ /
+------Host B----------Host C----------+
.Ed
.Pp
On host A
.Pq Fx :
.Bd -literal -offset indent
route add default B
ifconfig greN create
ifconfig greN A D netmask 0xffffffff linkX up
ifconfig greN tunnel A D
route add E D
.Ed
.Pp
On Host D (Cisco):
.Bd -literal -offset indent
Interface TunnelX
ip unnumbered D ! e.g. address from Ethernet interface
tunnel source D ! e.g. address from Ethernet interface
tunnel destination A
ip route C <some interface and mask>
ip route A mask C
ip route X mask tunnelX
.Ed
.Pp
OR
.Pp
On Host D
.Pq Fx :
.Bd -literal -offset indent
route add default C
ifconfig greN create
ifconfig greN D A
ifconfig greN tunnel D A
.Ed
.Pp
If all goes well, you should see packets flowing ;-)
.Pp
If you want to reach Host A over the tunnel (from Host D (Cisco)), then
you have to have an alias on Host A for e.g.\& the Ethernet interface like:
.Pp
.Dl "ifconfig <etherif> alias Y"
.Pp
and on the Cisco:
.Pp
.Dl "ip route Y mask tunnelX"
.Pp
A similar setup can be used to create a link between two private networks
(for example in the 192.168 subnet) over the Internet:
.Bd -literal
192.168.1.* --- Router A -------tunnel-------- Router B --- 192.168.2.*
\\ /
@ -238,29 +106,22 @@ Assuming router A has the (external) IP address A and the internal address
On router A:
.Bd -literal -offset indent
ifconfig greN create
ifconfig greN 192.168.1.1 192.168.2.1 link1
ifconfig greN tunnel A B
ifconfig greN inet 192.168.1.1 192.168.2.1
ifconfig greN inet tunnel A B
route add -net 192.168.2 -netmask 255.255.255.0 192.168.2.1
.Ed
.Pp
On router B:
.Bd -literal -offset indent
ifconfig greN create
ifconfig greN 192.168.2.1 192.168.1.1 link1
ifconfig greN tunnel B A
ifconfig greN inet 192.168.2.1 192.168.1.1
ifconfig greN inet tunnel B A
route add -net 192.168.1 -netmask 255.255.255.0 192.168.1.1
.Ed
.Pp
Note that this is a safe situation where the
.Cm link1
flag (as discussed in the
.Sx BUGS
section below) may (and probably should) be set.
.Sh NOTES
The MTU of
.Nm
interfaces is set to 1476 by default, to match the value used by Cisco routers.
If grekey is set this is lowered to 1472.
This may not be an optimal value, depending on the link between the two tunnel
endpoints.
It can be adjusted via
@ -268,25 +129,8 @@ It can be adjusted via
.Pp
For correct operation, the
.Nm
device needs a route to the destination that is less specific than the
one over the tunnel.
(Basically, there needs to be a route to the decapsulating host that
does not run over the tunnel, as this would be a loop.)
If the addresses are ambiguous, doing the
.Nm ifconfig Cm tunnel
step before the
.Xr ifconfig 8
call to set the
.Nm
IP addresses will help to find a route outside the tunnel.
.Pp
In order to tell
.Xr ifconfig 8
to actually mark the interface as
.Dq up ,
the keyword
.Cm up
must be given last on its command line.
device needs a route to the decapsulating host that does not run over the tunnel,
as this would be a loop.
.Pp
The kernel must be set to forward datagrams by setting the
.Va net.inet.ip.forwarding
@ -296,41 +140,20 @@ variable to non-zero.
.Xr gif 4 ,
.Xr inet 4 ,
.Xr ip 4 ,
.Xr me 4 ,
.Xr netintro 4 ,
.\" Xr options 4 ,
.Xr protocols 5 ,
.Xr ifconfig 8 ,
.Xr sysctl 8
.Pp
A description of GRE encapsulation can be found in RFC 1701 and RFC 1702.
.Pp
A description of MOBILE encapsulation can be found in RFC 2004.
A description of GRE encapsulation can be found in RFC 2784 and RFC 2890.
.Sh AUTHORS
.An Andrey V. Elsukov Aq Mt ae@FreeBSD.org
.An Heiko W.Rupp Aq Mt hwr@pilhuhn.de
.Sh BUGS
The
.Fn compute_route
code in
.Pa if_gre.c
toggles the last bit of the
IP-address to provoke the search for a less specific route than the
one directly over the tunnel to prevent loops.
This is possibly not the best solution.
.Pp
To avoid the address munging described above, turn on the
.Cm link1
flag on the
.Xr ifconfig 8
command line.
This implies that the GRE packet destination and the ifconfig remote host
are not the same IP addresses, and that the GRE destination does not route
over the
.Nm
interface itself.
.Pp
The current implementation uses the key only for outgoing packets.
Incoming packets with a different key or without a key will be treated as if they
would belong to this interface.
.Pp
RFC1701 is not fully supported, however all unsupported features have been
deprecated in RFC2784.
The sequence number field also used only for outgoing packets.

85
share/man/man4/me.4 Normal file
View File

@ -0,0 +1,85 @@
.\" Copyright (c) Andrey V. Elsukov <ae@FreeBSD.org>
.\" All rights reserved.
.\"
.\" 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.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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.
.\"
.\" $FreeBSD$
.\"
.Dd November 7, 2014
.Dt ME 4
.Os
.Sh NAME
.Nm me
.Nd encapsulating network device
.Sh SYNOPSIS
To compile the
driver into the kernel, place the following line in the kernel
configuration file:
.Bd -ragged -offset indent
.Cd "device me"
.Ed
.Pp
Alternatively, to load the
driver as a module at boot time, place the following line in
.Xr loader.conf 5 :
.Bd -literal -offset indent
if_me_load="YES"
.Ed
.Sh DESCRIPTION
The
.Nm
network interface pseudo device encapsulates datagrams
into IP.
These encapsulated datagrams are routed to a destination host,
where they are decapsulated and further routed to their final destination.
.Pp
.Nm
interfaces are dynamically created and destroyed with the
.Xr ifconfig 8
.Cm create
and
.Cm destroy
subcommands.
.Pp
This driver corresponds to RFC 2004.
Datagrams are encapsulated into IP with a shorter encapsulation.
The original
IP header is modified and the modifications are inserted between the
so modified header and the original payload.
The protocol number 55 is used for outer header.
.Sh NOTES
.Pp
For correct operation, the
.Nm
device needs a route to the decapsulating host that does not run over the tunnel,
as this would be a loop.
.Sh SEE ALSO
.Xr gif 4 ,
.Xr gre 4 ,
.Xr inet 4 ,
.Xr ip 4 ,
.Xr netintro 4 ,
.Xr protocols 5 ,
.Xr ifconfig 8 ,
.Xr sysctl 8
.Sh AUTHORS
.An Andrey V. Elsukov Aq Mt ae@FreeBSD.org

View File

@ -26,7 +26,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd December 7, 2012
.Dd November 6, 2014
.Dt DOMAIN 9
.Os
.Sh NAME
@ -82,10 +82,9 @@ struct domain {
(void **, int);
int (*dom_rtdetach) /* clean up routing table */
(void **, int);
int dom_rtoffset; /* an arg to rtattach, in bits */
int dom_maxrtkey; /* for routing layer */
void *(*dom_ifattach)(struct ifnet *);
void (*dom_ifdetach)(struct ifnet *, void *);
int (*dom_ifmtu)(struct ifnet *);
/* af-dependent data on ifnet */
};
.Ed

View File

@ -36,7 +36,7 @@ NO_WERROR=
.if defined(DEBUG_FLAGS)
CFLAGS+= ${DEBUG_FLAGS}
.if ${MK_CTF} != "no" && ${DEBUG_FLAGS:M-g} != ""
.if ${MK_CTF} != "no"
CTFFLAGS+= -g
.endif
.else

View File

@ -43,12 +43,14 @@ LIBDEVINFO?= ${DESTDIR}${LIBDIR}/libdevinfo.a
LIBDEVSTAT?= ${DESTDIR}${LIBDIR}/libdevstat.a
LIBDIALOG?= ${DESTDIR}${LIBDIR}/libdialog.a
LIBDNS?= ${DESTDIR}${LIBDIR}/libdns.a
LIBDPV?= ${DESTDIR}${LIBDIR}/libdpv.a
LIBDTRACE?= ${DESTDIR}${LIBDIR}/libdtrace.a
LIBDWARF?= ${DESTDIR}${LIBDIR}/libdwarf.a
LIBEDIT?= ${DESTDIR}${LIBDIR}/libedit.a
LIBELF?= ${DESTDIR}${LIBDIR}/libelf.a
LIBEXECINFO?= ${DESTDIR}${LIBDIR}/libexecinfo.a
LIBFETCH?= ${DESTDIR}${LIBDIR}/libfetch.a
LIBFIGPAR?= ${DESTDIR}${LIBDIR}/libfigpar.a
LIBFL?= "don't use LIBFL, use LIBL"
LIBFORM?= ${DESTDIR}${LIBDIR}/libform.a
LIBG2C?= ${DESTDIR}${LIBDIR}/libg2c.a

View File

@ -112,7 +112,7 @@ whereobj:
.if ${CANONICALOBJDIR} != ${.CURDIR} && exists(${CANONICALOBJDIR}/)
cleanobj:
@rm -rf ${CANONICALOBJDIR}
@-rm -rf ${CANONICALOBJDIR}
.else
cleanobj: clean cleandepend
.endif
@ -130,7 +130,7 @@ clean:
rm -f ${CLEANFILES}
.endif
.if defined(CLEANDIRS) && !empty(CLEANDIRS)
rm -rf ${CLEANDIRS}
-rm -rf ${CLEANDIRS}
.endif
.endif

View File

@ -128,6 +128,7 @@ __<bsd.own.mk>__:
.if ${MK_CTF} != "no"
CTFCONVERT_CMD= ${CTFCONVERT} ${CTFFLAGS} ${.TARGET}
DEBUG_FLAGS+= -g
.elif defined(.PARSEDIR) || (defined(MAKE_VERSION) && ${MAKE_VERSION} >= 5201111300)
CTFCONVERT_CMD=
.else

View File

@ -20,7 +20,7 @@ NO_WERROR=
CFLAGS+=${DEBUG_FLAGS}
CXXFLAGS+=${DEBUG_FLAGS}
.if ${MK_CTF} != "no" && ${DEBUG_FLAGS:M-g} != ""
.if ${MK_CTF} != "no"
CTFFLAGS+= -g
.endif
.endif

View File

@ -100,6 +100,8 @@ END(bcmp)
* ws@tools.de (Wolfgang Solfrank, TooLs GmbH) +49-228-985800
*/
ENTRY(bcopy)
pushq %rbp
movq %rsp,%rbp
xchgq %rsi,%rdi
movq %rdx,%rcx
@ -116,6 +118,7 @@ ENTRY(bcopy)
andq $7,%rcx /* any bytes left? */
rep
movsb
popq %rbp
ret
/* ALIGN_TEXT */
@ -135,6 +138,7 @@ ENTRY(bcopy)
rep
movsq
cld
popq %rbp
ret
END(bcopy)

View File

@ -361,3 +361,7 @@ device xenpci # Xen HVM Hypervisor services driver
# VMware support
device vmx # VMware VMXNET3 Ethernet
# Netmap provides direct access to TX/RX rings on supported NICs
device netmap # netmap(4) support

View File

@ -64,6 +64,8 @@ __FBSDID("$FreeBSD$");
#include <machine/cpufunc.h>
#include <machine/md_var.h>
#define IS_POWER_OF_2(val) (((val) & ((val) - 1)) == 0)
#define MAX_BPAGES 64
#define MAX_DMA_SEGMENTS 4096
#define BUS_DMA_EXCL_BOUNCE BUS_DMA_BUS2
@ -466,17 +468,18 @@ bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment,
parent = arm_root_dma_tag;
#endif
/* Basic sanity checking */
if (boundary != 0 && boundary < maxsegsz)
maxsegsz = boundary;
/* Basic sanity checking. */
KASSERT(boundary == 0 || IS_POWER_OF_2(boundary),
("dma tag boundary %lu, must be a power of 2", boundary));
KASSERT(boundary == 0 || boundary >= maxsegsz,
("dma tag boundary %lu is < maxsegsz %lu\n", boundary, maxsegsz));
KASSERT(alignment != 0 && IS_POWER_OF_2(alignment),
("dma tag alignment %lu, must be non-zero power of 2", alignment));
KASSERT(maxsegsz != 0, ("dma tag maxsegsz must not be zero"));
/* Return a NULL tag on failure */
*dmat = NULL;
if (maxsegsz == 0) {
return (EINVAL);
}
newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_DEVBUF,
M_ZERO | M_NOWAIT);
if (newtag == NULL) {

View File

@ -121,12 +121,16 @@ kern_pread(int fd, vm_offset_t dest, size_t len, off_t off)
ssize_t nread;
if (lseek(fd, off, SEEK_SET) == -1) {
#ifdef DEBUG
printf("\nlseek failed\n");
#endif
return (-1);
}
nread = archsw.arch_readin(fd, dest, len);
if (nread != len) {
#ifdef DEBUG
printf("\nreadin failed\n");
#endif
return (-1);
}
return (0);
@ -144,17 +148,23 @@ alloc_pread(int fd, off_t off, size_t len)
buf = malloc(len);
if (buf == NULL) {
#ifdef DEBUG
printf("\nmalloc(%d) failed\n", (int)len);
#endif
return (NULL);
}
if (lseek(fd, off, SEEK_SET) == -1) {
#ifdef DEBUG
printf("\nlseek failed\n");
#endif
free(buf);
return (NULL);
}
nread = read(fd, buf, len);
if (nread != len) {
#ifdef DEBUG
printf("\nread failed\n");
#endif
free(buf);
return (NULL);
}

View File

@ -137,7 +137,7 @@ static struct scsi_da_rw_recovery_page rw_er_page_default = {
/*correction_span*/0,
/*head_offset_count*/0,
/*data_strobe_offset_cnt*/0,
/*byte8*/0,
/*byte8*/SMS_RWER_LBPERE,
/*write_retry_count*/0,
/*reserved2*/0,
/*recovery_time_limit*/{0, 0},
@ -297,22 +297,58 @@ static struct scsi_info_exceptions_page ie_page_changeable = {
/*report_count*/{0, 0, 0, 0}
};
static struct scsi_logical_block_provisioning_page lbp_page_default = {
#define CTL_LBPM_LEN (sizeof(struct ctl_logical_block_provisioning_page) - 4)
static struct ctl_logical_block_provisioning_page lbp_page_default = {{
/*page_code*/SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF,
/*subpage_code*/0x02,
/*page_length*/{0, sizeof(struct scsi_logical_block_provisioning_page) - 4},
/*page_length*/{CTL_LBPM_LEN >> 8, CTL_LBPM_LEN},
/*flags*/0,
/*reserved*/{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
/*descr*/{}
/*descr*/{}},
{{/*flags*/0,
/*resource*/0x01,
/*reserved*/{0, 0},
/*count*/{0, 0, 0, 0}},
{/*flags*/0,
/*resource*/0x02,
/*reserved*/{0, 0},
/*count*/{0, 0, 0, 0}},
{/*flags*/0,
/*resource*/0xf1,
/*reserved*/{0, 0},
/*count*/{0, 0, 0, 0}},
{/*flags*/0,
/*resource*/0xf2,
/*reserved*/{0, 0},
/*count*/{0, 0, 0, 0}}
}
};
static struct scsi_logical_block_provisioning_page lbp_page_changeable = {
static struct ctl_logical_block_provisioning_page lbp_page_changeable = {{
/*page_code*/SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF,
/*subpage_code*/0x02,
/*page_length*/{0, sizeof(struct scsi_logical_block_provisioning_page) - 4},
/*page_length*/{CTL_LBPM_LEN >> 8, CTL_LBPM_LEN},
/*flags*/0,
/*reserved*/{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
/*descr*/{}
/*descr*/{}},
{{/*flags*/0,
/*resource*/0,
/*reserved*/{0, 0},
/*count*/{0, 0, 0, 0}},
{/*flags*/0,
/*resource*/0,
/*reserved*/{0, 0},
/*count*/{0, 0, 0, 0}},
{/*flags*/0,
/*resource*/0,
/*reserved*/{0, 0},
/*count*/{0, 0, 0, 0}},
{/*flags*/0,
/*resource*/0,
/*reserved*/{0, 0},
/*count*/{0, 0, 0, 0}}
}
};
/*
@ -447,6 +483,7 @@ static void ctl_datamove_remote_read(union ctl_io *io);
static void ctl_datamove_remote(union ctl_io *io);
static int ctl_process_done(union ctl_io *io);
static void ctl_lun_thread(void *arg);
static void ctl_thresh_thread(void *arg);
static void ctl_work_thread(void *arg);
static void ctl_enqueue_incoming(union ctl_io *io);
static void ctl_enqueue_rtr(union ctl_io *io);
@ -1085,6 +1122,15 @@ ctl_init(void)
ctl_pool_free(other_pool);
return (error);
}
error = kproc_kthread_add(ctl_thresh_thread, softc,
&softc->ctl_proc, NULL, 0, 0, "ctl", "thresh");
if (error != 0) {
printf("error creating CTL threshold thread!\n");
ctl_pool_free(internal_pool);
ctl_pool_free(emergency_pool);
ctl_pool_free(other_pool);
return (error);
}
if (bootverbose)
printf("ctl: CAM Target Layer loaded\n");
@ -3991,6 +4037,52 @@ ctl_copy_io(union ctl_io *src, union ctl_io *dest)
dest->io_hdr.flags |= CTL_FLAG_INT_COPY;
}
static int
ctl_expand_number(const char *buf, uint64_t *num)
{
char *endptr;
uint64_t number;
unsigned shift;
number = strtoq(buf, &endptr, 0);
switch (tolower((unsigned char)*endptr)) {
case 'e':
shift = 60;
break;
case 'p':
shift = 50;
break;
case 't':
shift = 40;
break;
case 'g':
shift = 30;
break;
case 'm':
shift = 20;
break;
case 'k':
shift = 10;
break;
case 'b':
case '\0': /* No unit. */
*num = number;
return (0);
default:
/* Unrecognized unit. */
return (-1);
}
if ((number << shift) >> shift != number) {
/* Overflow */
return (-1);
}
*num = number << shift;
return (0);
}
/*
* This routine could be used in the future to load default and/or saved
* mode page parameters for a particuar lun.
@ -4001,6 +4093,7 @@ ctl_init_page_index(struct ctl_lun *lun)
int i;
struct ctl_page_index *page_index;
const char *value;
uint64_t ival;
memcpy(&lun->mode_pages.index, page_index_template,
sizeof(page_index_template));
@ -4104,17 +4197,11 @@ ctl_init_page_index(struct ctl_lun *lun)
* works out a fake geometry based on the capacity.
*/
memcpy(&lun->mode_pages.rigid_disk_page[
CTL_PAGE_CURRENT], &rigid_disk_page_default,
CTL_PAGE_DEFAULT], &rigid_disk_page_default,
sizeof(rigid_disk_page_default));
memcpy(&lun->mode_pages.rigid_disk_page[
CTL_PAGE_CHANGEABLE],&rigid_disk_page_changeable,
sizeof(rigid_disk_page_changeable));
memcpy(&lun->mode_pages.rigid_disk_page[
CTL_PAGE_DEFAULT], &rigid_disk_page_default,
sizeof(rigid_disk_page_default));
memcpy(&lun->mode_pages.rigid_disk_page[
CTL_PAGE_SAVED], &rigid_disk_page_default,
sizeof(rigid_disk_page_default));
sectors_per_cylinder = CTL_DEFAULT_SECTORS_PER_TRACK *
CTL_DEFAULT_HEADS;
@ -4150,17 +4237,22 @@ ctl_init_page_index(struct ctl_lun *lun)
if (cylinders > 0xffffff)
cylinders = 0xffffff;
rigid_disk_page = &lun->mode_pages.rigid_disk_page[
CTL_PAGE_CURRENT];
scsi_ulto3b(cylinders, rigid_disk_page->cylinders);
rigid_disk_page = &lun->mode_pages.rigid_disk_page[
CTL_PAGE_DEFAULT];
scsi_ulto3b(cylinders, rigid_disk_page->cylinders);
rigid_disk_page = &lun->mode_pages.rigid_disk_page[
CTL_PAGE_SAVED];
scsi_ulto3b(cylinders, rigid_disk_page->cylinders);
if ((value = ctl_get_opt(&lun->be_lun->options,
"rpm")) != NULL) {
scsi_ulto2b(strtol(value, NULL, 0),
rigid_disk_page->rotation_rate);
}
memcpy(&lun->mode_pages.rigid_disk_page[CTL_PAGE_CURRENT],
&lun->mode_pages.rigid_disk_page[CTL_PAGE_DEFAULT],
sizeof(rigid_disk_page_default));
memcpy(&lun->mode_pages.rigid_disk_page[CTL_PAGE_SAVED],
&lun->mode_pages.rigid_disk_page[CTL_PAGE_DEFAULT],
sizeof(rigid_disk_page_default));
page_index->page_data =
(uint8_t *)lun->mode_pages.rigid_disk_page;
@ -4245,22 +4337,77 @@ ctl_init_page_index(struct ctl_lun *lun)
page_index->page_data =
(uint8_t *)lun->mode_pages.ie_page;
break;
case 0x02:
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_CURRENT],
case 0x02: {
struct ctl_logical_block_provisioning_page *page;
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_DEFAULT],
&lbp_page_default,
sizeof(lbp_page_default));
memcpy(&lun->mode_pages.lbp_page[
CTL_PAGE_CHANGEABLE], &lbp_page_changeable,
sizeof(lbp_page_changeable));
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_DEFAULT],
&lbp_page_default,
sizeof(lbp_page_default));
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_SAVED],
&lbp_page_default,
sizeof(lbp_page_default));
page = &lun->mode_pages.lbp_page[CTL_PAGE_SAVED];
value = ctl_get_opt(&lun->be_lun->options,
"avail-threshold");
if (value != NULL &&
ctl_expand_number(value, &ival) == 0) {
page->descr[0].flags |= SLBPPD_ENABLED |
SLBPPD_ARMING_DEC;
if (lun->be_lun->blocksize)
ival /= lun->be_lun->blocksize;
else
ival /= 512;
scsi_ulto4b(ival >> CTL_LBP_EXPONENT,
page->descr[0].count);
}
value = ctl_get_opt(&lun->be_lun->options,
"used-threshold");
if (value != NULL &&
ctl_expand_number(value, &ival) == 0) {
page->descr[1].flags |= SLBPPD_ENABLED |
SLBPPD_ARMING_INC;
if (lun->be_lun->blocksize)
ival /= lun->be_lun->blocksize;
else
ival /= 512;
scsi_ulto4b(ival >> CTL_LBP_EXPONENT,
page->descr[1].count);
}
value = ctl_get_opt(&lun->be_lun->options,
"pool-avail-threshold");
if (value != NULL &&
ctl_expand_number(value, &ival) == 0) {
page->descr[2].flags |= SLBPPD_ENABLED |
SLBPPD_ARMING_DEC;
if (lun->be_lun->blocksize)
ival /= lun->be_lun->blocksize;
else
ival /= 512;
scsi_ulto4b(ival >> CTL_LBP_EXPONENT,
page->descr[2].count);
}
value = ctl_get_opt(&lun->be_lun->options,
"pool-used-threshold");
if (value != NULL &&
ctl_expand_number(value, &ival) == 0) {
page->descr[3].flags |= SLBPPD_ENABLED |
SLBPPD_ARMING_INC;
if (lun->be_lun->blocksize)
ival /= lun->be_lun->blocksize;
else
ival /= 512;
scsi_ulto4b(ival >> CTL_LBP_EXPONENT,
page->descr[3].count);
}
memcpy(&lun->mode_pages.lbp_page[CTL_PAGE_CURRENT],
&lun->mode_pages.lbp_page[CTL_PAGE_SAVED],
sizeof(lbp_page_default));
page_index->page_data =
(uint8_t *)lun->mode_pages.lbp_page;
}
}}
break;
}
case SMS_VENDOR_SPECIFIC_PAGE:{
@ -4319,13 +4466,13 @@ static int
ctl_init_log_page_index(struct ctl_lun *lun)
{
struct ctl_page_index *page_index;
int i, j, prev;
int i, j, k, prev;
memcpy(&lun->log_pages.index, log_page_index_template,
sizeof(log_page_index_template));
prev = -1;
for (i = 0, j = 0; i < CTL_NUM_LOG_PAGES; i++) {
for (i = 0, j = 0, k = 0; i < CTL_NUM_LOG_PAGES; i++) {
page_index = &lun->log_pages.index[i];
/*
@ -4338,18 +4485,26 @@ ctl_init_log_page_index(struct ctl_lun *lun)
&& (page_index->page_flags & CTL_PAGE_FLAG_DISK_ONLY))
continue;
if (page_index->page_code == SLS_LOGICAL_BLOCK_PROVISIONING &&
((lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) == 0 ||
lun->backend->lun_attr == NULL))
continue;
if (page_index->page_code != prev) {
lun->log_pages.pages_page[j] = page_index->page_code;
prev = page_index->page_code;
j++;
}
lun->log_pages.subpages_page[i*2] = page_index->page_code;
lun->log_pages.subpages_page[i*2+1] = page_index->subpage;
lun->log_pages.subpages_page[k*2] = page_index->page_code;
lun->log_pages.subpages_page[k*2+1] = page_index->subpage;
k++;
}
lun->log_pages.index[0].page_data = &lun->log_pages.pages_page[0];
lun->log_pages.index[0].page_len = j;
lun->log_pages.index[1].page_data = &lun->log_pages.subpages_page[0];
lun->log_pages.index[1].page_len = i * 2;
lun->log_pages.index[1].page_len = k * 2;
lun->log_pages.index[2].page_data = &lun->log_pages.lbp_page[0];
lun->log_pages.index[2].page_len = 12*CTL_NUM_LBP_PARAMS;
return (CTL_RETVAL_COMPLETE);
}
@ -6937,6 +7092,75 @@ ctl_mode_sense(struct ctl_scsiio *ctsio)
return (CTL_RETVAL_COMPLETE);
}
int
ctl_lbp_log_sense_handler(struct ctl_scsiio *ctsio,
struct ctl_page_index *page_index,
int pc)
{
struct ctl_lun *lun;
struct scsi_log_param_header *phdr;
uint8_t *data;
uint64_t val;
lun = (struct ctl_lun *)ctsio->io_hdr.ctl_private[CTL_PRIV_LUN].ptr;
data = page_index->page_data;
if (lun->backend->lun_attr != NULL &&
(val = lun->backend->lun_attr(lun->be_lun->be_lun, "blocksavail"))
!= UINT64_MAX) {
phdr = (struct scsi_log_param_header *)data;
scsi_ulto2b(0x0001, phdr->param_code);
phdr->param_control = SLP_LBIN | SLP_LP;
phdr->param_len = 8;
data = (uint8_t *)(phdr + 1);
scsi_ulto4b(val >> CTL_LBP_EXPONENT, data);
data[4] = 0x01; /* per-LUN */
data += phdr->param_len;
}
if (lun->backend->lun_attr != NULL &&
(val = lun->backend->lun_attr(lun->be_lun->be_lun, "blocksused"))
!= UINT64_MAX) {
phdr = (struct scsi_log_param_header *)data;
scsi_ulto2b(0x0002, phdr->param_code);
phdr->param_control = SLP_LBIN | SLP_LP;
phdr->param_len = 8;
data = (uint8_t *)(phdr + 1);
scsi_ulto4b(val >> CTL_LBP_EXPONENT, data);
data[4] = 0x02; /* per-pool */
data += phdr->param_len;
}
if (lun->backend->lun_attr != NULL &&
(val = lun->backend->lun_attr(lun->be_lun->be_lun, "poolblocksavail"))
!= UINT64_MAX) {
phdr = (struct scsi_log_param_header *)data;
scsi_ulto2b(0x00f1, phdr->param_code);
phdr->param_control = SLP_LBIN | SLP_LP;
phdr->param_len = 8;
data = (uint8_t *)(phdr + 1);
scsi_ulto4b(val >> CTL_LBP_EXPONENT, data);
data[4] = 0x02; /* per-pool */
data += phdr->param_len;
}
if (lun->backend->lun_attr != NULL &&
(val = lun->backend->lun_attr(lun->be_lun->be_lun, "poolblocksused"))
!= UINT64_MAX) {
phdr = (struct scsi_log_param_header *)data;
scsi_ulto2b(0x00f2, phdr->param_code);
phdr->param_control = SLP_LBIN | SLP_LP;
phdr->param_len = 8;
data = (uint8_t *)(phdr + 1);
scsi_ulto4b(val >> CTL_LBP_EXPONENT, data);
data[4] = 0x02; /* per-pool */
data += phdr->param_len;
}
page_index->page_len = data - page_index->page_data;
return (0);
}
int
ctl_log_sense(struct ctl_scsiio *ctsio)
{
@ -10188,7 +10412,7 @@ ctl_inquiry_evpd_bdc(struct ctl_scsiio *ctsio, int alloc_len)
(value = ctl_get_opt(&lun->be_lun->options, "rpm")) != NULL)
i = strtol(value, NULL, 0);
else
i = SVPD_NON_ROTATING;
i = CTL_DEFAULT_ROTATION_RATE;
scsi_ulto2b(i, bdc_ptr->medium_rotation_rate);
if (lun != NULL &&
(value = ctl_get_opt(&lun->be_lun->options, "formfactor")) != NULL)
@ -10245,9 +10469,10 @@ ctl_inquiry_evpd_lbp(struct ctl_scsiio *ctsio, int alloc_len)
lbp_ptr->page_code = SVPD_LBP;
scsi_ulto2b(sizeof(*lbp_ptr) - 4, lbp_ptr->page_length);
if (lun != NULL && lun->be_lun->flags & CTL_LUN_FLAG_UNMAP) {
lbp_ptr->threshold_exponent = CTL_LBP_EXPONENT;
lbp_ptr->flags = SVPD_LBP_UNMAP | SVPD_LBP_WS16 |
SVPD_LBP_WS10 | SVPD_LBP_RZ | SVPD_LBP_ANC_SUP;
lbp_ptr->prov_type = SVPD_LBP_RESOURCE;
lbp_ptr->prov_type = SVPD_LBP_THIN;
}
ctsio->scsi_status = SCSI_STATUS_OK;
@ -13993,6 +14218,88 @@ ctl_lun_thread(void *arg)
}
}
static void
ctl_thresh_thread(void *arg)
{
struct ctl_softc *softc = (struct ctl_softc *)arg;
struct ctl_lun *lun;
struct ctl_be_lun *be_lun;
struct scsi_da_rw_recovery_page *rwpage;
struct ctl_logical_block_provisioning_page *page;
const char *attr;
uint64_t thres, val;
int i, e;
CTL_DEBUG_PRINT(("ctl_thresh_thread starting\n"));
for (;;) {
mtx_lock(&softc->ctl_lock);
STAILQ_FOREACH(lun, &softc->lun_list, links) {
be_lun = lun->be_lun;
if ((lun->flags & CTL_LUN_DISABLED) ||
(lun->flags & CTL_LUN_OFFLINE) ||
(be_lun->flags & CTL_LUN_FLAG_UNMAP) == 0 ||
lun->backend->lun_attr == NULL)
continue;
rwpage = &lun->mode_pages.rw_er_page[CTL_PAGE_CURRENT];
if ((rwpage->byte8 & SMS_RWER_LBPERE) == 0)
continue;
e = 0;
page = &lun->mode_pages.lbp_page[CTL_PAGE_CURRENT];
for (i = 0; i < CTL_NUM_LBP_THRESH; i++) {
if ((page->descr[i].flags & SLBPPD_ENABLED) == 0)
continue;
thres = scsi_4btoul(page->descr[i].count);
thres <<= CTL_LBP_EXPONENT;
switch (page->descr[i].resource) {
case 0x01:
attr = "blocksavail";
break;
case 0x02:
attr = "blocksused";
break;
case 0xf1:
attr = "poolblocksavail";
break;
case 0xf2:
attr = "poolblocksused";
break;
default:
continue;
}
mtx_unlock(&softc->ctl_lock); // XXX
val = lun->backend->lun_attr(
lun->be_lun->be_lun, attr);
mtx_lock(&softc->ctl_lock);
if (val == UINT64_MAX)
continue;
if ((page->descr[i].flags & SLBPPD_ARMING_MASK)
== SLBPPD_ARMING_INC)
e |= (val >= thres);
else
e |= (val <= thres);
}
mtx_lock(&lun->lun_lock);
if (e) {
if (lun->lasttpt == 0 ||
time_uptime - lun->lasttpt >= CTL_LBP_UA_PERIOD) {
lun->lasttpt = time_uptime;
for (i = 0; i < CTL_MAX_INITIATORS; i++)
lun->pending_ua[i] |=
CTL_UA_THIN_PROV_THRES;
}
} else {
lun->lasttpt = 0;
for (i = 0; i < CTL_MAX_INITIATORS; i++)
lun->pending_ua[i] &= ~CTL_UA_THIN_PROV_THRES;
}
mtx_unlock(&lun->lun_lock);
}
mtx_unlock(&softc->ctl_lock);
pause("-", CTL_LBP_PERIOD * hz);
}
}
static void
ctl_enqueue_incoming(union ctl_io *io)
{

View File

@ -127,7 +127,8 @@ typedef enum {
CTL_UA_RES_RELEASE = 0x0800,
CTL_UA_REG_PREEMPT = 0x1000,
CTL_UA_ASYM_ACC_CHANGE = 0x2000,
CTL_UA_CAPACITY_CHANGED = 0x4000
CTL_UA_CAPACITY_CHANGED = 0x4000,
CTL_UA_THIN_PROV_THRES = 0x8000
} ctl_ua_type;
#ifdef _KERNEL
@ -178,6 +179,9 @@ int ctl_debugconf_sp_sense_handler(struct ctl_scsiio *ctsio,
int ctl_debugconf_sp_select_handler(struct ctl_scsiio *ctsio,
struct ctl_page_index *page_index,
uint8_t *page_ptr);
int ctl_lbp_log_sense_handler(struct ctl_scsiio *ctsio,
struct ctl_page_index *page_index,
int pc);
int ctl_config_move_done(union ctl_io *io);
void ctl_datamove(union ctl_io *io);
void ctl_done(union ctl_io *io);

View File

@ -218,6 +218,7 @@ typedef void (*be_vfunc_t)(union ctl_io *io);
typedef int (*be_ioctl_t)(struct cdev *dev, u_long cmd, caddr_t addr, int flag,
struct thread *td);
typedef int (*be_luninfo_t)(void *be_lun, struct sbuf *sb);
typedef uint64_t (*be_lunattr_t)(void *be_lun, const char *attrname);
struct ctl_backend_driver {
char name[CTL_BE_NAME_LEN]; /* passed to CTL */
@ -229,6 +230,7 @@ struct ctl_backend_driver {
be_func_t config_write; /* passed to CTL */
be_ioctl_t ioctl; /* passed to CTL */
be_luninfo_t lun_info; /* passed to CTL */
be_lunattr_t lun_attr; /* passed to CTL */
#ifdef CS_BE_CONFIG_MOVE_DONE_IS_NOT_USED
be_func_t config_move_done; /* passed to backend */
#endif

View File

@ -145,6 +145,8 @@ struct ctl_be_block_lun;
typedef void (*cbb_dispatch_t)(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
typedef uint64_t (*cbb_getattr_t)(struct ctl_be_block_lun *be_lun,
const char *attrname);
/*
* Backend LUN structure. There is a 1:1 mapping between a block device
@ -161,6 +163,7 @@ struct ctl_be_block_lun {
cbb_dispatch_t dispatch;
cbb_dispatch_t lun_flush;
cbb_dispatch_t unmap;
cbb_getattr_t getattr;
uma_zone_t lun_zone;
uint64_t size_blocks;
uint64_t size_bytes;
@ -240,6 +243,8 @@ static void ctl_be_block_unmap_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
static void ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
struct ctl_be_block_io *beio);
static uint64_t ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun,
const char *attrname);
static void ctl_be_block_cw_dispatch(struct ctl_be_block_lun *be_lun,
union ctl_io *io);
static void ctl_be_block_dispatch(struct ctl_be_block_lun *be_lun,
@ -272,6 +277,7 @@ static void ctl_be_block_lun_config_status(void *be_lun,
static int ctl_be_block_config_write(union ctl_io *io);
static int ctl_be_block_config_read(union ctl_io *io);
static int ctl_be_block_lun_info(void *be_lun, struct sbuf *sb);
static uint64_t ctl_be_block_lun_attr(void *be_lun, const char *attrname);
int ctl_be_block_init(void);
static struct ctl_backend_driver ctl_be_block_driver =
@ -284,7 +290,8 @@ static struct ctl_backend_driver ctl_be_block_driver =
.config_read = ctl_be_block_config_read,
.config_write = ctl_be_block_config_write,
.ioctl = ctl_be_block_ioctl,
.lun_info = ctl_be_block_lun_info
.lun_info = ctl_be_block_lun_info,
.lun_attr = ctl_be_block_lun_attr
};
MALLOC_DEFINE(M_CTLBLK, "ctlblk", "Memory used for CTL block backend");
@ -1012,6 +1019,24 @@ ctl_be_block_dispatch_dev(struct ctl_be_block_lun *be_lun,
}
}
static uint64_t
ctl_be_block_getattr_dev(struct ctl_be_block_lun *be_lun, const char *attrname)
{
struct ctl_be_block_devdata *dev_data = &be_lun->backend.dev;
struct diocgattr_arg arg;
int error;
if (dev_data->csw == NULL || dev_data->csw->d_ioctl == NULL)
return (UINT64_MAX);
strlcpy(arg.name, attrname, sizeof(arg.name));
arg.len = sizeof(arg.value.off);
error = dev_data->csw->d_ioctl(dev_data->cdev,
DIOCGATTR, (caddr_t)&arg, FREAD, curthread);
if (error != 0)
return (UINT64_MAX);
return (arg.value.off);
}
static void
ctl_be_block_cw_done_ws(struct ctl_be_block_io *beio)
{
@ -1647,6 +1672,7 @@ ctl_be_block_open_dev(struct ctl_be_block_lun *be_lun, struct ctl_lun_req *req)
be_lun->dispatch = ctl_be_block_dispatch_dev;
be_lun->lun_flush = ctl_be_block_flush_dev;
be_lun->unmap = ctl_be_block_unmap_dev;
be_lun->getattr = ctl_be_block_getattr_dev;
error = VOP_GETATTR(be_lun->vn, &vattr, NOCRED);
if (error) {
@ -1993,10 +2019,10 @@ ctl_be_block_create(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
}
num_threads = tmp_num_threads;
}
unmap = 0;
unmap = (be_lun->dispatch == ctl_be_block_dispatch_zvol);
value = ctl_get_opt(&be_lun->ctl_be_lun.options, "unmap");
if (value != NULL && strcmp(value, "on") == 0)
unmap = 1;
if (value != NULL)
unmap = (strcmp(value, "on") == 0);
be_lun->flags = CTL_BE_BLOCK_LUN_UNCONFIGURED;
be_lun->ctl_be_lun.flags = CTL_LUN_FLAG_PRIMARY;
@ -2366,7 +2392,7 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
be_lun->params.lun_size_bytes = params->lun_size_bytes;
oldsize = be_lun->size_blocks;
oldsize = be_lun->size_bytes;
if (be_lun->vn == NULL)
error = ctl_be_block_open(softc, be_lun, req);
else if (be_lun->vn->v_type == VREG)
@ -2374,7 +2400,7 @@ ctl_be_block_modify(struct ctl_be_block_softc *softc, struct ctl_lun_req *req)
else
error = ctl_be_block_modify_dev(be_lun, req);
if (error == 0 && be_lun->size_blocks != oldsize) {
if (error == 0 && be_lun->size_bytes != oldsize) {
be_lun->size_blocks = be_lun->size_bytes >>
be_lun->blocksize_shift;
@ -2582,6 +2608,16 @@ bailout:
return (retval);
}
static uint64_t
ctl_be_block_lun_attr(void *be_lun, const char *attrname)
{
struct ctl_be_block_lun *lun = (struct ctl_be_block_lun *)be_lun;
if (lun->getattr == NULL)
return (UINT64_MAX);
return (lun->getattr(lun, attrname));
}
int
ctl_be_block_init(void)
{

View File

@ -463,6 +463,11 @@ ctl_build_ua(ctl_ua_type *ua_type, struct scsi_sense_data *sense,
asc = 0x2A;
ascq = 0x09;
break;
case CTL_UA_THIN_PROV_THRES:
/* 38h/07n THIN PROVISIONING SOFT THRESHOLD REACHED */
asc = 0x38;
ascq = 0x07;
break;
default:
panic("ctl_build_ua: Unknown UA %x", ua_to_build);
}

View File

@ -271,7 +271,7 @@ union ctl_softcs {
#define CTL_DEFAULT_SECTORS_PER_TRACK 256
#define CTL_DEFAULT_HEADS 128
#define CTL_DEFAULT_ROTATION_RATE 10000
#define CTL_DEFAULT_ROTATION_RATE SVPD_NON_ROTATING
struct ctl_page_index;
@ -302,6 +302,17 @@ struct ctl_page_index {
#define CTL_PAGE_DEFAULT 0x02
#define CTL_PAGE_SAVED 0x03
#define CTL_NUM_LBP_PARAMS 4
#define CTL_NUM_LBP_THRESH 4
#define CTL_LBP_EXPONENT 11 /* 2048 sectors */
#define CTL_LBP_PERIOD 10 /* 10 seconds */
#define CTL_LBP_UA_PERIOD 300 /* 5 minutes */
struct ctl_logical_block_provisioning_page {
struct scsi_logical_block_provisioning_page main;
struct scsi_logical_block_provisioning_page_descr descr[CTL_NUM_LBP_THRESH];
};
static const struct ctl_page_index page_index_template[] = {
{SMS_RW_ERROR_RECOVERY_PAGE, 0, sizeof(struct scsi_da_rw_recovery_page), NULL,
CTL_PAGE_FLAG_DISK_ONLY, NULL, NULL},
@ -316,7 +327,7 @@ static const struct ctl_page_index page_index_template[] = {
{SMS_INFO_EXCEPTIONS_PAGE, 0, sizeof(struct scsi_info_exceptions_page), NULL,
CTL_PAGE_FLAG_NONE, NULL, NULL},
{SMS_INFO_EXCEPTIONS_PAGE | SMPH_SPF, 0x02,
sizeof(struct scsi_logical_block_provisioning_page), NULL,
sizeof(struct ctl_logical_block_provisioning_page), NULL,
CTL_PAGE_FLAG_DISK_ONLY, NULL, NULL},
{SMS_VENDOR_SPECIFIC_PAGE | SMPH_SPF, DBGCNF_SUBPAGE_CODE,
sizeof(struct copan_debugconf_subpage), NULL, CTL_PAGE_FLAG_NONE,
@ -333,7 +344,7 @@ struct ctl_mode_pages {
struct scsi_caching_page caching_page[4];
struct scsi_control_page control_page[4];
struct scsi_info_exceptions_page ie_page[4];
struct scsi_logical_block_provisioning_page lbp_page[4];
struct ctl_logical_block_provisioning_page lbp_page[4];
struct copan_debugconf_subpage debugconf_subpage[4];
struct ctl_page_index index[CTL_NUM_MODE_PAGES];
};
@ -343,6 +354,8 @@ static const struct ctl_page_index log_page_index_template[] = {
CTL_PAGE_FLAG_NONE, NULL, NULL},
{SLS_SUPPORTED_PAGES_PAGE, SLS_SUPPORTED_SUBPAGES_SUBPAGE, 0, NULL,
CTL_PAGE_FLAG_NONE, NULL, NULL},
{SLS_LOGICAL_BLOCK_PROVISIONING, 0, 0, NULL,
CTL_PAGE_FLAG_NONE, ctl_lbp_log_sense_handler, NULL},
};
#define CTL_NUM_LOG_PAGES sizeof(log_page_index_template)/ \
@ -351,6 +364,7 @@ static const struct ctl_page_index log_page_index_template[] = {
struct ctl_log_pages {
uint8_t pages_page[CTL_NUM_LOG_PAGES];
uint8_t subpages_page[CTL_NUM_LOG_PAGES * 2];
uint8_t lbp_page[12*CTL_NUM_LBP_PARAMS];
struct ctl_page_index index[CTL_NUM_LOG_PAGES];
};
@ -411,6 +425,7 @@ struct ctl_lun {
struct scsi_sense_data pending_sense[CTL_MAX_INITIATORS];
#endif
ctl_ua_type pending_ua[CTL_MAX_INITIATORS];
time_t lasttpt;
struct ctl_mode_pages mode_pages;
struct ctl_log_pages log_pages;
struct ctl_lun_io_stats stats;

View File

@ -559,6 +559,7 @@ struct scsi_log_sense
#define SLS_ERROR_VERIFY_PAGE 0x05
#define SLS_ERROR_NONMEDIUM_PAGE 0x06
#define SLS_ERROR_LASTN_PAGE 0x07
#define SLS_LOGICAL_BLOCK_PROVISIONING 0x0c
#define SLS_SELF_TEST_PAGE 0x10
#define SLS_IE_PAGE 0x2f
#define SLS_PAGE_CTRL_MASK 0xC0
@ -740,6 +741,11 @@ struct scsi_info_exceptions_page {
struct scsi_logical_block_provisioning_page_descr {
uint8_t flags;
#define SLBPPD_ENABLED 0x80
#define SLBPPD_TYPE_MASK 0x38
#define SLBPPD_ARMING_MASK 0x07
#define SLBPPD_ARMING_DEC 0x02
#define SLBPPD_ARMING_INC 0x01
uint8_t resource;
uint8_t reserved[2];
uint8_t count[4];

View File

@ -387,6 +387,7 @@ typedef struct arc_stats {
kstat_named_t arcstat_l2_evict_lock_retry;
kstat_named_t arcstat_l2_evict_reading;
kstat_named_t arcstat_l2_free_on_write;
kstat_named_t arcstat_l2_cdata_free_on_write;
kstat_named_t arcstat_l2_abort_lowmem;
kstat_named_t arcstat_l2_cksum_bad;
kstat_named_t arcstat_l2_io_error;
@ -464,6 +465,7 @@ static arc_stats_t arc_stats = {
{ "l2_evict_lock_retry", KSTAT_DATA_UINT64 },
{ "l2_evict_reading", KSTAT_DATA_UINT64 },
{ "l2_free_on_write", KSTAT_DATA_UINT64 },
{ "l2_cdata_free_on_write", KSTAT_DATA_UINT64 },
{ "l2_abort_lowmem", KSTAT_DATA_UINT64 },
{ "l2_cksum_bad", KSTAT_DATA_UINT64 },
{ "l2_io_error", KSTAT_DATA_UINT64 },
@ -1655,6 +1657,21 @@ arc_buf_add_ref(arc_buf_t *buf, void* tag)
data, metadata, hits);
}
static void
arc_buf_free_on_write(void *data, size_t size,
void (*free_func)(void *, size_t))
{
l2arc_data_free_t *df;
df = kmem_alloc(sizeof (l2arc_data_free_t), KM_SLEEP);
df->l2df_data = data;
df->l2df_size = size;
df->l2df_func = free_func;
mutex_enter(&l2arc_free_on_write_mtx);
list_insert_head(l2arc_free_on_write, df);
mutex_exit(&l2arc_free_on_write_mtx);
}
/*
* Free the arc data buffer. If it is an l2arc write in progress,
* the buffer is placed on l2arc_free_on_write to be freed later.
@ -1665,14 +1682,7 @@ arc_buf_data_free(arc_buf_t *buf, void (*free_func)(void *, size_t))
arc_buf_hdr_t *hdr = buf->b_hdr;
if (HDR_L2_WRITING(hdr)) {
l2arc_data_free_t *df;
df = kmem_alloc(sizeof (l2arc_data_free_t), KM_SLEEP);
df->l2df_data = buf->b_data;
df->l2df_size = hdr->b_size;
df->l2df_func = free_func;
mutex_enter(&l2arc_free_on_write_mtx);
list_insert_head(l2arc_free_on_write, df);
mutex_exit(&l2arc_free_on_write_mtx);
arc_buf_free_on_write(buf->b_data, hdr->b_size, free_func);
ARCSTAT_BUMP(arcstat_l2_free_on_write);
} else {
free_func(buf->b_data, hdr->b_size);
@ -1683,6 +1693,23 @@ arc_buf_data_free(arc_buf_t *buf, void (*free_func)(void *, size_t))
* Free up buf->b_data and if 'remove' is set, then pull the
* arc_buf_t off of the the arc_buf_hdr_t's list and free it.
*/
static void
arc_buf_l2_cdata_free(arc_buf_hdr_t *hdr)
{
l2arc_buf_hdr_t *l2hdr = hdr->b_l2hdr;
ASSERT(MUTEX_HELD(&l2arc_buflist_mtx));
if (l2hdr->b_tmp_cdata == NULL)
return;
ASSERT(HDR_L2_WRITING(hdr));
arc_buf_free_on_write(l2hdr->b_tmp_cdata, hdr->b_size,
zio_data_buf_free);
ARCSTAT_BUMP(arcstat_l2_cdata_free_on_write);
l2hdr->b_tmp_cdata = NULL;
}
static void
arc_buf_destroy(arc_buf_t *buf, boolean_t recycle, boolean_t remove)
{
@ -1782,6 +1809,7 @@ arc_hdr_destroy(arc_buf_hdr_t *hdr)
trim_map_free(l2hdr->b_dev->l2ad_vdev, l2hdr->b_daddr,
hdr->b_size, 0);
list_remove(l2hdr->b_dev->l2ad_buflist, hdr);
arc_buf_l2_cdata_free(hdr);
ARCSTAT_INCR(arcstat_l2_size, -hdr->b_size);
ARCSTAT_INCR(arcstat_l2_asize, -l2hdr->b_asize);
vdev_space_update(l2hdr->b_dev->l2ad_vdev,
@ -3675,6 +3703,7 @@ arc_release(arc_buf_t *buf, void *tag)
l2hdr = hdr->b_l2hdr;
if (l2hdr) {
mutex_enter(&l2arc_buflist_mtx);
arc_buf_l2_cdata_free(hdr);
hdr->b_l2hdr = NULL;
list_remove(l2hdr->b_dev->l2ad_buflist, hdr);
}
@ -4964,6 +4993,11 @@ top:
ARCSTAT_INCR(arcstat_l2_asize, -abl2->b_asize);
bytes_evicted += abl2->b_asize;
ab->b_l2hdr = NULL;
/*
* We are destroying l2hdr, so ensure that
* its compressed buffer, if any, is not leaked.
*/
ASSERT(abl2->b_tmp_cdata == NULL);
kmem_free(abl2, sizeof (l2arc_buf_hdr_t));
ARCSTAT_INCR(arcstat_l2_size, -ab->b_size);
}
@ -5202,6 +5236,14 @@ l2arc_write_buffers(spa_t *spa, l2arc_dev_t *dev, uint64_t target_sz,
buf_data = l2hdr->b_tmp_cdata;
buf_sz = l2hdr->b_asize;
/*
* If the data has not been compressed, then clear b_tmp_cdata
* to make sure that it points only to a temporary compression
* buffer.
*/
if (!L2ARC_IS_VALID_COMPRESS(l2hdr->b_compress))
l2hdr->b_tmp_cdata = NULL;
/* Compression may have squashed the buffer to zero length. */
if (buf_sz != 0) {
uint64_t buf_p_sz;
@ -5392,15 +5434,18 @@ l2arc_release_cdata_buf(arc_buf_hdr_t *ab)
{
l2arc_buf_hdr_t *l2hdr = ab->b_l2hdr;
if (l2hdr->b_compress == ZIO_COMPRESS_LZ4) {
ASSERT(L2ARC_IS_VALID_COMPRESS(l2hdr->b_compress));
if (l2hdr->b_compress != ZIO_COMPRESS_EMPTY) {
/*
* If the data was compressed, then we've allocated a
* temporary buffer for it, so now we need to release it.
*/
ASSERT(l2hdr->b_tmp_cdata != NULL);
zio_data_buf_free(l2hdr->b_tmp_cdata, ab->b_size);
l2hdr->b_tmp_cdata = NULL;
} else {
ASSERT(l2hdr->b_tmp_cdata == NULL);
}
l2hdr->b_tmp_cdata = NULL;
}
/*

View File

@ -59,6 +59,7 @@ typedef struct traverse_data {
int td_flags;
prefetch_data_t *td_pfd;
boolean_t td_paused;
uint64_t td_hole_birth_enabled_txg;
blkptr_cb_t *td_func;
void *td_arg;
} traverse_data_t;
@ -229,25 +230,20 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
}
if (bp->blk_birth == 0) {
if (spa_feature_is_active(td->td_spa, SPA_FEATURE_HOLE_BIRTH)) {
/*
* Since this block has a birth time of 0 it must be a
* hole created before the SPA_FEATURE_HOLE_BIRTH
* feature was enabled. If SPA_FEATURE_HOLE_BIRTH
* was enabled before the min_txg for this traveral we
* know the hole must have been created before the
* min_txg for this traveral, so we can skip it. If
* SPA_FEATURE_HOLE_BIRTH was enabled after the min_txg
* for this traveral we cannot tell if the hole was
* created before or after the min_txg for this
* traversal, so we cannot skip it.
*/
uint64_t hole_birth_enabled_txg;
VERIFY(spa_feature_enabled_txg(td->td_spa,
SPA_FEATURE_HOLE_BIRTH, &hole_birth_enabled_txg));
if (hole_birth_enabled_txg < td->td_min_txg)
return (0);
}
/*
* Since this block has a birth time of 0 it must be a
* hole created before the SPA_FEATURE_HOLE_BIRTH
* feature was enabled. If SPA_FEATURE_HOLE_BIRTH
* was enabled before the min_txg for this traveral we
* know the hole must have been created before the
* min_txg for this traveral, so we can skip it. If
* SPA_FEATURE_HOLE_BIRTH was enabled after the min_txg
* for this traveral we cannot tell if the hole was
* created before or after the min_txg for this
* traversal, so we cannot skip it.
*/
if (td->td_hole_birth_enabled_txg < td->td_min_txg)
return (0);
} else if (bp->blk_birth <= td->td_min_txg) {
return (0);
}
@ -523,6 +519,13 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
td.td_flags = flags;
td.td_paused = B_FALSE;
if (spa_feature_is_active(spa, SPA_FEATURE_HOLE_BIRTH)) {
VERIFY(spa_feature_enabled_txg(spa,
SPA_FEATURE_HOLE_BIRTH, &td.td_hole_birth_enabled_txg));
} else {
td.td_hole_birth_enabled_txg = 0;
}
pd.pd_blks_max = zfs_pd_blks_max;
pd.pd_flags = flags;
mutex_init(&pd.pd_mtx, NULL, MUTEX_DEFAULT, NULL);

View File

@ -2459,10 +2459,38 @@ zvol_geom_start(struct bio *bp)
goto enqueue;
zvol_strategy(bp);
break;
case BIO_GETATTR:
case BIO_GETATTR: {
spa_t *spa = dmu_objset_spa(zv->zv_objset);
uint64_t refd, avail, usedobjs, availobjs, val;
if (g_handleattr_int(bp, "GEOM::candelete", 1))
return;
if (strcmp(bp->bio_attribute, "blocksavail") == 0) {
dmu_objset_space(zv->zv_objset, &refd, &avail,
&usedobjs, &availobjs);
if (g_handleattr_off_t(bp, "blocksavail",
avail / DEV_BSIZE))
return;
} else if (strcmp(bp->bio_attribute, "blocksused") == 0) {
dmu_objset_space(zv->zv_objset, &refd, &avail,
&usedobjs, &availobjs);
if (g_handleattr_off_t(bp, "blocksused",
refd / DEV_BSIZE))
return;
} else if (strcmp(bp->bio_attribute, "poolblocksavail") == 0) {
avail = metaslab_class_get_space(spa_normal_class(spa));
avail -= metaslab_class_get_alloc(spa_normal_class(spa));
if (g_handleattr_off_t(bp, "poolblocksavail",
avail / DEV_BSIZE))
return;
} else if (strcmp(bp->bio_attribute, "poolblocksused") == 0) {
refd = metaslab_class_get_alloc(spa_normal_class(spa));
if (g_handleattr_off_t(bp, "poolblocksused",
refd / DEV_BSIZE))
return;
}
/* FALLTHROUGH */
}
default:
g_io_deliver(bp, EOPNOTSUPP);
break;
@ -2861,6 +2889,30 @@ zvol_d_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct threa
case DIOCGSTRIPEOFFSET:
*(off_t *)data = 0;
break;
case DIOCGATTR: {
spa_t *spa = dmu_objset_spa(zv->zv_objset);
struct diocgattr_arg *arg = (struct diocgattr_arg *)data;
uint64_t refd, avail, usedobjs, availobjs;
if (strcmp(arg->name, "blocksavail") == 0) {
dmu_objset_space(zv->zv_objset, &refd, &avail,
&usedobjs, &availobjs);
arg->value.off = avail / DEV_BSIZE;
} else if (strcmp(arg->name, "blocksused") == 0) {
dmu_objset_space(zv->zv_objset, &refd, &avail,
&usedobjs, &availobjs);
arg->value.off = refd / DEV_BSIZE;
} else if (strcmp(arg->name, "poolblocksavail") == 0) {
avail = metaslab_class_get_space(spa_normal_class(spa));
avail -= metaslab_class_get_alloc(spa_normal_class(spa));
arg->value.off = avail / DEV_BSIZE;
} else if (strcmp(arg->name, "poolblocksused") == 0) {
refd = metaslab_class_get_alloc(spa_normal_class(spa));
arg->value.off = refd / DEV_BSIZE;
} else
error = ENOIOCTL;
break;
}
default:
error = ENOIOCTL;
}

View File

@ -879,12 +879,15 @@ device tun
# The `gif' device implements IPv6 over IP4 tunneling,
# IPv4 over IPv6 tunneling, IPv4 over IPv4 tunneling and
# IPv6 over IPv6 tunneling.
# The `gre' device implements two types of IP4 over IP4 tunneling:
# GRE and MOBILE, as specified in the RFC1701 and RFC2004.
# The `gre' device implements GRE (Generic Routing Encapsulation) tunneling,
# as specified in the RFC 2784 and RFC 2890.
# The `me' device implements Minimal Encapsulation within IPv4 as
# specified in the RFC 2004.
# The XBONEHACK option allows the same pair of addresses to be configured on
# multiple gif interfaces.
device gif
device gre
device me
options XBONEHACK
# The `faith' device captures packets sent to it and diverts them

View File

@ -3234,11 +3234,12 @@ net/if_fddisubr.c optional fddi
net/if_fwsubr.c optional fwip
net/if_gif.c optional gif inet | gif inet6 | \
netgraph_gif inet | netgraph_gif inet6
net/if_gre.c optional gre inet
net/if_gre.c optional gre inet | gre inet6
net/if_iso88025subr.c optional token
net/if_lagg.c optional lagg
net/if_loop.c optional loop
net/if_llatbl.c standard
net/if_me.c optional me inet
net/if_media.c standard
net/if_mib.c standard
net/if_spppfr.c optional sppp | netgraph_sppp
@ -3474,6 +3475,7 @@ netinet6/in6_proto.c optional inet6
netinet6/in6_rmx.c optional inet6
netinet6/in6_src.c optional inet6
netinet6/ip6_forward.c optional inet6
netinet6/ip6_gre.c optional gre inet6
netinet6/ip6_id.c optional inet6
netinet6/ip6_input.c optional inet6
netinet6/ip6_mroute.c optional mrouting inet6

View File

@ -99,11 +99,11 @@ CFLAGS+= -DHAVE_KERNEL_OPTION_HEADERS -include ${KERNBUILDDIR}/opt_global.h
# Add -I paths for system headers. Individual module makefiles don't
# need any -I paths for this. Similar defaults for .PATH can't be
# set because there are no standard paths for non-headers.
CFLAGS+= -I. -I@
CFLAGS+= -I. -I${SYSDIR}
# Add -I path for altq headers as they are included via net/if_var.h
# for example.
CFLAGS+= -I@/contrib/altq
CFLAGS+= -I${SYSDIR}/contrib/altq
CFLAGS.gcc+= -finline-limit=${INLINE_LIMIT}
CFLAGS.gcc+= --param inline-unit-growth=100
@ -132,12 +132,8 @@ CTFFLAGS+= -g
.endif
.if defined(FIRMWS)
.if !exists(@)
${KMOD:S/$/.c/}: @
.else
${KMOD:S/$/.c/}: @/tools/fw_stub.awk
.endif
${AWK} -f @/tools/fw_stub.awk ${FIRMWS} -m${KMOD} -c${KMOD:S/$/.c/g} \
${KMOD:S/$/.c/}: ${SYSDIR}/tools/fw_stub.awk
${AWK} -f ${SYSDIR}/tools/fw_stub.awk ${FIRMWS} -m${KMOD} -c${KMOD:S/$/.c/g} \
${FIRMWARE_LICENSE:C/.+/-l/}${FIRMWARE_LICENSE}
SRCS+= ${KMOD:S/$/.c/}
@ -216,7 +212,7 @@ ${FULLPROG}: ${OBJS}
${OBJCOPY} --strip-debug ${.TARGET}
.endif
_ILINKS=@ machine
_ILINKS=machine
.if ${MACHINE} != ${MACHINE_CPUARCH}
_ILINKS+=${MACHINE_CPUARCH}
.endif
@ -255,8 +251,6 @@ ${.OBJDIR}/${_link}:
@case ${.TARGET:T} in \
machine) \
path=${SYSDIR}/${MACHINE}/include ;; \
@) \
path=${SYSDIR} ;; \
*) \
path=${SYSDIR}/${.TARGET:T}/include ;; \
esac ; \
@ -390,12 +384,8 @@ MFILES?= dev/acpica/acpi_if.m dev/acpi_support/acpi_wmi_if.m \
.for _src in ${SRCS:M${_srcsrc:T:R}.${_ext}}
CLEANFILES+= ${_src}
.if !target(${_src})
.if !exists(@)
${_src}: @
.else
${_src}: @/tools/makeobjops.awk @/${_srcsrc}
.endif
${AWK} -f @/tools/makeobjops.awk @/${_srcsrc} -${_ext}
${_src}: ${SYSDIR}/tools/makeobjops.awk ${SYSDIR}/${_srcsrc}
${AWK} -f ${SYSDIR}/tools/makeobjops.awk ${SYSDIR}/${_srcsrc} -${_ext}
.endif
.endfor # _src
.endfor # _ext
@ -403,70 +393,46 @@ ${_src}: @/tools/makeobjops.awk @/${_srcsrc}
.if !empty(SRCS:Mvnode_if.c)
CLEANFILES+= vnode_if.c
.if !exists(@)
vnode_if.c: @
.else
vnode_if.c: @/tools/vnode_if.awk @/kern/vnode_if.src
.endif
${AWK} -f @/tools/vnode_if.awk @/kern/vnode_if.src -c
vnode_if.c: ${SYSDIR}/tools/vnode_if.awk ${SYSDIR}/kern/vnode_if.src
${AWK} -f ${SYSDIR}/tools/vnode_if.awk ${SYSDIR}/kern/vnode_if.src -c
.endif
.if !empty(SRCS:Mvnode_if.h)
CLEANFILES+= vnode_if.h vnode_if_newproto.h vnode_if_typedef.h
.if !exists(@)
vnode_if.h vnode_if_newproto.h vnode_if_typedef.h: @
.else
vnode_if.h vnode_if_newproto.h vnode_if_typedef.h: @/tools/vnode_if.awk \
@/kern/vnode_if.src
.endif
vnode_if.h vnode_if_newproto.h vnode_if_typedef.h: ${SYSDIR}/tools/vnode_if.awk \
${SYSDIR}/kern/vnode_if.src
vnode_if.h: vnode_if_newproto.h vnode_if_typedef.h
${AWK} -f @/tools/vnode_if.awk @/kern/vnode_if.src -h
${AWK} -f ${SYSDIR}/tools/vnode_if.awk ${SYSDIR}/kern/vnode_if.src -h
vnode_if_newproto.h:
${AWK} -f @/tools/vnode_if.awk @/kern/vnode_if.src -p
${AWK} -f ${SYSDIR}/tools/vnode_if.awk ${SYSDIR}/kern/vnode_if.src -p
vnode_if_typedef.h:
${AWK} -f @/tools/vnode_if.awk @/kern/vnode_if.src -q
${AWK} -f ${SYSDIR}/tools/vnode_if.awk ${SYSDIR}/kern/vnode_if.src -q
.endif
.for _i in mii pccard
.if !empty(SRCS:M${_i}devs.h)
CLEANFILES+= ${_i}devs.h
.if !exists(@)
${_i}devs.h: @
.else
${_i}devs.h: @/tools/${_i}devs2h.awk @/dev/${_i}/${_i}devs
.endif
${AWK} -f @/tools/${_i}devs2h.awk @/dev/${_i}/${_i}devs
${_i}devs.h: ${SYSDIR}/tools/${_i}devs2h.awk ${SYSDIR}/dev/${_i}/${_i}devs
${AWK} -f ${SYSDIR}/tools/${_i}devs2h.awk ${SYSDIR}/dev/${_i}/${_i}devs
.endif
.endfor # _i
.if !empty(SRCS:Musbdevs.h)
CLEANFILES+= usbdevs.h
.if !exists(@)
usbdevs.h: @
.else
usbdevs.h: @/tools/usbdevs2h.awk @/dev/usb/usbdevs
.endif
${AWK} -f @/tools/usbdevs2h.awk @/dev/usb/usbdevs -h
usbdevs.h: ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/usb/usbdevs
${AWK} -f ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/usb/usbdevs -h
.endif
.if !empty(SRCS:Musbdevs_data.h)
CLEANFILES+= usbdevs_data.h
.if !exists(@)
usbdevs_data.h: @
.else
usbdevs_data.h: @/tools/usbdevs2h.awk @/dev/usb/usbdevs
.endif
${AWK} -f @/tools/usbdevs2h.awk @/dev/usb/usbdevs -d
usbdevs_data.h: ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/usb/usbdevs
${AWK} -f ${SYSDIR}/tools/usbdevs2h.awk ${SYSDIR}/dev/usb/usbdevs -d
.endif
.if !empty(SRCS:Macpi_quirks.h)
CLEANFILES+= acpi_quirks.h
.if !exists(@)
acpi_quirks.h: @
.else
acpi_quirks.h: @/tools/acpi_quirks2h.awk @/dev/acpica/acpi_quirks
.endif
${AWK} -f @/tools/acpi_quirks2h.awk @/dev/acpica/acpi_quirks
acpi_quirks.h: ${SYSDIR}/tools/acpi_quirks2h.awk ${SYSDIR}/dev/acpica/acpi_quirks
${AWK} -f ${SYSDIR}/tools/acpi_quirks2h.awk ${SYSDIR}/dev/acpica/acpi_quirks
.endif
.if !empty(SRCS:Massym.s)
@ -475,18 +441,12 @@ assym.s: genassym.o
.if defined(KERNBUILDDIR)
genassym.o: opt_global.h
.endif
.if !exists(@)
assym.s:
.else
assym.s: @/kern/genassym.sh
.endif
sh @/kern/genassym.sh genassym.o > ${.TARGET}
.if exists(@)
genassym.o: @/${MACHINE_CPUARCH}/${MACHINE_CPUARCH}/genassym.c
.endif
assym.s: ${SYSDIR}/kern/genassym.sh
sh ${SYSDIR}/kern/genassym.sh genassym.o > ${.TARGET}
genassym.o: ${SYSDIR}/${MACHINE_CPUARCH}/${MACHINE_CPUARCH}/genassym.c
genassym.o: ${SRCS:Mopt_*.h}
${CC} -c ${CFLAGS:N-fno-common} \
@/${MACHINE_CPUARCH}/${MACHINE_CPUARCH}/genassym.c
${SYSDIR}/${MACHINE_CPUARCH}/${MACHINE_CPUARCH}/genassym.c
.endif
lint: ${SRCS}

View File

@ -217,7 +217,7 @@ ahci_attach(device_t dev)
ctlr->emloc = ATA_INL(ctlr->r_mem, AHCI_EM_LOC);
/* Create controller-wide DMA tag. */
if (bus_dma_tag_create(bus_get_dma_tag(dev), 0, 0,
if (bus_dma_tag_create(bus_get_dma_tag(dev), 1, 0,
(ctlr->caps & AHCI_CAP_64BIT) ? BUS_SPACE_MAXADDR :
BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL,
BUS_SPACE_MAXSIZE, BUS_SPACE_UNRESTRICTED, BUS_SPACE_MAXSIZE,

View File

@ -529,7 +529,7 @@ hv_nv_connect_to_vsp(struct hv_device *device)
int ret = 0;
device_t dev = device->device;
hn_softc_t *sc = device_get_softc(dev);
struct ifnet *ifp = sc->arpcom.ac_ifp;
struct ifnet *ifp = sc->hn_ifp;
net_dev = hv_nv_get_outbound_net_device(device);
if (!net_dev) {

View File

@ -965,7 +965,6 @@ typedef struct {
*/
typedef struct hn_softc {
struct ifnet *hn_ifp;
struct arpcom arpcom;
device_t hn_dev;
uint8_t hn_unit;
int hn_carrier;

View File

@ -255,7 +255,7 @@ netvsc_attach(device_t dev)
sc->hn_dev_obj = device_ctx;
ifp = sc->hn_ifp = sc->arpcom.ac_ifp = if_alloc(IFT_ETHER);
ifp = sc->hn_ifp = if_alloc(IFT_ETHER);
ifp->if_softc = sc;
if_initname(ifp, device_get_name(dev), device_get_unit(dev));
@ -634,8 +634,6 @@ netvsc_recv(struct hv_device *device_ctx, netvsc_packet *packet)
}
ifp = sc->hn_ifp;
ifp = sc->arpcom.ac_ifp;
if (!(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
return (0);

View File

@ -296,7 +296,7 @@ ida_eisa_attach(device_t dev)
error = bus_dma_tag_create(
/* parent */ bus_get_dma_tag(dev),
/* alignment */ 0,
/* alignment */ 1,
/* boundary */ 0,
/* lowaddr */ BUS_SPACE_MAXADDR_32BIT,
/* highaddr */ BUS_SPACE_MAXADDR,

View File

@ -107,6 +107,7 @@ i40e_allocate_dma_mem(struct i40e_hw *hw, struct i40e_dma_mem *mem,
"error %u\n", err);
goto fail_2;
}
mem->nseg = 1;
mem->size = size;
bus_dmamap_sync(mem->tag, mem->map,
BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);

View File

@ -147,8 +147,7 @@ void prefetch(void *x)
#define prefetch(x)
#endif
struct i40e_osdep
{
struct i40e_osdep {
bus_space_tag_t mem_bus_space_tag;
bus_space_handle_t mem_bus_space_handle;
bus_size_t mem_bus_space_size;

View File

@ -40,7 +40,7 @@
/*********************************************************************
* Driver version
*********************************************************************/
char ixl_driver_version[] = "1.2.2";
char ixl_driver_version[] = "1.2.8";
/*********************************************************************
* PCI Device ID Table
@ -109,6 +109,7 @@ static bool ixl_config_link(struct i40e_hw *);
static void ixl_config_rss(struct ixl_vsi *);
static void ixl_set_queue_rx_itr(struct ixl_queue *);
static void ixl_set_queue_tx_itr(struct ixl_queue *);
static int ixl_set_advertised_speeds(struct ixl_pf *, int);
static void ixl_enable_rings(struct ixl_vsi *);
static void ixl_disable_rings(struct ixl_vsi *);
@ -155,6 +156,7 @@ static void ixl_do_adminq(void *, int);
static int ixl_set_flowcntl(SYSCTL_HANDLER_ARGS);
static int ixl_set_advertise(SYSCTL_HANDLER_ARGS);
static int ixl_current_speed(SYSCTL_HANDLER_ARGS);
static int ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS);
/* Statistics */
static void ixl_add_hw_stats(struct ixl_pf *);
@ -176,7 +178,8 @@ static void ixl_stat_update32(struct i40e_hw *, u32, bool,
static int ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS);
static int ixl_sysctl_phy_abilities(SYSCTL_HANDLER_ARGS);
static int ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS);
static int ixl_sysctl_hw_res_info(SYSCTL_HANDLER_ARGS);
static int ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS);
static int ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS);
static int ixl_sysctl_dump_txd(SYSCTL_HANDLER_ARGS);
#endif
@ -276,6 +279,7 @@ int ixl_atr_rate = 20;
TUNABLE_INT("hw.ixl.atr_rate", &ixl_atr_rate);
#endif
static char *ixl_fc_string[6] = {
"None",
"Rx",
@ -398,6 +402,11 @@ ixl_attach(device_t dev)
OID_AUTO, "current_speed", CTLTYPE_STRING | CTLFLAG_RD,
pf, 0, ixl_current_speed, "A", "Current Port Speed");
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "fw_version", CTLTYPE_STRING | CTLFLAG_RD,
pf, 0, ixl_sysctl_show_fw, "A", "Firmware version");
SYSCTL_ADD_INT(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "rx_itr", CTLFLAG_RW,
@ -436,8 +445,13 @@ ixl_attach(device_t dev)
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "hw_res_info", CTLTYPE_STRING | CTLFLAG_RD,
pf, 0, ixl_sysctl_hw_res_info, "A", "HW Resource Allocation");
OID_AUTO, "hw_res_alloc", CTLTYPE_STRING | CTLFLAG_RD,
pf, 0, ixl_sysctl_hw_res_alloc, "A", "HW Resource Allocation");
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
OID_AUTO, "switch_config", CTLTYPE_STRING | CTLFLAG_RD,
pf, 0, ixl_sysctl_switch_config, "A", "HW Switch Configuration");
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
@ -445,7 +459,7 @@ ixl_attach(device_t dev)
pf, 0, ixl_sysctl_dump_txd, "I", "Desc dump");
#endif
/* Save off the information about this board */
/* Save off the PCI information */
hw->vendor_id = pci_get_vendor(dev);
hw->device_id = pci_get_device(dev);
hw->revision_id = pci_read_config(dev, PCIR_REVID, 1);
@ -593,6 +607,7 @@ ixl_attach(device_t dev)
bcopy(hw->mac.addr, hw->mac.perm_addr, ETHER_ADDR_LEN);
i40e_get_port_mac_addr(hw, hw->mac.port_addr);
/* Set up VSI and queues */
if (ixl_setup_stations(pf) != 0) {
device_printf(dev, "setup stations failed!\n");
error = ENOMEM;
@ -630,8 +645,11 @@ ixl_attach(device_t dev)
"an unqualified module was detected\n");
/* Setup OS specific network interface */
if (ixl_setup_interface(dev, vsi) != 0)
if (ixl_setup_interface(dev, vsi) != 0) {
device_printf(dev, "interface setup failed!\n");
error = EIO;
goto err_late;
}
/* Get the bus configuration and set the shared code */
bus = ixl_get_bus_info(hw, dev);
@ -642,25 +660,32 @@ ixl_attach(device_t dev)
ixl_update_stats_counters(pf);
ixl_add_hw_stats(pf);
/* Reset port's advertised speeds */
if (!i40e_is_40G_device(hw->device_id)) {
pf->advertised_speed = 0x7;
ixl_set_advertised_speeds(pf, 0x7);
}
/* Register for VLAN events */
vsi->vlan_attach = EVENTHANDLER_REGISTER(vlan_config,
ixl_register_vlan, vsi, EVENTHANDLER_PRI_FIRST);
vsi->vlan_detach = EVENTHANDLER_REGISTER(vlan_unconfig,
ixl_unregister_vlan, vsi, EVENTHANDLER_PRI_FIRST);
INIT_DEBUGOUT("ixl_attach: end");
return (0);
err_late:
ixl_free_vsi(vsi);
if (vsi->ifp != NULL)
if_free(vsi->ifp);
err_mac_hmc:
i40e_shutdown_lan_hmc(hw);
err_get_cap:
i40e_shutdown_adminq(hw);
err_out:
if (vsi->ifp != NULL)
if_free(vsi->ifp);
ixl_free_pci_resources(pf);
ixl_free_vsi(vsi);
IXL_PF_LOCK_DESTROY(pf);
return (error);
}
@ -725,6 +750,7 @@ ixl_detach(device_t dev)
ether_ifdetach(vsi->ifp);
callout_drain(&pf->timer);
ixl_free_pci_resources(pf);
bus_generic_detach(dev);
if_free(vsi->ifp);
@ -2246,6 +2272,34 @@ early:
return;
}
static void
ixl_add_ifmedia(struct ixl_vsi *vsi, u32 phy_type)
{
/* Display supported media types */
if (phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
if (phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
if (phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
if (phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
}
/*********************************************************************
*
@ -2276,7 +2330,7 @@ ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
ifp->if_ioctl = ixl_ioctl;
#if __FreeBSD_version >= 1100000
#if __FreeBSD_version >= 1100036
if_setgetcounterfn(ifp, ixl_get_counter);
#endif
@ -2286,8 +2340,6 @@ ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
ifp->if_snd.ifq_maxlen = que->num_desc - 2;
ether_ifattach(ifp, hw->mac.addr);
vsi->max_frame_size =
ifp->if_mtu + ETHER_HDR_LEN + ETHER_CRC_LEN
+ ETHER_VLAN_ENCAP_LEN;
@ -2328,40 +2380,26 @@ ixl_setup_interface(device_t dev, struct ixl_vsi *vsi)
ixl_media_status);
aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, TRUE, &abilities_resp, NULL);
if (aq_error) {
printf("Error getting supported media types, AQ error %d\n", aq_error);
return (EPERM);
}
/* Display supported media types */
if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_100BASE_TX))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_100_TX, 0, NULL);
if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_1000BASE_T))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_1000_T, 0, NULL);
if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_CR1_CU) ||
abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SFPP_CU))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_TWINAX, 0, NULL);
if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_SR))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_SR, 0, NULL);
if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_LR))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_LR, 0, NULL);
if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_10GBASE_T))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_10G_T, 0, NULL);
if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4_CU) ||
abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_CR4))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_CR4, 0, NULL);
if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_SR4))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_SR4, 0, NULL);
if (abilities_resp.phy_type & (1 << I40E_PHY_TYPE_40GBASE_LR4))
ifmedia_add(&vsi->media, IFM_ETHER | IFM_40G_LR4, 0, NULL);
if (aq_error == I40E_ERR_UNKNOWN_PHY) {
/* Need delay to detect fiber correctly */
i40e_msec_delay(200);
aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, TRUE, &abilities_resp, NULL);
if (aq_error == I40E_ERR_UNKNOWN_PHY)
device_printf(dev, "Unknown PHY type detected!\n");
else
ixl_add_ifmedia(vsi, abilities_resp.phy_type);
} else if (aq_error) {
device_printf(dev, "Error getting supported media types, err %d,"
" AQ error %d\n", aq_error, hw->aq.asq_last_status);
} else
ixl_add_ifmedia(vsi, abilities_resp.phy_type);
/* Use autoselect media by default */
ifmedia_add(&vsi->media, IFM_ETHER | IFM_AUTO, 0, NULL);
ifmedia_set(&vsi->media, IFM_ETHER | IFM_AUTO);
ether_ifattach(ifp, hw->mac.addr);
return (0);
}
@ -3728,10 +3766,6 @@ ixl_update_stats_counters(struct ixl_pf *pf)
pf->stat_offsets_loaded,
&osd->eth.rx_discards,
&nsd->eth.rx_discards);
ixl_stat_update32(hw, I40E_GLPRT_TDPC(hw->port),
pf->stat_offsets_loaded,
&osd->eth.tx_discards,
&nsd->eth.tx_discards);
ixl_stat_update48(hw, I40E_GLPRT_UPRCH(hw->port),
I40E_GLPRT_UPRCL(hw->port),
pf->stat_offsets_loaded,
@ -3915,8 +3949,8 @@ ixl_do_adminq(void *context, int pending)
u32 reg, loop = 0;
u16 opcode, result;
event.msg_len = IXL_AQ_BUF_SZ;
event.msg_buf = malloc(event.msg_len,
event.buf_len = IXL_AQ_BUF_SZ;
event.msg_buf = malloc(event.buf_len,
M_DEVBUF, M_NOWAIT | M_ZERO);
if (!event.msg_buf) {
printf("Unable to allocate adminq memory\n");
@ -4300,6 +4334,52 @@ ixl_current_speed(SYSCTL_HANDLER_ARGS)
return (error);
}
static int
ixl_set_advertised_speeds(struct ixl_pf *pf, int speeds)
{
struct i40e_hw *hw = &pf->hw;
device_t dev = pf->dev;
struct i40e_aq_get_phy_abilities_resp abilities;
struct i40e_aq_set_phy_config config;
enum i40e_status_code aq_error = 0;
/* Get current capability information */
aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, FALSE, &abilities, NULL);
if (aq_error) {
device_printf(dev, "%s: Error getting phy capabilities %d,"
" aq error: %d\n", __func__, aq_error,
hw->aq.asq_last_status);
return (EAGAIN);
}
/* Prepare new config */
bzero(&config, sizeof(config));
config.phy_type = abilities.phy_type;
config.abilities = abilities.abilities
| I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
config.eee_capability = abilities.eee_capability;
config.eeer = abilities.eeer_val;
config.low_power_ctrl = abilities.d3_lpan;
/* Translate into aq cmd link_speed */
if (speeds & 0x4)
config.link_speed |= I40E_LINK_SPEED_10GB;
if (speeds & 0x2)
config.link_speed |= I40E_LINK_SPEED_1GB;
if (speeds & 0x1)
config.link_speed |= I40E_LINK_SPEED_100MB;
/* Do aq command & restart link */
aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
if (aq_error) {
device_printf(dev, "%s: Error setting new phy config %d,"
" aq error: %d\n", __func__, aq_error,
hw->aq.asq_last_status);
return (EAGAIN);
}
return (0);
}
/*
** Control link advertise speed:
** Flags:
@ -4315,10 +4395,7 @@ ixl_set_advertise(SYSCTL_HANDLER_ARGS)
struct ixl_pf *pf = (struct ixl_pf *)arg1;
struct i40e_hw *hw = &pf->hw;
device_t dev = pf->dev;
struct i40e_aq_get_phy_abilities_resp abilities;
struct i40e_aq_set_phy_config config;
int requested_ls = 0;
enum i40e_status_code aq_error = 0;
int error = 0;
/*
@ -4343,39 +4420,9 @@ ixl_set_advertise(SYSCTL_HANDLER_ARGS)
if (pf->advertised_speed == requested_ls)
return (0);
/* Get current capability information */
aq_error = i40e_aq_get_phy_capabilities(hw, FALSE, FALSE, &abilities, NULL);
if (aq_error) {
device_printf(dev, "%s: Error getting phy capabilities %d,"
" aq error: %d\n", __func__, aq_error,
hw->aq.asq_last_status);
return (EAGAIN);
}
/* Prepare new config */
bzero(&config, sizeof(config));
config.phy_type = abilities.phy_type;
config.abilities = abilities.abilities
| I40E_AQ_PHY_ENABLE_ATOMIC_LINK;
config.eee_capability = abilities.eee_capability;
config.eeer = abilities.eeer_val;
config.low_power_ctrl = abilities.d3_lpan;
/* Translate into aq cmd link_speed */
if (requested_ls & 0x4)
config.link_speed |= I40E_LINK_SPEED_10GB;
if (requested_ls & 0x2)
config.link_speed |= I40E_LINK_SPEED_1GB;
if (requested_ls & 0x1)
config.link_speed |= I40E_LINK_SPEED_100MB;
/* Do aq command & restart link */
aq_error = i40e_aq_set_phy_config(hw, &config, NULL);
if (aq_error) {
device_printf(dev, "%s: Error setting new phy config %d,"
" aq error: %d\n", __func__, aq_error,
hw->aq.asq_last_status);
return (EAGAIN);
}
error = ixl_set_advertised_speeds(pf, requested_ls);
if (error)
return (error);
pf->advertised_speed = requested_ls;
ixl_update_link_status(pf);
@ -4454,6 +4501,26 @@ ixl_get_bus_info(struct i40e_hw *hw, device_t dev)
return (link);
}
static int
ixl_sysctl_show_fw(SYSCTL_HANDLER_ARGS)
{
struct ixl_pf *pf = (struct ixl_pf *)arg1;
struct i40e_hw *hw = &pf->hw;
char buf[32];
snprintf(buf, sizeof(buf),
"f%d.%d a%d.%d n%02x.%02x e%08x",
hw->aq.fw_maj_ver, hw->aq.fw_min_ver,
hw->aq.api_maj_ver, hw->aq.api_min_ver,
(hw->nvm.version & IXL_NVM_VERSION_HI_MASK) >>
IXL_NVM_VERSION_HI_SHIFT,
(hw->nvm.version & IXL_NVM_VERSION_LO_MASK) >>
IXL_NVM_VERSION_LO_SHIFT,
hw->nvm.eetrack);
return (sysctl_handle_string(oidp, buf, strlen(buf), req));
}
#ifdef IXL_DEBUG
static int
ixl_sysctl_link_status(SYSCTL_HANDLER_ARGS)
@ -4563,7 +4630,7 @@ ixl_sysctl_sw_filter_list(SYSCTL_HANDLER_ARGS)
#define IXL_SW_RES_SIZE 0x14
static int
ixl_sysctl_hw_res_info(SYSCTL_HANDLER_ARGS)
ixl_sysctl_hw_res_alloc(SYSCTL_HANDLER_ARGS)
{
struct ixl_pf *pf = (struct ixl_pf *)arg1;
struct i40e_hw *hw = &pf->hw;
@ -4620,7 +4687,120 @@ ixl_sysctl_hw_res_info(SYSCTL_HANDLER_ARGS)
device_printf(dev, "sysctl error: %d\n", error);
sbuf_delete(buf);
return error;
}
/*
** Caller must init and delete sbuf; this function will clear and
** finish it for caller.
*/
static char *
ixl_switch_element_string(struct sbuf *s, u16 seid, bool uplink)
{
sbuf_clear(s);
if (seid == 0 && uplink)
sbuf_cat(s, "Network");
else if (seid == 0)
sbuf_cat(s, "Host");
else if (seid == 1)
sbuf_cat(s, "EMP");
else if (seid <= 5)
sbuf_printf(s, "MAC %d", seid - 2);
else if (seid <= 15)
sbuf_cat(s, "Reserved");
else if (seid <= 31)
sbuf_printf(s, "PF %d", seid - 16);
else if (seid <= 159)
sbuf_printf(s, "VF %d", seid - 32);
else if (seid <= 287)
sbuf_cat(s, "Reserved");
else if (seid <= 511)
sbuf_cat(s, "Other"); // for other structures
else if (seid <= 895)
sbuf_printf(s, "VSI %d", seid - 512);
else if (seid <= 1023)
sbuf_printf(s, "Reserved");
else
sbuf_cat(s, "Invalid");
sbuf_finish(s);
return sbuf_data(s);
}
static int
ixl_sysctl_switch_config(SYSCTL_HANDLER_ARGS)
{
struct ixl_pf *pf = (struct ixl_pf *)arg1;
struct i40e_hw *hw = &pf->hw;
device_t dev = pf->dev;
struct sbuf *buf;
struct sbuf *nmbuf;
int error = 0;
u8 aq_buf[I40E_AQ_LARGE_BUF];
u16 next = 0;
struct i40e_aqc_get_switch_config_resp *sw_config;
sw_config = (struct i40e_aqc_get_switch_config_resp *)aq_buf;
buf = sbuf_new_for_sysctl(NULL, NULL, 0, req);
if (!buf) {
device_printf(dev, "Could not allocate sbuf for sysctl output.\n");
return (ENOMEM);
}
error = i40e_aq_get_switch_config(hw, sw_config,
sizeof(aq_buf), &next, NULL);
if (error) {
device_printf(dev, "%s: aq_get_switch_config() error %d, aq error %d\n",
__func__, error, hw->aq.asq_last_status);
sbuf_delete(buf);
return error;
}
nmbuf = sbuf_new_auto();
if (!nmbuf) {
device_printf(dev, "Could not allocate sbuf for name output.\n");
return (ENOMEM);
}
sbuf_cat(buf, "\n");
// Assuming <= 255 elements in switch
sbuf_printf(buf, "# of elements: %d\n", sw_config->header.num_reported);
/* Exclude:
** Revision -- all elements are revision 1 for now
*/
sbuf_printf(buf,
"SEID ( Name ) | Uplink | Downlink | Conn Type\n"
" | | | (uplink)\n");
for (int i = 0; i < sw_config->header.num_reported; i++) {
// "%4d (%8s) | %8s %8s %#8x",
sbuf_printf(buf, "%4d", sw_config->element[i].seid);
sbuf_cat(buf, " ");
sbuf_printf(buf, "(%8s)", ixl_switch_element_string(nmbuf, sw_config->element[i].seid, false));
sbuf_cat(buf, " | ");
sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].uplink_seid, true));
sbuf_cat(buf, " ");
sbuf_printf(buf, "%8s", ixl_switch_element_string(nmbuf, sw_config->element[i].downlink_seid, false));
sbuf_cat(buf, " ");
sbuf_printf(buf, "%#8x", sw_config->element[i].connection_type);
if (i < sw_config->header.num_reported - 1)
sbuf_cat(buf, "\n");
}
sbuf_delete(nmbuf);
error = sbuf_finish(buf);
if (error) {
device_printf(dev, "Error finishing sbuf: %d\n", error);
sbuf_delete(buf);
return error;
}
error = sysctl_handle_string(oidp, sbuf_data(buf), sbuf_len(buf), req);
if (error)
device_printf(dev, "sysctl error: %d\n", error);
sbuf_delete(buf);
return (error);
}
/*

File diff suppressed because it is too large Load Diff

View File

@ -162,7 +162,9 @@
/*
** Default number of entries in Tx queue buf_ring.
*/
#define DEFAULT_TXBRSZ (4096 * 4096)
#define SMALL_TXBRSZ 4096
/* This may require mbuf cluster tuning */
#define DEFAULT_TXBRSZ (SMALL_TXBRSZ * SMALL_TXBRSZ)
/* Alignment for rings */
#define DBA_ALIGN 128
@ -194,7 +196,7 @@
#define MAX_MULTICAST_ADDR 128
#define IXL_BAR 3
#define IXL_BAR 3
#define IXL_ADM_LIMIT 2
#define IXL_TSO_SIZE 65535
#define IXL_TX_BUF_SZ ((u32) 1514)
@ -208,7 +210,7 @@
#define IXL_ITR_NONE 3
#define IXL_QUEUE_EOL 0x7FF
#define IXL_MAX_FRAME 0x2600
#define IXL_MAX_TX_SEGS 8
#define IXL_MAX_TX_SEGS 8
#define IXL_MAX_TSO_SEGS 66
#define IXL_SPARSE_CHAIN 6
#define IXL_QUEUE_HUNG 0x80000000
@ -292,7 +294,6 @@
#define IXL_SET_NOPROTO(vsi, count) (vsi)->noproto = (count)
#endif
/*
*****************************************************************************
* vendor_info_array
@ -476,6 +477,7 @@ struct ixl_vsi {
struct i40e_eth_stats eth_stats;
struct i40e_eth_stats eth_stats_offsets;
bool stat_offsets_loaded;
/* VSI stat counters */
u64 ipackets;
u64 ierrors;
u64 opackets;
@ -523,7 +525,8 @@ ixl_get_filter(struct ixl_vsi *vsi)
/* create a new empty filter */
f = malloc(sizeof(struct ixl_mac_filter),
M_DEVBUF, M_NOWAIT | M_ZERO);
SLIST_INSERT_HEAD(&vsi->ftl, f, next);
if (f)
SLIST_INSERT_HEAD(&vsi->ftl, f, next);
return (f);
}

View File

@ -238,6 +238,11 @@ ixl_xmit(struct ixl_queue *que, struct mbuf **m_headp)
maxsegs = IXL_MAX_TSO_SEGS;
if (ixl_tso_detect_sparse(m_head)) {
m = m_defrag(m_head, M_NOWAIT);
if (m == NULL) {
m_freem(*m_headp);
*m_headp = NULL;
return (ENOBUFS);
}
*m_headp = m;
}
}
@ -791,6 +796,7 @@ ixl_txeof(struct ixl_queue *que)
mtx_assert(&txr->mtx, MA_OWNED);
/* These are not the descriptors you seek, move along :) */
if (txr->avail == que->num_desc) {
que->busy = 0;
@ -1083,8 +1089,8 @@ int
ixl_init_rx_ring(struct ixl_queue *que)
{
struct rx_ring *rxr = &que->rxr;
#if defined(INET6) || defined(INET)
struct ixl_vsi *vsi = que->vsi;
#if defined(INET6) || defined(INET)
struct ifnet *ifp = vsi->ifp;
struct lro_ctrl *lro = &rxr->lro;
#endif
@ -1186,6 +1192,9 @@ skip_head:
rxr->bytes = 0;
rxr->discard = FALSE;
wr32(vsi->hw, rxr->tail, que->num_desc - 1);
ixl_flush(vsi->hw);
#if defined(INET6) || defined(INET)
/*
** Now set up the LRO interface:
@ -1365,6 +1374,7 @@ ixl_rxeof(struct ixl_queue *que, int count)
IXL_RX_LOCK(rxr);
for (i = rxr->next_check; count != 0;) {
struct mbuf *sendmp, *mh, *mp;
u32 rsc, status, error;
@ -1660,3 +1670,4 @@ ixl_get_counter(if_t ifp, ift_counter cnt)
}
}
#endif

View File

@ -36,11 +36,13 @@
#ifndef _IXLV_H_
#define _IXLV_H_
#define IXLV_AQ_MAX_ERR 100
#include "ixlv_vc_mgr.h"
#define IXLV_AQ_MAX_ERR 1000
#define IXLV_MAX_FILTERS 128
#define IXLV_MAX_QUEUES 16
#define IXLV_AQ_TIMEOUT (1 * hz)
#define IXLV_CALLOUT_TIMO (hz / 50) // 20 msec
#define IXLV_MAX_QUEUES 16
#define IXLV_AQ_TIMEOUT (1 * hz)
#define IXLV_CALLOUT_TIMO (hz / 50) /* 20 msec */
#define IXLV_FLAG_AQ_ENABLE_QUEUES (u32)(1)
#define IXLV_FLAG_AQ_DISABLE_QUEUES (u32)(1 << 1)
@ -51,8 +53,8 @@
#define IXLV_FLAG_AQ_CONFIGURE_QUEUES (u32)(1 << 6)
#define IXLV_FLAG_AQ_MAP_VECTORS (u32)(1 << 7)
#define IXLV_FLAG_AQ_HANDLE_RESET (u32)(1 << 8)
#define IXLV_FLAG_AQ_CONFIGURE_PROMISC (u32)(1 << 9)
#define IXLV_FLAG_AQ_GET_STATS (u32)(1 << 10)
#define IXLV_FLAG_AQ_CONFIGURE_PROMISC (u32)(1 << 9)
#define IXLV_FLAG_AQ_GET_STATS (u32)(1 << 10)
/* printf %b arg */
#define IXLV_FLAGS \
@ -61,6 +63,9 @@
"\7CONFIGURE_QUEUES\10MAP_VECTORS\11HANDLE_RESET" \
"\12CONFIGURE_PROMISC\13GET_STATS"
/* Hack for compatibility with 1.0.x linux pf driver */
#define I40E_VIRTCHNL_OP_EVENT 17
/* Driver state */
enum ixlv_state_t {
IXLV_START,
@ -111,12 +116,10 @@ struct ixlv_sc {
struct ifmedia media;
struct callout timer;
struct callout aq_task;
int msix;
int if_flags;
struct mtx mtx;
struct mtx aq_task_mtx;
u32 qbase;
u32 admvec;
@ -127,10 +130,8 @@ struct ixlv_sc {
struct ixl_vsi vsi;
/* Mac Filter List */
/* Filter lists */
struct mac_list *mac_filters;
/* Vlan Filter List */
struct vlan_list *vlan_filters;
/* Promiscuous mode */
@ -138,11 +139,19 @@ struct ixlv_sc {
/* Admin queue task flags */
u32 aq_wait_count;
u32 aq_required;
u32 aq_pending;
struct ixl_vc_mgr vc_mgr;
struct ixl_vc_cmd add_mac_cmd;
struct ixl_vc_cmd del_mac_cmd;
struct ixl_vc_cmd config_queues_cmd;
struct ixl_vc_cmd map_vectors_cmd;
struct ixl_vc_cmd enable_queues_cmd;
struct ixl_vc_cmd add_vlan_cmd;
struct ixl_vc_cmd del_vlan_cmd;
struct ixl_vc_cmd add_multi_cmd;
struct ixl_vc_cmd del_multi_cmd;
/* Virtual comm channel */
enum i40e_virtchnl_ops current_op;
struct i40e_virtchnl_vf_resource *vf_res;
struct i40e_virtchnl_vsi_resource *vsi_res;
@ -150,16 +159,10 @@ struct ixlv_sc {
u64 watchdog_events;
u64 admin_irq;
/* Signaling channels */
u8 init_done;
u8 config_queues_done;
u8 map_vectors_done;
u8 enable_queues_done;
u8 disable_queues_done;
u8 add_ether_done;
u8 del_ether_done;
u8 aq_buffer[IXL_AQ_BUF_SZ];
};
#define IXLV_CORE_LOCK_ASSERT(sc) mtx_assert(&(sc)->mtx, MA_OWNED)
/*
** This checks for a zero mac addr, something that will be likely
** unless the Admin on the Host has created one.
@ -174,7 +177,7 @@ ixlv_check_ether_addr(u8 *addr)
status = FALSE;
return (status);
}
/*
** VF Common function prototypes
*/
@ -201,5 +204,6 @@ void ixlv_add_vlans(struct ixlv_sc *);
void ixlv_del_vlans(struct ixlv_sc *);
void ixlv_update_stats_counters(struct ixlv_sc *,
struct i40e_eth_stats *);
void ixlv_update_link_status(struct ixlv_sc *);
#endif /* _IXLV_H_ */

76
sys/dev/ixl/ixlv_vc_mgr.h Normal file
View File

@ -0,0 +1,76 @@
/******************************************************************************
Copyright (c) 2013-2014, Intel Corporation
All rights reserved.
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. Neither the name of the Intel Corporation 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.
******************************************************************************/
/*$FreeBSD$*/
#ifndef _IXLV_VC_MGR_H_
#define _IXLV_VC_MGR_H_
#include <sys/queue.h>
struct ixl_vc_cmd;
typedef void ixl_vc_callback_t(struct ixl_vc_cmd *, void *,
enum i40e_status_code);
#define IXLV_VC_CMD_FLAG_BUSY 0x0001
struct ixl_vc_cmd
{
uint32_t request;
uint32_t flags;
ixl_vc_callback_t *callback;
void *arg;
TAILQ_ENTRY(ixl_vc_cmd) next;
};
struct ixl_vc_mgr
{
struct ixlv_sc *sc;
struct ixl_vc_cmd *current;
struct callout callout;
TAILQ_HEAD(, ixl_vc_cmd) pending;
};
#define IXLV_VC_TIMEOUT (2 * hz)
void ixl_vc_init_mgr(struct ixlv_sc *, struct ixl_vc_mgr *);
void ixl_vc_enqueue(struct ixl_vc_mgr *, struct ixl_vc_cmd *,
uint32_t, ixl_vc_callback_t *, void *);
void ixl_vc_flush(struct ixl_vc_mgr *mgr);
#endif

View File

@ -47,6 +47,13 @@
#define IXLV_BUSY_WAIT_DELAY 10
#define IXLV_BUSY_WAIT_COUNT 50
static void ixl_vc_process_resp(struct ixl_vc_mgr *, uint32_t,
enum i40e_status_code);
static void ixl_vc_process_next(struct ixl_vc_mgr *mgr);
static void ixl_vc_schedule_retry(struct ixl_vc_mgr *mgr);
static void ixl_vc_send_current(struct ixl_vc_mgr *mgr);
#ifdef IXL_DEBUG
/*
** Validate VF messages
*/
@ -140,6 +147,7 @@ static int ixl_vc_validate_vf_msg(struct ixlv_sc *sc, u32 v_opcode,
else
return 0;
}
#endif
/*
** ixlv_send_pf_msg
@ -153,16 +161,17 @@ ixlv_send_pf_msg(struct ixlv_sc *sc,
struct i40e_hw *hw = &sc->hw;
device_t dev = sc->dev;
i40e_status err;
int val_err;
#ifdef IXL_DEBUG
/*
** Pre-validating messages to the PF, this might be
** removed for performance later?
** Pre-validating messages to the PF
*/
int val_err;
val_err = ixl_vc_validate_vf_msg(sc, op, msg, len);
if (val_err)
device_printf(dev, "Error validating msg to PF for op %d,"
" msglen %d: error %d\n", op, len, val_err);
#endif
err = i40e_aq_send_msg_to_pf(hw, op, I40E_SUCCESS, msg, len, NULL);
if (err)
@ -198,7 +207,8 @@ ixlv_send_api_ver(struct ixlv_sc *sc)
** initialized. Returns 0 if API versions match, EIO if
** they do not, or I40E_ERR_ADMIN_QUEUE_NO_WORK if the admin queue is empty.
*/
int ixlv_verify_api_ver(struct ixlv_sc *sc)
int
ixlv_verify_api_ver(struct ixlv_sc *sc)
{
struct i40e_virtchnl_version_info *pf_vvi;
struct i40e_hw *hw = &sc->hw;
@ -232,6 +242,8 @@ int ixlv_verify_api_ver(struct ixlv_sc *sc)
if ((enum i40e_virtchnl_ops)le32toh(event.desc.cookie_high) !=
I40E_VIRTCHNL_OP_VERSION) {
DDPRINTF(sc->dev, "Received unexpected op response: %d\n",
le32toh(event.desc.cookie_high));
err = EIO;
goto out_alloc;
}
@ -289,15 +301,15 @@ ixlv_get_vf_config(struct ixlv_sc *sc)
goto out;
}
do {
for (;;) {
err = i40e_clean_arq_element(hw, &event, NULL);
if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) {
if (++retries <= IXLV_AQ_MAX_ERR)
i40e_msec_delay(100);
i40e_msec_delay(10);
} else if ((enum i40e_virtchnl_ops)le32toh(event.desc.cookie_high) !=
I40E_VIRTCHNL_OP_GET_VF_RESOURCES) {
device_printf(dev, "%s: Received a response from PF,"
" opcode %d, error %d\n", __func__,
DDPRINTF(dev, "Received a response from PF,"
" opcode %d, error %d",
le32toh(event.desc.cookie_high),
le32toh(event.desc.cookie_low));
retries++;
@ -312,16 +324,17 @@ ixlv_get_vf_config(struct ixlv_sc *sc)
err = EIO;
goto out_alloc;
}
/* We retrieved the config message, with no errors */
break;
}
if (retries > IXLV_AQ_MAX_ERR) {
INIT_DBG_DEV(dev, "Did not receive response after %d tries.",
retries);
err = ETIMEDOUT;
goto out_alloc;
}
} while (err);
}
memcpy(sc->vf_res, event.msg_buf, min(event.msg_len, len));
i40e_vf_parse_hw_config(hw, sc->vf_res);
@ -345,28 +358,18 @@ ixlv_configure_queues(struct ixlv_sc *sc)
struct ixl_queue *que = vsi->queues;
struct tx_ring *txr;
struct rx_ring *rxr;
int len, pairs;;
int len, pairs;
struct i40e_virtchnl_vsi_queue_config_info *vqci;
struct i40e_virtchnl_queue_pair_info *vqpi;
if (sc->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
/* bail because we already have a command pending */
#ifdef IXL_DEBUG
device_printf(dev, "%s: command %d pending\n",
__func__, sc->current_op);
#endif
return;
}
pairs = vsi->num_queues;
sc->current_op = I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES;
len = sizeof(struct i40e_virtchnl_vsi_queue_config_info) +
(sizeof(struct i40e_virtchnl_queue_pair_info) * pairs);
vqci = malloc(len, M_DEVBUF, M_NOWAIT | M_ZERO);
if (!vqci) {
device_printf(dev, "%s: unable to allocate memory\n", __func__);
ixl_vc_schedule_retry(&sc->vc_mgr);
return;
}
vqci->vsi_id = sc->vsi_res->vsi_id;
@ -375,7 +378,7 @@ ixlv_configure_queues(struct ixlv_sc *sc)
/* Size check is not needed here - HW max is 16 queue pairs, and we
* can fit info for 31 of them into the AQ buffer before it overflows.
*/
for (int i = 0; i < pairs; i++, que++) {
for (int i = 0; i < pairs; i++, que++, vqpi++) {
txr = &que->txr;
rxr = &que->rxr;
vqpi->txq.vsi_id = vqci->vsi_id;
@ -393,14 +396,12 @@ ixlv_configure_queues(struct ixlv_sc *sc)
vqpi->rxq.dma_ring_addr = rxr->dma.pa;
vqpi->rxq.max_pkt_size = vsi->max_frame_size;
vqpi->rxq.databuffer_size = rxr->mbuf_sz;
vqpi++;
vqpi->rxq.splithdr_enabled = 0;
}
ixlv_send_pf_msg(sc, I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES,
(u8 *)vqci, len);
free(vqci, M_DEVBUF);
sc->aq_pending |= IXLV_FLAG_AQ_CONFIGURE_QUEUES;
sc->aq_required &= ~IXLV_FLAG_AQ_CONFIGURE_QUEUES;
}
/*
@ -413,22 +414,11 @@ ixlv_enable_queues(struct ixlv_sc *sc)
{
struct i40e_virtchnl_queue_select vqs;
if (sc->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
/* we already have a command pending */
#ifdef IXL_DEBUG
device_printf(sc->dev, "%s: command %d pending\n",
__func__, sc->current_op);
#endif
return;
}
sc->current_op = I40E_VIRTCHNL_OP_ENABLE_QUEUES;
vqs.vsi_id = sc->vsi_res->vsi_id;
vqs.tx_queues = (1 << sc->vsi_res->num_queue_pairs) - 1;
vqs.rx_queues = vqs.tx_queues;
ixlv_send_pf_msg(sc, I40E_VIRTCHNL_OP_ENABLE_QUEUES,
(u8 *)&vqs, sizeof(vqs));
sc->aq_pending |= IXLV_FLAG_AQ_ENABLE_QUEUES;
sc->aq_required &= ~IXLV_FLAG_AQ_ENABLE_QUEUES;
}
/*
@ -441,22 +431,11 @@ ixlv_disable_queues(struct ixlv_sc *sc)
{
struct i40e_virtchnl_queue_select vqs;
if (sc->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
/* we already have a command pending */
#ifdef IXL_DEBUG
device_printf(sc->dev, "%s: command %d pending\n",
__func__, sc->current_op);
#endif
return;
}
sc->current_op = I40E_VIRTCHNL_OP_DISABLE_QUEUES;
vqs.vsi_id = sc->vsi_res->vsi_id;
vqs.tx_queues = (1 << sc->vsi_res->num_queue_pairs) - 1;
vqs.rx_queues = vqs.tx_queues;
ixlv_send_pf_msg(sc, I40E_VIRTCHNL_OP_DISABLE_QUEUES,
(u8 *)&vqs, sizeof(vqs));
sc->aq_pending |= IXLV_FLAG_AQ_DISABLE_QUEUES;
sc->aq_required &= ~IXLV_FLAG_AQ_DISABLE_QUEUES;
}
/*
@ -473,16 +452,6 @@ ixlv_map_queues(struct ixlv_sc *sc)
struct ixl_vsi *vsi = &sc->vsi;
struct ixl_queue *que = vsi->queues;
if (sc->current_op != I40E_VIRTCHNL_OP_UNKNOWN) {
/* we already have a command pending */
#ifdef IXL_DEBUG
device_printf(sc->dev, "%s: command %d pending\n",
__func__, sc->current_op);
#endif
return;
}
sc->current_op = I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP;
/* How many queue vectors, adminq uses one */
q = sc->msix - 1;
@ -491,6 +460,7 @@ ixlv_map_queues(struct ixlv_sc *sc)
vm = malloc(len, M_DEVBUF, M_NOWAIT);
if (!vm) {
printf("%s: unable to allocate memory\n", __func__);
ixl_vc_schedule_retry(&sc->vc_mgr);
return;
}
@ -501,6 +471,8 @@ ixlv_map_queues(struct ixlv_sc *sc)
vm->vecmap[i].vector_id = i + 1; /* first is adminq */
vm->vecmap[i].txq_map = (1 << que->me);
vm->vecmap[i].rxq_map = (1 << que->me);
vm->vecmap[i].rxitr_idx = 0;
vm->vecmap[i].txitr_idx = 0;
}
/* Misc vector last - this is only for AdminQ messages */
@ -508,12 +480,12 @@ ixlv_map_queues(struct ixlv_sc *sc)
vm->vecmap[i].vector_id = 0;
vm->vecmap[i].txq_map = 0;
vm->vecmap[i].rxq_map = 0;
vm->vecmap[i].rxitr_idx = 0;
vm->vecmap[i].txitr_idx = 0;
ixlv_send_pf_msg(sc, I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP,
(u8 *)vm, len);
free(vm, M_DEVBUF);
sc->aq_pending |= IXLV_FLAG_AQ_MAP_VECTORS;
sc->aq_required &= ~IXLV_FLAG_AQ_MAP_VECTORS;
}
/*
@ -529,11 +501,6 @@ ixlv_add_vlans(struct ixlv_sc *sc)
device_t dev = sc->dev;
int len, i = 0, cnt = 0;
if (sc->current_op != I40E_VIRTCHNL_OP_UNKNOWN)
return;
sc->current_op = I40E_VIRTCHNL_OP_ADD_VLAN;
/* Get count of VLAN filters to add */
SLIST_FOREACH(f, sc->vlan_filters, next) {
if (f->flags & IXL_FILTER_ADD)
@ -541,8 +508,8 @@ ixlv_add_vlans(struct ixlv_sc *sc)
}
if (!cnt) { /* no work... */
sc->aq_required &= ~IXLV_FLAG_AQ_ADD_VLAN_FILTER;
sc->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_VLAN_FILTER,
I40E_SUCCESS);
return;
}
@ -552,6 +519,7 @@ ixlv_add_vlans(struct ixlv_sc *sc)
if (len > IXL_AQ_BUF_SZ) {
device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
__func__);
ixl_vc_schedule_retry(&sc->vc_mgr);
return;
}
@ -559,6 +527,7 @@ ixlv_add_vlans(struct ixlv_sc *sc)
if (!v) {
device_printf(dev, "%s: unable to allocate memory\n",
__func__);
ixl_vc_schedule_retry(&sc->vc_mgr);
return;
}
@ -575,16 +544,17 @@ ixlv_add_vlans(struct ixlv_sc *sc)
if (i == cnt)
break;
}
if (i == 0) { /* Should not happen... */
device_printf(dev, "%s: i == 0?\n", __func__);
return;
}
// ERJ: Should this be taken out?
if (i == 0) { /* Should not happen... */
device_printf(dev, "%s: i == 0?\n", __func__);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_VLAN_FILTER,
I40E_SUCCESS);
return;
}
ixlv_send_pf_msg(sc, I40E_VIRTCHNL_OP_ADD_VLAN, (u8 *)v, len);
free(v, M_DEVBUF);
/* add stats? */
sc->aq_pending |= IXLV_FLAG_AQ_ADD_VLAN_FILTER;
sc->aq_required &= ~IXLV_FLAG_AQ_ADD_VLAN_FILTER;
}
/*
@ -600,11 +570,6 @@ ixlv_del_vlans(struct ixlv_sc *sc)
struct ixlv_vlan_filter *f, *ftmp;
int len, i = 0, cnt = 0;
if (sc->current_op != I40E_VIRTCHNL_OP_UNKNOWN)
return;
sc->current_op = I40E_VIRTCHNL_OP_DEL_VLAN;
/* Get count of VLAN filters to delete */
SLIST_FOREACH(f, sc->vlan_filters, next) {
if (f->flags & IXL_FILTER_DEL)
@ -612,8 +577,8 @@ ixlv_del_vlans(struct ixlv_sc *sc)
}
if (!cnt) { /* no work... */
sc->aq_required &= ~IXLV_FLAG_AQ_DEL_VLAN_FILTER;
sc->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_VLAN_FILTER,
I40E_SUCCESS);
return;
}
@ -623,6 +588,7 @@ ixlv_del_vlans(struct ixlv_sc *sc)
if (len > IXL_AQ_BUF_SZ) {
device_printf(dev, "%s: Exceeded Max AQ Buf size\n",
__func__);
ixl_vc_schedule_retry(&sc->vc_mgr);
return;
}
@ -630,6 +596,7 @@ ixlv_del_vlans(struct ixlv_sc *sc)
if (!v) {
device_printf(dev, "%s: unable to allocate memory\n",
__func__);
ixl_vc_schedule_retry(&sc->vc_mgr);
return;
}
@ -647,16 +614,17 @@ ixlv_del_vlans(struct ixlv_sc *sc)
if (i == cnt)
break;
}
if (i == 0) { /* Should not happen... */
device_printf(dev, "%s: i == 0?\n", __func__);
return;
}
// ERJ: Take this out?
if (i == 0) { /* Should not happen... */
device_printf(dev, "%s: i == 0?\n", __func__);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_VLAN_FILTER,
I40E_SUCCESS);
return;
}
ixlv_send_pf_msg(sc, I40E_VIRTCHNL_OP_DEL_VLAN, (u8 *)v, len);
free(v, M_DEVBUF);
/* add stats? */
sc->aq_pending |= IXLV_FLAG_AQ_DEL_VLAN_FILTER;
sc->aq_required &= ~IXLV_FLAG_AQ_DEL_VLAN_FILTER;
}
@ -673,11 +641,6 @@ ixlv_add_ether_filters(struct ixlv_sc *sc)
device_t dev = sc->dev;
int len, j = 0, cnt = 0;
if (sc->current_op != I40E_VIRTCHNL_OP_UNKNOWN)
return;
sc->current_op = I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS;
/* Get count of MAC addresses to add */
SLIST_FOREACH(f, sc->mac_filters, next) {
if (f->flags & IXL_FILTER_ADD)
@ -685,9 +648,8 @@ ixlv_add_ether_filters(struct ixlv_sc *sc)
}
if (cnt == 0) { /* Should not happen... */
DDPRINTF(dev, "cnt == 0, exiting...");
sc->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
sc->aq_required &= ~IXLV_FLAG_AQ_ADD_MAC_FILTER;
wakeup(&sc->add_ether_done);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_MAC_FILTER,
I40E_SUCCESS);
return;
}
@ -698,6 +660,7 @@ ixlv_add_ether_filters(struct ixlv_sc *sc)
if (a == NULL) {
device_printf(dev, "%s: Failed to get memory for "
"virtchnl_ether_addr_list\n", __func__);
ixl_vc_schedule_retry(&sc->vc_mgr);
return;
}
a->vsi_id = sc->vsi.id;
@ -722,8 +685,6 @@ ixlv_add_ether_filters(struct ixlv_sc *sc)
I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS, (u8 *)a, len);
/* add stats? */
free(a, M_DEVBUF);
sc->aq_pending |= IXLV_FLAG_AQ_ADD_MAC_FILTER;
sc->aq_required &= ~IXLV_FLAG_AQ_ADD_MAC_FILTER;
return;
}
@ -740,11 +701,6 @@ ixlv_del_ether_filters(struct ixlv_sc *sc)
struct ixlv_mac_filter *f, *f_temp;
int len, j = 0, cnt = 0;
if (sc->current_op != I40E_VIRTCHNL_OP_UNKNOWN)
return;
sc->current_op = I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS;
/* Get count of MAC addresses to delete */
SLIST_FOREACH(f, sc->mac_filters, next) {
if (f->flags & IXL_FILTER_DEL)
@ -752,9 +708,8 @@ ixlv_del_ether_filters(struct ixlv_sc *sc)
}
if (cnt == 0) {
DDPRINTF(dev, "cnt == 0, exiting...");
sc->aq_required &= ~IXLV_FLAG_AQ_DEL_MAC_FILTER;
sc->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
wakeup(&sc->del_ether_done);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_MAC_FILTER,
I40E_SUCCESS);
return;
}
@ -765,6 +720,7 @@ ixlv_del_ether_filters(struct ixlv_sc *sc)
if (d == NULL) {
device_printf(dev, "%s: Failed to get memory for "
"virtchnl_ether_addr_list\n", __func__);
ixl_vc_schedule_retry(&sc->vc_mgr);
return;
}
d->vsi_id = sc->vsi.id;
@ -787,8 +743,6 @@ ixlv_del_ether_filters(struct ixlv_sc *sc)
I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS, (u8 *)d, len);
/* add stats? */
free(d, M_DEVBUF);
sc->aq_pending |= IXLV_FLAG_AQ_DEL_MAC_FILTER;
sc->aq_required &= ~IXLV_FLAG_AQ_DEL_MAC_FILTER;
return;
}
@ -806,7 +760,6 @@ ixlv_request_reset(struct ixlv_sc *sc)
*/
wr32(&sc->hw, I40E_VFGEN_RSTAT, I40E_VFR_INPROGRESS);
ixlv_send_pf_msg(sc, I40E_VIRTCHNL_OP_RESET_VF, NULL, 0);
sc->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
}
/*
@ -817,18 +770,11 @@ void
ixlv_request_stats(struct ixlv_sc *sc)
{
struct i40e_virtchnl_queue_select vqs;
int error = 0;
if (sc->current_op != I40E_VIRTCHNL_OP_UNKNOWN)
return;
sc->current_op = I40E_VIRTCHNL_OP_GET_STATS;
vqs.vsi_id = sc->vsi_res->vsi_id;
error = ixlv_send_pf_msg(sc, I40E_VIRTCHNL_OP_GET_STATS,
/* Low priority, we don't need to error check */
ixlv_send_pf_msg(sc, I40E_VIRTCHNL_OP_GET_STATS,
(u8 *)&vqs, sizeof(vqs));
/* Low priority, ok if it fails */
if (error)
sc->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
}
/*
@ -889,10 +835,16 @@ ixlv_vc_completion(struct ixlv_sc *sc,
switch (vpe->event) {
case I40E_VIRTCHNL_EVENT_LINK_CHANGE:
#ifdef IXL_DEBUG
device_printf(dev, "Link change: status %d, speed %d\n",
vpe->event_data.link_event.link_status,
vpe->event_data.link_event.link_speed);
#endif
vsi->link_up =
vpe->event_data.link_event.link_status;
vsi->link_speed =
vpe->event_data.link_event.link_speed;
ixlv_update_link_status(sc);
break;
case I40E_VIRTCHNL_EVENT_RESET_IMPENDING:
device_printf(dev, "PF initiated reset!\n");
@ -908,14 +860,6 @@ ixlv_vc_completion(struct ixlv_sc *sc,
return;
}
if (v_opcode != sc->current_op
&& sc->current_op != I40E_VIRTCHNL_OP_GET_STATS) {
device_printf(dev, "%s: Pending op is %d, received %d.\n",
__func__, sc->current_op, v_opcode);
sc->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
return;
}
/* Catch-all error response */
if (v_retval) {
device_printf(dev,
@ -933,27 +877,35 @@ ixlv_vc_completion(struct ixlv_sc *sc,
ixlv_update_stats_counters(sc, (struct i40e_eth_stats *)msg);
break;
case I40E_VIRTCHNL_OP_ADD_ETHER_ADDRESS:
sc->aq_pending &= ~(IXLV_FLAG_AQ_ADD_MAC_FILTER);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_MAC_FILTER,
v_retval);
if (v_retval) {
device_printf(dev, "WARNING: Error adding VF mac filter!\n");
device_printf(dev, "WARNING: Device may not receive traffic!\n");
}
break;
case I40E_VIRTCHNL_OP_DEL_ETHER_ADDRESS:
sc->aq_pending &= ~(IXLV_FLAG_AQ_DEL_MAC_FILTER);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_MAC_FILTER,
v_retval);
break;
case I40E_VIRTCHNL_OP_CONFIG_PROMISCUOUS_MODE:
sc->aq_pending &= ~(IXLV_FLAG_AQ_CONFIGURE_PROMISC);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIGURE_PROMISC,
v_retval);
break;
case I40E_VIRTCHNL_OP_ADD_VLAN:
sc->aq_pending &= ~(IXLV_FLAG_AQ_ADD_VLAN_FILTER);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ADD_VLAN_FILTER,
v_retval);
break;
case I40E_VIRTCHNL_OP_DEL_VLAN:
sc->aq_pending &= ~(IXLV_FLAG_AQ_DEL_VLAN_FILTER);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DEL_VLAN_FILTER,
v_retval);
break;
case I40E_VIRTCHNL_OP_ENABLE_QUEUES:
sc->aq_pending &= ~(IXLV_FLAG_AQ_ENABLE_QUEUES);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_ENABLE_QUEUES,
v_retval);
if (v_retval == 0) {
/* Update link status */
ixlv_update_link_status(sc);
/* Turn on all interrupts */
ixlv_enable_intr(vsi);
/* And inform the stack we're ready */
@ -962,7 +914,8 @@ ixlv_vc_completion(struct ixlv_sc *sc,
}
break;
case I40E_VIRTCHNL_OP_DISABLE_QUEUES:
sc->aq_pending &= ~(IXLV_FLAG_AQ_DISABLE_QUEUES);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_DISABLE_QUEUES,
v_retval);
if (v_retval == 0) {
/* Turn off all interrupts */
ixlv_disable_intr(vsi);
@ -971,10 +924,12 @@ ixlv_vc_completion(struct ixlv_sc *sc,
}
break;
case I40E_VIRTCHNL_OP_CONFIG_VSI_QUEUES:
sc->aq_pending &= ~(IXLV_FLAG_AQ_CONFIGURE_QUEUES);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_CONFIGURE_QUEUES,
v_retval);
break;
case I40E_VIRTCHNL_OP_CONFIG_IRQ_MAP:
sc->aq_pending &= ~(IXLV_FLAG_AQ_MAP_VECTORS);
ixl_vc_process_resp(&sc->vc_mgr, IXLV_FLAG_AQ_MAP_VECTORS,
v_retval);
break;
default:
device_printf(dev,
@ -982,6 +937,181 @@ ixlv_vc_completion(struct ixlv_sc *sc,
__func__, v_opcode);
break;
}
sc->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
return;
}
static void
ixl_vc_send_cmd(struct ixlv_sc *sc, uint32_t request)
{
switch (request) {
case IXLV_FLAG_AQ_MAP_VECTORS:
ixlv_map_queues(sc);
break;
case IXLV_FLAG_AQ_ADD_MAC_FILTER:
ixlv_add_ether_filters(sc);
break;
case IXLV_FLAG_AQ_ADD_VLAN_FILTER:
ixlv_add_vlans(sc);
break;
case IXLV_FLAG_AQ_DEL_MAC_FILTER:
ixlv_del_ether_filters(sc);
break;
case IXLV_FLAG_AQ_DEL_VLAN_FILTER:
ixlv_del_vlans(sc);
break;
case IXLV_FLAG_AQ_CONFIGURE_QUEUES:
ixlv_configure_queues(sc);
break;
case IXLV_FLAG_AQ_DISABLE_QUEUES:
ixlv_disable_queues(sc);
break;
case IXLV_FLAG_AQ_ENABLE_QUEUES:
ixlv_enable_queues(sc);
break;
}
}
void
ixl_vc_init_mgr(struct ixlv_sc *sc, struct ixl_vc_mgr *mgr)
{
mgr->sc = sc;
mgr->current = NULL;
TAILQ_INIT(&mgr->pending);
callout_init_mtx(&mgr->callout, &sc->mtx, 0);
}
static void
ixl_vc_process_completion(struct ixl_vc_mgr *mgr, enum i40e_status_code err)
{
struct ixl_vc_cmd *cmd;
cmd = mgr->current;
mgr->current = NULL;
cmd->flags &= ~IXLV_VC_CMD_FLAG_BUSY;
cmd->callback(cmd, cmd->arg, err);
ixl_vc_process_next(mgr);
}
static void
ixl_vc_process_resp(struct ixl_vc_mgr *mgr, uint32_t request,
enum i40e_status_code err)
{
struct ixl_vc_cmd *cmd;
cmd = mgr->current;
if (cmd == NULL || cmd->request != request)
return;
callout_stop(&mgr->callout);
ixl_vc_process_completion(mgr, err);
}
static void
ixl_vc_cmd_timeout(void *arg)
{
struct ixl_vc_mgr *mgr = (struct ixl_vc_mgr *)arg;
IXLV_CORE_LOCK_ASSERT(mgr->sc);
ixl_vc_process_completion(mgr, I40E_ERR_TIMEOUT);
}
static void
ixl_vc_cmd_retry(void *arg)
{
struct ixl_vc_mgr *mgr = (struct ixl_vc_mgr *)arg;
IXLV_CORE_LOCK_ASSERT(mgr->sc);
ixl_vc_send_current(mgr);
}
static void
ixl_vc_send_current(struct ixl_vc_mgr *mgr)
{
struct ixl_vc_cmd *cmd;
cmd = mgr->current;
ixl_vc_send_cmd(mgr->sc, cmd->request);
callout_reset(&mgr->callout, IXLV_VC_TIMEOUT, ixl_vc_cmd_timeout, mgr);
}
static void
ixl_vc_process_next(struct ixl_vc_mgr *mgr)
{
struct ixl_vc_cmd *cmd;
if (mgr->current != NULL)
return;
if (TAILQ_EMPTY(&mgr->pending))
return;
cmd = TAILQ_FIRST(&mgr->pending);
TAILQ_REMOVE(&mgr->pending, cmd, next);
mgr->current = cmd;
ixl_vc_send_current(mgr);
}
static void
ixl_vc_schedule_retry(struct ixl_vc_mgr *mgr)
{
callout_reset(&mgr->callout, howmany(hz, 100), ixl_vc_cmd_retry, mgr);
}
void
ixl_vc_enqueue(struct ixl_vc_mgr *mgr, struct ixl_vc_cmd *cmd,
uint32_t req, ixl_vc_callback_t *callback, void *arg)
{
IXLV_CORE_LOCK_ASSERT(mgr->sc);
if (cmd->flags & IXLV_VC_CMD_FLAG_BUSY) {
if (mgr->current == cmd)
mgr->current = NULL;
else
TAILQ_REMOVE(&mgr->pending, cmd, next);
}
cmd->request = req;
cmd->callback = callback;
cmd->arg = arg;
cmd->flags |= IXLV_VC_CMD_FLAG_BUSY;
TAILQ_INSERT_TAIL(&mgr->pending, cmd, next);
ixl_vc_process_next(mgr);
}
void
ixl_vc_flush(struct ixl_vc_mgr *mgr)
{
struct ixl_vc_cmd *cmd;
IXLV_CORE_LOCK_ASSERT(mgr->sc);
KASSERT(TAILQ_EMPTY(&mgr->pending) || mgr->current != NULL,
("ixlv: pending commands waiting but no command in progress"));
cmd = mgr->current;
if (cmd != NULL) {
mgr->current = NULL;
cmd->flags &= ~IXLV_VC_CMD_FLAG_BUSY;
cmd->callback(cmd, cmd->arg, I40E_ERR_ADAPTER_STOPPED);
}
while ((cmd = TAILQ_FIRST(&mgr->pending)) != NULL) {
TAILQ_REMOVE(&mgr->pending, cmd, next);
cmd->flags &= ~IXLV_VC_CMD_FLAG_BUSY;
cmd->callback(cmd, cmd->arg, I40E_ERR_ADAPTER_STOPPED);
}
callout_stop(&mgr->callout);
}

View File

@ -399,11 +399,17 @@ ofwbus_adjust_resource(device_t bus, device_t child __unused, int type,
}
static int
ofwbus_release_resource(device_t bus __unused, device_t child, int type,
ofwbus_release_resource(device_t bus, device_t child, int type,
int rid, struct resource *r)
{
struct resource_list_entry *rle;
int error;
/* Clean resource list entry */
rle = resource_list_find(BUS_GET_RESOURCE_LIST(bus, child), type, rid);
if (rle != NULL)
rle->res = NULL;
if ((rman_get_flags(r) & RF_ACTIVE) != 0) {
error = bus_deactivate_resource(child, type, rid, r);
if (error)

View File

@ -25,6 +25,17 @@
*
*/
/* This implementation of Fortuna is based on the descriptions found in
* ISBN 0-471-22357-3 "Practical Cryptography" by Ferguson and Schneier
* ("K&S").
*
* The above book is superceded by ISBN 978-0-470-47424-2 "Cryptography
* Engineering" by Ferguson, Schneier and Kohno ("FS&K").
*
* This code has not yet caught up with FS&K, but differences are not
* expected to be complex.
*/
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
@ -234,27 +245,26 @@ static void
reseed(uint8_t *junk, u_int length)
{
struct randomdev_hash context;
uint8_t hash[KEYSIZE], temp[KEYSIZE];
uint8_t hash[KEYSIZE];
KASSERT(fortuna_state.minpoolsize > 0, ("random: Fortuna threshold = 0"));
#ifdef _KERNEL
mtx_assert(&random_reseed_mtx, MA_OWNED);
#endif
/* F&S - temp = H(K|s) */
/* F&S - K = Hd(K|s) where Hd(m) is H(H(m)) */
randomdev_hash_init(&context);
#if 0
/* FS&K defines Hd(m) as H(H(0^512|m)) */
randomdev_hash_iterate(&context, zero_region, KEYSIZE);
#endif
randomdev_hash_iterate(&context, &fortuna_state.key, sizeof(fortuna_state.key));
randomdev_hash_iterate(&context, junk, length);
randomdev_hash_finish(&context, temp);
/* F&S - hash = H(temp) */
randomdev_hash_init(&context);
randomdev_hash_iterate(&context, temp, KEYSIZE);
randomdev_hash_finish(&context, hash);
/* F&S - K = hash */
randomdev_encrypt_init(&fortuna_state.key, temp);
memset(temp, 0, sizeof(temp));
randomdev_hash_init(&context);
randomdev_hash_iterate(&context, hash, KEYSIZE);
randomdev_hash_finish(&context, hash);
randomdev_encrypt_init(&fortuna_state.key, hash);
memset(hash, 0, sizeof(hash));
/* Unblock the device if it was blocked due to being unseeded */

View File

@ -61,42 +61,41 @@ static struct live_entropy_source random_ivy = {
};
static inline int
ivy_rng_store(long *buf)
ivy_rng_store(u_long *buf)
{
#ifdef __GNUCLIKE_ASM
long tmp;
u_long rndval;
int retry;
retry = RETRY_COUNT;
__asm __volatile(
"1:\n\t"
"rdrand %2\n\t" /* read randomness into tmp */
"jb 2f\n\t" /* CF is set on success, exit retry loop */
"rdrand %1\n\t" /* read randomness into tmp */
"jc 2f\n\t" /* CF is set on success, exit retry loop */
"dec %0\n\t" /* otherwise, retry-- */
"jne 1b\n\t" /* and loop if retries are not exhausted */
"jmp 3f\n" /* failure, retry is 0, used as return value */
"2:\n\t"
"mov %2,%1\n\t" /* *buf = tmp */
"3:"
: "+q" (retry), "=m" (*buf), "+q" (tmp) : : "cc");
"2:"
: "+r" (retry), "=r" (rndval) : : "cc");
*buf = rndval;
return (retry);
#else /* __GNUCLIKE_ASM */
return (0);
#endif
}
/* It is specifically allowed that buf is a multiple of sizeof(long) */
/* It is required that buf length is a multiple of sizeof(u_long). */
static u_int
random_ivy_read(void *buf, u_int c)
{
long *b;
u_long *b, rndval;
u_int count;
KASSERT(c % sizeof(*b) == 0, ("partial read %d", c));
b = buf;
for (count = c; count > 0; count -= sizeof(*b)) {
if (ivy_rng_store(b++) == 0)
if (ivy_rng_store(&rndval) == 0)
break;
*b++ = rndval;
}
return (c - count);
}
@ -133,4 +132,4 @@ rdrand_modevent(module_t mod, int type, void *unused)
DEV_MODULE(rdrand, rdrand_modevent, NULL);
MODULE_VERSION(rdrand, 1);
MODULE_DEPEND(rdrand, random_adaptors, 1, 1, 1);
MODULE_DEPEND(rdrand, randomdev, 1, 1, 1);

View File

@ -157,4 +157,4 @@ nehemiah_modevent(module_t mod, int type, void *unused)
DEV_MODULE(nehemiah, nehemiah_modevent, NULL);
MODULE_VERSION(nehemiah, 1);
MODULE_DEPEND(nehemiah, random_adaptors, 1, 1, 1);
MODULE_DEPEND(nehemiah, randomdev, 1, 1, 1);

View File

@ -159,15 +159,7 @@ randomdev_modevent(module_t mod __unused, int type, void *data __unused)
return (error);
}
#define EARLY_2_DEV_MODULE(name, evh, arg) \
static moduledata_t name##_mod = { \
#name, \
evh, \
arg \
}; \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_SECOND)
EARLY_2_DEV_MODULE(randomdev, randomdev_modevent, NULL);
DEV_MODULE_ORDERED(randomdev, randomdev_modevent, NULL, SI_ORDER_SECOND);
MODULE_VERSION(randomdev, 1);
/* ================

View File

@ -153,21 +153,13 @@ randomdev_soft_modevent(module_t mod __unused, int type, void *unused __unused)
return (error);
}
#define MID_DEV_MODULE(name, evh, arg) \
static moduledata_t name##_mod = { \
#name, \
evh, \
arg \
}; \
DECLARE_MODULE(name, name##_mod, SI_SUB_DRIVERS, SI_ORDER_MIDDLE)
#if defined(RANDOM_YARROW)
MID_DEV_MODULE(yarrow, randomdev_soft_modevent, NULL);
DEV_MODULE(yarrow, randomdev_soft_modevent, NULL);
MODULE_VERSION(yarrow, 1);
MODULE_DEPEND(yarrow, random_adaptors, 1, 1, 1);
MODULE_DEPEND(yarrow, randomdev, 1, 1, 1);
#endif
#if defined(RANDOM_FORTUNA)
MID_DEV_MODULE(fortuna, randomdev_soft_modevent, NULL);
DEV_MODULE(fortuna, randomdev_soft_modevent, NULL);
MODULE_VERSION(fortuna, 1);
MODULE_DEPEND(fortuna, random_adaptors, 1, 1, 1);
MODULE_DEPEND(fortuna, randomdev, 1, 1, 1);
#endif

View File

@ -210,37 +210,40 @@ spicds_init(struct spicds_info *codec)
snd_mtxlock(codec->lock);
if (codec->type == SPICDS_TYPE_AK4524 ||\
codec->type == SPICDS_TYPE_AK4528) {
/* power off */
spicds_wrcd(codec, AK4524_POWER, 0);
/* set parameter */
spicds_wrcd(codec, AK4524_FORMAT, codec->format);
spicds_wrcd(codec, AK4524_DVC, codec->dvc);
/* power on */
spicds_wrcd(codec, AK4524_POWER, AK452X_POWER_PWDA | AK452X_POWER_PWAD | AK452X_POWER_PWVR);
/* free reset register */
spicds_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD);
/* power off */
spicds_wrcd(codec, AK4524_POWER, 0);
/* set parameter */
spicds_wrcd(codec, AK4524_FORMAT, codec->format);
spicds_wrcd(codec, AK4524_DVC, codec->dvc);
/* power on */
spicds_wrcd(codec, AK4524_POWER,
AK452X_POWER_PWDA | AK452X_POWER_PWAD | AK452X_POWER_PWVR);
/* free reset register */
spicds_wrcd(codec, AK4524_RESET,
AK452X_RESET_RSDA | AK452X_RESET_RSAD);
}
if (codec->type == SPICDS_TYPE_WM8770) {
/* WM8770 init values are taken from ALSA */
/* These come first to reduce init pop noise */
spicds_wrcd(codec, 0x1b, 0x044); /* ADC Mux (AC'97 source) */
spicds_wrcd(codec, 0x1c, 0x00B); /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
spicds_wrcd(codec, 0x1d, 0x009); /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
/* WM8770 init values are taken from ALSA */
spicds_wrcd(codec, 0x18, 0x000); /* All power-up */
/* These come first to reduce init pop noise */
spicds_wrcd(codec, 0x1b, 0x044); /* ADC Mux (AC'97 source) */
spicds_wrcd(codec, 0x1c, 0x00B); /* Out Mux1 (VOUT1 = DAC+AUX, VOUT2 = DAC) */
spicds_wrcd(codec, 0x1d, 0x009); /* Out Mux2 (VOUT2 = DAC, VOUT3 = DAC) */
spicds_wrcd(codec, 0x16, 0x122); /* I2S, normal polarity, 24bit */
spicds_wrcd(codec, 0x17, 0x022); /* 256fs, slave mode */
spicds_wrcd(codec, 0x18, 0x000); /* All power-up */
spicds_wrcd(codec, 0x19, 0x000); /* -12dB ADC/L */
spicds_wrcd(codec, 0x1a, 0x000); /* -12dB ADC/R */
spicds_wrcd(codec, 0x16, 0x122); /* I2S, normal polarity, 24bit */
spicds_wrcd(codec, 0x17, 0x022); /* 256fs, slave mode */
spicds_wrcd(codec, 0x19, 0x000); /* -12dB ADC/L */
spicds_wrcd(codec, 0x1a, 0x000); /* -12dB ADC/R */
}
if (codec->type == SPICDS_TYPE_AK4358)
spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */
if (codec->type == SPICDS_TYPE_AK4358)
spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */
if (codec->type == SPICDS_TYPE_AK4381)
spicds_wrcd(codec, 0x00, 0x8f); /* I2S, 24bit, power-up */
spicds_wrcd(codec, 0x00, 0x8f); /* I2S, 24bit, power-up */
if (codec->type == SPICDS_TYPE_AK4396)
spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */
spicds_wrcd(codec, 0x00, 0x07); /* I2S, 24bit, power-up */
snd_mtxunlock(codec->lock);
}
@ -249,18 +252,18 @@ spicds_reinit(struct spicds_info *codec)
{
snd_mtxlock(codec->lock);
if (codec->type != SPICDS_TYPE_WM8770) {
/* reset */
spicds_wrcd(codec, AK4524_RESET, 0);
/* set parameter */
spicds_wrcd(codec, AK4524_FORMAT, codec->format);
spicds_wrcd(codec, AK4524_DVC, codec->dvc);
/* free reset register */
spicds_wrcd(codec, AK4524_RESET, AK452X_RESET_RSDA | AK452X_RESET_RSAD);
}
else {
/* WM8770 reinit */
/* AK4358 reinit */
/* AK4381 reinit */
/* reset */
spicds_wrcd(codec, AK4524_RESET, 0);
/* set parameter */
spicds_wrcd(codec, AK4524_FORMAT, codec->format);
spicds_wrcd(codec, AK4524_DVC, codec->dvc);
/* free reset register */
spicds_wrcd(codec, AK4524_RESET,
AK452X_RESET_RSDA | AK452X_RESET_RSAD);
} else {
/* WM8770 reinit */
/* AK4358 reinit */
/* AK4381 reinit */
}
snd_mtxunlock(codec->lock);
}
@ -301,11 +304,11 @@ spicds_set(struct spicds_info *codec, int dir, unsigned int left, unsigned int r
case SPICDS_TYPE_WM8770:
right = right + 27;
break;
case SPICDS_TYPE_AK4381:
case SPICDS_TYPE_AK4381:
case SPICDS_TYPE_AK4396:
right = right * 255 / 100;
break;
default:
default:
right = right * 127 / 100;
}
if (dir == PCMDIR_REC && codec->type == SPICDS_TYPE_AK4524) {

View File

@ -470,6 +470,8 @@ static const STRUCT_USB_HOST_ID u3g_devs[] = {
U3G_DEV(QUALCOMMINC, E2003, 0),
U3G_DEV(QUALCOMMINC, K3772_Z, 0),
U3G_DEV(QUALCOMMINC, K3772_Z_INIT, U3GINIT_SCSIEJECT),
U3G_DEV(QUALCOMMINC, MF195E, 0),
U3G_DEV(QUALCOMMINC, MF195E_INIT, U3GINIT_SCSIEJECT),
U3G_DEV(QUALCOMMINC, MF626, 0),
U3G_DEV(QUALCOMMINC, MF628, 0),
U3G_DEV(QUALCOMMINC, MF633R, 0),

View File

@ -3642,6 +3642,8 @@ product QUALCOMMINC E0086 0x0086 3G modem
product QUALCOMMINC SURFSTICK 0x0117 1&1 Surf Stick
product QUALCOMMINC K3772_Z_INIT 0x1179 K3772-Z Initial
product QUALCOMMINC K3772_Z 0x1181 K3772-Z
product QUALCOMMINC MF195E_INIT 0x1514 MF195E initial
product QUALCOMMINC MF195E 0x1516 MF195E
product QUALCOMMINC ZTE_STOR 0x2000 USB ZTE Storage
product QUALCOMMINC E2002 0x2002 3G modem
product QUALCOMMINC E2003 0x2003 3G modem

View File

@ -34,6 +34,7 @@ __FBSDID("$FreeBSD$");
#include <sys/kernel.h>
#include <sys/malloc.h>
#include <sys/module.h>
#include <sys/kdb.h>
#include <sys/lock.h>
#include <sys/mutex.h>
#include <sys/sglist.h>
@ -78,6 +79,11 @@ struct vtcon_port {
int vtcport_id;
int vtcport_flags;
#define VTCON_PORT_FLAG_GONE 0x01
#define VTCON_PORT_FLAG_CONSOLE 0x02
#if defined(KDB)
int vtcport_alt_break_state;
#endif
};
#define VTCON_PORT_LOCK(_port) mtx_lock(&(_port)->vtcport_mtx)
@ -94,17 +100,11 @@ struct vtcon_softc {
device_t vtcon_dev;
struct mtx vtcon_mtx;
uint64_t vtcon_features;
uint32_t vtcon_flags;
#define VTCON_FLAG_DETACHED 0x0001
#define VTCON_FLAG_SIZE 0x0010
#define VTCON_FLAG_MULTIPORT 0x0020
struct task vtcon_ctrl_task;
struct virtqueue *vtcon_ctrl_rxvq;
struct virtqueue *vtcon_ctrl_txvq;
struct mtx vtcon_ctrl_tx_mtx;
uint32_t vtcon_max_ports;
uint32_t vtcon_flags;
#define VTCON_FLAG_DETACHED 0x01
#define VTCON_FLAG_SIZE 0x02
#define VTCON_FLAG_MULTIPORT 0x04
/*
* Ports can be added and removed during runtime, but we have
@ -112,6 +112,11 @@ struct vtcon_softc {
* indexed by the port ID.
*/
struct vtcon_softc_port *vtcon_ports;
struct task vtcon_ctrl_task;
struct virtqueue *vtcon_ctrl_rxvq;
struct virtqueue *vtcon_ctrl_txvq;
struct mtx vtcon_ctrl_tx_mtx;
};
#define VTCON_LOCK(_sc) mtx_lock(&(_sc)->vtcon_mtx)
@ -133,6 +138,7 @@ struct vtcon_softc {
static struct virtio_feature_desc vtcon_feature_desc[] = {
{ VIRTIO_CONSOLE_F_SIZE, "ConsoleSize" },
{ VIRTIO_CONSOLE_F_MULTIPORT, "MultiplePorts" },
{ VIRTIO_CONSOLE_F_EMERG_WRITE, "EmergencyWrite" },
{ 0, NULL }
};
@ -331,10 +337,15 @@ vtcon_attach(device_t dev)
if (sc->vtcon_flags & VTCON_FLAG_MULTIPORT) {
TASK_INIT(&sc->vtcon_ctrl_task, 0, vtcon_ctrl_task_cb, sc);
error = vtcon_ctrl_init(sc);
} else
if (error)
goto fail;
} else {
error = vtcon_port_create(sc, 0);
if (error)
goto fail;
if (error)
goto fail;
if (sc->vtcon_flags & VTCON_FLAG_SIZE)
vtcon_port_update_console_size(sc);
}
error = virtio_setup_intr(dev, INTR_TYPE_TTY);
if (error) {
@ -703,6 +714,7 @@ vtcon_ctrl_port_add_event(struct vtcon_softc *sc, int id)
if (error) {
device_printf(dev, "%s: cannot create port %d: %d\n",
__func__, id, error);
vtcon_ctrl_send_control(sc, id, VIRTIO_CONSOLE_PORT_READY, 0);
return;
}
}
@ -735,9 +747,27 @@ vtcon_ctrl_port_remove_event(struct vtcon_softc *sc, int id)
static void
vtcon_ctrl_port_console_event(struct vtcon_softc *sc, int id)
{
device_t dev;
struct vtcon_softc_port *scport;
struct vtcon_port *port;
device_printf(sc->vtcon_dev, "%s: port %d console event\n",
__func__, id);
dev = sc->vtcon_dev;
scport = &sc->vtcon_ports[id];
VTCON_LOCK(sc);
port = scport->vcsp_port;
if (port == NULL) {
VTCON_UNLOCK(sc);
device_printf(dev, "%s: console port %d, but does not exist\n",
__func__, id);
return;
}
VTCON_PORT_LOCK(port);
VTCON_UNLOCK(sc);
port->vtcport_flags |= VTCON_PORT_FLAG_CONSOLE;
vtcon_port_submit_event(port, VIRTIO_CONSOLE_PORT_OPEN, 1);
VTCON_PORT_UNLOCK(port);
}
static void
@ -1179,8 +1209,14 @@ again:
deq = 0;
while ((buf = virtqueue_dequeue(vq, &len)) != NULL) {
for (i = 0; i < len; i++)
for (i = 0; i < len; i++) {
#if defined(KDB)
if (port->vtcport_flags & VTCON_PORT_FLAG_CONSOLE)
kdb_alt_break(buf[i],
&port->vtcport_alt_break_state);
#endif
ttydisc_rint(tp, buf[i], 0);
}
vtcon_port_requeue_buf(port, buf);
deq++;
}

View File

@ -182,7 +182,6 @@ struct vt_buf {
#define VBF_SCROLL 0x8 /* scroll locked mode. */
#define VBF_HISTORY_FULL 0x10 /* All rows filled. */
unsigned int vb_history_size;
#define VBF_DEFAULT_HISTORY_SIZE 500
int vb_roffset; /* (b) History rows offset. */
int vb_curroffset; /* (b) Saved rows offset. */
term_pos_t vb_cursor; /* (u) Cursor position. */
@ -194,6 +193,12 @@ struct vt_buf {
term_char_t **vb_rows; /* (u) Array of rows */
};
#ifdef SC_HISTORY_SIZE
#define VBF_DEFAULT_HISTORY_SIZE SC_HISTORY_SIZE
#else
#define VBF_DEFAULT_HISTORY_SIZE 500
#endif
void vtbuf_copy(struct vt_buf *, const term_rect_t *, const term_pos_t *);
void vtbuf_fill_locked(struct vt_buf *, const term_rect_t *, term_char_t);
void vtbuf_init_early(struct vt_buf *);

View File

@ -510,6 +510,16 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread
if (error == 0 && *(char *)data == '\0')
error = ENOENT;
break;
case DIOCGATTR: {
struct diocgattr_arg *arg = (struct diocgattr_arg *)data;
if (arg->len > sizeof(arg->value)) {
error = EINVAL;
break;
}
error = g_io_getattr(arg->name, cp, &arg->len, &arg->value);
break;
}
default:
if (cp->provider->geom->ioctl != NULL) {
error = cp->provider->geom->ioctl(cp->provider, cmd, data, fflag, td);

View File

@ -1859,11 +1859,13 @@ fddrop(struct filedesc *fdp)
{
int i;
mtx_lock(&fdesc_mtx);
i = --fdp->fd_holdcnt;
mtx_unlock(&fdesc_mtx);
if (i > 0)
return;
if (fdp->fd_holdcnt > 1) {
mtx_lock(&fdesc_mtx);
i = --fdp->fd_holdcnt;
mtx_unlock(&fdesc_mtx);
if (i > 0)
return;
}
FILEDESC_LOCK_DESTROY(fdp);
uma_zfree(filedesc0_zone, fdp);
@ -2026,7 +2028,7 @@ fdescfree(struct thread *td)
{
struct filedesc0 *fdp0;
struct filedesc *fdp;
struct freetable *ft;
struct freetable *ft, *tft;
struct filedescent *fde;
struct file *fp;
struct vnode *cdir, *jdir, *rdir;
@ -2078,10 +2080,8 @@ fdescfree(struct thread *td)
free(fdp->fd_files, M_FILEDESC);
fdp0 = (struct filedesc0 *)fdp;
while ((ft = SLIST_FIRST(&fdp0->fd_free)) != NULL) {
SLIST_REMOVE_HEAD(&fdp0->fd_free, ft_next);
SLIST_FOREACH_SAFE(ft, &fdp0->fd_free, ft_next, tft)
free(ft->ft_table, M_FILEDESC);
}
if (cdir != NULL)
vrele(cdir);
@ -3406,6 +3406,73 @@ static SYSCTL_NODE(_kern_proc, KERN_PROC_FILEDESC, filedesc,
CTLFLAG_RD|CTLFLAG_MPSAFE, sysctl_kern_proc_filedesc,
"Process filedesc entries");
/*
* Store a process current working directory information to sbuf.
*
* Takes a locked proc as argument, and returns with the proc unlocked.
*/
int
kern_proc_cwd_out(struct proc *p, struct sbuf *sb, ssize_t maxlen)
{
struct filedesc *fdp;
struct export_fd_buf *efbuf;
int error;
PROC_LOCK_ASSERT(p, MA_OWNED);
fdp = fdhold(p);
PROC_UNLOCK(p);
if (fdp == NULL)
return (EINVAL);
efbuf = malloc(sizeof(*efbuf), M_TEMP, M_WAITOK);
efbuf->fdp = fdp;
efbuf->sb = sb;
efbuf->remainder = maxlen;
FILEDESC_SLOCK(fdp);
if (fdp->fd_cdir == NULL)
error = EINVAL;
else {
vref(fdp->fd_cdir);
error = export_vnode_to_sb(fdp->fd_cdir, KF_FD_TYPE_CWD,
FREAD, efbuf);
}
FILEDESC_SUNLOCK(fdp);
fddrop(fdp);
free(efbuf, M_TEMP);
return (error);
}
/*
* Get per-process current working directory.
*/
static int
sysctl_kern_proc_cwd(SYSCTL_HANDLER_ARGS)
{
struct sbuf sb;
struct proc *p;
ssize_t maxlen;
int error, error2, *name;
name = (int *)arg1;
sbuf_new_for_sysctl(&sb, NULL, sizeof(struct kinfo_file), req);
error = pget((pid_t)name[0], PGET_CANDEBUG | PGET_NOTWEXIT, &p);
if (error != 0) {
sbuf_delete(&sb);
return (error);
}
maxlen = req->oldptr != NULL ? req->oldlen : -1;
error = kern_proc_cwd_out(p, &sb, maxlen);
error2 = sbuf_finish(&sb);
sbuf_delete(&sb);
return (error != 0 ? error : error2);
}
static SYSCTL_NODE(_kern_proc, KERN_PROC_CWD, cwd, CTLFLAG_RD|CTLFLAG_MPSAFE,
sysctl_kern_proc_cwd, "Process current working directory");
#ifdef DDB
/*
* For the purposes of debugging, generate a human-readable string for the

Some files were not shown because too many files have changed in this diff Show More