about summary refs log tree commit diff
path: root/Src/Modules/stat.c
diff options
context:
space:
mode:
Diffstat (limited to 'Src/Modules/stat.c')
-rw-r--r--Src/Modules/stat.c148
1 files changed, 117 insertions, 31 deletions
diff --git a/Src/Modules/stat.c b/Src/Modules/stat.c
index 09245b52f..d0f80829c 100644
--- a/Src/Modules/stat.c
+++ b/Src/Modules/stat.c
@@ -34,18 +34,21 @@ enum statnum { ST_DEV, ST_INO, ST_MODE, ST_NLINK, ST_UID, ST_GID,
 		   ST_RDEV, ST_SIZE, ST_ATIM, ST_MTIM, ST_CTIM,
 		   ST_BLKSIZE, ST_BLOCKS, ST_READLINK, ST_COUNT };
 enum statflags { STF_NAME = 1,  STF_FILE = 2, STF_STRING = 4, STF_RAW = 8,
-		     STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64 };
+		     STF_PICK = 16, STF_ARRAY = 32, STF_GMT = 64,
+		     STF_HASH = 128, STF_OCTAL = 256 };
 static char *statelts[] = { "device", "inode", "mode", "nlink",
 				"uid", "gid", "rdev", "size", "atime",
 				"mtime", "ctime", "blksize", "blocks",
 				"link", NULL };
+#define HNAMEKEY "name"
 
 /**/
 static void
 statmodeprint(mode_t mode, char *outbuf, int flags)
 {
     if (flags & STF_RAW) {
-	sprintf(outbuf, "%lu", (unsigned long)mode);
+	sprintf(outbuf, (flags & STF_OCTAL) ? "0%lo" : "%lu",
+		(unsigned long)mode);
 	if (flags & STF_STRING)
 	    strcat(outbuf, " (");
     }
@@ -64,6 +67,8 @@ statmodeprint(mode_t mode, char *outbuf, int flags)
 	    *pm = 'c';
 	else if (S_ISDIR(mode))
 	    *pm = 'd';
+	else if (S_ISDOOR(mode))
+	    *pm = 'D';
 	else if (S_ISFIFO(mode))
 	    *pm = 'p';
 	else if (S_ISLNK(mode))
@@ -85,6 +90,7 @@ statmodeprint(mode_t mode, char *outbuf, int flags)
 
 	for (i = 1; i <= 9; i++)
 	    pm[i] = (mode & *mfp++) ? modes[i] : '-';
+	pm[10] = '\0';
 
 	if (mode & S_ISUID)
 	    pm[3] = (mode & S_IXUSR) ? 's' : 'S';
@@ -210,7 +216,13 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
 	break;
 
     case ST_INO:
+#ifdef INO_T_IS_64_BIT
+	convbase(optr, sbuf->st_ino, 0);
+#else
+	DPUTS(sizeof(sbuf->st_ino) > 4,
+	      "Shell compiled with wrong ino_t size");
 	statulprint((unsigned long)sbuf->st_ino, optr);
+#endif
 	break;
 
     case ST_MODE:
@@ -234,7 +246,13 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
 	break;
 
     case ST_SIZE:
+#ifdef OFF_T_IS_64_BIT
+	convbase(optr, sbuf->st_size, 0);
+#else
+	DPUTS(sizeof(sbuf->st_size) > 4,
+	      "Shell compiled with wrong off_t size");
 	statulprint((unsigned long)sbuf->st_size, optr);
+#endif
 	break;
 
     case ST_ATIM:
@@ -286,6 +304,8 @@ statprint(struct stat *sbuf, char *outbuf, char *fname, int iwhich, int flags)
  *        file names are returned as a separate array element, type names as
  *        prefix to element.  Note the formatting deliberately contains
  *        fewer frills when -A is used.
+ *  -H hash:  as for -A array, but returns a hash with the keys being those
+ *        from stat -l
  *  -F fmt: specify a $TIME-like format for printing times; the default
  *        is the (CTIME-like) "%a %b %e %k:%M:%S".  This option implies
  *        -s as it is not useful for numerical times.
@@ -304,6 +324,7 @@ static int
 bin_stat(char *name, char **args, char *ops, int func)
 {
     char **aptr, *arrnam = NULL, **array = NULL, **arrptr = NULL;
+    char *hashnam = NULL, **hash = NULL, **hashptr = NULL;
     int len, iwhich = -1, ret = 0, flags = 0, arrsize = 0, fd = 0;
     struct stat statbuf;
     int found = 0, nargs;
@@ -327,10 +348,10 @@ bin_stat(char *name, char **args, char *ops, int func)
 		    iwhich = aptr - statelts;
 		}
 	    if (found > 1) {
-		zerrnam(name, "%s: ambiguous stat element", arg, 0);
+		zwarnnam(name, "%s: ambiguous stat element", arg, 0);
 		return 1;
 	    } else if (found == 0) {
-		zerrnam(name, "%s: no such stat element", arg, 0);
+		zwarnnam(name, "%s: no such stat element", arg, 0);
 		return 1;
 	    }
 	    /* if name of link requested, turn on lstat */
@@ -339,30 +360,40 @@ bin_stat(char *name, char **args, char *ops, int func)
 	    flags |= STF_PICK;
 	} else {
 	    for (; *arg; arg++) {
-		if (strchr("glLnNrstT", *arg))
-		    ops[*arg] = 1;
+		if (strchr("glLnNorstT", *arg))
+		    ops[STOUC(*arg)] = 1;
 		else if (*arg == 'A') {
 		    if (arg[1]) {
 			arrnam = arg+1;
 		    } else if (!(arrnam = *++args)) {
-			zerrnam(name, "missing parameter name\n",
+			zwarnnam(name, "missing parameter name",
 				NULL, 0);
 			return 1;
 		    }
 		    flags |= STF_ARRAY;
 		    break;
+		} else if (*arg == 'H') {
+		    if (arg[1]) {
+			hashnam = arg+1;
+		    } else if (!(hashnam = *++args)) {
+			zwarnnam(name, "missing parameter name",
+				NULL, 0);
+			return 1;
+		    }
+		    flags |= STF_HASH;
+		    break;
 		} else if (*arg == 'f') {
 		    char *sfd;
 		    ops['f'] = 1;
 		    if (arg[1]) {
 			sfd = arg+1;
 		    } else if (!(sfd = *++args)) {
-			zerrnam(name, "missing file descriptor\n", NULL, 0);
+			zwarnnam(name, "missing file descriptor", NULL, 0);
 			return 1;
 		    }
 		    fd = zstrtol(sfd, &sfd, 10);
 		    if (*sfd) {
-			zerrnam(name, "bad file descriptor\n", NULL, 0);
+			zwarnnam(name, "bad file descriptor", NULL, 0);
 			return 1;
 		    }
 		    break;
@@ -370,20 +401,29 @@ bin_stat(char *name, char **args, char *ops, int func)
 		    if (arg[1]) {
 			timefmt = arg+1;
 		    } else if (!(timefmt = *++args)) {
-			zerrnam(name, "missing time format\n", NULL, 0);
+			zwarnnam(name, "missing time format", NULL, 0);
 			return 1;
 		    }
 		    /* force string format in order to use time format */
 		    ops['s'] = 1;
 		    break;
 		} else {
-		    zerrnam(name, "bad option: -%c", NULL, *arg);
+		    zwarnnam(name, "bad option: -%c", NULL, *arg);
 		    return 1;
 		}
 	    }
 	}
     }
 
+    if ((flags & STF_ARRAY) && (flags & STF_HASH)) {
+    	/* We don't implement setting multiple variables at once */
+	zwarnnam(name, "both array and hash requested", NULL, 0);
+	return 1;
+	/* Alternate method would be to make -H blank arrnam etc etc *
+	 * and so get 'silent loss' of earlier choice, which would   *
+	 * be similar to stat -A foo -A bar filename                 */
+    }
+
     if (ops['l']) {
 	/* list types and return:  can also list to array */
 	if (arrnam) {
@@ -423,18 +463,22 @@ bin_stat(char *name, char **args, char *ops, int func)
 	for (aptr = args; *aptr; aptr++)
 	    nargs++;
 
+    if (ops['g']) {
+	flags |= STF_GMT;
+	ops['s'] = 1;
+    }
     if (ops['s'] || ops['r'])
 	flags |= STF_STRING;
     if (ops['r'] || !ops['s'])
 	flags |= STF_RAW;
     if (ops['n'])
 	flags |= STF_FILE;
+    if (ops['o'])
+	flags |= STF_OCTAL;
     if (ops['t'])
 	flags |= STF_NAME;
-    if (ops['g'])
-	flags |= STF_GMT;
 
-    if (!arrnam) {
+    if (!(arrnam || hashnam)) {
 	if (nargs > 1)
 	    flags |= STF_FILE;
 	if (!(flags & STF_PICK))
@@ -443,9 +487,20 @@ bin_stat(char *name, char **args, char *ops, int func)
 
     if (ops['N'] || ops['f'])
 	flags &= ~STF_FILE;
-    if (ops['T'])
+    if (ops['T'] || ops['H'])
 	flags &= ~STF_NAME;
 
+    if (hashnam) {
+    	if (nargs > 1) {
+	    zwarnnam(name, "only one file allowed with -H", NULL, 0);
+	    return 1;
+	}
+	arrsize = (flags & STF_PICK) ? 1 : ST_COUNT;
+	if (flags & STF_FILE)
+	    arrsize++;
+	hashptr = hash = (char **)zcalloc((arrsize+1)*2*sizeof(char *));
+    }
+
     if (arrnam) {
 	arrsize = (flags & STF_PICK) ? 1 : ST_COUNT;
 	if (flags & STF_FILE)
@@ -469,16 +524,24 @@ bin_stat(char *name, char **args, char *ops, int func)
 		continue;
 	}
 
-	if (flags & STF_FILE)
+	if (flags & STF_FILE) {
 	    if (arrnam)
 		*arrptr++ = ztrdup(*args);
-	    else
+	    else if (hashnam) {
+	    	*hashptr++ = ztrdup(HNAMEKEY);
+		*hashptr++ = ztrdup(*args);
+	    } else
 		printf("%s%s", *args, (flags & STF_PICK) ? " " : ":\n");
+	}
 	if (iwhich > -1) {
 	    statprint(&statbuf, outbuf, *args, iwhich, flags);
 	    if (arrnam)
 		*arrptr++ = ztrdup(outbuf);
-	    else
+	    else if (hashnam) {
+		/* STF_NAME explicitly turned off for ops['H'] above */
+	    	*hashptr++ = ztrdup(statelts[iwhich]);
+		*hashptr++ = ztrdup(outbuf);
+	    } else
 		printf("%s\n", outbuf);
 	} else {
 	    int i;
@@ -486,27 +549,40 @@ bin_stat(char *name, char **args, char *ops, int func)
 		statprint(&statbuf, outbuf, *args, i, flags);
 		if (arrnam)
 		    *arrptr++= ztrdup(outbuf);
-		else
+		else if (hashnam) {
+		    /* STF_NAME explicitly turned off for ops['H'] above */
+		    *hashptr++ = ztrdup(statelts[i]);
+		    *hashptr++ = ztrdup(outbuf);
+		} else
 		    printf("%s\n", outbuf);
 	    }
 	}
 	if (ops['f'])
 	    break;
 
-	if (!arrnam && args[1] && !(flags & STF_PICK))
+	if (!arrnam && !hashnam && args[1] && !(flags & STF_PICK))
 	    putchar('\n');
     }
 
-    if (arrnam)
-	if (ret) {
-	    for (aptr = array; *aptr; aptr++)
-		zsfree(*aptr);
-	    zfree(array, arrsize+1);
-	} else {
+    if (arrnam) {
+	if (ret)
+	    freearray(array);
+	else {
 	    setaparam(arrnam, array);
 	    if (errflag)
 		return 1;
 	}
+    }
+
+    if (hashnam) {
+    	if (ret)
+	    freearray(hash);
+	else {
+	    sethparam(hashnam, hash);
+	    if (errflag)
+		return 1;
+	}
+    }
 
     return ret;
 }
@@ -517,19 +593,29 @@ static struct builtin bintab[] = {
 
 /**/
 int
-boot_stat(Module m)
+setup_(Module m)
 {
-    return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+    return 0;
 }
 
-#ifdef MODULE
+/**/
+int
+boot_(Module m)
+{
+    return !addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
+}
 
 /**/
 int
-cleanup_stat(Module m)
+cleanup_(Module m)
 {
     deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
     return 0;
 }
 
-#endif
+/**/
+int
+finish_(Module m)
+{
+    return 0;
+}