Sync to HEAD@r274297.
This commit is contained in:
commit
a9413f6ca0
@ -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})
|
||||
|
@ -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>
|
||||
|
@ -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 ,
|
||||
|
124
bin/df/df.c
124
bin/df/df.c
@ -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);
|
||||
|
@ -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 .
|
||||
|
@ -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);
|
||||
|
@ -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 '$':
|
||||
|
@ -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)
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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),
|
||||
|
@ -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));
|
||||
|
@ -145,6 +145,8 @@
|
||||
..
|
||||
libnv
|
||||
..
|
||||
libpam
|
||||
..
|
||||
libproc
|
||||
..
|
||||
libutil
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
18
lib/libdpv/Makefile
Normal 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
633
lib/libdpv/dialog_util.c
Normal 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
73
lib/libdpv/dialog_util.h
Normal 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
359
lib/libdpv/dialogrc.c
Normal 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
56
lib/libdpv/dialogrc.h
Normal 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
770
lib/libdpv/dprompt.c
Normal 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
59
lib/libdpv/dprompt.h
Normal 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
510
lib/libdpv/dpv.3
Normal 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
721
lib/libdpv/dpv.c
Normal 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
161
lib/libdpv/dpv.h
Normal 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
66
lib/libdpv/dpv_private.h
Normal 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
111
lib/libdpv/status.c
Normal 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
43
lib/libdpv/status.h
Normal 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
107
lib/libdpv/util.c
Normal 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
50
lib/libdpv/util.h
Normal 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
21
lib/libfigpar/Makefile
Normal 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
251
lib/libfigpar/figpar.3
Normal 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
469
lib/libfigpar/figpar.c
Normal 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
99
lib/libfigpar/figpar.h
Normal 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
309
lib/libfigpar/string_m.c
Normal 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
43
lib/libfigpar/string_m.h
Normal 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_ */
|
@ -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>
|
||||
|
19
lib/libpam/libpam/tests/Makefile
Normal file
19
lib/libpam/libpam/tests/Makefile
Normal 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>
|
@ -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
|
||||
|
@ -4,7 +4,5 @@
|
||||
PROG= fsirand
|
||||
MAN= fsirand.8
|
||||
WARNS?= 3
|
||||
DPADD= ${LIBUTIL}
|
||||
LDADD= -lutil
|
||||
|
||||
.include <bsd.prog.mk>
|
||||
|
@ -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",
|
||||
|
@ -252,6 +252,7 @@ MAN= aac.4 \
|
||||
malo.4 \
|
||||
mcd.4 \
|
||||
md.4 \
|
||||
me.4 \
|
||||
mem.4 \
|
||||
meteor.4 \
|
||||
mfi.4 \
|
||||
|
@ -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
85
share/man/man4/me.4
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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];
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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}
|
||||
|
@ -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,
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
76
sys/dev/ixl/ixlv_vc_mgr.h
Normal 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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
/* ================
|
||||
|
@ -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
|
||||
|
@ -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) {
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
|
@ -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++;
|
||||
}
|
||||
|
@ -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 *);
|
||||
|
@ -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);
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user