]> git.saurik.com Git - apple/shell_cmds.git/commitdiff
shell_cmds-187.tar.gz os-x-1011 os-x-10111 os-x-10112 os-x-10113 os-x-10114 os-x-10115 os-x-10116 v187
authorApple <opensource@apple.com>
Fri, 16 Jan 2015 20:06:17 +0000 (20:06 +0000)
committerApple <opensource@apple.com>
Fri, 16 Jan 2015 20:06:17 +0000 (20:06 +0000)
20 files changed:
env/env.1
env/env.c
env/envopts.c [new file with mode: 0644]
env/envopts.h [new file with mode: 0644]
find/find.1
find/find.plist.part [new file with mode: 0644]
find/function.c
locate/locate/updatedb.sh
mktemp/mktemp.1
mktemp/mktemp.c
mktemp/mktemp.plist.part [new file with mode: 0644]
path_helper/path_helper.c
printenv/printenv.1
printenv/printenv.c
script/script.1
script/script.c
script/script.plist.part [new file with mode: 0644]
shell_cmds.xcodeproj/project.pbxproj
systime/systime.1
systime/systime.c

index d281dc993f9ca74016735e5f02cf911e23525bd9..101f4ebffcfbf871238aa0bbecd04ac5095cd5af 100644 (file)
--- a/env/env.1
+++ b/env/env.1
@@ -1,7 +1,5 @@
-.\"    $NetBSD: env.1,v 1.6 1997/10/18 13:55:22 lukem Exp $
-.\"
-.\" Copyright (c) 1980, 1990 The Regents of the University of California.
-.\" All rights reserved.
+.\" Copyright (c) 1980, 1990, 1993
+.\"    The Regents of the University of California.  All rights reserved.
 .\"
 .\" This code is derived from software contributed to Berkeley by
 .\" the Institute of Electrical and Electronics Engineers, Inc.
 .\" 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.
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    from: @(#)printenv.1    6.7 (Berkeley) 7/28/91
-.\"    $NetBSD: env.1,v 1.6 1997/10/18 13:55:22 lukem Exp $
+.\" From @(#)printenv.1        8.1 (Berkeley) 6/6/93
+.\" From FreeBSD: src/usr.bin/printenv/printenv.1,v 1.17 2002/11/26 17:33:35 ru Exp
+.\" $FreeBSD$
 .\"
-.Dd August 27, 1993
+.Dd April 17, 2008
 .Dt ENV 1
 .Os
 .Sh NAME
 .Nm env
-.Nd set and print environment
+.Nd set environment and execute command, or print environment
 .Sh SYNOPSIS
 .Nm
-.Op Fl i
-.Op Ar name=value ...
-.Oo
-.Ar utility
-.Op argument ...
-.Oc
+.Op Fl iv
+.Op Fl P Ar altpath
+.Op Fl S Ar string
+.Op Fl u Ar name
+.Op Ar name Ns = Ns Ar value ...
+.Op Ar utility Op Ar argument ...
 .Sh DESCRIPTION
+The
 .Nm
-executes
+utility executes another
 .Ar utility
 after modifying the environment as
-specified on the command line.  The option
-.Ar name=value
-specifies
-an environmental variable,
-.Ar name  ,
+specified on the command line.
+Each
+.Ar name Ns = Ns Ar value
+option specifies the setting of an environment variable,
+.Ar name ,
 with a value of
-.Ar value  .
-The option
-.Sq Fl i
-causes
+.Ar value .
+All such environment variables are set before the
+.Ar utility
+is executed.
+.Pp
+The options are as follows:
+.Bl -tag -width indent
+.It Fl i
+Execute the
+.Ar utility
+with only those environment variables specified by
+.Ar name Ns = Ns Ar value
+options.
+The environment inherited
+by
+.Nm
+is ignored completely.
+.\"    -P
+.It Fl P Ar altpath
+Search the set of directories as specified by
+.Ar altpath
+to locate the specified
+.Ar utility
+program, instead of using the value of the
+.Ev PATH
+environment variable.
+.\"    -S
+.It Fl S Ar string
+Split apart the given
+.Ar string
+into multiple strings, and process each of the resulting strings
+as separate arguments to the
+.Nm
+utility.
+The
+.Fl S
+option recognizes some special character escape sequences and
+also supports environment-variable substitution, as described
+below.
+.\"    -u
+.It Fl u Ar name
+If the environment variable
+.Ar name
+is in the environment, then remove it before processing the
+remaining options.
+This is similar to the
+.Ic unset
+command in
+.Xr sh 1 .
+The value for
+.Ar name
+must not include the
+.Ql =
+character.
+.\"    -v
+.It Fl v
+Print verbose information for each step of processing done by the
 .Nm
-to completely ignore the environment
-it inherits.
+utility.
+Additional information will be printed if
+.Fl v
+is specified multiple times.
+.El
+.Pp
+The above options are only recognized when they are specified
+before any
+.Ar name Ns = Ns Ar value
+options.
 .Pp
-If no 
+If no
 .Ar utility
 is specified,
 .Nm
 prints out the names and values
-of the variables in the environment, with one 
-.Ar name=value 
-pair per line.
-.Sh DIAGNOSTICS
-If the 
-.Ar utility
-is invoked, the exit status of 
+of the variables in the environment, with one name/value pair per line.
+.\"
+.Ss Details of Fl S Ss (split-string) processing
+The processing of the
+.Fl S
+option will split the given
+.Ar string
+into separate arguments based on any space or <tab> characters found in the
+.Ar string .
+Each of those new arguments will then be treated as if it had been
+specified as a separate argument on the original
 .Nm
-shall be the exit status of
-.Ar utility; 
-otherwise, the
+command.
+.Pp
+Spaces and tabs may be embedded in one of those new arguments by using
+single
+.Pq Dq Li '
+or double
+.Pq Ql \&"
+quotes, or backslashes
+.Pq Ql \e .
+Single quotes will escape all non-single quote characters, up to
+the matching single quote.
+Double quotes will escape all non-double quote characters, up to
+the matching double quote.
+It is an error if the end of the
+.Ar string
+is reached before the matching quote character.
+.Pp
+If
+.Fl S
+would create a new argument that starts with the
+.Ql #
+character, then that argument and the remainder of the
+.Ar string
+will be ignored.
+The
+.Ql \e#
+sequence can be used when you want a new argument to start
+with a
+.Ql #
+character, without causing the remainder of the
+.Ar string
+to be skipped.
+.Pp
+While processing the
+.Ar string
+value,
+.Fl S
+processing will treat certain character combinations as escape
+sequences which represent some action to take.
+The character escape sequences are in backslash notation.
+The characters and their meanings are as follows:
+.Pp
+.Bl -tag -width indent -offset indent -compact
+.It Cm \ec
+Ignore the remaining characters in the
+.Ar string .
+This must not appear inside a double-quoted string.
+.It Cm \ef
+Replace with a <form-feed> character.
+.It Cm \en
+Replace with a <new-line> character.
+.It Cm \er
+Replace with a <carriage return> character.
+.It Cm \et
+Replace with a <tab> character.
+.It Cm \ev
+Replace with a <vertical tab> character.
+.It Cm \e#
+Replace with a
+.Ql #
+character.
+This would be useful when you need a
+.Ql #
+as the first character in one of the arguments created
+by splitting apart the given
+.Ar string .
+.It Cm \e$
+Replace with a
+.Ql $
+character.
+.It Cm \e_
+If this is found inside of a double-quoted string, then replace it
+with a single blank.
+If this is found outside of a quoted string, then treat this as the
+separator character between new arguments in the original
+.Ar string .
+.It Cm \e"
+Replace with a <double quote> character.
+.It Cm \e\'
+Replace with a <single quote> character.
+.It Cm \e\e
+Replace with a backslash character.
+.El
+.Pp
+The sequences for <single-quote> and backslash are the only sequences
+which are recognized inside of a single-quoted string.
+The other sequences have no special meaning inside a single-quoted
+string.
+All escape sequences are recognized inside of a double-quoted string.
+It is an error if a single
+.Ql \e
+character is followed by a character other than the ones listed above.
+.Pp
+The processing of
+.Fl S
+also supports substitution of values from environment variables.
+To do this, the name of the environment variable must be inside of
+.Ql ${} ,
+such as:
+.Li ${SOMEVAR} .
+The common shell syntax of
+.Li $SOMEVAR
+is not supported.
+All values substituted will be the values of the environment variables
+as they were when the
 .Nm
-utility exits with one of the following values:
-.Bl -tag -width Ds
-.It 0
-The 
+utility was originally invoked.
+Those values will not be checked for any of the escape sequences as
+described above.
+And any settings of
+.Ar name Ns = Ns Ar value
+will not effect the values used for substitution in
+.Fl S
+processing.
+.Pp
+Also,
+.Fl S
+processing can not reference the value of the special parameters
+which are defined by most shells.
+For instance,
+.Fl S
+can not recognize special parameters such as:
+.Ql $* ,
+.Ql $@ ,
+.Ql $# ,
+.Ql $?
+or
+.Ql $$
+if they appear inside the given
+.Ar string .
+.\"
+.Ss Use in shell-scripts
+The
 .Nm
-utility completed successfully
-.It 1-125
-An error occurred in the
+utility is often used as the
+.Ar interpreter
+on the first line of interpreted scripts, as
+described in
+.Xr execve 2 .
+.Pp
+Note that the way the kernel parses the
+.Ql #!
+(first line) of an interpreted script has changed as of
+.Fx 6.0 .
+Prior to that, the
+.Fx
+kernel would split that first line into separate arguments based
+on any whitespace (space or <tab> characters) found in the line.
+So, if a script named
+.Pa /usr/local/bin/someport
+had a first line of:
+.Pp
+.Dl "#!/usr/local/bin/php -n -q -dsafe_mode=0"
+.Pp
+then the
+.Pa /usr/local/bin/php
+program would have been started with the arguments of:
+.Bd -literal -offset indent
+arg[0] = '/usr/local/bin/php'
+arg[1] = '-n'
+arg[2] = '-q'
+arg[3] = '-dsafe_mode=0'
+arg[4] = '/usr/local/bin/someport'
+.Ed
+.Pp
+plus any arguments the user specified when executing
+.Pa someport .
+However, this processing of multiple options on the
+.Ql #!
+line is not the way any other operating system parses the
+first line of an interpreted script.
+So after a change which was made for
+.Fx 6.0
+release, that script will result in
+.Pa /usr/local/bin/php
+being started with the arguments of:
+.Bd -literal -offset indent
+arg[0] = '/usr/local/bin/php'
+arg[1] = '-n -q -dsafe_mode=0'
+arg[2] = '/usr/local/bin/someport'
+.Ed
+.Pp
+plus any arguments the user specified.
+This caused a significant change in the behavior of a few scripts.
+In the case of above script, to have it behave the same way under
+.Fx 6.0
+as it did under earlier releases, the first line should be
+changed to:
+.Pp
+.Dl "#!/usr/bin/env -S /usr/local/bin/php -n -q -dsafe_mode=0"
+.Pp
+The
 .Nm
-utility.
-.It 126
-The utility specified by
-.Ar utility 
-was found, but could not be invoked.
-.It 127
-The utility specified by
-.Ar utility 
+utility will be started with the entire line as a single
+argument:
+.Pp
+.Dl "arg[1] = '-S /usr/local/bin/php -n -q -dsafe_mode=0'"
+.Pp
+and then
+.Fl S
+processing will split that line into separate arguments before
+executing
+.Pa /usr/local/bin/php .
+.\"
+.Sh ENVIRONMENT
+The
+.Nm
+utility uses the
+.Ev PATH
+environment variable to locate the requested
+.Ar utility
+if the name contains no
+.Ql /
+characters, unless the
+.Fl P
+option has been specified.
+.Sh EXIT STATUS
+.Ex -std
+An exit status of 126 indicates that
+.Ar utility
+was found, but could not be executed.
+An exit status of 127 indicates that
+.Ar utility
 could not be found.
-.El
+.Sh EXAMPLES
+Since the
+.Nm
+utility is often used as part of the first line of an interpreted script,
+the following examples show a number of ways that the
+.Nm
+utility can be useful in scripts.
+.Pp
+The kernel processing of an interpreted script does not allow a script
+to directly reference some other script as its own interpreter.
+As a way around this, the main difference between
+.Pp
+.Dl #!/usr/local/bin/foo
+and
+.Dl "#!/usr/bin/env /usr/local/bin/foo"
+.Pp
+is that the latter works even if
+.Pa /usr/local/bin/foo
+is itself an interpreted script.
+.Pp
+Probably the most common use of
+.Nm
+is to find the correct interpreter for a script, when the interpreter
+may be in different directories on different systems.
+The following example will find the
+.Ql perl
+interpreter by searching through the directories specified by
+.Ev PATH .
+.Pp
+.Dl "#!/usr/bin/env perl"
+.Pp
+One limitation of that example is that it assumes the user's value
+for
+.Ev PATH
+is set to a value which will find the interpreter you want
+to execute.
+The
+.Fl P
+option can be used to make sure a specific list of directories is
+used in the search for
+.Ar utility .
+Note that the
+.Fl S
+option is also required for this example to work correctly.
+.Pp
+.Dl "#!/usr/bin/env -S -P/usr/local/bin:/usr/bin perl"
+.Pp
+The above finds
+.Ql perl
+only if it is in
+.Pa /usr/local/bin
+or
+.Pa /usr/bin .
+That could be combined with the present value of
+.Ev PATH ,
+to provide more flexibility.
+Note that spaces are not required between the
+.Fl S
+and
+.Fl P
+options:
+.Pp
+.Dl "#!/usr/bin/env -S-P/usr/local/bin:/usr/bin:${PATH} perl"
 .Sh COMPATIBILITY
-The historic 
-.Fl 
-option has been deprecated but is still supported in this implementation.
+The
+.Nm
+utility accepts the
+.Fl
+option as a synonym for
+.Fl i .
 .Sh SEE ALSO
+.Xr printenv 1 ,
+.Xr sh 1 ,
 .Xr execvp 3 ,
 .Xr environ 7
 .Sh STANDARDS
 The
 .Nm
 utility conforms to
-.St -p1003.2-92 .
+.St -p1003.1-2001 .
+The
+.Fl P , S , u
+and
+.Fl v
+options are non-standard extensions supported by
+.Fx ,
+but which may not be available on other operating systems.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.4 .
+The
+.Fl P , S
+and
+.Fl v
+options were added in
+.Fx 6.0 .
 .Sh BUGS
+The
+.Nm
+utility does not handle values of
+.Ar utility
+which have an equals sign
+.Pq Ql =
+in their name, for obvious reasons.
+.Pp
+The
 .Nm
-doesn't handle commands with equal
-.Pq Dq =
-signs in their
-names, for obvious reasons.
+utility does not take multibyte characters into account when
+processing the
+.Fl S
+option, which may lead to incorrect results in some locales.
index 8d71dd80ce82767bf86bbed190f42e13a12df574..3dc152ad37a7b26f7f373e328736fbb4123508a9 100644 (file)
--- a/env/env.c
+++ b/env/env.c
  * 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.
@@ -44,7 +40,7 @@ static char sccsid[] = "@(#)env.c     8.3 (Berkeley) 4/2/94";
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$FreeBSD: src/usr.bin/env/env.c,v 1.11 2002/09/04 23:28:59 dwmalone Exp $");
+__FBSDID("$FreeBSD$");
 
 #include <err.h>
 #include <errno.h>
@@ -53,31 +49,83 @@ __RCSID("$FreeBSD: src/usr.bin/env/env.c,v 1.11 2002/09/04 23:28:59 dwmalone Exp
 #include <stdlib.h>
 #include <unistd.h>
 
+#include "envopts.h"
+
 extern char **environ;
 
+int     env_verbosity;
+
 static void usage(void);
 
 int
 main(int argc, char **argv)
 {
-       char **ep, *p;
+       char *altpath, **ep, *p, **parg;
        char *cleanenv[1];
-       int ch;
+       int ch, want_clear;
+       int rtrn;
 
-       while ((ch = getopt(argc, argv, "-i")) != -1)
+       altpath = NULL;
+       want_clear = 0;
+       while ((ch = getopt(argc, argv, "-iP:S:u:v")) != -1)
                switch(ch) {
                case '-':
                case 'i':
-                       environ = cleanenv;
-                       cleanenv[0] = NULL;
+                       want_clear = 1;
+                       break;
+               case 'P':
+                       altpath = strdup(optarg);
+                       break;
+               case 'S':
+                       /*
+                        * The -S option, for "split string on spaces, with
+                        * support for some simple substitutions"...
+                        */
+                       split_spaces(optarg, &optind, &argc, &argv);
+                       break;
+               case 'u':
+                       if (env_verbosity)
+                               fprintf(stderr, "#env unset:\t%s\n", optarg);
+                       rtrn = unsetenv(optarg);
+                       if (rtrn == -1)
+                               err(EXIT_FAILURE, "unsetenv %s", optarg);
+                       break;
+               case 'v':
+                       env_verbosity++;
+                       if (env_verbosity > 1)
+                               fprintf(stderr, "#env verbosity now at %d\n",
+                                   env_verbosity);
                        break;
                case '?':
                default:
                        usage();
                }
-       for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv)
-               (void)putenv(*argv);
+       if (want_clear) {
+               environ = cleanenv;
+               cleanenv[0] = NULL;
+               if (env_verbosity)
+                       fprintf(stderr, "#env clearing environ\n");
+       }
+       for (argv += optind; *argv && (p = strchr(*argv, '=')); ++argv) {
+               if (env_verbosity)
+                       fprintf(stderr, "#env setenv:\t%s\n", *argv);
+               *p = '\0';
+               rtrn = setenv(*argv, p + 1, 1);
+               *p = '=';
+               if (rtrn == -1)
+                       err(EXIT_FAILURE, "setenv %s", *argv);
+       }
        if (*argv) {
+               if (altpath)
+                       search_paths(altpath, argv);
+               if (env_verbosity) {
+                       fprintf(stderr, "#env executing:\t%s\n", *argv);
+                       for (parg = argv, argc = 0; *parg; parg++, argc++)
+                               fprintf(stderr, "#env    arg[%d]=\t'%s'\n",
+                                   argc, *parg);
+                       if (env_verbosity > 1)
+                               sleep(1);
+               }
                execvp(*argv, argv);
                err(errno == ENOENT ? 127 : 126, "%s", *argv);
        }
@@ -90,6 +138,7 @@ static void
 usage(void)
 {
        (void)fprintf(stderr,
-           "usage: env [-i] [name=value ...] [utility [argument ...]]\n");
+           "usage: env [-iv] [-P utilpath] [-S string] [-u name]\n"
+           "           [name=value ...] [utility [argument ...]]\n");
        exit(1);
 }
diff --git a/env/envopts.c b/env/envopts.c
new file mode 100644 (file)
index 0000000..f821430
--- /dev/null
@@ -0,0 +1,468 @@
+/*-
+ * Copyright (c) 2005  - Garance Alistair Drosehn <gad@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the FreeBSD Project.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <err.h>
+#include <errno.h>
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "envopts.h"
+
+static const char *
+                expand_vars(int in_thisarg, char **thisarg_p, char **dest_p,
+                    const char **src_p);
+static int      is_there(char *candidate);
+
+/*
+ * The is*() routines take a parameter of 'int', but expect values in the range
+ * of unsigned char.  Define some wrappers which take a value of type 'char',
+ * whether signed or unsigned, and ensure the value ends up in the right range.
+ */
+#define        isalnumch(Anychar) isalnum((u_char)(Anychar))
+#define        isalphach(Anychar) isalpha((u_char)(Anychar))
+#define        isspacech(Anychar) isspace((u_char)(Anychar))
+
+/*
+ * Routine to determine if a given fully-qualified filename is executable.
+ * This is copied almost verbatim from FreeBSD's usr.bin/which/which.c.
+ */
+static int
+is_there(char *candidate)
+{
+        struct stat fin;
+
+        /* XXX work around access(2) false positives for superuser */
+        if (access(candidate, X_OK) == 0 &&
+            stat(candidate, &fin) == 0 &&
+            S_ISREG(fin.st_mode) &&
+            (getuid() != 0 ||
+            (fin.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)) {
+                if (env_verbosity > 1)
+                       fprintf(stderr, "#env   matched:\t'%s'\n", candidate);
+                return (1);
+        }
+        return (0);
+}
+
+/**
+ * Routine to search through an alternate path-list, looking for a given
+ * filename to execute.  If the file is found, replace the original
+ * unqualified name with a fully-qualified path.  This allows `env' to
+ * execute programs from a specific strict list of possible paths, without
+ * changing the value of PATH seen by the program which will be executed.
+ * E.G.:
+ *     #!/usr/bin/env -S-P/usr/local/bin:/usr/bin perl
+ * will execute /usr/local/bin/perl or /usr/bin/perl (whichever is found
+ * first), no matter what the current value of PATH is, and without
+ * changing the value of PATH that the script will see when it runs.
+ *
+ * This is similar to the print_matches() routine in usr.bin/which/which.c.
+ */
+void
+search_paths(char *path, char **argv)
+{
+        char candidate[PATH_MAX];
+        const char *d;
+       char *filename, *fqname;
+
+       /* If the file has a `/' in it, then no search is done */
+       filename = *argv;
+       if (strchr(filename, '/') != NULL)
+               return;
+
+       if (env_verbosity > 1) {
+               fprintf(stderr, "#env Searching:\t'%s'\n", path);
+               fprintf(stderr, "#env  for file:\t'%s'\n", filename);
+       }
+
+       fqname = NULL;
+        while ((d = strsep(&path, ":")) != NULL) {
+                if (*d == '\0')
+                        d = ".";
+                if (snprintf(candidate, sizeof(candidate), "%s/%s", d,
+                    filename) >= (int)sizeof(candidate))
+                        continue;
+                if (is_there(candidate)) {
+                        fqname = candidate;
+                       break;
+                }
+        }
+
+       if (fqname == NULL) {
+               errno = ENOENT;
+               err(127, "%s", filename);
+       }
+       *argv = strdup(candidate);
+}
+
+/**
+ * Routine to split a string into multiple parameters, while recognizing a
+ * few special characters.  It recognizes both single and double-quoted
+ * strings.  This processing is designed entirely for the benefit of the
+ * parsing of "#!"-lines (aka "shebang" lines == the first line of an
+ * executable script).  Different operating systems parse that line in very
+ * different ways, and this split-on-spaces processing is meant to provide
+ * ways to specify arbitrary arguments on that line, no matter how the OS
+ * parses it.
+ *
+ * Within a single-quoted string, the two characters "\'" are treated as
+ * a literal "'" character to add to the string, and "\\" are treated as
+ * a literal "\" character to add.  Other than that, all characters are
+ * copied until the processing gets to a terminating "'".
+ *
+ * Within a double-quoted string, many more "\"-style escape sequences
+ * are recognized, mostly copied from what is recognized in the `printf'
+ * command.  Some OS's will not allow a literal blank character to be
+ * included in the one argument that they recognize on a shebang-line,
+ * so a few additional escape-sequences are defined to provide ways to
+ * specify blanks.
+ *
+ * Within a double-quoted string "\_" is turned into a literal blank.
+ * (Inside of a single-quoted string, the two characters are just copied)
+ * Outside of a quoted string, "\_" is treated as both a blank, and the
+ * end of the current argument.  So with a shelbang-line of:
+ *             #!/usr/bin/env -SA=avalue\_perl
+ * the -S value would be broken up into arguments "A=avalue" and "perl".
+ */
+void
+split_spaces(const char *str, int *origind, int *origc, char ***origv)
+{
+       static const char *nullarg = "";
+       const char *bq_src, *copystr, *src;
+       char *dest, **newargv, *newstr, **nextarg, **oldarg;
+       int addcount, bq_destlen, copychar, found_sep, in_arg, in_dq, in_sq;
+
+       /*
+        * Ignore leading space on the string, and then malloc enough room
+        * to build a copy of it.  The copy might end up shorter than the
+        * original, due to quoted strings and '\'-processing.
+        */
+       while (isspacech(*str))
+               str++;
+       if (*str == '\0')
+               return;
+       newstr = malloc(strlen(str) + 1);
+
+       /*
+        * Allocate plenty of space for the new array of arg-pointers,
+        * and start that array off with the first element of the old
+        * array.
+        */
+       newargv = malloc((*origc + (strlen(str) / 2) + 2) * sizeof(char *));
+       nextarg = newargv;
+       *nextarg++ = **origv;
+
+       /* Come up with the new args by splitting up the given string. */
+       addcount = 0;
+       bq_destlen = in_arg = in_dq = in_sq = 0;
+       bq_src = NULL;
+       for (src = str, dest = newstr; *src != '\0'; src++) {
+               /*
+                * This switch will look at a character in *src, and decide
+                * what should be copied to *dest.  It only decides what
+                * character(s) to copy, it should not modify *dest.  In some
+                * cases, it will look at multiple characters from *src.
+                */
+               copychar = found_sep = 0;
+               copystr = NULL;
+               switch (*src) {
+               case '"':
+                       if (in_sq)
+                               copychar = *src;
+                       else if (in_dq)
+                               in_dq = 0;
+                       else {
+                               /*
+                                * Referencing nullarg ensures that a new
+                                * argument is created, even if this quoted
+                                * string ends up with zero characters.
+                                */
+                               copystr = nullarg;
+                               in_dq = 1;
+                               bq_destlen = dest - *(nextarg - 1);
+                               bq_src = src;
+                       }
+                       break;
+               case '$':
+                       if (in_sq)
+                               copychar = *src;
+                       else {
+                               copystr = expand_vars(in_arg, (nextarg - 1),
+                                   &dest, &src);
+                       }
+                       break;
+               case '\'':
+                       if (in_dq)
+                               copychar = *src;
+                       else if (in_sq)
+                               in_sq = 0;
+                       else {
+                               /*
+                                * Referencing nullarg ensures that a new
+                                * argument is created, even if this quoted
+                                * string ends up with zero characters.
+                                */
+                               copystr = nullarg;
+                               in_sq = 1;
+                               bq_destlen = dest - *(nextarg - 1);
+                               bq_src = src;
+                       }
+                       break;
+               case '\\':
+                       if (in_sq) {
+                               /*
+                                * Inside single-quoted strings, only the
+                                * "\'" and "\\" are recognized as special
+                                * strings.
+                                */
+                               copychar = *(src + 1);
+                               if (copychar == '\'' || copychar == '\\')
+                                       src++;
+                               else
+                                       copychar = *src;
+                               break;
+                       }
+                       src++;
+                       switch (*src) {
+                       case '"':
+                       case '#':
+                       case '$':
+                       case '\'':
+                       case '\\':
+                               copychar = *src;
+                               break;
+                       case '_':
+                               /*
+                                * Alternate way to get a blank, which allows
+                                * that blank be used to separate arguments
+                                * when it is not inside a quoted string.
+                                */
+                               if (in_dq)
+                                       copychar = ' ';
+                               else {
+                                       found_sep = 1;
+                                       src++;
+                               }
+                               break;
+                       case 'c':
+                               /*
+                                * Ignore remaining characters in the -S string.
+                                * This would not make sense if found in the
+                                * middle of a quoted string.
+                                */
+                               if (in_dq)
+                                       errx(1, "Sequence '\\%c' is not allowed"
+                                           " in quoted strings", *src);
+                               goto str_done;
+                       case 'f':
+                               copychar = '\f';
+                               break;
+                       case 'n':
+                               copychar = '\n';
+                               break;
+                       case 'r':
+                               copychar = '\r';
+                               break;
+                       case 't':
+                               copychar = '\t';
+                               break;
+                       case 'v':
+                               copychar = '\v';
+                               break;
+                       default:
+                               if (isspacech(*src))
+                                       copychar = *src;
+                               else
+                                       errx(1, "Invalid sequence '\\%c' in -S",
+                                           *src);
+                       }
+                       break;
+               default:
+                       if ((in_dq || in_sq) && in_arg)
+                               copychar = *src;
+                       else if (isspacech(*src))
+                               found_sep = 1;
+                       else {
+                               /*
+                                * If the first character of a new argument
+                                * is `#', then ignore the remaining chars.
+                                */
+                               if (!in_arg && *src == '#')
+                                       goto str_done;
+                               copychar = *src;
+                       }
+               }
+               /*
+                * Now that the switch has determined what (if anything)
+                * needs to be copied, copy whatever that is to *dest.
+                */
+               if (copychar || copystr != NULL) {
+                       if (!in_arg) {
+                               /* This is the first byte of a new argument */
+                               *nextarg++ = dest;
+                               addcount++;
+                               in_arg = 1;
+                       }
+                       if (copychar)
+                               *dest++ = (char)copychar;
+                       else if (copystr != NULL)
+                               while (*copystr != '\0')
+                                       *dest++ = *copystr++;
+               } else if (found_sep) {
+                       *dest++ = '\0';
+                       while (isspacech(*src))
+                               src++;
+                       --src;
+                       in_arg = 0;
+               }
+       }
+str_done:
+       *dest = '\0';
+       *nextarg = NULL;
+       if (in_dq || in_sq) {
+               errx(1, "No terminating quote for string: %.*s%s",
+                   bq_destlen, *(nextarg - 1), bq_src);
+       }
+       if (env_verbosity > 1) {
+               fprintf(stderr, "#env  split -S:\t'%s'\n", str);
+               oldarg = newargv + 1;
+               fprintf(stderr, "#env      into:\t'%s'\n", *oldarg);
+               for (oldarg++; *oldarg; oldarg++)
+                       fprintf(stderr, "#env          &\t'%s'\n", *oldarg);
+       }
+
+       /* Copy the unprocessed arg-pointers from the original array */
+       for (oldarg = *origv + *origind; *oldarg; oldarg++)
+               *nextarg++ = *oldarg;
+       *nextarg = NULL;
+
+       /* Update optind/argc/argv in the calling routine */
+       *origind = 1;
+       *origc += addcount;
+       *origv = newargv;
+}
+
+/**
+ * Routine to split expand any environment variables referenced in the string
+ * that -S is processing.  For now it only supports the form ${VARNAME}.  It
+ * explicitly does not support $VARNAME, and obviously can not handle special
+ * shell-variables such as $?, $*, $1, etc.  It is called with *src_p pointing
+ * at the initial '$', and if successful it will update *src_p, *dest_p, and
+ * possibly *thisarg_p in the calling routine.
+ */
+static const char *
+expand_vars(int in_thisarg, char **thisarg_p, char **dest_p, const char **src_p)
+{
+       const char *vbegin, *vend, *vvalue;
+       char *newstr, *vname;
+       int bad_reference;
+       size_t namelen, newlen;
+
+       bad_reference = 1;
+       vbegin = vend = (*src_p) + 1;
+       if (*vbegin++ == '{')
+               if (*vbegin == '_' || isalphach(*vbegin)) {
+                       vend = vbegin + 1;
+                       while (*vend == '_' || isalnumch(*vend))
+                               vend++;
+                       if (*vend == '}')
+                               bad_reference = 0;
+               }
+       if (bad_reference)
+               errx(1, "Only ${VARNAME} expansion is supported, error at: %s",
+                   *src_p);
+
+       /*
+        * We now know we have a valid environment variable name, so update
+        * the caller's source-pointer to the last character in that reference,
+        * and then pick up the matching value.  If the variable is not found,
+        * or if it has a null value, then our work here is done.
+        */
+       *src_p = vend;
+       namelen = vend - vbegin + 1;
+       vname = malloc(namelen);
+       strlcpy(vname, vbegin, namelen);
+       vvalue = getenv(vname);
+       if (vvalue == NULL || *vvalue == '\0') {
+               if (env_verbosity > 2)
+                       fprintf(stderr,
+                           "#env  replacing ${%s} with null string\n",
+                           vname);
+               free(vname);
+               return (NULL);
+       }
+
+       if (env_verbosity > 2)
+               fprintf(stderr, "#env  expanding ${%s} into '%s'\n", vname,
+                   vvalue);
+
+       /*
+        * There is some value to copy to the destination.  If the value is
+        * shorter than the ${VARNAME} reference that it replaces, then our
+        * caller can just copy the value to the existing destination.
+        */
+       if (strlen(vname) + 3 >= strlen(vvalue)) {
+               free(vname);
+               return (vvalue);
+       }
+
+       /*
+        * The value is longer than the string it replaces, which means the
+        * present destination area is too small to hold it.  Create a new
+        * destination area, and update the caller's 'dest' variable to match.
+        * If the caller has already started copying some info for 'thisarg'
+        * into the present destination, then the new destination area must
+        * include a copy of that data, and the pointer to 'thisarg' must also
+        * be updated.  Note that it is still the caller which copies this
+        * vvalue to the new *dest.
+        */
+       newlen = strlen(vvalue) + strlen(*src_p) + 1;
+       if (in_thisarg) {
+               **dest_p = '\0';        /* Provide terminator for 'thisarg' */
+               newlen += strlen(*thisarg_p);
+               newstr = malloc(newlen);
+               strcpy(newstr, *thisarg_p);
+               *thisarg_p = newstr;
+       } else {
+               newstr = malloc(newlen);
+               *newstr = '\0';
+       }
+       *dest_p = strchr(newstr, '\0');
+       free(vname);
+       return (vvalue);
+}
diff --git a/env/envopts.h b/env/envopts.h
new file mode 100644 (file)
index 0000000..1f15c69
--- /dev/null
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2005  - Garance Alistair Drosehn <gad@FreeBSD.org>.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation
+ * are those of the authors and should not be interpreted as representing
+ * official policies, either expressed or implied, of the FreeBSD Project.
+ *
+ * $FreeBSD$
+ */
+
+void            search_paths(char *path, char **argv);
+void            split_spaces(const char *str, int *origind, int *origc,
+                   char ***origv);
+
+extern int      env_verbosity;
index 0d5e133431e3c4dac1d04ec247d5d835bb08d80f..c6bb28fef429cfbd4a3b2f649aec44d088d94d23 100644 (file)
@@ -501,6 +501,8 @@ Like
 .Ic -name ,
 but the contents of the symbolic link are matched instead of the file
 name.
+Note that this only matches broken symbolic links
+if symbolic links are being followed.
 This is a GNU find extension.
 .It Ic -ls
 This primary always evaluates to true.
diff --git a/find/find.plist.part b/find/find.plist.part
new file mode 100644 (file)
index 0000000..0148f95
--- /dev/null
@@ -0,0 +1,30 @@
+       <dict>
+               <key>OpenSourceProject</key>
+               <string>find</string>
+               <key>OpenSourceVersion</key>
+               <string>2011-12-10</string>
+               <key>OpenSourceWebsiteURL</key>
+               <string>http://svnweb.freebsd.org/base/head/usr.bin/find/</string>
+               <key>OpenSourceSCM</key>
+               <string>svn co http://svn.freebsd.org/base/head/usr.bin/find/</string>
+               <key>OpenSourceImportDate</key>
+               <string>2012-01-06</string>
+               <key>OpenSourceModifications</key>
+               <array>
+                       <string>Add -xattr and -xattrname options.</string>
+                       <string>execplus conformance fixes.</string>
+                       <string>Man page fix (4772561).</string>
+                       <string>Adjust FTS usage due to API differences.</string>
+                       <string>Avoid searching unsearchable directories (3849245).</string>
+                       <string>Add missing call to fts_close (4608460).</string>
+                       <string>Conformance fixes related to F_EXACTTIME.</string>
+                       <string>Apple-specific implementation of -acl primary.</string>
+                       <string>Conformance fix for f_name (6591280).</string>
+                       <string>setmode conformance fix (3936046).</string>
+                       <string>Use a saner MAXLOGNAME definition.</string>
+                       <string>Workaround for lack of rpmatch function.</string>
+                       <string>FreeBSD revisions 260336, 260355.</string>
+               </array>
+               <key>OpenSourceLicense</key>
+               <string>bsd</string>
+       </dict>
index 4e3950dbbaf5647cd0814694d612dc01ddb9d7f5..a673a025f1691d2518503c67ebfab6efd6e42d3b 100644 (file)
@@ -1145,11 +1145,24 @@ f_name(PLAN *plan, FTSENT *entry)
 {
        char fn[PATH_MAX];
        const char *name;
+       ssize_t len;
 
        if (plan->flags & F_LINK) {
-               name = fn;
-               if (readlink(entry->fts_accpath, fn, sizeof(fn)) == -1)
+               /*
+                * The below test both avoids obviously useless readlink()
+                * calls and ensures that symlinks with existent target do
+                * not match if symlinks are being followed.
+                * Assumption: fts will stat all symlinks that are to be
+                * followed and will return the stat information.
+                */
+               if (entry->fts_info != FTS_NSOK && entry->fts_info != FTS_SL &&
+                   entry->fts_info != FTS_SLNONE)
                        return 0;
+               len = readlink(entry->fts_accpath, fn, sizeof(fn) - 1);
+               if (len == -1)
+                       return 0;
+               fn[len] = '\0';
+               name = fn;
        } else if (entry->fts_namelen == 0) {
                name = basename(entry->fts_path);
        } else
index 1e4e8343ab41b8086a8ff7fed91ec4bff04c65a7..131b1f480797c6ea4ac7a35e72ad660c6bc30a51 100644 (file)
@@ -30,7 +30,7 @@
 
 if [ "$(id -u)" = "0" ]; then
        rc=0
-       export FCODES=`mktemp -t updatedb`
+       export FCODES=`sudo -u nobody mktemp -t updatedb`
        chown nobody $FCODES
        tmpdb=`su -fm nobody -c "$0"` || rc=1
        if [ $rc = 0 ]; then
index e9822d34584729c33ea43cd49d1d04c878374da7..4067e3182f3c9900d6c6643f17073fa7ab80480f 100644 (file)
@@ -9,10 +9,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,7 +26,7 @@
 .\" 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.21 2006/09/29 15:20:46 ru Exp $
+.\" $FreeBSD$
 .\"
 .Dd December 30, 2005
 .Dt MKTEMP 1
@@ -77,6 +73,11 @@ will
 result in
 .Nm
 selecting 1 of 56800235584 (62 ** 6) possible file names.
+On case-insensitive file systems, the effective number of unique
+names is significantly less; given six
+.Ql X Ns s ,
+.Nm
+will instead select 1 of 2176782336 (36 ** 6) possible unique file names.
 .Pp
 If
 .Nm
@@ -103,6 +104,14 @@ Care should
 be taken to ensure that it is appropriate to use an environment variable
 potentially supplied by the user.
 .Pp
+If no arguments are passed or if only the
+.Fl d
+flag is passed
+.Nm
+behaves as if
+.Fl t Li tmp
+was supplied.
+.Pp
 Any number of temporary files may be created in a single invocation,
 including one based on the internal template resulting from the
 .Fl t
@@ -154,10 +163,7 @@ Use of this
 option is not encouraged.
 .El
 .Sh EXIT STATUS
-The
-.Nm
-utility
-exits 0 on success, and 1 if an error occurs.
+.Ex -std
 .Sh EXAMPLES
 The following
 .Xr sh 1
index 6040f1636058f75ce53e9a52a55e016c66186c43..11db17e4db7972275cd0be7cb5214e72300f24b3 100644 (file)
@@ -35,6 +35,9 @@
  */
 
 #include <err.h>
+#ifdef __APPLE__
+#include <limits.h>
+#endif
 #include <paths.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -43,7 +46,7 @@
 
 #ifndef lint
 static const char rcsid[] =
-       "$FreeBSD: src/usr.bin/mktemp/mktemp.c,v 1.5 2002/03/22 01:33:17 imp Exp $";
+       "$FreeBSD$";
 #endif /* not lint */
 
 static void usage(void);
@@ -56,6 +59,10 @@ main(int argc, char **argv)
        const char *prefix;
        char *name;
        int dflag, qflag, tflag, uflag;
+#ifdef __APPLE__
+       char tmpbuf[PATH_MAX];
+       size_t len;
+#endif
 
        ret = dflag = qflag = tflag = uflag = 0;
        prefix = "mktemp";
@@ -87,17 +94,36 @@ main(int argc, char **argv)
        argc -= optind;
        argv += optind;
 
+       if (!tflag && argc < 1) {
+               tflag = 1;
+               prefix = "tmp";
+       }
+
        if (tflag) {
+#ifdef __APPLE__
+               if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmpbuf, sizeof(tmpbuf)) > 0) {
+                       tmpdir = tmpbuf;
+               } else {
+                       tmpdir = getenv("TMPDIR");
+               }
+
+               if (tmpdir == NULL) {
+                       tmpdir = _PATH_TMP;
+               }
+
+               len = strlen(tmpdir);
+               if (len > 0 && tmpdir[len - 1] == '/') {
+                       asprintf(&name, "%s%s.XXXXXXXX", tmpdir, prefix);
+               } else {
+                       asprintf(&name, "%s/%s.XXXXXXXX", tmpdir, prefix);
+               }
+#else
                tmpdir = getenv("TMPDIR");
                if (tmpdir == NULL)
                        asprintf(&name, "%s%s.XXXXXXXX", _PATH_TMP, 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);
-               }
+               else
+                       asprintf(&name, "%s/%s.XXXXXXXX", tmpdir, prefix);
+#endif
                /* if this fails, the program is in big trouble already */
                if (name == NULL) {
                        if (qflag)
@@ -105,8 +131,6 @@ main(int argc, char **argv)
                        else
                                errx(1, "cannot generate template");
                }
-       } else if (argc < 1) {
-               usage();
        }
                
        /* generate all requested files */
@@ -148,7 +172,7 @@ main(int argc, char **argv)
 }
 
 static void
-usage()
+usage(void)
 {
        fprintf(stderr,
                "usage: mktemp [-d] [-q] [-t prefix] [-u] template ...\n");
diff --git a/mktemp/mktemp.plist.part b/mktemp/mktemp.plist.part
new file mode 100644 (file)
index 0000000..3c927c2
--- /dev/null
@@ -0,0 +1,20 @@
+       <dict>
+               <key>OpenSourceProject</key>
+               <string>mktemp</string>
+               <key>OpenSourceVersion</key>
+               <string>2012-11-18</string>
+               <key>OpenSourceWebsiteURL</key>
+               <string>http://svnweb.freebsd.org/base/head/usr.bin/mktemp/</string>
+               <key>OpenSourceSCM</key>
+               <string>svn co http://svn.freebsd.org/base/head/usr.bin/mktemp/</string>
+               <key>OpenSourceImportDate</key>
+               <string>2014-08-11</string>
+               <key>OpenSourceModifications</key>
+               <array>
+                       <string>Avoid double-slash in output. (5334050)</string>
+                       <string>Document case-insensitive file system behavior. (14280248)</string>
+                       <string>Prefer _CS_DARWIN_USER_TEMP_DIR over TMPDIR and _PATH_TMP. (14338140)</string>
+               </array>
+               <key>OpenSourceLicense</key>
+               <string>bsd</string>
+       </dict>
index ff5c55a4446be09174ab4fe201a5b0e62fd36143..2313c99be8e05a19cfec6f7b376854ca1e457ee3 100644 (file)
@@ -80,7 +80,7 @@ char* read_segment(const char* line, size_t len) {
 
        size_t size = len + escapes + 1;
 
-       char* segment = malloc(size);
+       char* segment = calloc(1, size);
        if (segment == NULL) return NULL;
        
        for (i = 0, j = 0; i < len; ++i, ++j) {
index ea3fb0f35f4705228b50a113e9f79a0d0f138500..44443755c87b014fabec6aa9baa6bc68ab2d8709 100644 (file)
@@ -1,7 +1,5 @@
-.\"    $NetBSD: printenv.1,v 1.5 1997/10/19 12:44:21 lukem Exp $
-.\"
 .\" Copyright (c) 1980, 1990, 1993
-.\"   The Regents of the University of California.  All rights reserved.
+.\"    The Regents of the University of California.  All rights reserved.
 .\"
 .\" This code is derived from software contributed to Berkeley by
 .\" the Institute of Electrical and Electronics Engineers, Inc.
 .\" 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.
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.\"    from: @(#)printenv.1    8.1 (Berkeley) 6/6/93
-.\"    $NetBSD: printenv.1,v 1.5 1997/10/19 12:44:21 lukem Exp $
+.\"    @(#)printenv.1  8.1 (Berkeley) 6/6/93
+.\" $FreeBSD$
 .\"
-.Dd June 6, 1993
+.Dd May 12, 2003
 .Dt PRINTENV 1
 .Os
 .Sh NAME
 .Nm
 .Op Ar name
 .Sh DESCRIPTION
+The
 .Nm
-prints out the names and values of the variables in the environment,
-with one name/value pair per line.  If
+utility prints out the names and values of the variables in the environment,
+with one name/value pair per line.
+If
 .Ar name
 is specified, only
 its value is printed.
 .Pp
-If a
-.Ar name
-is specified and it is not defined in the environment,
+Some shells may provide a builtin
 .Nm
-returns exit status 1, else it returns status 0.
+command which is similar or identical to this utility.
+Consult the
+.Xr builtin 1
+manual page.
+.Sh EXIT STATUS
+.Ex -std
 .Sh SEE ALSO
 .Xr csh 1 ,
+.Xr env 1 ,
 .Xr sh 1 ,
 .Xr environ 7
+.Sh STANDARDS
+The
+.Nm
+utility is provided for compatibility with earlier
+.Bx
+and
+.Fx
+releases and is not specified by any standards.
+The functionality of
+.Nm
+can be duplicated with the
+.Xr echo 1
+and
+.Xr env 1
+utilities.
 .Sh HISTORY
 The
 .Nm
index be8b50bd3642311afffec5dc8f021c436f53221b..315833e85a75d136aa3c23a64e7433d1f29c8332 100644 (file)
@@ -1,8 +1,6 @@
-/*     $NetBSD: printenv.c,v 1.6 1997/10/19 12:44:26 lukem Exp $       */
-
-/*
+/*-
  * Copyright (c) 1987, 1993
- *    Regents of the University of California.  All rights reserved.
+ *     The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * 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>
 #ifndef lint
-__COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
-      The Regents of the University of California.  All rights reserved.\n");
+static const char copyright[] =
+"@(#) Copyright (c) 1987, 1993\n\
+       The Regents of the University of California.  All rights reserved.\n";
 #endif /* not lint */
 
+#if 0
 #ifndef lint
-/*static char sccsid[] = "from: @(#)printenv.c 8.2 (Berkeley) 5/4/95";*/
-__RCSID("$NetBSD: printenv.c,v 1.6 1997/10/19 12:44:26 lukem Exp $");
+static char sccsid[] = "@(#)printenv.c 8.2 (Berkeley) 5/4/95";
 #endif /* not lint */
+#endif
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
 
@@ -51,8 +49,8 @@ __RCSID("$NetBSD: printenv.c,v 1.6 1997/10/19 12:44:26 lukem Exp $");
 #include <string.h>
 #include <unistd.h>
 
-int    main __P((int, char **));
-void   usage __P((void));
+void   usage(void);
+extern char **environ;
 
 /*
  * printenv
@@ -61,11 +59,8 @@ void usage __P((void));
  * February, 1979
  */
 int
-main(argc, argv)
-       int argc;
-       char *argv[];
+main(int argc, char *argv[])
 {
-       extern char **environ;
        char *cp, **ep;
        size_t len;
        int ch;
@@ -97,7 +92,7 @@ main(argc, argv)
 }
 
 void
-usage()
+usage(void)
 {
        (void)fprintf(stderr, "usage: printenv [name]\n");
        exit(1);
index 8c0dae925069490114c79e45074b2f6c20ff52f3..ad12c53338cb3b4080cd0725e96e9d00745cef47 100644 (file)
@@ -9,10 +9,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 +26,9 @@
 .\" SUCH DAMAGE.
 .\"
 .\"    @(#)script.1    8.1 (Berkeley) 6/6/93
-.\" $FreeBSD: src/usr.bin/script/script.1,v 1.21 2004/07/03 00:24:43 ru Exp $
+.\" $FreeBSD$
 .\"
-.Dd January 22, 2004
+.Dd December 4, 2013
 .Dt SCRIPT 1
 .Os
 .Sh NAME
@@ -40,7 +36,8 @@
 .Nd make typescript of terminal session
 .Sh SYNOPSIS
 .Nm
-.Op Fl akq
+.Op Fl adkpqr
+.Op Fl F Ar pipe
 .Op Fl t Ar time
 .Op Ar file Op Ar command ...
 .Sh DESCRIPTION
@@ -76,16 +73,40 @@ Append the output to
 or
 .Pa typescript ,
 retaining the prior contents.
+.It Fl d
+When playing back a session with the
+.Fl p
+flag, do not sleep between records when playing back a timestamped session.
+.It Fl F Ar pipe
+Immediately flush output after each write.
+This will allow a user to create a named pipe using
+.Xr mkfifo 1
+and another user may watch the live session using a utility like
+.Xr cat 1 .
+.\".It Fl f
+.\"Create
+.\".Ar file.filemon
+.\"or
+.\".Pa typescript.filemon
+.\"using
+.\".Xr filemon 4 .
 .It Fl k
-Log keys sent to program as well as output.
+Log keys sent to the program as well as output.
+.It Fl p
+Play back a session recorded with the
+.Fl r
+flag in real time.
 .It Fl q
-Run in quiet mode, omit the start and stop status messages.
+Run in quiet mode, omit the start, stop and command status messages.
+.It Fl r
+Record a session with input, output, and timestamping.
 .It Fl t Ar time
-Specify time interval between flushing script output file.
+Specify the interval at which the script output file will be flushed
+to disk, in seconds.
 A value of 0
 causes
 .Nm
-to flush for every character I/O event.
+to flush after every character I/O event.
 The default interval is
 30 seconds.
 .El
@@ -114,9 +135,22 @@ The
 utility works best with commands that do not manipulate the screen.
 The results are meant to emulate a hardcopy terminal, not an addressable one.
 .Sh ENVIRONMENT
-The following environment variable is utilized by
+The following environment variables are utilized by
 .Nm :
 .Bl -tag -width SHELL
+.It Ev SCRIPT
+The
+.Ev SCRIPT
+environment variable is added to the sub-shell.
+If
+.Ev SCRIPT
+already existed in the users environment,
+its value is overwritten within the sub-shell.
+The value of
+.Ev SCRIPT
+is the name of the
+.Ar typescript
+file.
 .It Ev SHELL
 If the variable
 .Ev SHELL
@@ -127,18 +161,31 @@ If
 .Ev SHELL
 is not set, the Bourne shell
 is assumed.
-(Most shells set this variable automatically).
+.Pq Most shells set this variable automatically .
 .El
 .Sh SEE ALSO
 .Xr csh 1
-(for the
-.Em history
-mechanism).
+.\".Xr filemon 4
+.\".Po
+.\"for the
+.\".Em history
+.\"mechanism
+.\".Pc .
 .Sh HISTORY
 The
 .Nm
 command appeared in
 .Bx 3.0 .
+.Pp
+The
+.Fl d ,
+.Fl p
+and
+.Fl r
+options first appeared in
+.Nx 2.0
+and were ported to
+.Fx 9.2 .
 .Sh BUGS
 The
 .Nm
@@ -156,4 +203,15 @@ mode, echo cancelling is far from ideal.
 The slave terminal mode is checked
 for ECHO mode to check when to avoid manual echo logging.
 This does not
-work when in a raw mode where the program being run is doing manual echo.
+work when the terminal is in a raw mode where
+the program being run is doing manual echo.
+.Pp
+If
+.Nm
+reads zero bytes from the terminal, it switches to a mode when it
+only attempts to read
+once a second until there is data to read.
+This prevents
+.Nm
+from spinning on zero-byte reads, but might cause a 1-second delay in
+processing of user input.
index 32d80f3d98fd2b5cca23be593d0ac4f76302b8b0..90e895ef0129f311c1f95a66dc8e071a9dbbe003 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ * Copyright (c) 2010, 2012  David E. O'Brien
  * Copyright (c) 1980, 1992, 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.
  * SUCH DAMAGE.
  */
 
-#include <sys/cdefs.h>
-
-__FBSDID("$FreeBSD: src/usr.bin/script/script.c,v 1.24 2004/02/15 17:30:13 cperciva Exp $");
-
+#include <sys/param.h>
+__FBSDID("$FreeBSD$");
 #ifndef lint
 static const char copyright[] =
 "@(#) Copyright (c) 1980, 1992, 1993\n\
        The Regents of the University of California.  All rights reserved.\n";
 #endif
-
 #ifndef lint
 static const char sccsid[] = "@(#)script.c     8.1 (Berkeley) 6/6/93";
 #endif
 
-#include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <sys/time.h>
+#include <sys/uio.h>
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+#else
+#include <sys/endian.h>
+#endif
+#ifdef ENABLE_FILEMON
+#include <dev/filemon/filemon.h>
+#endif /* ENABLE_FILEMON */
 
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
-#ifndef __APPLE__
+#ifdef __APPLE__
+#include <util.h>
+#else
 #include <libutil.h>
-#endif /* !__APPLE__ */
+#endif
 #include <paths.h>
 #include <signal.h>
 #include <stdio.h>
@@ -64,23 +68,37 @@ static const char sccsid[] = "@(#)script.c  8.1 (Berkeley) 6/6/93";
 #include <string.h>
 #include <termios.h>
 #include <unistd.h>
-#ifdef __APPLE__
-#include <util.h>
-#endif /* __APPLE__ */
 
-FILE   *fscript;
-int    master, slave;
-int    child;
-const char *fname;
-int    qflg, ttyflg;
+#define DEF_BUF 65536
 
-struct termios tt;
+struct stamp {
+       uint64_t scr_len;       /* amount of data */
+       uint64_t scr_sec;       /* time it arrived in seconds... */
+       uint32_t scr_usec;      /* ...and microseconds */
+       uint32_t scr_direction; /* 'i', 'o', etc (also indicates endianness) */
+};
 
-void   done(int) __dead2;
-void   dooutput(void);
-void   doshell(char **);
-void   fail(void);
-void   finish(void);
+static FILE *fscript;
+static int master, slave;
+static int child;
+static const char *fname;
+static char *fmfname;
+#ifdef ENABLE_FILEMON
+static int fflg, qflg, ttyflg;
+#else /* !ENABLE_FILEMON */
+static int qflg, ttyflg;
+#endif /* ENABLE_FILEMON */
+static int usesleep, rawout;
+
+static struct termios tt;
+
+static void done(int) __dead2;
+static void doshell(char **);
+static void fail(void);
+static void finish(void);
+static void record(FILE *, char *, size_t, int);
+static void consume(FILE *, off_t, char *, int);
+static void playback(FILE *) __dead2;
 static void usage(void);
 
 int
@@ -89,26 +107,58 @@ main(int argc, char *argv[])
        int cc;
        struct termios rtt, stt;
        struct winsize win;
-       int aflg, kflg, ch, n;
        struct timeval tv, *tvp;
        time_t tvec, start;
        char obuf[BUFSIZ];
        char ibuf[BUFSIZ];
        fd_set rfd;
-       int flushtime = 30;
+       int aflg, Fflg, kflg, pflg, ch, k, n;
+       int flushtime, readstdin;
+#ifdef ENABLE_FILEMON
+       int fm_fd, fm_log;
+#endif /* ENABLE_FILEMON */
+
+       aflg = Fflg = kflg = pflg = 0;
+       usesleep = 1;
+       rawout = 0;
+       flushtime = 30;
+#ifdef ENABLE_FILEMON
+       fm_fd = -1;     /* Shut up stupid "may be used uninitialized" GCC
+                          warning. (not needed w/clang) */
+#endif /* ENABLE_FILEMON */
 
-       aflg = kflg = 0;
-       while ((ch = getopt(argc, argv, "aqkt:")) != -1)
+#ifdef ENABLE_FILEMON
+       while ((ch = getopt(argc, argv, "adFfkpqrt:")) != -1)
+#else /* !ENABLE_FILEMON */
+       while ((ch = getopt(argc, argv, "adFkpqrt:")) != -1)
+#endif /* ENABLE_FILEMON */
                switch(ch) {
                case 'a':
                        aflg = 1;
                        break;
-               case 'q':
-                       qflg = 1;
+               case 'd':
+                       usesleep = 0;
                        break;
+               case 'F':
+                       Fflg = 1;
+                       break;
+#ifdef ENABLE_FILEMON
+               case 'f':
+                       fflg = 1;
+                       break;
+#endif /* ENABLE_FILEMON */
                case 'k':
                        kflg = 1;
                        break;
+               case 'p':
+                       pflg = 1;
+                       break;
+               case 'q':
+                       qflg = 1;
+                       break;
+               case 'r':
+                       rawout = 1;
+                       break;
                case 't':
                        flushtime = atoi(optarg);
                        if (flushtime < 0)
@@ -128,10 +178,32 @@ main(int argc, char *argv[])
        } else
                fname = "typescript";
 
-       if ((fscript = fopen(fname, aflg ? "a" : "w")) == NULL)
+       if ((fscript = fopen(fname, pflg ? "r" : aflg ? "a" : "w")) == NULL)
                err(1, "%s", fname);
 
-       if (ttyflg = isatty(STDIN_FILENO)) {
+#ifdef ENABLE_FILEMON
+       if (fflg) {
+               asprintf(&fmfname, "%s.filemon", fname);
+               if (!fmfname)
+                       err(1, "%s.filemon", fname);
+               if ((fm_fd = open("/dev/filemon", O_RDWR)) == -1)
+                       err(1, "open(\"/dev/filemon\", O_RDWR)");
+               if ((fm_log = open(fmfname, O_WRONLY | O_CREAT | O_TRUNC,
+                   S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1)
+                       err(1, "open(%s)", fmfname);
+               if (ioctl(fm_fd, FILEMON_SET_FD, &fm_log) < 0)
+                       err(1, "Cannot set filemon log file descriptor");
+
+               /* Set up these two fd's to close on exec. */
+               (void)fcntl(fm_fd, F_SETFD, FD_CLOEXEC);
+               (void)fcntl(fm_log, F_SETFD, FD_CLOEXEC);
+       }
+#endif /* ENABLE_FILEMON */
+
+       if (pflg)
+               playback(fscript);
+
+       if ((ttyflg = isatty(STDIN_FILENO)) != 0) {
                if (tcgetattr(STDIN_FILENO, &tt) == -1)
                        err(1, "tcgetattr");
                if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win) == -1)
@@ -143,11 +215,30 @@ main(int argc, char *argv[])
                        err(1, "openpty");
        }
 
+       if (rawout)
+               record(fscript, NULL, 0, 's');
+
        if (!qflg) {
                tvec = time(NULL);
                (void)printf("Script started, output file is %s\n", fname);
-               (void)fprintf(fscript, "Script started on %s", ctime(&tvec));
+               if (!rawout) {
+                       (void)fprintf(fscript, "Script started on %s",
+                           ctime(&tvec));
+                       if (argv[0]) {
+                               fprintf(fscript, "command: ");
+                               for (k = 0 ; argv[k] ; ++k)
+                                       fprintf(fscript, "%s%s", k ? " " : "",
+                                               argv[k]);
+                               fprintf(fscript, "\n");
+                       }
+               }
                fflush(fscript);
+#ifdef ENABLE_FILEMON
+               if (fflg) {
+                       (void)printf("Filemon started, output file is %s\n",
+                           fmfname);
+               }
+#endif /* ENABLE_FILEMON */
        }
        if (ttyflg) {
                rtt = tt;
@@ -163,23 +254,31 @@ main(int argc, char *argv[])
        }
        if (child == 0)
                doshell(argv);
-#ifdef __APPLE__
-       (void)close(slave);
-#endif /* __APPLE__ */
+       close(slave);
 
-       if (flushtime > 0)
-               tvp = &tv;
-       else
-               tvp = NULL;
+#ifdef ENABLE_FILEMON
+       if (fflg && ioctl(fm_fd, FILEMON_SET_PID, &child) < 0)
+               err(1, "Cannot set filemon PID");
+#endif /* ENABLE_FILEMON */
 
-       start = time(0);
-       FD_ZERO(&rfd);
+       start = tvec = time(0);
+       readstdin = 1;
        for (;;) {
+               FD_ZERO(&rfd);
                FD_SET(master, &rfd);
-               FD_SET(STDIN_FILENO, &rfd);
-               if (flushtime > 0) {
-                       tv.tv_sec = flushtime;
+               if (readstdin)
+                       FD_SET(STDIN_FILENO, &rfd);
+               if (!readstdin && ttyflg) {
+                       tv.tv_sec = 1;
+                       tv.tv_usec = 0;
+                       tvp = &tv;
+                       readstdin = 1;
+               } else if (flushtime > 0) {
+                       tv.tv_sec = flushtime - (tvec - start);
                        tv.tv_usec = 0;
+                       tvp = &tv;
+               } else {
+                       tvp = NULL;
                }
                n = select(master + 1, &rfd, 0, 0, tvp);
                if (n < 0 && errno != EINTR)
@@ -188,9 +287,16 @@ main(int argc, char *argv[])
                        cc = read(STDIN_FILENO, ibuf, BUFSIZ);
                        if (cc < 0)
                                break;
-                       if (cc == 0)
-                               (void)write(master, ibuf, 0);
+                       if (cc == 0) {
+                               if (tcgetattr(master, &stt) == 0 &&
+                                   (stt.c_lflag & ICANON) != 0) {
+                                       (void)write(master, &stt.c_cc[VEOF], 1);
+                               }
+                               readstdin = 0;
+                       }
                        if (cc > 0) {
+                               if (rawout)
+                                       record(fscript, ibuf, cc, 'i');
                                (void)write(master, ibuf, cc);
                                if (kflg && tcgetattr(master, &stt) >= 0 &&
                                    ((stt.c_lflag & ECHO) == 0)) {
@@ -203,13 +309,18 @@ main(int argc, char *argv[])
                        if (cc <= 0)
                                break;
                        (void)write(STDOUT_FILENO, obuf, cc);
-                       (void)fwrite(obuf, 1, cc, fscript);
+                       if (rawout)
+                               record(fscript, obuf, cc, 'o');
+                       else
+                               (void)fwrite(obuf, 1, cc, fscript);
                }
                tvec = time(0);
                if (tvec - start >= flushtime) {
                        fflush(fscript);
                        start = tvec;
                }
+               if (Fflg)
+                       fflush(fscript);
        }
        finish();
        done(0);
@@ -219,33 +330,31 @@ static void
 usage(void)
 {
        (void)fprintf(stderr,
-           "usage: script [-akq] [-t time] [file [command ...]]\n");
+#ifdef ENABLE_FILEMON
+           "usage: script [-adfkpqr] [-t time] [file [command ...]]\n");
+#else /* !ENABLE_FILEMON */
+           "usage: script [-adkpqr] [-t time] [file [command ...]]\n");
+#endif /* ENABLE_FILEMON */
        exit(1);
 }
 
-void
+static void
 finish(void)
 {
-       pid_t pid;
-       int die, e, status;
-
-       die = e = 0;
-       while ((pid = wait3(&status, WNOHANG, 0)) > 0)
-               if (pid == child) {
-                       die = 1;
-                       if (WIFEXITED(status))
-                               e = WEXITSTATUS(status);
-                       else if (WIFSIGNALED(status))
-                               e = WTERMSIG(status);
-                       else /* can't happen */
-                               e = 1;
-               }
+       int e, status;
 
-       if (die)
+       if (waitpid(child, &status, 0) == child) {
+               if (WIFEXITED(status))
+                       e = WEXITSTATUS(status);
+               else if (WIFSIGNALED(status))
+                       e = WTERMSIG(status);
+               else /* can't happen */
+                       e = 1;
                done(e);
+       }
 }
 
-void
+static void
 doshell(char **av)
 {
        const char *shell;
@@ -256,7 +365,9 @@ doshell(char **av)
 
        (void)close(master);
        (void)fclose(fscript);
+       free(fmfname);
        login_tty(slave);
+       setenv("SCRIPT", fname, 1);
        if (av[0]) {
                execvp(av[0], av);
                warn("%s", av[0]);
@@ -267,14 +378,14 @@ doshell(char **av)
        fail();
 }
 
-void
+static void
 fail(void)
 {
        (void)kill(0, SIGTERM);
        done(1);
 }
 
-void
+static void
 done(int eno)
 {
        time_t tvec;
@@ -282,11 +393,154 @@ done(int eno)
        if (ttyflg)
                (void)tcsetattr(STDIN_FILENO, TCSAFLUSH, &tt);
        tvec = time(NULL);
+       if (rawout)
+               record(fscript, NULL, 0, 'e');
        if (!qflg) {
-               (void)fprintf(fscript,"\nScript done on %s", ctime(&tvec));
+               if (!rawout)
+                       (void)fprintf(fscript,"\nScript done on %s",
+                           ctime(&tvec));
                (void)printf("\nScript done, output file is %s\n", fname);
+#ifdef ENABLE_FILEMON
+               if (fflg) {
+                       (void)printf("Filemon done, output file is %s\n",
+                           fmfname);
+               }
+#endif /* ENABLE_FILEMON */
        }
        (void)fclose(fscript);
        (void)close(master);
        exit(eno);
 }
+
+static void
+record(FILE *fp, char *buf, size_t cc, int direction)
+{
+       struct iovec iov[2];
+       struct stamp stamp;
+       struct timeval tv;
+
+       (void)gettimeofday(&tv, NULL);
+       stamp.scr_len = cc;
+       stamp.scr_sec = tv.tv_sec;
+       stamp.scr_usec = tv.tv_usec;
+       stamp.scr_direction = direction;
+       iov[0].iov_len = sizeof(stamp);
+       iov[0].iov_base = &stamp;
+       iov[1].iov_len = cc;
+       iov[1].iov_base = buf;
+       if (writev(fileno(fp), &iov[0], 2) == -1)
+               err(1, "writev");
+}
+
+static void
+consume(FILE *fp, off_t len, char *buf, int reg)
+{
+       size_t l;
+
+       if (reg) {
+               if (fseeko(fp, len, SEEK_CUR) == -1)
+                       err(1, NULL);
+       }
+       else {
+               while (len > 0) {
+                       l = MIN(DEF_BUF, len);
+                       if (fread(buf, sizeof(char), l, fp) != l)
+                               err(1, "cannot read buffer");
+                       len -= l;
+               }
+       }
+}
+
+#ifdef __APPLE__
+#define bswap32 OSSwapInt32
+#define bswap64 OSSwapInt64
+#endif /* __APPLE__ */
+#define swapstamp(stamp) do { \
+       if (stamp.scr_direction > 0xff) { \
+               stamp.scr_len = bswap64(stamp.scr_len); \
+               stamp.scr_sec = bswap64(stamp.scr_sec); \
+               stamp.scr_usec = bswap32(stamp.scr_usec); \
+               stamp.scr_direction = bswap32(stamp.scr_direction); \
+       } \
+} while (0/*CONSTCOND*/)
+
+static void
+playback(FILE *fp)
+{
+       struct timespec tsi, tso;
+       struct stamp stamp;
+       struct stat pst;
+       char buf[DEF_BUF];
+       off_t nread, save_len;
+       size_t l;
+       time_t tclock;
+       int reg;
+
+       if (fstat(fileno(fp), &pst) == -1)
+               err(1, "fstat failed");
+
+       reg = S_ISREG(pst.st_mode);
+
+       for (nread = 0; !reg || nread < pst.st_size; nread += save_len) {
+               if (fread(&stamp, sizeof(stamp), 1, fp) != 1) {
+                       if (reg)
+                               err(1, "reading playback header");
+                       else
+                               break;
+               }
+               swapstamp(stamp);
+               save_len = sizeof(stamp);
+
+               if (reg && stamp.scr_len >
+                   (uint64_t)(pst.st_size - save_len) - nread)
+                       errx(1, "invalid stamp");
+
+               save_len += stamp.scr_len;
+               tclock = stamp.scr_sec;
+               tso.tv_sec = stamp.scr_sec;
+               tso.tv_nsec = stamp.scr_usec * 1000;
+
+               switch (stamp.scr_direction) {
+               case 's':
+                       if (!qflg)
+                           (void)printf("Script started on %s",
+                               ctime(&tclock));
+                       tsi = tso;
+                       (void)consume(fp, stamp.scr_len, buf, reg);
+                       break;
+               case 'e':
+                       if (!qflg)
+                               (void)printf("\nScript done on %s",
+                                   ctime(&tclock));
+                       (void)consume(fp, stamp.scr_len, buf, reg);
+                       break;
+               case 'i':
+                       /* throw input away */
+                       (void)consume(fp, stamp.scr_len, buf, reg);
+                       break;
+               case 'o':
+                       tsi.tv_sec = tso.tv_sec - tsi.tv_sec;
+                       tsi.tv_nsec = tso.tv_nsec - tsi.tv_nsec;
+                       if (tsi.tv_nsec < 0) {
+                               tsi.tv_sec -= 1;
+                               tsi.tv_nsec += 1000000000;
+                       }
+                       if (usesleep)
+                               (void)nanosleep(&tsi, NULL);
+                       tsi = tso;
+                       while (stamp.scr_len > 0) {
+                               l = MIN(DEF_BUF, stamp.scr_len);
+                               if (fread(buf, sizeof(char), l, fp) != l)
+                                       err(1, "cannot read buffer");
+
+                               (void)write(STDOUT_FILENO, buf, l);
+                               stamp.scr_len -= l;
+                       }
+                       break;
+               default:
+                       errx(1, "invalid direction");
+               }
+       }
+       (void)fclose(fp);
+       exit(0);
+}
diff --git a/script/script.plist.part b/script/script.plist.part
new file mode 100644 (file)
index 0000000..b112d31
--- /dev/null
@@ -0,0 +1,20 @@
+       <dict>
+               <key>OpenSourceProject</key>
+               <string>script</string>
+               <key>OpenSourceVersion</key>
+               <string>2014-01-17</string>
+               <key>OpenSourceWebsiteURL</key>
+               <string>http://svnweb.freebsd.org/base/head/usr.bin/script/</string>
+               <key>OpenSourceSCM</key>
+               <string>svn co http://svn.freebsd.org/base/head/usr.bin/script/</string>
+               <key>OpenSourceImportDate</key>
+               <string>2014-09-22</string>
+               <key>OpenSourceModifications</key>
+               <array>
+                       <string>Use OSByteOrder swap functions.</string>
+                       <string>Include util.h instead of libutil.h.</string>
+                       <string>Disable -f (filemon) feature, guarded with ENABLE_FILEMON.</string>
+               </array>
+               <key>OpenSourceLicense</key>
+               <string>bsd</string>
+       </dict>
index ced8bc15db7e8d1842a961b2f1fa0ccb951e000c..58fea8597683cef7a518a7aa9a02eca4b6e10c3e 100644 (file)
                FCE30EE014B536F200CC0294 /* locate.code.c in Sources */ = {isa = PBXBuildFile; fileRef = FCBA13A114A141A300AA698B /* locate.code.c */; };
                FCE30EE114B536F800CC0294 /* locate.code.8 in CopyFiles */ = {isa = PBXBuildFile; fileRef = FCBA13B114A141A300AA698B /* locate.code.8 */; };
                FCED3AF614B4FC1800C313C3 /* libpam.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FCED3AF514B4FC1800C313C3 /* libpam.dylib */; };
+               FD88EB03198C5257006B7EFD /* envopts.c in Sources */ = {isa = PBXBuildFile; fileRef = FD88EB01198C5257006B7EFD /* envopts.c */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
                FCE30ED214B5368A00CC0294 /* locate.bigram */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locate.bigram; sourceTree = BUILT_PRODUCTS_DIR; };
                FCE30EDE14B536C900CC0294 /* locate.code */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = locate.code; sourceTree = BUILT_PRODUCTS_DIR; };
                FCED3AF514B4FC1800C313C3 /* libpam.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libpam.dylib; path = /usr/lib/libpam.dylib; sourceTree = "<absolute>"; };
+               FD88EB01198C5257006B7EFD /* envopts.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = envopts.c; sourceTree = "<group>"; };
+               FD88EB02198C5257006B7EFD /* envopts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = envopts.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
                        children = (
                                FCBA136214A141A300AA698B /* env.1 */,
                                FCBA136314A141A300AA698B /* env.c */,
+                               FD88EB01198C5257006B7EFD /* envopts.c */,
+                               FD88EB02198C5257006B7EFD /* envopts.h */,
                        );
                        path = env;
                        sourceTree = "<group>";
                        buildActionMask = 2147483647;
                        files = (
                                FCBA14FC14A144E500AA698B /* env.c in Sources */,
+                               FD88EB03198C5257006B7EFD /* envopts.c in Sources */,
                        );
                        runOnlyForDeploymentPostprocessing = 0;
                };
index 43fb81f2515feab9ca2b9757f1d3c522697bcbeb..ce296b6d3177b03e34d09f545be770e55dddbe4c 100644 (file)
@@ -7,14 +7,23 @@
 .Sh SYNOPSIS\r
 .Nm\r
 .Op Fl P\r
+.Op Fl r\r
+.Op Fl t Ar sleep_time\r
 .Ar utility Op Ar argument ...\r
 .Nm\r
 .Fl p\r
+.Op Fl r\r
+.Op Fl t Ar sleep_time\r
 .Nm\r
 .Op Fl P\r
 .Fl u Ar user\r
 .Fl s Ar sys\r
 .Fl i Ar idle\r
+.Nm\r
+.Op Fl P\r
+.Op Fl r\r
+.Op Fl t Ar sleep_time\r
+.Fl T Ar target_pid\r
 .Sh DESCRIPTION\r
 .Nm\r
 is similar to\r
@@ -45,9 +54,23 @@ $ systime -u $systime_user -s $systime_sys -i $systime_idle
 18.79 real 2.03 user 1.04 sys\r
 .Ed\r
 .Pp\r
+The\r
+.Nm\r
+program can also be used to print the usage of a process with\r
+.Fl T Ar target_pid\r
+, also printing the system wide usage\r
+.Pp\r
 .Fl P\r
 can be used to print time spent as a percentage of overall CPU capacity\r
 of the system (capped at 100%)\r
+.Pp\r
+.Fl r\r
+can be used to print the usage iteratively with\r
+.Ar sleep_time\r
+seconds sleep between iterations\r
+.Pp\r
+.Fl t Ar sleep_time\r
+can be used to specify sleep_time between iterations, defaults to 1 second if not specified.\r
 .Sh SEE ALSO\r
 .Xr time 1 ,\r
 .Xr top 1\r
index 746a8bd79be9dbf1c071e8c69e292d08f71fcc53..37cee8be8ccd944d17c26b8277a874496ca82e08 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <unistd.h>
+#include <libproc.h>
+#include <mach/mach_time.h>
 
 static void usage(void);
 static void do_print(void);
-static void do_difftime(bool usepercent, uint64_t olduser, uint64_t oldsystem, uint64_t oldidle);
+static void do_difftime(bool usepercent, uint64_t *olduser, uint64_t *oldsystem, uint64_t *oldidle);
+static void do_piddifftime(bool userpercent, int pid, uint64_t *old_pid_user, uint64_t *old_pid_system, uint64_t *old_pid_time);
 static kern_return_t get_processor_time(uint64_t *user, uint64_t *sys, uint64_t *idle);
 static kern_return_t get_processor_count(int *ncpu);
+static mach_timebase_info_data_t timebase_info;
 
 int
 main(int argc, char *argv[])
@@ -43,20 +47,36 @@ main(int argc, char *argv[])
        const char *optu = NULL;
        const char *opts = NULL;
        const char *opti = NULL;
+       const char *tpid = NULL;
+       const char *opt_sleep_time = NULL;
+       int sleep_time = 1;
+       int target_pid;
+       bool systemwide_time = false;
        int pid;
        int status;
        uint64_t olduser, oldsystem, oldidle;
+       uint64_t old_pid_time;
+       uint64_t old_pid_user, old_pid_system;
        kern_return_t kret;
        bool usepercent = false;
+       bool recurring = false;
 
-       while ((ch = getopt(argc, argv, "Ppu:s:i:")) != -1) {
+       while ((ch = getopt(argc, argv, "PrT:t:pu:s:i:")) != -1) {
                switch (ch) {
                case 'P':
                        usepercent = true;
                        break;
+               case 'r':
+                       recurring = true;
+                       break;
+               case 't':
+                       opt_sleep_time = optarg;
+                       break;
+               case 'T':
+                       tpid = optarg;
+                       break;
                case 'p':
-                       do_print();
-                       exit(0);
+                       systemwide_time = true;
                        break;
                case 'u':
                        optu = optarg;
@@ -73,6 +93,63 @@ main(int argc, char *argv[])
                }
        }
 
+       mach_timebase_info(&timebase_info);
+
+       if (opt_sleep_time) {
+               char *endstr;
+               sleep_time = (int)strtoul(opt_sleep_time, &endstr, 0);
+               if (opt_sleep_time[0] == '\0' || endstr[0] != '\0')
+                       usage();
+       }
+       
+       if (systemwide_time) {
+               bool first_pass = true;
+               olduser = oldsystem = oldidle = 0;
+
+               if (recurring != true) {
+                       do_print();
+                       exit(0);
+               }
+               do {
+                       if (first_pass) {
+                               do_difftime(false, &olduser, &oldsystem, &oldidle);
+                               first_pass = false;
+                       } else {
+                               do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+                       }
+                       sleep(sleep_time);
+               } while (recurring);
+
+               exit(0);
+       }
+
+
+       if (tpid) {
+               char *endstr;
+               bool first_pass = true;
+
+               target_pid = (int)strtoul(tpid, &endstr, 0);
+               if (tpid[0] == '\0' || endstr[0] != '\0')
+                       usage();
+
+               olduser = oldsystem = oldidle = 0;
+               old_pid_user = old_pid_system = old_pid_time = 0;
+               
+               do {    
+                       if (first_pass) {
+                               do_difftime(false, &olduser, &oldsystem, &oldidle);
+                               do_piddifftime(false, target_pid, &old_pid_user, &old_pid_system, &old_pid_time);
+                               first_pass = false;
+                       } else {
+                               do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
+                               do_piddifftime(usepercent, target_pid, &old_pid_user, &old_pid_system, &old_pid_time);
+                       }
+
+                       sleep(sleep_time);
+               } while (recurring);
+               exit(0);
+       }
+
        if (optu || opts || opti) {
                char *endstr;
 
@@ -94,7 +171,7 @@ main(int argc, char *argv[])
                if (opti[0] == '\0' || endstr[0] != '\0')
                        usage();
 
-               do_difftime(usepercent, olduser, oldsystem, oldidle);
+               do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
                exit(0);
        }
 
@@ -104,28 +181,34 @@ main(int argc, char *argv[])
        if (argc == 0)
                usage();
 
-       kret = get_processor_time(&olduser, &oldsystem, &oldidle);
-       if (kret)
-               errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
+       do {
+               kret = get_processor_time(&olduser, &oldsystem, &oldidle);
+               if (kret)
+                       errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
+
+               switch(pid = vfork()) {
+                       case -1:                        /* error */
+                               perror("time");
+                               exit(1);
+                               /* NOTREACHED */
+                       case 0:                         /* child */
+                               execvp(*argv, argv);
+                               perror(*argv);
+                               _exit((errno == ENOENT) ? 127 : 126);
+                               /* NOTREACHED */
+               }
 
-       switch(pid = vfork()) {
-               case -1:                        /* error */
-                       perror("time");
-                       exit(1);
-                       /* NOTREACHED */
-               case 0:                         /* child */
-                       execvp(*argv, argv);
-                       perror(*argv);
-                       _exit((errno == ENOENT) ? 127 : 126);
-                       /* NOTREACHED */
-       }
+               /* parent */
+               (void)signal(SIGINT, SIG_IGN);
+               (void)signal(SIGQUIT, SIG_IGN);
+               while (wait(&status) != pid);
+               (void)signal(SIGINT, SIG_DFL);
+               (void)signal(SIGQUIT, SIG_DFL);
 
-       /* parent */
-       (void)signal(SIGINT, SIG_IGN);
-       (void)signal(SIGQUIT, SIG_IGN);
-       while (wait(&status) != pid);
+               do_difftime(usepercent, &olduser, &oldsystem, &oldidle);
 
-       do_difftime(usepercent, olduser, oldsystem, oldidle);
+               sleep(sleep_time);
+       } while (recurring);
 
        exit (WIFEXITED(status) ? WEXITSTATUS(status) : EXIT_FAILURE);
 
@@ -135,9 +218,10 @@ main(int argc, char *argv[])
 static void
 usage(void)
 {
-       fprintf(stderr, "usage: systime [-P] utility [argument ...]\n"
-                       "       systime -p\n"
-                       "       systime [-P] -u user -s sys -i idle\n");
+       fprintf(stderr, "usage: systime [-P] [-r] [-t sleep_time] utility [argument ...]\n"
+                       "       systime -p [-r] [-t sleep_time]\n"
+                       "       systime [-P] -u user -s sys -i idle\n"
+                       "       systime [-P] [-r] [-t sleep_time] -T target_pid\n");
        exit(1);
 }
 
@@ -157,7 +241,7 @@ do_print(void)
 }
 
 static void
-do_difftime(bool usepercent, uint64_t olduser, uint64_t oldsystem, uint64_t oldidle)
+do_difftime(bool usepercent, uint64_t *olduser, uint64_t *oldsystem, uint64_t *oldidle)
 {
        uint64_t user, system, idle;
        uint64_t userelapsed, systemelapsed, idleelapsed, totalelapsed;
@@ -167,9 +251,9 @@ do_difftime(bool usepercent, uint64_t olduser, uint64_t oldsystem, uint64_t oldi
        if (kret)
                errx(1, "Error getting processor time: %s (%d)", mach_error_string(kret), kret);
 
-       userelapsed = user - olduser;
-       systemelapsed = system - oldsystem;
-       idleelapsed = idle - oldidle;
+       userelapsed = user - *olduser;
+       systemelapsed = system - *oldsystem;
+       idleelapsed = idle - *oldidle;
        totalelapsed = userelapsed + systemelapsed + idleelapsed;
 
        if (usepercent) {
@@ -189,6 +273,51 @@ do_difftime(bool usepercent, uint64_t olduser, uint64_t oldsystem, uint64_t oldi
                                ((double)userelapsed) / 1000,
                                ((double)systemelapsed) / 1000);
        }
+       *olduser = user;
+       *oldsystem = system;
+       *oldidle = idle;
+}
+
+static void
+do_piddifftime(bool usepercent, int pid, uint64_t *old_pid_user, uint64_t *old_pid_system, uint64_t *old_pid_time)
+{
+       uint64_t pid_user, pid_system, pid_time;
+       uint64_t userelapsed, systemelapsed, totalelapsed;
+       struct proc_taskinfo info;
+       int size;
+
+       size = proc_pidinfo(pid, PROC_PIDTASKINFO, 0, &info, sizeof(info));
+       if (size == PROC_PIDTASKINFO_SIZE) {
+               pid_user = info.pti_total_user;
+               pid_system = info.pti_total_system;
+       } else {
+               fprintf(stderr, "Error in proc_pidinfo(): %s",
+                               strerror(errno));
+               exit(1);
+       }
+
+       pid_time = mach_absolute_time();
+
+       userelapsed = pid_user - *old_pid_user;
+       systemelapsed = pid_system - *old_pid_system;
+       totalelapsed = pid_time - *old_pid_time;
+
+       if (usepercent) {
+               fprintf(stderr, "Pid %d: %1.02f%% user %1.02f%% sys\n",
+                          pid,
+                          ((double)userelapsed * 100)/totalelapsed,
+                          ((double)systemelapsed * 100)/totalelapsed);
+       } else {
+               fprintf(stderr, "Pid %d: %1.02f user %1.02f sys\n",
+                               pid,
+                               (((double)userelapsed) * timebase_info.numer / timebase_info.denom) / 1000000000,
+                               (((double)systemelapsed) * timebase_info.numer / timebase_info.denom) / 1000000000);
+       }
+
+       *old_pid_user = pid_user;
+       *old_pid_system = pid_system;
+       *old_pid_time = pid_time;
+
 }
 
 static kern_return_t