update/fix manpage support

. add bsd-style MLINKS to minix man set, restoring aliases
	  (e.g. man add64 -> int64)
	. update daily cron script to run makewhatis and restore makewhatis
	  in man Makefile (makedb), restores functionality of man -k
	. netbsd imports of man, mdocml, makewhatis, libutil, apropos
	. update man.conf with manpage locations, restoring man [-s] <section>
	. throws out some obsolete manpages
This commit is contained in:
Ben Gras 2011-09-26 16:19:29 +00:00
parent 8c9e62b299
commit 0c3983b25a
248 changed files with 29174 additions and 13693 deletions

1
.gitignore vendored
View file

@ -34,3 +34,4 @@ CVS
minix-port.patch minix-port.patch
*.worldstone.log *.worldstone.log
.worldstone* .worldstone*
usr.bin/mdocml/man/*.7

View file

@ -61,12 +61,14 @@ commands: includes libraries
$(MAKE) -C commands all $(MAKE) -C commands all
$(MAKE) -C bin all $(MAKE) -C bin all
$(MAKE) -C usr.bin all $(MAKE) -C usr.bin all
$(MAKE) -C libexec all
dep-all: dep-all:
$(MAKE) CC=cc -C boot dependall $(MAKE) CC=cc -C boot dependall
$(MAKE) -C commands dependall $(MAKE) -C commands dependall
$(MAKE) -C bin dependall $(MAKE) -C bin dependall
$(MAKE) -C usr.bin dependall $(MAKE) -C usr.bin dependall
$(MAKE) -C libexec dependall
$(MAKE) -C kernel dependall $(MAKE) -C kernel dependall
$(MAKE) -C servers dependall $(MAKE) -C servers dependall
$(MAKE) -C drivers dependall $(MAKE) -C drivers dependall
@ -82,10 +84,12 @@ all:
$(MAKE) -C commands all $(MAKE) -C commands all
$(MAKE) -C bin all $(MAKE) -C bin all
$(MAKE) -C usr.bin all $(MAKE) -C usr.bin all
$(MAKE) -C libexec all
$(MAKE) -C tools all $(MAKE) -C tools all
install: install:
$(MAKE) CC=cc -C boot install $(MAKE) CC=cc -C boot install
$(MAKE) -C libexec install
$(MAKE) -C man install makedb $(MAKE) -C man install makedb
$(MAKE) -C commands install $(MAKE) -C commands install
$(MAKE) -C bin install $(MAKE) -C bin install
@ -99,6 +103,7 @@ clean: mkfiles
$(MAKE) -C commands clean $(MAKE) -C commands clean
$(MAKE) -C bin clean $(MAKE) -C bin clean
$(MAKE) -C usr.bin clean $(MAKE) -C usr.bin clean
$(MAKE) -C libexec clean
$(MAKE) -C tools clean $(MAKE) -C tools clean
$(MAKE) -C lib clean_all $(MAKE) -C lib clean_all
$(MAKE) -C test clean $(MAKE) -C test clean
@ -109,4 +114,5 @@ cleandepend: mkfiles
$(MAKE) -C commands cleandepend $(MAKE) -C commands cleandepend
$(MAKE) -C bin cleandepend $(MAKE) -C bin cleandepend
$(MAKE) -C usr.bin cleandepend $(MAKE) -C usr.bin cleandepend
$(MAKE) -C libexec cleandepend
$(MAKE) -C tools cleandepend $(MAKE) -C tools cleandepend

View file

@ -16,8 +16,8 @@ SUBDIR= aal add_route adduser arp ash at autil awk \
hostaddr id ifconfig ifdef install \ hostaddr id ifconfig ifdef install \
intr ipcrm ipcs irdpd isoread join kill last leave \ intr ipcrm ipcs irdpd isoread join kill last leave \
less lex loadkeys loadramdisk logger login look lp \ less lex loadkeys loadramdisk logger login look lp \
lpd ls lspci M mail make MAKEDEV man \ lpd ls lspci M mail make MAKEDEV \
mdb mdocml mesg mined ackmkdep mkfifo mkfs.mfs mknod \ mdb mesg mined ackmkdep mkfifo mkfs.mfs mknod \
mkproto modem mount mt netconf newroot nice acknm nohup \ mkproto modem mount mt netconf newroot nice acknm nohup \
nonamed od passwd paste patch pax \ nonamed od passwd paste patch pax \
ping postinstall poweroff pr prep printf printroot \ ping postinstall poweroff pr prep printf printroot \

View file

@ -1,14 +0,0 @@
# $NetBSD: Makefile,v 1.10 2007/10/05 07:38:52 lukem Exp $
# @(#)Makefile 8.1 (Berkeley) 6/6/93
PROG= man
SRCS= man.c manconf.c
MAN= man.1 man.conf.5
DPADD+= ${LIBMINIXUTIL}
LDADD+= -lminixutil
FILES=man.conf
FILESDIR=/etc
.include <bsd.prog.mk>

View file

@ -1,6 +0,0 @@
_version BSD.2
_subdir man[1-9]
_suffix .0
_build .[1-9] mandoc %s
_build .tbl tbl %s | mandoc
_default /usr/man /usr/pkg/X11R6/man /usr/pkg/man /usr/pkg/gcc44/man

View file

@ -1,43 +0,0 @@
<?xml version='1.0' encoding="utf-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0" >
<xsl:output encoding="utf-8" method="html" indent="yes" doctype-public="-//W3C//DTD HTML 4.01 Transitional//EN" />
<xsl:template match="/changelog">
<html>
<head>
<title>mdocml - CVS-ChangeLog</title>
<link rel="stylesheet" href="index.css" type="text/css" media="all" />
</head>
<body>
<xsl:for-each select="entry">
<div class="clhead">
<xsl:text>Files modified by </xsl:text>
<xsl:value-of select="concat(author, ': ', date, ' (', time, ')')" />
</div>
<div class="clbody">
<strong>
<xsl:text>Note: </xsl:text>
</strong>
<xsl:value-of select="msg"/>
<ul class="clbody">
<xsl:for-each select="file">
<li>
<xsl:value-of select="name"/>
<span class="rev">
<xsl:text> &#8212; Rev: </xsl:text>
<xsl:value-of select="revision"/>
<xsl:text>, Status: </xsl:text>
<xsl:value-of select="cvsstate"/>
<xsl:if test="tag">
<xsl:text>, Tag: </xsl:text>
<xsl:value-of select="tag" />
</xsl:if>
</span>
</li>
</xsl:for-each>
</ul>
</div>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View file

@ -1,36 +0,0 @@
VERSION = 1.10.2
VDATE = 19 June 2010
VFLAGS = -DVERSION="\"$(VERSION)\""
.if ${CC} == gcc
WFLAGS = -W -Wall -Wstrict-prototypes -Wno-unused-parameter -Wwrite-strings
CFLAGS += -g $(WFLAGS) $(VFLAGS) -DHAVE_CONFIG_H
ARFLAGS = rs
.else
CFLAGS += ${VFLAGS} -DHAVE_CONFIG_H
ARFLAGS = r
.endif
# Specify this if you want to hard-code the operating system to appear
# in the lower-left hand corner of -mdoc manuals.
# CFLAGS += -DOSNAME="\"OpenBSD 4.5\""
# Unset this if you don't want Xo/Xc allowing split `It' lines, which
# breaks symmetry.
CFLAGS += -DUGLY
SRCS = main.c mdoc_term.c chars.c term.c tree.c compat.c \
man_term.c html.c mdoc_html.c man_html.c out.c \
term_ps.c term_ascii.c man_macro.c man.c man_hash.c \
man_validate.c man_action.c mandoc.c man_argv.c roff.c \
mdoc_macro.c mdoc.c mdoc_hash.c mdoc_strings.c mdoc_argv.c \
mdoc_validate.c mdoc_action.c lib.c att.c arch.c vol.c \
msec.c st.c
MAN = mandoc.1 mdoc.3 mdoc.7 mandoc_char.7 man.7 man.3 roff.7 roff.3
PROG = mandoc
.include <bsd.prog.mk>

View file

@ -1,446 +0,0 @@
/* $Id: chars.in,v 1.25 2010/06/19 20:46:27 kristaps Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*
* The ASCII translation tables. STRING corresponds to predefined
* strings (cf. mdoc_samples.7 and tmac/mdoc/doc-nroff). CHAR
* corresponds to special characters (cf. groff_char.7). BOTH contains
* sequences that are equivalent in both STRING and CHAR.
*
* Either way, the left-hand side corresponds to the input sequence (\x,
* \(xx, \*(xx and so on) whose length is listed second element. The
* right-hand side is what's produced by the front-end, with the fourth
* element being its length.
*
* XXX - C-escape strings!
* XXX - update LINES_MAX if adding more!
*/
/* Non-breaking, non-collapsing space uses unit separator. */
static const char ascii_nbrsp[2] = { ASCII_NBRSP, 0 };
CHAR_TBL_START
/* Spacing. */
CHAR("c", 1, "", 0, "", 0)
CHAR("0", 1, " ", 1, "&#8194;", 7)
CHAR(" ", 1, " ", 1, "&#8194;", 7)
CHAR("~", 1, ascii_nbrsp, 1, "&#160;", 6)
CHAR("%", 1, "", 0, "", 0)
CHAR("&", 1, "", 0, "", 0)
CHAR("^", 1, "", 0, "", 0)
CHAR("|", 1, "", 0, "", 0)
CHAR("}", 1, "", 0, "", 0)
/* Accents. */
CHAR("a\"", 2, "\"", 1, "&#779;", 6)
CHAR("a-", 2, "-", 1, "&#175;", 6)
CHAR("a.", 2, ".", 1, "&#729;", 6)
CHAR("a^", 2, "^", 1, "&#770;", 6)
BOTH("\'", 1, "\'", 1, "&#769;", 6)
BOTH("aa", 2, "\'", 1, "&#769;", 6)
BOTH("ga", 2, "`", 1, "&#768;", 6)
BOTH("`", 1, "`", 1, "&#768;", 6)
CHAR("ab", 2, "`", 1, "&#774;", 6)
CHAR("ac", 2, ",", 1, "&#807;", 6)
CHAR("ad", 2, "\"", 1, "&#776;", 6)
CHAR("ah", 2, "v", 1, "&#711;", 6)
CHAR("ao", 2, "o", 1, "&#730;", 6)
CHAR("a~", 2, "~", 1, "&#771;", 6)
CHAR("ho", 2, ",", 1, "&#808;", 6)
CHAR("ha", 2, "^", 1, "^", 1)
CHAR("ti", 2, "~", 1, "~", 1)
/* Quotes. */
CHAR("Bq", 2, ",,", 2, "&#8222;", 7)
CHAR("bq", 2, ",", 1, "&#8218;", 7)
BOTH("lq", 2, "``", 2, "&#8220;", 7)
BOTH("rq", 2, "\'\'", 2, "&#8221;", 7)
CHAR("oq", 2, "`", 1, "&#8216;", 7)
CHAR("cq", 2, "\'", 1, "&#8217;", 7)
CHAR("aq", 2, "\'", 1, "\'", 1)
CHAR("dq", 2, "\"", 1, "\"", 1)
CHAR("Fo", 2, "<<", 2, "&#171;", 6)
CHAR("Fc", 2, ">>", 2, "&#187;", 6)
CHAR("fo", 2, "<", 1, "&#8249;", 7)
CHAR("fc", 2, ">", 1, "&#8250;", 7)
/* Brackets. */
CHAR("lB", 2, "[", 1, "[", 1)
CHAR("rB", 2, "]", 1, "]", 1)
CHAR("lC", 2, "{", 1, "{", 1)
CHAR("rC", 2, "}", 1, "}", 1)
CHAR("la", 2, "<", 1, "&#10216;", 8)
CHAR("ra", 2, ">", 1, "&#10217;", 8)
CHAR("bv", 2, "|", 1, "&#9130;", 7)
CHAR("braceex", 7, "|", 1, "&#9130;", 7)
CHAR("bracketlefttp", 13, "|", 1, "&#9121;", 7)
CHAR("bracketleftbp", 13, "|", 1, "&#9123;", 7)
CHAR("bracketleftex", 13, "|", 1, "&#9122;", 7)
CHAR("bracketrighttp", 14, "|", 1, "&#9124;", 7)
CHAR("bracketrightbp", 14, "|", 1, "&#9126;", 7)
CHAR("bracketrightex", 14, "|", 1, "&#9125;", 7)
CHAR("lt", 2, ",-", 2, "&#9127;", 7)
CHAR("bracelefttp", 11, ",-", 2, "&#9127;", 7)
CHAR("lk", 2, "{", 1, "&#9128;", 7)
CHAR("braceleftmid", 12, "{", 1, "&#9128;", 7)
CHAR("lb", 2, ",-", 2, "&#9129;", 7)
CHAR("braceleftbp", 11, "`-", 2, "&#9129;", 7)
CHAR("braceleftex", 11, "|", 1, "&#9130;", 7)
CHAR("rt", 2, "-.", 2, "&#9131;", 7)
CHAR("bracerighttp", 12, "-.", 2, "&#9131;", 7)
CHAR("rk", 2, "}", 1, "&#9132;", 7)
CHAR("bracerightmid", 13, "}", 1, "&#9132;", 7)
CHAR("rb", 2, "-\'", 2, "&#9133;", 7)
CHAR("bracerightbp", 12, "-\'", 2, "&#9133;", 7)
CHAR("bracerightex", 12, "|", 1, "&#9130;", 7)
CHAR("parenlefttp", 11, "/", 1, "&#9115;", 7)
CHAR("parenleftbp", 11, "\\", 1, "&#9117;", 7)
CHAR("parenleftex", 11, "|", 1, "&#9116;", 7)
CHAR("parenrighttp", 12, "\\", 1, "&#9118;", 7)
CHAR("parenrightbp", 12, "/", 1, "&#9120;", 7)
CHAR("parenrightex", 12, "|", 1, "&#9119;", 7)
/* Greek characters. */
CHAR("*A", 2, "A", 1, "&#913;", 6)
CHAR("*B", 2, "B", 1, "&#914;", 6)
CHAR("*G", 2, "|", 1, "&#915;", 6)
CHAR("*D", 2, "/\\", 2, "&#916;", 6)
CHAR("*E", 2, "E", 1, "&#917;", 6)
CHAR("*Z", 2, "Z", 1, "&#918;", 6)
CHAR("*Y", 2, "H", 1, "&#919;", 6)
CHAR("*H", 2, "O", 1, "&#920;", 6)
CHAR("*I", 2, "I", 1, "&#921;", 6)
CHAR("*K", 2, "K", 1, "&#922;", 6)
CHAR("*L", 2, "/\\", 2, "&#923;", 6)
CHAR("*M", 2, "M", 1, "&#924;", 6)
CHAR("*N", 2, "N", 1, "&#925;", 6)
CHAR("*C", 2, "H", 1, "&#926;", 6)
CHAR("*O", 2, "O", 1, "&#927;", 6)
CHAR("*P", 2, "TT", 2, "&#928;", 6)
CHAR("*R", 2, "P", 1, "&#929;", 6)
CHAR("*S", 2, ">", 1, "&#931;", 6)
CHAR("*T", 2, "T", 1, "&#932;", 6)
CHAR("*U", 2, "Y", 1, "&#933;", 6)
CHAR("*F", 2, "O_", 1, "&#934;", 6)
CHAR("*X", 2, "X", 1, "&#935;", 6)
CHAR("*Q", 2, "Y", 1, "&#936;", 6)
CHAR("*W", 2, "O", 1, "&#937;", 6)
CHAR("*a", 2, "a", 1, "&#945;", 6)
CHAR("*b", 2, "B", 1, "&#946;", 6)
CHAR("*g", 2, "y", 1, "&#947;", 6)
CHAR("*d", 2, "d", 1, "&#948;", 6)
CHAR("*e", 2, "e", 1, "&#949;", 6)
CHAR("*z", 2, "C", 1, "&#950;", 6)
CHAR("*y", 2, "n", 1, "&#951;", 6)
CHAR("*h", 2, "0", 1, "&#952;", 6)
CHAR("*i", 2, "i", 1, "&#953;", 6)
CHAR("*k", 2, "k", 1, "&#954;", 6)
CHAR("*l", 2, "\\", 1, "&#955;", 6)
CHAR("*m", 2, "u", 1, "&#956;", 6)
CHAR("*n", 2, "v", 1, "&#957;", 6)
CHAR("*c", 2, "E", 1, "&#958;", 6)
CHAR("*o", 2, "o", 1, "&#959;", 6)
CHAR("*p", 2, "n", 1, "&#960;", 6)
CHAR("*r", 2, "p", 1, "&#961;", 6)
CHAR("*s", 2, "o", 1, "&#963;", 6)
CHAR("*t", 2, "t", 1, "&#964;", 6)
CHAR("*u", 2, "u", 1, "&#965;", 6)
CHAR("*f", 2, "o", 1, "&#981;", 6)
CHAR("*x", 2, "x", 1, "&#967;", 6)
CHAR("*q", 2, "u", 1, "&#968;", 6)
CHAR("*w", 2, "w", 1, "&#969;", 6)
CHAR("+h", 2, "0", 1, "&#977;", 6)
CHAR("+f", 2, "o", 1, "&#966;", 6)
CHAR("+p", 2, "w", 1, "&#982;", 6)
CHAR("+e", 2, "e", 1, "&#1013;", 7)
CHAR("ts", 2, "s", 1, "&#962;", 6)
/* Accented letters. */
CHAR(",C", 2, "C", 1, "&#199;", 6)
CHAR(",c", 2, "c", 1, "&#231;", 6)
CHAR("/L", 2, "L", 1, "&#321;", 6)
CHAR("/O", 2, "O", 1, "&#216;", 6)
CHAR("/l", 2, "l", 1, "&#322;", 6)
CHAR("/o", 2, "o", 1, "&#248;", 6)
CHAR("oA", 2, "A", 1, "&#197;", 6)
CHAR("oa", 2, "a", 1, "&#229;", 6)
CHAR(":A", 2, "A", 1, "&#196;", 6)
CHAR(":E", 2, "E", 1, "&#203;", 6)
CHAR(":I", 2, "I", 1, "&#207;", 6)
CHAR(":O", 2, "O", 1, "&#214;", 6)
CHAR(":U", 2, "U", 1, "&#220;", 6)
CHAR(":a", 2, "a", 1, "&#228;", 6)
CHAR(":e", 2, "e", 1, "&#235;", 6)
CHAR(":i", 2, "i", 1, "&#239;", 6)
CHAR(":o", 2, "o", 1, "&#245;", 6)
CHAR(":u", 2, "u", 1, "&#252;", 6)
CHAR(":y", 2, "y", 1, "&#255;", 6)
CHAR("\'A", 2, "A", 1, "&#193;", 6)
CHAR("\'E", 2, "E", 1, "&#201;", 6)
CHAR("\'I", 2, "I", 1, "&#205;", 6)
CHAR("\'O", 2, "O", 1, "&#211;", 6)
CHAR("\'U", 2, "U", 1, "&#218;", 6)
CHAR("\'a", 2, "a", 1, "&#225;", 6)
CHAR("\'e", 2, "e", 1, "&#233;", 6)
CHAR("\'i", 2, "i", 1, "&#237;", 6)
CHAR("\'o", 2, "o", 1, "&#243;", 6)
CHAR("\'u", 2, "u", 1, "&#250;", 6)
CHAR("^A", 2, "A", 1, "&#194;", 6)
CHAR("^E", 2, "E", 1, "&#202;", 6)
CHAR("^I", 2, "I", 1, "&#206;", 6)
CHAR("^O", 2, "O", 1, "&#212;", 6)
CHAR("^U", 2, "U", 1, "&#219;", 6)
CHAR("^a", 2, "a", 1, "&#226;", 6)
CHAR("^e", 2, "e", 1, "&#234;", 6)
CHAR("^i", 2, "i", 1, "&#238;", 6)
CHAR("^o", 2, "o", 1, "&#244;", 6)
CHAR("^u", 2, "u", 1, "&#251;", 6)
CHAR("`A", 2, "A", 1, "&#192;", 6)
CHAR("`E", 2, "E", 1, "&#200;", 6)
CHAR("`I", 2, "I", 1, "&#204;", 6)
CHAR("`O", 2, "O", 1, "&#210;", 6)
CHAR("`U", 2, "U", 1, "&#217;", 6)
CHAR("`a", 2, "a", 1, "&#224;", 6)
CHAR("`e", 2, "e", 1, "&#232;", 6)
CHAR("`i", 2, "i", 1, "&#236;", 6)
CHAR("`o", 2, "o", 1, "&#242;", 6)
CHAR("`u", 2, "u", 1, "&#249;", 6)
CHAR("~A", 2, "A", 1, "&#195;", 6)
CHAR("~N", 2, "N", 1, "&#209;", 6)
CHAR("~O", 2, "O", 1, "&#213;", 6)
CHAR("~a", 2, "a", 1, "&#227;", 6)
CHAR("~n", 2, "n", 1, "&#241;", 6)
CHAR("~o", 2, "o", 1, "&#245;", 6)
/* Arrows and lines. */
CHAR("<-", 2, "<-", 2, "&#8592;", 7)
CHAR("->", 2, "->", 2, "&#8594;", 7)
CHAR("<>", 2, "<>", 2, "&#8596;", 7)
CHAR("da", 2, "v", 1, "&#8595;", 7)
BOTH("ua", 2, "^", 1, "&#8593;", 7)
BOTH("va", 2, "^v", 2, "&#8597;", 7)
CHAR("lA", 2, "<=", 2, "&#8656;", 7)
CHAR("rA", 2, "=>", 2, "&#8658;", 7)
CHAR("hA", 2, "<=>", 3, "&#8660;", 7)
CHAR("dA", 2, "v", 1, "&#8659;", 7)
CHAR("uA", 2, "^", 1, "&#8657;", 7)
CHAR("vA", 2, "^=v", 3, "&#8661;", 7)
/* Logic. */
CHAR("AN", 2, "^", 1, "&#8743;", 7)
CHAR("OR", 2, "v", 1, "&#8744;", 7)
CHAR("no", 2, "~", 1, "&#172;", 6)
CHAR("tno", 3, "~", 1, "&#172;", 6)
CHAR("te", 2, "3", 1, "&#8707;", 7)
CHAR("fa", 2, "V", 1, "&#8704;", 7)
CHAR("st", 2, "-)", 2, "&#8715;", 7)
CHAR("tf", 2, ".:.", 3, "&#8756;", 7)
CHAR("3d", 2, ".:.", 3, "&#8756;", 7)
CHAR("or", 2, "|", 1, "|", 1)
/* Mathematicals. */
CHAR("pl", 2, "+", 1, "&#43;", 5)
CHAR("mi", 2, "-", 1, "&#8722;", 7)
CHAR("-", 1, "-", 1, "-", 1)
CHAR("-+", 2, "-+", 2, "&#8723;", 7)
CHAR("+-", 2, "+-", 2, "&#177;", 6)
CHAR("t+-", 3, "+-", 2, "&#177;", 6)
CHAR("pc", 2, ".", 1, "&#183;", 6)
CHAR("md", 2, ".", 1, "&#8901;", 7)
CHAR("mu", 2, "x", 1, "&#215;", 6)
CHAR("tmu", 3, "x", 1, "&#215;", 6)
CHAR("c*", 2, "x", 1, "&#8855;", 7)
CHAR("c+", 2, "+", 1, "&#8853;", 7)
CHAR("di", 2, "-:-", 3, "&#247;", 6)
CHAR("tdi", 3, "-:-", 3, "&#247;", 6)
CHAR("f/", 2, "/", 1, "&#8260;", 7)
CHAR("**", 2, "*", 1, "&#8727;", 7)
BOTH("<=", 2, "<=", 2, "&#8804;", 7)
BOTH(">=", 2, ">=", 2, "&#8805;", 7)
CHAR("<<", 2, "<<", 2, "&#8810;", 7)
CHAR(">>", 2, ">>", 2, "&#8811;", 7)
CHAR("eq", 2, "=", 1, "&#61;", 5)
CHAR("!=", 2, "!=", 2, "&#8800;", 7)
CHAR("==", 2, "==", 2, "&#8801;", 7)
CHAR("ne", 2, "!==", 3, "&#8802;", 7)
CHAR("=~", 2, "=~", 2, "&#8773;", 7)
CHAR("-~", 2, "-~", 2, "&#8771;", 7)
CHAR("ap", 2, "~", 1, "&#8764;", 7)
CHAR("~~", 2, "~~", 2, "&#8776;", 7)
CHAR("~=", 2, "~=", 2, "&#8780;", 7)
CHAR("pt", 2, "oc", 2, "&#8733;", 7)
CHAR("es", 2, "{}", 2, "&#8709;", 7)
CHAR("mo", 2, "E", 1, "&#8712;", 7)
CHAR("nm", 2, "!E", 2, "&#8713;", 7)
CHAR("sb", 2, "(=", 2, "&#8834;", 7)
CHAR("nb", 2, "(!=", 3, "&#8836;", 7)
CHAR("sp", 2, "=)", 2, "&#8835;", 7)
CHAR("nc", 2, "!=)", 3, "&#8837;", 7)
CHAR("ib", 2, "(=", 2, "&#8838;", 7)
CHAR("ip", 2, "=)", 2, "&#8839;", 7)
CHAR("ca", 2, "(^)", 3, "&#8745;", 7)
CHAR("cu", 2, "U", 1, "&#8746;", 7)
CHAR("/_", 2, "/_", 2, "&#8736;", 7)
CHAR("pp", 2, "_|_", 3, "&#8869;", 7)
CHAR("is", 2, "I", 1, "&#8747;", 7)
CHAR("integral", 8, "I", 1, "&#8747;", 7)
CHAR("sum", 3, "E", 1, "&#8721;", 7)
CHAR("product", 7, "TT", 2, "&#8719;", 7)
CHAR("coproduct", 9, "U", 1, "&#8720;", 7)
CHAR("gr", 2, "V", 1, "&#8711;", 7)
CHAR("sr", 2, "\\/", 2, "&#8730;", 7)
CHAR("sqrt", 4, "\\/", 2, "&#8730;", 7)
CHAR("lc", 2, "|~", 2, "&#8968;", 7)
CHAR("rc", 2, "~|", 2, "&#8969;", 7)
CHAR("lf", 2, "|_", 2, "&#8970;", 7)
CHAR("rf", 2, "_|", 2, "&#8971;", 7)
CHAR("if", 2, "oo", 2, "&#8734;", 7)
CHAR("Ah", 2, "N", 1, "&#8501;", 7)
CHAR("Im", 2, "I", 1, "&#8465;", 7)
CHAR("Re", 2, "R", 1, "&#8476;", 7)
CHAR("pd", 2, "a", 1, "&#8706;", 7)
CHAR("-h", 2, "/h", 2, "&#8463;", 7)
/* Ligatures. */
CHAR("ff", 2, "ff", 2, "&#64256;", 8)
CHAR("fi", 2, "fi", 2, "&#64257;", 8)
CHAR("fl", 2, "fl", 2, "&#64258;", 8)
CHAR("Fi", 2, "ffi", 3, "&#64259;", 8)
CHAR("Fl", 2, "ffl", 3, "&#64260;", 8)
BOTH("AE", 2, "AE", 2, "&#198;", 6)
BOTH("ae", 2, "ae", 2, "&#230;", 6)
CHAR("OE", 2, "OE", 2, "&#338;", 6)
CHAR("oe", 2, "oe", 2, "&#339;", 6)
CHAR("ss", 2, "ss", 2, "&#223;", 6)
CHAR("IJ", 2, "IJ", 2, "&#306;", 6)
CHAR("ij", 2, "ij", 2, "&#307;", 6)
/* Special letters. */
CHAR("-D", 2, "D", 1, "&#208;", 6)
CHAR("Sd", 2, "o", 1, "&#240;", 6)
CHAR("TP", 2, "b", 1, "&#222;", 6)
CHAR("Tp", 2, "b", 1, "&#254;", 6)
CHAR(".i", 2, "i", 1, "&#305;", 6)
CHAR(".j", 2, "j", 1, "&#567;", 6)
/* Currency. */
CHAR("Do", 2, "$", 1, "$", 1)
CHAR("ct", 2, "c", 1, "&#162;", 6)
CHAR("Eu", 2, "EUR", 3, "&#8364;", 7)
CHAR("eu", 2, "EUR", 3, "&#8364;", 7)
CHAR("Ye", 2, "Y", 1, "&#165;", 6)
CHAR("Po", 2, "L", 1, "&#163;", 6)
CHAR("Cs", 2, "x", 1, "&#164;", 6)
CHAR("Fn", 2, "f", 1, "&#402;", 6)
/* pod2man holdovers. */
STRING("--", 2, "--", 2, "&#8212;", 7)
STRING("PI", 2, "pi", 2, "&#960;", 6)
STRING("L\"", 2, "``", 2, "&#8220;", 7)
STRING("R\"", 2, "\'\'", 2, "&#8221;", 7)
STRING("C+", 2, "C++", 3, "C++", 3)
STRING("C`", 2, "`", 1, "&#8216;", 7)
STRING("C\'", 2, "\'", 1, "&#8217;", 7)
STRING("Aq", 2, "\'", 1, "\'", 1)
STRING("^", 1, "^", 1, "^", 1)
STRING(",", 1, ",", 1, ",", 1)
STRING("~", 1, "~", 1, "~", 1)
STRING("/", 1, "/", 1, "/", 1)
STRING(":", 1, "\"", 1, "&#776;", 6)
STRING("8", 1, "B", 1, "&#946;", 6)
STRING("o", 1, "o", 1, "&#176;", 6)
STRING("D-", 2, "D", 1, "&#208;", 6)
STRING("d-", 2, "o", 1, "&#240;", 6)
STRING("Th", 2, "b", 1, "&#222;", 6)
STRING("th", 2, "b", 1, "&#254;", 6)
/* Old style. */
STRING("Am", 2, "&", 1, "&amp;", 5)
STRING("Ba", 2, "|", 1, "|", 1)
STRING("Ge", 2, ">=", 2, "&#8805;", 7)
STRING("Gt", 2, ">", 1, "&gt;", 4)
STRING("If", 2, "infinity", 8, "infinity", 8)
STRING("Le", 2, "<=", 2, "&#8804;", 7)
STRING("Lq", 2, "``", 2, "&#8220;", 7)
STRING("Lt", 2, "<", 1, "&lt;", 4)
STRING("Na", 2, "NaN", 3, "NaN", 3)
STRING("Ne", 2, "!=", 2, "&#8800;", 7)
STRING("Pi", 2, "pi", 2, "&#960;", 6)
STRING("Pm", 2, "+-", 2, "&#177;", 6)
STRING("R", 1, "(R)", 3, "&#174;", 6)
STRING("Rq", 2, "\'\'", 2, "&#8221;", 7)
STRING("Tm", 2, "tm", 2, "&#8482;", 7)
STRING("left-bracket", 12, "[", 1, "[", 1)
STRING("left-parenthesis", 16, "(", 1, "(", 1)
STRING("left-singlequote", 16, "`", 1, "&#8216;", 7)
STRING("lp", 2, "(", 1, "(", 1)
STRING("q", 1, "\"", 1, "&quot;", 6)
STRING("quote-left", 10, "`", 1, "&#8216;", 7)
STRING("quote-right", 11, "\'", 1, "&#8217;", 7)
STRING("right-bracket", 13, "]", 1, "]", 1)
STRING("right-parenthesis", 17, ")", 1, ")", 1)
STRING("right-singlequote", 17, "\'", 1, "&#8217;", 7)
STRING("rp", 2, ")", 1, ")", 1)
/* Lines. */
CHAR("ba", 2, "|", 1, "&#124;", 6)
CHAR("br", 2, "|", 1, "&#9474;", 7)
CHAR("ul", 2, "_", 1, "&#95;", 5)
CHAR("rl", 2, "-", 1, "&#8254;", 7)
CHAR("bb", 2, "|", 1, "&#166;", 6)
CHAR("sl", 2, "/", 1, "&#47;", 5)
CHAR("rs", 2, "\\", 1, "&#92;", 5)
/* Text markers. */
CHAR("ci", 2, "o", 1, "&#9675;", 7)
CHAR("bu", 2, "o", 1, "&#8226;", 7)
CHAR("dd", 2, "=", 1, "&#8225;", 7)
CHAR("dg", 2, "-", 1, "&#8224;", 7)
CHAR("lz", 2, "<>", 2, "&#9674;", 7)
CHAR("sq", 2, "[]", 2, "&#9633;", 7)
CHAR("ps", 2, "9|", 2, "&#182;", 6)
CHAR("sc", 2, "S", 1, "&#167;", 6)
CHAR("lh", 2, "<=", 2, "&#9756;", 7)
CHAR("rh", 2, "=>", 2, "&#9758;", 7)
CHAR("at", 2, "@", 1, "&#64;", 5)
CHAR("sh", 2, "#", 1, "&#35;", 5)
CHAR("CR", 2, "_|", 2, "&#8629;", 7)
CHAR("OK", 2, "\\/", 2, "&#10003;", 8)
/* Legal symbols. */
CHAR("co", 2, "(C)", 3, "&#169;", 6)
CHAR("rg", 2, "(R)", 3, "&#174;", 6)
CHAR("tm", 2, "tm", 2, "&#8482;", 7)
/* Punctuation. */
CHAR(".", 1, ".", 1, ".", 1)
CHAR("r!", 2, "i", 1, "&#161;", 6)
CHAR("r?", 2, "c", 1, "&#191;", 6)
CHAR("em", 2, "--", 2, "&#8212;", 7)
CHAR("en", 2, "-", 1, "&#8211;", 7)
CHAR("hy", 2, "-", 1, "&#8208;", 7)
CHAR("e", 1, "\\", 1, "\\", 1)
/* Units. */
CHAR("de", 2, "o", 1, "&#176;", 6)
CHAR("%0", 2, "%o", 2, "&#8240;", 7)
CHAR("fm", 2, "\'", 1, "&#8242;", 7)
CHAR("sd", 2, "\"", 1, "&#8243;", 7)
CHAR("mc", 2, "mu", 2, "&#181;", 6)
CHAR_TBL_END

View file

@ -1,20 +0,0 @@
#ifndef MANDOC_CONFIG_H
#define MANDOC_CONFIG_H
#define HAVE_STRLCAT
#define HAVE_STRLCPY
#include <sys/types.h>
#include <sys/cdefs.h>
#ifndef __GNUC__
#define inline
#endif
#ifndef _DIAGASSERT
#define _DIAGASSERT assert
#endif
#endif /* MANDOC_CONFIG_H */

View file

@ -1,72 +0,0 @@
/* $Id: example.style.css,v 1.20 2010/04/08 08:17:55 kristaps Exp $ */
div.body { font-family: monospace;
min-width: 580px; width: 580px; } /* Top-most div tag. */
div.sec-head { font-weight: bold; font-style: normal; } /* Sections (Sh). */
div.sec-body { }
div.sec-block { }
div.ssec-head { font-weight: bold; font-style: normal; } /* Sub-sections (Ss). */
div.ssec-body { }
div.ssec-block { }
span.addr { } /* Address (Ad). */
span.arg { font-style: italic; font-weight: normal; } /* Command argument (Ar). */
span.author { } /* Author name (An). */
span.bold { font-weight: bold; font-style: normal; } /* Generically bold (SB, BI, IB, BR, RB, B). */
span.cmd { font-weight: bold; font-style: normal; } /* Command (Cm). */
span.config { font-weight: bold; font-style: normal; } /* Config statement (Cd). */
span.define { } /* Defines (Dv). */
span.desc { } /* Nd. After em-dash. */
span.diag { font-weight: bold; font-style: normal; } /* Diagnostic (Bl -diag). */
span.emph { font-style: italic; font-weight: normal; } /* Emphasis (Em). */
span.env { } /* Environment variables (Ev). */
span.errno { } /* Error string (Er). */
span.farg { font-style: italic; font-weight: normal; } /* Function argument (Fa, Fn). */
span.file { font-style: italic; font-weight: normal; } /* File (Pa). */
span.flag { font-weight: bold; font-style: normal; } /* Flag (Fl, Cm). */
span.fname { font-weight: bold; font-style: normal; } /* Function name (Fa, Fn, Rv). */
span.ftype { font-style: italic; font-weight: normal; } /* Function types (Ft, Fn). */
span.includes { font-weight: bold; font-style: normal; } /* Header includes (In). */
span.italic { font-style: italic; font-weight: normal; } /* Generically italic (BI, IB, I). */
span.lib { } /* Library (Lb). */
span.lit { } /* Literals (Bf -literal). */
span.macro { font-weight: bold; font-style: normal; } /* Macro-ish thing (Fd). */
span.name { font-weight: bold; font-style: normal; } /* Name of utility (Nm). */
span.opt { } /* Options (Op, Oo/Oc). */
span.ref { } /* Citations (Rs). */
span.ref-auth { } /* Reference author (%A). */
span.ref-book { font-style: italic; font-weight: normal; } /* Reference book (%B). */
span.ref-city { } /* Reference city (%C). */
span.ref-date { } /* Reference date (%D). */
span.ref-issue { font-style: italic; font-weight: normal; } /* Reference issuer/publisher (%I). */
span.ref-jrnl { font-style: italic; font-weight: normal; } /* Reference journal (%J). */
span.ref-num { } /* Reference number (%N). */
span.ref-opt { } /* Reference optionals (%O). */
span.ref-page { } /* Reference page (%P). */
span.ref-corp { } /* Reference corporate/foreign author (%Q). */
span.ref-rep { } /* Reference report (%R). */
span.ref-title { text-decoration: underline; } /* Reference title (%T). */
span.ref-vol { } /* Reference volume (%V). */
span.roman { font-style: normal; font-weight: normal; } /* Generic font. */
span.small { font-size: smaller; } /* Generically small (SB, SM). */
span.symb { font-weight: bold; font-style: normal; } /* Symbols. */
span.type { font-style: italic; font-weight: normal; } /* Variable types (Vt). */
span.unix { } /* Unices (Ux, Ox, Nx, Fx, Bx, Bsx, Dx). */
span.utility { font-weight: bold; font-style: normal; } /* Name of utility (Ex). */
span.var { font-weight: bold; font-style: normal; } /* Variables (Rv). */
a.link-ext { } /* Off-site link (Lk). */
a.link-includes { } /* Include-file link (In). */
a.link-mail { } /* Mailto links (Mt). */
a.link-man { } /* Manual links (Xr). */
a.link-ref { } /* Reference section links (%Q). */
a.link-sec { } /* Section links (Sx). */
div.emph { font-style: italic; font-weight: normal; } /* Emphasis (Bl -emphasis). */
div.lit { } /* Literal (D1, Bd -literal, Dl, Bd -literal). */
div.symb { font-weight: bold; font-style: normal; } /* Symbols (Bl -symbolic). */
table.footer { } /* Document footer. */
table.header { } /* Document header. */

Binary file not shown.

Before

Width:  |  Height:  |  Size: 165 B

View file

@ -1,48 +0,0 @@
body { color: #333333;
font-size: smaller;
font-family: Verdana, Tahoma, Arial, sans-serif; }
table.frame { max-width: 800px;
padding-left: 10px; }
table { padding-left: 40px; }
p { padding-left: 40px;
text-align: justify; }
h1 { font-weight: bold;
font-size: small;
font-family: Verdana, Tahoma, Arial, sans-serif; }
h2 { font-weight: bold;
font-size: small;
padding-left: 20px;
margin-bottom: 0px;
font-family: Verdana, Tahoma, Arial, sans-serif; }
span.nm { color: #000000; font-weight: bold; }
span.attn { color: #000000; font-weight: bold; }
span.flag { font-weight: bold; }
div.head { border-bottom: 1px solid #dddddd;
padding-bottom: 5px;
text-align: right; }
div.subhead { font-size: smaller;
margin-bottom: 1em; }
div.foot { border-top: 1px solid #dddddd;
padding-top: 5px;
font-size: smaller;
text-align: right; }
a.external { background: transparent url(external.png) center right no-repeat;
padding-right: 12px; }
span.date { color: #000000; }
div.news { margin-bottom: 2em; }
div.news ul { margin-left: 4em; }

View file

@ -1,420 +0,0 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<HTML>
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
<META NAME="resource-type" CONTENT="document">
<LINK REL="stylesheet" HREF="index.css" TYPE="text/css" MEDIA="all">
<TITLE>mdocml | mdoc macro compiler</TITLE>
</HEAD>
<BODY>
<TABLE CLASS="frame" SUMMARY="[frame]">
<COL WIDTH="100%">
<TBODY>
<TR>
<TD>
<DIV CLASS="head">
<B>mdocml</B> &#8211; mdoc macro compiler
</DIV>
<DIV CLASS="subhead">
<A HREF="#description">Description</A> |
<A HREF="#sources">Sources</A> |
<A HREF="#documentation">Documentation</A> |
<A HREF="#contact">Contact</A> |
<A HREF="#news">News</A>
</DIV>
</TD>
</TR>
<TR>
<TD VALIGN="top">
<H1>
<A NAME="description">DESCRIPTION</A>
</H1>
<P>
<SPAN CLASS="nm">mdocml</SPAN> is a suite of tools compiling <Q>-mdoc</Q>, the roff macro package
of choice for BSD manual pages, and <Q>-man</Q>, the predominant historical package for UNIX
manuals. The mission of <SPAN CLASS="nm">mdocml</SPAN> is to deprecate <A
HREF="http://www.gnu.org/software/groff/" CLASS="external">groff</A>, the GNU roff implementation, for
displaying -mdoc pages whilst providing token support for -man.
</P>
<P>
Why? groff amounts to over 5 MB of source code, most of which is C++ and all of which is GPL. It runs
slowly, produces uncertain output, and varies in operation from system to system. mdocml strives to fix
this (respectively small, C, ISC-licensed, fast and regular).
</P>
<P>
The core of <SPAN CLASS="nm">mdocml</SPAN> is composed of the <A HREF="mdoc.3.html">libmdoc</A>, <A
HREF="man.3.html">libman</A>, and <A HREF="roff.3.html">libroff</A> validating compiler libraries. All
are simple, fast libraries operating on memory buffers, so they may be used for a variety of front-ends
(terminal-based, CGI and so on). The front-end is <A HREF="mandoc.1.html">mandoc</A>, which formats
manuals for display.
</P>
<P>
The <SPAN CLASS="nm">mdocml</SPAN> suite is a <A CLASS="external" HREF="http://bsd.lv/">BSD.lv
Project</A> member.
</P>
</TD>
</TR>
<TR>
<TD>
<H1>
<A NAME="sources">SOURCES</A>
</H1>
<P>
Sources correctly build and install on DragonFly BSD, FreeBSD, OpenBSD, NetBSD, GNU/Linux, and many
other operating systems, tested variously on i386, AMD64, alpha, and others. The most current version
is <SPAN CLASS="attn">@VERSION@</SPAN>, dated <SPAN class="attn">@VDATE@</SPAN>. A full <A
HREF="ChangeLog.html">ChangeLog</A> (<A HREF="ChangeLog.txt">txt</A>) is written with each release.
</P>
<H2>
Current
</H2>
<TABLE WIDTH="100%" SUMMARY="Current Sources">
<COL WIDTH="200">
<COL>
<TBODY>
<TR>
<TD>Source archive</TD>
<TD>
<A HREF="/snapshots/mdocml.tar.gz">/snapshots/mdocml.tar.gz</A>
(<A HREF="/snapshots/mdocml.md5">md5</A>)
</TD>
</TR>
<TR>
<TD>Online source</TD>
<TD>
<A HREF="http://mdocml.bsd.lv/cgi-bin/cvsweb/?cvsroot=mdocml">cvsweb</A>
</TD>
</TR>
</TBODY>
</TABLE>
<H2>
Downstream
</H2>
<TABLE WIDTH="100%" SUMMARY="Downstream Sources">
<COL WIDTH="200">
<COL>
<TBODY>
<TR>
<TD>DragonFly BSD</TD>
<TD>
<A HREF="http://gitweb.dragonflybsd.org/dragonfly.git/tree/HEAD:/usr.bin/mandoc"
CLASS="external">usr.bin/mandoc</A>
</TD>
</TR>
<TR>
<TD>FreeBSD</TD>
<TD>
<A HREF="http://www.freebsd.org/cgi/cvsweb.cgi/ports/textproc/mdocml/"
CLASS="external">ports/textproc/mdocml</A>
</TD>
</TR>
<TR>
<TD>NetBSD</TD>
<TD>
<A HREF="http://cvsweb.netbsd.org/bsdweb.cgi/src/external/bsd/mdocml/"
CLASS="external">src/external/bsd/mdocml</A>
</TD>
</TR>
<TR>
<TD>OpenBSD</TD>
<TD>
<A HREF="http://www.openbsd.org/cgi-bin/cvsweb/src/usr.bin/mandoc/"
CLASS="external">src/usr.bin/mandoc</A>
</TD>
</TR>
</TBODY>
</TABLE>
<H2>
Historical
</H2>
<TABLE WIDTH="100%" SUMMARY="Archived Sources">
<COL WIDTH="200">
<COL>
<TBODY>
<TR>
<TD>Source archive</TD>
<TD>
<A HREF="/snapshots/">/snapshots/</A>
</TD>
</TR>
</TBODY>
</TABLE>
</TD>
</TR>
<TR>
<TD>
<H1>
<A NAME="documentation">DOCUMENTATION</A>
</H1>
<P>
These manuals are generated automatically and refer to the current snapshot.
</P>
<TABLE WIDTH="100%" SUMMARY="Documentation">
<COL WIDTH="200">
<COL>
<TBODY>
<TR>
<TD VALIGN="top"><A HREF="man.3.html">man(3)</A></TD>
<TD VALIGN="top">
man macro compiler library
<DIV STYLE="font-size: smaller;">
<A HREF="man.3.txt">text</A> | <A HREF="man.3.ps">postscript</A>
</DIV>
</TD>
</TR>
<TR>
<TD VALIGN="top"><A HREF="man.7.html">man(7)</A></TD>
<TD VALIGN="top">
man language reference
<DIV STYLE="font-size: smaller;">
<A HREF="man.7.txt">text</A> | <A HREF="man.7.ps">postscript</A>
</DIV>
</TD>
</TR>
<TR>
<TD VALIGN="top"><A HREF="mandoc.1.html">mandoc(1)</A></TD>
<TD VALIGN="top">
format and display UNIX manuals
<DIV STYLE="font-size: smaller;">
<A HREF="mandoc.1.txt">text</A> | <A HREF="mandoc.1.ps">postscript</A>
</DIV>
</TD>
</TR>
<TR>
<TD VALIGN="top"><A HREF="mandoc_char.7.html">mandoc_char(7)</A></TD>
<TD VALIGN="top">
mandoc special characters
<DIV STYLE="font-size: smaller;">
<A HREF="mandoc_char.7.txt">text</A> | <A HREF="mandoc_char.7.ps">postscript</A>
</DIV>
</TD>
</TR>
<TR>
<TD VALIGN="top"><A HREF="mdoc.3.html">mdoc(3)</A></TD>
<TD VALIGN="top">
mdoc macro compiler library
<DIV STYLE="font-size: smaller;">
<A HREF="mdoc.3.txt">text</A> | <A HREF="mdoc.3.ps">postscript</A>
</DIV>
</TD>
</TR>
<TR>
<TD VALIGN="top"><A HREF="mdoc.7.html">mdoc(7)</A></TD>
<TD VALIGN="top">
mdoc language reference
<DIV STYLE="font-size: smaller;">
<A HREF="mdoc.7.txt">text</A> | <A HREF="mdoc.7.ps">postscript</A>
</DIV>
</TD>
</TR>
<TR>
<TD VALIGN="top"><A HREF="roff.3.html">roff(3)</A></TD>
<TD VALIGN="top">
roff macro compiler library
<DIV STYLE="font-size: smaller;">
<A HREF="roff.3.txt">text</A> | <A HREF="roff.3.ps">postscript</A>
</DIV>
</TD>
</TR>
<TR>
<TD VALIGN="top"><A HREF="roff.7.html">roff(7)</A></TD>
<TD VALIGN="top">
roff-mandoc language reference
<DIV STYLE="font-size: smaller;">
<A HREF="roff.7.txt">text</A> | <A HREF="roff.7.ps">postscript</A>
</DIV>
</TD>
</TR>
</TBODY>
</TABLE>
<P>
See <Q><A CLASS="external" HREF="http://manpages.bsd.lv">Writing UNIX Manual Pages</A></Q> for a general
introduction to manpages and mdoc.
</P>
</TD>
</TR>
<TR>
<TD>
<H1>
<A NAME="contact">CONTACT</A>
</H1>
<P>
For all issues related to <SPAN CLASS="nm">mdocml</SPAN>, contact Kristaps Dzonsons, kris<A
CLASS="external"
HREF="http://mailhide.recaptcha.net/d?k=01M6h_w7twDp58ZgH57eWC_w==&amp;c=Q2DBUt401ePlSeupJFrq_Q=="
TITLE="Reveal this e-mail address">...</A>@bsd.lv.
</P>
<P>
You may also subscribe to several mailing lists (these require subscription, which is moderated). An
archive is not yet available on-line, although you may request one once subscribed.
</P>
<TABLE WIDTH="100%" SUMMARY="Mailing Lists">
<COL WIDTH="200">
<COL>
<TBODY>
<TR>
<TD>
disc<A CLASS="external" TITLE="Reveal this e-mail address"
HREF="http://www.google.com/recaptcha/mailhide/d?k=01KQ80PFH5n3BBNpF5Gs4sRg==&amp;c=EV1QytpQqTHSItc2IXvZyocgYLPnG5K0JKw_gwMC9yc=">...</A>@mdocml.bsd.lv
</TD>
<TD>high-level discussions and version announcements</TD>
</TR>
<TR>
<TD>
tec<A CLASS="external" TITLE="Reveal this e-mail address"
HREF="http://www.google.com/recaptcha/mailhide/d?k=01qDX_iV0RlUOarEvb6mR28g==&amp;c=gRXsTjza0NNCFPaYu-Taj2tF0pmYZSc90EZkFkhkxgo=">...</A>@mdocml.bsd.lv
</TD>
<TD>low-level discussions</TD>
</TR>
<TR>
<TD>
sou<A CLASS="external" TITLE="Reveal this e-mail address"
HREF="http://www.google.com/recaptcha/mailhide/d?k=01prQrAZhhl2EbIwVcRfABsQ==&amp;c=KtTW4Yic9xk-8g40KzJoca4fR3MYXv28g8NC6OQV-T8=">...</A>@mdocml.bsd.lv
</TD>
<TD>source commit messages</TD>
</TR>
</TBODY>
</TABLE>
</TD>
</TR>
<TR>
<TD>
<H1>
<A NAME="news">NEWS</A>
</H1>
<DIV CLASS="news">
<P>
<SPAN CLASS="date">19-06-2010</SPAN>:
version 1.10.2
</P>
<P>
Small release featuring text-decoration in <SPAN CLASS="flag">-Tps</SPAN> output, a few
minor relaxations of errors, and some optimisations.
</P>
</DIV>
<DIV CLASS="news">
<P>
<SPAN CLASS="date">07-06-2010</SPAN>:
version 1.10.1
</P>
<P>
This primarily focusses on the <Q>Bl</Q> and <Q>It</Q> macros described in <A
HREF="mdoc.7.html">mdoc</A>. Multi-line column support is now fully compatible with
groff, as are implicit list entries for columns. Removed manuals.7 in favour of <A
CLASS="external" HREF="http://manpages.bsd.lv">http://manpages.bsd.lv</A>. The way we
handle the SYNOPSIS section (see the SYNOPSIS documentation in <A
HREF="mdoc.7.html#x4d414e55414cx20x535452554354555245">MANUAL STRUCTURE</A>) has also
been considerably simplified compared to groff's method. Furthermore, the <SPAN
CLASS="flag">-Owidth=width</SPAN> output option has been added to <SPAN
CLASS="flag">-Tascii</SPAN> (see <A HREF="mandoc.1.html">mandoc</A>). Lastly, initial
PostScript output has been added with the <SPAN CLASS="flag">-Tps</SPAN> option to <A
HREF="mandoc.1.html">mandoc</A>. It's brutally simple at the moment: fixed-font, with
no font decorations.
</P>
</DIV>
<DIV CLASS="news">
<P>
<SPAN CLASS="date">29-05-2010</SPAN>:
version 1.10.0
</P>
<P>
Release consisting of the results from the m2k10 hackathon and up-merge from OpenBSD.
This requires a significant note of thanks to Ingo Schwarze (OpenBSD) and Joerg
Sonnenberger (NetBSD) for their hard work, and again to Joerg for hosting m2k10.
Highlights (mostly cribbed from Ingo's m2k10 report) follow in no particular order:
</P>
<UL>
<LI>a <A HREF="roff.3.html">libroff</A> preprocessor in front of <A
HREF="mdoc.3.html">libmdoc</A> and <A HREF="man.3.html">libman</A> stripping out
<A HREF="roff.7.html">roff</A> instructions;</LI>
<LI>end-of-sentence (EOS) detection in free-form and macro lines;</LI>
<LI>correct handling of tab-separated columnar lists in <SPAN
CLASS="flag">-mdoc</SPAN>;</LI>
<LI>improved main calling routines to optionally use mmap() for better
performance;</LI>
<LI>cleaned up exiting when invoked as <SPAN CLASS="flag">-Tlint</SPAN> or over
multiple files with <SPAN CLASS="flag">-fign-errors</SPAN>;</LI>
<LI>error and warning message handling re-written to be unified for <A
HREF="roff.3.html">libroff</A>, <A HREF="mdoc.3.html">libmdoc</A>, and <A
HREF="man.3.html">libman</A>;</LI>
<LI>handling of badly-nested explicit-scoped macros;</LI>
<LI>improved free-form text parsing in <A HREF="man.3.html">libman</A> and <A
HREF="mdoc.3.html">libmdoc</A>;</LI>
<LI>significant GNU troff compatibility improvements in <SPAN
CLASS="flag">-Tascii</SPAN>, largely in terms of spacing;</LI>
<LI>a regression framework for making sure the many fragilities of GNU troff
aren't trampled in subsequent work;</LI>
<LI>support for <SPAN CLASS="flag">-Tascii</SPAN> breaking at hyphens
encountered in free-form text;</LI>
<LI>and many more minor fixes and improvements (no really, consult <A
HREF="http://mdocml.bsd.lv/cgi-bin/cvsweb/?cvsroot=mdocml">cvsweb</A> and see
for yourself!).</LI>
</UL>
</DIV>
<DIV CLASS="news">
<P>
<SPAN CLASS="date">13-05-2010</SPAN>:
version 1.9.25
</P>
<P>
Fixed handling of <Q>\*(Ba</Q> escape. Backed out <SPAN
CLASS="flag">-fno-ign-chars</SPAN> (pointless complexity). Fixed erroneous
breaking of literal lines. Fixed SYNOPSIS breaking lines before non-initial
macros. Changed default section ordering. Most importantly, the framework for
end-of-sentence double-spacing is in place, now implemented for the
<Q>end-of-sentence, end-of-line</Q> rule. This is a stable roll-back point
before the mandoc hackathon in Rostock!
</P>
</DIV>
<DIV CLASS="news">
<P>
<SPAN CLASS="date">09-05-2010</SPAN>:
version 1.9.24
</P>
<P>
Rolled back break-at-hyphen. <SPAN CLASS="flag">-DUGLY</SPAN> is now the
default (no feature splits!). Free-form text is not de-chunked any more: lines
are passed whole-sale into the front-end, including whitespace. Added mailing
lists. Lastly, <SPAN CLASS="nm">mdocml</SPAN> is the focus of two <A
CLASS="external" HREF="http://socghop.appspot.com/">Google Summer of Code</A>
projects this year: <Q><A CLASS="external"
HREF="http://netbsd-soc.sourceforge.net/projects/mandoc_ps/">mandoc -Tps</A></Q>
(NetBSD) and <Q><A CLASS="external"
HREF="http://wiki.freebsd.org/SummerOfCode2010Projects">BSD-licensed
Text-Processing Tools</A></Q> (FreeBSD).
</P>
</DIV>
<P>
See <A HREF="http://mdocml.bsd.lv/cgi-bin/cvsweb/index.sgml?cvsroot=mdocml">cvsweb</A> for
historical notes.
</P>
</TD>
</TR>
<TR>
<TD>
<DIV CLASS="foot">
Copyright &#169; 2008&#8211;2010 Kristaps Dzonsons, $Date: 2010/06/19 20:43:35 $
</DIV>
</TD>
</TR>
</TBODY>
</TABLE>
</BODY>
</HTML>

View file

@ -1,870 +0,0 @@
/* $Id: main.c,v 1.89 2010/06/19 20:46:27 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/mman.h>
#include <sys/stat.h>
#include <assert.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mandoc.h"
#include "mdoc.h"
#include "man.h"
#include "roff.h"
#include "main.h"
#define UNCONST(a) ((void *)(uintptr_t)(const void *)(a))
/* FIXME: Intel's compiler? LLVM? pcc? */
#if !defined(__GNUC__) || (__GNUC__ < 2)
# if !defined(lint)
# define __attribute__(x)
# endif
#endif /* !defined(__GNUC__) || (__GNUC__ < 2) */
typedef void (*out_mdoc)(void *, const struct mdoc *);
typedef void (*out_man)(void *, const struct man *);
typedef void (*out_free)(void *);
struct buf {
char *buf;
size_t sz;
};
enum intt {
INTT_AUTO,
INTT_MDOC,
INTT_MAN
};
enum outt {
OUTT_ASCII = 0,
OUTT_TREE,
OUTT_HTML,
OUTT_XHTML,
OUTT_LINT,
OUTT_PS
};
struct curparse {
const char *file; /* Current parse. */
int fd; /* Current parse. */
int wflags;
/* FIXME: set by max error */
#define WARN_WALL (1 << 0) /* All-warnings mask. */
#define WARN_WERR (1 << 2) /* Warnings->errors. */
int fflags;
#define FL_IGN_SCOPE (1 << 0) /* Ignore scope errors. */
#define FL_NIGN_ESCAPE (1 << 1) /* Don't ignore bad escapes. */
#define FL_NIGN_MACRO (1 << 2) /* Don't ignore bad macros. */
#define FL_IGN_ERRORS (1 << 4) /* Ignore failed parse. */
#define FL_STRICT FL_NIGN_ESCAPE | \
FL_NIGN_MACRO /* ignore nothing */
enum intt inttype; /* which parser to use */
struct man *man; /* man parser */
struct mdoc *mdoc; /* mdoc parser */
struct roff *roff; /* roff parser (!NULL) */
enum outt outtype; /* which output to use */
out_mdoc outmdoc; /* mdoc output ptr */
out_man outman; /* man output ptr */
out_free outfree; /* free output ptr */
void *outdata; /* data for output */
char outopts[BUFSIZ]; /* buf of output opts */
};
static const char * const mandocerrs[MANDOCERR_MAX] = {
"ok",
"text should be uppercase",
"sections out of conventional order",
"section name repeats",
"out of order prologue",
"repeated prologue entry",
"list type must come first",
"bad standard",
"bad library",
"bad escape sequence",
"unterminated quoted string",
"argument requires the width argument",
"superfluous width argument",
"ignoring argument",
"bad date argument",
"bad width argument",
"unknown manual section",
"section not in conventional manual section",
"end of line whitespace",
"scope open on exit",
"NAME section must come first",
"bad Boolean value",
"child violates parent syntax",
"bad AT&T symbol",
"list type repeated",
"display type repeated",
"argument repeated",
"manual name not yet set",
"obsolete macro ignored",
"empty macro ignored",
"macro not allowed in body",
"macro not allowed in prologue",
"bad character",
"bad NAME section contents",
"no blank lines",
"no text in this context",
"bad comment style",
"unknown macro will be lost",
"line scope broken",
"scope broken",
"argument count wrong",
"request scope close w/none open",
"scope already open",
"macro requires line argument(s)",
"macro requires body argument(s)",
"macro requires argument(s)",
"no title in document",
"missing list type",
"missing display type",
"line argument(s) will be lost",
"body argument(s) will be lost",
"column syntax is inconsistent",
"missing font type",
"displays may not be nested",
"unsupported display type",
"no scope to rewind: syntax violated",
"scope broken, syntax violated",
"line scope broken, syntax violated",
"argument count wrong, violates syntax",
"child violates parent syntax",
"argument count wrong, violates syntax",
"no document body",
"no document prologue",
"utsname system call failed",
"memory exhausted",
};
static void fdesc(struct curparse *);
static void ffile(const char *, struct curparse *);
static int foptions(int *, char *);
static struct man *man_init(struct curparse *);
static struct mdoc *mdoc_init(struct curparse *);
static struct roff *roff_init(struct curparse *);
static int moptions(enum intt *, char *);
static int mmsg(enum mandocerr, void *,
int, int, const char *);
static int pset(const char *, int, struct curparse *,
struct man **, struct mdoc **);
static int toptions(struct curparse *, char *);
static void usage(void) __attribute__((noreturn));
static void version(void) __attribute__((noreturn));
static int woptions(int *, char *);
static const char *progname;
static int with_error;
static int with_warning;
int
main(int argc, char *argv[])
{
int c;
struct curparse curp;
progname = strrchr(argv[0], '/');
if (progname == NULL)
progname = argv[0];
else
++progname;
memset(&curp, 0, sizeof(struct curparse));
curp.inttype = INTT_AUTO;
curp.outtype = OUTT_ASCII;
/* LINTED */
while (-1 != (c = getopt(argc, argv, "f:m:O:T:VW:")))
switch (c) {
case ('f'):
if ( ! foptions(&curp.fflags, optarg))
return(EXIT_FAILURE);
break;
case ('m'):
if ( ! moptions(&curp.inttype, optarg))
return(EXIT_FAILURE);
break;
case ('O'):
(void)strlcat(curp.outopts, optarg, BUFSIZ);
(void)strlcat(curp.outopts, ",", BUFSIZ);
break;
case ('T'):
if ( ! toptions(&curp, optarg))
return(EXIT_FAILURE);
break;
case ('W'):
if ( ! woptions(&curp.wflags, optarg))
return(EXIT_FAILURE);
break;
case ('V'):
version();
/* NOTREACHED */
default:
usage();
/* NOTREACHED */
}
argc -= optind;
argv += optind;
if (NULL == *argv) {
curp.file = "<stdin>";
curp.fd = STDIN_FILENO;
fdesc(&curp);
}
while (*argv) {
ffile(*argv, &curp);
if (with_error && !(curp.fflags & FL_IGN_ERRORS))
break;
++argv;
}
if (curp.outfree)
(*curp.outfree)(curp.outdata);
if (curp.mdoc)
mdoc_free(curp.mdoc);
if (curp.man)
man_free(curp.man);
if (curp.roff)
roff_free(curp.roff);
return((with_warning || with_error) ?
EXIT_FAILURE : EXIT_SUCCESS);
}
static void
version(void)
{
(void)printf("%s %s\n", progname, VERSION);
exit(EXIT_SUCCESS);
}
static void
usage(void)
{
(void)fprintf(stderr, "usage: %s [-V] [-foption] "
"[-mformat] [-Ooption] [-Toutput] "
"[-Werr] [file...]\n", progname);
exit(EXIT_FAILURE);
}
static struct man *
man_init(struct curparse *curp)
{
int pflags;
/* Defaults from mandoc.1. */
pflags = MAN_IGN_MACRO | MAN_IGN_ESCAPE;
if (curp->fflags & FL_NIGN_MACRO)
pflags &= ~MAN_IGN_MACRO;
if (curp->fflags & FL_NIGN_ESCAPE)
pflags &= ~MAN_IGN_ESCAPE;
return(man_alloc(curp, pflags, mmsg));
}
static struct roff *
roff_init(struct curparse *curp)
{
return(roff_alloc(mmsg, curp));
}
static struct mdoc *
mdoc_init(struct curparse *curp)
{
int pflags;
/* Defaults from mandoc.1. */
pflags = MDOC_IGN_MACRO | MDOC_IGN_ESCAPE;
if (curp->fflags & FL_IGN_SCOPE)
pflags |= MDOC_IGN_SCOPE;
if (curp->fflags & FL_NIGN_ESCAPE)
pflags &= ~MDOC_IGN_ESCAPE;
if (curp->fflags & FL_NIGN_MACRO)
pflags &= ~MDOC_IGN_MACRO;
return(mdoc_alloc(curp, pflags, mmsg));
}
static void
ffile(const char *file, struct curparse *curp)
{
curp->file = file;
if (-1 == (curp->fd = open(curp->file, O_RDONLY, 0))) {
perror(curp->file);
with_error = 1;
return;
}
fdesc(curp);
if (-1 == close(curp->fd))
perror(curp->file);
}
static int
resize_buf(struct buf *buf, size_t initial)
{
void *tmp;
size_t sz;
if (buf->sz == 0)
sz = initial;
else
sz = 2 * buf->sz;
tmp = realloc(buf->buf, sz);
if (NULL == tmp) {
perror(NULL);
return(0);
}
buf->buf = tmp;
buf->sz = sz;
return(1);
}
static int
read_whole_file(struct curparse *curp, struct buf *fb, int *with_mmap)
{
struct stat st;
size_t off;
ssize_t ssz;
if (-1 == fstat(curp->fd, &st)) {
perror(curp->file);
with_error = 1;
return(0);
}
#ifndef __minix
/*
* If we're a regular file, try just reading in the whole entry
* via mmap(). This is faster than reading it into blocks, and
* since each file is only a few bytes to begin with, I'm not
* concerned that this is going to tank any machines.
*/
if (S_ISREG(st.st_mode)) {
if (st.st_size >= (1U << 31)) {
fprintf(stderr, "%s: input too large\n",
curp->file);
with_error = 1;
return(0);
}
*with_mmap = 1;
fb->sz = (size_t)st.st_size;
fb->buf = mmap(NULL, fb->sz, PROT_READ,
MAP_FILE|MAP_SHARED, curp->fd, 0);
if (fb->buf != MAP_FAILED)
return(1);
}
#endif
/*
* If this isn't a regular file (like, say, stdin), then we must
* go the old way and just read things in bit by bit.
*/
*with_mmap = 0;
off = 0;
fb->sz = 0;
fb->buf = NULL;
for (;;) {
if (off == fb->sz) {
if (fb->sz == (1U << 31)) {
fprintf(stderr, "%s: input too large\n",
curp->file);
break;
}
if (! resize_buf(fb, 65536))
break;
}
ssz = read(curp->fd, fb->buf + (int)off, fb->sz - off);
if (ssz == 0) {
fb->sz = off;
return(1);
}
if (ssz == -1) {
perror(curp->file);
break;
}
off += (size_t)ssz;
}
free(fb->buf);
fb->buf = NULL;
with_error = 1;
return(0);
}
static void
fdesc(struct curparse *curp)
{
struct buf ln, blk;
int i, pos, lnn, lnn_start, with_mmap, of;
enum rofferr re;
struct man *man;
struct mdoc *mdoc;
struct roff *roff;
man = NULL;
mdoc = NULL;
roff = NULL;
memset(&ln, 0, sizeof(struct buf));
/*
* Two buffers: ln and buf. buf is the input file and may be
* memory mapped. ln is a line buffer and grows on-demand.
*/
if ( ! read_whole_file(curp, &blk, &with_mmap))
return;
if (NULL == curp->roff)
curp->roff = roff_init(curp);
if (NULL == (roff = curp->roff))
goto bailout;
for (i = 0, lnn = 1; i < (int)blk.sz;) {
pos = 0;
lnn_start = lnn;
while (i < (int)blk.sz) {
if ('\n' == blk.buf[i]) {
++i;
++lnn;
break;
}
/* Trailing backslash is like a plain character. */
if ('\\' != blk.buf[i] || i + 1 == (int)blk.sz) {
if (pos >= (int)ln.sz)
if (! resize_buf(&ln, 256))
goto bailout;
ln.buf[pos++] = blk.buf[i++];
continue;
}
/* Found an escape and at least one other character. */
if ('\n' == blk.buf[i + 1]) {
/* Escaped newlines are skipped over */
i += 2;
++lnn;
continue;
}
if ('"' == blk.buf[i + 1]) {
i += 2;
/* Comment, skip to end of line */
for (; i < (int)blk.sz; ++i) {
if ('\n' == blk.buf[i]) {
++i;
++lnn;
break;
}
}
/* Backout trailing whitespaces */
for (; pos > 0; --pos) {
if (ln.buf[pos - 1] != ' ')
break;
if (pos > 2 && ln.buf[pos - 2] == '\\')
break;
}
break;
}
/* Some other escape sequence, copy and continue. */
if (pos + 1 >= (int)ln.sz)
if (! resize_buf(&ln, 256))
goto bailout;
ln.buf[pos++] = blk.buf[i++];
ln.buf[pos++] = blk.buf[i++];
}
if (pos >= (int)ln.sz)
if (! resize_buf(&ln, 256))
goto bailout;
ln.buf[pos] = '\0';
/*
* A significant amount of complexity is contained by
* the roff preprocessor. It's line-oriented but can be
* expressed on one line, so we need at times to
* readjust our starting point and re-run it. The roff
* preprocessor can also readjust the buffers with new
* data, so we pass them in wholesale.
*/
of = 0;
do {
re = roff_parseln(roff, lnn_start,
&ln.buf, &ln.sz, of, &of);
} while (ROFF_RERUN == re);
if (ROFF_IGN == re)
continue;
else if (ROFF_ERR == re)
goto bailout;
/*
* If input parsers have not been allocated, do so now.
* We keep these instanced betwen parsers, but set them
* locally per parse routine since we can use different
* parsers with each one.
*/
if ( ! (man || mdoc))
if ( ! pset(ln.buf + of, pos - of, curp, &man, &mdoc))
goto bailout;
/* Lastly, push down into the parsers themselves. */
if (man && ! man_parseln(man, lnn_start, ln.buf, of))
goto bailout;
if (mdoc && ! mdoc_parseln(mdoc, lnn_start, ln.buf, of))
goto bailout;
}
/* NOTE a parser may not have been assigned, yet. */
if ( ! (man || mdoc)) {
fprintf(stderr, "%s: Not a manual\n", curp->file);
goto bailout;
}
/* Clean up the parse routine ASTs. */
if (mdoc && ! mdoc_endparse(mdoc))
goto bailout;
if (man && ! man_endparse(man))
goto bailout;
if (roff && ! roff_endparse(roff))
goto bailout;
/* If unset, allocate output dev now (if applicable). */
if ( ! (curp->outman && curp->outmdoc)) {
switch (curp->outtype) {
case (OUTT_XHTML):
curp->outdata = xhtml_alloc(curp->outopts);
break;
case (OUTT_HTML):
curp->outdata = html_alloc(curp->outopts);
break;
case (OUTT_ASCII):
curp->outdata = ascii_alloc(curp->outopts);
curp->outfree = ascii_free;
break;
case (OUTT_PS):
curp->outdata = ps_alloc();
curp->outfree = ps_free;
break;
default:
break;
}
switch (curp->outtype) {
case (OUTT_HTML):
/* FALLTHROUGH */
case (OUTT_XHTML):
curp->outman = html_man;
curp->outmdoc = html_mdoc;
curp->outfree = html_free;
break;
case (OUTT_TREE):
curp->outman = tree_man;
curp->outmdoc = tree_mdoc;
break;
case (OUTT_ASCII):
/* FALLTHROUGH */
case (OUTT_PS):
curp->outman = terminal_man;
curp->outmdoc = terminal_mdoc;
break;
default:
break;
}
}
/* Execute the out device, if it exists. */
if (man && curp->outman)
(*curp->outman)(curp->outdata, man);
if (mdoc && curp->outmdoc)
(*curp->outmdoc)(curp->outdata, mdoc);
cleanup:
if (mdoc)
mdoc_reset(mdoc);
if (man)
man_reset(man);
if (roff)
roff_reset(roff);
if (ln.buf)
free(ln.buf);
#ifdef __minix
assert(!with_mmap);
#else
if (with_mmap)
munmap(blk.buf, blk.sz);
else
#endif
free(blk.buf);
return;
bailout:
with_error = 1;
goto cleanup;
}
static int
pset(const char *buf, int pos, struct curparse *curp,
struct man **man, struct mdoc **mdoc)
{
int i;
/*
* Try to intuit which kind of manual parser should be used. If
* passed in by command-line (-man, -mdoc), then use that
* explicitly. If passed as -mandoc, then try to guess from the
* line: either skip dot-lines, use -mdoc when finding `.Dt', or
* default to -man, which is more lenient.
*/
if ('.' == buf[0] || '\'' == buf[0]) {
for (i = 1; buf[i]; i++)
if (' ' != buf[i] && '\t' != buf[i])
break;
if (0 == buf[i])
return(1);
}
switch (curp->inttype) {
case (INTT_MDOC):
if (NULL == curp->mdoc)
curp->mdoc = mdoc_init(curp);
if (NULL == (*mdoc = curp->mdoc))
return(0);
return(1);
case (INTT_MAN):
if (NULL == curp->man)
curp->man = man_init(curp);
if (NULL == (*man = curp->man))
return(0);
return(1);
default:
break;
}
if (pos >= 3 && 0 == memcmp(buf, ".Dd", 3)) {
if (NULL == curp->mdoc)
curp->mdoc = mdoc_init(curp);
if (NULL == (*mdoc = curp->mdoc))
return(0);
return(1);
}
if (NULL == curp->man)
curp->man = man_init(curp);
if (NULL == (*man = curp->man))
return(0);
return(1);
}
static int
moptions(enum intt *tflags, char *arg)
{
if (0 == strcmp(arg, "doc"))
*tflags = INTT_MDOC;
else if (0 == strcmp(arg, "andoc"))
*tflags = INTT_AUTO;
else if (0 == strcmp(arg, "an"))
*tflags = INTT_MAN;
else {
fprintf(stderr, "%s: Bad argument\n", arg);
return(0);
}
return(1);
}
static int
toptions(struct curparse *curp, char *arg)
{
if (0 == strcmp(arg, "ascii"))
curp->outtype = OUTT_ASCII;
else if (0 == strcmp(arg, "lint")) {
curp->outtype = OUTT_LINT;
curp->wflags |= WARN_WALL;
curp->fflags |= FL_STRICT;
}
else if (0 == strcmp(arg, "tree"))
curp->outtype = OUTT_TREE;
else if (0 == strcmp(arg, "html"))
curp->outtype = OUTT_HTML;
else if (0 == strcmp(arg, "xhtml"))
curp->outtype = OUTT_XHTML;
else if (0 == strcmp(arg, "ps"))
curp->outtype = OUTT_PS;
else {
fprintf(stderr, "%s: Bad argument\n", arg);
return(0);
}
return(1);
}
static int
foptions(int *fflags, char *arg)
{
char *v, *o;
const char *toks[8];
toks[0] = "ign-scope";
toks[1] = "no-ign-escape";
toks[2] = "no-ign-macro";
toks[3] = "ign-errors";
toks[4] = "strict";
toks[5] = "ign-escape";
toks[6] = NULL;
while (*arg) {
o = arg;
switch (getsubopt(&arg, UNCONST(toks), &v)) {
case (0):
*fflags |= FL_IGN_SCOPE;
break;
case (1):
*fflags |= FL_NIGN_ESCAPE;
break;
case (2):
*fflags |= FL_NIGN_MACRO;
break;
case (3):
*fflags |= FL_IGN_ERRORS;
break;
case (4):
*fflags |= FL_STRICT;
break;
case (5):
*fflags &= ~FL_NIGN_ESCAPE;
break;
default:
fprintf(stderr, "%s: Bad argument\n", o);
return(0);
}
}
return(1);
}
static int
woptions(int *wflags, char *arg)
{
char *v, *o;
const char *toks[3];
toks[0] = "all";
toks[1] = "error";
toks[2] = NULL;
while (*arg) {
o = arg;
switch (getsubopt(&arg, UNCONST(toks), &v)) {
case (0):
*wflags |= WARN_WALL;
break;
case (1):
*wflags |= WARN_WERR;
break;
default:
fprintf(stderr, "%s: Bad argument\n", o);
return(0);
}
}
return(1);
}
static int
mmsg(enum mandocerr t, void *arg, int ln, int col, const char *msg)
{
struct curparse *cp;
cp = (struct curparse *)arg;
if (t <= MANDOCERR_ERROR) {
if ( ! (cp->wflags & WARN_WALL))
return(1);
with_warning = 1;
} else
with_error = 1;
fprintf(stderr, "%s:%d:%d: %s", cp->file,
ln, col + 1, mandocerrs[t]);
if (msg)
fprintf(stderr, ": %s", msg);
fputc('\n', stderr);
/* This is superfluous, but whatever. */
if (t > MANDOCERR_ERROR)
return(0);
if (cp->wflags & WARN_WERR) {
with_error = 1;
return(0);
}
return(1);
}

View file

@ -1,280 +0,0 @@
/* $Id: man_action.c,v 1.39 2010/05/26 14:03:54 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
#include "libman.h"
#include "libmandoc.h"
struct actions {
int (*post)(struct man *);
};
static int post_TH(struct man *);
static int post_fi(struct man *);
static int post_nf(struct man *);
static int post_AT(struct man *);
static int post_UC(struct man *);
const struct actions man_actions[MAN_MAX] = {
{ NULL }, /* br */
{ post_TH }, /* TH */
{ NULL }, /* SH */
{ NULL }, /* SS */
{ NULL }, /* TP */
{ NULL }, /* LP */
{ NULL }, /* PP */
{ NULL }, /* P */
{ NULL }, /* IP */
{ NULL }, /* HP */
{ NULL }, /* SM */
{ NULL }, /* SB */
{ NULL }, /* BI */
{ NULL }, /* IB */
{ NULL }, /* BR */
{ NULL }, /* RB */
{ NULL }, /* R */
{ NULL }, /* B */
{ NULL }, /* I */
{ NULL }, /* IR */
{ NULL }, /* RI */
{ NULL }, /* na */
{ NULL }, /* i */
{ NULL }, /* sp */
{ post_nf }, /* nf */
{ post_fi }, /* fi */
{ NULL }, /* r */
{ NULL }, /* RE */
{ NULL }, /* RS */
{ NULL }, /* DT */
{ post_UC }, /* UC */
{ NULL }, /* PD */
{ NULL }, /* Sp */
{ post_nf }, /* Vb */
{ post_fi }, /* Ve */
{ post_AT }, /* AT */
};
int
man_action_post(struct man *m)
{
if (MAN_ACTED & m->last->flags)
return(1);
m->last->flags |= MAN_ACTED;
switch (m->last->type) {
case (MAN_TEXT):
/* FALLTHROUGH */
case (MAN_ROOT):
return(1);
default:
break;
}
if (NULL == man_actions[m->last->tok].post)
return(1);
return((*man_actions[m->last->tok].post)(m));
}
static int
post_fi(struct man *m)
{
if ( ! (MAN_LITERAL & m->flags))
if ( ! man_nmsg(m, m->last, MANDOCERR_NOSCOPE))
return(0);
m->flags &= ~MAN_LITERAL;
return(1);
}
static int
post_nf(struct man *m)
{
if (MAN_LITERAL & m->flags)
if ( ! man_nmsg(m, m->last, MANDOCERR_SCOPEREP))
return(0);
m->flags |= MAN_LITERAL;
return(1);
}
static int
post_TH(struct man *m)
{
struct man_node *n;
if (m->meta.title)
free(m->meta.title);
if (m->meta.vol)
free(m->meta.vol);
if (m->meta.source)
free(m->meta.source);
if (m->meta.msec)
free(m->meta.msec);
if (m->meta.rawdate)
free(m->meta.rawdate);
m->meta.title = m->meta.vol = m->meta.rawdate =
m->meta.msec = m->meta.source = NULL;
m->meta.date = 0;
/* ->TITLE<- MSEC DATE SOURCE VOL */
n = m->last->child;
assert(n);
m->meta.title = mandoc_strdup(n->string);
/* TITLE ->MSEC<- DATE SOURCE VOL */
n = n->next;
assert(n);
m->meta.msec = mandoc_strdup(n->string);
/* TITLE MSEC ->DATE<- SOURCE VOL */
/*
* Try to parse the date. If this works, stash the epoch (this
* is optimal because we can reformat it in the canonical form).
* If it doesn't parse, isn't specified at all, or is an empty
* string, then use the current date.
*/
n = n->next;
if (n && n->string && *n->string) {
m->meta.date = mandoc_a2time
(MTIME_ISO_8601, n->string);
if (0 == m->meta.date) {
if ( ! man_nmsg(m, n, MANDOCERR_BADDATE))
return(0);
m->meta.rawdate = mandoc_strdup(n->string);
}
} else
m->meta.date = time(NULL);
/* TITLE MSEC DATE ->SOURCE<- VOL */
if (n && (n = n->next))
m->meta.source = mandoc_strdup(n->string);
/* TITLE MSEC DATE SOURCE ->VOL<- */
if (n && (n = n->next))
m->meta.vol = mandoc_strdup(n->string);
/*
* Remove the `TH' node after we've processed it for our
* meta-data.
*/
man_node_delete(m, m->last);
return(1);
}
static int
post_AT(struct man *m)
{
static const char * const unix_versions[] = {
"7th Edition",
"System III",
"System V",
"System V Release 2",
};
const char *p, *s;
struct man_node *n, *nn;
n = m->last->child;
if (NULL == n || MAN_TEXT != n->type)
p = unix_versions[0];
else {
s = n->string;
if (0 == strcmp(s, "3"))
p = unix_versions[0];
else if (0 == strcmp(s, "4"))
p = unix_versions[1];
else if (0 == strcmp(s, "5")) {
nn = n->next;
if (nn && MAN_TEXT == nn->type && nn->string[0])
p = unix_versions[3];
else
p = unix_versions[2];
} else
p = unix_versions[0];
}
if (m->meta.source)
free(m->meta.source);
m->meta.source = mandoc_strdup(p);
return(1);
}
static int
post_UC(struct man *m)
{
static const char * const bsd_versions[] = {
"3rd Berkeley Distribution",
"4th Berkeley Distribution",
"4.2 Berkeley Distribution",
"4.3 Berkeley Distribution",
"4.4 Berkeley Distribution",
};
const char *p, *s;
struct man_node *n;
n = m->last->child;
if (NULL == n || MAN_TEXT != n->type)
p = bsd_versions[0];
else {
s = n->string;
if (0 == strcmp(s, "3"))
p = bsd_versions[0];
else if (0 == strcmp(s, "4"))
p = bsd_versions[1];
else if (0 == strcmp(s, "5"))
p = bsd_versions[2];
else if (0 == strcmp(s, "6"))
p = bsd_versions[3];
else if (0 == strcmp(s, "7"))
p = bsd_versions[4];
else
p = bsd_versions[0];
}
if (m->meta.source)
free(m->meta.source);
m->meta.source = mandoc_strdup(p);
return(1);
}

View file

@ -1,104 +0,0 @@
/* $Id: man_argv.c,v 1.4 2010/06/19 20:46:28 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "mandoc.h"
#include "libman.h"
int
man_args(struct man *m, int line, int *pos, char *buf, char **v)
{
assert(*pos);
assert(' ' != buf[*pos]);
if (0 == buf[*pos])
return(ARGS_EOLN);
*v = &buf[*pos];
/*
* Process a quoted literal. A quote begins with a double-quote
* and ends with a double-quote NOT preceded by a double-quote.
* Whitespace is NOT involved in literal termination.
*/
if ('\"' == buf[*pos]) {
*v = &buf[++(*pos)];
for ( ; buf[*pos]; (*pos)++) {
if ('\"' != buf[*pos])
continue;
if ('\"' != buf[*pos + 1])
break;
(*pos)++;
}
if (0 == buf[*pos]) {
if ( ! man_pmsg(m, line, *pos, MANDOCERR_BADQUOTE))
return(ARGS_ERROR);
return(ARGS_QWORD);
}
buf[(*pos)++] = 0;
if (0 == buf[*pos])
return(ARGS_QWORD);
while (' ' == buf[*pos])
(*pos)++;
if (0 == buf[*pos])
if ( ! man_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE))
return(ARGS_ERROR);
return(ARGS_QWORD);
}
/*
* A non-quoted term progresses until either the end of line or
* a non-escaped whitespace.
*/
for ( ; buf[*pos]; (*pos)++)
if (' ' == buf[*pos] && '\\' != buf[*pos - 1])
break;
if (0 == buf[*pos])
return(ARGS_WORD);
buf[(*pos)++] = 0;
while (' ' == buf[*pos])
(*pos)++;
if (0 == buf[*pos])
if ( ! man_pmsg(m, line, *pos, MANDOCERR_EOLNSPACE))
return(ARGS_ERROR);
return(ARGS_WORD);
}

View file

@ -1,328 +0,0 @@
/* $Id: man_validate.c,v 1.44 2010/06/19 20:46:28 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdlib.h>
#include "mandoc.h"
#include "libman.h"
#include "libmandoc.h"
#define CHKARGS struct man *m, struct man_node *n
typedef int (*v_check)(CHKARGS);
struct man_valid {
v_check *pres;
v_check *posts;
};
static int check_bline(CHKARGS);
static int check_eq0(CHKARGS);
static int check_le1(CHKARGS);
static int check_ge2(CHKARGS);
static int check_le5(CHKARGS);
static int check_par(CHKARGS);
static int check_part(CHKARGS);
static int check_root(CHKARGS);
static int check_sec(CHKARGS);
static int check_text(CHKARGS);
static int check_title(CHKARGS);
static v_check posts_eq0[] = { check_eq0, NULL };
static v_check posts_th[] = { check_ge2, check_le5, check_title, NULL };
static v_check posts_par[] = { check_par, NULL };
static v_check posts_part[] = { check_part, NULL };
static v_check posts_sec[] = { check_sec, NULL };
static v_check posts_le1[] = { check_le1, NULL };
static v_check pres_bline[] = { check_bline, NULL };
static const struct man_valid man_valids[MAN_MAX] = {
{ NULL, posts_eq0 }, /* br */
{ pres_bline, posts_th }, /* TH */
{ pres_bline, posts_sec }, /* SH */
{ pres_bline, posts_sec }, /* SS */
{ pres_bline, posts_par }, /* TP */
{ pres_bline, posts_par }, /* LP */
{ pres_bline, posts_par }, /* PP */
{ pres_bline, posts_par }, /* P */
{ pres_bline, posts_par }, /* IP */
{ pres_bline, posts_par }, /* HP */
{ NULL, NULL }, /* SM */
{ NULL, NULL }, /* SB */
{ NULL, NULL }, /* BI */
{ NULL, NULL }, /* IB */
{ NULL, NULL }, /* BR */
{ NULL, NULL }, /* RB */
{ NULL, NULL }, /* R */
{ NULL, NULL }, /* B */
{ NULL, NULL }, /* I */
{ NULL, NULL }, /* IR */
{ NULL, NULL }, /* RI */
{ NULL, posts_eq0 }, /* na */
{ NULL, NULL }, /* i */
{ NULL, posts_le1 }, /* sp */
{ pres_bline, posts_eq0 }, /* nf */
{ pres_bline, posts_eq0 }, /* fi */
{ NULL, NULL }, /* r */
{ NULL, NULL }, /* RE */
{ NULL, posts_part }, /* RS */
{ NULL, NULL }, /* DT */
{ NULL, NULL }, /* UC */
{ NULL, NULL }, /* PD */
{ NULL, posts_le1 }, /* Sp */
{ pres_bline, posts_le1 }, /* Vb */
{ pres_bline, posts_eq0 }, /* Ve */
{ NULL, NULL }, /* AT */
};
int
man_valid_pre(struct man *m, struct man_node *n)
{
v_check *cp;
if (MAN_TEXT == n->type)
return(1);
if (MAN_ROOT == n->type)
return(1);
if (NULL == (cp = man_valids[n->tok].pres))
return(1);
for ( ; *cp; cp++)
if ( ! (*cp)(m, n))
return(0);
return(1);
}
int
man_valid_post(struct man *m)
{
v_check *cp;
if (MAN_VALID & m->last->flags)
return(1);
m->last->flags |= MAN_VALID;
switch (m->last->type) {
case (MAN_TEXT):
return(check_text(m, m->last));
case (MAN_ROOT):
return(check_root(m, m->last));
default:
break;
}
if (NULL == (cp = man_valids[m->last->tok].posts))
return(1);
for ( ; *cp; cp++)
if ( ! (*cp)(m, m->last))
return(0);
return(1);
}
static int
check_root(CHKARGS)
{
if (MAN_BLINE & m->flags)
return(man_nmsg(m, n, MANDOCERR_SCOPEEXIT));
if (MAN_ELINE & m->flags)
return(man_nmsg(m, n, MANDOCERR_SCOPEEXIT));
m->flags &= ~MAN_BLINE;
m->flags &= ~MAN_ELINE;
if (NULL == m->first->child) {
man_nmsg(m, n, MANDOCERR_NODOCBODY);
return(0);
} else if (NULL == m->meta.title) {
if ( ! man_nmsg(m, n, MANDOCERR_NOTITLE))
return(0);
/*
* If a title hasn't been set, do so now (by
* implication, date and section also aren't set).
*
* FIXME: this should be in man_action.c.
*/
m->meta.title = mandoc_strdup("unknown");
m->meta.date = time(NULL);
m->meta.msec = mandoc_strdup("1");
}
return(1);
}
static int
check_title(CHKARGS)
{
const char *p;
assert(n->child);
/* FIXME: is this sufficient? */
if ('\0' == *n->child->string) {
man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT);
return(0);
}
for (p = n->child->string; '\0' != *p; p++)
if (isalpha((u_char)*p) && ! isupper((u_char)*p))
if ( ! man_nmsg(m, n, MANDOCERR_UPPERCASE))
return(0);
return(1);
}
static int
check_text(CHKARGS)
{
char *p;
int pos, c;
assert(n->string);
for (p = n->string, pos = n->pos + 1; *p; p++, pos++) {
if ('\\' == *p) {
c = mandoc_special(p);
if (c) {
p += c - 1;
pos += c - 1;
continue;
}
c = man_pmsg(m, n->line, pos, MANDOCERR_BADESCAPE);
if ( ! (MAN_IGN_ESCAPE & m->pflags) && ! c)
return(c);
}
if ('\t' == *p || isprint((u_char)*p) || ASCII_HYPH == *p)
continue;
if ( ! man_pmsg(m, n->line, pos, MANDOCERR_BADCHAR))
return(0);
}
return(1);
}
#define INEQ_DEFINE(x, ineq, name) \
static int \
check_##name(CHKARGS) \
{ \
if (n->nchild ineq (x)) \
return(1); \
man_vmsg(m, MANDOCERR_SYNTARGCOUNT, n->line, n->pos, \
"line arguments %s %d (have %d)", \
#ineq, (x), n->nchild); \
return(0); \
}
INEQ_DEFINE(0, ==, eq0)
INEQ_DEFINE(1, <=, le1)
INEQ_DEFINE(2, >=, ge2)
INEQ_DEFINE(5, <=, le5)
static int
check_sec(CHKARGS)
{
if (MAN_HEAD == n->type && 0 == n->nchild) {
man_nmsg(m, n, MANDOCERR_SYNTARGCOUNT);
return(0);
} else if (MAN_BODY == n->type && 0 == n->nchild)
return(man_nmsg(m, n, MANDOCERR_NOBODY));
return(1);
}
static int
check_part(CHKARGS)
{
if (MAN_BODY == n->type && 0 == n->nchild)
return(man_nmsg(m, n, MANDOCERR_NOBODY));
return(1);
}
static int
check_par(CHKARGS)
{
if (MAN_BODY == n->type)
switch (n->tok) {
case (MAN_IP):
/* FALLTHROUGH */
case (MAN_HP):
/* FALLTHROUGH */
case (MAN_TP):
/* Body-less lists are ok. */
break;
default:
if (n->nchild)
break;
return(man_nmsg(m, n, MANDOCERR_NOBODY));
}
if (MAN_HEAD == n->type)
switch (n->tok) {
case (MAN_PP):
/* FALLTHROUGH */
case (MAN_P):
/* FALLTHROUGH */
case (MAN_LP):
if (0 == n->nchild)
break;
return(man_nmsg(m, n, MANDOCERR_ARGSLOST));
default:
if (n->nchild)
break;
return(man_nmsg(m, n, MANDOCERR_NOARGS));
}
return(1);
}
static int
check_bline(CHKARGS)
{
assert( ! (MAN_ELINE & m->flags));
if (MAN_BLINE & m->flags) {
man_nmsg(m, n, MANDOCERR_SYNTLINESCOPE);
return(0);
}
return(1);
}

View file

@ -1,396 +0,0 @@
/* $Id: mandoc.c,v 1.19 2010/06/19 20:46:28 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include "mandoc.h"
#include "libmandoc.h"
static int a2time(time_t *, const char *, const char *);
static int spec_norm(char *, int);
/*
* "Normalise" a special string by converting its ASCII_HYPH entries
* into actual hyphens.
*/
static int
spec_norm(char *p, int sz)
{
int i;
for (i = 0; i < sz; i++)
if (ASCII_HYPH == p[i])
p[i] = '-';
return(sz);
}
int
mandoc_special(char *p)
{
int terminator; /* Terminator for \s. */
int lim; /* Limit for N in \s. */
int c, i;
char *sv;
sv = p;
if ('\\' != *p++)
return(spec_norm(sv, 0));
switch (*p) {
case ('\''):
/* FALLTHROUGH */
case ('`'):
/* FALLTHROUGH */
case ('q'):
/* FALLTHROUGH */
case (ASCII_HYPH):
/* FALLTHROUGH */
case ('-'):
/* FALLTHROUGH */
case ('~'):
/* FALLTHROUGH */
case ('^'):
/* FALLTHROUGH */
case ('%'):
/* FALLTHROUGH */
case ('0'):
/* FALLTHROUGH */
case (' '):
/* FALLTHROUGH */
case ('}'):
/* FALLTHROUGH */
case ('|'):
/* FALLTHROUGH */
case ('&'):
/* FALLTHROUGH */
case ('.'):
/* FALLTHROUGH */
case (':'):
/* FALLTHROUGH */
case ('c'):
/* FALLTHROUGH */
case ('e'):
return(spec_norm(sv, 2));
case ('s'):
if ('\0' == *++p)
return(spec_norm(sv, 2));
c = 2;
terminator = 0;
lim = 1;
if (*p == '\'') {
lim = 0;
terminator = 1;
++p;
++c;
} else if (*p == '[') {
lim = 0;
terminator = 2;
++p;
++c;
} else if (*p == '(') {
lim = 2;
terminator = 3;
++p;
++c;
}
if (*p == '+' || *p == '-') {
++p;
++c;
}
if (*p == '\'') {
if (terminator)
return(spec_norm(sv, 0));
lim = 0;
terminator = 1;
++p;
++c;
} else if (*p == '[') {
if (terminator)
return(spec_norm(sv, 0));
lim = 0;
terminator = 2;
++p;
++c;
} else if (*p == '(') {
if (terminator)
return(spec_norm(sv, 0));
lim = 2;
terminator = 3;
++p;
++c;
}
/* TODO: needs to handle floating point. */
if ( ! isdigit((u_char)*p))
return(spec_norm(sv, 0));
for (i = 0; isdigit((u_char)*p); i++) {
if (lim && i >= lim)
break;
++p;
++c;
}
if (terminator && terminator < 3) {
if (1 == terminator && *p != '\'')
return(spec_norm(sv, 0));
if (2 == terminator && *p != ']')
return(spec_norm(sv, 0));
++p;
++c;
}
return(spec_norm(sv, c));
case ('f'):
/* FALLTHROUGH */
case ('F'):
/* FALLTHROUGH */
case ('*'):
if ('\0' == *++p || isspace((u_char)*p))
return(spec_norm(sv, 0));
switch (*p) {
case ('('):
if ('\0' == *++p || isspace((u_char)*p))
return(spec_norm(sv, 0));
return(spec_norm(sv, 4));
case ('['):
for (c = 3, p++; *p && ']' != *p; p++, c++)
if (isspace((u_char)*p))
break;
return(spec_norm(sv, *p == ']' ? c : 0));
default:
break;
}
return(spec_norm(sv, 3));
case ('('):
if ('\0' == *++p || isspace((u_char)*p))
return(spec_norm(sv, 0));
if ('\0' == *++p || isspace((u_char)*p))
return(spec_norm(sv, 0));
return(spec_norm(sv, 4));
case ('['):
break;
default:
return(spec_norm(sv, 0));
}
for (c = 3, p++; *p && ']' != *p; p++, c++)
if (isspace((u_char)*p))
break;
return(spec_norm(sv, *p == ']' ? c : 0));
}
void *
mandoc_calloc(size_t num, size_t size)
{
void *ptr;
ptr = calloc(num, size);
if (NULL == ptr) {
perror(NULL);
exit(EXIT_FAILURE);
}
return(ptr);
}
void *
mandoc_malloc(size_t size)
{
void *ptr;
ptr = malloc(size);
if (NULL == ptr) {
perror(NULL);
exit(EXIT_FAILURE);
}
return(ptr);
}
void *
mandoc_realloc(void *ptr, size_t size)
{
ptr = realloc(ptr, size);
if (NULL == ptr) {
perror(NULL);
exit(EXIT_FAILURE);
}
return(ptr);
}
char *
mandoc_strdup(const char *ptr)
{
char *p;
p = strdup(ptr);
if (NULL == p) {
perror(NULL);
exit(EXIT_FAILURE);
}
return(p);
}
static int
a2time(time_t *t, const char *fmt, const char *p)
{
struct tm tm;
char *pp;
memset(&tm, 0, sizeof(struct tm));
pp = strptime(p, fmt, &tm);
if (NULL != pp && '\0' == *pp) {
*t = mktime(&tm);
return(1);
}
return(0);
}
/*
* Convert from a manual date string (see mdoc(7) and man(7)) into a
* date according to the stipulated date type.
*/
time_t
mandoc_a2time(int flags, const char *p)
{
time_t t;
if (MTIME_MDOCDATE & flags) {
if (0 == strcmp(p, "$" "Mdocdate$"))
return(time(NULL));
if (a2time(&t, "$" "Mdocdate: %b %d %Y $", p))
return(t);
}
if (MTIME_CANONICAL & flags || MTIME_REDUCED & flags)
if (a2time(&t, "%b %d, %Y", p))
return(t);
if (MTIME_ISO_8601 & flags)
if (a2time(&t, "%Y-%m-%d", p))
return(t);
if (MTIME_REDUCED & flags) {
if (a2time(&t, "%d, %Y", p))
return(t);
if (a2time(&t, "%Y", p))
return(t);
}
return(0);
}
int
mandoc_eos(const char *p, size_t sz)
{
if (0 == sz)
return(0);
/*
* End-of-sentence recognition must include situations where
* some symbols, such as `)', allow prior EOS punctuation to
* propogate outward.
*/
for ( ; sz; sz--) {
switch (p[(int)sz - 1]) {
case ('\"'):
/* FALLTHROUGH */
case ('\''):
/* FALLTHROUGH */
case (']'):
/* FALLTHROUGH */
case (')'):
break;
case ('.'):
/* Escaped periods. */
if (sz > 1 && '\\' == p[(int)sz - 2])
return(0);
/* FALLTHROUGH */
case ('!'):
/* FALLTHROUGH */
case ('?'):
return(1);
default:
return(0);
}
}
return(0);
}
int
mandoc_hyph(const char *start, const char *c)
{
/*
* Choose whether to break at a hyphenated character. We only
* do this if it's free-standing within a word.
*/
/* Skip first/last character of buffer. */
if (c == start || '\0' == *(c + 1))
return(0);
/* Skip first/last character of word. */
if ('\t' == *(c + 1) || '\t' == *(c - 1))
return(0);
if (' ' == *(c + 1) || ' ' == *(c - 1))
return(0);
/* Skip double invocations. */
if ('-' == *(c + 1) || '-' == *(c - 1))
return(0);
/* Skip escapes. */
if ('\\' == *(c - 1))
return(0);
return(1);
}

View file

@ -1,110 +0,0 @@
/* $Id: mandoc.h,v 1.12 2010/06/12 11:41:50 kristaps Exp $ */
/*
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef MANDOC_H
#define MANDOC_H
#define ASCII_NBRSP 31 /* non-breaking space */
#define ASCII_HYPH 30 /* breakable hyphen */
__BEGIN_DECLS
enum mandocerr {
MANDOCERR_OK,
MANDOCERR_UPPERCASE, /* text should be uppercase */
MANDOCERR_SECOOO, /* sections out of conventional order */
MANDOCERR_SECREP, /* section name repeats */
MANDOCERR_PROLOGOOO, /* out of order prologue */
MANDOCERR_PROLOGREP, /* repeated prologue entry */
MANDOCERR_LISTFIRST, /* list type must come first */
MANDOCERR_BADSTANDARD, /* bad standard */
MANDOCERR_BADLIB, /* bad library */
MANDOCERR_BADESCAPE, /* bad escape sequence */
MANDOCERR_BADQUOTE, /* unterminated quoted string */
MANDOCERR_NOWIDTHARG, /* argument requires the width argument */
/* FIXME: merge with MANDOCERR_IGNARGV. */
MANDOCERR_WIDTHARG, /* superfluous width argument */
MANDOCERR_IGNARGV, /* macro ignoring argv */
MANDOCERR_BADDATE, /* bad date argument */
MANDOCERR_BADWIDTH, /* bad width argument */
MANDOCERR_BADMSEC, /* unknown manual section */
MANDOCERR_SECMSEC, /* section not in conventional manual section */
MANDOCERR_EOLNSPACE, /* end of line whitespace */
MANDOCERR_SCOPEEXIT, /* scope open on exit */
#define MANDOCERR_WARNING MANDOCERR_SCOPEEXIT
MANDOCERR_NAMESECFIRST, /* NAME section must come first */
MANDOCERR_BADBOOL, /* bad Boolean value */
MANDOCERR_CHILD, /* child violates parent syntax */
MANDOCERR_BADATT, /* bad AT&T symbol */
MANDOCERR_LISTREP, /* list type repeated */
MANDOCERR_DISPREP, /* display type repeated */
MANDOCERR_ARGVREP, /* argument repeated */
MANDOCERR_NONAME, /* manual name not yet set */
MANDOCERR_MACROOBS, /* obsolete macro ignored */
MANDOCERR_MACROEMPTY, /* empty macro ignored */
MANDOCERR_BADBODY, /* macro not allowed in body */
MANDOCERR_BADPROLOG, /* macro not allowed in prologue */
MANDOCERR_BADCHAR, /* bad character */
MANDOCERR_BADNAMESEC, /* bad NAME section contents */
MANDOCERR_NOBLANKLN, /* no blank lines */
MANDOCERR_NOTEXT, /* no text in this context */
MANDOCERR_BADCOMMENT, /* bad comment style */
MANDOCERR_MACRO, /* unknown macro will be lost */
MANDOCERR_LINESCOPE, /* line scope broken */
MANDOCERR_SCOPE, /* scope broken */
MANDOCERR_ARGCOUNT, /* argument count wrong */
MANDOCERR_NOSCOPE, /* request scope close w/none open */
MANDOCERR_SCOPEREP, /* scope already open */
/* FIXME: merge following with MANDOCERR_ARGCOUNT */
MANDOCERR_NOARGS, /* macro requires line argument(s) */
MANDOCERR_NOBODY, /* macro requires body argument(s) */
MANDOCERR_NOARGV, /* macro requires argument(s) */
MANDOCERR_NOTITLE, /* no title in document */
MANDOCERR_LISTTYPE, /* missing list type */
MANDOCERR_DISPTYPE, /* missing display type */
MANDOCERR_ARGSLOST, /* line argument(s) will be lost */
MANDOCERR_BODYLOST, /* body argument(s) will be lost */
#define MANDOCERR_ERROR MANDOCERR_BODYLOST
MANDOCERR_COLUMNS, /* column syntax is inconsistent */
/* FIXME: this should be a MANDOCERR_ERROR */
MANDOCERR_FONTTYPE, /* missing font type */
/* FIXME: this should be a MANDOCERR_ERROR */
MANDOCERR_NESTEDDISP, /* displays may not be nested */
MANDOCERR_BADDISP, /* unsupported display type */
MANDOCERR_SYNTNOSCOPE, /* request scope close w/none open */
MANDOCERR_SYNTSCOPE, /* scope broken, syntax violated */
MANDOCERR_SYNTLINESCOPE, /* line scope broken, syntax violated */
MANDOCERR_SYNTARGVCOUNT, /* argument count wrong, violates syntax */
MANDOCERR_SYNTCHILD, /* child violates parent syntax */
MANDOCERR_SYNTARGCOUNT, /* argument count wrong, violates syntax */
MANDOCERR_NODOCBODY, /* no document body */
MANDOCERR_NODOCPROLOG, /* no document prologue */
MANDOCERR_UTSNAME, /* utsname() system call failed */
MANDOCERR_MEM, /* memory exhausted */
#define MANDOCERR_FATAL MANDOCERR_MEM
MANDOCERR_MAX
};
typedef int (*mandocmsg)(enum mandocerr,
void *, int, int, const char *);
__END_DECLS
#endif /*!MANDOC_H*/

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -1,399 +0,0 @@
/* $Id: out.c,v 1.16 2010/06/19 20:46:28 kristaps Exp $ */
/*
* Copyright (c) 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/types.h>
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "out.h"
/* See a2roffdeco(). */
#define C2LIM(c, l) do { \
(l) = 1; \
if ('[' == (c) || '\'' == (c)) \
(l) = 0; \
else if ('(' == (c)) \
(l) = 2; } \
while (/* CONSTCOND */ 0)
/* See a2roffdeco(). */
#define C2TERM(c, t) do { \
(t) = 0; \
if ('\'' == (c)) \
(t) = 1; \
else if ('[' == (c)) \
(t) = 2; \
else if ('(' == (c)) \
(t) = 3; } \
while (/* CONSTCOND */ 0)
/*
* Convert a `scaling unit' to a consistent form, or fail. Scaling
* units are documented in groff.7, mdoc.7, man.7.
*/
int
a2roffsu(const char *src, struct roffsu *dst, enum roffscale def)
{
char buf[BUFSIZ], hasd;
int i;
enum roffscale unit;
if ('\0' == *src)
return(0);
i = hasd = 0;
switch (*src) {
case ('+'):
src++;
break;
case ('-'):
buf[i++] = *src++;
break;
default:
break;
}
if ('\0' == *src)
return(0);
while (i < BUFSIZ) {
if ( ! isdigit((u_char)*src)) {
if ('.' != *src)
break;
else if (hasd)
break;
else
hasd = 1;
}
buf[i++] = *src++;
}
if (BUFSIZ == i || (*src && *(src + 1)))
return(0);
buf[i] = '\0';
switch (*src) {
case ('c'):
unit = SCALE_CM;
break;
case ('i'):
unit = SCALE_IN;
break;
case ('P'):
unit = SCALE_PC;
break;
case ('p'):
unit = SCALE_PT;
break;
case ('f'):
unit = SCALE_FS;
break;
case ('v'):
unit = SCALE_VS;
break;
case ('m'):
unit = SCALE_EM;
break;
case ('\0'):
if (SCALE_MAX == def)
return(0);
unit = SCALE_BU;
break;
case ('u'):
unit = SCALE_BU;
break;
case ('M'):
unit = SCALE_MM;
break;
case ('n'):
unit = SCALE_EN;
break;
default:
return(0);
}
if ((dst->scale = atof(buf)) < 0)
dst->scale = 0;
dst->unit = unit;
dst->pt = hasd;
return(1);
}
/*
* Correctly writes the time in nroff form, which differs from standard
* form in that a space isn't printed in lieu of the extra %e field for
* single-digit dates.
*/
void
time2a(time_t t, char *dst, size_t sz)
{
struct tm tm;
char buf[5];
char *p;
size_t nsz;
assert(sz > 1);
localtime_r(&t, &tm);
p = dst;
nsz = 0;
dst[0] = '\0';
if (0 == (nsz = strftime(p, sz, "%B ", &tm)))
return;
p += (int)nsz;
sz -= nsz;
if (0 == strftime(buf, sizeof(buf), "%e, ", &tm))
return;
nsz = strlcat(p, buf + (' ' == buf[0] ? 1 : 0), sz);
if (nsz >= sz)
return;
p += (int)nsz;
sz -= nsz;
(void)strftime(p, sz, "%Y", &tm);
}
/*
* Returns length of parsed string (the leading "\" should NOT be
* included). This can be zero if the current character is the nil
* terminator. "d" is set to the type of parsed decorator, which may
* have an adjoining "word" of size "sz" (e.g., "(ab" -> "ab", 2).
*/
int
a2roffdeco(enum roffdeco *d,
const char **word, size_t *sz)
{
int j, term, lim;
char set;
const char *wp, *sp;
*d = DECO_NONE;
wp = *word;
switch ((set = *wp)) {
case ('\0'):
return(0);
case ('('):
if ('\0' == *(++wp))
return(1);
if ('\0' == *(wp + 1))
return(2);
*d = DECO_SPECIAL;
*sz = 2;
*word = wp;
return(3);
case ('F'):
/* FALLTHROUGH */
case ('f'):
/*
* FIXME: this needs work and consolidation (it should
* follow the sequence that special characters do, for
* one), but isn't a priority at the moment. Note, for
* one, that in reality \fB != \FB, although here we let
* these slip by.
*/
switch (*(++wp)) {
case ('\0'):
return(1);
case ('3'):
/* FALLTHROUGH */
case ('B'):
*d = DECO_BOLD;
return(2);
case ('2'):
/* FALLTHROUGH */
case ('I'):
*d = DECO_ITALIC;
return(2);
case ('P'):
*d = DECO_PREVIOUS;
return(2);
case ('1'):
/* FALLTHROUGH */
case ('R'):
*d = DECO_ROMAN;
return(2);
case ('('):
if ('\0' == *(++wp))
return(2);
if ('\0' == *(wp + 1))
return(3);
*d = 'F' == set ? DECO_FFONT : DECO_FONT;
*sz = 2;
*word = wp;
return(4);
case ('['):
*word = ++wp;
for (j = 0; *wp && ']' != *wp; wp++, j++)
/* Loop... */ ;
if ('\0' == *wp)
return(j + 2);
*d = 'F' == set ? DECO_FFONT : DECO_FONT;
*sz = (size_t)j;
return(j + 3);
default:
break;
}
*d = 'F' == set ? DECO_FFONT : DECO_FONT;
*sz = 1;
*word = wp;
return(2);
case ('*'):
switch (*(++wp)) {
case ('\0'):
return(1);
case ('('):
if ('\0' == *(++wp))
return(2);
if ('\0' == *(wp + 1))
return(3);
*d = DECO_RESERVED;
*sz = 2;
*word = wp;
return(4);
case ('['):
*word = ++wp;
for (j = 0; *wp && ']' != *wp; wp++, j++)
/* Loop... */ ;
if ('\0' == *wp)
return(j + 2);
*d = DECO_RESERVED;
*sz = (size_t)j;
return(j + 3);
default:
break;
}
*d = DECO_RESERVED;
*sz = 1;
*word = wp;
return(2);
case ('s'):
sp = wp;
if ('\0' == *(++wp))
return(1);
C2LIM(*wp, lim);
C2TERM(*wp, term);
if (term)
wp++;
*word = wp;
if (*wp == '+' || *wp == '-')
++wp;
switch (*wp) {
case ('\''):
/* FALLTHROUGH */
case ('['):
/* FALLTHROUGH */
case ('('):
if (term)
return((int)(wp - sp));
C2LIM(*wp, lim);
C2TERM(*wp, term);
wp++;
break;
default:
break;
}
if ( ! isdigit((u_char)*wp))
return((int)(wp - sp));
for (j = 0; isdigit((u_char)*wp); j++) {
if (lim && j >= lim)
break;
++wp;
}
if (term && term < 3) {
if (1 == term && *wp != '\'')
return((int)(wp - sp));
if (2 == term && *wp != ']')
return((int)(wp - sp));
++wp;
}
*d = DECO_SIZE;
return((int)(wp - sp));
case ('['):
*word = ++wp;
for (j = 0; *wp && ']' != *wp; wp++, j++)
/* Loop... */ ;
if ('\0' == *wp)
return(j + 1);
*d = DECO_SPECIAL;
*sz = (size_t)j;
return(j + 2);
case ('c'):
*d = DECO_NOSPACE;
*sz = 1;
return(1);
default:
break;
}
*d = DECO_SPECIAL;
*word = wp;
*sz = 1;
return(1);
}

View file

@ -1,304 +0,0 @@
.\" $Id: roff.7,v 1.9 2010/06/10 21:42:02 kristaps Exp $
.\"
.\" Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
.\"
.\" Permission to use, copy, modify, and distribute this software for any
.\" purpose with or without fee is hereby granted, provided that the above
.\" copyright notice and this permission notice appear in all copies.
.\"
.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
.Dd $Mdocdate: June 10 2010 $
.Dt ROFF 7
.Os
.Sh NAME
.Nm roff
.Nd roff language reference
.Sh DESCRIPTION
The
.Nm roff
language is a general-purpose text-formatting language. The purpose of
this document is to consistently describe those language constructs
accepted by the
.Xr mandoc 1
utility. It is a work in progress.
.Pp
An
.Nm
document follows simple rules: lines beginning with the control
characters
.Sq \.
or
.Sq \(aq
are parsed for macros. Other lines are interpreted within the scope of
prior macros:
.Bd -literal -offset indent
\&.xx Macro lines change control state.
Other lines are interpreted within the current state.
.Ed
.Sh LANGUAGE SYNTAX
.Nm
documents may contain only graphable 7-bit ASCII characters, the space
character, and, in certain circumstances, the tab character. All
manuals must have
.Ux
line terminators.
.Sh MACRO SYNTAX
Macros are arbitrary in length and begin with a control character ,
.Sq \.
or
.Sq \(aq ,
at the beginning of the line.
An arbitrary amount of whitespace may sit between the control character
and the macro name.
Thus, the following are equivalent:
.Bd -literal -offset indent
\&.if
\&.\ \ \ \&if
.Ed
.Sh REFERENCE
This section is a canonical reference of all macros, arranged
alphabetically.
.Ss \&am
The syntax of this macro is the same as that of
.Sx \&ig ,
except that a leading argument must be specified.
It is ignored, as are its children.
.Ss \&ami
The syntax of this macro is the same as that of
.Sx \&ig ,
except that a leading argument must be specified.
It is ignored, as are its children.
.Ss \&am1
The syntax of this macro is the same as that of
.Sx \&ig ,
except that a leading argument must be specified.
It is ignored, as are its children.
.Ss \&de
The syntax of this macro is the same as that of
.Sx \&ig ,
except that a leading argument must be specified.
It is ignored, as are its children.
.Ss \&dei
The syntax of this macro is the same as that of
.Sx \&ig ,
except that a leading argument must be specified.
It is ignored, as are its children.
.Ss \&ds
Define a string.
This macro is intended to have two arguments,
the name of the string to define and its content.
Currently, it is ignored including its arguments,
and the number of arguments is not checked.
.Ss \&de1
The syntax of this macro is the same as that of
.Sx \&ig ,
except that a leading argument must be specified.
It is ignored, as are its children.
.Ss \&el
The
.Qq else
half of an if/else conditional.
Pops a result off the stack of conditional evaluations pushed by
.Sx \&ie
and uses it as its conditional.
If no stack entries are present (e.g., due to no prior
.Sx \&ie
calls)
then false is assumed.
The syntax of this macro is similar to
.Sx \&if
except that the conditional is missing.
.Ss \&ie
The
.Qq if
half of an if/else conditional.
The result of the conditional is pushed into a stack used by subsequent
invocations of
.Sx \&el ,
which may be separated by any intervening input (or not exist at all).
Its syntax is equivalent to
.Sx \&if .
.Ss \&if
Begins a conditional.
Right now, the conditional evaluates to true
if and only if it starts with the letter
.Sy n ,
indicating processing in
.Xr nroff 1
style as opposed to
.Xr troff 1
style.
If a conditional is false, its children are not processed, but are
syntactically interpreted to preserve the integrity of the input
document.
Thus,
.Pp
.D1 \&.if t \e .ig
.Pp
will discard the
.Sq \&.ig ,
which may lead to interesting results, but
.Pp
.D1 \&.if t \e .if t \e{\e
.Pp
will continue to syntactically interpret to the block close of the final
conditional.
Sub-conditionals, in this case, obviously inherit the truth value of
the parent.
This macro has the following syntax:
.Pp
.Bd -literal -offset indent -compact
\&.if COND \e{\e
BODY...
\&.\e}
.Ed
.Bd -literal -offset indent -compact
\&.if COND \e{ BODY
BODY... \e}
.Ed
.Bd -literal -offset indent -compact
\&.if COND \e{ BODY
BODY...
\&.\e}
.Ed
.Bd -literal -offset indent -compact
\&.if COND \e
BODY
.Ed
.Pp
COND is a conditional statement.
roff allows for complicated conditionals; mandoc is much simpler.
At this time, mandoc supports only
.Sq n ,
evaluating to true;
and
.Sq t ,
.Sq e ,
and
.Sq o ,
evaluating to false.
All other invocations are read up to the next end of line or space and
evaluate as false.
.Pp
If the BODY section is begun by an escaped brace
.Sq \e{ ,
scope continues until a closing-brace macro
.Sq \.\e} .
If the BODY is not enclosed in braces, scope continues until the next
macro or word.
If the COND is followed by a BODY on the same line, whether after a
brace or not, then macros
.Em must
begin with a control character.
It is generally more intuitive, in this case, to write
.Bd -literal -offset indent
\&.if COND \e{\e
\&.foo
bar
\&.\e}
.Ed
.Pp
than having the macro follow as
.Pp
.D1 \&.if COND \e{ .foo
.Pp
The scope of a conditional is always parsed, but only executed if the
conditional evaluates to true.
.Pp
Note that text subsequent a
.Sq \&.\e}
macro is discarded.
Furthermore, if an explicit closing sequence
.Sq \e}
is specified in a free-form line, the entire line is accepted within the
scope of the prior macro, not only the text preceding the close, with the
.Sq \e}
collapsing into a zero-width space.
.Ss \&ig
Ignore input.
Accepts the following syntax:
.Pp
.Bd -literal -offset indent -compact
\&.ig
BODY...
\&..
.Ed
.Bd -literal -offset indent -compact
\&.ig END
BODY...
\&.END
.Ed
.Pp
In the first case, input is ignored until a
.Sq \&..
macro is encountered on its own line.
In the second case, input is ignored until a
.Sq \&.END
is encountered.
Text subsequent the
.Sq \&.END
or
.Sq \&..
is discarded.
.Pp
Do not use the escape
.Sq \e
anywhere in the definition of END.
It causes very strange behaviour.
Furthermore, if you redefine a
.Nm
macro, such as
.Pp
.D1 \&.ig if
.Pp
the subsequent invocation of
.Sx \&if
will first signify the end of comment, then be invoked as a macro.
This behaviour really shouldn't be counted upon.
.Ss \&rm
Remove a request, macro or string.
This macro is intended to have one argument,
the name of the request, macro or string to be undefined.
Currently, it is ignored including its arguments,
and the number of arguments is not checked.
.Ss \&tr
Output character translation.
This macro is intended to have one argument,
consisting of an even number of characters.
Currently, it is ignored including its arguments,
and the number of arguments is not checked.
.Sh COMPATIBILITY
This section documents compatibility between mandoc and other other
troff implementations, at this time limited to GNU troff
.Pq Qq groff .
The term
.Qq historic groff
refers to groff versions before the
.Pa doc.tmac
file re-write
.Pq somewhere between 1.15 and 1.19 .
.Pp
.Bl -dash -compact
.It
Historic groff did not accept white-space buffering the custom END tag
for the
.Sx \&ig
macro.
.It
The
.Sx \&if
and family would print funny white-spaces with historic groff when
depending on next-line syntax.
.El
.Sh AUTHORS
The
.Nm
reference was written by
.An Kristaps Dzonsons Aq kristaps@bsd.lv .

View file

@ -1,857 +0,0 @@
/* $Id: roff.c,v 1.88 2010/06/10 21:42:02 kristaps Exp $ */
/*
* Copyright (c) 2010 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <assert.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "mandoc.h"
#include "roff.h"
#define RSTACK_MAX 128
#define ROFF_CTL(c) \
('.' == (c) || '\'' == (c))
#ifndef __minix
#if 1
#define ROFF_DEBUG(fmt, args...) \
do { /* Nothing. */ } while (/*CONSTCOND*/ 0)
#else
#define ROFF_DEBUG(fmt, args...) \
do { fprintf(stderr, fmt , ##args); } while (/*CONSTCOND*/ 0)
#endif
#else
void do_nothing(char *fmt, ...)
{
}
#if 1
#define ROFF_DEBUG do_nothing
#else
#define ROFF_DEBUG fprintf
#endif
#endif
enum rofft {
ROFF_am,
ROFF_ami,
ROFF_am1,
ROFF_de,
ROFF_dei,
ROFF_de1,
ROFF_ds,
ROFF_el,
ROFF_ie,
ROFF_if,
ROFF_ig,
ROFF_rm,
ROFF_tr,
ROFF_cblock,
ROFF_ccond,
ROFF_MAX
};
enum roffrule {
ROFFRULE_ALLOW,
ROFFRULE_DENY
};
struct roff {
struct roffnode *last; /* leaf of stack */
mandocmsg msg; /* err/warn/fatal messages */
void *data; /* privdata for messages */
enum roffrule rstack[RSTACK_MAX]; /* stack of !`ie' rules */
int rstackpos; /* position in rstack */
};
struct roffnode {
enum rofft tok; /* type of node */
struct roffnode *parent; /* up one in stack */
int line; /* parse line */
int col; /* parse col */
char *end; /* end-rules: custom token */
int endspan; /* end-rules: next-line or infty */
enum roffrule rule; /* current evaluation rule */
};
#define ROFF_ARGS struct roff *r, /* parse ctx */ \
enum rofft tok, /* tok of macro */ \
char **bufp, /* input buffer */ \
size_t *szp, /* size of input buffer */ \
int ln, /* parse line */ \
int ppos, /* original pos in buffer */ \
int pos, /* current pos in buffer */ \
int *offs /* reset offset of buffer data */
typedef enum rofferr (*roffproc)(ROFF_ARGS);
struct roffmac {
const char *name; /* macro name */
roffproc proc; /* process new macro */
roffproc text; /* process as child text of macro */
roffproc sub; /* process as child of macro */
int flags;
#define ROFFMAC_STRUCT (1 << 0) /* always interpret */
struct roffmac *next;
};
static enum rofferr roff_block(ROFF_ARGS);
static enum rofferr roff_block_text(ROFF_ARGS);
static enum rofferr roff_block_sub(ROFF_ARGS);
static enum rofferr roff_cblock(ROFF_ARGS);
static enum rofferr roff_ccond(ROFF_ARGS);
static enum rofferr roff_cond(ROFF_ARGS);
static enum rofferr roff_cond_text(ROFF_ARGS);
static enum rofferr roff_cond_sub(ROFF_ARGS);
static enum roffrule roff_evalcond(const char *, int *);
static enum rofferr roff_line(ROFF_ARGS);
/* See roff_hash_find() */
#define ASCII_HI 126
#define ASCII_LO 33
#define HASHWIDTH (ASCII_HI - ASCII_LO + 1)
static struct roffmac *hash[HASHWIDTH];
static struct roffmac roffs[ROFF_MAX] = {
{ "am", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "ami", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "am1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "de", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "dei", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "de1", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "ds", roff_line, NULL, NULL, 0, NULL },
{ "el", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "ie", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "if", roff_cond, roff_cond_text, roff_cond_sub, ROFFMAC_STRUCT, NULL },
{ "ig", roff_block, roff_block_text, roff_block_sub, 0, NULL },
{ "rm", roff_line, NULL, NULL, 0, NULL },
{ "tr", roff_line, NULL, NULL, 0, NULL },
{ ".", roff_cblock, NULL, NULL, 0, NULL },
{ "\\}", roff_ccond, NULL, NULL, 0, NULL },
};
static void roff_free1(struct roff *);
static enum rofft roff_hash_find(const char *);
static void roff_hash_init(void);
static void roffnode_cleanscope(struct roff *);
static int roffnode_push(struct roff *,
enum rofft, int, int);
static void roffnode_pop(struct roff *);
static enum rofft roff_parse(const char *, int *);
/* See roff_hash_find() */
#define ROFF_HASH(p) (p[0] - ASCII_LO)
static void
roff_hash_init(void)
{
struct roffmac *n;
int buc, i;
for (i = 0; i < (int)ROFF_MAX; i++) {
assert(roffs[i].name[0] >= ASCII_LO);
assert(roffs[i].name[0] <= ASCII_HI);
buc = ROFF_HASH(roffs[i].name);
if (NULL != (n = hash[buc])) {
for ( ; n->next; n = n->next)
/* Do nothing. */ ;
n->next = &roffs[i];
} else
hash[buc] = &roffs[i];
}
}
/*
* Look up a roff token by its name. Returns ROFF_MAX if no macro by
* the nil-terminated string name could be found.
*/
static enum rofft
roff_hash_find(const char *p)
{
int buc;
struct roffmac *n;
/*
* libroff has an extremely simple hashtable, for the time
* being, which simply keys on the first character, which must
* be printable, then walks a chain. It works well enough until
* optimised.
*/
if (p[0] < ASCII_LO || p[0] > ASCII_HI)
return(ROFF_MAX);
buc = ROFF_HASH(p);
if (NULL == (n = hash[buc]))
return(ROFF_MAX);
for ( ; n; n = n->next)
if (0 == strcmp(n->name, p))
return((enum rofft)(n - roffs));
return(ROFF_MAX);
}
/*
* Pop the current node off of the stack of roff instructions currently
* pending.
*/
static void
roffnode_pop(struct roff *r)
{
struct roffnode *p;
assert(r->last);
p = r->last;
if (ROFF_el == p->tok)
if (r->rstackpos > -1)
r->rstackpos--;
r->last = r->last->parent;
if (p->end)
free(p->end);
free(p);
}
/*
* Push a roff node onto the instruction stack. This must later be
* removed with roffnode_pop().
*/
static int
roffnode_push(struct roff *r, enum rofft tok, int line, int col)
{
struct roffnode *p;
if (NULL == (p = calloc(1, sizeof(struct roffnode)))) {
(*r->msg)(MANDOCERR_MEM, r->data, line, col, NULL);
return(0);
}
p->tok = tok;
p->parent = r->last;
p->line = line;
p->col = col;
p->rule = p->parent ? p->parent->rule : ROFFRULE_DENY;
r->last = p;
return(1);
}
static void
roff_free1(struct roff *r)
{
while (r->last)
roffnode_pop(r);
}
void
roff_reset(struct roff *r)
{
roff_free1(r);
}
void
roff_free(struct roff *r)
{
roff_free1(r);
free(r);
}
struct roff *
roff_alloc(const mandocmsg msg, void *data)
{
struct roff *r;
if (NULL == (r = calloc(1, sizeof(struct roff)))) {
(*msg)(MANDOCERR_MEM, data, 0, 0, NULL);
return(0);
}
r->msg = msg;
r->data = data;
r->rstackpos = -1;
roff_hash_init();
return(r);
}
enum rofferr
roff_parseln(struct roff *r, int ln,
char **bufp, size_t *szp, int pos, int *offs)
{
enum rofft t;
int ppos;
/*
* First, if a scope is open and we're not a macro, pass the
* text through the macro's filter. If a scope isn't open and
* we're not a macro, just let it through.
*/
if (r->last && ! ROFF_CTL((*bufp)[pos])) {
t = r->last->tok;
assert(roffs[t].text);
ROFF_DEBUG("roff: intercept scoped text: %s, [%s]\n",
roffs[t].name, &(*bufp)[pos]);
return((*roffs[t].text)
(r, t, bufp, szp, ln, pos, pos, offs));
} else if ( ! ROFF_CTL((*bufp)[pos])) {
ROFF_DEBUG("roff: pass non-scoped text: [%s]\n",
&(*bufp)[pos]);
return(ROFF_CONT);
}
/*
* If a scope is open, go to the child handler for that macro,
* as it may want to preprocess before doing anything with it.
*/
if (r->last) {
t = r->last->tok;
assert(roffs[t].sub);
ROFF_DEBUG("roff: intercept scoped context: %s\n",
roffs[t].name);
return((*roffs[t].sub)
(r, t, bufp, szp, ln, pos, pos, offs));
}
/*
* Lastly, as we've no scope open, try to look up and execute
* the new macro. If no macro is found, simply return and let
* the compilers handle it.
*/
ppos = pos;
if (ROFF_MAX == (t = roff_parse(*bufp, &pos))) {
ROFF_DEBUG("roff: pass non-scoped non-macro: [%s]\n",
&(*bufp)[pos]);
return(ROFF_CONT);
}
ROFF_DEBUG("roff: intercept new-scope: %s, [%s]\n",
roffs[t].name, &(*bufp)[pos]);
assert(roffs[t].proc);
return((*roffs[t].proc)
(r, t, bufp, szp, ln, ppos, pos, offs));
}
int
roff_endparse(struct roff *r)
{
if (NULL == r->last)
return(1);
return((*r->msg)(MANDOCERR_SCOPEEXIT, r->data, r->last->line,
r->last->col, NULL));
}
/*
* Parse a roff node's type from the input buffer. This must be in the
* form of ".foo xxx" in the usual way.
*/
static enum rofft
roff_parse(const char *buf, int *pos)
{
int j;
char mac[5];
enum rofft t;
assert(ROFF_CTL(buf[*pos]));
(*pos)++;
while (buf[*pos] && (' ' == buf[*pos] || '\t' == buf[*pos]))
(*pos)++;
if ('\0' == buf[*pos])
return(ROFF_MAX);
for (j = 0; j < 4; j++, (*pos)++)
if ('\0' == (mac[j] = buf[*pos]))
break;
else if (' ' == buf[*pos] || (j && '\\' == buf[*pos]))
break;
if (j == 4 || j < 1)
return(ROFF_MAX);
mac[j] = '\0';
if (ROFF_MAX == (t = roff_hash_find(mac)))
return(t);
while (buf[*pos] && ' ' == buf[*pos])
(*pos)++;
return(t);
}
/* ARGSUSED */
static enum rofferr
roff_cblock(ROFF_ARGS)
{
/*
* A block-close `..' should only be invoked as a child of an
* ignore macro, otherwise raise a warning and just ignore it.
*/
if (NULL == r->last) {
if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
return(ROFF_ERR);
return(ROFF_IGN);
}
switch (r->last->tok) {
case (ROFF_am):
/* FALLTHROUGH */
case (ROFF_ami):
/* FALLTHROUGH */
case (ROFF_am1):
/* FALLTHROUGH */
case (ROFF_de):
/* FALLTHROUGH */
case (ROFF_dei):
/* FALLTHROUGH */
case (ROFF_de1):
/* FALLTHROUGH */
case (ROFF_ig):
break;
default:
if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
return(ROFF_ERR);
return(ROFF_IGN);
}
if ((*bufp)[pos])
if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
return(ROFF_ERR);
roffnode_pop(r);
roffnode_cleanscope(r);
return(ROFF_IGN);
}
static void
roffnode_cleanscope(struct roff *r)
{
while (r->last) {
if (--r->last->endspan < 0)
break;
roffnode_pop(r);
}
}
/* ARGSUSED */
static enum rofferr
roff_ccond(ROFF_ARGS)
{
if (NULL == r->last) {
if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
return(ROFF_ERR);
return(ROFF_IGN);
}
switch (r->last->tok) {
case (ROFF_el):
/* FALLTHROUGH */
case (ROFF_ie):
/* FALLTHROUGH */
case (ROFF_if):
break;
default:
if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
return(ROFF_ERR);
return(ROFF_IGN);
}
if (r->last->endspan > -1) {
if ( ! (*r->msg)(MANDOCERR_NOSCOPE, r->data, ln, ppos, NULL))
return(ROFF_ERR);
return(ROFF_IGN);
}
if ((*bufp)[pos])
if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
return(ROFF_ERR);
roffnode_pop(r);
roffnode_cleanscope(r);
return(ROFF_IGN);
}
/* ARGSUSED */
static enum rofferr
roff_block(ROFF_ARGS)
{
int sv;
size_t sz;
if (ROFF_ig != tok && '\0' == (*bufp)[pos]) {
if ( ! (*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
return(ROFF_ERR);
return(ROFF_IGN);
} else if (ROFF_ig != tok) {
while ((*bufp)[pos] && ' ' != (*bufp)[pos])
pos++;
while (' ' == (*bufp)[pos])
pos++;
}
if ( ! roffnode_push(r, tok, ln, ppos))
return(ROFF_ERR);
if ('\0' == (*bufp)[pos])
return(ROFF_IGN);
sv = pos;
while ((*bufp)[pos] && ' ' != (*bufp)[pos] &&
'\t' != (*bufp)[pos])
pos++;
/*
* Note: groff does NOT like escape characters in the input.
* Instead of detecting this, we're just going to let it fly and
* to hell with it.
*/
assert(pos > sv);
sz = (size_t)(pos - sv);
if (1 == sz && '.' == (*bufp)[sv])
return(ROFF_IGN);
r->last->end = malloc(sz + 1);
if (NULL == r->last->end) {
(*r->msg)(MANDOCERR_MEM, r->data, ln, pos, NULL);
return(ROFF_ERR);
}
memcpy(r->last->end, *bufp + sv, sz);
r->last->end[(int)sz] = '\0';
if ((*bufp)[pos])
if ( ! (*r->msg)(MANDOCERR_ARGSLOST, r->data, ln, pos, NULL))
return(ROFF_ERR);
return(ROFF_IGN);
}
/* ARGSUSED */
static enum rofferr
roff_block_sub(ROFF_ARGS)
{
enum rofft t;
int i, j;
/*
* First check whether a custom macro exists at this level. If
* it does, then check against it. This is some of groff's
* stranger behaviours. If we encountered a custom end-scope
* tag and that tag also happens to be a "real" macro, then we
* need to try interpreting it again as a real macro. If it's
* not, then return ignore. Else continue.
*/
if (r->last->end) {
i = pos + 1;
while (' ' == (*bufp)[i] || '\t' == (*bufp)[i])
i++;
for (j = 0; r->last->end[j]; j++, i++)
if ((*bufp)[i] != r->last->end[j])
break;
if ('\0' == r->last->end[j] &&
('\0' == (*bufp)[i] ||
' ' == (*bufp)[i] ||
'\t' == (*bufp)[i])) {
roffnode_pop(r);
roffnode_cleanscope(r);
if (ROFF_MAX != roff_parse(*bufp, &pos))
return(ROFF_RERUN);
return(ROFF_IGN);
}
}
/*
* If we have no custom end-query or lookup failed, then try
* pulling it out of the hashtable.
*/
ppos = pos;
t = roff_parse(*bufp, &pos);
/* If we're not a comment-end, then throw it away. */
if (ROFF_cblock != t)
return(ROFF_IGN);
assert(roffs[t].proc);
return((*roffs[t].proc)(r, t, bufp,
szp, ln, ppos, pos, offs));
}
/* ARGSUSED */
static enum rofferr
roff_block_text(ROFF_ARGS)
{
return(ROFF_IGN);
}
/* ARGSUSED */
static enum rofferr
roff_cond_sub(ROFF_ARGS)
{
enum rofft t;
enum roffrule rr;
struct roffnode *l;
ppos = pos;
rr = r->last->rule;
/*
* Clean out scope. If we've closed ourselves, then don't
* continue.
*/
l = r->last;
roffnode_cleanscope(r);
if (l != r->last)
return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
if (ROFF_MAX == (t = roff_parse(*bufp, &pos)))
return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
/*
* A denied conditional must evaluate its children if and only
* if they're either structurally required (such as loops and
* conditionals) or a closing macro.
*/
if (ROFFRULE_DENY == rr)
if ( ! (ROFFMAC_STRUCT & roffs[t].flags))
if (ROFF_ccond != t)
return(ROFF_IGN);
assert(roffs[t].proc);
return((*roffs[t].proc)
(r, t, bufp, szp, ln, ppos, pos, offs));
}
/* ARGSUSED */
static enum rofferr
roff_cond_text(ROFF_ARGS)
{
char *ep, *st;
enum roffrule rr;
rr = r->last->rule;
/*
* We display the value of the text if out current evaluation
* scope permits us to do so.
*/
st = &(*bufp)[pos];
if (NULL == (ep = strstr(st, "\\}"))) {
roffnode_cleanscope(r);
return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
}
if (ep == st || (ep > st && '\\' != *(ep - 1)))
roffnode_pop(r);
roffnode_cleanscope(r);
return(ROFFRULE_DENY == rr ? ROFF_IGN : ROFF_CONT);
}
static enum roffrule
roff_evalcond(const char *v, int *pos)
{
switch (v[*pos]) {
case ('n'):
(*pos)++;
return(ROFFRULE_ALLOW);
case ('e'):
/* FALLTHROUGH */
case ('o'):
/* FALLTHROUGH */
case ('t'):
(*pos)++;
return(ROFFRULE_DENY);
default:
break;
}
while (v[*pos] && ' ' != v[*pos])
(*pos)++;
return(ROFFRULE_DENY);
}
/* ARGSUSED */
static enum rofferr
roff_cond(ROFF_ARGS)
{
int sv;
enum roffrule rule;
/* Stack overflow! */
if (ROFF_ie == tok && r->rstackpos == RSTACK_MAX - 1) {
(*r->msg)(MANDOCERR_MEM, r->data, ln, ppos, NULL);
return(ROFF_ERR);
}
/* First, evaluate the conditional. */
if (ROFF_el == tok) {
/*
* An `.el' will get the value of the current rstack
* entry set in prior `ie' calls or defaults to DENY.
*/
if (r->rstackpos < 0)
rule = ROFFRULE_DENY;
else
rule = r->rstack[r->rstackpos];
} else
rule = roff_evalcond(*bufp, &pos);
sv = pos;
while (' ' == (*bufp)[pos])
pos++;
/*
* Roff is weird. If we have just white-space after the
* conditional, it's considered the BODY and we exit without
* really doing anything. Warn about this. It's probably
* wrong.
*/
if ('\0' == (*bufp)[pos] && sv != pos) {
if ((*r->msg)(MANDOCERR_NOARGS, r->data, ln, ppos, NULL))
return(ROFF_IGN);
return(ROFF_ERR);
}
if ( ! roffnode_push(r, tok, ln, ppos))
return(ROFF_ERR);
r->last->rule = rule;
ROFF_DEBUG("roff: cond: %s -> %s\n", roffs[tok].name,
ROFFRULE_ALLOW == rule ? "allow" : "deny");
if (ROFF_ie == tok) {
/*
* An if-else will put the NEGATION of the current
* evaluated conditional into the stack.
*/
r->rstackpos++;
if (ROFFRULE_DENY == r->last->rule)
r->rstack[r->rstackpos] = ROFFRULE_ALLOW;
else
r->rstack[r->rstackpos] = ROFFRULE_DENY;
}
/* If the parent has false as its rule, then so do we. */
if (r->last->parent && ROFFRULE_DENY == r->last->parent->rule) {
r->last->rule = ROFFRULE_DENY;
ROFF_DEBUG("roff: cond override: %s -> deny\n",
roffs[tok].name);
}
/*
* Determine scope. If we're invoked with "\{" trailing the
* conditional, then we're in a multiline scope. Else our scope
* expires on the next line.
*/
r->last->endspan = 1;
if ('\\' == (*bufp)[pos] && '{' == (*bufp)[pos + 1]) {
r->last->endspan = -1;
pos += 2;
ROFF_DEBUG("roff: cond-scope: %s, multi-line\n",
roffs[tok].name);
} else
ROFF_DEBUG("roff: cond-scope: %s, one-line\n",
roffs[tok].name);
/*
* If there are no arguments on the line, the next-line scope is
* assumed.
*/
if ('\0' == (*bufp)[pos])
return(ROFF_IGN);
/* Otherwise re-run the roff parser after recalculating. */
*offs = pos;
return(ROFF_RERUN);
}
/* ARGSUSED */
static enum rofferr
roff_line(ROFF_ARGS)
{
return(ROFF_IGN);
}

View file

@ -1,77 +0,0 @@
div.body { color: #333333;
max-width: 800px;
padding-left: 10px;
font-size: smaller;
font-family: Verdana, Tahoma, Arial, sans-serif; }
div.sec-head { color: #000000;
font-weight: bold; }
div.sec-body { }
div.sec-block { padding-bottom: 1em; }
div.ssec-head { color: #000000;
font-weight: bold; }
div.ssec-body { }
div.ssec-block { }
span.addr { } /* Address (Ad). */
span.arg { font-style: italic; } /* Command argument (Ar). */
span.author { } /* Author name (An). */
span.cmd { font-weight: bold; } /* Command (Cm). */
span.config { font-weight: bold; } /* Config statement (Cd). */
span.define { } /* Defines (Dv). */
span.desc { } /* Nd. After em-dash. */
span.diag { font-weight: bold; } /* Diagnostic (Bl -diag). */
span.emph { font-style: italic; } /* Emphasis (Em). */
span.env { } /* Environment variables (Ev). */
span.errno { } /* Error string (Er). */
span.farg { font-style: italic; } /* Function argument (Fa, Fn). */
span.file { font-style: italic; } /* File (Pa). */
span.flag { font-weight: bold; } /* Flag (Fl, Cm). */
span.fname { font-weight: bold; } /* Function name (Fa, Fn, Rv). */
span.ftype { font-style: italic; } /* Function types (Ft, Fn). */
span.includes { font-weight: bold; } /* Header includes (In). */
span.lib { } /* Library (Lb). */
span.lit { font-family: monospace; } /* Literals (Bf -literal). */
span.macro { font-weight: bold; } /* Macro-ish thing (Fd). */
span.name { color: #003333; font-weight: bold; } /* Name of utility (Nm). */
span.opt { } /* Options (Op, Oo/Oc). */
span.ref { } /* Citations (Rs). */
span.ref-auth { } /* Reference author (%A). */
span.ref-book { font-style: italic; } /* Reference book (%B). */
span.ref-city { } /* Reference city (%C). */
span.ref-date { } /* Reference date (%D). */
span.ref-issue { font-style: italic; } /* Reference issuer/publisher (%I). */
span.ref-jrnl { font-style: italic; } /* Reference journal (%J). */
span.ref-num { } /* Reference number (%N). */
span.ref-opt { } /* Reference optionals (%O). */
span.ref-page { } /* Reference page (%P). */
span.ref-corp { } /* Reference corporate/foreign author (%Q). */
span.ref-rep { } /* Reference report (%R). */
span.ref-title { } /* Reference title (%T). */
span.ref-vol { } /* Reference volume (%V). */
span.symb { font-weight: bold; } /* Symbols. */
span.type { font-style: italic; } /* Variable types (Vt). */
span.unix { } /* Unices (Ux, Ox, Nx, Fx, Bx, Bsx, Dx). */
span.utility { font-weight: bold; } /* Name of utility (Ex). */
span.var { font-weight: bold; } /* Variables (Rv). */
a.link-ext { background: transparent url(external.png) center right no-repeat; padding-right: 12px; }/* Off-site link (Lk). */
a.link-includes { } /* Include-file link (In). */
a.link-mail { background: transparent url(external.png) center right no-repeat; padding-right: 12px; }/* Mailto links (Mt). */
a.link-man { } /* Manual links (Xr). */
a.link-sec { text-decoration: none; border-bottom: 1px dotted #339999; } /* Section links (Sx). */
div.emph { font-style: italic; } /* Emphasis (Bl -emphasis). */
div.lit { margin: 3px;
padding: 3px;
background-color: #EEEEEE;
border: 1px solid #339999;
color: #000000;
font-family: monospace; }
div.symb { font-weight: bold; } /* Symbols (Bl -symbolic). */
table.header { border-bottom: 1px dotted #dddddd;
color: #999999; }
table.footer { border-top: 1px dotted #dddddd;
color: #999999; }

View file

@ -1,427 +0,0 @@
/* $Id: term_ps.c,v 1.10 2010/06/19 20:46:28 kristaps Exp $ */
/*
* Copyright (c) 2008, 2009 Kristaps Dzonsons <kristaps@bsd.lv>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <sys/param.h>
#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "out.h"
#include "main.h"
#include "term.h"
#define PS_CHAR_WIDTH 6
#define PS_CHAR_HEIGHT 12
#define PS_CHAR_TOPMARG (792 - 24)
#define PS_CHAR_TOP (PS_CHAR_TOPMARG - 36)
#define PS_CHAR_LEFT 36
#define PS_CHAR_BOTMARG 24
#define PS_CHAR_BOT (PS_CHAR_BOTMARG + 36)
#define PS_BUFSLOP 128
#define PS_GROWBUF(p, sz) \
do if ((p)->engine.ps.psmargcur + (sz) > \
(p)->engine.ps.psmargsz) { \
(p)->engine.ps.psmargsz += /* CONSTCOND */ \
MAX(PS_BUFSLOP, (sz)); \
(p)->engine.ps.psmarg = realloc \
((p)->engine.ps.psmarg, \
(p)->engine.ps.psmargsz); \
if (NULL == (p)->engine.ps.psmarg) { \
perror(NULL); \
exit(EXIT_FAILURE); \
} \
} while (/* CONSTCOND */ 0)
static void ps_letter(struct termp *, char);
static void ps_begin(struct termp *);
static void ps_end(struct termp *);
static void ps_advance(struct termp *, size_t);
static void ps_endline(struct termp *);
static void ps_fclose(struct termp *);
static void ps_pclose(struct termp *);
static void ps_pletter(struct termp *, char);
static void ps_printf(struct termp *, const char *, ...);
static void ps_putchar(struct termp *, char);
static void ps_setfont(struct termp *, enum termfont);
void *
ps_alloc(void)
{
struct termp *p;
if (NULL == (p = term_alloc(TERMENC_ASCII)))
return(NULL);
p->type = TERMTYPE_PS;
p->letter = ps_letter;
p->begin = ps_begin;
p->end = ps_end;
p->advance = ps_advance;
p->endline = ps_endline;
return(p);
}
void
ps_free(void *arg)
{
struct termp *p;
p = (struct termp *)arg;
if (p->engine.ps.psmarg)
free(p->engine.ps.psmarg);
term_free(p);
}
static void
ps_printf(struct termp *p, const char *fmt, ...)
{
va_list ap;
int pos;
va_start(ap, fmt);
/*
* If we're running in regular mode, then pipe directly into
* vprintf(). If we're processing margins, then push the data
* into our growable margin buffer.
*/
if ( ! (PS_MARGINS & p->engine.ps.psstate)) {
vprintf(fmt, ap);
va_end(ap);
return;
}
/*
* XXX: I assume that the in-margin print won't exceed
* PS_BUFSLOP (128 bytes), which is reasonable but still an
* assumption that will cause pukeage if it's not the case.
*/
PS_GROWBUF(p, PS_BUFSLOP);
pos = (int)p->engine.ps.psmargcur;
vsnprintf(&p->engine.ps.psmarg[pos], PS_BUFSLOP, fmt, ap);
p->engine.ps.psmargcur = strlen(p->engine.ps.psmarg);
va_end(ap);
}
static void
ps_putchar(struct termp *p, char c)
{
int pos;
/* See ps_printf(). */
if ( ! (PS_MARGINS & p->engine.ps.psstate)) {
putchar(c);
return;
}
PS_GROWBUF(p, 2);
pos = (int)p->engine.ps.psmargcur++;
p->engine.ps.psmarg[pos++] = c;
p->engine.ps.psmarg[pos] = '\0';
}
/* ARGSUSED */
static void
ps_end(struct termp *p)
{
/*
* At the end of the file, do one last showpage. This is the
* same behaviour as groff(1) and works for multiple pages as
* well as just one.
*/
assert(0 == p->engine.ps.psstate);
assert('\0' == p->engine.ps.last);
assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
printf("%s", p->engine.ps.psmarg);
printf("showpage\n");
printf("%s\n", "%%EOF");
}
static void
ps_begin(struct termp *p)
{
/*
* Print margins into margin buffer. Nothing gets output to the
* screen yet, so we don't need to initialise the primary state.
*/
if (p->engine.ps.psmarg) {
assert(p->engine.ps.psmargsz);
p->engine.ps.psmarg[0] = '\0';
}
p->engine.ps.psmargcur = 0;
p->engine.ps.psstate = PS_MARGINS;
p->engine.ps.pscol = PS_CHAR_LEFT;
p->engine.ps.psrow = PS_CHAR_TOPMARG;
ps_setfont(p, TERMFONT_NONE);
(*p->headf)(p, p->argf);
(*p->endline)(p);
p->engine.ps.pscol = PS_CHAR_LEFT;
p->engine.ps.psrow = PS_CHAR_BOTMARG;
(*p->footf)(p, p->argf);
(*p->endline)(p);
p->engine.ps.psstate &= ~PS_MARGINS;
assert(0 == p->engine.ps.psstate);
assert(p->engine.ps.psmarg);
assert('\0' != p->engine.ps.psmarg[0]);
/*
* Print header and initialise page state. Following this,
* stuff gets printed to the screen, so make sure we're sane.
*/
printf("%s\n", "%!PS");
ps_setfont(p, TERMFONT_NONE);
p->engine.ps.pscol = PS_CHAR_LEFT;
p->engine.ps.psrow = PS_CHAR_TOP;
}
static void
ps_pletter(struct termp *p, char c)
{
/*
* If we're not in a PostScript "word" context, then open one
* now at the current cursor.
*/
if ( ! (PS_INLINE & p->engine.ps.psstate)) {
ps_printf(p, "%zu %zu moveto\n(",
p->engine.ps.pscol,
p->engine.ps.psrow);
p->engine.ps.psstate |= PS_INLINE;
}
/*
* We need to escape these characters as per the PostScript
* specification. We would also escape non-graphable characters
* (like tabs), but none of them would get to this point and
* it's superfluous to abort() on them.
*/
switch (c) {
case ('('):
/* FALLTHROUGH */
case (')'):
/* FALLTHROUGH */
case ('\\'):
ps_putchar(p, '\\');
break;
default:
break;
}
/* Write the character and adjust where we are on the page. */
ps_putchar(p, c);
p->engine.ps.pscol += PS_CHAR_WIDTH;
}
static void
ps_pclose(struct termp *p)
{
/*
* Spit out that we're exiting a word context (this is a
* "partial close" because we don't check the last-char buffer
* or anything).
*/
if ( ! (PS_INLINE & p->engine.ps.psstate))
return;
ps_printf(p, ") show\n");
p->engine.ps.psstate &= ~PS_INLINE;
}
static void
ps_fclose(struct termp *p)
{
/*
* Strong closure: if we have a last-char, spit it out after
* checking that we're in the right font mode. This will of
* course open a new scope, if applicable.
*
* Following this, close out any scope that's open.
*/
if ('\0' != p->engine.ps.last) {
if (p->engine.ps.lastf != TERMFONT_NONE) {
ps_pclose(p);
ps_setfont(p, TERMFONT_NONE);
}
ps_pletter(p, p->engine.ps.last);
p->engine.ps.last = '\0';
}
if ( ! (PS_INLINE & p->engine.ps.psstate))
return;
ps_pclose(p);
}
static void
ps_letter(struct termp *p, char c)
{
char cc;
/*
* State machine dictates whether to buffer the last character
* or not. Basically, encoded words are detected by checking if
* we're an "8" and switching on the buffer. Then we put "8" in
* our buffer, and on the next charater, flush both character
* and buffer. Thus, "regular" words are detected by having a
* regular character and a regular buffer character.
*/
if ('\0' == p->engine.ps.last) {
assert(8 != c);
p->engine.ps.last = c;
return;
} else if (8 == p->engine.ps.last) {
assert(8 != c);
p->engine.ps.last = '\0';
} else if (8 == c) {
assert(8 != p->engine.ps.last);
if ('_' == p->engine.ps.last) {
if (p->engine.ps.lastf != TERMFONT_UNDER) {
ps_pclose(p);
ps_setfont(p, TERMFONT_UNDER);
}
} else if (p->engine.ps.lastf != TERMFONT_BOLD) {
ps_pclose(p);
ps_setfont(p, TERMFONT_BOLD);
}
p->engine.ps.last = c;
return;
} else {
if (p->engine.ps.lastf != TERMFONT_NONE) {
ps_pclose(p);
ps_setfont(p, TERMFONT_NONE);
}
cc = p->engine.ps.last;
p->engine.ps.last = c;
c = cc;
}
ps_pletter(p, c);
}
static void
ps_advance(struct termp *p, size_t len)
{
/*
* Advance some spaces. This can probably be made smarter,
* i.e., to have multiple space-separated words in the same
* scope, but this is easier: just close out the current scope
* and readjust our column settings.
*/
ps_fclose(p);
p->engine.ps.pscol += len ? len * PS_CHAR_WIDTH : 0;
}
static void
ps_endline(struct termp *p)
{
/* Close out any scopes we have open: we're at eoln. */
ps_fclose(p);
/*
* If we're in the margin, don't try to recalculate our current
* row. XXX: if the column tries to be fancy with multiple
* lines, we'll do nasty stuff.
*/
if (PS_MARGINS & p->engine.ps.psstate)
return;
/*
* Put us down a line. If we're at the page bottom, spit out a
* showpage and restart our row.
*/
p->engine.ps.pscol = PS_CHAR_LEFT;
if (p->engine.ps.psrow >= PS_CHAR_HEIGHT + PS_CHAR_BOT) {
p->engine.ps.psrow -= PS_CHAR_HEIGHT;
return;
}
assert(p->engine.ps.psmarg && p->engine.ps.psmarg[0]);
printf("%s", p->engine.ps.psmarg);
printf("showpage\n");
p->engine.ps.psrow = PS_CHAR_TOP;
}
static void
ps_setfont(struct termp *p, enum termfont f)
{
if (TERMFONT_BOLD == f)
ps_printf(p, "/Courier-Bold\n");
else if (TERMFONT_UNDER == f)
ps_printf(p, "/Courier-Oblique\n");
else
ps_printf(p, "/Courier\n");
ps_printf(p, "10 selectfont\n");
p->engine.ps.lastf = f;
}

View file

@ -0,0 +1,3 @@
# $NetBSD: Makefile.inc,v 1.1 2008/12/16 22:33:11 christos Exp $
.PATH.c: ${.PARSEDIR}
SRCS+= snprintb.c

View file

@ -0,0 +1,282 @@
/* $NetBSD: snprintb.c,v 1.5 2009/05/13 02:50:31 pgoyette Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* snprintb: print an interpreted bitmask to a buffer
*
* => returns the length of the buffer that would be required to print the
* string minus the terminating NUL.
*/
#ifndef _STANDALONE
# ifndef _KERNEL
# if HAVE_NBTOOL_CONFIG_H
# include "nbtool_config.h"
# endif
# include <sys/cdefs.h>
# if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: snprintb.c,v 1.5 2009/05/13 02:50:31 pgoyette Exp $");
# endif
# include <sys/types.h>
# include <sys/inttypes.h>
# include <stdio.h>
# include <util.h>
# include <errno.h>
# else
# include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: snprintb.c,v 1.5 2009/05/13 02:50:31 pgoyette Exp $");
# include <sys/param.h>
# include <sys/inttypes.h>
# include <sys/systm.h>
# include <lib/libkern/libkern.h>
# endif
int
snprintb_m(char *buf, size_t buflen, const char *bitfmt, uint64_t val,
size_t l_max)
{
char *bp = buf, *s_bp = NULL;
const char *c_fmt, *s_fmt = NULL, *cur_fmt;
const char *sbase;
int bit, ch, t_len, s_len = 0, l_len, f_len, v_len, sep;
int restart = 0;
uint64_t field;
#ifdef _KERNEL
/*
* For safety; no other *s*printf() do this, but in the kernel
* we don't usually check the return value
*/
(void)memset(buf, 0, buflen);
#endif /* _KERNEL */
ch = *bitfmt++;
switch (ch != '\177' ? ch : *bitfmt++) {
case 8:
sbase = "0%" PRIo64;
break;
case 10:
sbase = "%" PRId64;
break;
case 16:
sbase = "0x%" PRIx64;
break;
default:
goto internal;
}
/* Reserve space for trailing blank line if needed */
if (l_max > 0)
buflen--;
t_len = snprintf(bp, buflen, sbase, val);
if (t_len < 0)
goto internal;
v_len = l_len = t_len;
if ((size_t)t_len < buflen)
bp += t_len;
else
bp += buflen - 1;
/*
* If the value we printed was 0 and we're using the old-style format,
* we're done.
*/
if ((val == 0) && (ch != '\177'))
goto terminate;
#define STORE(c) { l_len++; \
if ((size_t)(++t_len) < buflen) \
*bp++ = (c); \
} while ( /* CONSTCOND */ 0)
#define BACKUP { if (s_bp != NULL) { \
bp = s_bp; s_bp = NULL; \
t_len -= l_len - s_len; \
restart = 1; \
bitfmt = s_fmt; \
} \
STORE('>'); STORE('\0'); \
if ((size_t)t_len < buflen) \
snprintf(bp, buflen - t_len, sbase, val); \
t_len += v_len; l_len = v_len; bp += v_len; \
} while ( /* CONSTCOND */ 0)
#define PUTSEP \
if (l_max > 0 && (size_t)l_len >= l_max) { \
BACKUP; \
STORE('<'); \
} else { \
/* Remember separator location */ \
if ( l_max > 0 && sep != '<') { \
s_len = l_len; \
s_bp = bp; \
s_fmt = cur_fmt; \
} \
STORE(sep); \
restart = 0; \
} \
#define PUTCHR(c) \
if (l_max > 0 && (size_t)l_len >= (l_max - 1)) { \
BACKUP; \
if (restart == 0) { \
STORE(c); \
} else \
sep = '<'; \
} else { \
STORE(c); \
restart = 0; \
} \
#define PUTS(s) while ((ch = *(s)++) != 0) { \
PUTCHR(ch); \
if (restart) \
break; \
}
/*
* Chris Torek's new bitmask format is identified by a leading \177
*/
sep = '<';
if (ch != '\177') {
/* old (standard) format. */
for (;(bit = *bitfmt) != 0;) {
cur_fmt = bitfmt++;
if (val & (1 << (bit - 1))) {
PUTSEP;
if (restart)
continue;
sep = ',';
for (; (ch = *bitfmt) > ' '; ++bitfmt) {
PUTCHR(ch);
if (restart)
break;
}
} else
for (; *bitfmt > ' '; ++bitfmt)
continue;
}
} else {
/* new quad-capable format; also does fields. */
field = val;
while (c_fmt = bitfmt, (ch = *bitfmt++) != '\0') {
bit = *bitfmt++; /* now 0-origin */
switch (ch) {
case 'b':
if (((u_int)(val >> bit) & 1) == 0)
goto skip;
cur_fmt = c_fmt;
PUTSEP;
if (restart)
break;
PUTS(bitfmt);
if (restart == 0)
sep = ',';
break;
case 'f':
case 'F':
cur_fmt = c_fmt;
f_len = *bitfmt++; /* field length */
field = (val >> bit) &
(((uint64_t)1 << f_len) - 1);
if (ch == 'F') /* just extract */
break;
PUTSEP;
if (restart == 0) {
sep = ',';
PUTS(bitfmt);
}
if (restart == 0) {
PUTCHR('=');
}
if (restart == 0) {
f_len = snprintf(bp, buflen - t_len,
sbase, field);
if (f_len < 0)
goto internal;
t_len += f_len;
l_len += f_len;
if ((size_t)t_len < buflen)
bp += f_len;
if (l_max > 0 &&
(size_t)l_len > l_max) {
PUTCHR('#');
}
}
break;
case '=':
case ':':
/*
* Here "bit" is actually a value instead,
* to be compared against the last field.
* This only works for values in [0..255],
* of course.
*/
if ((int)field != bit)
goto skip;
if (ch == '=') {
PUTCHR('=');
}
PUTS(bitfmt);
break;
default:
skip:
while (*bitfmt++ != '\0')
continue;
break;
}
}
}
l_len++;
if ((size_t)(++t_len) < buflen)
*bp++ = '>';
terminate:
*bp++ = '\0';
if (l_max != 0) {
t_len++;
*bp = '\0';
}
return t_len;
internal:
#ifndef _KERNEL
errno = EINVAL;
#endif
return -1;
}
int
snprintb(char *buf, size_t buflen, const char *bitfmt, uint64_t val)
{
return snprintb_m(buf, buflen, bitfmt, val, 0);
}
#endif

View file

@ -1,3 +1,7 @@
20110928:
Update your /usr/etc/daily and /etc/man.conf if you
want to fully enjoy the manpage fixes.
20110817: 20110817:
To use the new asynchronous version of VFS do: To use the new asynchronous version of VFS do:
# BUILDAVFS=yes make cleandepend world # BUILDAVFS=yes make cleandepend world

View file

@ -5,7 +5,7 @@ FILES1=fstab group hostname.file inet.conf motd.install mtab passwd profile \
protocols rc services termcap ttytab utmp rc.cd binary_sizes \ protocols rc services termcap ttytab utmp rc.cd binary_sizes \
binary_sizes.big binary_sizes.xxl syslog.conf rc.daemons.dist \ binary_sizes.big binary_sizes.xxl syslog.conf rc.daemons.dist \
rs.inet rs.single make.conf system.conf ttys resolv.conf rc.conf \ rs.inet rs.single make.conf system.conf ttys resolv.conf rc.conf \
rc.subr rc.subr man.conf
FILES2=shadow FILES2=shadow
FILES3=daily dhcptags.conf rc FILES3=daily dhcptags.conf rc

16
etc/man.conf Normal file
View file

@ -0,0 +1,16 @@
_version BSD.2
_subdir man{[1-9],1x}
_suffix .0
_build .[1-9] mandoc %s
_build .tbl tbl %s | mandoc
_default /usr/{,pkg/{,gcc44/}}man
_whatdb /usr/{,pkg/{,gcc44/}}man/whatis.db
1 man1
2 man2
3 man3
4 man4
5 man5
6 man6
7 man7
8 man8
9 man9

View file

@ -66,6 +66,9 @@ do
fi fi
done done
# Update manpage index
/usr/libexec/makewhatis
# Continue with a local script if present. # Continue with a local script if present.
test -f /usr/local/etc/daily && sh /usr/local/etc/daily $caller test -f /usr/local/etc/daily && sh /usr/local/etc/daily $caller
exit 0 exit 0

View file

@ -21,7 +21,7 @@ SUBDIR= csu ${LIBCOMPAT_DIR} ${LIBC_DIR} libdriver libnetdriver \
libddekit libminixfs libddekit libminixfs
.if defined(NBSD_LIBC) && (${NBSD_LIBC} != "no") .if defined(NBSD_LIBC) && (${NBSD_LIBC} != "no")
SUBDIR+= libelf libminc libcrypt libterminfo libcurses libvassert SUBDIR+= libelf libminc libcrypt libterminfo libcurses libvassert libutil
.endif .endif
.if ${COMPILER_TYPE} == "ack" .if ${COMPILER_TYPE} == "ack"
@ -31,7 +31,6 @@ SUBDIR+= ack/libd ack/libe ack/libfp ack/liby
.if ${OBJECT_FMT} == "a.out" .if ${OBJECT_FMT} == "a.out"
SUBDIR+= libend SUBDIR+= libend
.endif .endif
.include <bsd.subdir.mk> .include <bsd.subdir.mk>
build_ack: build_ack:

92
lib/libutil/Makefile Normal file
View file

@ -0,0 +1,92 @@
# $NetBSD: Makefile,v 1.63 2010/01/27 19:10:31 drochner Exp $
# @(#)Makefile 8.1 (Berkeley) 6/4/93
USE_SHLIBDIR= yes
.include <bsd.own.mk>
.include "${NETBSDSRCDIR}/common/lib/libutil/Makefile.inc"
WARNS= 4
LIB= util
CPPFLAGS+=-DLIBC_SCCS -I${.CURDIR}
SRCS= efun.c getbootfile.c \
getmntopts.c \
login.c loginx.c login_tty.c logout.c logoutx.c \
logwtmp.c logwtmpx.c opendisk.c \
passwd.c pw_scan.c pidfile.c pidlock.c pty.c \
raise_default_signal.c \
secure_path.c snprintb.c \
ttyaction.c
#disklabel_dkcksum.c disklabel_scan.c \
#if_media.c \
#sockaddr_snprintf.c
#getlabelsector.c
#getmaxpartitions.c
#stat_flags.c
#getrawpartition.c
#login_cap.c
#ttymsg.c
#parsedate.y
MAN= efun.3 getbootfile.3 getlabelsector.3 getmaxpartitions.3 \
getmntopts.3 \
getrawpartition.3 \
login.3 login_cap.3 loginx.3 \
disklabel_dkcksum.3 disklabel_scan.3 \
opendisk.3 openpty.3 parsedate.3 pidfile.3 pidlock.3 \
pw_getconf.3 pw_init.3 pw_lock.3 secure_path.3 \
raise_default_signal.3 \
snprintb.3 sockaddr_snprintf.3 stat_flags.3 ttyaction.3 \
ttymsg.3 util.3
YPREFIX=__pd
#.PATH: ${NETBSDSRCDIR}/lib/libc/gen
.PATH: ${NETBSDSRCDIR}/lib/nbsd_libc/gen
#.include "compat/Makefile.inc"
MLINKS+=getlabelsector.3 getlabeloffset.3
MLINKS+=login.3 logout.3
MLINKS+=login.3 logwtmp.3
MLINKS+=login_cap.3 login_getclass.3
MLINKS+=login_cap.3 login_getcapbool.3
MLINKS+=login_cap.3 login_getcapnum.3
MLINKS+=login_cap.3 login_getcapsize.3
MLINKS+=login_cap.3 login_getcapstr.3
MLINKS+=login_cap.3 login_getcaptime.3
MLINKS+=login_cap.3 login_close.3
MLINKS+=login_cap.3 setclasscontext.3
MLINKS+=login_cap.3 setusercontext.3
MLINKS+=loginx.3 logoutx.3 loginx.3 logwtmpx.3
MLINKS+=openpty.3 login_tty.3
MLINKS+=openpty.3 forkpty.3
MLINKS+=pw_getconf.3 pw_getpwconf.3
MLINKS+=pw_init.3 pw_edit.3
MLINKS+=pw_init.3 pw_prompt.3
MLINKS+=pw_init.3 pw_copy.3
MLINKS+=pw_init.3 pw_copyx.3
MLINKS+=pw_init.3 pw_scan.3
MLINKS+=pw_init.3 pw_error.3
MLINKS+=pw_lock.3 pw_mkdb.3
MLINKS+=pw_lock.3 pw_abort.3
MLINKS+=pw_lock.3 pw_getprefix.3
MLINKS+=pw_lock.3 pw_setprefix.3
MLINKS+=pidlock.3 ttylock.3
MLINKS+=pidlock.3 ttyunlock.3
MLINKS+=efun.3 esetfunc.3
MLINKS+=efun.3 easprintf.3
MLINKS+=efun.3 estrlcpy.3
MLINKS+=efun.3 estrlcat.3
MLINKS+=efun.3 estrdup.3
MLINKS+=efun.3 estrndup.3
MLINKS+=efun.3 emalloc.3
MLINKS+=efun.3 ecalloc.3
MLINKS+=efun.3 erealloc.3
MLINKS+=efun.3 efopen.3
MLINKS+=efun.3 evasprintf.3
MLINKS+=stat_flags.3 string_to_flags.3
MLINKS+=stat_flags.3 flags_to_string.3
MLINKS+=snprintb.3 snprintb_m.3
.include <bsd.lib.mk>

View file

@ -0,0 +1,7 @@
# $NetBSD: Makefile.inc,v 1.2 2009/01/11 02:57:18 christos Exp $
.PATH: ${.CURDIR}/compat
CPPFLAGS+=-I${.CURDIR}/../libc -I${.CURDIR}/../../sys
SRCS+=compat_passwd.c compat_loginx.c compat_login.c compat_parsedate.c \
compat_login_cap.c

View file

@ -0,0 +1,63 @@
/* $NetBSD: compat_gepwconf.c,v 1.2 2009/01/11 02:57:18 christos Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: compat_gepwconf.c,v 1.2 2009/01/11 02:57:18 christos Exp $");
#endif /* LIBC_SCCS and not lint */
#define __LIBC12_SOURCE__
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <compat/include/pwd.h>
#include <util.h>
#include <compat/util.h>
__warn_references(pw_getpwconf,
"warning: reference to compatibility pw_getpwconf(); "
"include <pwd.h> to generate correct reference")
void
pw_getpwconf(char *buf, size_t len, const struct passwd50 *p, const char *opt)
{
struct passwd px;
passwd50_to_passwd(p, &px);
__pw_getpwconf50(buf, len, &px, opt);
}

View file

@ -0,0 +1,78 @@
/* $NetBSD: compat_login.c,v 1.2 2009/01/11 02:57:18 christos Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)login.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: compat_login.c,v 1.2 2009/01/11 02:57:18 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#define __LIBC12_SOURCE__
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <util.h>
#include <compat/util.h>
#include <utmp.h>
#include <compat/include/utmp.h>
__warn_references(login,
"warning: reference to compatibility login(); include <util.h> to generate correct reference")
void
login(const struct utmp50 *ut50)
{
int fd;
int tty;
struct utmp ut;
utmp50_to_utmp(ut50, &ut);
tty = ttyslot();
if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) >= 0) {
(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
(void)write(fd, &ut, sizeof(ut));
(void)close(fd);
}
if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
(void)write(fd, &ut, sizeof(ut));
(void)close(fd);
}
}

View file

@ -0,0 +1,70 @@
/* $NetBSD: compat_login_cap.c,v 1.2 2009/01/11 02:57:18 christos Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#define __LIBC12_SOURCE__
#include <sys/types.h>
#include <login_cap.h>
#include <compat/login_cap.h>
#include <pwd.h>
#include <compat/include/pwd.h>
__warn_references(login_getpwclass,
"warning: reference to compatibility login_getpwclass();"
" include <login_cap.h> for correct reference")
__warn_references(setusercontext,
"warning: reference to compatibility setusercontext();"
" include <login_cap.h> for correct reference")
login_cap_t *
login_getpwclass(const struct passwd50 *pw50)
{
struct passwd pw;
passwd50_to_passwd(pw50, &pw);
return __login_getpwclass50(&pw);
}
int
setusercontext(login_cap_t *lc, struct passwd50 *pw50, uid_t uid, u_int flags)
{
struct passwd pw;
passwd50_to_passwd(pw50, &pw);
return __setusercontext50(lc, &pw, uid, flags);
}

View file

@ -0,0 +1,64 @@
/* $NetBSD: compat_loginx.c,v 1.2 2009/01/11 02:57:18 christos Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: compat_loginx.c,v 1.2 2009/01/11 02:57:18 christos Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#define __LIBC12_SOURCE__
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <util.h>
#include <compat/util.h>
#include <utmp.h>
#include <compat/include/utmp.h>
#include <utmpx.h>
#include <compat/include/utmpx.h>
__warn_references(loginx,
"warning: reference to compatibility loginx(); include <util.h> to generate correct reference")
void
loginx(const struct utmpx50 *ut50)
{
struct utmpx ut;
utmpx50_to_utmpx(ut50, &ut);
(void)__pututxline50(&ut);
(void)__updwtmpx50(_PATH_WTMPX, &ut);
}

View file

@ -0,0 +1,73 @@
/* $NetBSD: compat_logoutx.c,v 1.2 2009/01/11 02:57:18 christos Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)logout.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: compat_logoutx.c,v 1.2 2009/01/11 02:57:18 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <util.h>
#include <utmp.h>
#include <utmpx.h>
int
logoutx(const char *line, int status, int type)
{
struct utmpx *utp, ut;
(void)strlcpy(ut.ut_line, line, sizeof(ut.ut_line));
if ((utp = getutxline(&ut)) == NULL) {
endutxent();
return 0;
}
utp->ut_type = type;
if (WIFEXITED(status))
utp->ut_exit.e_exit = (uint16_t)WEXITSTATUS(status);
if (WIFSIGNALED(status))
utp->ut_exit.e_termination = (uint16_t)WTERMSIG(status);
(void)gettimeofday(&utp->ut_tv, NULL);
(void)pututxline(utp);
endutxent();
return 1;
}

View file

@ -0,0 +1,60 @@
/* $NetBSD: compat_parsedate.c,v 1.2 2009/01/11 02:57:18 christos Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#define __LIBC12_SOURCE__
#include <string.h>
#include <time.h>
#include <sys/time.h>
#include <compat/include/time.h>
#include <compat/sys/time.h>
#include <util.h>
#include <compat/util.h>
__warn_references(parsedate,
"warning: reference to compatibility parsedate();"
" include <util.h> for correct reference")
int32_t
parsedate(const char *str, const int32_t *t50, const int *tzoff)
{
time_t t;
if (t50)
t = *t50;
return (int32_t)__parsedate50(str, t50 ? &t : NULL, tzoff);
}

View file

@ -0,0 +1,103 @@
/* $NetBSD: compat_passwd.c,v 1.2 2009/01/11 02:57:18 christos Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: compat_passwd.c,v 1.2 2009/01/11 02:57:18 christos Exp $");
#endif /* LIBC_SCCS and not lint */
#define __LIBC12_SOURCE__
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <pwd.h>
#include <compat/include/pwd.h>
#include <util.h>
#include <compat/util.h>
__warn_references(pw_scan,
"warning: reference to compatibility pw_scan(); "
"include <pwd.h> to generate correct reference")
__warn_references(pw_copy,
"warning: reference to compatibility pw_copy(); "
"include <util.h> to generate correct reference")
__warn_references(pw_copyx,
"warning: reference to compatibility pw_copyx(); "
"include <util.h> to generate correct reference")
__warn_references(pw_getpwconf,
"warning: reference to compatibility pw_getpwconf(); "
"include <pwd.h> to generate correct reference")
int
pw_scan(char *buf, struct passwd50 *p, int *flags)
{
struct passwd px;
int rv = __pw_scan50(buf, &px, flags);
passwd_to_passwd50(&px, p);
return rv;
}
void
pw_copy(int ffd, int tfd, struct passwd50 *pw50, struct passwd50 *opw50)
{
struct passwd pw, opw;
passwd50_to_passwd(pw50, &pw);
if (opw50)
passwd50_to_passwd(opw50, &opw);
__pw_copy50(ffd, tfd, &pw, opw50 ? &opw : NULL);
}
int
pw_copyx(int ffd, int tfd, struct passwd50 *pw50, struct passwd50 *opw50,
char *errbuf, size_t errbufsiz)
{
struct passwd pw, opw;
passwd50_to_passwd(pw50, &pw);
if (opw50)
passwd50_to_passwd(opw50, &opw);
return __pw_copyx50(ffd, tfd, &pw, opw50 ? &opw : NULL, errbuf,
errbufsiz);
}
void
pw_getpwconf(char *buf, size_t len, const struct passwd50 *p, const char *opt)
{
struct passwd px;
passwd50_to_passwd(p, &px);
__pw_getpwconf50(buf, len, &px, opt);
}

View file

@ -0,0 +1,51 @@
/* $NetBSD: login_cap.h,v 1.2 2009/01/11 02:57:18 christos Exp $ */
/*-
* Copyright (c) 2008 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the NetBSD
* Foundation, Inc. and its contributors.
* 4. Neither the name of The NetBSD Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _COMPAT_LOGIN_CAP_H_
#define _COMPAT_LOGIN_CAP_H_
struct passwd;
struct passwd50;
__BEGIN_DECLS
login_cap_t *login_getpwclass(const struct passwd50 *);
login_cap_t *__login_getpwclass50(const struct passwd *);
int setusercontext(login_cap_t *, struct passwd50 *, uid_t, u_int);
int __setusercontext50(login_cap_t *, struct passwd *, uid_t, u_int);
__END_DECLS
#endif /* !_COMPAT_LOGIN_CAP_H_ */

63
lib/libutil/compat/util.h Normal file
View file

@ -0,0 +1,63 @@
/* $NetBSD: util.h,v 1.2 2009/01/11 02:57:18 christos Exp $ */
/*-
* Copyright (c) 1995
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#ifndef _COMPAT_UTIL_H_
#define _COMPAT_UTIL_H_
#include <sys/cdefs.h>
#include <sys/types.h>
#include <compat/include/pwd.h>
#include <compat/include/utmp.h>
#include <compat/include/utmpx.h>
#include <machine/ansi.h>
void login(const struct utmp50 *);
void loginx(const struct utmpx50 *);
int32_t parsedate(const char *, const int32_t *, const int *);
void pw_copy(int, int, struct passwd50 *, struct passwd50 *);
int pw_copyx(int, int, struct passwd50 *, struct passwd50 *,
char *, size_t);
void pw_getpwconf(char *, size_t, const struct passwd50 *,
const char *);
void __login50(const struct utmp *);
void __loginx50(const struct utmpx *);
time_t __parsedate50(const char *, const time_t *, const int *);
void __pw_copy50(int, int, struct passwd *, struct passwd *);
int __pw_copyx50(int, int, struct passwd *, struct passwd *,
char *, size_t);
void __pw_getpwconf50(char *, size_t, const struct passwd *,
const char *);
#endif /* !_COMPAT_UTIL_H_ */

View file

@ -0,0 +1,56 @@
.\" $NetBSD: disklabel_dkcksum.3,v 1.8 2010/05/04 06:41:27 jruoho Exp $
.\"
.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Roland C. Dowdeswell.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 4, 2010
.Dt DISKLABEL_DKCKSUM 3
.Os
.Sh NAME
.Nm disklabel_dkcksum
.Nd compute the checksum for a disklabel
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft uint16_t
.Fo disklabel_dkcksum
.Fa "struct disklabel *lp"
.Fc
.Sh DESCRIPTION
.Fn disklabel_dkcksum
computes the checksum for the disklabel passed in as
.Fa lp .
.Sh RETURN VALUES
The
.Fn disklabel_dkcksum
returns the computed checksum.
.Sh HISTORY
The
.Fn disklabel_dkcksum
function call appeared in
.Nx 2.0 .

View file

@ -0,0 +1,58 @@
/* $NetBSD: disklabel_dkcksum.c,v 1.4 2005/05/15 21:01:34 thorpej Exp $ */
/*-
* Copyright (c) 1991, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#ifndef lint
#if 0
static char sccsid[] = "@(#)dkcksum.c 8.1 (Berkeley) 6/5/93";
#else
__RCSID("$NetBSD: disklabel_dkcksum.c,v 1.4 2005/05/15 21:01:34 thorpej Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/disklabel.h>
#include <util.h>
uint16_t
disklabel_dkcksum(struct disklabel *lp)
{
uint16_t *start, *end;
uint16_t sum;
sum = 0;
start = (uint16_t *)(void *)lp;
end = (uint16_t *)(void *)&lp->d_partitions[lp->d_npartitions];
while (start < end)
sum ^= *start++;
return (sum);
}

View file

@ -0,0 +1,59 @@
.\" $NetBSD: disklabel_scan.3,v 1.6 2010/05/04 06:41:27 jruoho Exp $
.\"
.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Roland C. Dowdeswell.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 4, 2010
.Dt DISKLABEL_SCAN 3
.Os
.Sh NAME
.Nm disklabel_scan
.Nd scan a buffer for a valid disklabel
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn disklabel_scan "struct disklabel *lp" "char *buf" "size_t buflen"
.Sh DESCRIPTION
.Fn disklabel_scan
scans the memory region specified by
.Fa buf
and
.Fa buflen
for a valid disklabel.
If such a label is found, it is copied into
.Fa lp .
.Sh RETURN VALUES
The
.Fn disklabel_scan
function returns 0 if a valid disklabel was found and 1 if not.
.Sh HISTORY
The
.Fn disklabel_scan
function call appeared in
.Nx 2.0 .

View file

@ -0,0 +1,69 @@
/* $NetBSD: disklabel_scan.c,v 1.3 2009/01/18 12:13:03 lukem Exp $ */
/*-
* Copyright (c) 2002 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Roland C. Dowdeswell.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#ifndef lint
__COPYRIGHT(
"@(#) Copyright (c) 2002\
The NetBSD Foundation, Inc. All rights reserved.");
__RCSID("$NetBSD: disklabel_scan.c,v 1.3 2009/01/18 12:13:03 lukem Exp $");
#endif
#include <string.h>
#include <unistd.h>
#include <util.h>
#include <sys/disklabel.h>
#define SCAN_INCR 4
int
disklabel_scan(struct disklabel *lp, char *buf, size_t buflen)
{
size_t i;
/* scan for the correct magic numbers. */
for (i=0; i <= buflen - sizeof(*lp); i += SCAN_INCR) {
memcpy(lp, buf + i, sizeof(*lp));
if (lp->d_magic == DISKMAGIC && lp->d_magic2 == DISKMAGIC)
goto sanity;
}
return 1;
sanity:
/* we've found something, let's sanity check it */
if (lp->d_npartitions > MAXPARTITIONS || disklabel_dkcksum(lp))
return 1;
return 0;
}

117
lib/libutil/efun.3 Normal file
View file

@ -0,0 +1,117 @@
.\" $NetBSD: efun.3,v 1.10 2010/05/03 05:40:37 jruoho Exp $
.\"
.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Christos Zoulas.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 3, 2010
.Dt EFUN 3
.Os
.Sh NAME
.Nm esetfunc ,
.Nm easprintf ,
.Nm efopen ,
.Nm emalloc ,
.Nm ecalloc ,
.Nm erealloc ,
.Nm estrdup ,
.Nm estrndup ,
.Nm estrlcat ,
.Nm estrlcpy ,
.Nm evasprintf
.Nd error-checked utility functions
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft void (*)(int, const char *, ...)
.Fn esetfunc "void (*)(int, const char *, ...)"
.Ft int
.Fn easprintf "char ** restrict str" "const char * restrict fmt" "..."
.Ft FILE *
.Fn efopen "const char *p" "const char *m"
.Ft void *
.Fn ecalloc "size_t n" "size_t c"
.Ft void *
.Fn emalloc "size_t n"
.Ft void *
.Fn erealloc "void *p" "size_t n"
.Ft char *
.Fn estrdup "const char *s"
.Ft char *
.Fn estrndup "const char *s" "size_t len"
.Ft size_t
.Fn estrlcat "char *dst" "const char *src" "size_t len"
.Ft size_t
.Fn estrlcpy "char *dst" "const char *src" "size_t len"
.Ft int
.Fn evasprintf "char ** restrict str" "const char * restrict fmt" "..."
.Sh DESCRIPTION
The
.Fn easprintf ,
.Fn efopen ,
.Fn ecalloc ,
.Fn emalloc ,
.Fn erealloc ,
.Fn estrdup ,
.Fn estrndup ,
.Fn estrlcat ,
.Fn estrlcpy ,
and
.Fn evasprintf
functions
operate exactly as the corresponding functions that do not start with an
.Sq e
except that in case of an error, they call
the installed error handler that can be configured with
.Fn esetfunc .
.Pp
For the string handling functions, it is an error when the destination
buffer is not large enough to hold the complete string.
For functions that allocate memory or open a file, it is an error when
they would return a null pointer.
The default error handler is
.Xr err 3 .
The function
.Fn esetfunc
returns the previous error handler function.
A
.Dv NULL
error handler will just call
.Xr exit 3 .
.Sh SEE ALSO
.Xr asprintf 3 ,
.Xr calloc 3 ,
.Xr err 3 ,
.Xr exit 3 ,
.Xr fopen 3 ,
.Xr malloc 3 ,
.Xr realloc 3 ,
.Xr strdup 3 ,
.Xr strlcat 3 ,
.Xr strlcpy 3 ,
.Xr strndup 3 ,
.Xr vasprintf 3

158
lib/libutil/efun.c Normal file
View file

@ -0,0 +1,158 @@
/* $NetBSD: efun.c,v 1.6 2008/04/28 20:23:02 martin Exp $ */
/*-
* Copyright (c) 2006 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#ifdef __RCSID
__RCSID("$NetBSD: efun.c,v 1.6 2008/04/28 20:23:02 martin Exp $");
#endif
#include <err.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <util.h>
static void (*efunc)(int, const char *, ...) = err;
void (*
esetfunc(void (*ef)(int, const char *, ...)))(int, const char *, ...)
{
void (*of)(int, const char *, ...) = efunc;
efunc = ef == NULL ? (void (*)(int, const char *, ...))exit : ef;
return of;
}
size_t
estrlcpy(char *dst, const char *src, size_t len)
{
size_t rv;
if ((rv = strlcpy(dst, src, len)) >= len) {
errno = ENAMETOOLONG;
(*efunc)(1,
"Cannot copy string; %zu chars needed %zu provided",
rv, len);
}
return rv;
}
size_t
estrlcat(char *dst, const char *src, size_t len)
{
size_t rv;
if ((rv = strlcat(dst, src, len)) >= len) {
errno = ENAMETOOLONG;
(*efunc)(1,
"Cannot append to string; %zu chars needed %zu provided",
rv, len);
}
return rv;
}
char *
estrdup(const char *s)
{
char *d = strdup(s);
if (d == NULL)
(*efunc)(1, "Cannot copy string");
return d;
}
char *
estrndup(const char *s, size_t len)
{
char *d = strndup(s, len);
if (d == NULL)
(*efunc)(1, "Cannot copy string");
return d;
}
void *
emalloc(size_t n)
{
void *p = malloc(n);
if (p == NULL)
(*efunc)(1, "Cannot allocate %zu bytes", n);
return p;
}
void *
ecalloc(size_t n, size_t s)
{
void *p = calloc(n, s);
if (p == NULL)
(*efunc)(1, "Cannot allocate %zu bytes", n);
return p;
}
void *
erealloc(void *p, size_t n)
{
void *q = realloc(p, n);
if (q == NULL)
(*efunc)(1, "Cannot re-allocate %zu bytes", n);
return q;
}
FILE *
efopen(const char *p, const char *m)
{
FILE *fp = fopen(p, m);
if (fp == NULL)
(*efunc)(1, "Cannot open `%s'", p);
return fp;
}
int
easprintf(char ** __restrict ret, const char * __restrict format, ...)
{
int rv;
va_list ap;
va_start(ap, format);
if ((rv = vasprintf(ret, format, ap)) == -1)
(*efunc)(1, "Cannot format string");
va_end(ap);
return rv;
}
int
evasprintf(char ** __restrict ret, const char * __restrict format, va_list ap)
{
int rv;
if ((rv = vasprintf(ret, format, ap)) == -1)
(*efunc)(1, "Cannot format string");
return rv;
}

61
lib/libutil/getbootfile.3 Normal file
View file

@ -0,0 +1,61 @@
.\" $NetBSD: getbootfile.3,v 1.9 2010/05/04 06:41:27 jruoho Exp $
.\"
.\" Copyright (c) 2001 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Thomas Klausner.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 4, 2010
.Dt GETBOOTFILE 3
.Os
.Sh NAME
.Nm getbootfile
.Nd get the name of the booted kernel file
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft const char *
.Fn getbootfile void
.Sh DESCRIPTION
.Fn getbootfile
returns a static pointer to the full path name of the file from which
the current kernel was loaded.
If it can not be determined, or the file is not ``secure'' (see
.Xr secure_path 3 ) ,
.Dv _PATH_UNIX
from
.In paths.h
is returned instead.
.Sh SEE ALSO
.Xr secure_path 3 ,
.Xr sysctl 3
.Sh HISTORY
The
.Fn getbootfile
function call appeared in
.Fx 2.0
and
.Nx 1.6 .

84
lib/libutil/getbootfile.c Normal file
View file

@ -0,0 +1,84 @@
/* $NetBSD: getbootfile.c,v 1.5 2008/04/28 20:23:02 martin Exp $ */
/*-
* Copyright (c) 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Thomas Klausner.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: getbootfile.c,v 1.5 2008/04/28 20:23:02 martin Exp $");
#endif
#include <sys/param.h>
#include <sys/sysctl.h>
#include <machine/cpu.h>
#include <string.h>
#include <paths.h>
#include <util.h>
#ifdef CPU_BOOTED_KERNEL
static char name[MAXPATHLEN];
#endif
const char *
getbootfile(void)
{
#ifdef CPU_BOOTED_KERNEL
int mib[2];
size_t size;
#endif
const char *kernel;
kernel = _PATH_UNIX;
#ifdef CPU_BOOTED_KERNEL
/* find real boot-kernel name */
mib[0] = CTL_MACHDEP;
mib[1] = CPU_BOOTED_KERNEL;
size = sizeof(name) - 1;
if (sysctl(mib, 2, name + 1, &size, NULL, 0) == 0) {
/*
* traditionally, this sysctl returns the relative
* path of the kernel with the leading slash stripped
* -- could be empty, though (e.g. when netbooting).
*/
if (name[1] != '\0') {
name[0] = '/';
kernel = name;
}
/* check if we got a valid and 'secure' filename */
if (strcmp(kernel, _PATH_UNIX) != 0 &&
secure_path(kernel) != 0) {
/* doesn't seems so, fall back to default */
kernel = _PATH_UNIX;
}
}
#endif
return (kernel);
}

View file

@ -0,0 +1,75 @@
.\" $NetBSD: getlabelsector.3,v 1.5 2009/06/24 22:31:58 zafer Exp $
.\"
.\"
.\" Copyright 2002 Wasabi Systems, Inc.
.\" All rights reserved.
.\"
.\" Written by Steve C. Woodford for Wasabi Systems, Inc.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed for the NetBSD Project by
.\" Wasabi Systems, Inc.
.\" 4. The name of Wasabi Systems, Inc. may not be used to endorse
.\" or promote products derived from this software without specific prior
.\" written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
.\" 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.
.\"
.Dd December 11, 2002
.Dt GETLABELSECTOR 3
.Os
.Sh NAME
.Nm getlabelsector ,
.Nm getlabeloffset
.Nd get the sector number and offset of the disklabel
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft daddr_t
.Fn getlabelsector void
.Ft off_t
.Fn getlabeloffset void
.Sh DESCRIPTION
The
.Fn getlabelsector
and
.Fn getlabeloffset
functions return values which describe the exact on-disk location of the
.Xr disklabel 5
on the current system, or \-1 on error.
These functions supersede the hardcoded
.Dv LABELSECTOR
and
.Dv LABELOFFSET
definitions previously used to derive the location of the
.Xr disklabel 5 .
.Sh SEE ALSO
.Xr sysctl 3 ,
.Xr disklabel 5
.Sh HISTORY
The
.Fn getlabelsector
and
.Fn getlabeloffset
functions appeared in
.Nx 2.0 .

View file

@ -0,0 +1,75 @@
/* $NetBSD: getlabelsector.c,v 1.3 2005/09/17 01:51:21 elad Exp $ */
/*
* Copyright 2002 Wasabi Systems, Inc.
* All rights reserved.
*
* Written by Steve C. Woodford for Wasabi Systems, Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed for the NetBSD Project by
* Wasabi Systems, Inc.
* 4. The name of Wasabi Systems, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC
* 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>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: getlabelsector.c,v 1.3 2005/09/17 01:51:21 elad Exp $");
#endif
#include <sys/param.h>
#include <sys/sysctl.h>
#include <util.h>
int
getlabelsector(void)
{
int sector, mib[2];
size_t varlen;
mib[0] = CTL_KERN;
mib[1] = KERN_LABELSECTOR;
varlen = sizeof(sector);
if (sysctl(mib, 2, &sector, &varlen, NULL, (size_t)0) < 0)
return (-1);
return sector;
}
off_t
getlabeloffset(void)
{
int offset, mib[2];
size_t varlen;
mib[0] = CTL_KERN;
mib[1] = KERN_LABELOFFSET;
varlen = sizeof(offset);
if (sysctl(mib, 2, &offset, &varlen, NULL, (size_t)0) < 0)
return (-1);
return ((off_t)offset);
}

View file

@ -0,0 +1,59 @@
.\" $NetBSD: getmaxpartitions.3,v 1.10 2010/05/04 06:41:27 jruoho Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Jason R. Thorpe.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 4, 2010
.Dt GETMAXPARTITIONS 3
.Os
.Sh NAME
.Nm getmaxpartitions
.Nd get the maximum number of partitions allowed per disk
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn getmaxpartitions void
.Sh DESCRIPTION
.Fn getmaxpartitions
returns the number of partitions that are allowed per disk on the
system, or \-1 in case of an error, setting the global
.Va errno
variable.
The possible values for
.Va errno
are the same as in
.Xr sysctl 3 .
.Sh SEE ALSO
.Xr getrawpartition 3 ,
.Xr sysctl 3
.Sh HISTORY
The
.Fn getmaxpartitions
function call appeared in
.Nx 1.2 .

View file

@ -0,0 +1,54 @@
/* $NetBSD: getmaxpartitions.c,v 1.6 2008/04/28 20:23:02 martin Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: getmaxpartitions.c,v 1.6 2008/04/28 20:23:02 martin Exp $");
#endif
#include <sys/param.h>
#include <sys/sysctl.h>
#include <util.h>
int
getmaxpartitions(void)
{
int maxpart, mib[2];
size_t varlen;
mib[0] = CTL_KERN;
mib[1] = KERN_MAXPARTITIONS;
varlen = sizeof(maxpart);
if (sysctl(mib, 2, &maxpart, &varlen, NULL, (size_t)0) < 0)
return (-1);
return (maxpart);
}

277
lib/libutil/getmntopts.3 Normal file
View file

@ -0,0 +1,277 @@
.\" $NetBSD: getmntopts.3,v 1.12 2010/08/24 12:05:01 christos Exp $
.\"
.\" Copyright (c) 1994
.\" The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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.
.\"
.\" @(#)getmntopts.3 8.3 (Berkeley) 3/30/95
.\"
.Dd May 4, 2010
.Dt GETMNTOPTS 3
.Os
.Sh NAME
.Nm getmntopts
.Nd scan mount options
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In mntopts.h
.Ft mntoptparse_t
.Fn getmntopts "const char *options" "const struct mntopt *mopts" "int *flagp" "int *altflagp"
.Ft const char *
.Fn getmntoptstr "mntoptparse_t mp" "const char *opt"
.Ft long
.Fn getmntoptnum "mntoptparse_t mp" "const char *opt"
.Ft void
.Fn freemntopts "mntoptparse_t mp"
.Sh DESCRIPTION
The
.Fn getmntopts
function takes a comma separated option list and a list
of valid option names, and computes the bitmasks
corresponding to the requested set of options.
.Pp
The string
.Ar options
is broken down into a sequence of comma separated tokens.
Each token is looked up in the table described by
.Ar mopts
and the bits in
the word referenced by either
.Ar flagp
or
.Ar altflagp
(depending on the
.Dv m_altloc
field of the option's table entry)
are updated.
The flag words are not initialized by
.Fn getmntopts .
The table,
.Ar mopts ,
has the following format:
.Bd -literal
struct mntopt {
const char *m_option; /* option name */
int m_inverse; /* negative option, e.g., "dev" */
int m_flag; /* bit to set, e.g., MNT_RDONLY */
int m_altloc; /* use altflagp rather than flagp */
};
.Ed
.Pp
The members of this structure are:
.Bl -tag -width m_inverse
.It Fa m_option
the option name,
for example
.Dq suid .
.It Fa m_inverse
tells
.Fn getmntopts
that the name has the inverse meaning of the bit.
For example,
.Dq suid
is the string, whereas the mount flag is
.Dv MNT_NOSUID .
In this case, the sense of the string and the flag
are inverted, so the
.Fa m_inverse
flag should be set.
.It Fa m_flag
the value of the bit to be set or cleared in
the flag word when the option is recognized.
The bit is set when the option is discovered,
but cleared if the option name was preceded
by the letters
.Dq no .
The
.Fa m_inverse
flag causes these two operations to be reversed.
.It Fa m_altloc
the bit should be set or cleared in
.Ar altflagp
rather than
.Ar flagp .
.El
.Pp
Each of the user visible
.Dv MNT_
flags has a corresponding
.Dv MOPT_
macro which defines an appropriate
.Li "struct mntopt"
entry.
To simplify the program interface and ensure consistency across all
programs, a general purpose macro,
.Dv MOPT_STDOPTS ,
is defined which contains an entry for all the generic VFS options.
In addition, the macros
.Dv MOPT_FORCE
and
.Dv MOPT_UPDATE
exist to enable the
.Dv MNT_FORCE
and
.Dv MNT_UPDATE
flags to be set.
Finally, the table must be terminated by an entry with a
.Dv NULL
first element.
.Pp
.Fn getmntopts
returns a
.Li "mntoptparse_t"
handle that can be used in subsequent
.Fn getmntoptstr
and
.Fn getmntoptnum
calls to fetch a value for an option and that must be freed with a call
to
.Fn freemntopts .
If an error occurred, then if the external integer value
.Va getmnt_silent
is zero then
.Fn getmntopts
prints an error message and exits;
if
.Va getmnt_silent
is non-zero then
.Fn getmntopts
returns
.Dv NULL .
.Pp
The
.Fn getmntoptstr
function returns the string value of the named option, if such a value
was set in the option string.
If the value was not set, then if the external integer value
.Va getmnt_silent
is zero then
.Fn getmntoptstr
prints an error message and exits;
if
.Va getmnt_silent
is non-zero then
.Fn getmntoptstr
returns
.Dv NULL .
.Pp
The
.Fn getmntoptnum
returns the long value of the named option, if such a value was set in the
option string.
If the value was not set, or could not be converted from a string to a
long, then if the external integer value
.Va getmnt_silent
is zero then
.Fn getmntoptnum
prints an error message and exits;
if
.Va getmnt_silent
is non-zero then
.Fn getmntoptnum
returns \-1.
.Pp
The
.Fn freemntopts
frees the storage used by
.Fn getmntopts .
.Sh RETURN VALUES
.Fn getmntopts
returns
.Dv NULL
if an error occurred.
Note that some bits may already have been set in
.Va flagp
and
.Va altflagp
even if
.Dv NULL
is returned.
.Fn getmntoptstr
returns
.Dv NULL
if an error occurred.
.Fn getmntoptnum
returns \-1 if an error occurred.
.Sh EXAMPLES
Most commands will use the standard option set.
Local filesystems which support the
.Dv MNT_UPDATE
flag, would also have an
.Dv MOPT_UPDATE
entry.
This can be declared and used as follows:
.Bd -literal -offset indent
#include \*[Lt]mntopts.h\*[Gt]
static const struct mntopt mopts[] = {
MOPT_STDOPTS,
MOPT_UPDATE,
{ NULL }
};
\&...
long val;
mntoptparse_t mp;
mntflags = mntaltflags = 0;
\&...
mp = getmntopts(options, mopts, \*[Am]mntflags, \*[Am]mntaltflags);
if (mp == NULL)
err(EXIT_FAILURE, "getmntopts");
\&...
val = getmntoptnum(mp, "rsize");
freemntopts(mp);
.Ed
.Sh DIAGNOSTICS
If the external integer variable
.Va getmnt_silent
is zero then the
.Fn getmntopts ,
.Fn getmntoptstr ,
and
.Fn getmntoptnum
functions display an error message and exit if an error occurred.
By default
.Va getmnt_silent
is zero.
.Sh SEE ALSO
.Xr err 3 ,
.Xr mount 8
.Sh HISTORY
The
.Fn getmntopts
function appeared in
.Bx 4.4 .
It was moved to the utilities library and enhanced to retrieve option
values in
.Nx 2.0 .

194
lib/libutil/getmntopts.c Normal file
View file

@ -0,0 +1,194 @@
/* $NetBSD: getmntopts.c,v 1.4 2007/08/26 22:46:15 pooka Exp $ */
/*-
* Copyright (c) 1994
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#ifndef lint
#if 0
static char sccsid[] = "@(#)getmntopts.c 8.3 (Berkeley) 3/29/95";
#else
__RCSID("$NetBSD: getmntopts.c,v 1.4 2007/08/26 22:46:15 pooka Exp $");
#endif
#endif /* not lint */
#include <sys/param.h>
#include <sys/mount.h>
#include <err.h>
#include <errno.h>
#include <fstab.h>
#include <stdlib.h>
#include <string.h>
#include <mntopts.h>
int getmnt_silent = 0;
static const char errmsg[] = "-o %s: option not supported";
struct mntoptparse {
const char *options;
const struct mntopt *mopts;
char *optbuf;
char **optarg;
};
const char *
getmntoptstr(mntoptparse_t mp, const char *opt)
{
const struct mntopt *m;
for (m = mp->mopts; m->m_option != NULL; m++)
if (strcasecmp(opt, m->m_option) == 0)
break;
if (m->m_option == NULL) {
if (getmnt_silent == 0)
errx(1, errmsg, opt);
else
return NULL;
}
return mp->optarg[m - mp->mopts];
}
long
getmntoptnum(mntoptparse_t mp, const char *opt)
{
char *ep;
long rv;
void (*fun)(int, const char *, ...) = NULL;
const char *val = getmntoptstr(mp, opt);
if (val == NULL) {
if (getmnt_silent == 0)
errx(1, "Missing %s argument", opt);
else
return -1;
}
errno = 0;
rv = strtol(val, &ep, 0);
if (*ep)
fun = errx;
if (errno == ERANGE && (rv == LONG_MAX || rv == LONG_MIN))
fun = err;
if (fun) {
if (getmnt_silent != 0)
return -1;
(*fun)(1, "Invalid %s argument `%s'", opt, val);
}
return rv;
}
void
freemntopts(mntoptparse_t mp)
{
free(mp->optbuf);
free(mp->optarg);
free(mp);
}
mntoptparse_t
getmntopts(const char *options, const struct mntopt *m0, int *flagp,
int *altflagp)
{
const struct mntopt *m;
int negative;
char *opt, *p;
int *thisflagp;
size_t nopts;
mntoptparse_t mp;
for (nopts = 0, m = m0; m->m_option != NULL; ++m, nopts++)
continue;
if ((mp = malloc(sizeof(struct mntoptparse))) == NULL)
return NULL;
/* Copy option string, since it is about to be torn asunder... */
if ((mp->optbuf = strdup(options)) == NULL) {
free(mp);
return NULL;
}
if ((mp->optarg = calloc(nopts, sizeof(char *))) == NULL) {
free(mp->optbuf);
free(mp);
return NULL;
}
mp->mopts = m0;
mp->options = options;
for (opt = mp->optbuf; (opt = strtok(opt, ",")) != NULL; opt = NULL) {
/* Check for "no" prefix. */
if (opt[0] == 'n' && opt[1] == 'o') {
negative = 1;
opt += 2;
} else
negative = 0;
/*
* for options with assignments in them (ie. quotas)
* ignore the assignment as it's handled elsewhere
*/
p = strchr(opt, '=');
if (p) {
*p++ = '\0';
}
/* Scan option table. */
for (m = m0; m->m_option != NULL; ++m)
if (strcasecmp(opt, m->m_option) == 0)
break;
/* Save flag, or fail if option is not recognised. */
if (m->m_option) {
mp->optarg[m - m0] = p;
thisflagp = m->m_altloc ? altflagp : flagp;
if (negative == m->m_inverse)
*thisflagp |= m->m_flag;
else
*thisflagp &= ~m->m_flag;
} else if (!getmnt_silent) {
errx(1, errmsg, opt);
} else {
free(mp->optbuf);
free(mp);
return NULL;
}
}
return mp;
}

View file

@ -0,0 +1,71 @@
.\" $NetBSD: getrawpartition.3,v 1.11 2010/05/04 06:41:27 jruoho Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Jason R. Thorpe.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 4, 2010
.Dt GETRAWPARTITION 3
.Os
.Sh NAME
.Nm getrawpartition
.Nd get the system
.Dq raw
partition
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn getrawpartition void
.Sh DESCRIPTION
.Fn getrawpartition
returns the partition number (
.Sq a
== 0,
.Sq b
== 1, ...) of the
.Dq raw
partition of the system's disks,
or \-1 in case of an error, setting the global
.Va errno
variable.
The possible values for
.Va errno
are the same as in
.Xr sysctl 3 .
The
.Dq raw
partition is defined as the partition which provides access to the entire
disk, regardless of the disk's partition map.
.Sh SEE ALSO
.Xr getmaxpartitions 3 ,
.Xr sysctl 3
.Sh HISTORY
The
.Fn getrawpartition
function call appeared in
.Nx 1.2 .

View file

@ -0,0 +1,54 @@
/* $NetBSD: getrawpartition.c,v 1.6 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: getrawpartition.c,v 1.6 2008/04/28 20:23:03 martin Exp $");
#endif
#include <sys/param.h>
#include <sys/sysctl.h>
#include <util.h>
int
getrawpartition()
{
int rawpart, mib[2];
size_t varlen;
mib[0] = CTL_KERN;
mib[1] = KERN_RAWPARTITION;
varlen = sizeof(rawpart);
if (sysctl(mib, 2, &rawpart, &varlen, NULL, (size_t)0) < 0)
return (-1);
return (rawpart);
}

180
lib/libutil/if_media.c Normal file
View file

@ -0,0 +1,180 @@
/* $NetBSD: if_media.c,v 1.2 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 1997, 1998, 2000 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
* NASA Ames Research Center.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: if_media.c,v 1.2 2008/04/28 20:23:03 martin Exp $");
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <net/if_media.h>
struct ifmedia_description ifm_mode_descriptions[] =
IFM_MODE_DESCRIPTIONS;
struct ifmedia_description ifm_type_descriptions[] =
IFM_TYPE_DESCRIPTIONS;
struct ifmedia_description ifm_subtype_descriptions[] =
IFM_SUBTYPE_DESCRIPTIONS;
struct ifmedia_description ifm_option_descriptions[] =
IFM_OPTION_DESCRIPTIONS;
const char *
get_media_type_string(int mword)
{
struct ifmedia_description *desc;
for (desc = ifm_type_descriptions; desc->ifmt_string != NULL; desc++) {
if (IFM_TYPE(mword) == desc->ifmt_word)
return (desc->ifmt_string);
}
return "<unknown type>";
}
const char *
get_media_subtype_string(int mword)
{
struct ifmedia_description *desc;
for (desc = ifm_subtype_descriptions; desc->ifmt_string != NULL;
desc++) {
if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
IFM_SUBTYPE(desc->ifmt_word) == IFM_SUBTYPE(mword))
return desc->ifmt_string;
}
return "<unknown subtype>";
}
const char *
get_media_mode_string(int mword)
{
struct ifmedia_description *desc;
for (desc = ifm_mode_descriptions; desc->ifmt_string != NULL; desc++) {
if (IFM_TYPE_MATCH(desc->ifmt_word, mword) &&
IFM_MODE(mword) == IFM_MODE(desc->ifmt_word))
return desc->ifmt_string;
}
return NULL;
}
const char *
get_media_option_string(int *mwordp)
{
struct ifmedia_description *desc;
int mword = *mwordp;
for (desc = ifm_option_descriptions; desc->ifmt_string != NULL;
desc++) {
if (!IFM_TYPE_MATCH(desc->ifmt_word, mword))
continue;
if (mword & IFM_OPTIONS(desc->ifmt_word)) {
*mwordp = mword & ~IFM_OPTIONS(desc->ifmt_word);
return desc->ifmt_string;
}
}
/* Historical behaviour is to ignore unknown option bits! */
*mwordp = mword & ~IFM_OPTIONS(~0);
return NULL;
}
int
lookup_media_word(struct ifmedia_description *desc, int type, const char *val)
{
for (; desc->ifmt_string != NULL; desc++) {
if (IFM_TYPE_MATCH(desc->ifmt_word, type) &&
strcasecmp(desc->ifmt_string, val) == 0)
return (desc->ifmt_word);
}
return -1;
}
int
get_media_mode(int type, const char *val)
{
return lookup_media_word(ifm_mode_descriptions, type, val);
}
int
get_media_subtype(int type, const char *val)
{
return lookup_media_word(ifm_subtype_descriptions, type, val);
}
int
get_media_options(int type, const char *val, char **invalid)
{
char *optlist, *str;
int option, rval = 0;
/* We muck with the string, so copy it. */
optlist = strdup(val);
if (optlist == NULL) {
if (invalid != NULL)
*invalid = NULL;
return -1;
}
str = optlist;
/*
* Look up the options in the user-provided comma-separated list.
*/
type = IFM_TYPE(type);
for (; (str = strtok(str, ",")) != NULL; str = NULL) {
option = lookup_media_word(ifm_option_descriptions, type, str);
if (option != -1) {
rval |= IFM_OPTIONS(option);
continue;
}
rval = -1;
if (invalid == NULL)
break;
/* Pass invalid option at start of malloced buffer */
if (str != optlist)
memmove(optlist, str, strlen(str) + 1);
/* Caller should free() or exit() */
*invalid = optlist;
return rval;
}
free(optlist);
return (rval);
}

107
lib/libutil/login.3 Normal file
View file

@ -0,0 +1,107 @@
.\" $NetBSD: login.3,v 1.6 2003/08/07 16:44:58 agc Exp $
.\"
.\" Copyright (c) 1995
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software developed by the Computer Systems
.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract
.\" BG 91-66 and contributed to Berkeley.
.\"
.\" 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 University 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 REGENTS 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 REGENTS 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.
.\"
.Dd December 14, 1995
.Dt LOGIN 3
.Os
.Sh NAME
.Nm login ,
.Nm logout ,
.Nm logwtmp
.Nd login utility functions
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft void
.Fn login "struct utmp *ut"
.Ft int
.Fn logout "const char *line"
.Ft void
.Fn logwtmp "const char *line" "const char *name" "const char *host"
.Sh DESCRIPTION
The
.Fn login ,
.Fn logout ,
and
.Fn logwtmp
functions operate on the database of current users in
.Pa /var/run/utmp
and on the logfile
.Pa /var/log/wtmp
of logins and logouts.
.Pp
The
.Fn login
function updates the
.Pa /var/run/utmp
and
.Pa /var/log/wtmp
files with user information contained in
.Fa ut .
.Pp
The
.Fn logout
function removes the entry from
.Pa /var/run/utmp
corresponding to the device
.Fa line .
.Pp
The
.Fn logwtmp
function adds an entry to
.Pa /var/log/wtmp .
Since
.Fn login
will add the appropriate entry for
.Pa /var/log/wtmp
during a login,
.Fn logwtmp
is usually used for logouts.
.Sh RETURN VALUES
.Fn logout
returns non-zero if it was able to find and delete an entry for
.Fa line ,
and zero if there is no entry for
.Fa line
in
.Pa /var/run/utmp .
.Sh FILES
.Bl -tag -width /var/run/wtmp -compact
.It Pa /dev/\(**
.It Pa /etc/ttys
.It Pa /var/run/utmp
.It Pa /var/log/wtmp
.El
.Sh SEE ALSO
.Xr utmp 5

70
lib/libutil/login.c Normal file
View file

@ -0,0 +1,70 @@
/* $NetBSD: login.c,v 1.16 2003/08/07 16:44:58 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)login.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: login.c,v 1.16 2003/08/07 16:44:58 agc Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <util.h>
#include <utmp.h>
void
login(const struct utmp *ut)
{
int fd;
int tty;
_DIAGASSERT(ut != NULL);
tty = ttyslot();
if (tty > 0 && (fd = open(_PATH_UTMP, O_WRONLY|O_CREAT, 0644)) >= 0) {
(void)lseek(fd, (off_t)(tty * sizeof(struct utmp)), SEEK_SET);
(void)write(fd, ut, sizeof(struct utmp));
(void)close(fd);
}
if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) >= 0) {
(void)write(fd, ut, sizeof(struct utmp));
(void)close(fd);
}
}

289
lib/libutil/login_cap.3 Normal file
View file

@ -0,0 +1,289 @@
.\" $NetBSD: login_cap.3,v 1.18 2010/05/05 22:05:31 wiz Exp $
.\"
.\" Copyright (c) 1996,1997 Berkeley Software Design, Inc. 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. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by Berkeley Software Design,
.\" Inc.
.\" 4. The name of Berkeley Software Design, Inc. may not be used to endorse
.\" or promote products derived from this software without specific prior
.\" written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``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 BERKELEY SOFTWARE DESIGN, INC. 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.
.\"
.\" BSDI login_cap.3,v 1.4 1997/11/07 16:22:27 jch Exp
.\"
.Dd October 6, 2007
.Dt LOGIN_CAP 3
.Os
.Sh NAME
.Nm login_getclass ,
.Nm login_getcapbool ,
.Nm login_getcapnum ,
.Nm login_getcapsize ,
.Nm login_getcapstr ,
.Nm login_getcaptime ,
.Nm login_close ,
.Nm setclasscontext ,
.Nm setusercontext
.Nd query login.conf database about a user class
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In sys/types.h
.In login_cap.h
.Ft login_cap_t *
.Fn login_getclass "char *class"
.Ft int
.Fn login_getcapbool "login_cap_t *lc" "const char *cap" "u_int def"
.Ft quad_t
.Fn login_getcapnum "login_cap_t *lc" "const char *cap" "quad_t def" "quad_t err"
.Ft quad_t
.Fn login_getcapsize "login_cap_t *lc" "const char *cap" "quad_t def" "quad_t err"
.Ft char *
.Fn login_getcapstr "login_cap_t *lc" "const char *cap" "char *def" "char *err"
.Ft quad_t
.Fn login_getcaptime "login_cap_t *lc" "const char *cap" "quad_t def" "quad_t err"
.Ft void
.Fn login_close "login_cap_t *lc"
.Ft int
.Fn setclasscontext "const char *class" "u_int flags"
.Ft int
.Fn setusercontext "login_cap_t *lc" "const struct passwd *pwd" "uid_t uid" "u_int flags"
.Sh DESCRIPTION
The
.Fn login_getclass
function extracts the entry specified by
.Ar class
(or
.Li default
if
.Ar class
is
.Dv NULL
or the empty string)
from
.Pa /etc/login.conf
(see
.Xr login.conf 5 ) .
If the entry is found, a
.Li login_cap_t
pointer is returned.
.Dv NULL
is returned if the user class is not found.
When the
.Li login_cap_t
structure is no longer needed, it should be freed by the
.Fn login_close
function.
.Pp
Once
.Ar lc
has been returned by
.Fn login_getclass ,
any of the other
.Fn login_*
functions may be called.
.Pp
The
.Fn login_getcapnum ,
.Fn login_getcapsize ,
.Fn login_getcapstr ,
and
.Fn login_getcaptime
functions all query the database entry for a field named
.Ar cap .
If the field is found, its value is returned.
If the field is not found, the value specified by
.Ar def
is returned.
If an error is encountered while trying to find the field,
.Ar err
is returned.
See
.Xr login.conf 5
for a discussion of the various textual forms the value may take.
The
.Fn login_getcapbool
function is slightly different.
It returns
.Ar def
if no capabilities were found for this class (typically meaning that
the default class was used and the
.Li /etc/login.conf
file is missing).
It returns a non-zero value if
.Ar cap ,
with no value, was found,
zero otherwise.
.Pp
The
.Fn setclasscontext
function takes
.Ar class ,
the name of a user class,
and sets the resources defined by that class according to
.Ar flags .
Only the
.Dv LOGIN_SETPATH ,
.Dv LOGIN_SETPRIORITY ,
.Dv LOGIN_SETRESOURCES ,
and
.Dv LOGIN_SETUMASK
bits are used.
(See
.Fn setusercontext
below).
It returns 0 on success and -1 on failure.
.Pp
The
.Fn setusercontext
function
sets the resources according to
.Ar flags .
The
.Ar lc
argument, if not
.Dv NULL ,
contains the class information that should
be used.
The
.Ar pwd
argument, if not
.Dv NULL ,
provides information about the user.
Both
.Ar lc
and
.Ar pwd
cannot be
.Dv NULL .
The
.Ar uid
argument is used in place of the user id contained in the
.Ar pwd
structure when calling
.Xr setuid 2 .
The various bits available to be or-ed together to make up
.Ar flags
are:
.Bl -tag -width LOGIN_SETRESOURCESXX
.It LOGIN_SETGID
Set the group id.
Requires the
.Ar pwd
field be specified.
.It LOGIN_SETGROUPS
Set the group membership list by calling
.Xr initgroups 3 .
Requires the
.Ar pwd
field be specified.
.It LOGIN_SETGROUP
Set the group id and call
.Xr initgroups 3 .
Requires the
.Ar pwd
field be specified.
.It LOGIN_SETLOGIN
Sets the login name by
.Xr setlogin 2 .
Requires the
.Ar pwd
field be specified.
.It LOGIN_SETPATH
Sets the
.Ev PATH
environment variable.
.It LOGIN_SETPRIORITY
Sets the priority by
.Xr setpriority 2 .
.It LOGIN_SETRESOURCES
Sets the various system resources by
.Xr setrlimit 2 .
.It LOGIN_SETUMASK
Sets the umask by
.Xr umask 2 .
.It LOGIN_SETUSER
Sets the user id to
.Ar uid
by
.Xr setuid 2 .
.It LOGIN_SETENV
Sets the environment variables as defined by the setenv keyword, by
.Xr setenv 3 .
.It LOGIN_SETALL
Sets all of the above.
.El
.Sh SEE ALSO
.Xr setlogin 2 ,
.Xr setpriority 2 ,
.Xr setrlimit 2 ,
.Xr setuid 2 ,
.Xr umask 2 ,
.Xr initgroups 3 ,
.Xr secure_path 3 ,
.Xr login.conf 5
.Sh HISTORY
The
.Nm
family of functions are largely based on the
.Bsx
implementation of same, and appeared in
.Nx 1.5
by kind permission.
.Sh CAVEATS
The string returned by
.Fn login_getcapstr
is allocated via
.Xr malloc 3
when the specified capability is present and thus it is the responsibility
of the caller to
.Fn free
this space.
However, if the capability was not found or an error occurred and
.Fa def
or
.Fa err
(whichever is relevant) are
.Pf non- Dv NULL
the returned value is simply what was passed in to
.Fn login_getcapstr .
Therefore it is not possible to blindly
.Fn free
the return value without first checking it against
.Fa def
and
.Fa err .
.Pp
The same warnings set forth in
.Xr setlogin 2
apply to
.Fn setusercontext
when the
.Dv LOGIN_SETLOGIN
flag is used.
Specifically, changing the login name affects all processes in the current
session, not just the current process.
See
.Xr setlogin 2
for more information.

987
lib/libutil/login_cap.c Normal file
View file

@ -0,0 +1,987 @@
/* $NetBSD: login_cap.c,v 1.29 2007/12/04 22:09:02 mjf Exp $ */
/*-
* Copyright (c) 1995,1997 Berkeley Software Design, Inc. 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Berkeley Software Design,
* Inc.
* 4. The name of Berkeley Software Design, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``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 BERKELEY SOFTWARE DESIGN, INC. 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.
*
* BSDI login_cap.c,v 2.13 1998/02/07 03:17:05 prb Exp
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: login_cap.c,v 1.29 2007/12/04 22:09:02 mjf Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/param.h>
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <login_cap.h>
#include <paths.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <util.h>
static u_quad_t multiply(u_quad_t, u_quad_t);
static u_quad_t strtolimit(const char *, char **, int);
static u_quad_t strtosize(const char *, char **, int);
static int gsetrl(login_cap_t *, int, const char *, int type);
static int isinfinite(const char *);
static int envset(void *, const char *, const char *, int);
login_cap_t *
login_getclass(const char *class)
{
const char *classfiles[2];
login_cap_t *lc;
int res;
/* class may be NULL */
if (secure_path(_PATH_LOGIN_CONF) == 0) {
classfiles[0] = _PATH_LOGIN_CONF;
classfiles[1] = NULL;
} else {
classfiles[0] = NULL;
}
if ((lc = malloc(sizeof(login_cap_t))) == NULL) {
syslog(LOG_ERR, "%s:%d malloc: %m", __FILE__, __LINE__);
return (0);
}
lc->lc_cap = 0;
lc->lc_style = 0;
if (class == NULL || class[0] == '\0')
class = LOGIN_DEFCLASS;
if ((lc->lc_class = strdup(class)) == NULL) {
syslog(LOG_ERR, "%s:%d strdup: %m", __FILE__, __LINE__);
free(lc);
return (0);
}
/*
* Not having a login.conf file is not an error condition.
* The individual routines deal reasonably with missing
* capabilities and use default values.
*/
if (classfiles[0] == NULL)
return(lc);
if ((res = cgetent(&lc->lc_cap, classfiles, lc->lc_class)) != 0) {
lc->lc_cap = 0;
switch (res) {
case 1:
syslog(LOG_ERR, "%s: couldn't resolve 'tc'",
lc->lc_class);
break;
case -1:
if (strcmp(lc->lc_class, LOGIN_DEFCLASS) == 0)
return (lc);
syslog(LOG_ERR, "%s: unknown class", lc->lc_class);
break;
case -2:
syslog(LOG_ERR, "%s: getting class information: %m",
lc->lc_class);
break;
case -3:
syslog(LOG_ERR, "%s: 'tc' reference loop",
lc->lc_class);
break;
default:
syslog(LOG_ERR, "%s: unexpected cgetent error",
lc->lc_class);
break;
}
free(lc->lc_class);
free(lc);
return (0);
}
return (lc);
}
login_cap_t *
login_getpwclass(const struct passwd *pwd)
{
/* pwd may be NULL */
return login_getclass(pwd ? pwd->pw_class : NULL);
}
char *
login_getcapstr(login_cap_t *lc, const char *cap, char *def, char *e)
{
char *res = NULL;
int status;
errno = 0;
_DIAGASSERT(cap != NULL);
if (!lc || !lc->lc_cap)
return (def);
switch (status = cgetstr(lc->lc_cap, cap, &res)) {
case -1:
if (res)
free(res);
return (def);
case -2:
syslog(LOG_ERR, "%s: getting capability %s: %m",
lc->lc_class, cap);
if (res)
free(res);
return (e);
default:
if (status >= 0)
return (res);
syslog(LOG_ERR, "%s: unexpected error with capability %s",
lc->lc_class, cap);
if (res)
free(res);
return (e);
}
}
quad_t
login_getcaptime(login_cap_t *lc, const char *cap, quad_t def, quad_t e)
{
char *ep;
char *res = NULL, *sres;
int status;
quad_t q, r;
_DIAGASSERT(cap != NULL);
errno = 0;
if (!lc || !lc->lc_cap)
return (def);
switch (status = cgetstr(lc->lc_cap, cap, &res)) {
case -1:
if (res)
free(res);
return (def);
case -2:
syslog(LOG_ERR, "%s: getting capability %s: %m",
lc->lc_class, cap);
errno = ERANGE;
if (res)
free(res);
return (e);
default:
if (status >= 0)
break;
syslog(LOG_ERR, "%s: unexpected error with capability %s",
lc->lc_class, cap);
errno = ERANGE;
if (res)
free(res);
return (e);
}
if (isinfinite(res))
return (RLIM_INFINITY);
errno = 0;
q = 0;
sres = res;
while (*res) {
r = strtoq(res, &ep, 0);
if (!ep || ep == res ||
((r == QUAD_MIN || r == QUAD_MAX) && errno == ERANGE)) {
invalid:
syslog(LOG_ERR, "%s:%s=%s: invalid time",
lc->lc_class, cap, sres);
errno = ERANGE;
free(sres);
return (e);
}
switch (*ep++) {
case '\0':
--ep;
break;
case 's': case 'S':
break;
case 'm': case 'M':
r *= 60;
break;
case 'h': case 'H':
r *= 60 * 60;
break;
case 'd': case 'D':
r *= 60 * 60 * 24;
break;
case 'w': case 'W':
r *= 60 * 60 * 24 * 7;
break;
case 'y': case 'Y': /* Pretty absurd */
r *= 60 * 60 * 24 * 365;
break;
default:
goto invalid;
}
res = ep;
q += r;
}
free(sres);
return (q);
}
quad_t
login_getcapnum(login_cap_t *lc, const char *cap, quad_t def, quad_t e)
{
char *ep;
char *res = NULL;
int status;
quad_t q;
_DIAGASSERT(cap != NULL);
errno = 0;
if (!lc || !lc->lc_cap)
return (def);
switch (status = cgetstr(lc->lc_cap, cap, &res)) {
case -1:
if (res)
free(res);
return (def);
case -2:
syslog(LOG_ERR, "%s: getting capability %s: %m",
lc->lc_class, cap);
errno = ERANGE;
if (res)
free(res);
return (e);
default:
if (status >= 0)
break;
syslog(LOG_ERR, "%s: unexpected error with capability %s",
lc->lc_class, cap);
errno = ERANGE;
if (res)
free(res);
return (e);
}
if (isinfinite(res))
return (RLIM_INFINITY);
errno = 0;
q = strtoq(res, &ep, 0);
if (!ep || ep == res || ep[0] ||
((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) {
syslog(LOG_ERR, "%s:%s=%s: invalid number",
lc->lc_class, cap, res);
errno = ERANGE;
free(res);
return (e);
}
free(res);
return (q);
}
quad_t
login_getcapsize(login_cap_t *lc, const char *cap, quad_t def, quad_t e)
{
char *ep;
char *res = NULL;
int status;
quad_t q;
_DIAGASSERT(cap != NULL);
errno = 0;
if (!lc || !lc->lc_cap)
return (def);
switch (status = cgetstr(lc->lc_cap, cap, &res)) {
case -1:
if (res)
free(res);
return (def);
case -2:
syslog(LOG_ERR, "%s: getting capability %s: %m",
lc->lc_class, cap);
errno = ERANGE;
if (res)
free(res);
return (e);
default:
if (status >= 0)
break;
syslog(LOG_ERR, "%s: unexpected error with capability %s",
lc->lc_class, cap);
errno = ERANGE;
if (res)
free(res);
return (e);
}
errno = 0;
q = strtolimit(res, &ep, 0);
if (!ep || ep == res || (ep[0] && ep[1]) ||
((q == QUAD_MIN || q == QUAD_MAX) && errno == ERANGE)) {
syslog(LOG_ERR, "%s:%s=%s: invalid size",
lc->lc_class, cap, res);
errno = ERANGE;
free(res);
return (e);
}
free(res);
return (q);
}
int
login_getcapbool(login_cap_t *lc, const char *cap, u_int def)
{
_DIAGASSERT(cap != NULL);
if (!lc || !lc->lc_cap)
return (def);
return (cgetcap(lc->lc_cap, cap, ':') != NULL);
}
void
login_close(login_cap_t *lc)
{
if (lc) {
if (lc->lc_class)
free(lc->lc_class);
if (lc->lc_cap)
free(lc->lc_cap);
if (lc->lc_style)
free(lc->lc_style);
free(lc);
}
}
#define R_CTIME 1
#define R_CSIZE 2
#define R_CNUMB 3
static struct {
int what;
int type;
const char *name;
} r_list[] = {
{ RLIMIT_CPU, R_CTIME, "cputime", },
{ RLIMIT_FSIZE, R_CSIZE, "filesize", },
{ RLIMIT_DATA, R_CSIZE, "datasize", },
{ RLIMIT_STACK, R_CSIZE, "stacksize", },
{ RLIMIT_RSS, R_CSIZE, "memoryuse", },
{ RLIMIT_MEMLOCK, R_CSIZE, "memorylocked", },
{ RLIMIT_NPROC, R_CNUMB, "maxproc", },
{ RLIMIT_NOFILE, R_CNUMB, "openfiles", },
{ RLIMIT_CORE, R_CSIZE, "coredumpsize", },
{ RLIMIT_SBSIZE, R_CSIZE, "sbsize", },
{ -1, 0, 0 }
};
static int
gsetrl(login_cap_t *lc, int what, const char *name, int type)
{
struct rlimit rl;
struct rlimit r;
char name_cur[32];
char name_max[32];
_DIAGASSERT(name != NULL);
(void)snprintf(name_cur, sizeof(name_cur), "%s-cur", name);
(void)snprintf(name_max, sizeof(name_max), "%s-max", name);
if (getrlimit(what, &r)) {
syslog(LOG_ERR, "getting resource limit: %m");
return (-1);
}
#define RCUR r.rlim_cur
#define RMAX r.rlim_max
switch (type) {
case R_CTIME:
RCUR = login_getcaptime(lc, name, RCUR, RCUR);
RMAX = login_getcaptime(lc, name, RMAX, RMAX);
rl.rlim_cur = login_getcaptime(lc, name_cur, RCUR, RCUR);
rl.rlim_max = login_getcaptime(lc, name_max, RMAX, RMAX);
break;
case R_CSIZE:
RCUR = login_getcapsize(lc, name, RCUR, RCUR);
RMAX = login_getcapsize(lc, name, RMAX, RMAX);
rl.rlim_cur = login_getcapsize(lc, name_cur, RCUR, RCUR);
rl.rlim_max = login_getcapsize(lc, name_max, RMAX, RMAX);
break;
case R_CNUMB:
RCUR = login_getcapnum(lc, name, RCUR, RCUR);
RMAX = login_getcapnum(lc, name, RMAX, RMAX);
rl.rlim_cur = login_getcapnum(lc, name_cur, RCUR, RCUR);
rl.rlim_max = login_getcapnum(lc, name_max, RMAX, RMAX);
break;
default:
syslog(LOG_ERR, "%s: invalid type %d setting resource limit %s",
lc->lc_class, type, name);
return (-1);
}
if (setrlimit(what, &rl)) {
syslog(LOG_ERR, "%s: setting resource limit %s: %m",
lc->lc_class, name);
return (-1);
}
#undef RCUR
#undef RMAX
return (0);
}
static int
/*ARGSUSED*/
envset(void *envp __unused, const char *name, const char *value, int overwrite)
{
return setenv(name, value, overwrite);
}
int
setuserenv(login_cap_t *lc, envfunc_t senv, void *envp)
{
const char *stop = ", \t";
size_t i, count;
char *ptr;
char **res;
char *str = login_getcapstr(lc, "setenv", NULL, NULL);
if (str == NULL || *str == '\0')
return 0;
/*
* count the sub-strings, this may over-count since we don't
* account for escaped delimiters.
*/
for (i = 1, ptr = str; *ptr; i++) {
ptr += strcspn(ptr, stop);
if (*ptr)
ptr++;
}
/* allocate ptr array and string */
count = i;
res = malloc(count * sizeof(char *) + strlen(str) + 1);
if (!res)
return -1;
ptr = (char *)(void *)&res[count];
(void)strcpy(ptr, str);
/* split string */
for (i = 0; (res[i] = stresep(&ptr, stop, '\\')) != NULL; )
if (*res[i])
i++;
count = i;
for (i = 0; i < count; i++) {
if ((ptr = strchr(res[i], '=')) != NULL)
*ptr++ = '\0';
else
ptr = NULL;
(void)(*senv)(envp, res[i], ptr ? ptr : "", 1);
}
free(res);
return 0;
}
int
setclasscontext(const char *class, u_int flags)
{
int ret;
login_cap_t *lc;
flags &= LOGIN_SETRESOURCES | LOGIN_SETPRIORITY | LOGIN_SETUMASK |
LOGIN_SETPATH;
lc = login_getclass(class);
ret = lc ? setusercontext(lc, NULL, 0, flags) : -1;
login_close(lc);
return (ret);
}
int
setusercontext(login_cap_t *lc, struct passwd *pwd, uid_t uid, u_int flags)
{
char per_user_tmp[MAXPATHLEN + 1];
const char *component_name;
login_cap_t *flc;
quad_t p;
int i;
ssize_t len;
flc = NULL;
if (!lc)
flc = lc = login_getclass(pwd ? pwd->pw_class : NULL);
/*
* Without the pwd entry being passed we cannot set either
* the group or the login. We could complain about it.
*/
if (pwd == NULL)
flags &= ~(LOGIN_SETGROUP|LOGIN_SETLOGIN);
#ifdef LOGIN_OSETGROUP
if (pwd == NULL)
flags &= ~LOGIN_OSETGROUP;
if (flags & LOGIN_OSETGROUP)
flags = (flags & ~LOGIN_OSETGROUP) | LOGIN_SETGROUP;
#endif
if (flags & LOGIN_SETRESOURCES)
for (i = 0; r_list[i].name; ++i)
(void)gsetrl(lc, r_list[i].what, r_list[i].name,
r_list[i].type);
if (flags & LOGIN_SETPRIORITY) {
p = login_getcapnum(lc, "priority", (quad_t)0, (quad_t)0);
if (setpriority(PRIO_PROCESS, 0, (int)p) == -1)
syslog(LOG_ERR, "%s: setpriority: %m", lc->lc_class);
}
if (flags & LOGIN_SETUMASK) {
p = login_getcapnum(lc, "umask", (quad_t) LOGIN_DEFUMASK,
(quad_t)LOGIN_DEFUMASK);
umask((mode_t)p);
}
if (flags & LOGIN_SETGID) {
if (setgid(pwd->pw_gid) == -1) {
syslog(LOG_ERR, "setgid(%d): %m", pwd->pw_gid);
login_close(flc);
return (-1);
}
}
if (flags & LOGIN_SETGROUPS) {
if (initgroups(pwd->pw_name, pwd->pw_gid) == -1) {
syslog(LOG_ERR, "initgroups(%s,%d): %m",
pwd->pw_name, pwd->pw_gid);
login_close(flc);
return (-1);
}
}
/* Create per-user temporary directories if needed. */
if ((len = readlink("/tmp", per_user_tmp,
sizeof(per_user_tmp) - 6)) != -1) {
static const char atuid[] = "/@ruid";
char *lp;
/* readlink does not nul-terminate the string */
per_user_tmp[len] = '\0';
/* Check if it's magic symlink. */
lp = strstr(per_user_tmp, atuid);
if (lp != NULL && *(lp + (sizeof(atuid) - 1)) == '\0') {
lp++;
if (snprintf(lp, 11, "/%u", pwd->pw_uid) > 10) {
syslog(LOG_ERR, "real temporary path too long");
login_close(flc);
return (-1);
}
if (mkdir(per_user_tmp, S_IRWXU) != -1) {
if (chown(per_user_tmp, pwd->pw_uid,
pwd->pw_gid)) {
component_name = "chown";
goto out;
}
/*
* Must set sticky bit for tmp directory, some
* programs rely on this.
*/
if(chmod(per_user_tmp, S_IRWXU | S_ISVTX)) {
component_name = "chmod";
goto out;
}
} else {
if (errno != EEXIST) {
component_name = "mkdir";
goto out;
} else {
/*
* We must ensure that we own the
* directory and that is has the correct
* permissions, otherwise a DOS attack
* is possible.
*/
struct stat sb;
if (stat(per_user_tmp, &sb) == -1) {
component_name = "stat";
goto out;
}
if (sb.st_uid != pwd->pw_uid) {
if (chown(per_user_tmp,
pwd->pw_uid, pwd->pw_gid)) {
component_name = "chown";
goto out;
}
}
if (sb.st_mode != (S_IRWXU | S_ISVTX)) {
if (chmod(per_user_tmp,
S_IRWXU | S_ISVTX)) {
component_name = "chmod";
goto out;
}
}
}
}
}
}
errno = 0;
if (flags & LOGIN_SETLOGIN)
if (setlogin(pwd->pw_name) == -1) {
syslog(LOG_ERR, "setlogin(%s) failure: %m",
pwd->pw_name);
login_close(flc);
return (-1);
}
if (flags & LOGIN_SETUSER)
if (setuid(uid) == -1) {
syslog(LOG_ERR, "setuid(%d): %m", uid);
login_close(flc);
return (-1);
}
if (flags & LOGIN_SETENV)
setuserenv(lc, envset, NULL);
if (flags & LOGIN_SETPATH)
setuserpath(lc, pwd ? pwd->pw_dir : "", envset, NULL);
login_close(flc);
return (0);
out:
if (component_name != NULL) {
syslog(LOG_ERR, "%s %s: %m", component_name, per_user_tmp);
login_close(flc);
return (-1);
} else {
syslog(LOG_ERR, "%s: %m", per_user_tmp);
login_close(flc);
return (-1);
}
}
void
setuserpath(login_cap_t *lc, const char *home, envfunc_t senv, void *envp)
{
size_t hlen, plen;
int cnt = 0;
char *path;
const char *cpath;
char *p, *q;
_DIAGASSERT(home != NULL);
hlen = strlen(home);
p = path = login_getcapstr(lc, "path", NULL, NULL);
if (p) {
while (*p)
if (*p++ == '~')
++cnt;
plen = (p - path) + cnt * (hlen + 1) + 1;
p = path;
q = path = malloc(plen);
if (q) {
while (*p) {
p += strspn(p, " \t");
if (*p == '\0')
break;
plen = strcspn(p, " \t");
if (hlen == 0 && *p == '~') {
p += plen;
continue;
}
if (q != path)
*q++ = ':';
if (*p == '~') {
strcpy(q, home);
q += hlen;
++p;
--plen;
}
memcpy(q, p, plen);
p += plen;
q += plen;
}
*q = '\0';
cpath = path;
} else
cpath = _PATH_DEFPATH;
} else
cpath = _PATH_DEFPATH;
if ((*senv)(envp, "PATH", cpath, 1))
warn("could not set PATH");
}
/*
* Convert an expression of the following forms
* 1) A number.
* 2) A number followed by a b (mult by 512).
* 3) A number followed by a k (mult by 1024).
* 5) A number followed by a m (mult by 1024 * 1024).
* 6) A number followed by a g (mult by 1024 * 1024 * 1024).
* 7) A number followed by a t (mult by 1024 * 1024 * 1024 * 1024).
* 8) Two or more numbers (with/without k,b,m,g, or t).
* separated by x (also * for backwards compatibility), specifying
* the product of the indicated values.
*/
static u_quad_t
strtosize(const char *str, char **endptr, int radix)
{
u_quad_t num, num2;
char *expr, *expr2;
_DIAGASSERT(str != NULL);
/* endptr may be NULL */
errno = 0;
num = strtouq(str, &expr, radix);
if (errno || expr == str) {
if (endptr)
*endptr = expr;
return (num);
}
switch(*expr) {
case 'b': case 'B':
num = multiply(num, (u_quad_t)512);
++expr;
break;
case 'k': case 'K':
num = multiply(num, (u_quad_t)1024);
++expr;
break;
case 'm': case 'M':
num = multiply(num, (u_quad_t)1024 * 1024);
++expr;
break;
case 'g': case 'G':
num = multiply(num, (u_quad_t)1024 * 1024 * 1024);
++expr;
break;
case 't': case 'T':
num = multiply(num, (u_quad_t)1024 * 1024);
num = multiply(num, (u_quad_t)1024 * 1024);
++expr;
break;
}
if (errno)
goto erange;
switch(*expr) {
case '*': /* Backward compatible. */
case 'x':
num2 = strtosize(expr+1, &expr2, radix);
if (errno) {
expr = expr2;
goto erange;
}
if (expr2 == expr + 1) {
if (endptr)
*endptr = expr;
return (num);
}
expr = expr2;
num = multiply(num, num2);
if (errno)
goto erange;
break;
}
if (endptr)
*endptr = expr;
return (num);
erange:
if (endptr)
*endptr = expr;
errno = ERANGE;
return (UQUAD_MAX);
}
static u_quad_t
strtolimit(const char *str, char **endptr, int radix)
{
_DIAGASSERT(str != NULL);
/* endptr may be NULL */
if (isinfinite(str)) {
if (endptr)
*endptr = (char *)__UNCONST(str) + strlen(str);
return ((u_quad_t)RLIM_INFINITY);
}
return (strtosize(str, endptr, radix));
}
static int
isinfinite(const char *s)
{
static const char *infs[] = {
"infinity",
"inf",
"unlimited",
"unlimit",
NULL
};
const char **i;
_DIAGASSERT(s != NULL);
for (i = infs; *i; i++) {
if (!strcasecmp(s, *i))
return 1;
}
return 0;
}
static u_quad_t
multiply(u_quad_t n1, u_quad_t n2)
{
static int bpw = 0;
u_quad_t m;
u_quad_t r;
int b1, b2;
/*
* Get rid of the simple cases
*/
if (n1 == 0 || n2 == 0)
return (0);
if (n1 == 1)
return (n2);
if (n2 == 1)
return (n1);
/*
* sizeof() returns number of bytes needed for storage.
* This may be different from the actual number of useful bits.
*/
if (!bpw) {
bpw = sizeof(u_quad_t) * 8;
while (((u_quad_t)1 << (bpw-1)) == 0)
--bpw;
}
/*
* First check the magnitude of each number. If the sum of the
* magnatude is way to high, reject the number. (If this test
* is not done then the first multiply below may overflow.)
*/
for (b1 = bpw; (((u_quad_t)1 << (b1-1)) & n1) == 0; --b1)
;
for (b2 = bpw; (((u_quad_t)1 << (b2-1)) & n2) == 0; --b2)
;
if (b1 + b2 - 2 > bpw) {
errno = ERANGE;
return (UQUAD_MAX);
}
/*
* Decompose the multiplication to be:
* h1 = n1 & ~1
* h2 = n2 & ~1
* l1 = n1 & 1
* l2 = n2 & 1
* (h1 + l1) * (h2 + l2)
* (h1 * h2) + (h1 * l2) + (l1 * h2) + (l1 * l2)
*
* Since h1 && h2 do not have the low bit set, we can then say:
*
* (h1>>1 * h2>>1 * 4) + ...
*
* So if (h1>>1 * h2>>1) > (1<<(bpw - 2)) then the result will
* overflow.
*
* Finally, if MAX - ((h1 * l2) + (l1 * h2) + (l1 * l2)) < (h1*h2)
* then adding in residual amout will cause an overflow.
*/
m = (n1 >> 1) * (n2 >> 1);
if (m >= ((u_quad_t)1 << (bpw-2))) {
errno = ERANGE;
return (UQUAD_MAX);
}
m *= 4;
r = (n1 & n2 & 1)
+ (n2 & 1) * (n1 & ~(u_quad_t)1)
+ (n1 & 1) * (n2 & ~(u_quad_t)1);
if ((u_quad_t)(m + r) < m) {
errno = ERANGE;
return (UQUAD_MAX);
}
m += r;
return (m);
}

66
lib/libutil/login_tty.c Normal file
View file

@ -0,0 +1,66 @@
/* $NetBSD: login_tty.c,v 1.12 2008/02/09 05:07:26 dholland Exp $ */
/*-
* Copyright (c) 1990, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)login_tty.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: login_tty.c,v 1.12 2008/02/09 05:07:26 dholland Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <util.h>
int
login_tty(int fd)
{
_DIAGASSERT(fd != -1);
(void) setsid();
#ifdef TIOCSCTTY
if (ioctl(fd, TIOCSCTTY, (char *)NULL) == -1)
return (-1);
#endif
(void) dup2(fd, STDIN_FILENO);
(void) dup2(fd, STDOUT_FILENO);
(void) dup2(fd, STDERR_FILENO);
if (fd != STDIN_FILENO && fd != STDOUT_FILENO && fd != STDERR_FILENO)
(void) close(fd);
return (0);
}

93
lib/libutil/loginx.3 Normal file
View file

@ -0,0 +1,93 @@
.\" $NetBSD: loginx.3,v 1.3 2008/04/30 13:10:52 martin Exp $
.\"
.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Thomas Klausner.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd September 26, 2002
.Dt LOGINX 3
.Os
.Sh NAME
.Nm loginx ,
.Nm logoutx ,
.Nm logwtmpx
.Nd login utility functions
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft void
.Fn loginx "const struct utmpx *ut"
.Ft int
.Fn logoutx "const char *line" "int status" "int type"
.Ft void
.Fn logwtmpx "const char *line" "const char *name" "const char *host" "int status" "int type"
.Sh DESCRIPTION
The
.Fn loginx ,
.Fn logoutx ,
and
.Fn logwtmpx
operate on the
.Xr utmpx 5
database of currently logged in users, and the
.Xr wtmpx 5
database of logins and logouts.
.Pp
The
.Fn loginx
function updates the
.Pa /var/run/utmpx
and
.Pa /var/log/wtmpx
databases with the information from
.Fa ut .
.Pp
.Fn logoutx
updates the entry corresponding to
.Fa line
with the type and status from
.Fa type
and
.Fa status .
.Pp
.Fn logwtmpx
writes an entry filled with data from
.Fa line ,
.Fa name ,
.Fa host ,
.Fa status ,
and
.Fa type
to the
.Xr wtmpx 5
database.
.Sh RETURN VALUES
.Fn logoutx
returns 1 on success, and 0 if no corresponding entry was found.
.Sh SEE ALSO
.Xr endutxent 3 ,
.Xr utmpx 5

54
lib/libutil/loginx.c Normal file
View file

@ -0,0 +1,54 @@
/* $NetBSD: loginx.c,v 1.2 2003/08/07 16:44:59 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: loginx.c,v 1.2 2003/08/07 16:44:59 agc Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <util.h>
#include <utmp.h>
#include <utmpx.h>
void
loginx(const struct utmpx *ut)
{
(void)pututxline(ut);
(void)updwtmpx(_PATH_WTMPX, ut);
}

77
lib/libutil/logout.c Normal file
View file

@ -0,0 +1,77 @@
/* $NetBSD: logout.c,v 1.16 2005/08/27 17:07:17 elad Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)logout.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: logout.c,v 1.16 2005/08/27 17:07:17 elad Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/time.h>
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <util.h>
#include <utmp.h>
int
logout(const char *line)
{
int fd, rval;
struct utmp ut;
_DIAGASSERT(line != NULL);
if ((fd = open(_PATH_UTMP, O_RDWR, 0)) < 0)
return(0);
rval = 0;
while (read(fd, &ut, sizeof(ut)) == sizeof(ut)) {
if (!ut.ut_name[0] || strncmp(ut.ut_line, line,
(size_t)UT_LINESIZE))
continue;
memset(ut.ut_name, 0, (size_t)UT_NAMESIZE);
memset(ut.ut_host, 0, (size_t)UT_HOSTSIZE);
(void)time(&ut.ut_time);
(void)lseek(fd, -(off_t)sizeof(ut), SEEK_CUR);
(void)write(fd, &ut, sizeof(ut));
rval = 1;
}
(void)close(fd);
return(rval);
}

73
lib/libutil/logoutx.c Normal file
View file

@ -0,0 +1,73 @@
/* $NetBSD: logoutx.c,v 1.2 2003/08/07 16:44:59 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)logout.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: logoutx.c,v 1.2 2003/08/07 16:44:59 agc Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <assert.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <util.h>
#include <utmp.h>
#include <utmpx.h>
int
logoutx(const char *line, int status, int type)
{
struct utmpx *utp, ut;
(void)strlcpy(ut.ut_line, line, sizeof(ut.ut_line));
if ((utp = getutxline(&ut)) == NULL) {
endutxent();
return 0;
}
utp->ut_type = type;
if (WIFEXITED(status))
utp->ut_exit.e_exit = (uint16_t)WEXITSTATUS(status);
if (WIFSIGNALED(status))
utp->ut_exit.e_termination = (uint16_t)WTERMSIG(status);
(void)gettimeofday(&utp->ut_tv, NULL);
(void)pututxline(utp);
endutxent();
return 1;
}

75
lib/libutil/logwtmp.c Normal file
View file

@ -0,0 +1,75 @@
/* $NetBSD: logwtmp.c,v 1.14 2003/08/07 16:44:59 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: logwtmp.c,v 1.14 2003/08/07 16:44:59 agc Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <utmp.h>
#include <util.h>
void
logwtmp(const char *line, const char *name, const char *host)
{
struct utmp ut;
struct stat buf;
int fd;
_DIAGASSERT(line != NULL);
_DIAGASSERT(name != NULL);
_DIAGASSERT(host != NULL);
if ((fd = open(_PATH_WTMP, O_WRONLY|O_APPEND, 0)) < 0)
return;
if (fstat(fd, &buf) == 0) {
(void) strncpy(ut.ut_line, line, sizeof(ut.ut_line));
(void) strncpy(ut.ut_name, name, sizeof(ut.ut_name));
(void) strncpy(ut.ut_host, host, sizeof(ut.ut_host));
(void) time(&ut.ut_time);
if (write(fd, &ut, sizeof(struct utmp)) != sizeof(struct utmp))
(void) ftruncate(fd, buf.st_size);
}
(void) close(fd);
}

76
lib/libutil/logwtmpx.c Normal file
View file

@ -0,0 +1,76 @@
/* $NetBSD: logwtmpx.c,v 1.2 2003/08/07 16:44:59 agc Exp $ */
/*
* Copyright (c) 1988, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)logwtmp.c 8.1 (Berkeley) 6/4/93";
#else
__RCSID("$NetBSD: logwtmpx.c,v 1.2 2003/08/07 16:44:59 agc Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/file.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <utmp.h>
#include <utmpx.h>
#include <util.h>
void
logwtmpx(const char *line, const char *name, const char *host, int status,
int type)
{
struct utmpx ut;
_DIAGASSERT(line != NULL);
_DIAGASSERT(name != NULL);
_DIAGASSERT(host != NULL);
(void)memset(&ut, 0, sizeof(ut));
(void)strncpy(ut.ut_line, line, sizeof(ut.ut_line));
(void)strncpy(ut.ut_name, name, sizeof(ut.ut_name));
(void)strncpy(ut.ut_host, host, sizeof(ut.ut_host));
ut.ut_type = type;
if (WIFEXITED(status))
ut.ut_exit.e_exit = (uint16_t)WEXITSTATUS(status);
if (WIFSIGNALED(status))
ut.ut_exit.e_termination = (uint16_t)WTERMSIG(status);
(void)gettimeofday(&ut.ut_tv, NULL);
(void)updwtmpx(_PATH_WTMPX, &ut);
}

172
lib/libutil/opendisk.3 Normal file
View file

@ -0,0 +1,172 @@
.\" $NetBSD: opendisk.3,v 1.11 2008/04/30 13:10:52 martin Exp $
.\"
.\" Copyright (c) 1997, 2001 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Luke Mewburn.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd December 11, 2001
.Dt OPENDISK 3
.Os
.Sh NAME
.Nm opendisk
.Nd open a disk partition
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fo opendisk
.Fa "const char *path"
.Fa "int flags"
.Fa "char *buf"
.Fa "size_t buflen"
.Fa "int iscooked"
.Fc
.Sh DESCRIPTION
.Fn opendisk
opens
.Fa path ,
for reading and/or writing as specified by the argument
.Fa flags
using
.Xr open 2 ,
and the file descriptor is returned to the caller.
.Fa buf
is used to store the resultant filename.
.Fa buflen
is the size, in bytes, of the array referenced by
.Fa buf
(usually
.Dv MAXPATHLEN
bytes).
.Fa iscooked
controls which paths in
.Pa /dev
are tried.
.Pp
.Fn opendisk
attempts to open the following variations of
.Fa path ,
in order:
.Bl -tag -width "/dev/rpathX"
.It Pa path
The pathname as given.
.It Pa path Ns Em X
.Fa path
with a suffix of
.Sq Em X ,
where
.Sq Em X
represents the raw partition of the device, as determined by
.Xr getrawpartition 3 ,
usually
.Dq c .
.El
.Pp
If
.Fa path
does not contain a
slash
.Pq Dq / ,
the following variations are attempted:
.Pp
.Bl -dash -offset indent
.It
If
.Fa iscooked
is zero:
.Pp
.Bl -tag -width "/dev/rpathX"
.It Pa /dev/rpath
.Fa path
with a prefix of
.Dq Pa /dev/r .
.It Pa /dev/rpath Ns Em X
.Fa path
with a prefix of
.Dq Pa /dev/r
and a suffix of
.Sq Em X
(q.v.).
.El
.It
If
.Fa iscooked
is non-zero:
.Bl -tag -width "/dev/rpathX"
.It Pa /dev/path
.Fa path
with a prefix of
.Dq Pa /dev/ .
.It Pa /dev/path Ns Em X
.Fa path
with a prefix of
.Dq Pa /dev/
and a suffix of
.Sq Em X
(q.v.).
.El
.El
.Sh RETURN VALUES
An open file descriptor, or -1 if the
.Xr open 2
failed.
.Sh ERRORS
.Fn opendisk
may set
.Va errno
to one of the following values:
.Bl -tag -width Er
.It Bq Er EINVAL
.Dv O_CREAT
was set in
.Fa flags ,
or
.Xr getrawpartition 3
didn't return a valid partition.
.It Bq Er EFAULT
.Fa buf
was the
.Dv NULL
pointer.
.El
.Pp
The
.Fn opendisk
function
may also set
.Va errno
to any value specified by the
.Xr open 2
function.
.Sh SEE ALSO
.Xr open 2 ,
.Xr getrawpartition 3
.Sh HISTORY
The
.Fn opendisk
function first appeared in
.Nx 1.3 .

104
lib/libutil/opendisk.c Normal file
View file

@ -0,0 +1,104 @@
/* $NetBSD: opendisk.c,v 1.12 2009/10/13 22:00:31 pooka Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: opendisk.c,v 1.12 2009/10/13 22:00:31 pooka Exp $");
#endif
#include <sys/param.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <util.h>
#include <paths.h>
#include <stdio.h>
#include <string.h>
static int
__opendisk(const char *path, int flags, char *buf, size_t buflen, int iscooked,
int (*ofn)(const char *, int, ...))
{
int f, rawpart;
if (buf == NULL) {
errno = EFAULT;
return (-1);
}
snprintf(buf, buflen, "%s", path);
if ((flags & O_CREAT) != 0) {
errno = EINVAL;
return (-1);
}
rawpart = getrawpartition();
if (rawpart < 0)
return (-1); /* sysctl(3) in getrawpartition sets errno */
f = ofn(buf, flags, 0);
if (f != -1 || errno != ENOENT)
return (f);
snprintf(buf, buflen, "%s%c", path, 'a' + rawpart);
f = ofn(buf, flags, 0);
if (f != -1 || errno != ENOENT)
return (f);
if (strchr(path, '/') != NULL)
return (-1);
snprintf(buf, buflen, "%s%s%s", _PATH_DEV, iscooked ? "" : "r", path);
f = ofn(buf, flags, 0);
if (f != -1 || errno != ENOENT)
return (f);
snprintf(buf, buflen, "%s%s%s%c", _PATH_DEV, iscooked ? "" : "r", path,
'a' + rawpart);
f = ofn(buf, flags, 0);
return (f);
}
int
opendisk(const char *path, int flags, char *buf, size_t buflen, int iscooked)
{
return __opendisk(path, flags, buf, buflen, iscooked, open);
}
int
opendisk1(const char *path, int flags, char *buf, size_t buflen, int iscooked,
int (*ofn)(const char *, int, ...))
{
return __opendisk(path, flags, buf, buflen, iscooked, ofn);
}

165
lib/libutil/openpty.3 Normal file
View file

@ -0,0 +1,165 @@
.\" $NetBSD: openpty.3,v 1.14 2008/11/28 07:17:17 dholland Exp $
.\"
.\" Copyright (c) 1995
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software developed by the Computer Systems
.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract
.\" BG 91-66 and contributed to Berkeley.
.\"
.\" 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 University 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 REGENTS 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 REGENTS 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.
.\"
.Dd November 28, 2008
.Dt OPENPTY 3
.Os
.Sh NAME
.Nm openpty ,
.Nm login_tty ,
.Nm forkpty
.Nd tty utility functions
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn openpty "int *amaster" "int *aslave" "char *name" "struct termios *termp" "struct winsize *winp"
.Ft int
.Fn login_tty "int fd"
.Ft pid_t
.Fn forkpty "int *amaster" "char *name" "struct termios *termp" "struct winsize *winp"
.Sh DESCRIPTION
The
.Fn openpty ,
.Fn login_tty ,
and
.Fn forkpty
functions perform manipulations on ttys and pseudo-ttys.
.Pp
The
.Fn openpty
function finds an available pseudo-tty and returns file descriptors
for the master and slave in
.Fa amaster
and
.Fa aslave .
If
.Fa name
is non-null, the filename of the slave is returned in
.Fa name .
If
.Fa termp
is non-null, the terminal parameters of the slave will be set to the
values in
.Fa termp .
If
.Fa winp
is non-null, the window size of the slave will be set to the values in
.Fa winp .
.Pp
The
.Fn login_tty
function prepares for a login on the tty
.Fa fd
(which may be a real tty device, or the slave of a pseudo-tty as
returned by
.Fn openpty )
by creating a new session, making
.Fa fd
the controlling terminal for the current process, setting
.Fa fd
to be the standard input, output, and error streams of the current
process, and closing
.Fa fd .
.Pp
The
.Fn forkpty
function combines
.Fn openpty ,
.Fn fork ,
and
.Fn login_tty
to create a new process operating in a pseudo-tty.
The file descriptor of the master side of the pseudo-tty is returned
(to the parent process only) in
.Fa amaster .
The filename of the slave is returned (to both the parent and child
processes) in
.Fa name
if
.Fa name
is non-null.
The
.Fa termp
and
.Fa winp
parameters, if non-null, will determine the terminal attributes and
window size of the slave side of the pseudo-tty.
.Sh RETURN VALUES
If a call to
.Fn openpty ,
.Fn login_tty ,
or
.Fn forkpty
is not successful, -1 is returned and
.Va errno
is set to indicate the error.
Otherwise,
.Fn openpty ,
.Fn login_tty ,
and the child process of
.Fn forkpty
return 0, and the parent process of
.Fn forkpty
returns the process ID of the child process.
.Sh FILES
.Bl -tag -width /dev/[pt]ty[p-zP-T][0-9a-zA-Z] -compact
.It Pa /dev/[pt]ty[p-zP-T][0-9a-zA-Z]
.El
.Sh ERRORS
.Fn openpty
will fail if:
.Bl -tag -width Er
.It Bq Er ENOENT
There are no available ttys.
.It Bq Er EPERM
The caller was not the superuser and the
.Xr ptm 4
device is missing or not configured.
.El
.Pp
.Fn login_tty
will fail if
.Fn ioctl
fails to set
.Fa fd
to the controlling terminal of the current process.
.Fn forkpty
will fail if either
.Fn openpty
or
.Fn fork
fails.
.Sh SEE ALSO
.Xr fork 2

278
lib/libutil/parsedate.3 Normal file
View file

@ -0,0 +1,278 @@
.\" $NetBSD: parsedate.3,v 1.10 2010/12/22 09:12:28 wiz Exp $
.\"
.\" Copyright (c) 2006 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Christos Zoulas.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd December 20, 2010
.Dt PARSEDATE 3
.Os
.Sh NAME
.Nm parsedate
.Nd date parsing function
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft time_t
.Fn parsedate "const char *datestr" "const time_t *time" "const int *tzoff"
.Sh DESCRIPTION
The
.Fn parsedate
function parses a datetime from
.Ar datestr
described in english relative to an optional
.Ar time
point and an optional timezone offset in seconds specified in
.Ar tzoff .
If either
.Ar time
or
.Ar tzoff
are
.Dv NULL ,
then the current time and timezone offset are used.
.Pp
The
.Ar datestr
is a sequence of white-space separated items.
The white-space is optional the concatenated items are not ambiguous.
An empty
.Ar datestr
is equivalent to midnight today (the beginning of this day).
.Pp
The following words have the indicated numeric meanings:
.Dv last =
\-1,
.Dv this =
0,
.Dv first, next, or one =
1,
.Dv second
is unused so that it is not confused with
.Dq seconds ,
.Dv two =
2,
.Dv third or three =
3,
.Dv fourth or four =
4,
.Dv fifth or five =
5,
.Dv sixth or six =
6,
.Dv seventh or seven =
7,
.Dv eighth or eight =
8,
.Dv ninth or nine =
9,
.Dv tenth or ten =
10,
.Dv eleventh or eleven =
11,
.Dv twelfth or twoelve =
12.
.Pp
The following words are recognized in English only:
.Dv AM ,
.Dv PM ,
.Dv a.m. ,
.Dv p.m.
.Pp
The months:
.Dv january ,
.Dv february ,
.Dv march ,
.Dv april ,
.Dv may ,
.Dv june ,
.Dv july ,
.Dv august ,
.Dv september ,
.Dv sept ,
.Dv october ,
.Dv november ,
.Dv december ,
.Pp
The days of the week:
.Dv sunday ,
.Dv monday ,
.Dv tuesday ,
.Dv tues ,
.Dv wednesday ,
.Dv wednes ,
.Dv thursday ,
.Dv thur ,
.Dv thurs ,
.Dv friday ,
.Dv saturday .
.Pp
Time units:
.Dv year ,
.Dv month ,
.Dv fortnight ,
.Dv week ,
.Dv day ,
.Dv hour ,
.Dv minute ,
.Dv min ,
.Dv second ,
.Dv sec ,
.Dv tomorrow ,
.Dv yesterday .
.Pp
Timezone names:
.Dv gmt ,
.Dv ut ,
.Dv utc ,
.Dv wet ,
.Dv bst ,
.Dv wat ,
.Dv at ,
.Dv ast ,
.Dv adt ,
.Dv est ,
.Dv edt ,
.Dv cst ,
.Dv cdt ,
.Dv mst ,
.Dv mdt ,
.Dv pst ,
.Dv pdt ,
.Dv yst ,
.Dv ydt ,
.Dv hst ,
.Dv hdt ,
.Dv cat ,
.Dv ahst ,
.Dv nt ,
.Dv idlw ,
.Dv cet ,
.Dv met ,
.Dv mewt ,
.Dv mest ,
.Dv swt ,
.Dv sst ,
.Dv fwt ,
.Dv fst ,
.Dv eet ,
.Dv bt ,
.Dv zp4 ,
.Dv zp5 ,
.Dv zp6 ,
.Dv wast ,
.Dv wadt ,
.Dv cct ,
.Dv jst ,
.Dv east ,
.Dv eadt ,
.Dv gst ,
.Dv nzt ,
.Dv nzst ,
.Dv nzdt ,
.Dv idle .
.Pp
A variety of unambiguous dates are recognized:
.Bl -tag -compact -width "20 Jun 1994"
.It 69-09-10
For years between 69-99 we assume 1900+ and for years between 0-68
we assume 2000+.
.It 2006-11-17
An ISO-8601 date.
.It 10/1/2000
October 10, 2000; the common US format.
.It 20 Jun 1994
.It 23jun2001
.It 1-sep-06
Other common abbreviations.
.It 1/11
the year can be omitted
.El
.Pp
As well as times:
.Bl -tag -compact -width 12:11:01.000012
.It 10:01
.It 10:12pm
.It 12:11:01.000012
.It 12:21-0500
.El
.Pp
Relative items are also supported:
.Bl -tag -compact -width "this thursday"
.It -1 month
.It last friday
.It one week ago
.It this thursday
.It next sunday
.It +2 years
.El
.Pp
Seconds since epoch (also known as UNIX time) are also supported:
.Bl -tag -compact -width "@735275209"
.It @735275209
Tue Apr 20 03:06:49 UTC 1993
.El
.Sh RETURN VALUES
.Fn parsedate
returns the number of seconds passed since the Epoch, or
.Dv \-1
if the date could not be parsed properly.
.Sh SEE ALSO
.Xr date 1 ,
.Xr eeprom 8
.Sh HISTORY
The parser used in
.Fn parsedate
was originally written by Steven M. Bellovin while at the University
of North Carolina at Chapel Hill.
It was later tweaked by a couple of people on Usenet.
Completely overhauled by Rich $alz and Jim Berets in August, 1990.
.Pp
The
.Fn parsedate
function first appeared in
.Nx 4.0 .
.Sh BUGS
.Bl -tag -compact -width 1
.It 1
The
.Fn parsedate
function is not re-entrant or thread-safe.
.It 2
The
.Fn parsedate
function cannot compute days before the unix epoch (19700101).
.It 3
The
.Fn parsedate
function assumes years less than 0 mean -
.Fa year ,
years less than 70 mean 2000 +
.Fa year ,
years less than 100 mean 1900 +
.Fa year .
.El

1060
lib/libutil/parsedate.y Normal file

File diff suppressed because it is too large Load diff

665
lib/libutil/passwd.c Normal file
View file

@ -0,0 +1,665 @@
/* $NetBSD: passwd.c,v 1.50 2010/08/18 08:32:02 christos Exp $ */
/*
* Copyright (c) 1987, 1993, 1994, 1995
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: passwd.c,v 1.50 2010/08/18 08:32:02 christos Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <assert.h>
#include <ctype.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <paths.h>
#include <pwd.h>
#include <grp.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
static const char *pw_filename(const char *filename);
static void pw_cont(int sig);
static const char * pw_equal(char *buf, struct passwd *old_pw);
static const char *pw_default(const char *option);
static int read_line(FILE *fp, char *line, int max);
static void trim_whitespace(char *line);
static char pw_prefix[MAXPATHLEN];
const char *
pw_getprefix(void)
{
return(pw_prefix);
}
int
pw_setprefix(const char *new_prefix)
{
size_t length;
_DIAGASSERT(new_prefix != NULL);
length = strlen(new_prefix);
if (length < sizeof(pw_prefix)) {
(void)strcpy(pw_prefix, new_prefix);
while (length > 0 && pw_prefix[length - 1] == '/')
pw_prefix[--length] = '\0';
return(0);
}
errno = ENAMETOOLONG;
return(-1);
}
static const char *
pw_filename(const char *filename)
{
static char newfilename[MAXPATHLEN];
_DIAGASSERT(filename != NULL);
if (pw_prefix[0] == '\0')
return filename;
if (strlen(pw_prefix) + strlen(filename) < sizeof(newfilename))
return strcat(strcpy(newfilename, pw_prefix), filename);
errno = ENAMETOOLONG;
return(NULL);
}
int
pw_lock(int retries)
{
const char *filename;
int i, fd;
mode_t old_mode;
int oerrno;
/* Acquire the lock file. */
filename = pw_filename(_PATH_MASTERPASSWD_LOCK);
if (filename == NULL)
return(-1);
old_mode = umask(0);
fd = open(filename, O_WRONLY|O_CREAT|O_EXCL, 0600);
for (i = 0; i < retries && fd < 0 && errno == EEXIST; i++) {
sleep(1);
fd = open(filename, O_WRONLY|O_CREAT|O_EXCL,
0600);
}
oerrno = errno;
(void)umask(old_mode);
errno = oerrno;
return(fd);
}
int
pw_mkdb(username, secureonly)
const char *username;
int secureonly;
{
const char *args[9];
int pstat, i;
pid_t pid;
pid = vfork();
if (pid == -1)
return -1;
if (pid == 0) {
args[0] = "pwd_mkdb";
args[1] = "-d";
args[2] = pw_prefix;
args[3] = "-pl";
i = 4;
if (secureonly)
args[i++] = "-s";
if (username != NULL) {
args[i++] = "-u";
args[i++] = username;
}
args[i++] = pw_filename(_PATH_MASTERPASSWD_LOCK);
args[i] = NULL;
execv(_PATH_PWD_MKDB, (char * const *)__UNCONST(args));
_exit(1);
}
pid = waitpid(pid, &pstat, 0);
if (pid == -1) {
warn("error waiting for pid %lu", (unsigned long)pid);
return -1;
}
if (WIFEXITED(pstat)) {
if (WEXITSTATUS(pstat) != 0) {
warnx("pwd_mkdb exited with static %d",
WEXITSTATUS(pstat));
return -1;
}
} else if (WIFSIGNALED(pstat)) {
warnx("pwd_mkdb exited with signal %d", WTERMSIG(pstat));
return -1;
}
return 0;
}
int
pw_abort(void)
{
const char *filename;
filename = pw_filename(_PATH_MASTERPASSWD_LOCK);
return((filename == NULL) ? -1 : unlink(filename));
}
/* Everything below this point is intended for the convenience of programs
* which allow a user to interactively edit the passwd file. Errors in the
* routines below will cause the process to abort. */
static pid_t editpid = -1;
static void
pw_cont(int sig)
{
if (editpid != -1)
kill(editpid, sig);
}
void
pw_init(void)
{
struct rlimit rlim;
#ifndef __minix
/* Unlimited resource limits. */
rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
(void)setrlimit(RLIMIT_CPU, &rlim);
(void)setrlimit(RLIMIT_FSIZE, &rlim);
(void)setrlimit(RLIMIT_STACK, &rlim);
(void)setrlimit(RLIMIT_DATA, &rlim);
(void)setrlimit(RLIMIT_RSS, &rlim);
/* Don't drop core (not really necessary, but GP's). */
rlim.rlim_cur = rlim.rlim_max = 0;
(void)setrlimit(RLIMIT_CORE, &rlim);
#endif
/* Turn off signals. */
(void)signal(SIGALRM, SIG_IGN);
(void)signal(SIGHUP, SIG_IGN);
(void)signal(SIGINT, SIG_IGN);
(void)signal(SIGPIPE, SIG_IGN);
(void)signal(SIGQUIT, SIG_IGN);
(void)signal(SIGTERM, SIG_IGN);
(void)signal(SIGCONT, pw_cont);
}
void
pw_edit(int notsetuid, const char *filename)
{
int pstat;
char *p;
const char * volatile editor;
const char *argp[] = { "sh", "-c", NULL, NULL };
if (filename == NULL)
filename = _PATH_MASTERPASSWD_LOCK;
filename = pw_filename(filename);
if (filename == NULL)
return;
if ((editor = getenv("EDITOR")) == NULL)
editor = _PATH_VI;
p = malloc(strlen(editor) + 1 + strlen(filename) + 1);
if (p == NULL)
return;
sprintf(p, "%s %s", editor, filename);
argp[2] = p;
switch(editpid = vfork()) {
case -1:
free(p);
return;
case 0:
if (notsetuid) {
setgid(getgid());
setuid(getuid());
}
execvp(_PATH_BSHELL, (char *const *)__UNCONST(argp));
_exit(1);
}
free(p);
for (;;) {
editpid = waitpid(editpid, (int *)&pstat, WUNTRACED);
if (editpid == -1)
pw_error(editor, 1, 1);
else if (WIFSTOPPED(pstat))
raise(WSTOPSIG(pstat));
else if (WIFEXITED(pstat) && WEXITSTATUS(pstat) == 0)
break;
else
pw_error(editor, 1, 1);
}
editpid = -1;
}
void
pw_prompt(void)
{
int c;
(void)printf("re-edit the password file? [y]: ");
(void)fflush(stdout);
c = getchar();
if (c != EOF && c != '\n')
while (getchar() != '\n');
if (c == 'n')
pw_error(NULL, 0, 0);
}
/* for use in pw_copy(). Compare a pw entry to a pw struct. */
/* returns a character string labelling the miscompared field or 0 */
static const char *
pw_equal(char *buf, struct passwd *pw)
{
struct passwd buf_pw;
size_t len;
_DIAGASSERT(buf != NULL);
_DIAGASSERT(pw != NULL);
len = strlen (buf);
if (buf[len-1] == '\n')
buf[len-1] = '\0';
if (!pw_scan(buf, &buf_pw, NULL))
return "corrupt line";
if (strcmp(pw->pw_name, buf_pw.pw_name) != 0)
return "name";
if (pw->pw_uid != buf_pw.pw_uid)
return "uid";
if (pw->pw_gid != buf_pw.pw_gid)
return "gid";
if (strcmp( pw->pw_class, buf_pw.pw_class) != 0)
return "class";
if (pw->pw_change != buf_pw.pw_change)
return "change";
if (pw->pw_expire != buf_pw.pw_expire)
return "expire";
if (strcmp( pw->pw_gecos, buf_pw.pw_gecos) != 0)
return "gecos";
if (strcmp( pw->pw_dir, buf_pw.pw_dir) != 0)
return "dir";
if (strcmp( pw->pw_shell, buf_pw.pw_shell) != 0)
return "shell";
return (char *)0;
}
void
pw_copy(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw)
{
char errbuf[200];
int rv;
rv = pw_copyx(ffd, tfd, pw, old_pw, errbuf, sizeof(errbuf));
if (rv == 0) {
warnx("%s", errbuf);
pw_error(NULL, 0, 1);
}
}
static void
pw_print(FILE *to, const struct passwd *pw)
{
(void)fprintf(to, "%s:%s:%d:%d:%s:%lld:%lld:%s:%s:%s\n",
pw->pw_name, pw->pw_passwd, pw->pw_uid, pw->pw_gid,
pw->pw_class, (long long)pw->pw_change,
(long long)pw->pw_expire,
pw->pw_gecos, pw->pw_dir, pw->pw_shell);
}
int
pw_copyx(int ffd, int tfd, struct passwd *pw, struct passwd *old_pw,
char *errbuf, size_t errbufsz)
{
const char *filename;
char mpwd[MAXPATHLEN], mpwdl[MAXPATHLEN], *p, buf[8192];
FILE *from, *to;
int done;
_DIAGASSERT(pw != NULL);
_DIAGASSERT(errbuf != NULL);
/* old_pw may be NULL */
if ((filename = pw_filename(_PATH_MASTERPASSWD)) == NULL) {
snprintf(errbuf, errbufsz, "%s: %s", pw_prefix,
strerror(errno));
return (0);
}
(void)strcpy(mpwd, filename);
if ((filename = pw_filename(_PATH_MASTERPASSWD_LOCK)) == NULL) {
snprintf(errbuf, errbufsz, "%s: %s", pw_prefix,
strerror(errno));
return (0);
}
(void)strcpy(mpwdl, filename);
if (!(from = fdopen(ffd, "r"))) {
snprintf(errbuf, errbufsz, "%s: %s", mpwd, strerror(errno));
return (0);
}
if (!(to = fdopen(tfd, "w"))) {
snprintf(errbuf, errbufsz, "%s: %s", mpwdl, strerror(errno));
(void)fclose(from);
return (0);
}
for (done = 0; fgets(buf, (int)sizeof(buf), from);) {
const char *neq;
if (!strchr(buf, '\n')) {
snprintf(errbuf, errbufsz, "%s: line too long", mpwd);
(void)fclose(from);
(void)fclose(to);
return (0);
}
if (done) {
(void)fprintf(to, "%s", buf);
if (ferror(to)) {
snprintf(errbuf, errbufsz, "%s",
strerror(errno));
(void)fclose(from);
(void)fclose(to);
return (0);
}
continue;
}
if (!(p = strchr(buf, ':'))) {
snprintf(errbuf, errbufsz, "%s: corrupted entry", mpwd);
(void)fclose(from);
(void)fclose(to);
return (0);
}
*p = '\0';
if (strcmp(buf, pw->pw_name)) {
*p = ':';
(void)fprintf(to, "%s", buf);
if (ferror(to)) {
snprintf(errbuf, errbufsz, "%s",
strerror(errno));
(void)fclose(from);
(void)fclose(to);
return (0);
}
continue;
}
*p = ':';
if (old_pw && (neq = pw_equal(buf, old_pw)) != NULL) {
if (strcmp(neq, "corrupt line") == 0)
(void)snprintf(errbuf, errbufsz,
"%s: entry %s corrupted", mpwd,
pw->pw_name);
else
(void)snprintf(errbuf, errbufsz,
"%s: entry %s inconsistent %s",
mpwd, pw->pw_name, neq);
(void)fclose(from);
(void)fclose(to);
return (0);
}
pw_print(to, pw);
done = 1;
if (ferror(to)) {
snprintf(errbuf, errbufsz, "%s", strerror(errno));
(void)fclose(from);
(void)fclose(to);
return (0);
}
}
/* Only append a new entry if real uid is root! */
if (!done) {
if (getuid() == 0) {
pw_print(to, pw);
done = 1;
} else {
snprintf(errbuf, errbufsz,
"%s: changes not made, no such entry", mpwd);
}
}
if (ferror(to)) {
snprintf(errbuf, errbufsz, "%s", strerror(errno));
(void)fclose(from);
(void)fclose(to);
return (0);
}
(void)fclose(from);
(void)fclose(to);
return (done);
}
void
pw_error(const char *name, int error, int eval)
{
if (error) {
if (name)
warn("%s", name);
else
warn(NULL);
}
warnx("%s%s: unchanged", pw_prefix, _PATH_MASTERPASSWD);
pw_abort();
exit(eval);
}
/* Removes head and/or tail spaces. */
static void
trim_whitespace(char *line)
{
char *p;
_DIAGASSERT(line != NULL);
/* Remove leading spaces */
p = line;
while (isspace((unsigned char) *p))
p++;
memmove(line, p, strlen(p) + 1);
/* Remove trailing spaces */
p = line + strlen(line) - 1;
while (isspace((unsigned char) *p))
p--;
*(p + 1) = '\0';
}
/* Get one line, remove spaces from front and tail */
static int
read_line(FILE *fp, char *line, int max)
{
char *p;
_DIAGASSERT(fp != NULL);
_DIAGASSERT(line != NULL);
/* Read one line of config */
if (fgets(line, max, fp) == NULL)
return (0);
if ((p = strchr(line, '\n')) == NULL) {
warnx("line too long");
return (0);
}
*p = '\0';
/* Remove comments */
if ((p = strchr(line, '#')) != NULL)
*p = '\0';
trim_whitespace(line);
return (1);
}
static const char *
pw_default(const char *option)
{
static const char *options[][2] = {
{ "localcipher", "old" },
{ "ypcipher", "old" },
};
size_t i;
_DIAGASSERT(option != NULL);
for (i = 0; i < sizeof(options) / sizeof(options[0]); i++)
if (strcmp(options[i][0], option) == 0)
return (options[i][1]);
return (NULL);
}
/*
* Retrieve password information from the /etc/passwd.conf file, at the
* moment this is only for choosing the cipher to use. It could easily be
* used for other authentication methods as well.
*/
void
pw_getconf(char *data, size_t max, const char *key, const char *option)
{
FILE *fp;
char line[LINE_MAX], *p, *p2;
static char result[LINE_MAX];
int got, found;
const char *cp;
_DIAGASSERT(data != NULL);
_DIAGASSERT(key != NULL);
_DIAGASSERT(option != NULL);
got = 0;
found = 0;
result[0] = '\0';
if ((fp = fopen(_PATH_PASSWD_CONF, "r")) == NULL) {
if ((cp = pw_default(option)) != NULL)
strlcpy(data, cp, max);
else
data[0] = '\0';
return;
}
while (!found && (got || read_line(fp, line, LINE_MAX))) {
got = 0;
if (strncmp(key, line, strlen(key)) != 0 ||
line[strlen(key)] != ':')
continue;
/* Now we found our specified key */
while (read_line(fp, line, LINE_MAX)) {
/* Leaving key field */
if (line[0] != '\0' && strchr(line + 1, ':') != NULL) {
got = 1;
break;
}
p2 = line;
if ((p = strsep(&p2, "=")) == NULL || p2 == NULL)
continue;
trim_whitespace(p);
if (!strncmp(p, option, strlen(option))) {
trim_whitespace(p2);
strcpy(result, p2);
found = 1;
break;
}
}
}
fclose(fp);
if (!found)
errno = ENOENT;
if (!got)
errno = ENOTDIR;
/*
* If we got no result and were looking for a default
* value, try hard coded defaults.
*/
if (strlen(result) == 0 && strcmp(key, "default") == 0 &&
(cp = pw_default(option)) != NULL)
strlcpy(data, cp, max);
else
strlcpy(data, result, max);
}
void
pw_getpwconf(char *data, size_t max, const struct passwd *pwd,
const char *option)
{
char grpkey[LINE_MAX];
struct group grs, *grp;
char grbuf[1024];
pw_getconf(data, max, pwd->pw_name, option);
/* Try to find an entry for the group */
if (*data == '\0') {
(void)getgrgid_r(pwd->pw_gid, &grs, grbuf, sizeof(grbuf), &grp);
if (grp != NULL) {
(void)snprintf(grpkey, sizeof(grpkey), ":%s",
grp->gr_name);
pw_getconf(data, max, grpkey, option);
}
if (*data == '\0')
pw_getconf(data, max, "default", option);
}
}

89
lib/libutil/pidfile.3 Normal file
View file

@ -0,0 +1,89 @@
.\" $NetBSD: pidfile.3,v 1.12 2010/05/05 22:05:31 wiz Exp $
.\"
.\" Copyright (c) 1999 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Jason R. Thorpe.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. Redistributions in binary form must reproduce the above copyright
.\" notice, this list of conditions and the following disclaimer in the
.\" documentation and/or other materials provided with the distribution.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 4, 2010
.Dt PIDFILE 3
.Os
.Sh NAME
.Nm pidfile
.Nd write a daemon pid file
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn pidfile "const char *basename"
.Sh DESCRIPTION
.Fn pidfile
writes a file containing the process ID of the program to the
.Pa /var/run
directory.
The file name has the form
.Pa /var/run/basename.pid .
If the
.Ar basename
argument is
.Dv NULL ,
.Fn pidfile
will determine the program name and use that instead.
.Pp
The pid file can be used as a quick reference if
the process needs to be sent a signal.
When the program exits, the pid file will be removed automatically, unless
the program receives a fatal signal.
.Pp
Note that only the first invocation of
.Fn pidfile
causes a pid file to be written; subsequent invocations have no effect
unless a new
.Ar basename
is supplied.
If called with a new
.Ar basename ,
.Fn pidfile
will remove the old pid file and write the new one.
.Sh RETURN VALUES
.Fn pidfile
returns 0 on success and -1 on failure.
.Sh SEE ALSO
.Xr atexit 3
.Sh HISTORY
The
.Fn pidfile
function call appeared in
.Nx 1.5 .
.Sh BUGS
.Fn pidfile
uses
.Xr atexit 3
to ensure the pidfile is unlinked at program exit.
However, programs that use the
.Xr _exit 2
function (for example, in signal handlers)
will not trigger this behaviour.

120
lib/libutil/pidfile.c Normal file
View file

@ -0,0 +1,120 @@
/* $NetBSD: pidfile.c,v 1.8 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 1999 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Jason R. Thorpe and Matthias Scheler.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: pidfile.c,v 1.8 2008/04/28 20:23:03 martin Exp $");
#endif
#include <sys/param.h>
#include <paths.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
static int pidfile_atexit_done;
static pid_t pidfile_pid;
static char *pidfile_basename;
static char *pidfile_path;
static void pidfile_cleanup(void);
int
pidfile(const char *basename)
{
FILE *f;
/*
* Register handler which will remove the pidfile later.
*/
if (!pidfile_atexit_done) {
if (atexit(pidfile_cleanup) < 0)
return -1;
pidfile_atexit_done = 1;
}
if (basename == NULL)
basename = getprogname();
/*
* If pidfile has already been created for the supplied basename
* we don't need to create a pidfile again.
*/
if (pidfile_path != NULL) {
if (strcmp(pidfile_basename, basename) == 0)
return 0;
/*
* Remove existing pidfile if it was created by this process.
*/
pidfile_cleanup();
free(pidfile_path);
pidfile_path = NULL;
free(pidfile_basename);
pidfile_basename = NULL;
}
pidfile_pid = getpid();
pidfile_basename = strdup(basename);
if (pidfile_basename == NULL)
return -1;
/* _PATH_VARRUN includes trailing / */
(void) asprintf(&pidfile_path, "%s%s.pid", _PATH_VARRUN, basename);
if (pidfile_path == NULL) {
free(pidfile_basename);
pidfile_basename = NULL;
return -1;
}
if ((f = fopen(pidfile_path, "w")) == NULL) {
free(pidfile_path);
pidfile_path = NULL;
free(pidfile_basename);
pidfile_basename = NULL;
return -1;
}
(void) fprintf(f, "%d\n", pidfile_pid);
(void) fclose(f);
return 0;
}
static void
pidfile_cleanup(void)
{
/* Only remove the pidfile if it was created by this process. */
if ((pidfile_path != NULL) && (pidfile_pid == getpid()))
(void) unlink(pidfile_path);
}

184
lib/libutil/pidlock.3 Normal file
View file

@ -0,0 +1,184 @@
.\" $NetBSD: pidlock.3,v 1.12 2009/03/09 19:24:27 joerg Exp $
.\"
.\" Copyright 1996, 1997 by Curt Sampson <cjs@NetBSD.org>
.\"
.\" 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.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd March 19, 2006
.Dt PIDLOCK 3
.Os
.Sh NAME
.Nm pidlock ,
.Nm ttylock ,
.Nm ttyunlock
.Nd locks based on files containing PIDs
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn pidlock "const char *lockfile" "int flags" "pid_t *locker" "const char *info"
.Ft int
.Fn ttylock "const char *tty" "int flags" "pid_t *locker"
.Ft int
.Fn ttyunlock "const char *tty"
.Sh DESCRIPTION
The
.Fn pidlock
.Fn ttylock ,
and
.Fn ttyunlock
functions attempt to create a lockfile for an arbitrary resource that
only one program may hold at a time.
(In the case of
.Fn ttylock ,
this is access to a tty device.)
If the
function succeeds in creating the lockfile, it will succeed for
no other program calling it with the same lockfile until the original
calling program has removed the lockfile or exited.
The
.Fn ttyunlock
function will remove the lockfile created by
.Fn ttylock .
.Pp
These functions use the method of creating a lockfile traditionally
used by UUCP software.
This is described as follows in the documentation for Taylor UUCP:
.Bd -filled -offset indent
The lock file normally contains the process ID of the locking process.
This makes it easy to determine whether a lock is still valid.
The algorithm is to create a temporary file and then link
it to the name that must be locked.
If the link fails because a file with that name already exists,
the existing file is read to get the process ID.
If the process still exists, the lock attempt fails.
Otherwise the lock file is deleted and the locking algorithm
is retried.
.Ed
.Pp
The PID is stored in ASCII format, with leading spaces to pad it
out to ten characters, and a terminating newline.
This implementation has been extended to put the hostname
on the second line of the file, terminated with a newline, and
optionally an arbitrary comment on the third line of the file, also
terminated with a newline.
If a comment is given, but
.Dv PIDLOCK_NONBLOCK
is not, a blank line will be written as the second line of the file.
.Pp
The
.Fn pidlock
function will attempt to create the file
.Fa lockfile
and put the current process's pid in it.
The
.Fn ttylock
function will do the same, but should be passed only the base name
(with no leading directory prefix) of the
.Fa tty
to be locked; it will test that the tty exists in
.Pa /dev
and is a character device, and then create
the file in the
.Pa /var/spool/lock
directory and prefix the filename with
.Pa LCK.. .
Use the
.Fn ttyunlock
function to remove this lock.
.Pp
The following flags may be passed in
.Pa flags :
.Bl -tag -width Dv -offset indent
.It Dv PIDLOCK_NONBLOCK
The function should return immediately when a lock is held by another
active process.
Otherwise the function will wait (forever, if necessary)
for the lock to be freed.
.It Dv PIDLOCK_USEHOSTNAME
The hostname should be compared against the hostname in the second
line of the file (if present), and if they differ, no attempt at
checking for a living process holding the lock will be made, and
the lockfile will never be deleted.
(The process is assumed to be alive.)
This is used for locking on NFS or other remote filesystems.
(The function will never create a lock if
.Dv PIDLOCK_USEHOSTNAME
is specified and no hostname is present.)
.El
.Pp
If
.Pa locker
is non-null, it will contain the PID of the locking process, if there
is one, on return.
.Pp
If
.Pa info
is non-null and the lock succeeds, the string it points to will be
written as the third line of the lock file.
.Sh RETURN VALUES
Zero is returned if the operation was successful; on an error a -1
is returned and a standard error code is left in the global location
.Va errno .
.Sh ERRORS
In addition to the errors that are returned from
.Xr stat 2 ,
.Xr open 2 ,
.Xr read 2 ,
.Xr write 2 ,
and
.Xr link 2 ,
.Fn pidlock
or
.Fn ttylock
can set
.Va errno
to the following values on failure:
.Bl -tag -width Er
.It Bq Er EWOULDBLOCK
Another running process has a lock and the
.Dv PIDLOCK_NONBLOCK
flag was specified.
.It Bq Er EFTYPE
The
.Fa tty
specified in
.Fn ttylock
is not a character special device.
.El
.\" .Sh SEE ALSO
.Sh HISTORY
The
.Fn pidlock
and
.Fn ttylock
functions appeared in
.Nx 1.3 .
.Sh AUTHORS
.An Curt Sampson
.Aq cjs@NetBSD.org .
.Sh BUGS
The lockfile format breaks if a pid is longer than ten digits when
printed in decimal form.
.Pp
The PID returned will be the pid of the locker on the remote machine if
.Dv PIDLOCK_USEHOSTNAME
is specified, but there is no indication that this is not on the local
machine.

232
lib/libutil/pidlock.c Normal file
View file

@ -0,0 +1,232 @@
/* $NetBSD: pidlock.c,v 1.15 2009/01/18 12:13:04 lukem Exp $ */
/*
* Copyright 1996, 1997 by Curt Sampson <cjs@NetBSD.org>.
*
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: pidlock.c,v 1.15 2009/01/18 12:13:04 lukem Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
#include <paths.h>
/*
* Create a lockfile. Return 0 when locked, -1 on error.
*/
int
pidlock(const char *lockfile, int flags, pid_t *locker, const char *info)
{
char tempfile[MAXPATHLEN];
char hostname[MAXHOSTNAMELEN + 1];
pid_t pid2 = -1;
struct stat st;
int err;
int f = -1;
char s[256];
char *p;
size_t len;
_DIAGASSERT(lockfile != NULL);
/* locker may be NULL */
/* info may be NULL */
if (gethostname(hostname, sizeof(hostname)))
return -1;
hostname[sizeof(hostname) - 1] = '\0';
/*
* Build a path to the temporary file.
* We use the path with the PID and hostname appended.
* XXX This is not thread safe.
*/
if (snprintf(tempfile, sizeof(tempfile), "%s.%d.%s", lockfile,
(int) getpid(), hostname) >= (int)sizeof(tempfile)) {
errno = ENAMETOOLONG;
return -1;
}
/* Open it, write pid, hostname, info. */
if ((f = open(tempfile, O_WRONLY|O_CREAT|O_TRUNC, 0600)) == -1)
goto out;
(void)snprintf(s, sizeof(s), "%10d\n", getpid()); /* pid */
if (write(f, s, (size_t)11) != 11)
goto out;
if ((flags & PIDLOCK_USEHOSTNAME)) { /* hostname */
len = strlen(hostname);
if ((size_t)write(f, hostname, len) != len
|| write(f, "\n", (size_t)1) != 1)
goto out;
}
if (info) { /* info */
if (!(flags & PIDLOCK_USEHOSTNAME)) {
/* write blank line because there's no hostname */
if (write(f, "\n", (size_t)1) != 1)
goto out;
}
len = strlen(info);
if ((size_t)write(f, info, len) != len ||
write(f, "\n", (size_t)1) != 1)
goto out;
}
(void)close(f);
f = -1;
/* Hard link the temporary file to the real lock file. */
/* This is an atomic operation. */
lockfailed:
while (link(tempfile, lockfile) == -1) {
if (errno != EEXIST)
goto out;
/* Find out who has this lockfile. */
if ((f = open(lockfile, O_RDONLY, 0)) != -1) {
if ((err = read(f, s, (size_t)11)) == -1)
goto out;
if (err == 0) {
errno = EINVAL;
goto out;
}
pid2 = atoi(s);
if ((err = read(f, s, sizeof(s) - 2)) == -1)
goto out;
if (err == 0)
*s = '\0';
s[sizeof(s) - 1] = '\0';
if ((p = strchr(s, '\n')) != NULL)
*p = '\0';
(void)close(f);
f = -1;
if ((flags & PIDLOCK_USEHOSTNAME) == 0 ||
strcmp(s, hostname) == 0) {
if (kill(pid2, 0) == -1 && errno == ESRCH) {
/* process doesn't exist */
(void)unlink(lockfile);
continue;
}
}
}
if (flags & PIDLOCK_NONBLOCK) {
if (locker)
*locker = pid2;
errno = EWOULDBLOCK;
goto out;
} else
sleep(5);
}
/*
* Check to see that we really were successful (in case we're
* using NFS) by making sure that something really is linked
* to our tempfile (reference count is two).
*/
if (stat(tempfile, &st) == -1)
goto out;
if (st.st_nlink != 2)
goto lockfailed;
(void)unlink(tempfile);
if (locker)
*locker = getpid(); /* return this process's PID on lock */
errno = 0;
return 0;
out:
err = errno;
if (f != -1)
(void)close(f);
(void)unlink(tempfile);
errno = err;
return -1;
}
static int
checktty(const char *tty)
{
char ttyfile[MAXPATHLEN];
struct stat sb;
(void)strlcpy(ttyfile, _PATH_DEV, sizeof(ttyfile));
(void)strlcat(ttyfile, tty, sizeof(ttyfile));
/* make sure the tty exists */
if (stat(ttyfile, &sb) == -1)
return -1;
if (!S_ISCHR(sb.st_mode)) {
errno = EFTYPE;
return -1;
}
return 0;
}
#define LOCKPATH "/var/spool/lock/LCK.."
static char *
makelock(char *buf, size_t bufsiz, const char *tty)
{
(void)strlcpy(buf, LOCKPATH, bufsiz);
(void)strlcat(buf, tty, bufsiz);
return buf;
}
/*ARGSUSED*/
int
ttylock(const char *tty, int flags, pid_t *locker)
{
char lockfile[MAXPATHLEN];
_DIAGASSERT(tty != NULL);
if (checktty(tty) != 0)
return -1;
/* do the lock */
return pidlock(makelock(lockfile, sizeof(lockfile), tty),
flags, locker, 0);
}
int
ttyunlock(const char *tty)
{
char lockfile[MAXPATHLEN];
_DIAGASSERT(tty != NULL);
if (checktty(tty) != 0)
return -1;
/* remove the lock */
return unlink(makelock(lockfile, sizeof(lockfile), tty));
}

170
lib/libutil/pty.c Normal file
View file

@ -0,0 +1,170 @@
/* $NetBSD: pty.c,v 1.31 2009/02/20 16:44:06 christos Exp $ */
/*-
* Copyright (c) 1990, 1993, 1994
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)pty.c 8.3 (Berkeley) 5/16/94";
#else
__RCSID("$NetBSD: pty.c,v 1.31 2009/02/20 16:44:06 christos Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
#include <grp.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <util.h>
/*
* XXX: `v' removed until no ports are using console devices which use ttyv0
*/
#define TTY_LETTERS "pqrstuwxyzPQRST"
#define TTY_OLD_SUFFIX "0123456789abcdef"
#define TTY_NEW_SUFFIX "ghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
int
openpty(int *amaster, int *aslave, char *name, struct termios *term,
struct winsize *winp)
{
char line[] = "/dev/XtyXX";
const char *cp1, *cp2, *cp, *linep;
int master, slave;
gid_t ttygid;
mode_t mode;
struct group grs, *grp;
char grbuf[1024];
_DIAGASSERT(amaster != NULL);
_DIAGASSERT(aslave != NULL);
/* name may be NULL */
/* term may be NULL */
/* winp may be NULL */
#ifndef __minix
if ((master = open("/dev/ptm", O_RDWR)) != -1) {
struct ptmget pt;
if (ioctl(master, TIOCPTMGET, &pt) != -1) {
(void)close(master);
master = pt.cfd;
slave = pt.sfd;
linep = pt.sn;
goto gotit;
}
(void)close(master);
}
#endif
(void)getgrnam_r("tty", &grs, grbuf, sizeof(grbuf), &grp);
if (grp != NULL) {
ttygid = grp->gr_gid;
mode = S_IRUSR|S_IWUSR|S_IWGRP;
} else {
ttygid = getgid();
mode = S_IRUSR|S_IWUSR;
}
for (cp1 = TTY_LETTERS; *cp1; cp1++) {
line[8] = *cp1;
for (cp = cp2 = TTY_OLD_SUFFIX TTY_NEW_SUFFIX; *cp2; cp2++) {
line[5] = 'p';
line[9] = *cp2;
if ((master = open(line, O_RDWR, 0)) == -1) {
if (errno != ENOENT)
continue; /* busy */
if ((size_t)(cp2 - cp + 1) < sizeof(TTY_OLD_SUFFIX))
return -1; /* out of ptys */
else
break; /* out of ptys in this group */
}
line[5] = 't';
linep = line;
if (chown(line, getuid(), ttygid) == 0 &&
chmod(line, mode) == 0 &&
revoke(line) == 0 &&
(slave = open(line, O_RDWR, 0)) != -1) {
gotit:
*amaster = master;
*aslave = slave;
if (name)
(void)strcpy(name, linep);
if (term)
(void)tcsetattr(slave, TCSAFLUSH, term);
if (winp)
(void)ioctl(slave, TIOCSWINSZ, winp);
return 0;
}
(void)close(master);
}
}
errno = ENOENT; /* out of ptys */
return -1;
}
pid_t
forkpty(int *amaster, char *name, struct termios *term, struct winsize *winp)
{
int master, slave;
pid_t pid;
_DIAGASSERT(amaster != NULL);
/* name may be NULL */
/* term may be NULL */
/* winp may be NULL */
if (openpty(&master, &slave, name, term, winp) == -1)
return -1;
switch (pid = fork()) {
case -1:
return -1;
case 0:
/*
* child
*/
(void)close(master);
login_tty(slave);
return 0;
}
/*
* parent
*/
*amaster = master;
(void)close(slave);
return pid;
}

114
lib/libutil/pw_getconf.3 Normal file
View file

@ -0,0 +1,114 @@
.\" $NetBSD: pw_getconf.3,v 1.12 2010/05/04 06:41:27 jruoho Exp $
.\"
.\" Copyright 1997 Niels Provos <provos@physnet.uni-hamburg.de>
.\" 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. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by Niels Provos.
.\" 4. The name of the author may not be used to endorse or promote products
.\" derived from this software without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
.\"
.\" from OpenBSD: pw_getconf.3,v 1.5 1999/09/21 04:52:46 csapuntz Exp
.\"
.Dd May 4, 2010
.Dt PW_GETCONF 3
.Os
.Sh NAME
.Nm pw_getconf ,
.Nm pw_getpwconf
.Nd password encryption configuration access function
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft void
.Fn pw_getconf "char *data" "size_t len" "const char *key" "const char *option"
.Ft void
.Fn pw_getpwconf "char *data" "size_t len" "const struct passwd *pwd" "const char *option"
.Sh DESCRIPTION
The
.Fn pw_getconf
function reads
.Pa /etc/passwd.conf
and retrieves the value of the option specified
by
.Pa option
from the section given by
.Pa key .
If no suitable entry is found
for the
.Pa key
an empty string will be returned in data.
.Pp
To retrieve default values the key
.Pa default
can be used.
In this case, if
.Pa /etc/passwd.conf
does not exist or does not contain a
.Pa default
section, the built-in defaults will be returned.
They are as follows:
.Bl -column localcipher data -offset indent
.It Sy option data
.It ypcipher old
.It localcipher old
.El
.Pp
An empty string is returned for all errors.
.Pp
.Fn pw_getpwconf
returns the value for the option specified for the particular user
specified in
.Ar pwd .
If that option is not found, then it tries to find the option in
the primary group of that user, and if that fails, then it returns
the default entry.
.Sh FILES
.Bl -tag -width /etc/passwd.conf -compact
.It Pa /etc/passwd.conf
.El
.Sh ERRORS
.Fn pw_getconf
and
.Fn pw_getpwconf
will fail if:
.Bl -tag -width Er
.It Bq Er ENOENT
There is no option named
.Pa option
in the specified key.
.It Bq Er ENOTDIR
There is no key in
.Pa /etc/passwd.conf
named
.Pa key .
.El
.Sh SEE ALSO
.Xr passwd 5 ,
.Xr passwd.conf 5
.Sh HISTORY
The
.Fn pw_getconf
function first appeared in
.Nx 1.6 .

229
lib/libutil/pw_init.3 Normal file
View file

@ -0,0 +1,229 @@
.\" $NetBSD: pw_init.3,v 1.15 2010/05/05 22:05:31 wiz Exp $
.\"
.\" Copyright (c) 1995
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software developed by the Computer Systems
.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract
.\" BG 91-66 and contributed to Berkeley.
.\"
.\" 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 University 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 REGENTS 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 REGENTS 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.
.\"
.Dd August 1, 2004
.Dt PW_INIT 3
.Os
.Sh NAME
.Nm pw_init ,
.Nm pw_edit ,
.Nm pw_prompt ,
.Nm pw_copy ,
.Nm pw_copyx ,
.Nm pw_scan ,
.Nm pw_error
.Nd utility functions for interactive passwd file updates
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In pwd.h
.In util.h
.Ft void
.Fn pw_init "void"
.Ft void
.Fn pw_edit "int notsetuid" "const char *filename"
.Ft void
.Fn pw_prompt "void"
.Ft void
.Fn pw_copy "int ffd" "int tfd" "struct passwd *pw" "struct passwd *old_pw"
.Ft int
.Fn pw_copyx "int ffd" "int tfd" "struct passwd *pw" "struct passwd *old_pw" \
"char *errbuf" "size_t errbufsz"
.Ft int
.Fn pw_scan "char *bp" "struct passwd *pw" "int *flags"
.Ft void
.Fn pw_error "const char *name" "int err" "int eval"
.Sh DESCRIPTION
These functions are designed as conveniences for interactive programs
which update the passwd file and do nothing else.
They generally handle errors by printing out a message to the standard error
stream and possibly aborting the process.
.Pp
The
.Fn pw_init
function prepares for a passwd update by unlimiting all resource
constraints, disabling core dumps (thus preventing dumping the
contents of the passwd database into a world-readable file), and
disabling most signals.
.Pp
The
.Fn pw_edit
function runs an editor (named by the environment variable EDITOR, or
.Pa /usr/bin/vi
if EDITOR is not set) on the file
.Fa filename
(or
.Pa /etc/ptmp
if
.Fa filename
is
.Dv NULL ) .
If
.Fa notsetuid
is nonzero,
.Fn pw_edit
will set the effective user and group ID to the real user and group ID
before running the editor.
.Pp
The
.Fn pw_prompt
function asks the user whether he or she wants to re-edit the password
file; if the answer is no,
.Fn pw_prompt
deletes the lock file and exits the process.
.Pp
The
.Fn pw_copy
function reads a passwd file from
.Fa ffd
and writes it to
.Fa tfd ,
updating the entry corresponding to pw-\*[Gt]pw_name with the information
in
.Fa pw .
If
.Fa old_pw
is not
.Dv NULL ,
it checks to make sure the old entry is the same as
the one described in
.Fa old_pw
or the process is aborted.
If an entry is not found to match
.Fa pw ,
a new entry is appended to the passwd file only if the real user
ID is 0.
If an error occurs,
.Fn pw_copy
will display a message on
.Dv stderr
and call
.Fn pw_error .
.Pp
The
.Fn pw_copyx
function performs the same operation as
.Fn pw_copy
with the exception of error handling.
Upon an error,
.Fn pw_copyx
will write an error message into the buffer pointed to by
.Fa errbuf
which has the size
.Fa errbufsz .
.Pp
The
.Fn pw_scan
function accepts in
.Fa bp
a passwd entry as it would be represented in
.Pa /etc/master.passwd
and fills in
.Fa pw
with corresponding values; string fields in
.Fa pw
will be pointers into
.Fa bp .
Some characters in
.Fa bp
will be overwritten with 0s in order to terminate the strings pointed
to by
.Fa pw .
If
.Fa flags
is non-null, it should be cleared and the following options
enabled if required:
.Bl -tag -offset indent -width _PASSWORD_OLDFMT
.It Dv _PASSWORD_NOWARN
Don't print warnings.
.It Dv _PASSWORD_OLDFMT
Parse
.Fa bp
as an old format entry as found in
.Pa /etc/passwd .
.El
.Pp
Upon return it is cleared, and filled in with the following flags:
.Bl -tag -offset indent -width _PASSWORD_NOGID
.It Dv _PASSWORD_NOUID
The uid field of
.Fa bp
is empty.
.It Dv _PASSWORD_NOGID
The gid field of
.Fa bp
is empty.
.It Dv _PASSWORD_NOCHG
The change field of
.Fa bp
is empty.
.It Dv _PASSWORD_NOEXP
The expire field of
.Fa bp
is empty.
.El
.Pp
The
.Fn pw_error
function displays an error message, aborts the current passwd update,
and exits the current process.
If
.Fa err
is non-zero, a warning message beginning with
.Fa name
is printed for the current value of
.Va errno .
The process exits with status
.Fa eval .
.Sh RETURN VALUES
The
.Fn pw_copyx
function returns 1 if the new password entry was successfully written
to the destination file, and 0 otherwise.
.Pp
The
.Fn pw_scan
function prints a warning message and returns 0 if the string in the
.Fa bp
argument is not a valid passwd string.
Otherwise,
.Fn pw_scan
returns 1.
.Sh FILES
.Bl -tag -width /etc/master.passwd -compact
.It Pa /etc/master.passwd
.It Pa /etc/ptmp
.El
.Sh SEE ALSO
.Xr pw_lock 3 ,
.Xr passwd 5

139
lib/libutil/pw_lock.3 Normal file
View file

@ -0,0 +1,139 @@
.\" $NetBSD: pw_lock.3,v 1.14 2010/05/05 22:05:31 wiz Exp $
.\"
.\" Copyright (c) 1995
.\" The Regents of the University of California. All rights reserved.
.\"
.\" This code is derived from software developed by the Computer Systems
.\" Engineering group at Lawrence Berkeley Laboratory under DARPA contract
.\" BG 91-66 and contributed to Berkeley.
.\"
.\" 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 University 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 REGENTS 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 REGENTS 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.
.\"
.Dd February 17, 2007
.Dt PW_LOCK 3
.Os
.Sh NAME
.Nm pw_lock ,
.Nm pw_mkdb ,
.Nm pw_abort ,
.Nm pw_setprefix ,
.Nm pw_getprefix
.Nd passwd file update functions
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn pw_lock "int retries"
.Ft int
.Fn pw_mkdb "const char *username" "int secureonly"
.Ft void
.Fn pw_abort "void"
.Ft int
.Fn pw_setprefix "const char *new_prefix"
.Ft "const char *"
.Fn pw_getprefix "void"
.Sh DESCRIPTION
The
.Fn pw_lock ,
.Fn pw_mkdb ,
and
.Fn pw_abort
functions allow a program to update the system passwd database.
.Pp
The
.Fn pw_lock
function attempts to lock the passwd database by creating the file
.Pa /etc/ptmp ,
and returns the file descriptor of that file.
If
.Fa retries
is greater than zero,
.Fn pw_lock
will try multiple times to open
.Pa /etc/ptmp ,
waiting one second between tries.
In addition to being a lock file,
.Pa /etc/ptmp
will also hold the contents of the new passwd file.
.Pp
The
.Fn pw_mkdb
function updates the passwd file from the contents of
.Pa /etc/ptmp .
You should finish writing to and close the file descriptor returned by
.Fn pw_lock
before calling
.Fn pw_mkdb .
If
.Fn pw_mkdb
fails and you do not wish to retry, you should make sure to call
.Fn pw_abort
to clean up the lock file.
If the
.Ar username
argument is not
.Dv NULL ,
only database entries pertaining to the specified user
will be modified.
If the
.Ar secureonly
argument is non-zero, only the secure database will be updated.
.Pp
The
.Fn pw_abort
function aborts a passwd file update by deleting
.Pa /etc/ptmp .
The passwd database remains unchanged.
.Pp
The
.Fn pw_setprefix
function defines the root directory used for passwd file updates.
If the prefix is set to
.Pa /newroot
.Fn pw_lock
will operate on
.Pa /newroot/etc/ptmp
afterwards.
The default prefix is an empty string.
.Pp
The
.Fn pw_getprefix
function returns the root directory which is currently used for passwd file
updates.
.Sh RETURN VALUES
The
.Fn pw_lock
and
.Fn pw_mkdb
functions return -1 if they are unable to complete properly.
.Sh FILES
.Bl -tag -width /etc/master.passwd -compact
.It Pa /etc/master.passwd
.It Pa /etc/ptmp
.El
.Sh SEE ALSO
.Xr pw_init 3 ,
.Xr pwd_mkdb 8

View file

@ -0,0 +1,116 @@
.\" $NetBSD: raise_default_signal.3,v 1.2 2008/04/30 13:10:52 martin Exp $
.\"
.\" Copyright (c) 2007 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Luke Mewburn.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd September 25, 2007
.Dt RAISE_DEFAULT_SIGNAL 3
.Os
.Sh NAME
.Nm raise_default_signal
.Nd raise the default signal handler
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fo raise_default_signal
.Fa "int sig"
.Fc
.Sh DESCRIPTION
The
.Fn raise_default_signal
function raises the default signal handler for the signal
.Fa sig .
This function may be used by a user-defined signal handler router
to ensure that a parent process receives the correct notification
of a process termination by a signal.
This can be used to avoid a common programming mistake
when terminating a process from a custom
.Dv SIGINT
or
.Dv SIGQUIT
signal handler.
.Pp
The operations performed are:
.Bl -enum -offset indent
.It
Block all signals, using
.Xr sigprocmask 3 .
.It
Set the signal handler for signal
.Fa sig
to the default signal handler
.Dv ( SIG_DFL ) .
.It
.Xr raise 3
signal
.Fa sig .
.It
Unblock signal
.Fa sig
to deliver it.
.It
Restore the original signal mask and handler,
even if there was a failure.
.El
.Pp
See
.Xr signal 7
for a table of signals and default actions.
.Pp
The
.Fn raise_default_signal
function should be async-signal-safe.
.Sh RETURN VALUES
Upon successful completion, a value of 0 is returned.
Otherwise, a value of \-1 is returned and the global variable
.Va errno
is set to indicate the error.
.Sh ERRORS
The
.Fn raise_default_signal
function may fail and set
.Va errno
for any of the errors specified for the functions
.Xr sigemptyset 3 ,
.Xr sigfillset 3 ,
.Xr sigaddset 3 ,
.Xr sigprocmask 2 ,
.Xr sigaction 2 ,
or
.Xr raise 3 .
.Sh SEE ALSO
.Xr sigaction 2 ,
.Xr sigprocmask 2 ,
.Xr raise 3 ,
.Xr signal 7
.Sh HISTORY
The
.Fn raise_default_signal
function first appeared in
.Nx 5.0 .

View file

@ -0,0 +1,117 @@
/* $NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 2007 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Luke Mewburn.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#endif
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: raise_default_signal.c,v 1.3 2008/04/28 20:23:03 martin Exp $");
#endif
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <util.h>
#if ! HAVE_RAISE_DEFAULT_SIGNAL
/*
* raise_default_signal sig
* Raise the default signal handler for sig, by
* - block all signals
* - set the signal handler to SIG_DFL
* - raise the signal
* - unblock the signal to deliver it
*
* The original signal mask and signal handler is restored on exit
* (whether successful or not).
*
* Returns 0 on success, or -1 on failure with errno set to
* on of the values for sigemptyset(), sigaddset(), sigprocmask(),
* sigaction(), or raise().
*/
int
raise_default_signal(int sig)
{
struct sigaction origact, act;
sigset_t origmask, fullmask, mask;
int retval, oerrno;
retval = -1;
/* Setup data structures */
/* XXX memset(3) isn't async-safe according to signal(7) */
(void)memset(&act, 0, sizeof(act));
act.sa_handler = SIG_DFL;
act.sa_flags = 0;
if ((sigemptyset(&act.sa_mask) == -1) ||
(sigfillset(&fullmask) == -1) ||
(sigemptyset(&mask) == -1) ||
(sigaddset(&mask, sig) == -1))
goto restore_none;
/* Block all signals */
if (sigprocmask(SIG_BLOCK, &fullmask, &origmask) == -1)
goto restore_none;
/* (use 'goto restore_mask' to restore state) */
/* Enable the SIG_DFL handler */
if (sigaction(sig, &act, &origact) == -1)
goto restore_mask;
/* (use 'goto restore_act' to restore state) */
/* Raise the signal, and unblock the signal to deliver it */
if ((raise(sig) == -1) ||
(sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1))
goto restore_act;
/* Flag successful raise() */
retval = 0;
/* Restore the original handler */
restore_act:
oerrno = errno;
(void)sigaction(sig, &origact, NULL);
errno = oerrno;
/* Restore the original mask */
restore_mask:
oerrno = errno;
(void)sigprocmask(SIG_SETMASK, &origmask, NULL);
errno = oerrno;
restore_none:
return retval;
}
#endif /* ! HAVE_RAISE_DEFAULT_SIGNAL */

71
lib/libutil/secure_path.3 Normal file
View file

@ -0,0 +1,71 @@
.\" $NetBSD: secure_path.3,v 1.10 2010/05/04 06:41:27 jruoho Exp $
.\"
.\" Copyright (c) 1996,1997 Berkeley Software Design, Inc. 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. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by Berkeley Software Design,
.\" Inc.
.\" 4. The name of Berkeley Software Design, Inc. may not be used to endorse
.\" or promote products derived from this software without specific prior
.\" written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``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 BERKELEY SOFTWARE DESIGN, INC. 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.
.\"
.\" from BSDI: login_cap.3,v 1.4 1997/11/07 16:22:27 jch Exp
.\"
.Dd May 4, 2010
.Dt SECURE_PATH 3
.Os
.Sh NAME
.Nm secure_path
.Nd determine if a file appears to be ``secure''
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn secure_path "const char *path"
.Sh DESCRIPTION
The
.Fn secure_path
function takes a path name and returns zero if the referenced file is
.Dq secure ,
non-zero if not.
Any
.Dq insecurity ,
other than failure to access
the referenced file, will be logged to the system log.
.Pp
To be
.Dq secure ,
the referenced file must exist, be a regular file (and not a
directory), owned by the super-user, and writable only by the super-user.
.Sh SEE ALSO
.Xr openlog 3
.Sh HISTORY
The
.Fn secure_path
function is based on the
.Bsx
implementation of same, and appeared in
.Nx 1.5
by kind permission.

72
lib/libutil/secure_path.c Normal file
View file

@ -0,0 +1,72 @@
/* $NetBSD: secure_path.c,v 1.2 2003/01/06 20:30:30 wiz Exp $ */
/*-
* Copyright (c) 1995,1997 Berkeley Software Design, Inc. 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. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by Berkeley Software Design,
* Inc.
* 4. The name of Berkeley Software Design, Inc. may not be used to endorse
* or promote products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY BERKELEY SOFTWARE DESIGN, INC. ``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 BERKELEY SOFTWARE DESIGN, INC. 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.
*
* BSDI login_cap.c,v 2.13 1998/02/07 03:17:05 prb Exp
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: secure_path.c,v 1.2 2003/01/06 20:30:30 wiz Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <assert.h>
#include <syslog.h>
#include <util.h>
int
secure_path(const char *path)
{
struct stat sb;
_DIAGASSERT(path != NULL);
/*
* If not a regular file, or is owned/writable by someone
* other than root, quit.
*/
if (lstat(path, &sb) < 0)
/* syslog(LOG_ERR, "cannot stat %s: %m", path) */;
else if (!S_ISREG(sb.st_mode))
syslog(LOG_ERR, "%s: not a regular file", path);
else if (sb.st_uid != 0)
syslog(LOG_ERR, "%s: not owned by root", path);
else if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0)
syslog(LOG_ERR, "%s: writable by non-root", path);
else
return (0);
return (-1);
}

View file

@ -0,0 +1,5 @@
# $NetBSD: shlib_version,v 1.47 2009/05/13 02:50:32 pgoyette Exp $
# Remember to update distrib/sets/lists/base/shl.* when changing
#
major=7
minor=17

279
lib/libutil/snprintb.3 Normal file
View file

@ -0,0 +1,279 @@
.\" $NetBSD: snprintb.3,v 1.14 2009/05/13 02:50:32 pgoyette Exp $
.\"
.\" Copyright (c) 1998 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Jeremy Cooper.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 7, 2009
.Dt SNPRINTB 3
.Os
.Sh NAME
.Nm snprintb
.Nd bitmask output conversion
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn "snprintb" "char *buf" "size_t buflen" "const char *fmt" "uint64_t val"
.Ft int
.Fn "snprintb_m" "char *buf" "size_t buflen" "const char *fmt" "uint64_t val" \
"size_t max"
.Sh DESCRIPTION
The
.Fn snprintb
function formats a bitmask into a mnemonic form suitable for printing.
.Pp
This conversion is useful for decoding bit fields in device registers.
It formats the integer
.Fa val
into the buffer
.Fa buf ,
of size
.Fa buflen ,
using a specified radix and an interpretation of
the bits within that integer as though they were flags.
The buffer is always NUL-terminated.
If the buffer
.Fa buf
is too small to hold the formatted output,
.Fn snprintb
will fill as much as it can, and return the number of bytes
that would have written if the buffer was long enough excluding the
terminating NUL.
.Pp
The decoding directive string
.Fa fmt
describes how the bitfield is to be interpreted and displayed.
It follows two possible syntaxes, referred to as
.Dq old
and
.Dq new .
The main advantage of the
.Dq new
formatting is that it is capable of handling multi-bit fields.
.Pp
The first character of
.Fa fmt
may be
.Li \e177 ,
indicating that the remainder of the format string follows the
.Dq new
syntax.
The second character
.Pq the first for the old format
is a binary character representation of the
output numeral base in which the bitfield will be printed before it is decoded.
Recognized radix values
.Pq in C escape-character format
are
.Li \e10
.Pq octal ,
.Li \e12
.Pq decimal ,
and
.Li \e20
.Pq hexadecimal .
.Pp
The remaining characters in
.Fa fmt
are interpreted as a list of bit-position\(endescription pairs.
From here the syntaxes diverge.
.Pp
The
.Dq old
format syntax is series of bit-position\(endescription pairs.
Each begins with a binary character value that represents the position
of the bit being described.
A bit position value of one describes the least significant bit.
Whereas a position value of 32
.Pq octal 40, hexadecimal 20, the ASCII space character
describes the most significant bit.
.Pp
The remaining characters in a bit-position\(endescription pair are the
characters to print should the bit being described be set.
Description strings are delimited by the next bit position value character
encountered
.Pq distinguishable by its value being \*[Le] 32 ,
or the end of the decoding directive string itself.
.Pp
For the
.Dq new
format syntax, a bit-position\(endescription begins with a field type
followed by a binary bit-position and possibly a field length.
The least significant bit is bit-position zero, unlike the
.Dq old
syntax where it is one.
.Bl -tag -width "xxxxx"
.It Cm b\eB
Describes a bit position.
The bit-position
.Fa B
indicates the corresponding bit, as in the
.Dq old
format.
.It Cm f\eB\eL
Describes a multi-bit field beginning at bit-position
.Fa B
and having a bit-length of
.Fa L .
The remaining characters are printed as a description of the field
followed by
.Sq \&=
and the value of the field.
The value of the field is printed in the base specified as the second
character of the decoding directive string
.Ar fmt .
.It Cm F\eB\eL
Describes a multi-bit field like
.Sq f ,
but just extracts the value for use with the
.Sq \&=
and
.Sq \&:
formatting directives described below.
.It Cm \&=\eV
The field previously extracted by the last
.Sq f
or
.Sq F
operator is compared to the byte
.Sq Cm V
.Pq for values 0 through 255 .
If they are equal,
.Sq \&=
followed by the string following
.Sq Cm V
is printed.
This and the
.Sq \&:
operator may be repeated to annotate multiple possible values.
.It Cm :\eV
Operates like the
.Sq \&=
operator, but omits the leading
.Sq \&= .
.El
.Pp
Finally, each field is delimited by a NUL
.Pq Sq \e0
character.
By convention, the format string has an additional NUL character at
the end, following that delimiting the last bit-position\(endescription
pair.
.Pp
The
.Fn snprintb_m
function accepts an additional
.Fa max
argument.
If this argument is zero, the
.Fn snprintb_m
function returns exactly the same results in the
.Fa buf
as the
.Fn snprintb
function.
If the
.Fa max
argument is present and has a non-zero value, it represents the maximum
length of a formatted string.
If the formatted string would require more than
.Fa max
characters, the
.Fn snprintb_m
function returns multiple formatted strings in the output buffer
.Fa buf .
Each string is NUL-terminated, and the last string is followed by an
additional NUL character (or, if you prefer, a zero-length string).
.Sh RETURN VALUES
The
.Fn snprintb
and
.Fn snprintb_m
functions return the number of bytes that would have written to the buffer
if there was adequate space, excluding the final terminating NUL, or \-1 in
case an error occurred.
For
.Fn snprintb_m ,
the NUL characters terminating each individual string are included in the
total number of bytes.
.Sh EXAMPLES
Two examples of the old formatting style:
.Bd -literal -offset indent
snprintb(buf, buflen, "\e10\e2BITTWO\e1BITONE", 3)
\(rA "3\*[Lt]BITTWO,BITONE\*[Gt]"
snprintb(buf, buflen,
"\e20\ex10NOTBOOT\ex0fFPP\ex0eSDVMA\ex0cVIDEO"
"\ex0bLORES\ex0aFPA\ex09DIAG\ex07CACHE"
"\ex06IOCACHE\ex05LOOPBACK\ex04DBGCACHE",
0xe860)
\(rA "e860\*[Lt]NOTBOOT,FPP,SDVMA,VIDEO,CACHE,IOCACHE\*[Gt]"
.Ed
.Pp
An example of the new formatting style:
.Bd -literal -offset indent
snprintb(buf, buflen,
"\e177\e020b\e0LSB\e0b\e1_BITONE\e0f\e4\e4NIBBLE2\e0"
"f\ex10\e4BURST\e0=\e4FOUR\e0=\exfSIXTEEN\e0"
"b\ex1fMSB\e0\e0",
0x800f0701)
\(rA "800f0701\*[Lt]LSB,NIBBLE2=0,BURST=f=SIXTEEN,MSB\*[Gt]"
.Ed
.Sh ERRORS
.Fn snprintb
will fail if:
.Bl -tag -width Er
.It Bq Er EINVAL
The leading character does not describe a supported format,
or
.Fn snprintf
failed.
.El
.Sh SEE ALSO
.Xr printf 3 ,
.Xr snprintf 3
.Sh HISTORY
The
.Fn snprintb
function was originally implemented as a non-standard
.Li %b
format string for the kernel
.Fn printf
function in
.Nx 1.5
and earlier releases.
It was called
.Fn bitmask_snprintf
in
.Nx 5.0
and earlier releases.
.Sh AUTHORS
The
.Dq new
format was the invention of
.An Chris Torek .

View file

@ -0,0 +1,236 @@
.\" $NetBSD: sockaddr_snprintf.3,v 1.7 2009/04/11 16:13:49 joerg Exp $
.\"
.\" Copyright (c) 2004 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Christos Zoulas.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd April 9, 2005
.Dt SOCKADDR_SNPRINTF 3
.Os
.Sh NAME
.Nm sockaddr_snprintf
.Nd formatting function for socket address structures
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn sockaddr_snprintf "char *buf" "size_t buflen" "const char *fmt" "const struct sockaddr *sa"
.Sh DESCRIPTION
The
.Fn sockaddr_snprintf
function formats a socket address into a form suitable for printing.
.Pp
This function is convenient because it is protocol independent, i.e. one does
not need to know the address family of the sockaddr in order to print it.
The
.Xr printf 3
like format string specifies how the address is going to be printed.
Some formatting characters are only supported by some address families.
If a certain formatting character is not supported, then the string
.Dq N/A
is printed.
.Pp
The resulting formatted string is placed into
.Fa buf .
Up to
.Fa buflen
characters are placed in
.Fa buf .
.Pp
The following formatting characters are supported (immediately
after a percent
.Pq Sq %
sign):
.Bl -tag -width %a
.It a
The node address portion of the socket address is printed numerically.
For
.Dv AF_INET
the address is printed as:
.Dq A.B.C.D
and
for AF_INET6
the address is printed as:
.Dq A:B...[%if]
using
.Xr getnameinfo 3
internally with
.Dv NI_NUMERICHOST .
For
.Dv AF_APPLETALK
the address is printed as:
.Dq A.B
For
.Dv AF_LOCAL
.Pq Dv AF_UNIX
the address is printed as:
.Dq socket-path
For
.Dv AF_LINK
the address is printed as:
.Dq a.b.c.d.e.f
using
.Xr link_ntoa 3 ,
but the interface portion is skipped (see below).
For
.Dv AF_UNSPEC
nothing is printed.
.It A
The symbolic name of the address is printed.
For
.Dv AF_INET
and
.Dv AF_INET6
this is the hostname associated with the address.
For all other address families, it is the same as the
.Dq a
format.
.It f
The numeric value of the family of the address is printed.
.It l
The length of the socket address is printed.
.It p
For
.Dv AF_INET ,
.Dv AF_INET6 ,
and
.Dv AF_APPLETALK
the numeric value of the port portion of the address is printed.
.It P
For
.Dv AF_INET
and
.Dv AF_INET6
this is the name of the service associated with the port number, if
available.
For all other address families, it is the same as the
.Dq p
format.
.It I
For
.Dv AF_LINK
addresses, the interface name portion is printed.
.It F
For
.Dv AF_INET6
addresses, the flowinfo portion of the address is printed numerically.
.It R
For
.Dv AF_APPLETALK
addresses, the netrange portion of the address is printed as:
.Dq phase:[firstnet,lastnet]
.It S
For
.Dv AF_INET6
addresses, the scope portion of the address is printed numerically.
.It ?
If present between
.Dq %
and the format character, and the selected format does not apply to
the given address family, the
.Dq N/A
string is elided and no output results.
.El
.Sh RETURN VALUES
The
.Fn sockaddr_snprintf
function returns the number of characters that are required to format the
value
.Fa val
given the format string
.Fa fmt
excluding the terminating NUL.
The returned string in
.Fa buf
is always NUL-terminated.
If the address family is not supported,
.Fn sockaddr_snprintf
returns \-1 and sets
.Va errno
to
.Dv EAFNOSUPPORT .
For
.Dv AF_INET
and
.Dv AF_INET6
addresses
.Fn sockaddr_snprintf
returns \-1 if the
.Xr getnameinfo 3
conversion failed, and
.Fa errno
is set to the error value from
.Xr getnameinfo 3 .
.Sh ERRORS
If the buffer
.Fa buf
is too small to hold the formatted output,
.Fn sockaddr_snprintf
will still return the buffer, containing a truncated string.
.Sh SEE ALSO
.Xr getaddrinfo 3 ,
.Xr getnameinfo 3 ,
.Xr link_ntoa 3 ,
.Xr snprintf 3
.Sh HISTORY
The
.Fn sockaddr_snprintf
first appeared in
.Nx 3.0 .
.Sh BUGS
The
.Fn sockaddr_snprintf
interface is experimental and might change in the future.
.Pp
There is no way to specify different formatting styles for particular
addresses.
For example it would be useful to print
.Dv AF_LINK
addresses as
.Dq %.2x:%.2x...
instead of
.Dq %x.%x...
.Pp
This function is supposed to be quick, but
.Xr getnameinfo 3
might use system calls to convert the scope number to an interface
name and the
.Dq A
and
.Dq P
format characters call
.Xr getaddrinfo 3
which may block for a noticeable period of time.
.Pp
Not all formatting characters are supported by all address families and
printing
.Dq N/A
is not very convenient.
The
.Dq \&?
character can suppress this, but other formatting (e.g., spacing or
punctuation) will remain.

View file

@ -0,0 +1,229 @@
/* $NetBSD: sockaddr_snprintf.c,v 1.9 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 2004 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: sockaddr_snprintf.c,v 1.9 2008/04/28 20:23:03 martin Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netatalk/at.h>
#include <net/if_dl.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <util.h>
#include <netdb.h>
int
sockaddr_snprintf(char * const sbuf, const size_t len, const char * const fmt,
const struct sockaddr * const sa)
{
const void *a = NULL;
char abuf[1024], nbuf[1024], *addr = NULL, *w = NULL;
char Abuf[1024], pbuf[32], *name = NULL, *port = NULL;
char *ebuf = &sbuf[len - 1], *buf = sbuf;
const char *ptr, *s;
int p = -1;
const struct sockaddr_at *sat = NULL;
const struct sockaddr_in *sin4 = NULL;
const struct sockaddr_in6 *sin6 = NULL;
const struct sockaddr_un *sun = NULL;
const struct sockaddr_dl *sdl = NULL;
int na = 1;
#define ADDC(c) do { if (buf < ebuf) *buf++ = c; else buf++; } \
while (/*CONSTCOND*/0)
#define ADDS(p) do { for (s = p; *s; s++) ADDC(*s); } \
while (/*CONSTCOND*/0)
#define ADDNA() do { if (na) ADDS("N/A"); } \
while (/*CONSTCOND*/0)
switch (sa->sa_family) {
case AF_UNSPEC:
goto done;
case AF_APPLETALK:
sat = ((const struct sockaddr_at *)(const void *)sa);
p = ntohs(sat->sat_port);
(void)snprintf(addr = abuf, sizeof(abuf), "%u.%u",
ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
(void)snprintf(port = pbuf, sizeof(pbuf), "%d", p);
break;
case AF_LOCAL:
sun = ((const struct sockaddr_un *)(const void *)sa);
(void)strlcpy(addr = abuf, sun->sun_path, SUN_LEN(sun));
break;
case AF_INET:
sin4 = ((const struct sockaddr_in *)(const void *)sa);
p = ntohs(sin4->sin_port);
a = &sin4->sin_addr;
break;
case AF_INET6:
sin6 = ((const struct sockaddr_in6 *)(const void *)sa);
p = ntohs(sin6->sin6_port);
a = &sin6->sin6_addr;
break;
case AF_LINK:
sdl = ((const struct sockaddr_dl *)(const void *)sa);
(void)strlcpy(addr = abuf, link_ntoa(sdl), sizeof(abuf));
if ((w = strchr(addr, ':')) != 0) {
*w++ = '\0';
addr = w;
}
break;
default:
errno = EAFNOSUPPORT;
return -1;
}
if (addr == abuf)
name = addr;
if (a && getnameinfo(sa, (socklen_t)sa->sa_len, addr = abuf,
(unsigned int)sizeof(abuf), NULL, 0,
NI_NUMERICHOST|NI_NUMERICSERV) != 0)
return -1;
for (ptr = fmt; *ptr; ptr++) {
if (*ptr != '%') {
ADDC(*ptr);
continue;
}
next_char:
switch (*++ptr) {
case '?':
na = 0;
goto next_char;
case 'a':
ADDS(addr);
break;
case 'p':
if (p != -1) {
(void)snprintf(nbuf, sizeof(nbuf), "%d", p);
ADDS(nbuf);
} else
ADDNA();
break;
case 'f':
(void)snprintf(nbuf, sizeof(nbuf), "%d", sa->sa_family);
ADDS(nbuf);
break;
case 'l':
(void)snprintf(nbuf, sizeof(nbuf), "%d", sa->sa_len);
ADDS(nbuf);
break;
case 'A':
if (name)
ADDS(name);
else if (!a)
ADDNA();
else {
getnameinfo(sa, (socklen_t)sa->sa_len,
name = Abuf,
(unsigned int)sizeof(nbuf), NULL, 0, 0);
ADDS(name);
}
break;
case 'P':
if (port)
ADDS(port);
else if (p == -1)
ADDNA();
else {
getnameinfo(sa, (socklen_t)sa->sa_len, NULL, 0,
port = pbuf,
(unsigned int)sizeof(pbuf), 0);
ADDS(port);
}
break;
case 'I':
if (sdl && addr != abuf) {
ADDS(abuf);
} else {
ADDNA();
}
break;
case 'F':
if (sin6) {
(void)snprintf(nbuf, sizeof(nbuf), "%d",
sin6->sin6_flowinfo);
ADDS(nbuf);
break;
} else {
ADDNA();
}
break;
case 'S':
if (sin6) {
(void)snprintf(nbuf, sizeof(nbuf), "%d",
sin6->sin6_scope_id);
ADDS(nbuf);
break;
} else {
ADDNA();
}
break;
case 'R':
if (sat) {
const struct netrange *n =
&sat->sat_range.r_netrange;
(void)snprintf(nbuf, sizeof(nbuf),
"%d:[%d,%d]", n->nr_phase , n->nr_firstnet,
n->nr_lastnet);
ADDS(nbuf);
} else {
ADDNA();
}
break;
default:
ADDC('%');
if (na == 0)
ADDC('?');
if (*ptr == '\0')
goto done;
/*FALLTHROUGH*/
case '%':
ADDC(*ptr);
break;
}
na = 1;
}
done:
if (buf < ebuf)
*buf = '\0';
else if (len != 0)
sbuf[len - 1] = '\0';
return (int)(buf - sbuf);
}

125
lib/libutil/stat_flags.3 Normal file
View file

@ -0,0 +1,125 @@
.\" $NetBSD: stat_flags.3,v 1.6 2010/05/04 06:53:35 jruoho Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Christos Zoulas.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 4, 2010
.Dt STAT_FLAGS 3
.Os
.Sh NAME
.Nm string_to_flags ,
.Nm flags_to_string
.Nd Stat flags parsing and printing functions
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft char *
.Fn flags_to_string "u_long flags" "const char *def"
.Ft int
.Fn string_to_flags "char **stringp" "u_long *setp" "u_long clrp"
.Sh DESCRIPTION
The
.Fn flags_to_string
and
.Fn string_to_flags
functions are used by
programs such as
.Xr ls 1 ,
.Xr mtree 8 ,
.Xr makefs 8 ,
etc., to parse and/or print the
.Dv st_flags field in the
.Xr stat 2
structure.
.Pp
They recognize the following flags:
.Bl -column -offset indent "uappnd " "SF_IMMUTABLE" "xxx"
.It Sy String Ta Sy Flag Ta Sy Description
.It Va arch Ta Dv SF_ARCHIVED Ta file is archived
.It Va nodump Ta Dv UF_NODUMP Ta do not dump file
.It Va opaque Ta Dv UF_OPAQUE Ta directory is opaque in union filesystems
.It Va sappnd Ta Dv SF_APPEND Ta writes to the file may only append
.It Va schg Ta Dv SF_IMMUTABLE Ta file cannot be changed; it is immutable
.It Va snap Ta Dv SF_SNAPSHOT Ta file is a snapshot inode
.It Va uappnd Ta Dv UF_APPEND Ta writes to the file may only append
.It Va uchg Ta Dv UF_IMMUTABLE Ta file cannot be changed; it is immutable
.El
.Pp
The
.Dv SF_APPEND
and
.Dv SF_IMMUTABLE
flags are for the superuser only, whereas
.Dv UF_APPEND
and
.Dv UF_IMMUTABLE
are for the user only.
.Pp
The
.Fn flags_to_string
function converts the bits set in the
.Fa flags
argument to a comma-separated string and returns it.
If no flags are set, then the
.Fa def
string is returned.
The returned string is allocated via
.Xr malloc 3
and it is the responsibility of the caller to
.Xr free 3
it.
.Pp
The
.Fn string_to_flags
function takes a
.Fa stringp
of space, comma, or tab separated flag names
and places their bit value on the
.Fa setp
argument.
If the flag name is prefixed by:
.Dq no ,
then the bit value is placed on the
.Fa clrp
argument.
.Sh RETURN VALUES
.Fn flags_to_string
returns the symbolic representation of flags, the default string, or
.Dv NULL
if allocation failed.
.Pp
.Fn string_to_flags
returns
.Dv 0
on success and
.Dv 1
if it fails to parse the string, setting
.Fa stringp
to point to the first string that it failed to parse.
.Sh SEE ALSO
.Xr stat 2

186
lib/libutil/stat_flags.c Normal file
View file

@ -0,0 +1,186 @@
/* $NetBSD: stat_flags.c,v 1.2 2007/01/16 17:34:02 cbiere Exp $ */
/*-
* Copyright (c) 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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.
*/
#if HAVE_NBTOOL_CONFIG_H
#include "nbtool_config.h"
#else
#define HAVE_STRUCT_STAT_ST_FLAGS 1
#endif
#include <sys/cdefs.h>
#if !defined(lint)
#if 0
static char sccsid[] = "@(#)stat_flags.c 8.2 (Berkeley) 7/28/94";
#else
__RCSID("$NetBSD: stat_flags.c,v 1.2 2007/01/16 17:34:02 cbiere Exp $");
#endif
#endif /* not lint */
#include <sys/types.h>
#include <sys/stat.h>
#include <fts.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include "util.h"
#define SAPPEND(s) do { \
if (prefix != NULL) \
(void)strlcat(string, prefix, sizeof(string)); \
(void)strlcat(string, s, sizeof(string)); \
prefix = ","; \
} while (/* CONSTCOND */ 0)
/*
* flags_to_string --
* Convert stat flags to a comma-separated string. If no flags
* are set, return the default string.
*/
char *
flags_to_string(u_long flags, const char *def)
{
char string[128];
const char *prefix;
string[0] = '\0';
prefix = NULL;
#if HAVE_STRUCT_STAT_ST_FLAGS
if (flags & UF_APPEND)
SAPPEND("uappnd");
if (flags & UF_IMMUTABLE)
SAPPEND("uchg");
if (flags & UF_NODUMP)
SAPPEND("nodump");
if (flags & UF_OPAQUE)
SAPPEND("opaque");
if (flags & SF_APPEND)
SAPPEND("sappnd");
if (flags & SF_ARCHIVED)
SAPPEND("arch");
if (flags & SF_IMMUTABLE)
SAPPEND("schg");
#ifdef SF_SNAPSHOT
if (flags & SF_SNAPSHOT)
SAPPEND("snap");
#endif
#endif
if (prefix != NULL)
return strdup(string);
return strdup(def);
}
#define TEST(a, b, f) { \
if (!strcmp(a, b)) { \
if (clear) { \
if (clrp) \
*clrp |= (f); \
if (setp) \
*setp &= ~(f); \
} else { \
if (setp) \
*setp |= (f); \
if (clrp) \
*clrp &= ~(f); \
} \
break; \
} \
}
/*
* string_to_flags --
* Take string of arguments and return stat flags. Return 0 on
* success, 1 on failure. On failure, stringp is set to point
* to the offending token.
*/
int
string_to_flags(char **stringp, u_long *setp, u_long *clrp)
{
int clear;
char *string, *p;
if (setp)
*setp = 0;
if (clrp)
*clrp = 0;
#if HAVE_STRUCT_STAT_ST_FLAGS
string = *stringp;
while ((p = strsep(&string, "\t ,")) != NULL) {
clear = 0;
*stringp = p;
if (*p == '\0')
continue;
if (p[0] == 'n' && p[1] == 'o') {
clear = 1;
p += 2;
}
switch (p[0]) {
case 'a':
TEST(p, "arch", SF_ARCHIVED);
TEST(p, "archived", SF_ARCHIVED);
return (1);
case 'd':
clear = !clear;
TEST(p, "dump", UF_NODUMP);
return (1);
case 'n':
/*
* Support `nonodump'. Note that
* the state of clear is not changed.
*/
TEST(p, "nodump", UF_NODUMP);
return (1);
case 'o':
TEST(p, "opaque", UF_OPAQUE);
return (1);
case 's':
TEST(p, "sappnd", SF_APPEND);
TEST(p, "sappend", SF_APPEND);
TEST(p, "schg", SF_IMMUTABLE);
TEST(p, "schange", SF_IMMUTABLE);
TEST(p, "simmutable", SF_IMMUTABLE);
return (1);
case 'u':
TEST(p, "uappnd", UF_APPEND);
TEST(p, "uappend", UF_APPEND);
TEST(p, "uchg", UF_IMMUTABLE);
TEST(p, "uchange", UF_IMMUTABLE);
TEST(p, "uimmutable", UF_IMMUTABLE);
return (1);
default:
return (1);
}
}
#endif
return (0);
}

108
lib/libutil/ttyaction.3 Normal file
View file

@ -0,0 +1,108 @@
.\" $NetBSD: ttyaction.3,v 1.15 2010/05/04 06:41:27 jruoho Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\"
.\" This code is derived from software contributed to The NetBSD Foundation
.\" by Gordon W. Ross.
.\"
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd May 4, 2010
.Dt TTYACTION 3
.Os
.Sh NAME
.Nm ttyaction
.Nd ttyaction utility function
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft int
.Fn ttyaction "char *ttyname" "char *action" "char *username"
.Sh DESCRIPTION
The
.Fn ttyaction
function is used by
.Xr login 1 ,
.Xr getty 8 ,
.Xr telnetd 8
and
.Xr rlogind 8
to execute site-specific commands
when a login session begins and ends.
.Pp
The
.Fn ttyaction
function scans the
.Pa /etc/ttyaction
file for any records that match the current
.Fa ttyname
and
.Fa action
parameters, and for each matching record,
runs the shell command shown in that record.
The record format is described in
.Xr ttyaction 5 .
The parameter
.Fa username
is the name of the new owner of the
.Fa ttyname
device.
Note that the
.Fa ttyname
parameter may be passed as a fully qualified pathname, and the
.Fn ttyaction
function will skip the leading "/dev/" part of the string.
(This is a convenience for login and getty.)
.Sh RETURN VALUES
.Fn ttyaction
returns the status of the last command it executed,
or zero if no matching commands were found.
.Sh FILES
.Bl -tag -width /etc/ttyaction -compact
.It Pa /dev/\(**
.It Pa /etc/ttyaction
.El
.Sh SEE ALSO
.Xr ttyaction 5
.Sh AUTHORS
.An Gordon W. Ross
.Aq gwr@NetBSD.org ,
.An Chris G. Demetriou
.Aq cgd@NetBSD.org ,
.An Ty Sarna
.Aq tsarna@NetBSD.org .
.Sh BUGS
There should be some
.Em other
mechanism to allow selection of different access control policies
on a per-line basis.
It has been suggested that the same
.Fn ttyaction
mechanism should also be used for determining access control, but
it was decided (after much discussion) that
.Fn ttyaction
should only describe actions to be performed
.Em after
the system has decided to change the ownership of some tty.
Access control policies will be handled by a separate mechanism.

160
lib/libutil/ttyaction.c Normal file
View file

@ -0,0 +1,160 @@
/* $NetBSD: ttyaction.c,v 1.19 2008/04/28 20:23:03 martin Exp $ */
/*-
* Copyright (c) 1996 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Gordon W. Ross.
*
* 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* For each matching "tty" and "action" run the "command."
* See fnmatch() for matching the tty name.
*/
#include <sys/cdefs.h>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: ttyaction.c,v 1.19 2008/04/28 20:23:03 martin Exp $");
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "util.h"
#ifndef _PATH_TTYACTION
#define _PATH_TTYACTION "/etc/ttyaction"
#endif
static const char *actfile = _PATH_TTYACTION;
static const char *pathenv = "PATH=" _PATH_STDPATH;
int
ttyaction(const char *tty, const char *act, const char *user)
{
FILE *fp;
char *p1, *p2;
const char *argv[4];
const char *envp[8];
char *lastp;
char line[1024];
char env_tty[64];
char env_act[64];
char env_user[256];
int error, linenum, status;
pid_t pid;
_DIAGASSERT(tty != NULL);
_DIAGASSERT(act != NULL);
_DIAGASSERT(user != NULL);
fp = fopen(actfile, "r");
if (fp == NULL)
return 0;
/* Skip the "/dev/" part of the first arg. */
if (!strncmp(tty, "/dev/", (size_t)5))
tty += 5;
/* Args will be: "sh -c ..." */
argv[0] = _PATH_BSHELL;
argv[1] = "-c";
argv[2] = NULL; /* see below */
argv[3] = NULL;
/*
* Environment needs: TTY, ACT, USER
*/
snprintf(env_tty, sizeof(env_tty), "TTY=%s", tty);
snprintf(env_act, sizeof(env_act), "ACT=%s", act);
snprintf(env_user, sizeof(env_user), "USER=%s", user);
envp[0] = pathenv;
envp[1] = env_tty;
envp[2] = env_act;
envp[3] = env_user;
envp[4] = NULL;
linenum = 0;
status = 0;
while (fgets(line, (int)sizeof(line), fp)) {
linenum++;
/* Allow comment lines. */
if (line[0] == '#')
continue;
p1 = strtok_r(line, " \t", &lastp);
p2 = strtok_r(NULL, " \t", &lastp);
/* This arg goes to end of line. */
argv[2] = strtok_r(NULL, "\n", &lastp);
if (!p1 || !p2 || !argv[2]) {
warnx("%s: line %d format error", actfile, linenum);
continue;
}
if (fnmatch(p1, tty, 0) || fnmatch(p2, act, 0))
continue;
/* OK, this is a match. Run the command. */
pid = fork();
if (pid == -1) {
warnx("fork failed: %s", strerror(errno));
continue;
}
if (pid == 0) {
/* This is the child. */
error = execve(argv[0],
(char *const *)__UNCONST(argv),
(char *const *)__UNCONST(envp));
/* If we get here, it is an error. */
warnx("%s: line %d: exec failed: %s",
actfile, linenum, strerror(errno));
_exit(1);
}
/* This is the parent. */
error = waitpid(pid, &status, 0);
if (error == -1) {
warnx("%s: line %d: wait failed: %s",
actfile, linenum, strerror(errno));
continue;
}
if (WTERMSIG(status)) {
warnx("%s: line %d: child died with signal %d",
actfile, linenum, WTERMSIG(status));
continue;
}
}
fclose(fp);
return status;
}

60
lib/libutil/ttymsg.3 Normal file
View file

@ -0,0 +1,60 @@
.\" $NetBSD: ttymsg.3,v 1.11 2008/04/30 13:10:52 martin Exp $
.\"
.\" Copyright (c) 1996 The NetBSD Foundation, Inc.
.\" 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
.Dd June 29, 1997
.Dt TTYMSG 3
.Os
.Sh NAME
.Nm ttymsg
.Nd ttymsg utility function
.Sh LIBRARY
.Lb libutil
.Sh SYNOPSIS
.In util.h
.Ft char *
.Fn ttymsg "struct iovec *iov" "int iovlen" "const char *tty" "int tmout"
.Sh DESCRIPTION
The
.Fn ttymsg
function is used by
programs such as
.Xr talkd 8 ,
.Xr syslogd 8 ,
.Xr wall 1 ,
etc., to display the contents of a uio structure on a terminal.
.Fn ttymsg
forks and finishes in the child if the write would block after
waiting up to
.Fa tmout
seconds.
.Sh RETURN VALUES
.Fn ttymsg
returns a pointer to an error string on unexpected
error; the string is not newline-terminated.
Various "normal" errors are
ignored (exclusive-use, lack of permission, etc.).
.Sh SEE ALSO
.Xr writev 2

208
lib/libutil/ttymsg.c Normal file
View file

@ -0,0 +1,208 @@
/* $NetBSD: ttymsg.c,v 1.23 2009/01/18 12:13:04 lukem Exp $ */
/*
* Copyright (c) 1989, 1993
* The Regents of the University of California. 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 University 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 REGENTS 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 REGENTS 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>
#if defined(LIBC_SCCS) && !defined(lint)
#if 0
static char sccsid[] = "@(#)ttymsg.c 8.2 (Berkeley) 11/16/93";
#else
__RCSID("$NetBSD: ttymsg.c,v 1.23 2009/01/18 12:13:04 lukem Exp $");
#endif
#endif /* LIBC_SCCS and not lint */
#include <sys/types.h>
#include <sys/uio.h>
#include <assert.h>
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
#include <paths.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <util.h>
/*
* Display the contents of a uio structure on a terminal. Used by wall(1),
* syslogd(8), and talkd(8). Forks and finishes in child if write would block,
* waiting up to tmout seconds. Returns pointer to error string on unexpected
* error; string is not newline-terminated. Various "normal" errors are
* ignored (exclusive-use, lack of permission, etc.).
*/
char *
ttymsg(struct iovec *iov, int iovcnt, const char *line, int tmout)
{
static char errbuf[1024];
char device[MAXNAMLEN];
const char *ptr;
int fd, ret;
struct iovec localiov[32];
sigset_t nset;
int forked = 0;
size_t cnt, left, wret;
_DIAGASSERT(iov != NULL);
_DIAGASSERT(iovcnt >= 0);
_DIAGASSERT(line != NULL);
if (iovcnt < 0) {
(void)snprintf(errbuf, sizeof(errbuf),
"%s: negative iovcnt", __func__);
return errbuf;
}
if ((size_t)iovcnt >= sizeof(localiov) / sizeof(localiov[0])) {
(void)snprintf(errbuf, sizeof(errbuf),
"%s: too many iov's (%d) max is %zu", __func__,
iovcnt, sizeof(localiov) / sizeof(localiov[0]));
return errbuf;
}
ptr = strncmp(line, "pts/", (size_t)4) == 0 ? line + 4 : line;
if (strcspn(ptr, "./") != strlen(ptr)) {
/* A slash or dot is an attempt to break security... */
(void)snprintf(errbuf, sizeof(errbuf),
"%s: '/' or '.' in \"%s\"", __func__, line);
return errbuf;
}
ret = snprintf(device, sizeof(device), "%s%s", _PATH_DEV, line);
if (ret == -1 || ret >= (int)sizeof(device)) {
(void) snprintf(errbuf, sizeof(errbuf),
"%s: line `%s' too long", __func__, line);
return errbuf;
}
cnt = (size_t)ret;
/*
* open will fail on slip lines or exclusive-use lines
* if not running as root; not an error.
*/
if ((fd = open(device, O_WRONLY|O_NONBLOCK, 0)) < 0) {
if (errno == EBUSY || errno == EACCES)
return NULL;
(void)snprintf(errbuf, sizeof(errbuf),
"%s: Cannot open `%s' (%s)",
__func__, device, strerror(errno));
return errbuf;
}
if (!isatty(fd)) {
(void)snprintf(errbuf, sizeof(errbuf),
"%s: line `%s' is not a tty device", __func__, device);
(void)close(fd);
return errbuf;
}
for (cnt = left = 0; cnt < (size_t)iovcnt; ++cnt)
left += iov[cnt].iov_len;
for (;;) {
wret = writev(fd, iov, iovcnt);
if (wret >= left)
break;
if (wret > 0) {
left -= wret;
if (iov != localiov) {
(void)memcpy(localiov, iov,
iovcnt * sizeof(struct iovec));
iov = localiov;
}
for (cnt = 0; wret >= iov->iov_len; ++cnt) {
wret -= iov->iov_len;
++iov;
--iovcnt;
}
if (wret) {
iov->iov_base =
(char *)iov->iov_base + wret;
iov->iov_len -= wret;
}
continue;
} else if (wret == 0) {
(void)snprintf(errbuf, sizeof(errbuf),
"%s: failed writing %zu bytes to `%s'", __func__,
left, device);
(void) close(fd);
if (forked)
_exit(1);
return errbuf;
}
if (errno == EWOULDBLOCK) {
pid_t cpid;
if (forked) {
(void)close(fd);
_exit(1);
}
cpid = fork();
if (cpid < 0) {
(void)snprintf(errbuf, sizeof(errbuf),
"%s: Cannot fork (%s)", __func__,
strerror(errno));
(void)close(fd);
return errbuf;
}
if (cpid) { /* parent */
(void)close(fd);
return NULL;
}
forked++;
/* wait at most tmout seconds */
(void)signal(SIGALRM, SIG_DFL);
(void)signal(SIGTERM, SIG_DFL); /* XXX */
sigfillset(&nset);
(void)sigprocmask(SIG_UNBLOCK, &nset, NULL);
(void)alarm((u_int)tmout);
(void)fcntl(fd, F_SETFL, 0); /* clear O_NONBLOCK */
continue;
}
/*
* We get ENODEV on a slip line if we're running as root,
* and EIO if the line just went away.
*/
if (errno == ENODEV || errno == EIO)
break;
(void) close(fd);
if (forked)
_exit(1);
(void)snprintf(errbuf, sizeof(errbuf),
"%s: Write to line `%s' failed (%s)", __func__,
device, strerror(errno));
return errbuf;
}
(void) close(fd);
if (forked)
_exit(0);
return NULL;
}

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