]> git.saurik.com Git - apple/shell_cmds.git/blobdiff - find/function.c
shell_cmds-187.tar.gz
[apple/shell_cmds.git] / find / function.c
index a7cbd263dbab9358f13026627bd4ba1b26651546..a673a025f1691d2518503c67ebfab6efd6e42d3b 100644 (file)
  * 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.
@@ -41,7 +37,7 @@ static const char sccsid[] = "@(#)function.c  8.10 (Berkeley) 5/4/95";
 #endif /* not lint */
 
 #include <sys/cdefs.h>
-__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.60 2008/02/24 00:01:06 imp Exp $");
+__FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.71 2011/06/13 05:22:07 avatar Exp $");
 
 #include <sys/param.h>
 #include <sys/ucred.h>
@@ -50,7 +46,6 @@ __FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.60 2008/02/24 00:01:06 imp E
 #include <sys/acl.h>
 #include <sys/wait.h>
 #include <sys/mount.h>
-#include <sys/timeb.h>
 
 #include <dirent.h>
 #include <err.h>
@@ -67,16 +62,17 @@ __FBSDID("$FreeBSD: src/usr.bin/find/function.c,v 1.60 2008/02/24 00:01:06 imp E
 #include <unistd.h>
 #include <ctype.h>
 
-#include "find.h"
-
 #ifdef __APPLE__
 #include <sys/sysctl.h>
+#include <sys/xattr.h>
 #include <libgen.h>
 #include <get_compat.h>
 #else
 #define COMPAT_MODE(func, mode) 1
 #endif
 
+#include "find.h"
+
 static PLAN *palloc(OPTION *);
 static long long find_parsenum(PLAN *, const char *, char *, char *);
 static long long find_parsetime(PLAN *, const char *, char *);
@@ -85,6 +81,7 @@ static char *nextarg(OPTION *, char ***);
 extern char **environ;
 
 static PLAN *lastexecplus = NULL;
+int execplus_error;
 
 #define        COMPARE(a, b) do {                                              \
        switch (plan->flags & F_ELG_MASK) {                             \
@@ -371,56 +368,115 @@ c_mXXdepth(OPTION *option, char ***argvp)
        return new;
 }
 
-#ifndef __APPLE__
 /*
  * -acl function --
  *
  *     Show files with EXTENDED ACL attributes.
  */
+#ifdef __APPLE__
 int
 f_acl(PLAN *plan __unused, FTSENT *entry)
 {
-       int match, entries;
+       acl_t facl;
+       int match;
        acl_entry_t ae;
+
+       match = 0;
+       if ((facl = acl_get_link_np(entry->fts_accpath, ACL_TYPE_EXTENDED)) != NULL) {
+               if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 0) {
+                       match = 1;
+               }
+               acl_free(facl);
+       }
+       return match;
+}
+#else /* !__APPLE__ */
+int
+f_acl(PLAN *plan __unused, FTSENT *entry)
+{
        acl_t facl;
+       acl_type_t acl_type;
+       int acl_supported = 0, ret, trivial;
 
        if (S_ISLNK(entry->fts_statp->st_mode))
                return 0;
-       if ((match = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED)) <= 0) {
-               if (match < 0 && errno != EINVAL)
-                       warn("%s", entry->fts_accpath);
-       else
-               return 0;
+       ret = pathconf(entry->fts_accpath, _PC_ACL_NFS4);
+       if (ret > 0) {
+               acl_supported = 1;
+               acl_type = ACL_TYPE_NFS4;
+       } else if (ret < 0 && errno != EINVAL) {
+               warn("%s", entry->fts_accpath);
+               return (0);
        }
-       match = 0;
-       if ((facl = acl_get_file(entry->fts_accpath,ACL_TYPE_ACCESS)) != NULL) {
-               if (acl_get_entry(facl, ACL_FIRST_ENTRY, &ae) == 1) {
-                       /*
-                        * POSIX.1e requires that ACLs of type ACL_TYPE_ACCESS
-                        * must have at least three entries (owner, group,
-                        * other).
-                        */
-                       entries = 1;
-                       while (acl_get_entry(facl, ACL_NEXT_ENTRY, &ae) == 1) {
-                               if (++entries > 3) {
-                                       match = 1;
-                                       break;
-                               }
-                       }
+       if (acl_supported == 0) {
+               ret = pathconf(entry->fts_accpath, _PC_ACL_EXTENDED);
+               if (ret > 0) {
+                       acl_supported = 1;
+                       acl_type = ACL_TYPE_ACCESS;
+               } else if (ret < 0 && errno != EINVAL) {
+                       warn("%s", entry->fts_accpath);
+                       return (0);
                }
-               acl_free(facl);
-       } else
+       }
+       if (acl_supported == 0)
+               return (0);
+
+       facl = acl_get_file(entry->fts_accpath, acl_type);
+       if (facl == NULL) {
                warn("%s", entry->fts_accpath);
-       return match;
+               return (0);
+       }
+       ret = acl_is_trivial_np(facl, &trivial);
+       acl_free(facl);
+       if (ret) {
+               warn("%s", entry->fts_accpath);
+               acl_free(facl);
+               return (0);
+       }
+       if (trivial)
+               return (0);
+       return (1);
 }
+#endif /* __APPLE__ */
 
 PLAN *
 c_acl(OPTION *option, char ***argvp __unused)
 {
+#ifndef __APPLE__
        ftsoptions &= ~FTS_NOSTAT;
+#endif /* !__APPLE__ */
        return (palloc(option));
 }
-#endif /* !__APPLE__ */
+
+#ifdef __APPLE__
+int
+f_xattr(PLAN *plan __unused, FTSENT *entry)
+{
+       ssize_t xattr;
+       int match;
+
+       match = 0;
+       xattr = listxattr(entry->fts_accpath, NULL, 0, XATTR_NOFOLLOW);
+       if (xattr > 0) {
+               match = 1;
+       }
+       return match;
+}
+
+int
+f_xattrname(PLAN *plan, FTSENT *entry)
+{
+       ssize_t xattr;
+       int match;
+
+       match = 0;
+       xattr = getxattr(entry->fts_accpath, plan->c_data, NULL, 0, 0, XATTR_NOFOLLOW);
+       if (xattr > 0) {
+               match = 1;
+       }
+       return match;
+}
+#endif /* __APPLE__ */
 
 /*
  * -delete functions --
@@ -437,11 +493,13 @@ f_delete(PLAN *plan __unused, FTSENT *entry)
 
        /* sanity check */
        if (isdepth == 0 ||                     /* depth off */
-           (ftsoptions & FTS_NOSTAT) ||        /* not stat()ing */
-           !(ftsoptions & FTS_PHYSICAL) ||     /* physical off */
-           (ftsoptions & FTS_LOGICAL))         /* or finally, logical on */
+           (ftsoptions & FTS_NOSTAT))          /* not stat()ing */
                errx(1, "-delete: insecure options got turned on");
 
+       if (!(ftsoptions & FTS_PHYSICAL) ||     /* physical off */
+           (ftsoptions & FTS_LOGICAL))         /* or finally, logical on */
+               errx(1, "-delete: forbidden when symlinks are followed");
+
        /* Potentially unsafe - do not accept relative paths whatsoever */
        if (strchr(entry->fts_accpath, '/') != NULL)
                errx(1, "-delete: %s: relative path potentially not safe",
@@ -451,7 +509,7 @@ f_delete(PLAN *plan __unused, FTSENT *entry)
        if ((entry->fts_statp->st_flags & (UF_APPEND|UF_IMMUTABLE)) &&
            !(entry->fts_statp->st_flags & (SF_APPEND|SF_IMMUTABLE)) &&
            geteuid() == 0)
-               chflags(entry->fts_accpath,
+               lchflags(entry->fts_accpath,
                       entry->fts_statp->st_flags &= ~(UF_APPEND|UF_IMMUTABLE));
 
        /* rmdir directories, unlink everything else */
@@ -472,8 +530,6 @@ c_delete(OPTION *option, char ***argvp __unused)
 {
 
        ftsoptions &= ~FTS_NOSTAT;      /* no optimise */
-       ftsoptions |= FTS_PHYSICAL;     /* disable -follow */
-       ftsoptions &= ~FTS_LOGICAL;     /* disable -follow */
        isoutput = 1;                   /* possible output */
        isdepth = 1;                    /* -depth implied */
 
@@ -560,7 +616,7 @@ f_empty(PLAN *plan __unused, FTSENT *entry)
                empty = 1;
                dir = opendir(entry->fts_accpath);
                if (dir == NULL)
-                       err(1, "%s", entry->fts_accpath);
+                       return 0;
                for (dp = readdir(dir); dp; dp = readdir(dir))
                        if (dp->d_name[0] != '.' ||
                            (dp->d_name[1] != '\0' &&
@@ -664,8 +720,10 @@ doexec:    if ((plan->flags & F_NEEDOK) && !queryuser(plan->e_argv))
                plan->e_psize = plan->e_pbsize;
        }
        pid = waitpid(pid, &status, 0);
-       if (plan->flags & F_EXECPLUS && WIFEXITED(status) && WEXITSTATUS(status))
-               _exit(WEXITSTATUS(status));
+       if (plan->flags & F_EXECPLUS && WIFEXITED(status) && WEXITSTATUS(status) && !execplus_error) {
+               /* Test 140 (8907531, 10656525) */
+               execplus_error = WEXITSTATUS(status);
+       }
        return (pid != -1 && WIFEXITED(status) && !WEXITSTATUS(status));
 }
 
@@ -772,7 +830,7 @@ done:       *argvp = argv + 1;
 
 /* Finish any pending -exec ... {} + functions. */
 void
-finish_execplus()
+finish_execplus(void)
 {
        PLAN *p;
 
@@ -853,7 +911,8 @@ f_fstype(PLAN *plan, FTSENT *entry)
        static dev_t curdev;    /* need a guaranteed illegal dev value */
        static int first = 1;
        struct statfs sb;
-       static int val_type, val_flags;
+       static int val_flags;
+       static char fstype[sizeof(sb.f_fstypename)];
        char *p, save[2] = {0,0};
 
        if ((plan->flags & F_MTMASK) == F_MTUNKNOWN)
@@ -895,13 +954,13 @@ f_fstype(PLAN *plan, FTSENT *entry)
                 * always copy both of them.
                 */
                val_flags = sb.f_flags;
-               val_type = sb.f_type;
+               strlcpy(fstype, sb.f_fstypename, sizeof(fstype));
        }
        switch (plan->flags & F_MTMASK) {
        case F_MTFLAG:
                return val_flags & plan->mt_data;
        case F_MTTYPE:
-               return val_type == plan->mt_data;
+               return (strncmp(fstype, plan->c_data, sizeof(fstype)) == 0);
        default:
                abort();
        }
@@ -912,22 +971,11 @@ c_fstype(OPTION *option, char ***argvp)
 {
        char *fsname;
        PLAN *new;
-       struct vfsconf vfc;
 
        fsname = nextarg(option, argvp);
        ftsoptions &= ~FTS_NOSTAT;
 
        new = palloc(option);
-
-       /*
-        * Check first for a filesystem name.
-        */
-       if (getvfsbyname(fsname, &vfc) == 0) {
-               new->flags |= F_MTTYPE;
-               new->mt_data = vfc.vfc_typenum;
-               return new;
-       }
-
        switch (*fsname) {
        case 'l':
                if (!strcmp(fsname, "local")) {
@@ -945,12 +993,8 @@ c_fstype(OPTION *option, char ***argvp)
                break;
        }
 
-       /*
-        * We need to make filesystem checks for filesystems
-        * that exists but aren't in the kernel work.
-        */
-       fprintf(stderr, "Warning: Unknown filesystem type %s\n", fsname);
-       new->flags |= F_MTUNKNOWN;
+       new->flags |= F_MTTYPE;
+       new->c_data = fsname;
        return new;
 }
 
@@ -1101,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_path, 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
@@ -1159,7 +1216,7 @@ c_newer(OPTION *option, char ***argvp)
        new = palloc(option);
        /* compare against what */
        if (option->flags & F_TIME2_T) {
-               new->t_data = get_date(fn_or_tspec, (struct timeb *) 0);
+               new->t_data = get_date(fn_or_tspec);
                if (new->t_data == (time_t) -1)
                        errx(1, "Can't parse date/time: %s", fn_or_tspec);
        } else {
@@ -1169,6 +1226,8 @@ c_newer(OPTION *option, char ***argvp)
                        new->t_data = sb.st_ctime;
                else if (option->flags & F_TIME2_A)
                        new->t_data = sb.st_atime;
+               else if (option->flags & F_TIME2_B)
+                       new->t_data = sb.st_birthtime;
                else
                        new->t_data = sb.st_mtime;
        }