]> git.saurik.com Git - apple/shell_cmds.git/commitdiff
shell_cmds-149.tar.gz mac-os-x-106 mac-os-x-1061 mac-os-x-1062 mac-os-x-1063 mac-os-x-1064 mac-os-x-1065 mac-os-x-1066 mac-os-x-1067 mac-os-x-1068 v149
authorApple <opensource@apple.com>
Thu, 19 Mar 2009 21:56:53 +0000 (21:56 +0000)
committerApple <opensource@apple.com>
Thu, 19 Mar 2009 21:56:53 +0000 (21:56 +0000)
53 files changed:
Makefile
alias/generic.sh
date/date.1
find/Makefile
find/extern.h
find/find.1
find/find.c
find/find.h
find/function.c
find/ls.c
find/main.c
find/option.c
hostname/Makefile
hostname/hostname.1
hostname/hostname.c
id/id.c
jot/Makefile
jot/jot.1
jot/jot.c
killall/killall.c
lastcomm/lastcomm.c
locate/locate/Makefile
locate/locate/com.apple.locate.plist [new file with mode: 0644]
locate/locate/fastfind.c
locate/locate/locate.1
locate/locate/locate.c
locate/locate/locate.updatedb.8
locate/locate/updatedb.sh
mktemp/mktemp.1
mktemp/mktemp.c
nohup/nohup.1
nohup/nohup.c
path_helper/Makefile [new file with mode: 0644]
path_helper/path_helper.8 [new file with mode: 0644]
path_helper/path_helper.c [new file with mode: 0644]
printf/printf.1
printf/printf.c
sleep/Makefile
sleep/sleep.1
sleep/sleep.c
su/Makefile
su/su.1
su/su.c
su/su.pam [new file with mode: 0644]
uname/uname.c
w/w.1
who/Makefile
who/utmpentry.c [new file with mode: 0644]
who/utmpentry.h [new file with mode: 0644]
who/who.1
who/who.c
xargs/xargs.1
xargs/xargs.c

index 1b52900d572de4aa7fe9f7504443419c6236fbe4..0afb832051b6514c1d1fe859c0be4344d213095f 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -4,7 +4,7 @@ Embedded=$(shell tconf --test TARGET_OS_EMBEDDED)
 
 SubProjects = alias apply basename chroot date dirname echo env expr false \
         find getopt hostname id jot kill killall lastcomm locate logname mktemp \
-        nice nohup printenv printf pwd renice script shlock sleep \
+        nice nohup path_helper printenv printf pwd renice script shlock sleep \
         tee test time true uname users w whereis which who xargs yes
 
 ifeq ($(Embedded),NO)
index b47956d099863dcb53f102ef425ae43e17f177d7..5948cc944c1c475d5451eb5ffd5a1ea2419cb0d1 100644 (file)
@@ -1,4 +1,4 @@
 #!/bin/sh
 # $FreeBSD: src/usr.bin/alias/generic.sh,v 1.2 2005/10/24 22:32:19 cperciva Exp $
 # This file is in the public domain.
-builtin ${0##*/} ${1+"$@"}
+builtin `echo ${0##*/} | tr \[:upper:] \[:lower:]` ${1+"$@"}
index e176c35a478d899c7f208be7c1cb7093b7817194..d5f2d65f248467e654ebc6c17a85722ce0d393d2 100644 (file)
@@ -363,13 +363,10 @@ The command:
 sets the date to
 .Dq Li "June 13, 1985, 4:27 PM" .
 .Pp
-.Dl "date ""+%Y%m%d%H%M.%S"""
+.Dl "date ""+%m%d%H%M%Y.%S"""
 .Pp
 may be used on one machine to print out the date
 suitable for setting on another.
-.Qq ( Li "+%m%d%H%M%Y.%S"
-for use on
-.Tn Linux . )
 .Pp
 The command:
 .Pp
@@ -422,6 +419,9 @@ Unable to set the date
 .It 2
 Able to set the local date, but unable to set it globally
 .El
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
 .Sh SEE ALSO
 .Xr gettimeofday 2 ,
 .Xr strftime 3 ,
index 6d3babeef12ec4aa0f53aa0587db0d85c7ca3ca9..8555945a76bf298b22c81a7079d3b19d2cabcf1e 100644 (file)
@@ -6,7 +6,7 @@ CFILES = find.c function.c ls.c main.c misc.c operator.c option.c
 YFILES = getdate.y
 MANPAGES = find.1
 
-Extra_CC_Flags = -Wall -mdynamic-no-pic \
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic \
        -D__FBSDID=__RCSID -D_DARWIN_USE_64_BIT_INODE
 Extra_LD_Flags = -dead_strip
 
index 945b5575dc86f554c9930505154994d1e0bb1767..4ad1ed022b28dccfe7898d9cc369d9d5e3872b13 100644 (file)
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)extern.h    8.3 (Berkeley) 4/16/94
- *     $FreeBSD: src/usr.bin/find/extern.h,v 1.23 2006/05/14 20:23:00 krion Exp $
+ *     $FreeBSD: src/usr.bin/find/extern.h,v 1.24 2008/02/23 16:29:04 imp Exp $
  */
 
 #include <sys/cdefs.h>
@@ -74,6 +74,7 @@ creat_f       c_nouser;
 creat_f        c_perm;
 creat_f        c_print;
 creat_f        c_regex;
+creat_f        c_samefile;
 creat_f        c_simple;
 creat_f        c_size;
 creat_f        c_type;
@@ -90,6 +91,7 @@ exec_f        f_depth;
 exec_f f_empty;
 exec_f f_exec;
 exec_f f_expr;
+exec_f f_false;
 exec_f f_flags;
 exec_f f_fstype;
 exec_f f_group;
@@ -108,6 +110,7 @@ exec_f      f_perm;
 exec_f f_print;
 exec_f f_print0;
 exec_f f_prune;
+exec_f f_quit;
 exec_f f_regex;
 exec_f f_size;
 exec_f f_type;
index a20f4504b8faf78545de607eea4a5d7cb742dc82..c63342caf40570b004f9dc5e50076c15378ccf1d 100644 (file)
@@ -33,9 +33,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"    @(#)find.1      8.7 (Berkeley) 5/9/95
-.\" $FreeBSD: src/usr.bin/find/find.1,v 1.81 2006/12/13 17:02:50 ru Exp $
+.\" $FreeBSD: src/usr.bin/find/find.1,v 1.86 2008/03/03 08:32:58 ru Exp $
 .\"
-.Dd December 13, 2006
+.Dd February 24, 2008
 .Dt FIND 1
 .Os
 .Sh NAME
 .Nm
 .Op Fl H | Fl L | Fl P
 .Op Fl EXdsx
-.Op Fl f Ar pathname
-.Ar pathname ...
-.Ar expression
+.Op Fl f Ar path
+.Ar path ...
+.Op Ar expression
 .Nm
 .Op Fl H | Fl L | Fl P
 .Op Fl EXdsx
-.Fl f Ar pathname
-.Op Ar pathname ...
-.Ar expression
+.Fl f Ar path
+.Op Ar path ...
+.Op Ar expression
 .Sh DESCRIPTION
 The
 .Nm
 utility recursively descends the directory tree for each
-.Ar pathname
+.Ar path
 listed, evaluating an
 .Ar expression
 (composed of the
@@ -75,7 +75,7 @@ Interpret regular expressions followed by
 .Ic -regex
 and
 .Ic -iregex
-options as extended (modern) regular expressions rather than basic
+primaries as extended (modern) regular expressions rather than basic
 regular expressions (BRE's).
 The
 .Xr re_format 7
@@ -144,7 +144,9 @@ This option is equivalent to the
 .Ic -depth
 primary of
 .St -p1003.1-2001 .
+The
 .Fl d
+option
 can be useful when
 .Nm
 is used with
@@ -210,7 +212,7 @@ Please refer to the
 .Ic -atime
 primary description for information on supported time units.
 .\" .It Ic -acl
-.\" May be used in conjunction with other options to locate
+.\" May be used in conjunction with other primaries to locate
 .\" files with extended ACLs.
 .\" See
 .\" .Xr acl 3
@@ -291,6 +293,12 @@ units.
 Please refer to the
 .Ic -atime
 primary description for information on supported time units.
+.It Ic -d
+Same as 
+.Ic depth .
+GNU find implements this as a primary in mistaken emulation of
+.Fx
+.Xr find 1 .
 .It Ic -delete
 Delete found files and/or directories.
 Always returns true.
@@ -363,6 +371,15 @@ The filename substituted for
 the string
 .Dq Li {}
 is not qualified.
+.It Ic -execdir Ar utility Oo Ar argument ... Oc Li {} +
+Same as
+.Ic -execdir ,
+except that
+.Dq Li {}
+is replaced with as many pathnames as possible for each invocation of
+.Ar utility .
+This behaviour is similar to that of
+.Xr xargs 1 .
 .It Ic -flags Oo Cm - Ns | Ns Cm + Oc Ns Ar flags , Ns Ar notflags
 The flags are specified using symbolic names (see
 .Xr chflags 1 ) .
@@ -426,6 +443,15 @@ the
 .Nm
 is being executed and the latter matches any file system which is
 mounted read-only.
+.It Ic -gid Ar gname
+The same thing as
+.Ar -group Ar gname 
+for compatibility with GNU find.
+GNU find imposes a restriction that
+.Ar gname 
+is numeric, while
+.Xr find 1 
+does not.
 .It Ic -group Ar gname
 True if the file belongs to the group
 .Ar gname .
@@ -434,6 +460,13 @@ If
 is numeric and there is no such group name, then
 .Ar gname
 is treated as a group ID.
+.It Ic -ignore_readdir_race
+This option is for GNU find compatibility and is ignored.
+.It Ic -ilname Ar pattern
+Like
+.Ic -lname ,
+but the match is case insensitive.
+This is a GNU find extension.
 .It Ic -iname Ar pattern
 Like
 .Ic -name ,
@@ -449,10 +482,20 @@ but the match is case insensitive.
 Like
 .Ic -regex ,
 but the match is case insensitive.
+.It Ic -iwholename Ar pattern
+The same thing as 
+.Ic -ipath ,
+for GNU find compatibility.
 .It Ic -links Ar n
 True if the file has
 .Ar n
 links.
+.It Ic -lname Ar pattern
+Like
+.Ic -name ,
+but the contents of the symbolic link are matched instead of the file
+name.
+This is a GNU find extension.
 .It Ic -ls
 This primary always evaluates to true.
 The following information for the current file is written to standard output:
@@ -465,7 +508,7 @@ displayed preceded by
 .Dq Li -> .
 The format is identical to that produced by
 .Bk -words
-.Nm ls Fl dgils .
+.Dq Nm ls Fl dgils .
 .Ek
 .It Ic -maxdepth Ar n
 Always true; descend at most
@@ -475,7 +518,7 @@ If any
 .Ic -maxdepth
 primary is specified, it applies to the entire expression even if it would
 not normally be evaluated.
-.Ic -maxdepth Li 0
+.Dq Ic -maxdepth Li 0
 limits the whole search to the command line arguments.
 .It Ic -mindepth Ar n
 Always true; do not apply any tests or actions at levels less than
@@ -484,7 +527,7 @@ If any
 .Ic -mindepth
 primary is specified, it applies to the entire expression even if it would
 not normally be evaluated.
-.Ic -mindepth Li 1
+.Dq Ic -mindepth Li 1
 processes all but the command line arguments.
 .It Ic -mmin Ar n
 True if the difference between the file last modification time and the time
@@ -495,6 +538,10 @@ minutes.
 .It Ic -mnewer Ar file
 Same as
 .Ic -newer .
+.It Ic -mount
+The same thing as 
+.Ic -xdev ,
+for GNU find compatibility.
 .It Ic -mtime Ar n Ns Op Cm smhdw
 If no units are specified, this primary evaluates to
 true if the difference between the file last modification time and the time
@@ -531,21 +578,21 @@ True if the current file has a more recent last modification time than
 .Ar file .
 .It Ic -newer Ns Ar X Ns Ar Y Ar file
 True if the current file has a more recent last access time
-.Ar ( X Ns = Ns Cm a ) ,
+.Pq Ar X Ns = Ns Cm a ,
 inode creation time
-.Ar ( X Ns = Ns Cm B ) ,
+.Pq Ar X Ns = Ns Cm B ,
 change time
-.Ar ( X Ns = Ns Cm c ) ,
+.Pq Ar X Ns = Ns Cm c ,
 or modification time
-.Ar ( X Ns = Ns Cm m )
+.Pq Ar X Ns = Ns Cm m
 than the last access time
-.Ar ( Y Ns = Ns Cm a ) ,
+.Pq Ar Y Ns = Ns Cm a ,
 inode creation time
-.Ar ( Y Ns = Ns Cm B ) ,
+.Pq Ar Y Ns = Ns Cm B ,
 change time
-.Ar ( Y Ns = Ns Cm c ) ,
+.Pq Ar Y Ns = Ns Cm c ,
 or modification time
-.Ar ( Y Ns = Ns Cm m )
+.Pq Ar Y Ns = Ns Cm m
 of
 .Ar file .
 In addition, if
@@ -561,6 +608,13 @@ is equivalent to
 .Ic -newer .
 .It Ic -nogroup
 True if the file belongs to an unknown group.
+.It Ic -noignore_readdir_race
+This option is for GNU find compatibility and is ignored.
+.It Ic -noleaf
+This option is for GNU find compatibility.
+In GNU find it disables an optimization not relevant to 
+.Xr find 1 ,
+so it is ignored.
 .It Ic -nouser
 True if the file belongs to an unknown user.
 .It Ic -ok Ar utility Oo Ar argument ... Oc Li \&;
@@ -689,6 +743,14 @@ but not
 .Dq Li xyzzy
 or
 .Dq Li /foo/ .
+.It Ic -samefile Ar name
+True if the file is a hard link to
+.Ar name .
+If the command option
+.Ic -L
+is specified, it is also true if the file is a symbolic link and
+points to 
+.Ar name .
 .It Ic -size Ar n Ns Op Cm ckMGTP
 True if the file's size, rounded up, in 512-byte blocks is
 .Ar n .
@@ -718,7 +780,6 @@ terabytes (1024 gigabytes)
 .It Cm P
 petabytes (1024 terabytes)
 .El
-.Pp
 .It Ic -type Ar t
 True if the file is of the specified type.
 Possible file types are as follows:
@@ -739,6 +800,15 @@ FIFO
 .It Cm s
 socket
 .El
+.It Ic -uid Ar uname
+The same thing as
+.Ar -user Ar uname 
+for compatibility with GNU find.
+GNU find imposes a restriction that
+.Ar uname 
+is numeric, while
+.Xr find 1 
+does not.
 .It Ic -user Ar uname
 True if the file belongs to the user
 .Ar uname .
@@ -747,6 +817,10 @@ If
 is numeric and there is no such user name, then
 .Ar uname
 is treated as a user ID.
+.It Ic -wholename Ar pattern
+The same thing as 
+.Ic -path ,
+for GNU find compatibility.
 .El
 .Pp
 All primaries which take a numeric argument allow the number to be
@@ -764,19 +838,23 @@ and neither means
 The primaries may be combined using the following operators.
 The operators are listed in order of decreasing precedence.
 .Pp
-.Bl -tag -width "( expression )" -compact
+.Bl -tag -width indent -compact
 .It Cm \&( Ar expression Cm \&)
 This evaluates to true if the parenthesized expression evaluates to
 true.
 .Pp
 .It Cm \&! Ar expression
-.It Cm -false Ar expression
 .It Cm -not Ar expression
 This is the unary
 .Tn NOT
 operator.
 It evaluates to true if the expression is false.
 .Pp
+.It Cm -false
+Always false.
+.It Cm -true
+Always true.
+.Pp
 .It Ar expression Cm -and Ar expression
 .It Ar expression expression
 The
@@ -888,15 +966,15 @@ utility syntax is a superset of the syntax specified by the
 standard.
 .Pp
 All the single character options except
-.Ic -H
+.Fl H
 and
-.Ic -L
+.Fl L
 as well as
 .Ic -amin , -anewer , -cmin , -cnewer , -delete , -empty , -fstype ,
 .Ic -iname , -inum , -iregex , -ls , -maxdepth , -mindepth , -mmin ,
 .Ic -path , -print0 , -regex
 and all of the
-.Ic -B
+.Ic -B*
 birthtime related primaries are extensions to
 .St -p1003.1-2001 .
 .Pp
index 35f800664aded9b3a074be559cc8bbad7154ad82..22f43f0aa3590ea43ab60d4f1ec138c7e9e87f4b 100644 (file)
@@ -64,7 +64,11 @@ __FBSDID("$FreeBSD: src/usr.bin/find/find.c,v 1.18 2006/05/14 20:23:00 krion Exp
 
 #include "find.h"
 
+#ifdef __APPLE__
+static int find_compare(const FTSENT **s1, const FTSENT **s2);
+#else /* !__APPLE__ */
 static int find_compare(const FTSENT * const *s1, const FTSENT * const *s2);
+#endif /* __APPLE__ */
 
 /*
  * find_compare --
@@ -73,7 +77,11 @@ static int find_compare(const FTSENT * const *s1, const FTSENT * const *s2);
  *     order within each directory.
  */
 static int
+#ifdef __APPLE__
+find_compare(const FTSENT **s1, const FTSENT **s2)
+#else /* !__APPLE__ */
 find_compare(const FTSENT * const *s1, const FTSENT * const *s2)
+#endif /* __APPLE__ */
 {
 
        return (strcoll((*s1)->fts_name, (*s2)->fts_name));
@@ -239,7 +247,7 @@ find_execute(PLAN *plan, char *paths[])
                if (COMPAT_MODE("bin/find", "unix2003") && getuid() 
                  && stat_ret == 0 
                  && ((statInfo.st_mode & S_IFMT) == S_IFDIR)) {
-                       if ((statInfo.st_mode & (S_IXUSR + S_IXGRP + S_IXOTH)) != 0) {
+                       if (access(paths[pathIndex], X_OK) == 0) {
                                myPaths = addPath(myPaths, paths[pathIndex]);
                        } else {
                                if (stat_errno != ENAMETOOLONG) {       /* if name is too long, just let existing logic handle it */
index 6a8bc437f129dd90a4426a907e705a003c04c9a9..a37a613f3bf55806a030a3faeaea10d02cbf7a0a 100644 (file)
@@ -34,7 +34,7 @@
  * SUCH DAMAGE.
  *
  *     @(#)find.h      8.1 (Berkeley) 6/6/93
- *     $FreeBSD: src/usr.bin/find/find.h,v 1.19 2006/05/14 20:23:01 krion Exp $
+ *     $FreeBSD: src/usr.bin/find/find.h,v 1.20 2008/02/23 16:29:04 imp Exp $
  */
 
 #include <regex.h>
@@ -74,6 +74,7 @@ typedef       struct _plandata *creat_f(struct _option *, char ***);
 #define F_EXECPLUS     0x00020000      /* -exec ... {} + */
 #define        F_TIME_B        0x00040000      /* one of -Btime, -Bnewer, -newerB* */
 #define        F_TIME2_B       0x00080000      /* one of -newer?B */
+#define F_LINK         0x00100000      /* lname or ilname */
 
 /* node definition */
 typedef struct _plandata {
index 0e6028e9b8cf046b5acf0c3e828f5abc16e818df..a7cbd263dbab9358f13026627bd4ba1b26651546 100644 (file)
@@ -41,7 +41,7 @@ static const char sccsid[] = "@(#)function.c  8.10 (Berkeley) 5/4/95";
 #endif /* not lint */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.58 2006/05/27 18:27:41 krion Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.60 2008/02/24 00:01:06 imp Exp $");
 
 #include <sys/param.h>
 #include <sys/ucred.h>
@@ -71,6 +71,7 @@ __FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.58 2006/05/27 18:27:41 krion
 
 #ifdef __APPLE__
 #include <sys/sysctl.h>
+#include <libgen.h>
 #include <get_compat.h>
 #else
 #define COMPAT_MODE(func, mode) 1
@@ -320,10 +321,10 @@ f_Xtime(PLAN *plan, FTSENT *entry)
        else
                xtime = entry->fts_statp->st_mtime;
 
-       if (COMPAT_MODE("bin/find", "unix2003") || plan->flags & F_EXACTTIME)
-               COMPARE((now - xtime) / 86400, plan->t_data);
+       if (plan->flags & F_EXACTTIME)
+               COMPARE(now - xtime, plan->t_data);
        else
-               COMPARE((now - xtime + 86400 - 1) / 86400, plan->t_data);
+               COMPARE((now - xtime + (COMPAT_MODE("bin/find", "unix2003") ? 0 : 86400 - 1)) / 86400, plan->t_data);
 }
 
 PLAN *
@@ -337,7 +338,7 @@ c_Xtime(OPTION *option, char ***argvp)
 
        new = palloc(option);
        new->t_data = find_parsetime(new, option->name, value);
-       if (!(new->flags & F_EXACTTIME))
+       if (!(new->flags & F_EXACTTIME) && !COMPAT_MODE("bin/find", "unix2003"))
                TIME_CORRECT(new);
        return new;
 }
@@ -483,7 +484,7 @@ c_delete(OPTION *option, char ***argvp __unused)
 /*
  * always_true --
  *
- *     Always true, used for -maxdepth, -mindepth, -xdev and -follow
+ *     Always true, used for -maxdepth, -mindepth, -xdev, -follow, and -true
  */
 int
 f_always_true(PLAN *plan __unused, FTSENT *entry __unused)
@@ -981,7 +982,7 @@ c_group(OPTION *option, char ***argvp)
        g = getgrnam(gname);
        if (g == NULL) {
                char* cp = gname;
-               if( gname[0] == '-' || gname[0] == '+' )
+               if (gname[0] == '-' || gname[0] == '+')
                        gname++;
                gid = atoi(gname);
                if (gid == 0 && gname[0] != '0')
@@ -1019,6 +1020,30 @@ c_inum(OPTION *option, char ***argvp)
        return new;
 }
 
+/*
+ * -samefile FN
+ *
+ *     True if the file has the same inode (eg hard link) FN
+ */
+
+/* f_samefile is just f_inum */
+PLAN *
+c_samefile(OPTION *option, char ***argvp)
+{
+       char *fn;
+       PLAN *new;
+       struct stat sb;
+
+       fn = nextarg(option, argvp);
+       ftsoptions &= ~FTS_NOSTAT;
+
+       new = palloc(option);
+       if (stat(fn, &sb))
+               err(1, "%s", fn);
+       new->i_data = sb.st_ino;
+       return new;
+}
+
 /*
  * -links n functions --
  *
@@ -1074,7 +1099,18 @@ c_ls(OPTION *option, char ***argvp __unused)
 int
 f_name(PLAN *plan, FTSENT *entry)
 {
-       return !fnmatch(plan->c_data, entry->fts_name,
+       char fn[PATH_MAX];
+       const char *name;
+
+       if (plan->flags & F_LINK) {
+               name = fn;
+               if (readlink(entry->fts_path, fn, sizeof(fn)) == -1)
+                       return 0;
+       } else if (entry->fts_namelen == 0) {
+               name = basename(entry->fts_path);
+       } else
+               name = entry->fts_name;
+       return !fnmatch(plan->c_data, name,
            plan->flags & F_IGNCASE ? FNM_CASEFOLD : 0);
 }
 
@@ -1367,7 +1403,7 @@ c_regex(OPTION *option, char ***argvp)
        return new;
 }
 
-/* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or */
+/* c_simple covers c_prune, c_openparen, c_closeparen, c_not, c_or, c_true, c_false */
 
 PLAN *
 c_simple(OPTION *option, char ***argvp __unused)
@@ -1649,3 +1685,29 @@ f_or(PLAN *plan, FTSENT *entry)
 }
 
 /* c_or == c_simple */
+
+/*
+ * -false
+ *
+ *     Always false.
+ */
+int
+f_false(PLAN *plan __unused, FTSENT *entry __unused)
+{
+       return 0;
+}
+
+/* c_false == c_simple */
+
+/*
+ * -quit
+ *
+ *     Exits the program
+ */
+int
+f_quit(PLAN *plan __unused, FTSENT *entry __unused)
+{
+       exit(0);
+}
+
+/* c_quit == c_simple */
index 5a42be2aea2e95ee5722da8c8fb2194a18222b27..cf84d57e7e79e8130e3507a069dd1f66193db9cc 100644 (file)
--- a/find/ls.c
+++ b/find/ls.c
@@ -55,7 +55,8 @@ __FBSDID("$FreeBSD: src/usr.bin/find/ls.c,v 1.17 2004/01/20 09:27:03 des Exp $")
 #include <time.h>
 #include <unistd.h>
 #ifdef __APPLE__
-#include <utmp.h>
+/* definition from utmp.h */
+#define UT_NAMESIZE     8
 #endif /* __APPLE__ */
 
 #include "find.h"
index b1f22332658ad7e7fe05551a58200071dc5b6fa3..007ee1486d0b3bbfd9d451ce438b1e8d6668210c 100644 (file)
@@ -47,7 +47,7 @@ static char sccsid[] = "@(#)main.c    8.4 (Berkeley) 5/4/95";
 #endif /* not lint */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/usr.bin/find/main.c,v 1.15 2003/06/14 13:00:21 markm Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/find/main.c,v 1.16 2008/03/03 08:32:58 ru Exp $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -163,7 +163,8 @@ main(int argc, char *argv[])
 static void
 usage(void)
 {
-       (void)fprintf(stderr,
-"usage: find [-H | -L | -P] [-EXdsx] [-f file] [file ...] [expression]\n");
+       (void)fprintf(stderr, "%s\n%s\n",
+"usage: find [-H | -L | -P] [-EXdsx] [-f path] path ... [expression]",
+"       find [-H | -L | -P] [-EXdsx] -f path [path ...] [expression]");
        exit(1);
 }
index 004d5500326ea53fb5bfe6f80336183cb28cf94f..9ff745123c69a93f3ff7d5d4331f31816a820673 100644 (file)
@@ -41,7 +41,7 @@ static char sccsid[] = "@(#)option.c  8.2 (Berkeley) 4/16/94";
 #endif /* not lint */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/usr.bin/find/option.c,v 1.25 2006/04/05 23:06:11 ceri Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/find/option.c,v 1.26 2008/02/23 16:29:04 imp Exp $");
 
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -58,6 +58,7 @@ __FBSDID("$FreeBSD: src/usr.bin/find/option.c,v 1.25 2006/04/05 23:06:11 ceri Ex
 int typecompare(const void *, const void *);
 
 /* NB: the following table must be sorted lexically. */
+/* Options listed with C++ comments are in gnu find, but not our find */
 static OPTION const options[] = {
        { "!",          c_simple,       f_not,          0 },
        { "(",          c_simple,       f_openparen,    0 },
@@ -76,26 +77,38 @@ static OPTION const options[] = {
        { "-cmin",      c_Xmin,         f_Xmin,         F_TIME_C },
        { "-cnewer",    c_newer,        f_newer,        F_TIME_C },
        { "-ctime",     c_Xtime,        f_Xtime,        F_TIME_C },
+       { "-d",         c_depth,        f_depth,        0 },
+// -daystart
        { "-delete",    c_delete,       f_delete,       0 },
        { "-depth",     c_depth,        f_depth,        0 },
        { "-empty",     c_empty,        f_empty,        0 },
        { "-exec",      c_exec,         f_exec,         0 },
        { "-execdir",   c_exec,         f_exec,         F_EXECDIR },
-       { "-false",     c_simple,       f_not,          0 },
+       { "-false",     c_simple,       f_false,        0 },
        { "-flags",     c_flags,        f_flags,        0 },
+// -fls
        { "-follow",    c_follow,       f_always_true,  0 },
+// -fprint
+// -fprint0
+// -fprintf
        { "-fstype",    c_fstype,       f_fstype,       0 },
+       { "-gid",       c_group,        f_group,        0 },
        { "-group",     c_group,        f_group,        0 },
+       { "-ignore_readdir_race",c_simple, f_always_true,0 },
+       { "-ilname",    c_name,         f_name,         F_LINK | F_IGNCASE },
        { "-iname",     c_name,         f_name,         F_IGNCASE },
        { "-inum",      c_inum,         f_inum,         0 },
        { "-ipath",     c_name,         f_path,         F_IGNCASE },
        { "-iregex",    c_regex,        f_regex,        F_IGNCASE },
+       { "-iwholename",c_name,         f_path,         F_IGNCASE },
        { "-links",     c_links,        f_links,        0 },
+       { "-lname",     c_name,         f_name,         F_LINK },
        { "-ls",        c_ls,           f_ls,           0 },
        { "-maxdepth",  c_mXXdepth,     f_always_true,  F_MAXDEPTH },
        { "-mindepth",  c_mXXdepth,     f_always_true,  0 },
        { "-mmin",      c_Xmin,         f_Xmin,         0 },
        { "-mnewer",    c_newer,        f_newer,        0 },
+       { "-mount",     c_xdev,         f_always_true,  0 },
        { "-mtime",     c_Xtime,        f_Xtime,        0 },
        { "-name",      c_name,         f_name,         0 },
        { "-newer",     c_newer,        f_newer,        0 },
@@ -120,6 +133,8 @@ static OPTION const options[] = {
        { "-newermm",   c_newer,        f_newer,        0 },
        { "-newermt",   c_newer,        f_newer,        F_TIME2_T },
        { "-nogroup",   c_nogroup,      f_nogroup,      0 },
+       { "-noignore_readdir_race",c_simple, f_always_true,0 },
+       { "-noleaf",    c_simple,       f_always_true,  0 },
        { "-not",       c_simple,       f_not,          0 },
        { "-nouser",    c_nouser,       f_nouser,       0 },
        { "-o",         c_simple,       f_or,           0 },
@@ -130,12 +145,19 @@ static OPTION const options[] = {
        { "-perm",      c_perm,         f_perm,         0 },
        { "-print",     c_print,        f_print,        0 },
        { "-print0",    c_print,        f_print0,       0 },
+// -printf
        { "-prune",     c_simple,       f_prune,        0 },
+       { "-quit",      c_simple,       f_quit,         0 },
        { "-regex",     c_regex,        f_regex,        0 },
+       { "-samefile",  c_samefile,     f_inum,         0 },
        { "-size",      c_size,         f_size,         0 },
+       { "-true",      c_simple,       f_always_true,  0 },
        { "-type",      c_type,         f_type,         0 },
+       { "-uid",       c_user,         f_user,         0 },
        { "-user",      c_user,         f_user,         0 },
+       { "-wholename", c_name,         f_path,         0 },
        { "-xdev",      c_xdev,         f_always_true,  0 },
+// -xtype
 };
 
 /*
index 22b3e47b8b0de077eea80fd5777e91e1dd3647d5..3b6d0d91231a88ae900ff4328bbfa461d9a342bb 100644 (file)
@@ -4,8 +4,7 @@ Install_Dir = /bin
 CFILES = hostname.c
 MANPAGES = hostname.1
 
-Extra_CC_Flags = -Wall -mdynamic-no-pic \
-       -DKERNEL_PRIVATE
+Extra_CC_Flags = -Wall -mdynamic-no-pic -D__FBSDID=__RCSID
 Extra_LD_Flags = -dead_strip
 
 include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
index 7700a1515eda7f448c8e5ff57ce976e1a64628f6..291b3197239eb460766610b1a8478dfbd8a60f8d 100644 (file)
@@ -1,3 +1,4 @@
+.\"-
 .\" Copyright (c) 1983, 1988, 1990, 1993
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
@@ -9,10 +10,6 @@
 .\" 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 University of
-.\"    California, Berkeley and its contributors.
 .\" 4. 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.
@@ -30,9 +27,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"    @(#)hostname.1  8.2 (Berkeley) 4/28/95
-.\" $FreeBSD: src/bin/hostname/hostname.1,v 1.14 2002/04/16 20:02:56 charnier Exp $
+.\" $FreeBSD: src/bin/hostname/hostname.1,v 1.21 2006/12/08 07:47:08 kientzle Exp $
 .\"
-.Dd April 28, 1995
+.Dd December 7, 2006
 .Dt HOSTNAME 1
 .Os
 .Sh NAME
 .Nd set or print name of current host system
 .Sh SYNOPSIS
 .Nm
-.Op Fl s
+.Op Fl fs
 .Op Ar name-of-host
 .Sh DESCRIPTION
 The
 .Nm
 utility prints the name of the current host.
-The super-user can set the hostname by supplying an argument.
+The super-user can
+set the hostname by supplying an argument.
+To keep the hostname between reboots, run
+.Sq scutil --set HostName Ar name-of-host .
 .Pp
 Options:
 .Bl -tag -width flag
+.It Fl f
+Include domain information in the printed name.
+This is the default behavior.
 .It Fl s
 Trim off any domain information from the printed
 name.
 .El
 .Sh SEE ALSO
-.Xr gethostname 3
+.Xr gethostname 3 ,
+.Xr scutil 8
 .Sh HISTORY
 The
 .Nm
index a294914d9ed5de08e9a6be0d5dd57f0311e01575..3df6542d3ce6e3709d6f6905fc106773c476f34d 100644 (file)
@@ -1,4 +1,4 @@
-/*
+/*-
  * Copyright (c) 1988, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
  * 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 University of
- *     California, Berkeley and its contributors.
  * 4. 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.
@@ -31,6 +27,7 @@
  * SUCH DAMAGE.
  */
 
+#if 0
 #ifndef lint
 static char const copyright[] =
 "@(#) Copyright (c) 1988, 1993\n\
@@ -38,12 +35,11 @@ static char const copyright[] =
 #endif /* not lint */
 
 #ifndef lint
-#if 0
 static char sccsid[] = "@(#)hostname.c 8.1 (Berkeley) 5/31/93";
-#endif
 #endif /* not lint */
+#endif
 #include <sys/cdefs.h>
-__RCSID("$FreeBSD: src/bin/hostname/hostname.c,v 1.14 2002/06/30 05:13:53 obrien Exp $");
+__FBSDID("$FreeBSD: src/bin/hostname/hostname.c,v 1.19 2006/12/08 07:47:08 kientzle Exp $");
 
 #include <sys/param.h>
 
@@ -62,8 +58,15 @@ main(int argc, char *argv[])
        char *p, hostname[MAXHOSTNAMELEN];
 
        sflag = 0;
-       while ((ch = getopt(argc, argv, "s")) != -1)
+       while ((ch = getopt(argc, argv, "fs")) != -1)
                switch (ch) {
+               case 'f':
+                       /*
+                        * On Linux, "hostname -f" prints FQDN.
+                        * BSD "hostname" always prints FQDN by
+                        * default, so we accept but ignore -f.
+                        */
+                       break;
                case 's':
                        sflag = 1;
                        break;
@@ -97,6 +100,6 @@ void
 usage(void)
 {
 
-       (void)fprintf(stderr, "usage: hostname [-s] [name-of-host]\n");
+       (void)fprintf(stderr, "usage: hostname [-fs] [name-of-host]\n");
        exit(1);
 }
diff --git a/id/id.c b/id/id.c
index becc5912f1d40382d4d1a4efdb8529af7d465c3d..5bdb99c772459e2b178fff0e7f545883fd1b5bf5 100644 (file)
--- a/id/id.c
+++ b/id/id.c
@@ -266,7 +266,7 @@ id_print(struct passwd *pw, int use_ggl, int p_euid, int p_egid)
        uid_t uid, euid;
        int cnt, ngroups;
 #ifdef __APPLE__
-       gid_t *groups;
+       gid_t *groups = NULL;
 #else
        gid_t groups[NGROUPS + 1];
 #endif
@@ -300,11 +300,16 @@ id_print(struct passwd *pw, int use_ggl, int p_euid, int p_egid)
        }
        else {
 #ifdef __APPLE__
-               groups = malloc(NGROUPS + 1);
+               groups = malloc((NGROUPS + 1) * sizeof(gid_t));
 #endif
                ngroups = getgroups(NGROUPS + 1, groups);
        }
 
+#ifdef __APPLE__
+       if (ngroups < 0)
+               warn("failed to retrieve group list");
+#endif
+
        if (pw != NULL)
                printf("uid=%u(%s)", uid, pw->pw_name);
        else 
index 3993c7b15c999357585b06897cf827c113d0445a..6abd3b5d78095fd5f19f2dd6716e19a066cffeb1 100644 (file)
@@ -4,7 +4,7 @@ Install_Dir = /usr/bin
 CFILES = jot.c
 MANPAGES = jot.1
 
-Extra_CC_Flags = -Wall -mdynamic-no-pic
+Extra_CC_Flags = -Wall -mdynamic-no-pic -D__FBSDID=__RCSID
 Extra_LD_Flags = -dead_strip
 
 include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
index 3ae05e47f21d4608fcdc6ea64e2358be95bbd19a..3e6488d9f795f72b791c36517d2eaf8a247d1392 100644 (file)
--- a/jot/jot.1
+++ b/jot/jot.1
@@ -30,9 +30,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"    @(#)jot.1       8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: src/usr.bin/jot/jot.1,v 1.14 2002/07/03 12:24:11 ru Exp $
+.\" $FreeBSD: src/usr.bin/jot/jot.1,v 1.23 2006/11/06 15:11:50 dds Exp $
 .\"
-.Dd June 6, 1993
+.Dd November 6, 2006
 .Dt JOT 1
 .Os
 .Sh NAME
@@ -106,7 +106,8 @@ and the step size or, for random data, the seed.
 While at least one of them must appear,
 any of the other three may be omitted, and
 will be considered as such if given as
-.Fl "" .
+.Fl ""
+or as an empty string.
 Any three of these arguments determines the fourth.
 If four are specified and the given and computed values of
 .Ar reps
@@ -114,7 +115,7 @@ conflict, the lower value is used.
 If fewer than three are specified, defaults are assigned
 left to right, except for
 .Ar s ,
-which assumes its default unless both
+which assumes a default of 1 or -1 if both
 .Ar begin
 and
 .Ar end
@@ -139,14 +140,41 @@ representing the corresponding value in
 The last argument must be a real number.
 .Pp
 Random numbers are obtained through
-.Xr random 3 .
+.Xr arc4random 3
+when no seed is specified,
+and through
+.Xr random 3
+when a seed is given.
+When
+.Nm
+is asked to generate random integers or characters with begin
+and end values in the range of the random number generator function
+and no format is specified with one of the
+.Fl w ,
+.Fl b ,
+or
+.Fl p
+options,
+.Nm
+will arrange for all the values in the range to appear in the output
+with an equal probability.
+In all other cases be careful to ensure that the output format's
+rounding or truncation will not skew the distribution of output
+values in an unintended way.
+.Pp
 The name
 .Nm
 derives in part from
 .Nm iota ,
 a function in APL.
+.Sh EXIT STATUS
+.Ex -std
 .Sh EXAMPLES
 The command
+.Dl jot - 1 10
+.Pp
+prints the integers from 1 to 10,
+while the command
 .Dl jot 21 -1 1.00
 .Pp
 prints 21 evenly spaced numbers increasing from -1 to 1.
@@ -168,11 +196,11 @@ may be obtained through
 .Pp
 and thirty
 .Xr ed 1
-substitution commands applying to lines 2, 7, 12, etc. is
+substitution commands applying to lines 2, 7, 12, etc.\& is
 the result of
 .Dl jot -w %ds/old/new/ 30 2 - 5
 .Pp
-The stuttering sequence 9, 9, 8, 8, 7, etc. can be
+The stuttering sequence 9, 9, 8, 8, 7, etc.\& can be
 produced by suitable choice of step size,
 as in
 .Dl jot - 9 0 -.5
@@ -187,7 +215,6 @@ from column 10 and ending in column 132, use
 and to print all lines 80 characters or longer,
 .Dl grep `jot -s \&"\&" -b \&. 80`
 .Sh DIAGNOSTICS
-.Ex -std
 The following diagnostic messages deserve special explanation:
 .Bl -diag
 .It "illegal or unsupported format '%s'"
@@ -208,12 +235,16 @@ associated with the requested output format.
 More than one conversion format specifier has been supplied,
 but only one is allowed.
 .El
-.Sh AUTHOR
-John A. Kunze <jak@ucop.edu>
 .Sh SEE ALSO
 .Xr ed 1 ,
 .Xr expand 1 ,
 .Xr rs 1 ,
 .Xr yes 1 ,
+.Xr arc4random 3 ,
 .Xr printf 3 ,
 .Xr random 3
+.Sh HISTORY
+The
+.Nm
+utility first appeared in
+.Bx 4.2 .
index b25779317d62584f68140fd87f11af68858b105d..dfed0fc6ac94c4a2153a161964bab57e211f714f 100644 (file)
--- a/jot/jot.c
+++ b/jot/jot.c
@@ -43,7 +43,7 @@ static char sccsid[] = "@(#)jot.c     8.1 (Berkeley) 6/6/93";
 #endif
 #endif
 #include <sys/cdefs.h>
-__RCSID("$FreeBSD: src/usr.bin/jot/jot.c,v 1.24 2002/07/05 15:58:27 mike Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/jot/jot.c,v 1.37 2006/12/09 15:23:20 delphij Exp $");
 
 /*
  * jot - print sequential or random data
@@ -57,76 +57,86 @@ __RCSID("$FreeBSD: src/usr.bin/jot/jot.c,v 1.24 2002/07/05 15:58:27 mike Exp $")
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
 
+/* Defaults */
 #define        REPS_DEF        100
 #define        BEGIN_DEF       1
 #define        ENDER_DEF       100
 #define        STEP_DEF        1
 
-#define        is_default(s)   (strcmp((s), "-") == 0)
+/* Flags of options that have been set */
+#define HAVE_STEP      1
+#define HAVE_ENDER     2
+#define HAVE_BEGIN     4
+#define HAVE_REPS      8
 
-double begin;
-double ender;
-double s;
-long   reps;
-int    randomize;
-int    infinity;
-int    boring;
-int    prec;
-int    longdata;
-int    intdata;
-int    chardata;
-int    nosign;
-int    nofinalnl;
-const  char *sepstring = "\n";
-char   format[BUFSIZ];
+#define        is_default(s)   (*(s) == 0 || strcmp((s), "-") == 0)
 
-void           getformat(void);
-int            getprec(char *);
-int            putdata(double, long);
+static bool    boring;
+static int     prec;
+static bool    longdata;
+static bool    intdata;
+static bool    chardata;
+static bool    nosign;
+static const   char *sepstring = "\n";
+static char    format[BUFSIZ];
+
+static void    getformat(void);
+static int     getprec(const char *);
+static int     putdata(double, bool);
 static void    usage(void);
 
 int
 main(int argc, char **argv)
 {
-       double  xd, yd;
-       long    id;
-       double  *x = &xd;
-       double  *y = &yd;
-       long    *i = &id;
-       unsigned int    mask = 0;
-       int     n = 0;
+       bool    have_format = false;
+       bool    infinity = false;
+       bool    nofinalnl = false;
+       bool    randomize = false;
+       bool    use_random = false;
        int     ch;
+       int     mask = 0;
+       int     n = 0;
+       double  begin;
+       double  divisor;
+       double  ender;
+       double  s;
+       double  x, y;
+       long    i;
+       long    reps;
 
-       while ((ch = getopt(argc, argv, "rb:w:cs:np:")) != -1)
+       while ((ch = getopt(argc, argv, "b:cnp:rs:w:")) != -1)
                switch (ch) {
-               case 'r':
-                       randomize = 1;
-                       break;
-               case 'c':
-                       chardata = 1;
-                       break;
-               case 'n':
-                       nofinalnl = 1;
-                       break;
                case 'b':
-                       boring = 1;
+                       boring = true;
                        /* FALLTHROUGH */
                case 'w':
                        if (strlcpy(format, optarg, sizeof(format)) >=
                            sizeof(format))
                                errx(1, "-%c word too long", ch);
+                       have_format = true;
                        break;
-               case 's':
-                       sepstring = optarg;
+               case 'c':
+                       chardata = true;
+                       break;
+               case 'n':
+                       nofinalnl = true;
                        break;
                case 'p':
                        prec = atoi(optarg);
                        if (prec <= 0)
                                errx(1, "bad precision value");
+                       have_format = true;
+                       break;
+               case 'r':
+                       randomize = true;
+                       break;
+               case 's':
+                       sepstring = optarg;
                        break;
                default:
                        usage();
@@ -139,31 +149,36 @@ main(int argc, char **argv)
                if (!is_default(argv[3])) {
                        if (!sscanf(argv[3], "%lf", &s))
                                errx(1, "bad s value: %s", argv[3]);
-                       mask |= 01;
+                       mask |= HAVE_STEP;
+                       if (randomize)
+                               use_random = true;
                }
+               /* FALLTHROUGH */
        case 3:
                if (!is_default(argv[2])) {
                        if (!sscanf(argv[2], "%lf", &ender))
                                ender = argv[2][strlen(argv[2])-1];
-                       mask |= 02;
+                       mask |= HAVE_ENDER;
                        if (!prec)
                                n = getprec(argv[2]);
                }
+               /* FALLTHROUGH */
        case 2:
                if (!is_default(argv[1])) {
                        if (!sscanf(argv[1], "%lf", &begin))
                                begin = argv[1][strlen(argv[1])-1];
-                       mask |= 04;
+                       mask |= HAVE_BEGIN;
                        if (!prec)
                                prec = getprec(argv[1]);
                        if (n > prec)           /* maximum precision */
                                prec = n;
                }
+               /* FALLTHROUGH */
        case 1:
                if (!is_default(argv[0])) {
                        if (!sscanf(argv[0], "%ld", &reps))
                                errx(1, "bad reps value: %s", argv[0]);
-                       mask |= 010;
+                       mask |= HAVE_REPS;
                }
                break;
        case 0:
@@ -175,59 +190,39 @@ main(int argc, char **argv)
        getformat();
        while (mask)    /* 4 bit mask has 1's where last 4 args were given */
                switch (mask) { /* fill in the 0's by default or computation */
-               case 001:
-                       reps = REPS_DEF;
-                       mask = 011;
-                       break;
-               case 002:
-                       reps = REPS_DEF;
-                       mask = 012;
-                       break;
-               case 003:
-                       reps = REPS_DEF;
-                       mask = 013;
-                       break;
-               case 004:
-                       reps = REPS_DEF;
-                       mask = 014;
-                       break;
-               case 005:
+               case HAVE_STEP:
+               case HAVE_ENDER:
+               case HAVE_ENDER | HAVE_STEP:
+               case HAVE_BEGIN:
+               case HAVE_BEGIN | HAVE_STEP:
                        reps = REPS_DEF;
-                       mask = 015;
+                       mask |= HAVE_REPS;
                        break;
-               case 006:
-                       reps = REPS_DEF;
-                       mask = 016;
+               case HAVE_BEGIN | HAVE_ENDER:
+                       s = ender > begin ? 1 : -1;
+                       mask |= HAVE_STEP;
                        break;
-               case 007:
-                       if (randomize) {
+               case HAVE_BEGIN | HAVE_ENDER | HAVE_STEP:
+                       if (randomize)
                                reps = REPS_DEF;
-                               mask = 0;
-                               break;
-                       }
-                       if (s == 0.0) {
+                       else if (s == 0.0)
                                reps = 0;
-                               mask = 0;
-                               break;
-                       }
-                       reps = (ender - begin + s) / s;
+                       else
+                               reps = (ender - begin + s) / s;
                        if (reps <= 0)
                                errx(1, "impossible stepsize");
                        mask = 0;
                        break;
-               case 010:
+               case HAVE_REPS:
+               case HAVE_REPS | HAVE_STEP:
                        begin = BEGIN_DEF;
-                       mask = 014;
+                       mask |= HAVE_BEGIN;
                        break;
-               case 011:
-                       begin = BEGIN_DEF;
-                       mask = 015;
-                       break;
-               case 012:
-                       s = (randomize ? time(NULL) : STEP_DEF);
-                       mask = 013;
+               case HAVE_REPS | HAVE_ENDER:
+                       s = STEP_DEF;
+                       mask = HAVE_REPS | HAVE_ENDER | HAVE_STEP;
                        break;
-               case 013:
+               case HAVE_REPS | HAVE_ENDER | HAVE_STEP:
                        if (randomize)
                                begin = BEGIN_DEF;
                        else if (reps == 0)
@@ -235,21 +230,19 @@ main(int argc, char **argv)
                        begin = ender - reps * s + s;
                        mask = 0;
                        break;
-               case 014:
-                       s = (randomize ? -1.0 : STEP_DEF);
-                       mask = 015;
+               case HAVE_REPS | HAVE_BEGIN:
+                       s = STEP_DEF;
+                       mask = HAVE_REPS | HAVE_BEGIN | HAVE_STEP;
                        break;
-               case 015:
+               case HAVE_REPS | HAVE_BEGIN | HAVE_STEP:
                        if (randomize)
                                ender = ENDER_DEF;
                        else
                                ender = begin + reps * s - s;
                        mask = 0;
                        break;
-               case 016:
-                       if (randomize)
-                               s = -1.0;
-                       else if (reps == 0)
+               case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER:
+                       if (reps == 0)
                                errx(1, "infinite sequences cannot be bounded");
                        else if (reps == 1)
                                s = 0.0;
@@ -257,7 +250,8 @@ main(int argc, char **argv)
                                s = (ender - begin) / (reps - 1);
                        mask = 0;
                        break;
-               case 017:               /* if reps given and implied, */
+               case HAVE_REPS | HAVE_BEGIN | HAVE_ENDER | HAVE_STEP:
+                       /* if reps given and implied, */
                        if (!randomize && s != 0.0) {
                                long t = (ender - begin + s) / s;
                                if (t <= 0)
@@ -271,25 +265,57 @@ main(int argc, char **argv)
                        errx(1, "bad mask");
                }
        if (reps == 0)
-               infinity = 1;
+               infinity = true;
        if (randomize) {
-               *x = (ender - begin) * (ender > begin ? 1 : -1);
-               for (*i = 1; *i <= reps || infinity; (*i)++) {
-                       *y = arc4random() / (double)UINT32_MAX;
-                       if (putdata(*y * *x + begin, reps - *i))
+               if (use_random) {
+                       srandom((unsigned long)s);
+                       divisor = (double)INT32_MAX + 1;
+               } else
+                       divisor = (double)UINT32_MAX + 1;
+
+               /*
+                * Attempt to DWIM when the user has specified an
+                * integer range within that of the random number
+                * generator: distribute the numbers equally in
+                * the range [begin .. ender].  Jot's default %.0f
+                * format would make the appearance of the first and
+                * last specified value half as likely as the rest.
+                */
+               if (!have_format && prec == 0 &&
+                   begin >= 0 && begin < divisor &&
+                   ender >= 0 && ender < divisor) {
+                       ender += 1;
+                       nosign = true;
+                       intdata = true;
+                       (void)strlcpy(format,
+                           chardata ? "%c" : "%u", sizeof(format));
+               }
+               x = (ender - begin) * (ender > begin ? 1 : -1);
+               for (i = 1; i <= reps || infinity; i++) {
+                       if (use_random)
+                               y = random() / divisor;
+                       else
+                               y = arc4random() / divisor;
+                       if (putdata(y * x + begin, !(reps - i)))
                                errx(1, "range error in conversion");
                }
        } else
-               for (*i = 1, *x = begin; *i <= reps || infinity; (*i)++, *x += s)
-                       if (putdata(*x, reps - *i))
+               for (i = 1, x = begin; i <= reps || infinity; i++, x += s)
+                       if (putdata(x, !(reps - i)))
                                errx(1, "range error in conversion");
        if (!nofinalnl)
                putchar('\n');
        exit(0);
 }
 
-int
-putdata(double x, long int notlast)
+/*
+ * Send x to stdout using the specified format.
+ * Last is  true if this is the set's last value.
+ * Return 0 if OK, or a positive number if the number passed was
+ * outside the range specified by the various flags.
+ */
+static int
+putdata(double x, bool last)
 {
 
        if (boring)
@@ -317,7 +343,7 @@ putdata(double x, long int notlast)
 
        } else
                printf(format, x);
-       if (notlast != 0)
+       if (!last)
                fputs(sepstring, stdout);
 
        return (0);
@@ -332,11 +358,15 @@ usage(void)
        exit(1);
 }
 
-int
-getprec(char *str)
+/* 
+ * Return the number of digits following the number's decimal point.
+ * Return 0 if no decimal point is found.
+ */
+static int
+getprec(const char *str)
 {
-       char    *p;
-       char    *q;
+       const char      *p;
+       const char      *q;
 
        for (p = str; *p; p++)
                if (*p == '.')
@@ -344,12 +374,16 @@ getprec(char *str)
        if (!*p)
                return (0);
        for (q = ++p; *p; p++)
-               if (!isdigit(*p))
+               if (!isdigit((unsigned char)*p))
                        break;
        return (p - q);
 }
 
-void
+/*
+ * Set format, intdata, chardata, longdata, and nosign
+ * based on the command line arguments.
+ */
+static void
 getformat(void)
 {
        char    *p, *p2;
@@ -359,8 +393,12 @@ getformat(void)
        if (boring)                             /* no need to bother */
                return;
        for (p = format; *p; p++)               /* look for '%' */
-               if (*p == '%' && *(p+1) != '%') /* leave %% alone */
-                       break;
+               if (*p == '%') {
+                       if (p[1] == '%')
+                               p++;            /* leave %% alone */
+                       else
+                               break;
+               }
        sz = sizeof(format) - strlen(format) - 1;
        if (!*p && !chardata) {
                if (snprintf(p, sz, "%%.%df", prec) >= (int)sz)
@@ -368,7 +406,7 @@ getformat(void)
        } else if (!*p && chardata) {
                if (strlcpy(p, "%c", sz) >= sz)
                        errx(1, "-w word too long");
-               intdata = 1;
+               intdata = true;
        } else if (!*(p+1)) {
                if (sz <= 0)
                        errx(1, "-w word too long");
@@ -381,8 +419,8 @@ getformat(void)
                 */
                p2 = p++;
                dot = hash = space = sign = numbers = 0;
-               while (!isalpha(*p)) {
-                       if (isdigit(*p)) {
+               while (!isalpha((unsigned char)*p)) {
+                       if (isdigit((unsigned char)*p)) {
                                numbers++;
                                p++;
                        } else if ((*p == '#' && !(numbers|dot|sign|space|
@@ -395,7 +433,7 @@ getformat(void)
                                goto fmt_broken;
                }
                if (*p == 'l') {
-                       longdata = 1;
+                       longdata = true;
                        if (*++p == 'l') {
                                if (p[1] != '\0')
                                        p++;
@@ -404,24 +442,24 @@ getformat(void)
                }
                switch (*p) {
                case 'o': case 'u': case 'x': case 'X':
-                       intdata = nosign = 1;
+                       intdata = nosign = true;
                        break;
                case 'd': case 'i':
-                       intdata = 1;
+                       intdata = true;
                        break;
                case 'D':
                        if (!longdata) {
-                               intdata = 1;
+                               intdata = true;
                                break;
                        }
                case 'O': case 'U':
                        if (!longdata) {
-                               intdata = nosign = 1;
+                               intdata = nosign = true;
                                break;
                        }
                case 'c':
                        if (!(intdata | longdata)) {
-                               chardata = 1;
+                               chardata = true;
                                break;
                        }
                case 'h': case 'n': case 'p': case 'q': case 's': case 'L':
@@ -443,7 +481,9 @@ fmt_broken:
                        else if (*p == '%' && *(p+1) == '%')
                                p++;
                        else if (*p == '%' && !*(p+1)) {
-                               strcat(format, "%");
+                               if (strlcat(format, "%", sizeof(format)) >=
+                                   sizeof(format))
+                                       errx(1, "-w word too long");
                                break;
                        }
        }
index 795df0424a3b1e9f281340a2aafcfa3d030a68a1..38d6a09b05ec90b28efb31ac888582384279bb0b 100644 (file)
@@ -49,6 +49,9 @@ __FBSDID("$FreeBSD: src/usr.bin/killall/killall.c,v 1.31 2004/07/29 18:36:35 max
 #include <unistd.h>
 #include <locale.h>
 
+#include <getopt.h>
+#define OPTIONS ("c:dej:lmst:u:vz")
+
 static void __dead2
 usage(void)
 {
@@ -104,6 +107,61 @@ nosig(char *name)
        exit(1);
 }
 
+/*
+ * kludge_signal_args - remove any signal option (-SIGXXX, -##) from the argv array.
+ */
+void
+kludge_signal_args(int *argc, char **argv, int *sig)
+{
+       int i;
+       int shift = 0;
+       int kludge = 1;
+       char *ptr;
+       const char *const *p;
+       char            *ep;
+
+       /* i = 1, skip program name */
+       for (i = 1; i < *argc; i++) {
+               /* Stop if we encounter either a non-option or -- */
+               if (*argv[i] != '-' || strcmp(argv[i], "--") == 0)
+                       kludge = 0;
+               ptr = argv[i] + 1;
+               if (kludge && strchr(OPTIONS, *ptr) == NULL) {
+                       if (isalpha(*ptr)) {
+                               if (strcmp(ptr, "help") == 0)
+                                       usage();
+                               if (strncasecmp(ptr, "sig", 3) == 0)
+                                       ptr += 3;
+                               for (*sig = NSIG, p = sys_signame + 1; --*sig; ++p)
+                                       if (strcasecmp(*p, ptr) == 0) {
+                                               *sig = p - sys_signame;
+                                               break;
+                                       }
+                               if (!*sig)
+                                       nosig(ptr);
+                       } else if (isdigit(*ptr)) {
+                               *sig = strtol(ptr, &ep, 10);
+                               if (*ep)
+                                       errx(1, "illegal signal number: %s", ptr);
+                               if (*sig < 0 || *sig >= NSIG)
+                                       nosig(ptr);
+                       } else
+                               nosig(ptr);
+
+                       shift++;
+                       continue;
+               }
+
+               argv[i - shift] = argv[i];
+       }
+
+       for (i = *argc - shift; i < *argc; i++) {
+               argv[i] = NULL;
+       }
+
+       *argc -= shift;
+}
+
 int
 main(int ac, char **av)
 {
@@ -140,7 +198,6 @@ main(int ac, char **av)
 #endif /* !__APPLE__ */
        dev_t           thistdev;
        int             sig = SIGTERM;
-       const char *const *p;
        char            *ep;
        int             errors = 0;
 #ifndef __APPLE__
@@ -152,105 +209,62 @@ main(int ac, char **av)
        size_t          size;
        int             matched;
        int             killed = 0;
+       int             ch;
 
        setlocale(LC_ALL, "");
 
-       av++;
-       ac--;
+       kludge_signal_args(&ac, av, &sig);
 
-       while (ac > 0) {
-               if (strcmp(*av, "-l") == 0) {
+       while ((ch = getopt(ac, av, OPTIONS)) != -1) {
+               switch (ch) {
+               case 'c':
+                       cmd = optarg;
+                       break;
+               case 'd':
+                       dflag++;
+                       break;
+               case 'e':
+                       eflag++;
+                       break;
+#ifndef __APPLE__
+               case 'j':
+                       jflag++;
+                       jid = strtol(optarg, &ep, 10);
+                       if (*ep)
+                               errx(1, "illegal jid: %s", optarg);
+                       if (jail_attach(jid) == -1)
+                               err(1, "jail_attach(): %d", jid);
+                       break;
+#endif /* __APPLE__ */
+               case 'l':
                        printsig(stdout);
                        exit(0);
-               }
-               if (strcmp(*av, "-help") == 0)
-                       usage();
-               if (**av == '-') {
-                       ++*av;
-                       switch (**av) {
-#ifndef __APPLE__
-                       case 'j':
-                               ++*av;
-                               if (**av == '\0')
-                                       ++av;
-                               --ac;
-                               jflag++;
-                               if (!*av)
-                                       errx(1, "must specify jid");
-                               jid = strtol(*av, &ep, 10);
-                               if (!*av || *ep)
-                                       errx(1, "illegal jid: %s", *av);
-                               if (jail_attach(jid) == -1)
-                                       err(1, "jail_attach(): %d", jid);
-                               break;
-#endif /* !__APPLE__ */
-                       case 'u':
-                               ++*av;
-                               if (**av == '\0')
-                                       ++av;
-                               --ac;
-                               user = *av;
-                               break;
-                       case 't':
-                               ++*av;
-                               if (**av == '\0')
-                                       ++av;
-                               --ac;
-                               tty = *av;
-                               break;
-                       case 'c':
-                               ++*av;
-                               if (**av == '\0')
-                                       ++av;
-                               --ac;
-                               cmd = *av;
-                               break;
-                       case 'v':
-                               vflag++;
-                               break;
-                       case 's':
-                               sflag++;
-                               break;
-                       case 'd':
-                               dflag++;
-                               break;
-                       case 'e':
-                               eflag++;
-                               break;
-                       case 'm':
-                               mflag++;
-                               break;
-                       case 'z':
-                               zflag++;
-                               break;
-                       default:
-                               if (isalpha((unsigned char)**av)) {
-                                       if (strncasecmp(*av, "sig", 3) == 0)
-                                               *av += 3;
-                                       for (sig = NSIG, p = sys_signame + 1;
-                                            --sig; ++p)
-                                               if (strcasecmp(*p, *av) == 0) {
-                                                       sig = p - sys_signame;
-                                                       break;
-                                               }
-                                       if (!sig)
-                                               nosig(*av);
-                               } else if (isdigit((unsigned char)**av)) {
-                                       sig = strtol(*av, &ep, 10);
-                                       if (!*av || *ep)
-                                               errx(1, "illegal signal number: %s", *av);
-                                       if (sig < 0 || sig >= NSIG)
-                                               nosig(*av);
-                               } else
-                                       nosig(*av);
-                       }
-                       ++av;
-                       --ac;
-               } else {
+               case 'm':
+                       mflag++;
+                       break;
+               case 's':
+                       sflag++;
+                       break;
+               case 't':
+                       tty = optarg;
                        break;
+               case 'u':
+                       user = optarg;
+                       break;
+               case 'v':
+                       vflag++;
+                       break;
+               case 'z':
+                       zflag++;
+                       break;
+               default:
+                       usage();
                }
        }
 
+       ac -= optind;
+       av += optind;
+
 #ifdef __APPLE__
        if (user == NULL && tty == NULL && cmd == NULL && ac == 0)
 #else /* !__APPLE__*/
index 242d9591e2dd03ff01dcf7315426348a1aa77711..589ce7a75e9f4f3488023bbf7cb3e0152c8996fd 100644 (file)
@@ -62,7 +62,9 @@ __RCSID("$NetBSD: lastcomm.c,v 1.14 1998/04/02 10:22:03 kleink Exp $");
 #include <time.h>
 #include <tzfile.h>
 #include <unistd.h>
-#include <utmp.h>
+/* definitions from utmp.h */
+#define UT_NAMESIZE     8
+#define UT_LINESIZE     8
 #include "pathnames.h"
 
 time_t  expand __P((u_int));
index a454d076b7c8e6abb0d990524523898e5043bc89..96c5764478272ff6ac2c04880a747002b92e4e84 100644 (file)
@@ -8,6 +8,7 @@ MANPAGES = locate.1 locate.updatedb.8
             fastfind.c \
             locate.1 locate.updatedb.8 locate.rc \
             concatdb.sh mklocatedb.sh updatedb.sh
+LAUNCHD_PLISTS = com.apple.locate.plist
 
 Extra_CC_Flags = -Wall -mdynamic-no-pic
 Extra_LD_Flags = -dead_strip
diff --git a/locate/locate/com.apple.locate.plist b/locate/locate/com.apple.locate.plist
new file mode 100644 (file)
index 0000000..98703ab
--- /dev/null
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>Label</key>
+       <string>com.apple.locate</string>
+       <key>Disabled</key>
+       <true/>
+       <key>ProgramArguments</key>
+       <array>
+               <string>/usr/libexec/locate.updatedb</string>
+       </array>
+       <key>LowPriorityIO</key>
+       <true/>
+       <key>Nice</key>
+       <integer>5</integer>
+       <key>KeepAlive</key>
+       <dict>
+               <key>PathState</key>
+               <dict>
+                       <key>/var/db/locate.database</key>
+                       <false/>
+               </dict>
+       </dict>
+       <key>StartCalendarInterval</key>
+       <dict>
+               <key>Hour</key>
+               <integer>3</integer>
+               <key>Minute</key>
+               <integer>15</integer>
+               <key>Weekday</key>
+               <integer>6</integer>
+       </dict>
+       <key>AbandonProcessGroup</key>
+       <true/>
+</dict>
+</plist>
index 9383f0735219f341b6ced219d478871d0c5f70e8..e683de7e332dcd5d25540af9cedc134fca8a3506 100644 (file)
@@ -216,6 +216,14 @@ fastfind
                        count += c - OFFSET;
                }
 
+#ifdef __APPLE__
+               if (count < 0) {
+                       errx(1, "Your locate database appears to be corrupt. "
+                           "Run 'sudo /usr/libexec/locate.updatedb' to "
+                           "regenerate the database.");
+               }
+#endif /* __APPLE__ */
+
                /* overlay old path */
                p = path + count;
                foundchar = p - 1;
index 05c036ec526709dd1af3eb2b9de9ee153c96d189..cdde7183f635b3254f8e6656e7e001bb14a615ca 100644 (file)
@@ -193,13 +193,13 @@ path to the locate database if set and not empty, ignored if the
 option was specified.
 .El
 .Sh FILES
-.Bl -tag -width /etc/periodic/weekly/310.locate -compact
+.Bl -tag -width /System/Library/LaunchDaemons/com.apple.locate.plist -compact
 .It Pa /var/db/locate.database
 locate database
 .It Pa /usr/libexec/locate.updatedb
 Script to update the locate database
-.It Pa /etc/periodic/weekly/310.locate
-Script that starts the database rebuild
+.It Pa /System/Library/LaunchDaemons/com.apple.locate.plist
+Job that starts the database rebuild
 .El
 .Sh SEE ALSO
 .Xr find 1 ,
@@ -231,8 +231,8 @@ list files that have been removed from the system.
 This is because
 locate only reports files that are present in the database, which is
 typically only regenerated once a week by the
-.Pa /etc/periodic/weekly/310.locate
-script.
+.Pa /System/Library/LaunchDaemons/com.apple.locate.plist
+job.
 Use
 .Xr find 1
 to locate files that are of a more transitory nature.
index bad3e34ba85984c8642275cdde9ff2d0359285ab..315bfd3f4944abcff716d271be7eb78363eb6126 100644 (file)
@@ -81,6 +81,9 @@ static const char rcsid[] =
 #include <sys/param.h>
 #include <ctype.h>
 #include <err.h>
+#ifdef __APPLE__
+#include <errno.h>
+#endif /* __APPLE__ */
 #include <fnmatch.h>
 #include <locale.h>
 #include <stdio.h>
@@ -246,8 +249,27 @@ search_fopen(db, s)
                        *(s+1) = NULL;
                }
        } 
+#ifdef __APPLE__
+       else if ((fp = fopen(db, "r")) == NULL) {
+               if (errno == ENOENT && !strcmp(db, _PATH_FCODES)) {
+                       fprintf(stderr, "\n"
+                           "WARNING: The locate database (%s) does not exist.\n"
+                           "To create the database, run the following command:\n"
+                           "\n"
+                           "  sudo launchctl load -w /System/Library/LaunchDaemons/com.apple.locate.plist\n"
+                               "\n"
+                               "Please be aware that the database can take some time to generate; once\n"
+                               "the database has been created, this message will no longer appear.\n"
+                           "\n",
+                           db);
+                       exit(1);
+               }
+               err(1,  "`%s'", db);
+       }
+#else /* !__APPLE__ */
        else if ((fp = fopen(db, "r")) == NULL)
                err(1,  "`%s'", db);
+#endif /* __APPLE__ */
 
        /* count only chars or lines */
        if (f_statistic) {
index 12db435d434a8ddb6eaf741f126e69045729bcef..880668acf7abda00da236b0fe67d2c0d8f5a7e24 100755 (executable)
@@ -44,8 +44,8 @@ The
 utility updates the database used by
 .Xr locate 1 .
 It is typically run once a week by the
-.Pa /etc/periodic/weekly/310.locate
-script.
+.Pa /System/Library/LaunchDaemons/com.apple.locate.plist
+job.
 .Pp
 The contents of the newly built database can be controlled by the
 .Pa /etc/locate.rc
@@ -64,7 +64,7 @@ the configuration file
 .El
 .Sh SEE ALSO
 .Xr locate 1 ,
-.Xr periodic 8
+.Xr launchd 8
 .Rs
 .%A Woods, James A.
 .%D 1983
index 7baaf62e12cecda9c198b9daaf4a719cd2a94e86..1e4e8343ab41b8086a8ff7fed91ec4bff04c65a7 100644 (file)
 # $FreeBSD: src/usr.bin/locate/locate/updatedb.sh,v 1.20 2005/11/12 12:45:08 grog Exp $
 
 if [ "$(id -u)" = "0" ]; then
-       echo ">>> WARNING" 1>&2
-       echo ">>> Executing updatedb as root.  This WILL reveal all filenames" 1>&2
-       echo ">>> on your machine to all login users, which is a security risk." 1>&2
+       rc=0
+       export FCODES=`mktemp -t updatedb`
+       chown nobody $FCODES
+       tmpdb=`su -fm nobody -c "$0"` || rc=1
+       if [ $rc = 0 ]; then
+               install -m 0444 -o nobody -g wheel $FCODES /var/db/locate.database
+       fi
+       rm $FCODES
+       exit $rc
 fi
 : ${LOCATE_CONFIG="/etc/locate.rc"}
 if [ -f "$LOCATE_CONFIG" -a -r "$LOCATE_CONFIG" ]; then
@@ -47,11 +53,13 @@ fi
 
 PATH=$LIBEXECDIR:/bin:/usr/bin:$PATH; export PATH
 
+# 6497475
+set -o noglob
 
 : ${mklocatedb:=locate.mklocatedb}      # make locate database program
 : ${FCODES:=/var/db/locate.database}    # the database
 : ${SEARCHPATHS:="/"}          # directories to be put in the database
-: ${PRUNEPATHS:="/tmp /var/tmp */Backups.backupdb"} # unwanted directories
+: ${PRUNEPATHS:="/private/tmp /private/var/folders /private/var/tmp */Backups.backupdb"} # unwanted directories
 : ${FILESYSTEMS:="hfs ufs"}                     # allowed filesystems 
 : ${find:=find}
 
index 05a2765bc2200454735ec384cca90e740db3a808..e9822d34584729c33ea43cd49d1d04c878374da7 100644 (file)
@@ -30,9 +30,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\" From: $OpenBSD: mktemp.1,v 1.8 1998/03/19 06:13:37 millert Exp $
-.\" $FreeBSD: src/usr.bin/mktemp/mktemp.1,v 1.7.2.6 2001/07/22 12:40:27 dd Exp $
+.\" $FreeBSD: src/usr.bin/mktemp/mktemp.1,v 1.21 2006/09/29 15:20:46 ru Exp $
 .\"
-.Dd November 20, 1996
+.Dd December 30, 2005
 .Dt MKTEMP 1
 .Os
 .Sh NAME
 The
 .Nm
 utility takes each of the given file name templates and overwrites a
-portion of it to create a file name.  This file name is unique
-and suitable for use by the application.  The template may be
+portion of it to create a file name.
+This file name is unique
+and suitable for use by the application.
+The template may be
 any file name with some number of
 .Ql X Ns s
 appended
@@ -74,7 +76,7 @@ provided; six
 will
 result in
 .Nm
-testing roughly 26 ** 6 combinations.
+selecting 1 of 56800235584 (62 ** 6) possible file names.
 .Pp
 If
 .Nm
@@ -88,7 +90,7 @@ If the
 .Fl t Ar prefix
 option is given,
 .Nm
-will generate an template string based on the
+will generate a template string based on the
 .Ar prefix
 and the
 .Ev TMPDIR
@@ -106,15 +108,20 @@ including one based on the internal template resulting from the
 .Fl t
 flag.
 .Pp
-.Nm Mktemp
-is provided to allow shell scripts to safely use temporary files.
+The
+.Nm
+utility is provided to allow shell scripts to safely use temporary files.
 Traditionally, many shell scripts take the name of the program with
-the pid as a suffix and use that as a temporary file name.  This
+the pid as a suffix and use that as a temporary file name.
+This
 kind of naming scheme is predictable and the race condition it creates
-is easy for an attacker to win.  A safer, though still inferior, approach
-is to make a temporary directory using the same naming scheme.  While
+is easy for an attacker to win.
+A safer, though still inferior, approach
+is to make a temporary directory using the same naming scheme.
+While
 this does allow one to guarantee that a temporary file will not be
-subverted, it still allows a simple denial of service attack.  For these
+subverted, it still allows a simple denial of service attack.
+For these
 reasons it is suggested that
 .Nm
 be used instead.
@@ -124,7 +131,8 @@ The available options are as follows:
 .It Fl d
 Make a directory instead of a file.
 .It Fl q
-Fail silently if an error occurs.  This is useful if
+Fail silently if an error occurs.
+This is useful if
 a script does not want error output to go to standard error.
 .It Fl t Ar prefix
 Generate a template (using the supplied
@@ -135,14 +143,17 @@ if set) to create a filename template.
 .It Fl u
 Operate in
 .Dq unsafe
-mode.  The temp file will be unlinked before
+mode.
+The temp file will be unlinked before
 .Nm
-exits.  This is slightly better than
+exits.
+This is slightly better than
 .Xr mktemp 3
-but still introduces a race condition.  Use of this
+but still introduces a race condition.
+Use of this
 option is not encouraged.
 .El
-.Sh DIAGNOSTICS
+.Sh EXIT STATUS
 The
 .Nm
 utility
@@ -192,4 +203,4 @@ man page, and
 first appeared in
 .Fx 2.2.7 .
 This man page is taken from
-.Ox
+.Ox .
index 46e0c86e21b828d6b423f8579f7c4a5dd248b17a..6040f1636058f75ce53e9a52a55e016c66186c43 100644 (file)
 
 #ifndef lint
 static const char rcsid[] =
-       "$FreeBSD: src/usr.bin/mktemp/mktemp.c,v 1.2.6.1 2000/10/15 11:37:43 alex Exp $";
+       "$FreeBSD: src/usr.bin/mktemp/mktemp.c,v 1.5 2002/03/22 01:33:17 imp Exp $";
 #endif /* not lint */
 
-static void usage __P((void));
+static void usage(void);
 
 int
 main(int argc, char **argv)
 {
        int c, fd, ret;
-       char *tmpdir, *prefix;
+       char *tmpdir;
+       const char *prefix;
        char *name;
        int dflag, qflag, tflag, uflag;
 
@@ -90,8 +91,13 @@ main(int argc, char **argv)
                tmpdir = getenv("TMPDIR");
                if (tmpdir == NULL)
                        asprintf(&name, "%s%s.XXXXXXXX", _PATH_TMP, prefix);
-               else
-                       asprintf(&name, "%s/%s.XXXXXXXX", tmpdir, prefix);
+               else {
+                       int len = strlen(tmpdir);
+                       if (len > 0 && tmpdir[len - 1] == '/')
+                               asprintf(&name, "%s%s.XXXXXXXX", tmpdir, prefix);
+                       else
+                               asprintf(&name, "%s/%s.XXXXXXXX", tmpdir, prefix);
+               }
                /* if this fails, the program is in big trouble already */
                if (name == NULL) {
                        if (qflag)
@@ -110,6 +116,7 @@ main(int argc, char **argv)
                        argv++;
                        argc--;
                }
+
                if (dflag) {
                        if (mkdtemp(name) == NULL) {
                                ret = 1;
index fba4399b975c946401677eafb0831ed5106411c6..34f19e6c76f2f8df2eb77342af0d01918f7299d6 100644 (file)
@@ -1,5 +1,3 @@
-.\"    $NetBSD: nohup.1,v 1.6 1997/10/19 10:23:25 lukem Exp $
-.\"
 .\" Copyright (c) 1989, 1990, 1993
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
 .\" SUCH DAMAGE.
 .\"
 .\"    @(#)nohup.1     8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/nohup/nohup.1,v 1.13 2005/01/17 07:44:27 ru Exp $
 .\"
-.Dd June 6, 1993
+.Dd July 19, 2001
 .Dt NOHUP 1
 .Os
 .Sh NAME
 .Nm nohup
-.Nd invoke a command immune to hangups
+.Nd invoke a utility immune to hangups
 .Sh SYNOPSIS
 .Nm
+.Op Fl Fl
 .Ar utility
-.Op Ar arg ...
+.Op Ar arguments
 .Sh DESCRIPTION
 The
 .Nm
 utility invokes
-.Ar command
-with
-its arguments
+.Ar utility
+with its
+.Ar arguments
 and at this time sets the signal
 .Dv SIGHUP
-to be ignored. 
+to be ignored.
 If the standard output is a terminal, the standard output is
 appended to the file
 .Pa nohup.out
 in the current directory.
 If standard error is a terminal, it is directed to the same place
 as the standard output.
+.Pp
+Some shells may provide a builtin
+.Nm
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
 .Sh ENVIRONMENT
-The following variable is utilized by
-.Nm .
+The following variables are utilized by
+.Nm :
 .Bl -tag -width flag
 .It Ev HOME
 If the output file
@@ -74,32 +81,44 @@ cannot be created in the current directory, the
 utility uses the directory named by
 .Ev HOME
 to create the file.
+.It Ev PATH
+Used to locate the requested
+.Ar utility
+if the name contains no
+.Ql /
+characters.
 .El
-.Sh DIAGNOSTICS
+.Sh EXIT STATUS
 The
 .Nm
-utility shall exit with one of the following values:
-.Bl -tag -width Ds 
+utility exits with one of the following values:
+.Bl -tag -width Ds
 .It 126
 The
 .Ar utility
-was found but could not be invoked.
+was found, but could not be invoked.
 .It 127
 The
 .Ar utility
-could not be found or an error occurred in 
+could not be found or an error occurred in
 .Nm .
 .El
 .Pp
-Otherwise, the exit status of 
+Otherwise, the exit status of
 .Nm
-shall be that of 
+will be that of
 .Ar utility .
 .Sh SEE ALSO
+.Xr builtin 1 ,
+.Xr csh 1 ,
 .Xr signal 3
 .Sh STANDARDS
 The
 .Nm
-command is expected to be
+utility is expected to be
 .St -p1003.2
 compatible.
+.Sh BUGS
+Two or more instances of
+.Nm
+can append to the same file, which makes for a confusing output.
index cea00b77e400005a1acd0666b396881537d6f532..4262680f9ae42bb613514c64759d2fab0433cae9 100644 (file)
@@ -95,8 +95,8 @@ main(int argc, char *argv[])
        (void)signal(SIGHUP, SIG_IGN);
 
 #ifdef __APPLE__
-       if (_vprocmgr_move_subset_to_user(geteuid(), "Background") != NULL)
-               err(EXIT_MISC, "can't migrate to background session");
+       if (_vprocmgr_detach_from_console(0) != NULL)
+               err(EXIT_MISC, "can't detach from console");
 #endif
        execvp(*argv, argv);
        exit_status = (errno == ENOENT) ? EXIT_NOTFOUND : EXIT_NOEXEC;
diff --git a/path_helper/Makefile b/path_helper/Makefile
new file mode 100644 (file)
index 0000000..6979d34
--- /dev/null
@@ -0,0 +1,10 @@
+Project = path_helper
+Install_Dir = /usr/libexec
+
+CFILES = path_helper.c
+MANPAGES = path_helper.8
+
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_LD_Flags = -dead_strip
+
+include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/path_helper/path_helper.8 b/path_helper/path_helper.8
new file mode 100644 (file)
index 0000000..c86f2d7
--- /dev/null
@@ -0,0 +1,76 @@
+.\"
+.\" Copyright (c) 2007 Apple Inc.  All rights reserved.
+.\"
+.\" @APPLE_LICENSE_HEADER_START@
+.\" 
+.\" This file contains Original Code and/or Modifications of Original Code
+.\" as defined in and that are subject to the Apple Public Source License
+.\" Version 2.0 (the 'License'). You may not use this file except in
+.\" compliance with the License. Please obtain a copy of the License at
+.\" http://www.opensource.apple.com/apsl/ and read it before using this
+.\" file.
+.\" 
+.\" The Original Code and all software distributed under the License are
+.\" distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+.\" EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+.\" INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+.\" FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+.\" Please see the License for the specific language governing rights and
+.\" limitations under the License.
+.\" 
+.\" @APPLE_LICENSE_HEADER_END@
+.\"
+.Dd March 15, 2007
+.Dt path_helper 8
+.Os "Mac OS X"
+.Sh NAME
+.Nm path_helper
+.Nd helper for constructing PATH environment variable
+.Sh SYNOPSIS
+.Nm
+.Op Fl c | Fl s
+.Sh DESCRIPTION
+The
+.Nm
+utility reads the contents of the files in the directories
+.Pa /etc/paths.d
+and
+.Pa /etc/manpaths.d
+and appends their contents to the
+.Ev PATH
+and
+.Ev MANPATH
+environment variables respectively.
+(The
+.Ev MANPATH
+environment variable will not be modified unless it is already set
+in the environment.)
+.Pp
+Files in these directories should contain one path element per line.
+.Pp
+Prior to reading these directories, default
+.Ev PATH
+and
+.Ev MANPATH
+values are obtained from the files
+.Pa /etc/paths
+and
+.Pa /etc/manpaths
+respectively.
+.Pp
+Options:
+.Bl -tag -width Ds
+.It Fl c
+Generate C-shell commands on stdout.  This is the default if
+.Ev SHELL
+ends with "csh".
+.It Fl s
+Generate Bourne shell commands on stdout.  This is the default if
+.Ev SHELL
+does not end with "csh".
+.El
+.Sh NOTE
+The
+.Nm 
+utility should not be invoked directly.
+It is intended only for use by the shell profile.
diff --git a/path_helper/path_helper.c b/path_helper/path_helper.c
new file mode 100644 (file)
index 0000000..ff5c55a
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2008 Apple Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ * 
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apple Public Source License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://www.opensource.apple.com/apsl/ and read it before using this
+ * file.
+ * 
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ * 
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <fts.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <limits.h>
+
+static void usage() {
+       fprintf(stderr, "usage: path_helper [-c | -s]");
+       exit(1);
+}
+
+// Append path segment if it does not exist.  Reallocate
+// the path buffer as necessary.
+
+int append_path_segment(char** path, const char* segment) {
+       if (*path == NULL || segment == NULL) return -1;
+
+       size_t pathlen = strlen(*path);
+       size_t seglen = strlen(segment);
+
+       if (seglen == 0) return 0;
+
+       // Does the segment already exist in the path?
+       // (^|:)segment(:|$)
+       char* match = strstr(*path, segment);
+       while (match) {
+               if ((match == *path || match[-1] == ':') &&
+                       (match[seglen] == ':' || match[seglen] == 0)) {
+                       return 0;
+               }
+               match = strstr(match+1, segment);
+       }
+       
+       // size = pathlen + ':' + segment + '\0'
+       size_t size = pathlen + seglen + 2;
+       *path = reallocf(*path, size);
+       if (*path == NULL) return -1;
+
+       if (pathlen > 0) strlcat(*path, ":", size);
+       strlcat(*path, segment, size);
+       return 0;
+}
+
+// Convert fgetln output into a sanitized segment
+// escape quotes, dollars, etc.
+char* read_segment(const char* line, size_t len) {
+       int escapes = 0;
+       size_t i, j;
+       
+       for (i = 0; i < len; ++i) {
+               char c = line[i];
+               if (c == '\"' || c == '\'' || c == '$') {
+                       ++escapes;
+               }
+       }
+
+       size_t size = len + escapes + 1;
+
+       char* segment = malloc(size);
+       if (segment == NULL) return NULL;
+       
+       for (i = 0, j = 0; i < len; ++i, ++j) {
+               char c = line[i];
+               if (c == '\"' || c == '\'' || c == '$') {
+                       segment[j++] = '\\';
+                       segment[j] = c;
+               } else if (c == '\n') {
+                       segment[j] = 0;
+                       break;
+               } else {
+                       segment[j] = line[i];
+               }
+       }
+
+       return segment;
+}
+
+// Construct a path variable, starting with the contents
+// of the given environment variable, adding the contents
+// of the default file and files in the path directory.
+
+char* construct_path(char* env_var, char* defaults_path, char* dir_path) {
+       FTS* fts;
+       FTSENT* ent;
+
+       char* result = calloc(sizeof(char), 1);
+
+       char* dirpathv[] = { defaults_path, dir_path, NULL };
+       fts = fts_open(dirpathv, FTS_PHYSICAL | FTS_XDEV, NULL);
+       if (!fts) {
+               perror(dir_path);
+               return NULL;
+       }
+
+       while ((ent = fts_read(fts)) != NULL) {
+               // only interested in regular files, one level deep
+               if (ent->fts_info != FTS_F) {
+                       if (ent->fts_level >= 1) fts_set(fts, ent, FTS_SKIP);
+                       continue;
+               }
+
+               FILE* f = fopen(ent->fts_accpath, "r");
+               if (f == NULL) {
+                       perror(ent->fts_accpath);
+                       continue;
+               }
+
+               for (;;) {
+                       size_t len;
+                       char* line = fgetln(f, &len);
+                       if (line == NULL) break;
+                       char* segment = read_segment(line, len);
+                       
+                       append_path_segment(&result, segment);
+               }
+
+               fclose(f);
+       }
+       fts_close(fts);
+       
+       // merge in any existing custom PATH elemenets
+       char* str = getenv(env_var);
+       if (str) str = strdup(str);
+       while (str) {
+               char* sep = strchr(str, ':');
+               if (sep) *sep = 0;
+               
+               append_path_segment(&result, str);
+               if (sep) {
+                       str = sep + 1;
+               } else {
+                       str = NULL;
+               }
+       }
+       
+       return result;
+}
+
+enum {
+       STYLE_CSH,
+       STYLE_SH
+};
+
+int main(int argc, char* argv[]) {
+       int style = STYLE_SH;
+
+       if (argc > 2) usage();
+       
+       // default to csh style, if $SHELL ends with "csh".
+       char* shell = getenv("SHELL");
+       if (shell) {
+               char* str = strstr(shell, "csh");
+               if (str) style = STYLE_CSH;
+       }
+       
+       if (argc == 2 && strcmp(argv[1], "-c") == 0) style = STYLE_CSH;
+       if (argc == 2 && strcmp(argv[1], "-s") == 0) style = STYLE_SH;
+
+       char* path = construct_path("PATH", "/etc/paths", "/etc/paths.d");
+       char* manpath = NULL;
+
+       // only adjust manpath if already set
+       int do_manpath = (getenv("MANPATH") != NULL);
+       if (do_manpath) {
+               manpath = construct_path("MANPATH", "/etc/manpaths", "/etc/manpaths.d");
+       }
+
+       if (style == STYLE_CSH) {
+               printf("setenv PATH \"%s\";\n", path);
+               if (do_manpath) printf("setenv MANPATH \"%s\";\n", manpath);
+       } else {
+               printf("PATH=\"%s\"; export PATH;\n", path);
+               if (do_manpath) printf("MANPATH=\"%s\"; export MANPATH;\n", manpath);
+       }
+
+       return 0;
+}
index 6598d4e3d796ae44396fcc6bb9f7eea144f24db6..fcdbfb335cc59ed6799b4c997206b25bcd2062a2 100644 (file)
@@ -1,5 +1,3 @@
-.\"    $NetBSD: printf.1,v 1.10 1998/08/22 14:54:48 garbled Exp $
-.\"
 .\" Copyright (c) 1989, 1990, 1993
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    from: @(#)printf.1      8.1 (Berkeley) 6/6/93
+.\"    @(#)printf.1    8.1 (Berkeley) 6/6/93
+.\" $FreeBSD: src/usr.bin/printf/printf.1,v 1.34 2005/06/14 11:50:52 ru Exp $
 .\"
-.Dd November 5, 1993
+.Dd April 14, 2005
 .Dt PRINTF 1
 .Os
 .Sh NAME
 .Nd formatted output
 .Sh SYNOPSIS
 .Nm
-.Ar format
-.Op Ar arguments  ...
+.Ar format Op Ar arguments ...
 .Sh DESCRIPTION
 The
 .Nm
 utility formats and prints its arguments, after the first, under control
 of the
-.Ar format  .
+.Ar format .
 The
 .Ar format
 is a character string which contains three types of objects: plain characters,
 which are simply copied to standard output, character escape sequences which
 are converted and copied to the standard output, and format specifications,
 each of which causes printing of the next successive
-.Ar argument  .
+.Ar argument .
 .Pp
 The
 .Ar arguments
 after the first are treated as strings if the corresponding format is
 either
-.Cm b ,
-.Cm c
+.Cm c , b
 or
 .Cm s ;
 otherwise it is evaluated as a C constant, with the following extensions:
@@ -74,27 +71,29 @@ otherwise it is evaluated as a C constant, with the following extensions:
 .It
 A leading plus or minus sign is allowed.
 .It
-If the leading character is a single or double quote, the value is the 
+If the leading character is a single or double quote, the value is the
 .Tn ASCII
 code of the next character.
 .El
 .Pp
 The format string is reused as often as necessary to satisfy the
-.Ar arguments  .
+.Ar arguments .
 Any extra format specifications are evaluated with zero or the null
 string.
 .Pp
-Character escape sequences are in backslash notation as defined in 
-.St -ansiC .
+Character escape sequences are in backslash notation as defined in the
+.St -ansiC ,
+with extensions.
 The characters and their meanings
 are as follows:
-.Bl -tag -width Ds -offset indent
-.It Cm \ee
-Write an <escape> character.
+.Pp
+.Bl -tag -width Ds -offset indent -compact
 .It Cm \ea
 Write a <bell> character.
 .It Cm \eb
 Write a <backspace> character.
+.It Cm \ec
+Ignore remaining characters in this string.
 .It Cm \ef
 Write a <form-feed> character.
 .It Cm \en
@@ -109,7 +108,8 @@ Write a <vertical tab> character.
 Write a <single quote> character.
 .It Cm \e\e
 Write a backslash character.
-.It Cm \e Ns Ar num 
+.It Cm \e Ns Ar num
+.It Cm \e0 Ns Ar num
 Write an 8-bit character whose
 .Tn ASCII
 value is the 1-, 2-, or 3-digit
@@ -126,31 +126,31 @@ in the following order:
 .Bl -tag -width Ds
 .It Cm #
 A `#' character
-specifying that the value should be printed in an ``alternative form''.
+specifying that the value should be printed in an ``alternate form''.
 For
-.Cm c  ,
-.Cm d ,
+.Cm c , d ,
 and
-.Cm s  ,
-formats, this option has no effect.  For the
+.Cm s ,
+formats, this option has no effect.
+For the
 .Cm o
 formats the precision of the number is increased to force the first
-character of the output string to a zero.  For the
+character of the output string to a zero.
+For the
 .Cm x
 .Pq Cm X
 format, a non-zero result has the string
 .Li 0x
 .Pq Li 0X
-prepended to it.  For
-.Cm e  ,
-.Cm E ,
-.Cm f  ,
-.Cm g ,
+prepended to it.
+For
+.Cm e , E , f , g ,
 and
-.Cm G  ,
+.Cm G ,
 formats, the result will always contain a decimal point, even if no
 digits follow the point (normally, a decimal point only appears in the
-results of those formats if a digit follows the decimal point).  For
+results of those formats if a digit follows the decimal point).
+For
 .Cm g
 and
 .Cm G
@@ -165,10 +165,12 @@ A `+' character specifying that there should always be
 a sign placed before the number when using signed formats.
 .It Sq \&\ \&
 A space specifying that a blank should be left before a positive number
-for a signed format.  A `+' overrides a space if both are used;
+for a signed format.
+A `+' overrides a space if both are used;
 .It Cm \&0
 A zero `0' character indicating that zero-padding should be used
-rather than blank-padding.  A `\-' overrides a `0' if both are used;
+rather than blank-padding.
+A `\-' overrides a `0' if both are used;
 .El
 .It "Field Width:"
 An optional digit string specifying a
@@ -185,14 +187,21 @@ followed by an optional digit string giving a
 which specifies the number of digits to appear after the decimal point,
 for
 .Cm e
-and 
+and
 .Cm f
 formats, or the maximum number of characters to be printed
 from a string; if the digit string is missing, the precision is treated
 as zero;
 .It Format:
 A character which indicates the type of format to use (one of
-.Cm diouxXfwEgGbcs ) .
+.Cm diouxXfFeEgGaAcsb ) .
+The uppercase formats differ from their lowercase counterparts only in
+that the output of the former is entirely in uppercase.
+The floating-point format specifiers
+.Pq Cm fFeEgGaA
+may be prefixed by an
+.Cm L
+to request that additional precision be used, if available.
 .El
 .Pp
 A field width or precision may be
@@ -209,43 +218,62 @@ The
 .Ar argument
 is printed as a signed decimal (d or i), unsigned octal, unsigned decimal,
 or unsigned hexadecimal (X or x), respectively.
-.It Cm f
+.It Cm fF
 The
 .Ar argument
-is printed in the style 
-.Sm off
-.Pf [\-]ddd Cm \&. No ddd
-.Sm on
-where the number of d's
+is printed in the style `[\-]ddd.ddd' where the number of d's
 after the decimal point is equal to the precision specification for
 the argument.
 If the precision is missing, 6 digits are given; if the precision
 is explicitly 0, no digits and no decimal point are printed.
+The values \*[If] and \*[Na] are printed as
+.Ql inf
+and
+.Ql nan ,
+respectively.
 .It Cm eE
 The
 .Ar argument
-is printed in the style 
+is printed in the style
+.Cm e
 .Sm off
-.Pf [\-]d Cm \&. No ddd Cm e No \\*(Pmdd
+.Sq Op - Ar d.ddd No \(+- Ar dd
 .Sm on
 where there
 is one digit before the decimal point and the number after is equal to
 the precision specification for the argument; when the precision is
 missing, 6 digits are produced.
-An upper-case E is used for an `E' format.
+The values \*[If] and \*[Na] are printed as
+.Ql inf
+and
+.Ql nan ,
+respectively.
 .It Cm gG
 The
 .Ar argument
 is printed in style
 .Cm f
+.Pq Cm F
 or in style
 .Cm e
 .Pq Cm E
 whichever gives full precision in minimum space.
-.It Cm b
-Characters from the string
+.It Cm aA
+The
 .Ar argument
-are printed with backslash-escape sequences expanded.
+is printed in style
+.Sm off
+.Sq Op - Ar h.hhh No \(+- Li p Ar d
+.Sm on
+where there is one digit before the hexadecimal point and the number
+after is equal to the precision specification for the argument;
+when the precision is missing, enough digits are produced to convey
+the argument's exact double-precision floating-point representation.
+The values \*[If] and \*[Na] are printed as
+.Ql inf
+and
+.Ql nan ,
+respectively.
 .It Cm c
 The first character of
 .Ar argument
@@ -256,29 +284,71 @@ Characters from the string
 are printed until the end is reached or until the number of characters
 indicated by the precision specification is reached; however if the
 precision is 0 or missing, all characters in the string are printed.
+.It Cm b
+As for
+.Cm s ,
+but interpret character escapes in backslash notation in the string
+.Ar argument .
 .It Cm \&%
 Print a `%'; no argument is used.
 .El
 .Pp
+The decimal point
+character is defined in the program's locale (category
+.Dv LC_NUMERIC ) .
+.Pp
 In no case does a non-existent or small field width cause truncation of
 a field; padding takes place only if the specified field width exceeds
 the actual width.
-.Sh RETURN VALUES
-.Nm
-exits 0 on success, 1 on failure.
+.Sh EXIT STATUS
+.Ex -std
+.Sh COMPATIBILITY
+The traditional
+.Bx
+behavior of converting arguments of numeric formats not beginning
+with a digit to the
+.Tn ASCII
+code of the first character is not supported.
 .Sh SEE ALSO
 .Xr echo 1 ,
 .Xr printf 3
 .Sh STANDARDS
 The
 .Nm
-utility mostly conforms to 
-.St -p1003.2-92 .
+command is expected to be mostly compatible with the
+.St -p1003.2
+specification.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.3 Reno .
+It is modeled
+after the standard library function,
+.Xr printf 3 .
 .Sh BUGS
 Since the floating point numbers are translated from
 .Tn ASCII
 to floating-point and
 then back again, floating-point precision may be lost.
+(By default, the number is translated to an IEEE-754 double-precision
+value before being printed.
+The
+.Cm L
+modifier may produce additional precision, depending on the hardware platform.)
+.Pp
+.Tn ANSI
+hexadecimal character constants were deliberately not provided.
+.Pp
+The escape sequence \e000 is the string terminator.
+When present in the argument for the
+.Cm b
+format, the argument will be truncated at the \e000 character.
+.Pp
+Multibyte characters are not recognized in format strings (this is only
+a problem if
+.Ql %
+can appear inside a multibyte character).
 .Pp
 Parsing of - arguments is also somewhat different from
 .Xr printf 3 ,
index 9ac5fbd40f40e70f01a009f5bf2988458cf9531d..5c82411c08d9bb5a2c51514e4906a614723b67cb 100644 (file)
@@ -1,5 +1,3 @@
-/*     $NetBSD: printf.c,v 1.19 1998/02/03 03:10:15 perry Exp $        */
-
 /*
  * Copyright (c) 1989, 1993
  *     The Regents of the University of California.  All rights reserved.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
-#ifndef lint
 #if !defined(BUILTIN) && !defined(SHELL)
-__COPYRIGHT("@(#) Copyright (c) 1989, 1993\n\
-       The Regents of the University of California.  All rights reserved.\n");
-#endif
+#ifndef lint
+static char const copyright[] =
+"@(#) Copyright (c) 1989, 1993\n\
+       The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
 #endif
 
 #ifndef lint
 #if 0
-static char sccsid[] = "@(#)printf.c   8.2 (Berkeley) 3/22/95";
-#else
-__RCSID("$NetBSD: printf.c,v 1.19 1998/02/03 03:10:15 perry Exp $");
+static char const sccsid[] = "@(#)printf.c     8.1 (Berkeley) 7/20/93";
 #endif
+static const char rcsid[] =
+  "$FreeBSD: src/usr.bin/printf/printf.c,v 1.37 2005/08/05 08:18:00 stefanf Exp $";
 #endif /* not lint */
 
 #include <sys/types.h>
 
-#include <ctype.h>
 #include <err.h>
 #include <errno.h>
+#include <inttypes.h>
 #include <limits.h>
-#include <locale.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
 #include <string.h>
 #include <unistd.h>
 
-static int      print_escape_str __P((const char *));
-static size_t   print_escape __P((const char *));
-
-static int      getchr __P((void));
-static double   getdouble __P((void));
-static int      getint __P((void));
-static long     getlong __P((void));
-static unsigned long getulong __P ((void));
-static char    *getstr __P((void));
-static char    *mklong __P((const char *, int)); 
-static void      check_conversion __P((const char *, const char *));
-static void     usage __P((void)); 
-     
-static int     rval;
-static char  **gargv;
-
-#ifdef BUILTIN
-int progprintf __P((int, char **));
-#else
-int main __P((int, char **));
-#endif
-
-#define isodigit(c)    ((c) >= '0' && (c) <= '7')
-#define octtobin(c)    ((c) - '0')
-#define hextobin(c)    ((c) >= 'A' && (c) <= 'F' ? c - 'A' + 10 : (c) >= 'a' && (c) <= 'f' ? c - 'a' + 10 : c - '0')
-
 #ifdef SHELL
 #define main printfcmd
-#ifdef __APPLE__
 #include "bltin/bltin.h"
+#include "memalloc.h"
 #else
-#include "../../bin/sh/bltin/bltin.h"
-#endif
-
-#ifdef __STDC__
-#include <stdarg.h>
-#else
-#include <vararg.h>
-#endif
-
-static void warnx __P((const char *fmt, ...));
-
-static void 
-#ifdef __STDC__
-warnx(const char *fmt, ...)
-#else
-warnx(fmt, va_alist)
-       const char *fmt;
-       va_dcl
+#define        warnx1(a, b, c)         warnx(a)
+#define        warnx2(a, b, c)         warnx(a, b)
+#define        warnx3(a, b, c)         warnx(a, b, c)
 #endif
-{
-       
-       char buf[64];
-       va_list ap;
 
-#ifdef __STDC__
-       va_start(ap, fmt);
-#else
-       va_start(ap);
+#ifndef BUILTIN
+#include <locale.h>
 #endif
-       vsprintf(buf, fmt, ap);
-       va_end(ap);
-
-       error(buf);
-}
-#endif /* SHELL */
 
-#define PF(f, func) { \
-       if (fieldwidth) \
-               if (precision) \
-                       (void)printf(f, fieldwidth, precision, func); \
+#define PF(f, func) do { \
+       char *b = NULL; \
+       if (havewidth) \
+               if (haveprec) \
+                       (void)asprintf(&b, f, fieldwidth, precision, func); \
                else \
-                       (void)printf(f, fieldwidth, func); \
-       else if (precision) \
-               (void)printf(f, precision, func); \
+                       (void)asprintf(&b, f, fieldwidth, func); \
+       else if (haveprec) \
+               (void)asprintf(&b, f, precision, func); \
        else \
-               (void)printf(f, func); \
-}
+               (void)asprintf(&b, f, func); \
+       if (b) { \
+               (void)fputs(b, stdout); \
+               free(b); \
+       } \
+} while (0)
+
+static int      asciicode(void);
+static char    *doformat(char *, int *);
+static int      escape(char *, int, size_t *);
+static int      getchr(void);
+static int      getfloating(long double *, int);
+static int      getint(int *);
+static int      getnum(intmax_t *, uintmax_t *, int);
+static const char
+               *getstr(void);
+static char    *mknum(char *, int);
+static void     usage(void);
+
+static char **gargv;
 
 int
 #ifdef BUILTIN
-progprintf(argc, argv)
+progprintf(int argc, char *argv[])
 #else
-main(argc, argv)
+main(int argc, char *argv[])
 #endif
-       int argc;
-       char *argv[];
 {
-       char *fmt, *start;
-       int fieldwidth, precision;
-       char convch, nextch;
-       char *format;
-       int ch;
+       size_t len;
+       int ch, chopped, end, rval;
+       char *format, *fmt, *start;
 
-#if !defined(SHELL) && !defined(BUILTIN)
-       (void)setlocale (LC_ALL, "");
+#ifndef BUILTIN
+       (void) setlocale(LC_NUMERIC, "");
 #endif
-
-       while ((ch = getopt(argc, argv, "")) != -1) {
+       while ((ch = getopt(argc, argv, "")) != -1)
                switch (ch) {
                case '?':
                default:
                        usage();
                        return (1);
                }
-       }
        argc -= optind;
        argv += optind;
 
@@ -176,375 +132,426 @@ main(argc, argv)
                return (1);
        }
 
-       format = *argv;
+       /*
+        * Basic algorithm is to scan the format string for conversion
+        * specifications -- once one is found, find out if the field
+        * width or precision is a '*'; if it is, gather up value.  Note,
+        * format strings are reused as necessary to use up the provided
+        * arguments, arguments of zero/null string are provided to use
+        * up the format string.
+        */
+       fmt = format = *argv;
+       chopped = escape(fmt, 1, &len);         /* backslash interpretation */
+       rval = end = 0;
        gargv = ++argv;
-
-#define SKIP1  "#-+ 0"
-#define SKIP2  "*0123456789"
-       do {
-               /*
-                * Basic algorithm is to scan the format string for conversion
-                * specifications -- once one is found, find out if the field
-                * width or precision is a '*'; if it is, gather up value. 
-                * Note, format strings are reused as necessary to use up the
-                * provided arguments, arguments of zero/null string are 
-                * provided to use up the format string.
-                */
-
-               /* find next format specification */
-               for (fmt = format; *fmt; fmt++) {
-                       switch (*fmt) {
-                       case '%':
-                               start = fmt++;
-
-                               if (*fmt == '%') {
-                                       (void)putchar('%');
-                                       break;
-                               } else if (*fmt == 'b') {
-                                       char *p = getstr();
-                                       if (print_escape_str(p)) {
-                                               return (rval);
-                                       }
-                                       break;
-                               }
-
-                               /* skip to field width */
-                               for (; strchr(SKIP1, *fmt); ++fmt) ;
-                               fieldwidth = *fmt == '*' ? getint() : 0;
-
-                               /* skip to possible '.', get following precision */
-                               for (; strchr(SKIP2, *fmt); ++fmt) ;
-                               if (*fmt == '.')
-                                       ++fmt;
-                               precision = *fmt == '*' ? getint() : 0;
-
-                               for (; strchr(SKIP2, *fmt); ++fmt) ;
-                               if (!*fmt) {
-                                       warnx ("missing format character");
-                                       return(1);
-                               }
-
-                               convch = *fmt;
-                               nextch = *(fmt + 1);
-                               *(fmt + 1) = '\0';
-                               switch(convch) {
-                               case 'c': {
-                                       char p = getchr();
-                                       PF(start, p);
-                                       break;
-                               }
-                               case 's': {
-                                       char *p = getstr();
-                                       PF(start, p);
-                                       break;
-                               }
-                               case 'd':
-                               case 'i': {
-                                       char *f = mklong(start, convch);
-                                       long p = getlong();
-                                       PF(f, p);
-                                       break;
+       for (;;) {
+               start = fmt;
+               while (fmt < format + len) {
+                       if (fmt[0] == '%') {
+                               fwrite(start, 1, fmt - start, stdout);
+                               if (fmt[1] == '%') {
+                                       /* %% prints a % */
+                                       putchar('%');
+                                       fmt += 2;
+                               } else {
+                                       fmt = doformat(fmt, &rval);
+                                       if (fmt == NULL)
+                                               return (1);
+                                       end = 0;
                                }
-                               case 'o':
-                               case 'u':
-                               case 'x':
-                               case 'X': {
-                                       char *f = mklong(start, convch);
-                                       unsigned long p = getulong();
-                                       PF(f, p);
-                                       break;
-                               }
-                               case 'e':
-                               case 'E':
-                               case 'f':
-                               case 'g':
-                               case 'G': {
-                                       double p = getdouble();
-                                       PF(start, p);
-                                       break;
-                               }
-                               default:
-                                       warnx ("%s: invalid directive", start);
-                                       return(1);
-                               }
-                               *(fmt + 1) = nextch;
-                               break;
-
-                       case '\\':
-                               fmt += print_escape(fmt);
-                               break;
-
-                       default:
-                               (void)putchar(*fmt);
-                               break;
-                       }
+                               start = fmt;
+                       } else
+                               fmt++;
                }
-       } while (gargv > argv && *gargv);
 
-       return (rval);
+               if (end == 1) {
+                       warnx1("missing format character", NULL, NULL);
+                       return (1);
+               }
+               fwrite(start, 1, fmt - start, stdout);
+               if (chopped || !*gargv)
+                       return (rval);
+               /* Restart at the beginning of the format string. */
+               fmt = format;
+               end = 1;
+       }
+       /* NOTREACHED */
 }
 
 
-/*
- * Print SysV echo(1) style escape string 
- *     Halts processing string and returns 1 if a \c escape is encountered.
- */
-static int
-print_escape_str(str)
-       const char *str;
+static char *
+doformat(char *start, int *rval)
 {
-       int value;
-       int c;
-
-       while (*str) {
-               if (*str == '\\') {
-                       str++;
-                       /* 
-                        * %b string octal constants are not like those in C.
-                        * They start with a \0, and are followed by 0, 1, 2, 
-                        * or 3 octal digits. 
-                        */
-                       if (*str == '0') {
-                               str++;
-                               for (c = 3, value = 0; c-- && isodigit(*str); str++) {
-                                       value <<= 3;
-                                       value += octtobin(*str);
-                               }
-                               (void)putchar(value);
-                               str--;
-                       } else if (*str == 'c') {
-                               return 1;
-                       } else {
-                               str--;                  
-                               str += print_escape(str);
-                       }
+       static const char skip1[] = "#'-+ 0";
+       static const char skip2[] = "0123456789";
+       char *fmt;
+       int fieldwidth, haveprec, havewidth, mod_ldbl, precision;
+       char convch, nextch;
+
+       fmt = start + 1;
+       /* skip to field width */
+       fmt += strspn(fmt, skip1);
+       if (*fmt == '*') {
+               if (getint(&fieldwidth))
+                       return (NULL);
+               havewidth = 1;
+               ++fmt;
+       } else {
+               havewidth = 0;
+
+               /* skip to possible '.', get following precision */
+               fmt += strspn(fmt, skip2);
+       }
+       if (*fmt == '.') {
+               /* precision present? */
+               ++fmt;
+               if (*fmt == '*') {
+                       if (getint(&precision))
+                               return (NULL);
+                       haveprec = 1;
+                       ++fmt;
                } else {
-                       (void)putchar(*str);
+                       haveprec = 0;
+
+                       /* skip to conversion char */
+                       fmt += strspn(fmt, skip2);
                }
-               str++;
+       } else
+               haveprec = 0;
+       if (!*fmt) {
+               warnx1("missing format character", NULL, NULL);
+               return (NULL);
        }
 
-       return 0;
-}
-
-/*
- * Print "standard" escape characters 
- */
-static size_t
-print_escape(str)
-       const char *str;
-{
-       const char *start = str;
-       int value;
-       int c;
-
-       str++;
-
-       switch (*str) {
-       case '0': case '1': case '2': case '3':
-       case '4': case '5': case '6': case '7':
-               for (c = 3, value = 0; c-- && isodigit(*str); str++) {
-                       value <<= 3;
-                       value += octtobin(*str);
+       /*
+        * Look for a length modifier.  POSIX doesn't have these, so
+        * we only support them for floating-point conversions, which
+        * are extensions.  This is useful because the L modifier can
+        * be used to gain extra range and precision, while omitting
+        * it is more likely to produce consistent results on different
+        * architectures.  This is not so important for integers
+        * because overflow is the only bad thing that can happen to
+        * them, but consider the command  printf %a 1.1
+        */
+       if (*fmt == 'L') {
+               mod_ldbl = 1;
+               fmt++;
+               if (!strchr("aAeEfFgG", *fmt)) {
+                       warnx2("bad modifier L for %%%c", *fmt, NULL);
+                       return (NULL);
                }
-               (void)putchar(value);
-               return str - start - 1;
-               /* NOTREACHED */
-
-       case 'x':
-               str++;
-               for (value = 0; isxdigit(*str); str++) {
-                       value <<= 4;
-                       value += hextobin(*str);
-               }
-               if (value > UCHAR_MAX) {
-                       warnx ("escape sequence out of range for character");
-                       rval = 1;
-               }
-               (void)putchar (value);
-               return str - start - 1;
-               /* NOTREACHED */
-
-       case '\\':                      /* backslash */
-               (void)putchar('\\');
-               break;
-
-       case '\'':                      /* single quote */
-               (void)putchar('\'');
-               break;
+       } else {
+               mod_ldbl = 0;
+       }
 
-       case '"':                       /* double quote */
-               (void)putchar('"');
-               break;
+       convch = *fmt;
+       nextch = *++fmt;
+       *fmt = '\0';
+       switch (convch) {
+       case 'b': {
+               size_t len;
+               char *p;
+               int getout;
 
-       case 'a':                       /* alert */
-#ifdef __STDC__
-               (void)putchar('\a');
+#ifdef SHELL
+               p = savestr(getstr());
 #else
-               (void)putchar(007);
+               p = strdup(getstr());
 #endif
-               break;
-
-       case 'b':                       /* backspace */
-               (void)putchar('\b');
-               break;
-
-       case 'e':                       /* escape */
-#ifdef __GNUC__
-               (void)putchar('\e');
+               if (p == NULL) {
+                       warnx2("%s", strerror(ENOMEM), NULL);
+                       return (NULL);
+               }
+               getout = escape(p, 0, &len);
+               *(fmt - 1) = 's';
+               PF(start, p);
+               *(fmt - 1) = 'b';
+#ifdef SHELL
+               ckfree(p);
 #else
-               (void)putchar(033);
+               free(p);
 #endif
+               if (getout)
+                       return (fmt);
                break;
+       }
+       case 'c': {
+               char p;
 
-       case 'f':                       /* form-feed */
-               (void)putchar('\f');
-               break;
-
-       case 'n':                       /* newline */
-               (void)putchar('\n');
+               p = getchr();
+               PF(start, p);
                break;
+       }
+       case 's': {
+               const char *p;
 
-       case 'r':                       /* carriage-return */
-               (void)putchar('\r');
+               p = getstr();
+               PF(start, p);
                break;
-
-       case 't':                       /* tab */
-               (void)putchar('\t');
+       }
+       case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': {
+               char *f;
+               intmax_t val;
+               uintmax_t uval;
+               int signedconv;
+
+               signedconv = (convch == 'd' || convch == 'i');
+               if ((f = mknum(start, convch)) == NULL)
+                       return (NULL);
+               if (getnum(&val, &uval, signedconv))
+                       *rval = 1;
+               if (signedconv)
+                       PF(f, val);
+               else
+                       PF(f, uval);
                break;
-
-       case 'v':                       /* vertical-tab */
-               (void)putchar('\v');
+       }
+       case 'e': case 'E':
+       case 'f': case 'F':
+       case 'g': case 'G':
+       case 'a': case 'A': {
+               long double p;
+
+               if (getfloating(&p, mod_ldbl))
+                       *rval = 1;
+               if (mod_ldbl)
+                       PF(start, p);
+               else
+                       PF(start, (double)p);
                break;
-
+       }
        default:
-               (void)putchar(*str);
-               warnx("unknown escape sequence `\\%c'", *str);
-               rval = 1;
-               break;
+               warnx2("illegal format character %c", convch, NULL);
+               return (NULL);
        }
-
-       return 1;
+       *fmt = nextch;
+       return (fmt);
 }
 
 static char *
-mklong(str, ch)
-       const char *str;
-       char ch;
+mknum(char *str, int ch)
 {
-       static char copy[64];
-       size_t len;     
+       static char *copy;
+       static size_t copy_size;
+       char *newcopy;
+       size_t len, newlen;
 
        len = strlen(str) + 2;
-       (void)memmove(copy, str, len - 3);
-       copy[len - 3] = 'l';
+       if (len > copy_size) {
+               newlen = ((len + 1023) >> 10) << 10;
+#ifdef SHELL
+               if ((newcopy = ckrealloc(copy, newlen)) == NULL)
+#else
+               if ((newcopy = realloc(copy, newlen)) == NULL)
+#endif
+               {
+                       warnx2("%s", strerror(ENOMEM), NULL);
+                       return (NULL);
+               }
+               copy = newcopy;
+               copy_size = newlen;
+       }
+
+       memmove(copy, str, len - 3);
+       copy[len - 3] = 'j';
        copy[len - 2] = ch;
        copy[len - 1] = '\0';
-       return (copy);  
+       return (copy);
+}
+
+static int
+escape(char *fmt, int percent, size_t *len)
+{
+       char *save, *store;
+       int value, c;
+
+       for (save = store = fmt; (c = *fmt); ++fmt, ++store) {
+               if (c != '\\') {
+                       *store = c;
+                       continue;
+               }
+               switch (*++fmt) {
+               case '\0':              /* EOS, user error */
+                       *store = '\\';
+                       *++store = '\0';
+                       *len = store - save;
+                       return (0);
+               case '\\':              /* backslash */
+               case '\'':              /* single quote */
+                       *store = *fmt;
+                       break;
+               case 'a':               /* bell/alert */
+                       *store = '\a';
+                       break;
+               case 'b':               /* backspace */
+                       *store = '\b';
+                       break;
+               case 'c':
+                       *store = '\0';
+                       *len = store - save;
+                       return (1);
+               case 'f':               /* form-feed */
+                       *store = '\f';
+                       break;
+               case 'n':               /* newline */
+                       *store = '\n';
+                       break;
+               case 'r':               /* carriage-return */
+                       *store = '\r';
+                       break;
+               case 't':               /* horizontal tab */
+                       *store = '\t';
+                       break;
+               case 'v':               /* vertical tab */
+                       *store = '\v';
+                       break;
+                                       /* octal constant */
+               case '0': case '1': case '2': case '3':
+               case '4': case '5': case '6': case '7':
+                       for (c = *fmt == '0' ? 4 : 3, value = 0;
+                           c-- && *fmt >= '0' && *fmt <= '7'; ++fmt) {
+                               value <<= 3;
+                               value += *fmt - '0';
+                       }
+                       --fmt;
+                       if (percent && value == '%') {
+                               *store++ = '%';
+                               *store = '%';
+                       } else
+                               *store = value;
+                       break;
+               default:
+                       *store = *fmt;
+                       break;
+               }
+       }
+       *store = '\0';
+       *len = store - save;
+       return (0);
 }
 
 static int
-getchr()
+getchr(void)
 {
        if (!*gargv)
                return ('\0');
        return ((int)**gargv++);
 }
 
-static char *
-getstr()
+static const char *
+getstr(void)
 {
        if (!*gargv)
                return ("");
        return (*gargv++);
 }
 
-static char *Number = "+-.0123456789";
 static int
-getint()
+getint(int *ip)
 {
-       if (!*gargv)
-               return(0);
-
-       if (strchr(Number, **gargv))
-               return(atoi(*gargv++));
+       intmax_t val;
+       uintmax_t uval;
+       int rval;
 
-       return 0;
+       if (getnum(&val, &uval, 1))
+               return (1);
+       rval = 0;
+       if (val < INT_MIN || val > INT_MAX) {
+               warnx3("%s: %s", *gargv, strerror(ERANGE));
+               rval = 1;
+       }
+       *ip = (int)val;
+       return (rval);
 }
 
-static long
-getlong()
+static int
+getnum(intmax_t *ip, uintmax_t *uip, int signedconv)
 {
-       long val;
        char *ep;
+       int rval;
 
-       if (!*gargv)
-               return(0L);
-
-       if (**gargv == '\"' || **gargv == '\'')
-               return (long) *((*gargv++)+1);
-
+       if (!*gargv) {
+               *ip = 0;
+               return (0);
+       }
+       if (**gargv == '"' || **gargv == '\'') {
+               if (signedconv)
+                       *ip = asciicode();
+               else
+                       *uip = asciicode();
+               return (0);
+       }
+       rval = 0;
        errno = 0;
-       val = strtol (*gargv, &ep, 0);
-       check_conversion(*gargv++, ep);
-       return val;
+       if (signedconv)
+               *ip = strtoimax(*gargv, &ep, 0);
+       else
+               *uip = strtoumax(*gargv, &ep, 0);
+       if (ep == *gargv) {
+               warnx2("%s: expected numeric value", *gargv, NULL);
+               rval = 1;
+       }
+       else if (*ep != '\0') {
+               warnx2("%s: not completely converted", *gargv, NULL);
+               rval = 1;
+       }
+       if (errno == ERANGE) {
+               warnx3("%s: %s", *gargv, strerror(ERANGE));
+               rval = 1;
+       }
+       ++gargv;
+       return (rval);
 }
 
-static unsigned long
-getulong()
+static int
+getfloating(long double *dp, int mod_ldbl)
 {
-       unsigned long val;
        char *ep;
+       int rval;
 
-       if (!*gargv)
-               return(0UL);
-
-       if (**gargv == '\"' || **gargv == '\'')
-               return (unsigned long) *((*gargv++)+1);
-
+       if (!*gargv) {
+               *dp = 0.0;
+               return (0);
+       }
+       if (**gargv == '"' || **gargv == '\'') {
+               *dp = asciicode();
+               return (0);
+       }
+       rval = 0;
        errno = 0;
-       val = strtoul (*gargv, &ep, 0);
-       check_conversion(*gargv++, ep);
-       return val;
+       if (mod_ldbl)
+               *dp = strtold(*gargv, &ep);
+       else
+               *dp = strtod(*gargv, &ep);
+       if (ep == *gargv) {
+               warnx2("%s: expected numeric value", *gargv, NULL);
+               rval = 1;
+       } else if (*ep != '\0') {
+               warnx2("%s: not completely converted", *gargv, NULL);
+               rval = 1;
+       }
+       if (errno == ERANGE) {
+               warnx3("%s: %s", *gargv, strerror(ERANGE));
+               rval = 1;
+       }
+       ++gargv;
+       return (rval);
 }
 
-static double
-getdouble()
+static int
+asciicode(void)
 {
-       double val;
-       char *ep;
-
-       if (!*gargv)
-               return(0.0);
-
-       if (**gargv == '\"' || **gargv == '\'')
-               return (double) *((*gargv++)+1);
-
-       errno = 0;
-       val = strtod (*gargv, &ep);
-       check_conversion(*gargv++, ep);
-       return val;
-}
+       int ch;
 
-static void
-check_conversion(s, ep)
-       const char *s;
-       const char *ep;
-{
-       if (*ep) {
-               if (ep == s)
-                       warnx ("%s: expected numeric value", s);
-               else
-                       warnx ("%s: not completely converted", s);
-               rval = 1;
-       } else if (errno == ERANGE) {
-               warnx ("%s: %s", s, strerror(ERANGE));
-               rval = 1;
-       }
+       ch = **gargv;
+       if (ch == '\'' || ch == '"')
+               ch = (*gargv)[1];
+       ++gargv;
+       return (ch);
 }
 
 static void
-usage()
+usage(void)
 {
-       (void)fprintf(stderr, "usage: printf format [arg ...]\n");
+       (void)fprintf(stderr, "usage: printf format [arguments ...]\n");
 }
index f8cc3a8633f84f76f7ce7058eeede1a88ab8067d..5ed51f363bb59984f7a8f6292f72cb599946a0f6 100644 (file)
@@ -4,7 +4,8 @@ Install_Dir = /bin
 CFILES = sleep.c
 MANPAGES = sleep.1
 
-Extra_CC_Flags = -Wall -mdynamic-no-pic
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_CC_Flags += -D__FBSDID=__RCSID
 Extra_LD_Flags = -dead_strip
 
 include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
index 8ecc687ec4243340ae266ed617439ad3e838be3f..f5215be1b4da3ca9dd933afc92d79ccdc918a365 100644 (file)
@@ -1,5 +1,4 @@
-.\"    $NetBSD: sleep.1,v 1.11 1997/09/14 07:31:56 lukem Exp $
-.\"
+.\"-
 .\" Copyright (c) 1990, 1993, 1994
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
 .\" 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 University of
-.\"    California, Berkeley and its contributors.
 .\" 4. 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.
@@ -35,6 +30,7 @@
 .\" SUCH DAMAGE.
 .\"
 .\"    @(#)sleep.1     8.3 (Berkeley) 4/18/94
+.\" $FreeBSD: src/bin/sleep/sleep.1,v 1.22 2005/01/16 16:41:59 ru Exp $
 .\"
 .Dd April 18, 1994
 .Dt SLEEP 1
 .Sh DESCRIPTION
 The
 .Nm
-utility
+command
 suspends execution for a minimum of
 .Ar seconds .
-It is usually used to schedule the execution of other commands (see
-.Sx EXAMPLES
-below).
 .Pp
-The
+If the
 .Nm
-utility exits with one of the following values:
-.Bl -tag -width flag
-.It Li \&0
-On successful completion, or if the signal
+command receives a signal, it takes the standard action.
+.Sh IMPLEMENTATION NOTES
+The
 .Dv SIGALRM
-was received.
-.It Li \&>\&0
-An error occurred.
-.El
+signal is not handled specially by this implementation.
+.Pp
+The
+.Nm
+command will accept and honor a non-integer number of specified seconds
+(with a
+.Ql .\&
+character as a decimal point).
+.Bf Sy
+This is a non-portable extension, and its use will nearly guarantee that
+a shell script will not execute properly on another system.
+.Ef
+.Sh EXIT STATUS
+.Ex -std
 .Sh EXAMPLES
 To schedule the execution of a command for
 .Va x
-number seconds later:
+number seconds later (with
+.Xr csh 1 ) :
 .Pp
 .Dl (sleep 1800; sh command_file >& errors)&
 .Pp
 This incantation would wait a half hour before
-running the script command_file. (See the
+running the script command_file.
+(See the
 .Xr at 1
 utility.)
 .Pp
@@ -105,12 +109,16 @@ when the file is found, then another portion processing
 is done courteously by sleeping for 70 seconds in between each
 awk job.
 .Sh SEE ALSO
-.Xr setitimer 2 ,
-.Xr sleep 3 ,
-.Xr at 1
+.Xr nanosleep 2 ,
+.Xr sleep 3
 .Sh STANDARDS
 The
 .Nm
 command is expected to be
 .St -p1003.2
 compatible.
+.Sh HISTORY
+A
+.Nm
+command appeared in
+.At v4 .
index 87785b9772e8b8c81870f32747b81ed814aa1217..d41556cc76df68e24ed5305ca7f0210e316f2d8c 100644 (file)
@@ -1,6 +1,4 @@
-/*     $NetBSD: sleep.c,v 1.15 1998/07/28 11:41:58 mycroft Exp $       */
-
-/*
+/*-
  * Copyright (c) 1988, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  *
  * 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 University of
- *     California, Berkeley and its contributors.
  * 4. 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.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
+#if 0
 #ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1988, 1993, 1994\n\
-       The Regents of the University of California.  All rights reserved.\n");
+static char const copyright[] =
+"@(#) Copyright (c) 1988, 1993, 1994\n\
+       The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
 #ifndef lint
-#if 0
 static char sccsid[] = "@(#)sleep.c    8.3 (Berkeley) 4/2/94";
-#else
-__RCSID("$NetBSD: sleep.c,v 1.15 1998/07/28 11:41:58 mycroft Exp $");
-#endif
 #endif /* not lint */
+#endif
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/bin/sleep/sleep.c,v 1.20 2005/08/07 09:11:38 stefanf Exp $");
 
-#include <time.h>
 #include <ctype.h>
-#include <math.h>
-#include <signal.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <time.h>
 #include <unistd.h>
-#include <locale.h>
+#include <string.h>
 
-void usage __P((void));
-void alarmhandle __P((int));
-int  main __P((int, char *[]));
+void usage(void);
 
 int
-main(argc, argv)
-       int argc;
-       char *argv[];
+main(int argc, char *argv[])
 {
-       char *arg, *temp;
-       double val, ival, fval;
-       struct timespec ntime;
-       int fracflag;
-       int ch;
-
-       (void)setlocale(LC_ALL, "");
+       struct timespec time_to_sleep;
+       long l;
+       int neg;
+       char *p;
+
+       if (argc == 2) {
+           p = argv[1];
+       } else if (argc == 3 && !strcmp("--", argv[1])) {
+           // POSIX issue:   "sleep -- 3" should be the same as "sleep 3",
+           // normally getopt makes this kind of thing work, but sleep has
+           // no options, so we do it "the easy way"
+           p = argv[2];
+       } else {
+               usage();
+               return(1);
+       }
 
-       (void)signal(SIGALRM, alarmhandle);
+       /* Skip over leading whitespaces. */
+       while (isspace((unsigned char)*p))
+               ++p;
 
-       while ((ch = getopt(argc, argv, "")) != -1)
-               switch(ch) {
-               case '?':
-               default:
+       /* Check for optional `+' or `-' sign. */
+       neg = 0;
+       if (*p == '-') {
+               neg = 1;
+               ++p;
+               if (!isdigit((unsigned char)*p) && *p != '.') {
                        usage();
+                       return(1);
                }
-       argc -= optind;
-       argv += optind;
-
-       if (argc != 1)
-               usage();
-
-       /*
-        * Okay, why not just use atof for everything? Why bother
-        * checking if there is a fraction in use? Because the old
-        * sleep handled the full range of integers, that's why, and a
-        * double can't handle a large long. This is fairly useless
-        * given how large a number a double can hold on most
-        * machines, but now we won't ever have trouble. If you want
-        * 1000000000.9 seconds of sleep, well, that's your
-        * problem. Why use an isdigit() check instead of checking for
-        * a period? Because doing it this way means locales will be
-        * handled transparently by the atof code.
-        */
-       fracflag = 0;
-       arg = *argv;
-       for (temp = arg; *temp != '\0'; temp++)
-               if (!isdigit(*temp))
-                       fracflag++;
-
-       if (fracflag) {
-               val = atof(arg);
-               if (val <= 0)
-                       exit(0);
-               ival = floor(val);
-               fval = (1000000000 * (val-ival));
-               ntime.tv_sec = ival;
-               ntime.tv_nsec = fval;
        }
-       else{
-               ntime.tv_sec = atol(arg);
-               if (ntime.tv_sec <= 0)
-                       exit(0);
-               ntime.tv_nsec = 0;
+       else if (*p == '+')
+               ++p;
+
+       /* Calculate seconds. */
+       if (isdigit((unsigned char)*p)) {
+               l = strtol(p, &p, 10);
+               if (l > INT_MAX) {
+                       /*
+                        * Avoid overflow when `seconds' is huge.  This assumes
+                        * that the maximum value for a time_t is <= INT_MAX.
+                        */
+                       l = INT_MAX;
+               }
+       } else
+               l = 0;
+       time_to_sleep.tv_sec = (time_t)l;
+
+       /* Calculate nanoseconds. */
+       time_to_sleep.tv_nsec = 0;
+
+       if (*p == '.') {                /* Decimal point. */
+               l = 100000000L;
+               do {
+                       if (isdigit((unsigned char)*++p))
+                               time_to_sleep.tv_nsec += (*p - '0') * l;
+                       else
+                               break;
+                       l /= 10;
+               } while (l);
        }
 
-       (void)nanosleep(&ntime, NULL);
+       if (!neg && (time_to_sleep.tv_sec > 0 || time_to_sleep.tv_nsec > 0))
+               (void)nanosleep(&time_to_sleep, (struct timespec *)NULL);
 
-       exit(0);
-       /* NOTREACHED */
+       return(0);
 }
 
 void
-usage()
+usage(void)
 {
-       (void)fputs("usage: sleep seconds\n", stderr);
-       exit(1);
-       /* NOTREACHED */
-}
+       const char msg[] = "usage: sleep seconds\n";
 
-/* ARGSUSED */
-void
-alarmhandle(i)
-       int i;
-{
-       _exit(0);
-       /* NOTREACHED */
+       write(STDERR_FILENO, msg, sizeof(msg) - 1);
 }
index d1c21aa19e467426d4f4b400ae003cf35fda6562..5e72328ad2e7d7ff50a966d569266bd28c7c4a8e 100644 (file)
@@ -3,10 +3,13 @@ Project = su
 CFILES = su.c
 MANPAGES = su.1
 
-Extra_CC_Flags = -Wall -mdynamic-no-pic
-Extra_LD_Flags = -dead_strip \
-       -lpam -lpam_misc -lbsm
+Extra_CC_Flags = -Wall -mdynamic-no-pic -D__FBSDID=__RCSID
+Extra_LD_Flags = -dead_strip -lpam -lbsm
 
 include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
 
 Install_Program_Mode = 04555
+
+after_install:
+       $(MKDIR) $(DSTROOT)$(ETCDIR)/pam.d
+       $(INSTALL_FILE) su.pam $(DSTROOT)$(ETCDIR)/pam.d/su
diff --git a/su/su.1 b/su/su.1
index 906c9e58f8adeecd4be08c205e0da46b80687449..014a5674297a144c942db9e6dddbeedee732d2b2 100644 (file)
--- a/su/su.1
+++ b/su/su.1
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    from: @(#)su.1  8.2 (Berkeley) 4/18/94
-.\"    $NetBSD: su.1,v 1.14 1997/10/19 23:31:52 lukem Exp $
+.\"    @(#)su.1        8.2 (Berkeley) 4/18/94
+.\" $FreeBSD: src/usr.bin/su/su.1,v 1.40 2007/07/24 06:41:07 delphij Exp $
 .\"
-.Dd April 18, 1994
+.Dd September 13, 2006
 .Dt SU 1
 .Os
 .Sh NAME
 .Op Fl flm
 .Op Ar login Op Ar args
 .Sh DESCRIPTION
+The
 .Nm
-requests the password for
-.Ar login
-and switches to
-that user and group ID after obtaining proper authentication.
-A shell is then executed, and any additional
-.Ar "shell arguments"
-after the login name
-are passed to the shell.
-If
-.Nm
-is executed by root, no password is requested and a shell
-with the appropriate user ID is executed.
+utility requests appropriate user credentials via PAM
+and switches to that user ID
+(the default user is the superuser).
+A shell is then executed.
+.Pp
+PAM is used to set the policy
+.Xr su 1
+will use.
+In particular, by default only users in the
+.Dq Li admin
+or
+.Dq Li wheel
+groups can switch to UID 0
+.Pq Dq Li root .
+This group requirement may be changed by modifying the
+.Dq Li pam_group
+section of
+.Pa /etc/pam.d/su .
+See
+.Xr pam_group 8
+for details on how to modify this setting.
+.Pp
+By default, the environment is unmodified with the exception of
+.Ev USER ,
+.Ev HOME ,
+and
+.Ev SHELL .
+.Ev HOME
+and
+.Ev SHELL
+are set to the target login's default values.
+.Ev USER
+is set to the target login, unless the target login has a user ID of 0,
+in which case it is unmodified.
+The invoked shell is the one belonging to the target login.
+This is the traditional behavior of
+.Nm .
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
@@ -89,7 +115,9 @@ is imported from your current environment.
 The invoked shell is the target login's, and
 .Nm
 will change directory to the target login's home directory.
-This option is identical to just passing "-", as in "su -".
+.It Fl
+(no letter) The same as
+.Fl l .
 .It Fl m
 Leave the environment unmodified.
 The invoked shell is your login shell, and no directory changes are made.
@@ -104,40 +132,31 @@ will fail.
 .Pp
 The
 .Fl l
+(or
+.Fl )
 and
 .Fl m
 options are mutually exclusive; the last one specified
 overrides any previous ones.
 .Pp
-Only users in group
-.Dq wheel
-(normally gid 0)
-or group
-.Dq admin
-(normally gid 20) can
+If the optional
+.Ar args
+are provided on the command line, they are passed to the login shell of
+the target login.
+Note that all command line arguments before the target login name are
+processed by
 .Nm
-to
-.Dq root .
+itself, everything after the target login name gets passed to the login
+shell.
 .Pp
 By default (unless the prompt is reset by a startup file) the super-user
 prompt is set to
 .Dq Sy \&#
 to remind one of its awesome power.
-.Sh SEE ALSO
-.Xr csh 1 ,
-.Xr login 1 ,
-.Xr sh 1 ,
-.Xr skey 1 ,
-.Xr kinit 1 ,
-.Xr kerberos 1 ,
-.Xr passwd 5 ,
-.Xr group 5 ,
-.Xr environ 7
 .Sh ENVIRONMENT
 Environment variables used by
-.Nm 
-:
-.Bl -tag -width "HOME"
+.Nm :
+.Bl -tag -width HOME
 .It Ev HOME
 Default home directory of real user ID unless modified as
 specified above.
@@ -151,8 +170,44 @@ The user ID is always the effective ID (the target user ID) after an
 .Nm
 unless the user ID is 0 (root).
 .El
+.Sh FILES
+.Bl -tag -width ".Pa /etc/pam.d/su" -compact
+.It Pa /etc/pam.d/su
+PAM configuration for
+.Nm .
+.El
+.Sh EXAMPLES
+.Bl -tag -width 5n -compact
+.It Li "su man -c catman"
+Runs the command
+.Li catman
+as user
+.Li man .
+You will be asked for man's password unless your real UID is 0.
+.It Li "su man -c 'catman /usr/share/man /usr/local/man'"
+Same as above, but the target command consists of more than a
+single word and hence is quoted for use with the
+.Fl c
+option being passed to the shell.
+(Most shells expect the argument to
+.Fl c
+to be a single word).
+.It Li "su -l foo"
+Simulate a login for user foo.
+.It Li "su - foo"
+Same as above.
+.It Li "su -"
+Simulate a login for root.
+.El
+.Sh SEE ALSO
+.Xr csh 1 ,
+.Xr sh 1 ,
+.Xr group 5 ,
+.Xr passwd 5 ,
+.Xr environ 7 ,
+.Xr pam_group 8
 .Sh HISTORY
 A
 .Nm
 command appeared in
-.At v7 .
+.At v1 .
diff --git a/su/su.c b/su/su.c
index a7197f5c5b994d93e04e25fc9040a2d1c62ecfa3..e6d64a7cff0b2e81f1dc3915c740ae001db02a90 100644 (file)
--- a/su/su.c
+++ b/su/su.c
@@ -1,4 +1,34 @@
 /*
+ * Copyright (c) 2002, 2005 Networks Associates Technologies, Inc.
+ * All rights reserved.
+ *
+ * Portions of this software were developed for the FreeBSD Project by
+ * ThinkSec AS and NAI Labs, the Security Research Division of Network
+ * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
+ * ("CBOSS"), as part of the DARPA CHATS research program.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*-
  * Copyright (c) 1988, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  *
@@ -37,22 +67,31 @@ static const char copyright[] =
        The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
-#ifndef lint
 #if 0
+#ifndef lint
 static char sccsid[] = "@(#)su.c       8.3 (Berkeley) 4/2/94";
-#endif
-static const char rcsid[] =
-  "$FreeBSD: src/usr.bin/su/su.c,v 1.48 2002/01/24 16:20:17 des Exp $";
 #endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/usr.bin/su/su.c,v 1.87 2007/10/18 11:05:30 davidxu Exp $");
 
 #include <sys/param.h>
 #include <sys/time.h>
 #include <sys/resource.h>
 #include <sys/wait.h>
 
+#ifdef USE_BSM_AUDIT
+#include <bsm/libbsm.h>
+#include <bsm/audit_uevents.h>
+#endif
+
 #include <err.h>
 #include <errno.h>
 #include <grp.h>
+#ifndef __APPLE__
+#include <login_cap.h>
+#endif /* !__APPLE__ */
 #include <paths.h>
 #include <pwd.h>
 #include <signal.h>
@@ -61,47 +100,53 @@ static const char rcsid[] =
 #include <string.h>
 #include <syslog.h>
 #include <unistd.h>
-
-#include <pam/pam_appl.h>
-#include <pam/pam_misc.h>
-
-#define PAM_END() do {                                         \
-       int local_ret;                                          \
-       if (pamh != NULL && creds_set) {                        \
-               local_ret = pam_setcred(pamh, PAM_DELETE_CRED); \
-               if (local_ret != PAM_SUCCESS)                   \
-                       syslog(LOG_ERR, "pam_setcred: %s",      \
-                               pam_strerror(pamh, local_ret)); \
-               local_ret = pam_close_session(pamh, 0);         \
-               local_ret = pam_end(pamh, local_ret);           \
-               if (local_ret != PAM_SUCCESS)                   \
-                       syslog(LOG_ERR, "pam_end: %s",          \
-                               pam_strerror(pamh, local_ret)); \
-       }                                                       \
+#include <stdarg.h>
+
+#include <security/pam_appl.h>
+#include <security/openpam.h>
+
+#define PAM_END() do {                                                 \
+       int local_ret;                                                  \
+       if (pamh != NULL) {                                             \
+               local_ret = pam_setcred(pamh, PAM_DELETE_CRED);         \
+               if (local_ret != PAM_SUCCESS)                           \
+                       syslog(LOG_ERR, "pam_setcred: %s",              \
+                               pam_strerror(pamh, local_ret));         \
+               if (asthem) {                                           \
+                       local_ret = pam_close_session(pamh, 0);         \
+                       if (local_ret != PAM_SUCCESS)                   \
+                               syslog(LOG_ERR, "pam_close_session: %s",\
+                                       pam_strerror(pamh, local_ret)); \
+               }                                                       \
+               local_ret = pam_end(pamh, local_ret);                   \
+               if (local_ret != PAM_SUCCESS)                           \
+                       syslog(LOG_ERR, "pam_end: %s",                  \
+                               pam_strerror(pamh, local_ret));         \
+       }                                                               \
 } while (0)
 
 
-#define PAM_SET_ITEM(what, item) do {                          \
-       int local_ret;                                          \
-       local_ret = pam_set_item(pamh, what, item);             \
-       if (local_ret != PAM_SUCCESS) {                         \
-               syslog(LOG_ERR, "pam_set_item(" #what "): %s",  \
-                       pam_strerror(pamh, local_ret));         \
-               errx(1, "pam_set_item(" #what "): %s",          \
-                       pam_strerror(pamh, local_ret));         \
-       }                                                       \
+#define PAM_SET_ITEM(what, item) do {                                  \
+       int local_ret;                                                  \
+       local_ret = pam_set_item(pamh, what, item);                     \
+       if (local_ret != PAM_SUCCESS) {                                 \
+               syslog(LOG_ERR, "pam_set_item(" #what "): %s",          \
+                       pam_strerror(pamh, local_ret));                 \
+               errx(1, "pam_set_item(" #what "): %s",                  \
+                       pam_strerror(pamh, local_ret));                 \
+               /* NOTREACHED */                                        \
+       }                                                               \
 } while (0)
 
 enum tristate { UNSET, YES, NO };
 
 static pam_handle_t *pamh = NULL;
-static int     creds_set = 0;
 static char    **environ_pam;
 
 static char    *ontty(void);
-static int     chshell(char *);
-static void    usage(void);
-static int     export_pam_environment(void);
+static int     chshell(const char *);
+static void    usage(void) __dead2;
+static void    export_pam_environment(void);
 static int     ok_to_export(const char *);
 
 extern char    **environ;
@@ -111,30 +156,46 @@ main(int argc, char *argv[])
 {
        static char     *cleanenv;
        struct passwd   *pwd;
-       struct pam_conv conv = {misc_conv, NULL};
+       struct pam_conv conv = { openpam_ttyconv, NULL };
        enum tristate   iscsh;
+#ifndef __APPLE__
+       login_cap_t     *lc;
+#endif /* !__APPLE__ */
        union {
                const char      **a;
                char            * const *b;
-       }               np;
+       }               np;
        uid_t           ruid;
-       gid_t           gid;
-       int             asme, ch, asthem, fastlogin, prio, i, setwhat, retcode,
-                       statusp, child_pid, child_pgrp, ret_pid;
+       pid_t           child_pid, child_pgrp, pid;
+       int             asme, ch, asthem, fastlogin, prio, i, retcode,
+                       statusp, setmaclabel;
+#ifndef __APPLE__
+       u_int           setwhat;
+#endif /* !__APPLE__ */
        char            *username, *class, shellbuf[MAXPATHLEN];
        const char      *p, *user, *shell, *mytty, **nargv;
+       struct sigaction sa, sa_int, sa_quit, sa_pipe;
+       int temp, fds[2];
+#ifdef USE_BSM_AUDIT
+       const char      *aerr;
+       au_id_t          auid;
+#endif
+#ifdef __APPLE__
+       /* 4043304 */
        const char      *avshell;
        char            avshellbuf[MAXPATHLEN];
+#endif /* __APPLE__ */
 
        shell = class = cleanenv = NULL;
        asme = asthem = fastlogin = statusp = 0;
        user = "root";
        iscsh = UNSET;
+       setmaclabel = 0;
 
 #ifdef __APPLE__
        while ((ch = getopt(argc, argv, "-flm")) != -1)
 #else
-       while ((ch = getopt(argc, argv, "-flmc:")) != -1)
+       while ((ch = getopt(argc, argv, "-flmsc:")) != -1)
 #endif /* __APPLE__ */
                switch ((char)ch) {
                case 'f':
@@ -150,6 +211,9 @@ main(int argc, char *argv[])
                        asthem = 0;
                        break;
 #ifndef __APPLE__
+               case 's':
+                       setmaclabel = 1;
+                       break;
                case 'c':
                        class = optarg;
                        break;
@@ -157,6 +221,7 @@ main(int argc, char *argv[])
                case '?':
                default:
                        usage();
+               /* NOTREACHED */
                }
 
        if (optind < argc)
@@ -164,11 +229,31 @@ main(int argc, char *argv[])
 
        if (user == NULL)
                usage();
+       /* NOTREACHED */
 
-       if (strlen(user) > MAXLOGNAME - 1)
+       /*
+        * Try to provide more helpful debugging output if su(1) is running
+        * non-setuid, or was run from a file system not mounted setuid.
+        */
+       if (geteuid() != 0)
+               errx(1, "not running setuid");
+
+#ifdef USE_BSM_AUDIT
+       if (getauid(&auid) < 0 && errno != ENOSYS) {
+               syslog(LOG_AUTH | LOG_ERR, "getauid: %s", strerror(errno));
+               errx(1, "Permission denied");
+       }
+#endif
+       if (strlen(user) > MAXLOGNAME - 1) {
+#ifdef USE_BSM_AUDIT
+               if (audit_submit(AUE_su, auid,
+                   1, EPERM, "username too long: '%s'", user))
+                       errx(1, "Permission denied");
+#endif
                errx(1, "username too long");
+       }
 
-       nargv = malloc(sizeof(char *) * (argc + 4));
+       nargv = malloc(sizeof(char *) * (size_t)(argc + 4));
        if (nargv == NULL)
                errx(1, "malloc failure");
 
@@ -193,9 +278,14 @@ main(int argc, char *argv[])
        pwd = getpwnam(username);
        if (username == NULL || pwd == NULL || pwd->pw_uid != ruid)
                pwd = getpwuid(ruid);
-       if (pwd == NULL)
+       if (pwd == NULL) {
+#ifdef USE_BSM_AUDIT
+               if (audit_submit(AUE_su, auid, 1, EPERM,
+                   "unable to determine invoking subject: '%s'", username))
+                       errx(1, "Permission denied");
+#endif
                errx(1, "who are you?");
-       gid = pwd->pw_gid;
+       }
 
        username = strdup(pwd->pw_name);
        if (username == NULL)
@@ -221,7 +311,7 @@ main(int argc, char *argv[])
                errx(1, "pam_start: %s", pam_strerror(pamh, retcode));
        }
 
-       PAM_SET_ITEM(PAM_RUSER, getlogin());
+       PAM_SET_ITEM(PAM_RUSER, username);
 
        mytty = ttyname(STDERR_FILENO);
        if (!mytty)
@@ -230,46 +320,96 @@ main(int argc, char *argv[])
 
        retcode = pam_authenticate(pamh, 0);
        if (retcode != PAM_SUCCESS) {
-               syslog(LOG_ERR, "pam_authenticate: %s",
-                   pam_strerror(pamh, retcode));
+#ifdef USE_BSM_AUDIT
+               if (audit_submit(AUE_su, auid, 1, EPERM, "bad su %s to %s on %s",
+                   username, user, mytty))
+                       errx(1, "Permission denied");
+#endif
+               syslog(LOG_AUTH|LOG_WARNING, "BAD SU %s to %s on %s",
+                   username, user, mytty);
                errx(1, "Sorry");
        }
+#ifdef USE_BSM_AUDIT
+       if (audit_submit(AUE_su, auid, 0, 0, "successful authentication"))
+               errx(1, "Permission denied");
+#endif
        retcode = pam_get_item(pamh, PAM_USER, (const void **)&p);
        if (retcode == PAM_SUCCESS)
                user = p;
        else
                syslog(LOG_ERR, "pam_get_item(PAM_USER): %s",
                    pam_strerror(pamh, retcode));
+       pwd = getpwnam(user);
+       if (pwd == NULL) {
+#ifdef USE_BSM_AUDIT
+               if (audit_submit(AUE_su, auid, 1, EPERM,
+                   "unknown subject: %s", user))
+                       errx(1, "Permission denied");
+#endif
+               errx(1, "unknown login: %s", user);
+       }
 
        retcode = pam_acct_mgmt(pamh, 0);
        if (retcode == PAM_NEW_AUTHTOK_REQD) {
                retcode = pam_chauthtok(pamh,
                        PAM_CHANGE_EXPIRED_AUTHTOK);
                if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+                       aerr = pam_strerror(pamh, retcode);
+                       if (aerr == NULL)
+                               aerr = "Unknown PAM error";
+                       if (audit_submit(AUE_su, auid, 1, EPERM,
+                           "pam_chauthtok: %s", aerr))
+                               errx(1, "Permission denied");
+#endif
                        syslog(LOG_ERR, "pam_chauthtok: %s",
                            pam_strerror(pamh, retcode));
                        errx(1, "Sorry");
                }
        }
        if (retcode != PAM_SUCCESS) {
+#ifdef USE_BSM_AUDIT
+               if (audit_submit(AUE_su, auid, 1, EPERM, "pam_acct_mgmt: %s",
+                   pam_strerror(pamh, retcode)))
+                       errx(1, "Permission denied");
+#endif
                syslog(LOG_ERR, "pam_acct_mgmt: %s",
                        pam_strerror(pamh, retcode));
                errx(1, "Sorry");
        }
 
-       /* get target login information, default to root */
-       pwd = getpwnam(user);
-       if (pwd == NULL)
-               errx(1, "unknown login: %s", user);
+#ifndef __APPLE__
+       /* get target login information */
+       if (class == NULL)
+               lc = login_getpwclass(pwd);
+       else {
+               if (ruid != 0) {
+#ifdef USE_BSM_AUDIT
+                       if (audit_submit(AUE_su, auid, 1, EPERM,
+                           "only root may use -c"))
+                               errx(1, "Permission denied");
+#endif
+                       errx(1, "only root may use -c");
+               }
+               lc = login_getclass(class);
+               if (lc == NULL)
+                       errx(1, "unknown class: %s", class);
+       }
+#endif /* !__APPLE__ */
 
        /* if asme and non-standard target shell, must be root */
        if (asme) {
                if (ruid != 0 && !chshell(pwd->pw_shell))
-                       errx(1, "permission denied (shell).");
+                       errx(1, "permission denied (shell)");
        }
        else if (pwd->pw_shell && *pwd->pw_shell) {
+#ifdef __APPLE__
+               /* 3825554 */
                shell = strncpy(shellbuf, pwd->pw_shell, sizeof(shellbuf));
                shellbuf[sizeof(shellbuf) - 1] = '\0';
+#else
+               shell = pwd->pw_shell;
+#endif /* __APPLE__ */
                iscsh = UNSET;
        }
        else {
@@ -277,14 +417,14 @@ main(int argc, char *argv[])
                iscsh = NO;
        }
 
-       if ((p = strrchr(shell, '/')) != NULL)
-               avshell = p+1;
-       else
-               avshell = shell;
-
        /* if we're forking a csh, we want to slightly muck the args */
        if (iscsh == UNSET) {
-               iscsh = strcmp(avshell, "csh") ? (strcmp(avshell, "tcsh") ? NO : YES) : YES;
+               p = strrchr(shell, '/');
+               if (p)
+                       ++p;
+               else
+                       p = shell;
+               iscsh = strcmp(p, "csh") ? (strcmp(p, "tcsh") ? NO : YES) : YES;
        }
        setpriority(PRIO_PROCESS, 0, prio);
 
@@ -292,58 +432,119 @@ main(int argc, char *argv[])
         * PAM modules might add supplementary groups in pam_setcred(), so
         * initialize them first.
         */
-       if( initgroups(user, pwd->pw_gid) )
-               err(1, "initgroups failed");
-
-       retcode = pam_open_session(pamh, 0);
-       if( retcode != PAM_SUCCESS ) {
-               syslog(LOG_ERR, "pam_open_session(pamh, 0): %s", 
-                       pam_strerror(pamh, retcode));
-       }
+#ifdef __APPLE__
+       if (initgroups(user, pwd->pw_gid))
+               err(1, "initgroups");
+#else
+       if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETGROUP) < 0)
+               err(1, "setusercontext");
+#endif /* __APPLE__ */
 
        retcode = pam_setcred(pamh, PAM_ESTABLISH_CRED);
-       if (retcode != PAM_SUCCESS)
-               syslog(LOG_ERR, "pam_setcred(pamh, PAM_ESTABLISH_CRED): %s",
+       if (retcode != PAM_SUCCESS) {
+               syslog(LOG_ERR, "pam_setcred: %s",
                    pam_strerror(pamh, retcode));
-       else
-               creds_set = 1;
+               errx(1, "failed to establish credentials.");
+       }
+       if (asthem) {
+               retcode = pam_open_session(pamh, 0);
+               if (retcode != PAM_SUCCESS) {
+                       syslog(LOG_ERR, "pam_open_session: %s",
+                           pam_strerror(pamh, retcode));
+                       errx(1, "failed to open session.");
+               }
+       }
 
        /*
         * We must fork() before setuid() because we need to call
         * pam_setcred(pamh, PAM_DELETE_CRED) as root.
         */
-
+       sa.sa_flags = SA_RESTART;
+       sa.sa_handler = SIG_IGN;
+       sigemptyset(&sa.sa_mask);
+       sigaction(SIGINT, &sa, &sa_int);
+       sigaction(SIGQUIT, &sa, &sa_quit);
+       sigaction(SIGPIPE, &sa, &sa_pipe);
+       sa.sa_handler = SIG_DFL;
+       sigaction(SIGTSTP, &sa, NULL);
        statusp = 1;
+       if (pipe(fds) == -1) {
+               PAM_END();
+               err(1, "pipe");
+       }
        child_pid = fork();
        switch (child_pid) {
        default:
-               while ((ret_pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) {
+               sa.sa_handler = SIG_IGN;
+               sigaction(SIGTTOU, &sa, NULL);
+               close(fds[0]);
+               setpgid(child_pid, child_pid);
+               if (tcgetpgrp(STDERR_FILENO) == getpgrp())
+                       tcsetpgrp(STDERR_FILENO, child_pid);
+               close(fds[1]);
+               sigaction(SIGPIPE, &sa_pipe, NULL);
+               while ((pid = waitpid(child_pid, &statusp, WUNTRACED)) != -1) {
                        if (WIFSTOPPED(statusp)) {
-                               child_pgrp = tcgetpgrp(1);
+                               child_pgrp = getpgid(child_pid);
+                               if (tcgetpgrp(STDERR_FILENO) == child_pgrp)
+                                       tcsetpgrp(STDERR_FILENO, getpgrp());
                                kill(getpid(), SIGSTOP);
-                               tcsetpgrp(1, child_pgrp);
-                               kill(child_pid, SIGCONT); 
+                               if (tcgetpgrp(STDERR_FILENO) == getpgrp()) {
+                                       child_pgrp = getpgid(child_pid);
+                                       tcsetpgrp(STDERR_FILENO, child_pgrp);
+                               }
+                               kill(child_pid, SIGCONT);
                                statusp = 1;
                                continue;
                        }
                        break;
                }
-               if (ret_pid == -1)
+               tcsetpgrp(STDERR_FILENO, getpgrp());
+               if (pid == -1)
                        err(1, "waitpid");
                PAM_END();
                exit(WEXITSTATUS(statusp));
        case -1:
-               err(1, "fork");
                PAM_END();
-               exit(1);
+               err(1, "fork");
        case 0:
-               if( setgid(pwd->pw_gid) )
+               close(fds[1]);
+               read(fds[0], &temp, 1);
+               close(fds[0]);
+               sigaction(SIGPIPE, &sa_pipe, NULL);
+               sigaction(SIGINT, &sa_int, NULL);
+               sigaction(SIGQUIT, &sa_quit, NULL);
+
+#ifdef __APPLE__
+               if (setgid(pwd->pw_gid))
                        err(1, "setgid");
                /* Call initgroups(2) after setgid(2) to re-establish memberd */
-               if( initgroups(user, pwd->pw_gid) )
+               if (initgroups(user, pwd->pw_gid))
                        err(1, "initgroups");
-               if( setuid(pwd->pw_uid) )
+               if (setuid(pwd->pw_uid))
                        err(1, "setuid");
+#else
+               /*
+                * Set all user context except for: Environmental variables
+                * Umask Login records (wtmp, etc) Path
+                */
+               setwhat = LOGIN_SETALL & ~(LOGIN_SETENV | LOGIN_SETUMASK |
+                          LOGIN_SETLOGIN | LOGIN_SETPATH | LOGIN_SETGROUP |
+                          LOGIN_SETMAC);
+               /*
+                * If -s is present, also set the MAC label.
+                */
+               if (setmaclabel)
+                       setwhat |= LOGIN_SETMAC;
+               /*
+                * Don't touch resource/priority settings if -m has been used
+                * or -l and -c hasn't, and we're not su'ing to root.
+                */
+               if ((asme || (!asthem && class == NULL)) && pwd->pw_uid)
+                       setwhat &= ~(LOGIN_SETPRIORITY | LOGIN_SETRESOURCES);
+               if (setusercontext(lc, pwd, pwd->pw_uid, setwhat) < 0)
+                       err(1, "setusercontext");
+#endif /* __APPLE__ */
 
                if (!asme) {
                        if (asthem) {
@@ -355,6 +556,9 @@ main(int argc, char *argv[])
                                setenv("USER", pwd->pw_name, 1);
                        setenv("HOME", pwd->pw_dir, 1);
                        setenv("SHELL", shell, 1);
+#ifdef __APPLE__
+                       unsetenv("TMPDIR");
+#endif /* __APPLE__ */
 
                        if (asthem) {
                                /*
@@ -373,7 +577,7 @@ main(int argc, char *argv[])
                                setusercontext(lc, pwd, pwd->pw_uid,
                                        LOGIN_SETPATH | LOGIN_SETUMASK |
                                        LOGIN_SETENV);
-#endif
+#endif /* __APPLE__ */
                                if (p)
                                        setenv("TERM", p, 1);
 
@@ -382,6 +586,9 @@ main(int argc, char *argv[])
                                        errx(1, "no directory");
                        }
                }
+#ifndef __APPLE__
+               login_close(lc);
+#endif /* !__APPLE__ */
 
                if (iscsh == YES) {
                        if (fastlogin)
@@ -389,6 +596,12 @@ main(int argc, char *argv[])
                        if (asme)
                                *np.a-- = "-m";
                }
+#ifdef __APPLE__
+               /* 4043304 */
+               if ((p = strrchr(shell, '/')) != NULL)
+                       avshell = p + 1;
+               else
+                       avshell = shell;
 
                if (asthem) {
                        avshellbuf[0] = '-';
@@ -398,6 +611,10 @@ main(int argc, char *argv[])
 
                /* csh *no longer* strips the first character... */
                *np.a = avshell;
+#else
+               /* csh strips the first character... */
+               *np.a = asthem ? "-su" : iscsh == YES ? "_su" : "su";
+#endif /* __APPLE__ */
 
                if (ruid != 0)
                        syslog(LOG_NOTICE, "%s to %s%s", username, user,
@@ -408,17 +625,20 @@ main(int argc, char *argv[])
        }
 }
 
-static int
+static void
 export_pam_environment(void)
 {
        char    **pp;
+       char    *p;
 
        for (pp = environ_pam; *pp != NULL; pp++) {
-               if (ok_to_export(*pp))
-                       putenv(*pp);
+               if (ok_to_export(*pp)) {
+                       p = strchr(*pp, '=');
+                       *p = '\0';
+                       setenv(*pp, p + 1, 1);
+               }
                free(*pp);
        }
-       return PAM_SUCCESS;
 }
 
 /*
@@ -427,12 +647,14 @@ export_pam_environment(void)
  * - Make sure the string doesn't run on too long.
  * - Do not export certain variables.  This list was taken from the
  *   Solaris pam_putenv(3) man page.
+ * Note that if the user is chrooted, PAM may have a better idea than we
+ * do of where her home directory is.
  */
 static int
 ok_to_export(const char *s)
 {
        static const char *noexport[] = {
-               "SHELL", "HOME", "LOGNAME", "MAIL", "CDPATH",
+               "SHELL", /* "HOME", */ "LOGNAME", "MAIL", "CDPATH",
                "IFS", "PATH", NULL
        };
        const char **pp;
@@ -457,23 +679,22 @@ usage(void)
 #ifdef __APPLE__
        fprintf(stderr, "usage: su [-] [-flm] [login [args]]\n");
 #else
-       fprintf(stderr, "usage: su [-] [-flm] [-c class] [login [args]]\n");
+       fprintf(stderr, "usage: su [-] [-flms] [-c class] [login [args]]\n");
 #endif /* __APPLE__ */
        exit(1);
+       /* NOTREACHED */
 }
 
 static int
-chshell(char *sh)
+chshell(const char *sh)
 {
        int r;
        char *cp;
 
        r = 0;
        setusershell();
-       do {
-               cp = getusershell();
-               r = strcmp(cp, sh);
-       } while (!r && cp != NULL);
+       while ((cp = getusershell()) != NULL && !r)
+           r = (strcmp(cp, sh) == 0);
        endusershell();
        return r;
 }
diff --git a/su/su.pam b/su/su.pam
new file mode 100644 (file)
index 0000000..fd8a789
--- /dev/null
+++ b/su/su.pam
@@ -0,0 +1,7 @@
+# su: auth account session
+auth       sufficient     pam_rootok.so 
+auth       required       pam_opendirectory.so
+account    required       pam_group.so no_warn group=admin,wheel ruser root_only fail_safe
+account    required       pam_opendirectory.so no_check_shell
+password   required       pam_opendirectory.so
+session    required       pam_launchd.so
index 6c89b812a7b89e8395c3ae404965cf3643bb9f99..ddca5fdb8412f54d54c1a665e3421bcf4132fb81 100644 (file)
@@ -43,6 +43,9 @@ __RCSID("$NetBSD: uname.c,v 1.10 1998/11/09 13:24:05 kleink Exp $");
 #include <stdlib.h>
 #include <unistd.h>
 #include <err.h>
+#ifdef __APPLE__
+#include <string.h>
+#endif /* __APPLE__ */
 
 #include <sys/sysctl.h>
 #include <sys/utsname.h>
@@ -137,7 +140,9 @@ main(argc, argv)
                    &len, NULL, 0) < 0)
                        err(EXIT_FAILURE, "sysctl");
        }
-#else /* __APPLE__ */
+#endif /* !__APPLE__ */
+
+#ifdef __APPLE__
        /*
         * Let's allow the user to override the output of uname via the shell environment.
         * This is a useful feature for cross-compiling (eg. during an OS bringup).
@@ -151,7 +156,7 @@ main(argc, argv)
                s = getenv ("UNAME_VERSION");  if (s) strncpy (u.version,  s, sizeof (u.version));
                s = getenv ("UNAME_MACHINE");  if (s) strncpy (u.machine,  s, sizeof (u.machine));
        }
-#endif /* !__APPLE__ */
+#endif /* __APPLE__ */
 
        if (print_mask & PRINT_SYSNAME) {
                space++;
@@ -178,10 +183,12 @@ main(argc, argv)
 #ifndef __APPLE__
                fputs(machine_arch, stdout);
 #else
-#if   defined(__ppc__)
+#if defined(__ppc__) || defined(__ppc64__)
                fputs("powerpc", stdout);
-#elif defined(__i386__)
+#elif defined (__i386__) || defined(__x86_64__)
                fputs("i386", stdout);
+#elif defined(__arm__)
+               fputs("arm", stdout);
 #else
                fputs("unknown", stdout);
 #endif
diff --git a/w/w.1 b/w/w.1
index ba57bae98da2e120b539a4f82613b8d4a15e82f2..e94c39b95958b864a019b40f4821a4d01d1e94a0 100644 (file)
--- a/w/w.1
+++ b/w/w.1
@@ -121,3 +121,7 @@ The
 utility does not know about the new conventions for detection of background
 jobs.
 It will sometimes find a background job instead of the right one.
+.Pp
+Long hostnames and IPv6 addresses may be truncated; however, the
+.Xr who 1
+utility will display full hostnames.
index 434b84c2e93f9a1e876f6dad458d72ac5d41869b..bc1168cf6efe963d5e6e1a61d3c1a2b797264a84 100644 (file)
@@ -1,11 +1,11 @@
 Project = who
 Install_Dir = /usr/bin
 
-CFILES = who.c
+CFILES = who.c utmpentry.c
 MANPAGES = who.1
 
-Extra_CC_Flags = -Wall -mdynamic-no-pic \
-       -g -O0
+Extra_CC_Flags = -Wall -Werror -mdynamic-no-pic
+Extra_CC_Flags += -DSUPPORT_UTMPX -D_UTMPX_COMPAT
 Extra_LD_Flags = -dead_strip
 
 include $(MAKEFILEPATH)/CoreOS/ReleaseControl/BSDCommon.make
diff --git a/who/utmpentry.c b/who/utmpentry.c
new file mode 100644 (file)
index 0000000..b0e0914
--- /dev/null
@@ -0,0 +1,348 @@
+/*     $NetBSD: utmpentry.c,v 1.15 2008/07/13 20:07:48 dholland Exp $  */
+
+/*-
+ * Copyright (c) 2002 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>
+#ifndef lint
+__RCSID("$NetBSD: utmpentry.c,v 1.15 2008/07/13 20:07:48 dholland Exp $");
+#endif
+
+#include <sys/stat.h>
+
+#include <time.h>
+#include <string.h>
+#include <err.h>
+#include <stdlib.h>
+#ifdef __APPLE__
+#include <stdint.h>
+#endif /* __APPLE__ */
+
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+#endif
+#ifdef SUPPORT_UTMPX
+#include <utmpx.h>
+#endif
+
+#include "utmpentry.h"
+
+#ifdef __APPLE__
+#define        timespecclear(tsp)      (tsp)->tv_sec = (time_t)((tsp)->tv_nsec = 0L)
+#define        timespeccmp(tsp, usp, cmp)                                      \
+       (((tsp)->tv_sec == (usp)->tv_sec) ?                             \
+           ((tsp)->tv_nsec cmp (usp)->tv_nsec) :                       \
+           ((tsp)->tv_sec cmp (usp)->tv_sec))
+#endif /* __APPLE__ */
+
+/* Fail the compile if x is not true, by constructing an illegal type. */
+#define COMPILE_ASSERT(x) ((void)sizeof(struct { unsigned : ((x) ? 1 : -1); }))
+
+
+#ifdef SUPPORT_UTMP
+static void getentry(struct utmpentry *, struct utmp *);
+static struct timespec utmptime = {0, 0};
+#endif
+#ifdef SUPPORT_UTMPX
+static void getentryx(struct utmpentry *, struct utmpx *);
+static struct timespec utmpxtime = {0, 0};
+#endif
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static int setup(const char *);
+static void adjust_size(struct utmpentry *e);
+#endif
+
+int maxname = 8, maxline = 8, maxhost = 16;
+int etype = 1 << USER_PROCESS;
+static int numutmp = 0;
+static struct utmpentry *ehead;
+
+#if defined(SUPPORT_UTMPX) || defined(SUPPORT_UTMP)
+static void
+adjust_size(struct utmpentry *e)
+{
+       int max;
+
+       if ((max = strlen(e->name)) > maxname)
+               maxname = max;
+       if ((max = strlen(e->line)) > maxline)
+               maxline = max;
+       if ((max = strlen(e->host)) > maxhost)
+               maxhost = max;
+}
+
+static int
+setup(const char *fname)
+{
+       int what = 3;
+       struct stat st;
+       const char *sfname;
+
+       if (fname == NULL) {
+#ifdef SUPPORT_UTMPX
+               setutxent();
+#endif
+#ifdef SUPPORT_UTMP
+               setutent();
+#endif
+       } else {
+               size_t len = strlen(fname);
+               if (len == 0)
+                       errx(1, "Filename cannot be 0 length.");
+#ifdef __APPLE__
+               what = 1;
+#else /* !__APPLE__ */
+               what = fname[len - 1] == 'x' ? 1 : 2;
+#endif /* __APPLE__ */
+               if (what == 1) {
+#ifdef SUPPORT_UTMPX
+                       if (utmpxname(fname) == 0)
+                               warnx("Cannot set utmpx file to `%s'",
+                                   fname);
+#else
+                       warnx("utmpx support not compiled in");
+#endif
+               } else {
+#ifdef SUPPORT_UTMP
+                       if (utmpname(fname) == 0)
+                               warnx("Cannot set utmp file to `%s'",
+                                   fname);
+#else
+                       warnx("utmp support not compiled in");
+#endif
+               }
+       }
+#ifdef SUPPORT_UTMPX
+       if (what & 1) {
+               sfname = fname ? fname : _PATH_UTMPX;
+               if (stat(sfname, &st) == -1) {
+                       warn("Cannot stat `%s'", sfname);
+                       what &= ~1;
+               } else {
+                       if (timespeccmp(&st.st_mtimespec, &utmpxtime, >))
+                           utmpxtime = st.st_mtimespec;
+                       else
+                           what &= ~1;
+               }
+       }
+#endif
+#ifdef SUPPORT_UTMP
+       if (what & 2) {
+               sfname = fname ? fname : _PATH_UTMP;
+               if (stat(sfname, &st) == -1) {
+                       warn("Cannot stat `%s'", sfname);
+                       what &= ~2;
+               } else {
+                       if (timespeccmp(&st.st_mtimespec, &utmptime, >))
+                               utmptime = st.st_mtimespec;
+                       else
+                               what &= ~2;
+               }
+       }
+#endif
+       return what;
+}
+#endif
+
+void
+endutentries(void)
+{
+       struct utmpentry *ep;
+
+#ifdef SUPPORT_UTMP
+       timespecclear(&utmptime);
+#endif
+#ifdef SUPPORT_UTMPX
+       timespecclear(&utmpxtime);
+#endif
+       ep = ehead;
+       while (ep) {
+               struct utmpentry *sep = ep;
+               ep = ep->next;
+               free(sep);
+       }
+       ehead = NULL;
+       numutmp = 0;
+}
+
+int
+getutentries(const char *fname, struct utmpentry **epp)
+{
+#ifdef SUPPORT_UTMPX
+       struct utmpx *utx;
+#endif
+#ifdef SUPPORT_UTMP
+       struct utmp *ut;
+#endif
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+       struct utmpentry *ep;
+       int what = setup(fname);
+       struct utmpentry **nextp = &ehead;
+       switch (what) {
+       case 0:
+               /* No updates */
+               *epp = ehead;
+               return numutmp;
+       default:
+               /* Need to re-scan */
+               ehead = NULL;
+               numutmp = 0;
+       }
+#endif
+
+#ifdef SUPPORT_UTMPX
+       while ((what & 1) && (utx = getutxent()) != NULL) {
+#ifdef __APPLE__
+               if (((1 << utx->ut_type) & etype) == 0)
+#else /* !__APPLE__ */
+               if (fname == NULL && ((1 << utx->ut_type) & etype) == 0)
+#endif /* __APPLE__ */
+                       continue;
+               if ((ep = calloc(1, sizeof(struct utmpentry))) == NULL) {
+                       warn(NULL);
+                       return 0;
+               }
+               getentryx(ep, utx);
+               *nextp = ep;
+               nextp = &(ep->next);
+       }
+#endif
+
+#ifdef SUPPORT_UTMP
+       if ((etype & (1 << USER_PROCESS)) != 0) {
+               while ((what & 2) && (ut = getutent()) != NULL) {
+                       if (fname == NULL && (*ut->ut_name == '\0' ||
+                           *ut->ut_line == '\0'))
+                               continue;
+                       /* Don't process entries that we have utmpx for */
+                       for (ep = ehead; ep != NULL; ep = ep->next) {
+                               if (strncmp(ep->line, ut->ut_line,
+                                   sizeof(ut->ut_line)) == 0)
+                                       break;
+                       }
+                       if (ep != NULL)
+                               continue;
+                       if ((ep = calloc(1, sizeof(*ep))) == NULL) {
+                               warn(NULL);
+                               return 0;
+                       }
+                       getentry(ep, ut);
+                       *nextp = ep;
+                       nextp = &(ep->next);
+               }
+       }
+#endif
+       numutmp = 0;
+#if defined(SUPPORT_UTMP) || defined(SUPPORT_UTMPX)
+       if (ehead != NULL) {
+               struct utmpentry *from = ehead, *save;
+               
+               ehead = NULL;
+               while (from != NULL) {
+                       for (nextp = &ehead;
+                           (*nextp) && strcmp(from->line, (*nextp)->line) > 0;
+                           nextp = &(*nextp)->next)
+                               continue;
+                       save = from;
+                       from = from->next;
+                       save->next = *nextp;
+                       *nextp = save;
+                       numutmp++;
+               }
+       }
+       *epp = ehead;
+       return numutmp;
+#else
+       *epp = NULL;
+       return 0;
+#endif
+}
+
+#ifdef SUPPORT_UTMP
+static void
+getentry(struct utmpentry *e, struct utmp *up)
+{
+       COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
+       COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
+       COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
+
+       /*
+        * e has just been calloc'd. We don't need to clear it or
+        * append null-terminators, because its length is strictly
+        * greater than the source string. Use strncpy to _read_
+        * up->ut_* because they may not be terminated. For this
+        * reason we use the size of the _source_ as the length
+        * argument.
+        */
+       (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
+       (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
+       (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
+
+       e->tv.tv_sec = up->ut_time;
+       e->tv.tv_usec = 0;
+       e->pid = 0;
+       e->term = 0;
+       e->exit = 0;
+       e->sess = 0;
+       e->type = USER_PROCESS;
+       adjust_size(e);
+}
+#endif
+
+#ifdef SUPPORT_UTMPX
+static void
+getentryx(struct utmpentry *e, struct utmpx *up)
+{
+       COMPILE_ASSERT(sizeof(e->name) > sizeof(up->ut_name));
+       COMPILE_ASSERT(sizeof(e->line) > sizeof(up->ut_line));
+       COMPILE_ASSERT(sizeof(e->host) > sizeof(up->ut_host));
+
+       /*
+        * e has just been calloc'd. We don't need to clear it or
+        * append null-terminators, because its length is strictly
+        * greater than the source string. Use strncpy to _read_
+        * up->ut_* because they may not be terminated. For this
+        * reason we use the size of the _source_ as the length
+        * argument.
+        */
+       (void)strncpy(e->name, up->ut_name, sizeof(up->ut_name));
+       (void)strncpy(e->line, up->ut_line, sizeof(up->ut_line));
+       (void)strncpy(e->host, up->ut_host, sizeof(up->ut_host));
+
+       e->tv = up->ut_tv;
+       e->pid = up->ut_pid;
+#ifndef __APPLE__
+       e->term = up->ut_exit.e_termination;
+       e->exit = up->ut_exit.e_exit;
+       e->sess = up->ut_session;
+#endif /* !__APPLE__ */
+       e->type = up->ut_type;
+       adjust_size(e);
+}
+#endif
diff --git a/who/utmpentry.h b/who/utmpentry.h
new file mode 100644 (file)
index 0000000..012478a
--- /dev/null
@@ -0,0 +1,78 @@
+/*     $NetBSD: utmpentry.h,v 1.7 2008/07/13 20:07:49 dholland Exp $   */
+
+/*-
+ * Copyright (c) 2002 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 defined(SUPPORT_UTMPX)
+# include <utmpx.h>
+# define WHO_NAME_LEN          _UTX_USERSIZE
+# define WHO_LINE_LEN          _UTX_LINESIZE
+# define WHO_HOST_LEN          _UTX_HOSTSIZE
+#elif defined(SUPPORT_UTMP)
+# include <utmp.h>
+# define WHO_NAME_LEN          UT_NAMESIZE
+# define WHO_LINE_LEN          UT_LINESIZE
+# define WHO_HOST_LEN          UT_HOSTSIZE
+#else
+# error Either SUPPORT_UTMPX or SUPPORT_UTMP must be defined!
+#endif
+
+
+struct utmpentry {
+       char name[WHO_NAME_LEN + 1];
+       char line[WHO_LINE_LEN + 1];
+       char host[WHO_HOST_LEN + 1];
+       struct timeval tv;
+       pid_t pid;
+#ifndef __APPLE__
+       uint16_t term;
+       uint16_t exit;
+       uint16_t sess;
+#endif /* !__APPLE__ */
+       uint16_t type;
+       struct utmpentry *next;
+};
+
+extern int maxname, maxline, maxhost;
+extern int etype;
+
+/*
+ * getutentries provides a linked list of struct utmpentry and returns
+ * the number of entries. The first argument, if not null, names an 
+ * alternate utmp(x) file to look in.
+ *
+ * The memory returned by getutentries belongs to getutentries. The
+ * list returned (or elements of it) may be returned again later if
+ * utmp hasn't changed in the meantime.
+ *
+ * endutentries clears and frees the cached data.
+ */
+
+int getutentries(const char *, struct utmpentry **);
+void endutentries(void);
index f80a0f47c4aa2709d3ac6415df81c0ad517735e0..dbcbdf1b6f1c522428f7f983863c48373d5700ba 100644 (file)
--- a/who/who.1
+++ b/who/who.1
@@ -1,3 +1,5 @@
+.\"    $NetBSD: who.1,v 1.22 2007/01/18 00:15:05 wiz Exp $
+.\"
 .\" Copyright (c) 1986, 1991, 1993
 .\"    The Regents of the University of California.  All rights reserved.
 .\"
@@ -9,11 +11,7 @@
 .\" 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 University of
-.\"    California, Berkeley and its contributors.
-.\" 4. Neither the name of the University nor the names of its contributors
+.\" 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.
 .\"
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)who.1      8.2 (Berkeley) 12/30/93
-.\" $FreeBSD: src/usr.bin/who/who.1,v 1.16 2004/07/02 22:22:34 ru Exp $
 .\"
-.Dd May 8, 2002
+.Dd January 17, 2007
 .Dt WHO 1
 .Os
 .Sh NAME
 .Nm who
-.Nd display who is on the system
+.Nd display who is logged in
 .Sh SYNOPSIS
 .Nm
-.Op Fl HmqsTu
-.Op Cm am I
+.Op Fl abdHlmpqrsTtu
 .Op Ar file
+.Nm
+.Ar am i
 .Sh DESCRIPTION
 The
 .Nm
-utility displays information about currently logged in users.
-By default, this includes the login name, tty name, date and time of login and
-remote hostname if not local.
+utility displays a list of all users currently logged on, showing for
+each user the login name, tty name, the date and time of login, and
+hostname if not local.
 .Pp
-The options are as follows:
-.Bl -tag -width indent
+Available options:
+.Pp
+.Bl -tag -width file
+.It Fl a
+Same as
+.Fl bdlprTtu .
+.It Fl b
+Time of last system boot.
+.It Fl d
+Print dead processes.
 .It Fl H
-Write column headings above the output.
+Write column headings above the regular output.
+.It Fl l
+Print system login processes (unsupported).
 .It Fl m
-Show information about the terminal attached to standard input only.
+Only print information about the current terminal.
+This is the
+.Tn POSIX
+way of saying
+.Nm
+.Ar am i .
+.It Fl p
+Print active processes spawned by
+.Xr launchd 8
+(unsupported).
 .It Fl q
-.Dq "Quick mode" :
-List the names and number of logged in users in columns.
-All other command line options are ignored.
+.Dq Quick mode :
+List only the names and the number of users currently logged on.
+When this option is used, all other options are ignored.
+.It Fl r
+Print the current runlevel.
+This is meaningless on Mac OS X.
 .It Fl s
-Show the name, line and time fields only.
+List only the name, line and time fields.
 This is the default.
 .It Fl T
-Indicate whether each user is accepting messages.
-One of the following characters is written:
-.Pp
-.Bl -tag -width 1n -compact
-.It Li +
-User is accepting messages.
-.It Li \&-
-User is not accepting messages.
-.It Li \&?
-An error occurred.
-.El
+Print a character after the user name indicating the state of the
+terminal line:
+.Sq +
+if the terminal is writable;
+.Sq -
+if it is not;
+and
+.Sq \&?
+if a bad line is encountered.
+.It Fl t
+Print last system clock change (unsupported).
 .It Fl u
-Show idle time for each user in hours and minutes as
-.Ar hh Ns : Ns Ar mm ,
-.Ql \&.
-if the user has been idle less than a minute, and
-.Dq Li old
-if the user has been idle more than 24 hours.
-Additionally, display the PID of the user's login process.
-.It Cm am I
-Equivalent to
-.Fl m .
-.El
-.Pp
+Print the idle time for each user, and the associated process ID.
+.It Ar \&am I
+Returns the invoker's real user name.
+.It Ar file
 By default,
 .Nm
 gathers information from the file
 .Pa /var/run/utmpx .
-An alternate
+An alternative
 .Ar file
 may be specified.
-.Sh LEGACY DESCRIPTION
-In legacy mode,
-.Fl u
-does not display the PID of the user's login process.
-.Sh ENVIRONMENT
-The
-.Ev COLUMNS , LANG , LC_ALL
-and
-.Ev LC_TIME
-environment variables affect the execution of
-.Nm
-as described in
-.Xr environ 7 .
+.El
 .Sh FILES
-.Bl -tag -width /var/log/utmpx -compact
+.Bl -tag -width /var/run/utmpx -compact
 .It Pa /var/run/utmpx
 .El
-.Sh DIAGNOSTICS
-.Ex -std
 .Sh SEE ALSO
 .Xr last 1 ,
+.Xr mesg 1 ,
 .Xr users 1 ,
-.Xr w 1 ,
-.Xr compat 5 ,
+.Xr getuid 2 ,
 .Xr utmpx 5
 .Sh STANDARDS
 The
@@ -128,5 +126,5 @@ utility conforms to
 .Sh HISTORY
 A
 .Nm
-command appeared in
-.At v1 .
+utility appeared in
+.At v6 .
index da46ad77d9e4349d83f99c873ed6fdd6356d1cec..f0e356f22b246718bd138fe6826d1a8cd0c2d593 100644 (file)
--- a/who/who.c
+++ b/who/who.c
@@ -1,6 +1,11 @@
-/*-
- * Copyright (c) 2002 Tim J. Robbins.
- * All rights reserved.
+/*     $NetBSD: who.c,v 1.23 2008/07/24 15:35:41 christos Exp $        */
+
+/*
+ * Copyright (c) 1989, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Michael Fischbein.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * 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 AUTHOR OR CONTRIBUTORS BE LIABLE
+ * 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)
  */
 
 #include <sys/cdefs.h>
-/* commented as FBSDID not needed for Tiger ......
-__FBSDID("$FreeBSD: src/usr.bin/who/who.c,v 1.20 2003/10/26 05:05:48 peter Exp $");
-*/
+#ifndef lint
+__COPYRIGHT("@(#) Copyright (c) 1989, 1993\
+ The Regents of the University of California.  All rights reserved.");
+#endif /* not lint */
+
+#ifndef lint
+#if 0
+static char sccsid[] = "@(#)who.c      8.1 (Berkeley) 6/6/93";
+#endif
+__RCSID("$NetBSD: who.c,v 1.23 2008/07/24 15:35:41 christos Exp $");
+#endif /* not lint */
 
 #include <sys/types.h>
-#include <sys/ioctl.h>
 #include <sys/stat.h>
 
 #include <err.h>
-#include <errno.h>
-#include <langinfo.h>
-#include <limits.h>
 #include <locale.h>
-#include <paths.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
-#include <timeconv.h>
 #include <unistd.h>
+#ifdef SUPPORT_UTMP
+#include <utmp.h>
+#endif
+#ifdef SUPPORT_UTMPX
 #include <utmpx.h>
+#endif
+#ifdef __APPLE__
+#include <limits.h>
+#include <paths.h>
+#include <stdint.h>
+#endif /* __APPLE__ */
+
+#include "utmpentry.h"
 
-/* from utmp.h; used only for print formatting */
-#define        UT_NAMESIZE     8
-#define        UT_LINESIZE     8
-#define        UT_HOSTSIZE     16
-
-static void    heading(void);
-static void    process_utmp(void);
-static void    process_wtmp();
-static void    quick(void);
-static void    row(const struct utmpx *);
-static int     ttywidth(void);
-static void    usage(void);
-static void    whoami(void);
-
-static int     bflag;                  /* date & time of last reboot */
-static int     dflag;                  /* dead processes */
-static int     Hflag;                  /* Write column headings */
-static int     lflag;                  /* waiting to login */
-static int     mflag;                  /* Show info about current terminal */
-static int     pflag;                  /* Processes active & spawned by init */
-static int     qflag;                  /* "Quick" mode */
-static int     rflag;                  /* run-level of the init process */
-static int     sflag;                  /* Show name, line, time */
-static int     tflag;                  /* time of change to system clock */
-static int     Tflag;                  /* Show terminal state */
-static int     uflag;                  /* Show idle time */
 #ifdef __APPLE__
-#include <get_compat.h>
-#else  /* !__APPLE__ */
-#define COMPAT_MODE(a,b) (1)
+#define __UNCONST(a)   ((void *)(unsigned long)(const void *)(a))
 #endif /* __APPLE__ */
-static int     unix2003_std;
+
+static void output_labels(void);
+static void who_am_i(const char *, int);
+static void usage(void) __dead;
+static void process(const char *, int);
+static void eprint(const struct utmpentry *);
+static void print(const char *, const char *, time_t, const char *, pid_t pid,
+    uint16_t term, uint16_t xit, uint16_t sess, uint16_t type);
+static void quick(const char *);
+
+static int show_term;                  /* show term state */
+static int show_idle;                  /* show idle time */
+#ifndef __APPLE__
+static int show_details;               /* show exit status etc. */
+#endif /* !__APPLE__ */
+
+struct ut_type_names {
+  int type;
+  const char *name;
+} ut_type_names[] = {
+#ifdef SUPPORT_UTMPX
+  { EMPTY, "empty" }, 
+  { RUN_LVL, "run level" }, 
+  { BOOT_TIME, "boot time" }, 
+  { OLD_TIME, "old time" }, 
+  { NEW_TIME, "new time" }, 
+  { INIT_PROCESS, "init process" }, 
+  { LOGIN_PROCESS, "login process" }, 
+  { USER_PROCESS, "user process" }, 
+  { DEAD_PROCESS, "dead process" }, 
+#if defined(_NETBSD_SOURCE)
+  { ACCOUNTING, "accounting" }, 
+  { SIGNATURE, "signature" },
+  { DOWN_TIME, "down time" },
+#endif /* _NETBSD_SOURCE */
+#endif /* SUPPORT_UTMPX */
+  { -1, "unknown" }
+};
 
 int
 main(int argc, char *argv[])
 {
-       int ch;
+       int c, only_current_term, show_labels, quick_mode, default_mode;
+       int et = 0;
 
-       setlocale(LC_TIME, "");
+       setlocale(LC_ALL, "");
 
-       unix2003_std = COMPAT_MODE("bin/who", "unix2003");
+       only_current_term = show_term = show_idle = show_labels = 0;
+       quick_mode = default_mode = 0;
 
-       while ((ch = getopt(argc, argv, "abdHlmpqrstTu")) != -1) {
-               switch (ch) {
-
-               case 'a':               /* -b, -d, -l, -p, -r, -t, -T and -u */
-                       bflag = dflag = lflag = pflag = 1;
-                       rflag = tflag = Tflag = uflag = 1;
+       while ((c = getopt(argc, argv, "abdHlmpqrsTtuv")) != -1) {
+               switch (c) {
+               case 'a':
+                       et = -1;
+#ifdef __APPLE__
+                       show_idle = 1;
+#else /* !__APPLE__ */
+                       show_idle = show_details = 1;
+#endif /* __APPLE__ */
                        break;
-               case 'b':               /* date & time of last reboot */
-                       bflag = 1;
+               case 'b':
+                       et |= (1 << BOOT_TIME);
                        break;
-               case 'd':               /* dead processes */
-                       dflag = 1;
+               case 'd':
+                       et |= (1 << DEAD_PROCESS);
                        break;
-               case 'H':               /* Write column headings */
-                       Hflag = 1;
+               case 'H':
+                       show_labels = 1;
                        break;
-               case 'l':               /* waiting to login */
-                       lflag = 1;
+               case 'l':
+                       et |= (1 << LOGIN_PROCESS);
                        break;
-               case 'm':               /* Show info about current terminal */
-                       mflag = 1;
+               case 'm':
+                       only_current_term = 1;
                        break;
-               case 'p':               /* Processes active & spawned by init */
-                       pflag = 1;
+               case 'p':
+                       et |= (1 << INIT_PROCESS);
                        break;
-               case 'q':               /* "Quick" mode */
-                       qflag = 1;
+               case 'q':
+                       quick_mode = 1;
                        break;
-               case 'r':               /* run-level of the init process */
-                       rflag = 1;
+               case 'r':
+                       et |= (1 << RUN_LVL);
                        break;
-               case 's':               /* Show name, line, time */
-                       sflag = 1;
+               case 's':
+                       default_mode = 1;
                        break;
-               case 't':               /* time of change to system clock */
-                       tflag = 1;
+               case 'T':
+                       show_term = 1;
                        break;
-               case 'T':               /* Show terminal state */
-                       Tflag = 1;
+               case 't':
+                       et |= (1 << NEW_TIME);
                        break;
-               case 'u':               /* Show idle time */
-                       uflag = 1;
+               case 'u':
+                       show_idle = 1;
                        break;
+#ifndef __APPLE__
+               case 'v':
+                       show_details = 1;
+                       break;
+#endif /* !__APPLE__ */
                default:
                        usage();
-                       /*NOTREACHED*/
+                       /* NOTREACHED */
                }
        }
        argc -= optind;
        argv += optind;
 
-       if (argc >= 2 && strcmp(argv[0], "am") == 0 &&
-           (strcmp(argv[1], "i") == 0 || strcmp(argv[1], "I") == 0)) {
-               /* "who am i" or "who am I", equivalent to -m */
-               mflag = 1;
-               argc -= 2;
-               argv += 2;
+       if (et != 0)
+               etype = et;
+
+#ifndef __APPLE__
+       if (chdir("/dev")) {
+               err(EXIT_FAILURE, "cannot change directory to /dev");
+               /* NOTREACHED */
        }
-       if (argc > 1)
+#endif /* !__APPLE__ */
+
+       if (default_mode)
+               only_current_term = show_term = show_idle = 0;
+
+       switch (argc) {
+       case 0:                                 /* who */
+               if (quick_mode) {
+                       quick(NULL);
+               } else if (only_current_term) {
+                       who_am_i(NULL, show_labels);
+               } else {
+                       process(NULL, show_labels);
+               }
+               break;
+       case 1:                                 /* who utmp_file */
+               if (quick_mode) {
+                       quick(*argv);
+               } else if (only_current_term) {
+                       who_am_i(*argv, show_labels);
+               } else {
+                       process(*argv, show_labels);
+               }
+               break;
+       case 2:                                 /* who am i */
+               who_am_i(NULL, show_labels);
+               break;
+       default:
                usage();
-
-       if (*argv != NULL) {
-               if (!utmpxname(*argv) || !wtmpxname(*argv))
-                   usage();
+               /* NOTREACHED */
        }
 
-       if (qflag)
-               quick();
-       else {
-               if (sflag)
-                       Tflag = uflag = 0;
-               if (Hflag)
-                       heading();
-               if (mflag)
-                       whoami();
-               else
-                       /* read and process utmpx file for relevant options */
-                       if( Tflag || uflag || !(bflag || dflag || lflag || pflag || rflag) )
-                               process_utmp();
-       }
+       return 0;
+}
 
-       /* read and process wtmp file for relevant options */
-       if (bflag || dflag || lflag || pflag || rflag ) {
+static char *
+strrstr(const char *str, const char *pat)
+{
+       const char *estr;
+       size_t len;
+       if (*pat == '\0')
+               return __UNCONST(str);
 
-               process_wtmp();
-       }
+       len = strlen(pat);
 
-       endutxent();
-       exit(0);
+       for (estr = str + strlen(str); str < estr; estr--)
+               if (strncmp(estr, pat, len) == 0)
+                       return __UNCONST(estr);
+       return NULL;
 }
 
 static void
-usage(void)
+who_am_i(const char *fname, int show_labels)
 {
-
-       fprintf(stderr, "usage: who [-abdHlmpqrstTu] [am I] [file]\n");
-       exit(1);
+       struct passwd *pw;
+       const char *p;
+       char *t;
+       time_t now;
+       struct utmpentry *ehead, *ep;
+
+       /* search through the utmp and find an entry for this tty */
+       if ((p = ttyname(STDIN_FILENO)) != NULL) {
+
+               /* strip directory prefixes for ttys */
+               if ((t = strrstr(p, "/pts/")) != NULL ||
+                   (t = strrchr(p, '/')) != NULL)
+                       p = t + 1;
+
+               (void)getutentries(fname, &ehead);
+               for (ep = ehead; ep; ep = ep->next)
+                       if (strcmp(ep->line, p) == 0) {
+                               if (show_labels)
+                                       output_labels();
+                               eprint(ep);
+                               return;
+                       }
+       } else
+               p = "tty??";
+
+       (void)time(&now);
+       pw = getpwuid(getuid());
+       if (show_labels)
+               output_labels();
+       print(pw ? pw->pw_name : "?", p, now, "", getpid(), 0, 0, 0, 0);
 }
 
 static void
-heading(void)
+process(const char *fname, int show_labels)
 {
+       struct utmpentry *ehead, *ep;
+       (void)getutentries(fname, &ehead);
+       if (show_labels)
+               output_labels();
+       for (ep = ehead; ep != NULL; ep = ep->next)
+               eprint(ep);
+#ifdef __APPLE__
+       if ((etype & (1 << RUN_LVL)) != 0) {
+               printf("   .       run-level 3\n");
+       }
+#endif /* __APPLE__ */
+}
 
-       printf("%-*s ", UT_NAMESIZE, "NAME");
-       if (Tflag)
-               printf("S ");
-       printf("%-*s ", UT_LINESIZE, "LINE");
-       printf("%-*s ", 12, "TIME");
-       if (uflag)
-               printf("IDLE  ");
-       if (unix2003_std && uflag && !Tflag)
-               printf("     PID ");
-       printf("%-*s", UT_HOSTSIZE, "FROM");
-       putchar('\n');
+static void
+eprint(const struct utmpentry *ep)
+{
+       print(ep->name, ep->line, (time_t)ep->tv.tv_sec, ep->host, ep->pid,
+#ifdef __APPLE__
+           0, 0, 0, ep->type);
+#else /* !__APPLE__ */
+           ep->term, ep->exit, ep->sess, ep->type);
+#endif /* __APPLE__ */
 }
 
 static void
-row(const struct utmpx *ut)
+print(const char *name, const char *line, time_t t, const char *host,
+    pid_t pid, uint16_t term, uint16_t xit, uint16_t sess, uint16_t type)
 {
-       char buf[80], tty[sizeof(_PATH_DEV) + _UTX_LINESIZE];
        struct stat sb;
-       time_t idle, t;
-       static int d_first = -1;
-       struct tm *tm;
        char state;
-       char login_pidstr[20];
+       static time_t now = 0;
+       time_t idle;
+       const char *types = NULL;
+       size_t i;
 
-       if (d_first < 0)
-               d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
+       state = '?';
+       idle = 0;
 
-       if (Tflag || uflag) {
-               snprintf(tty, sizeof(tty), "%s%.*s", _PATH_DEV,
-                       _UTX_LINESIZE, ut->ut_line);
-               state = '?';
-               idle = 0;
+       for (i = 0; ut_type_names[i].type >= 0; i++) {
+               types = ut_type_names[i].name;
+               if (ut_type_names[i].type == type)
+                       break;
+       }
+       
+       if (show_term || show_idle) {
+               if (now == 0)
+                       time(&now);
+               
+#ifdef __APPLE__
+               char tty[PATH_MAX + 1];
+               snprintf(tty, sizeof(tty), "%s%s", _PATH_DEV, line);
                if (stat(tty, &sb) == 0) {
-                       state = sb.st_mode & (S_IWOTH|S_IWGRP) ?
-                           '+' : '-';
-                       idle = time(NULL) - sb.st_mtime;
-               }
-               if (unix2003_std && !Tflag) {
-                       /* uflag without Tflag */
-                       if (ut->ut_pid) {
-                               snprintf(login_pidstr,sizeof(login_pidstr),
-                                               "%8d",ut->ut_pid);
-                       } else {
-                               strcpy(login_pidstr,"       ?");
-                       }
+#else /* !__APPLE__ */
+               if (stat(line, &sb) == 0) {
+#endif /* __APPLE__ */
+                       state = (sb.st_mode & 020) ? '+' : '-';
+                       idle = now - sb.st_atime;
                }
+               
        }
 
-       printf("%-*.*s ", UT_NAMESIZE, _UTX_USERSIZE, ut->ut_user);
-       if (Tflag)
-               printf("%c ", state);
-       printf("%-*.*s ", UT_LINESIZE, _UTX_LINESIZE, ut->ut_line);
-       t = _time32_to_time(ut->ut_tv.tv_sec);
-       tm = localtime(&t);
-       strftime(buf, sizeof(buf), d_first ? "%e %b %R" : "%b %e %R", tm);
-       printf("%-*s ", 12, buf);
-       if (uflag) {
-               if (idle < 60)
-                       printf("  .   ");
-               else if (idle < 24 * 60 * 60)
-                       printf("%02d:%02d ", (int)(idle / 60 / 60),
-                           (int)(idle / 60 % 60));
-               else
-                       printf(" old  ");
-               if (unix2003_std && !Tflag) {
-                       printf("%s ", login_pidstr);
-               }
+#ifdef __APPLE__
+       switch (type) {
+       case LOGIN_PROCESS:
+               (void)printf("%-*.*s ", maxname, maxname, "LOGIN");
+               break;
+       case BOOT_TIME:
+               (void)printf("%-*.*s ", maxname, maxname, "reboot");
+               break;
+       default:
+               (void)printf("%-*.*s ", maxname, maxname, name);
+               break;
        }
-       if (*ut->ut_host != '\0')
-               printf("(%.*s)", _UTX_HOSTSIZE, ut->ut_host);
-       putchar('\n');
-
-}
+#else /* !__APPLE__ */
+       (void)printf("%-*.*s ", maxname, maxname, name);
+#endif /* __APPLE__ */
 
-static void
-process_utmp(void)
-{
-       struct utmpx *ut;
+       if (show_term)
+               (void)printf("%c ", state);
 
-       while ((ut = getutxent()) != NULL)
-               if (*ut->ut_user != '\0' && ut->ut_type == USER_PROCESS) {
-                       row(ut);
-               }
-}
-
-/* For some options, process the wtmp file to generate output */
-static void
-process_wtmp(void)
-{
-       struct utmpx *ut;
-       struct utmpx lboot_ut;
-       int num = 0;    /* count of user entries */
-
-       setutxent_wtmp(0);      /* zero means reverse chronological */
-       lboot_ut.ut_type = 0;
-       while (!lboot_ut.ut_type && (ut = getutxent_wtmp()) != NULL) {
-               switch(ut->ut_type) {
-               case BOOT_TIME:
-                       lboot_ut = *ut;
-                       strcpy(lboot_ut.ut_user, "reboot");
-                       strcpy(lboot_ut.ut_line, "~");
-                       break;
-               case INIT_PROCESS:
-               case LOGIN_PROCESS:
-               case USER_PROCESS:
-               case DEAD_PROCESS:
-                       num++;
-                       break;
+#ifdef __APPLE__
+       (void)printf("%-*.*s ", maxline, maxline, type == BOOT_TIME ? "~" : line);
+#else /* !__APPLE__ */
+       (void)printf("%-*.*s ", maxline, maxline, line);
+#endif /* __APPLE__ */
+       (void)printf("%.12s ", ctime(&t) + 4);
+
+       if (show_idle) {
+               if (idle < 60) 
+                       (void)printf("  .   ");
+               else if (idle < (24 * 60 * 60))
+                       (void)printf("%02ld:%02ld ", 
+                                    (long)(idle / (60 * 60)),
+                                    (long)(idle % (60 * 60)) / 60);
+               else
+                       (void)printf(" old  ");
+
+               (void)printf("\t%6d", pid);
+               
+#ifndef __APPLE__
+               if (show_details) {
+                       if (type == RUN_LVL)
+                               (void)printf("\tnew=%c old=%c", term, xit);
+                       else
+                               (void)printf("\tterm=%d exit=%d", term, xit);
+                       (void)printf(" sess=%d", sess);
+                       (void)printf(" type=%s ", types);
                }
+#endif /* !__APPLE__ */
        }
-       endutxent_wtmp();
-
-       if (bflag && lboot_ut.ut_type)
-               row(&lboot_ut);
+       
+#ifdef __APPLE__
+       /* 6179576 */
+       if (type == DEAD_PROCESS)
+               (void)printf("\tterm=%d exit=%d", 0, 0);
+#endif /* __APPLE__ */
 
-       /* run level of the init process is unknown in BSD system. If multi
-          user, then display the highest run level. Else, no-op.
-       */
-       if (rflag && (num > 1))
-               printf("   .       run-level 3\n");
+       if (*host)
+               (void)printf("\t(%.*s)", maxhost, host);
+       (void)putchar('\n');
 }
 
 static void
-quick(void)
+output_labels(void)
 {
-       struct utmpx *ut;
-       int col, ncols, num;
-
-       ncols = ttywidth();
-       col = num = 0;
-       while ((ut = getutxent()) != NULL) {
-               if (*ut->ut_user == '\0' || ut->ut_type != USER_PROCESS)
-                       continue;
-               printf("%-*.*s", UT_NAMESIZE, _UTX_USERSIZE, ut->ut_user);
-               if (++col < ncols / (UT_NAMESIZE + 1))
-                       putchar(' ');
-               else {
-                       col = 0;
-                       putchar('\n');
-               }
-               num++;
-       }
-       if (col != 0)
-               putchar('\n');
-
-       printf("# users = %d\n", num);
+       (void)printf("%-*.*s ", maxname, maxname, "USER");
+
+       if (show_term)
+               (void)printf("S ");
+       
+       (void)printf("%-*.*s ", maxline, maxline, "LINE");
+       (void)printf("WHEN         ");
+
+       if (show_idle) {
+               (void)printf("IDLE  ");
+               (void)printf("\t   PID");
+       
+               (void)printf("\tCOMMENT");
+       }               
+
+       (void)putchar('\n');
 }
 
 static void
-whoami(void)
+quick(const char *fname)
 {
-       struct utmpx ut;
-       struct utmpx *u;
-       struct passwd *pwd;
-       const char *name, *p, *tty;
-
-       if ((tty = ttyname(STDIN_FILENO)) == NULL)
-               tty = "tty??";
-       else if ((p = strrchr(tty, '/')) != NULL)
-               tty = p + 1;
-
-       memset(&ut, 0, sizeof(ut));
-       strncpy(ut.ut_line, tty, sizeof(ut.ut_line));
-       memcpy(ut.ut_id, tty + (strlen(tty) - sizeof(ut.ut_id)), sizeof(ut.ut_id));
-       ut.ut_type = USER_PROCESS;
-       /* Search utmp for our tty, dump first matching record. */
-       u = getutxid(&ut);
-       if (u) {
-               row(u);
-               return;
+       struct utmpentry *ehead, *ep;
+       int num = 0;
+
+       (void)getutentries(fname, &ehead);
+       for (ep = ehead; ep != NULL; ep = ep->next) {
+               (void)printf("%-*s ", maxname, ep->name);
+               if ((++num % 8) == 0)
+                       (void)putchar('\n');
        }
+       if (num % 8)
+               (void)putchar('\n');
 
-       /* Not found; fill the utmpx structure with the information we have. */
-       if ((pwd = getpwuid(getuid())) != NULL)
-               name = pwd->pw_name;
-       else
-               name = "?";
-       strncpy(ut.ut_user, name, _UTX_USERSIZE);
-       ut.ut_tv.tv_sec = _time_to_time32(time(NULL));
-       row(&ut);
+       (void)printf("# users = %d\n", num);
 }
 
-static int
-ttywidth(void)
+static void
+usage(void)
 {
-       struct winsize ws;
-       long width;
-       char *cols, *ep;
-
-       if ((cols = getenv("COLUMNS")) != NULL && *cols != '\0') {
-               errno = 0;
-               width = strtol(cols, &ep, 10);
-               if (errno || width <= 0 || width > INT_MAX || ep == cols ||
-                   *ep != '\0')
-                       warnx("invalid COLUMNS environment variable ignored");
-               else
-                       return (width);
-       }
-       if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1)
-               return (ws.ws_col);
-
-       return (80);
+#ifdef __APPLE__
+       (void)fprintf(stderr, "Usage: %s [-abdHlmpqrsTtu] [file]\n\t%s am i\n",
+#else /* !__APPLE__ */
+       (void)fprintf(stderr, "Usage: %s [-abdHlmqrsTtuv] [file]\n\t%s am i\n",
+#endif /* __APPLE__ */
+           getprogname(), getprogname());
+       exit(EXIT_FAILURE);
 }
index f8a8592e8adbbe77539d20ef0645bcccd7e7e0a8..90551f98a3d6a76b6e793dd6edeb469c51551a09 100644 (file)
@@ -283,6 +283,9 @@ In addition, the
 and
 .Fl n
 options are not mutually-exclusive.
+.Pp
+For more information about legacy mode, see
+.Xr compat 5 .
 .Sh EXIT STATUS
 The
 .Nm
index 8f71d99a1c84633b59e69f2e3476b43a3bf6769a..2d42c6292ca17856800864b3455f174e9bcf1f12 100644 (file)
@@ -100,7 +100,8 @@ int
 main(int argc, char *argv[])
 {
        long arg_max;
-       int ch, Jflag, nargs, nflag, nline;
+       int ch, Jflag, nflag, nline;
+       size_t nargs;
        size_t linelen;
        char *endptr;
 
@@ -158,7 +159,7 @@ main(int argc, char *argv[])
                        break;
                case 'n':
                        nflag = 1;
-                       if ((nargs = atoi(optarg)) <= 0)
+                       if ((nargs = strtol(optarg, NULL, 10)) <= 0)
                                errx(1, "illegal argument count");
                        if (COMPAT_MODE("bin/xargs", "Unix2003")) {
                                Lflag = 0; /* Override */
@@ -324,6 +325,19 @@ arg2:
                foundeof = *eofstr != '\0' &&
                    strcmp(argp, eofstr) == 0;
 
+#ifdef __APPLE__
+               /* 6591323: -I specifies that it processes the entire line,
+                * so only recognize eofstr at the end of a line. */
+               if (Iflag && !last_was_newline)
+                       foundeof = 0;
+
+               /* 6591323: Essentially the same as the EOF handling above. */
+               if (foundeof && (p - strlen(eofstr) == bbp)) {
+                       waitchildren(*argv, 1);
+                       exit(rval);
+               }
+#endif
+
                /* Do not make empty args unless they are quoted */
                if ((argp != p || wasquoted) && !foundeof) {
                        *p++ = '\0';