Subject: backing out printescaped()
To: None <tech-userlevel@netbsd.org>
From: Jan Schaumann <jschauma@netmeister.org>
List: tech-userlevel
Date: 09/07/2003 15:32:18
--UHN/qo2QbUvPLonB
Content-Type: multipart/mixed; boundary="envbJBWh7q8WU6mo"
Content-Disposition: inline


--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi,

As some of you may recall, a few weeks ago, I introduced behaviour into
/usr/src/bin to escape non-printable characters using vis(3)[1].  After
some discussion with Klaus Klein and Hubert Feyrer (who unfortunately
were not available during the original discussion) and others, it was
determined that this change was in fact Not A Good Thing, and were in
fact violating POSIX in some instances in that some tools are said to
print the pathname to stdout (which, if escaped, simply is not the same
thing anymore).  I apologize for the problems and/or instability
introduced, and thus propose to back out these changes.

However, it was also suggested to implement the '-b' option to ls(1) to
escape non-printable characters as FreeBSD and Linux do.  The attached
patch does that.  Another suggestion was to create a flag to cp(1),
mv(1) and rm(1), but since at least Linux has the '-b' flag to cp(1)
and mv(1), which does something completely different (causes the tool to
perform backups or something like that), it would not be wise to use
'-b' for that.  The attached patch would also implement the escaping of
non-printable characters if the '-e' flag is passed in combination with
'-v' or '-i'.

So:  is it worth to ``use up'' an option for this behaviour (which might
possibly be needed lateron for some other functionality), or should I
just back out the original changes?

Should ls(1) get the '-b' option?

-Jan

[1] See the thread starting with
http://mail-index.netbsd.org/tech-userlevel/2003/07/19/0000.html

--=20
I always said there was something fundamentally wrong with the universe.

--envbJBWh7q8WU6mo
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename=diff
Content-Transfer-Encoding: quoted-printable

Index: cp/cp.1
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/cp/cp.1,v
retrieving revision 1.24
diff -b -u -r1.24 cp.1
--- cp/cp.1	2003/08/07 09:05:02	1.24
+++ cp/cp.1	2003/08/30 19:34:34
@@ -45,7 +45,7 @@
 .Op Fl H | Fl L | Fl P
 .Oc
 .Op Fl f | i
-.Op Fl pv
+.Op Fl epv
 .Ar source_file target_file
 .Nm cp
 .Oo
@@ -53,7 +53,7 @@
 .Op Fl H | Fl L | Fl P
 .Oc
 .Op Fl f | i
-.Op Fl pv
+.Op Fl epv
 .Ar source_file ... target_directory
 .Sh DESCRIPTION
 In the first synopsis form, the
@@ -99,6 +99,12 @@
 to create special files rather than copying them as normal files.
 Created directories have the same mode as the corresponding source
 directory, unmodified by the process' umask.
+.It Fl e
+If the
+.Fl i
+or the
+.Fl v
+flag is specified, print octal escapes for nongraphic characters.
 .It Fl f
 For each existing destination pathname, attempt to overwrite it.
 If permissions do not allow copy to succeed, remove it and create a new
Index: cp/cp.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/cp/cp.c,v
retrieving revision 1.34
diff -b -u -r1.34 cp.c
--- cp/cp.c	2003/08/07 09:05:03	1.34
+++ cp/cp.c	2003/08/30 19:34:35
@@ -84,7 +84,7 @@
 PATH_T to =3D { to.p_path, "" };
=20
 uid_t myuid;
-int Rflag, fflag, iflag, pflag, rflag, stdout_ok, vflag;=20
+int Rflag, eflag, fflag, iflag, pflag, rflag, vflag;=20
 mode_t myumask;
=20
 enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
@@ -104,7 +104,7 @@
 	(void)setlocale(LC_ALL, "");
=20
 	Hflag =3D Lflag =3D Pflag =3D Rflag =3D 0;
-	while ((ch =3D getopt(argc, argv, "HLPRfiprv")) !=3D -1)=20
+	while ((ch =3D getopt(argc, argv, "HLPRefiprv")) !=3D -1)=20
 		switch (ch) {
 		case 'H':
 			Hflag =3D 1;
@@ -121,6 +121,9 @@
 		case 'R':
 			Rflag =3D 1;
 			break;
+		case 'e':
+			eflag =3D 1;
+			break;
 		case 'f':
 			fflag =3D 1;
 			iflag =3D 0;
@@ -149,8 +152,6 @@
 	if (argc < 2)
 		usage();
=20
-	stdout_ok =3D isatty(STDOUT_FILENO);
-
 	fts_options =3D FTS_NOCHDIR | FTS_PHYSICAL;
 	if (rflag) {
 		if (Rflag) {
@@ -187,7 +188,7 @@
 	/* Save the target base in "to". */
 	target =3D argv[--argc];
 	if (strlen(target) > MAXPATHLEN) {
-		errx(EXIT_FAILURE, "%s: name too long", printescaped(target));
+		errx(EXIT_FAILURE, "%s: name too long", target);
 		/* NOTREACHED */
 	}
 	(void)strcpy(to.p_path, target);
@@ -218,7 +219,7 @@
 	 */
 	r =3D stat(to.p_path, &to_stat);
 	if (r =3D=3D -1 && errno !=3D ENOENT) {
-		err(EXIT_FAILURE, "%s", printescaped(to.p_path));
+		err(EXIT_FAILURE, "%s", to.p_path);
 		/* NOTREACHED */
 	}
 	if (r =3D=3D -1 || !S_ISDIR(to_stat.st_mode)) {
@@ -242,7 +243,7 @@
 			else
 				r =3D lstat(*argv, &tmp_stat);
 			if (r =3D=3D -1) {
-				err(EXIT_FAILURE, "%s", printescaped(*argv));
+				err(EXIT_FAILURE, "%s", *argv);
 				/* NOTREACHED */
 			}
 		=09
@@ -270,27 +271,24 @@
 	FTS *ftsp;
 	FTSENT *curr;
 	int base, dne, nlen, rval;
-	char *p, *tmp, *fn;
+	char *p, *tmp;
=20
 	base =3D 0;	/* XXX gcc -Wuninitialized (see comment below) */
=20
 	if ((ftsp =3D fts_open(argv, fts_options, mastercmp)) =3D=3D NULL)
-		err(EXIT_FAILURE, "%s", printescaped(argv[0]));
+		err(EXIT_FAILURE, "%s", argv[0]);
 		/* NOTREACHED */
 	for (rval =3D 0; (curr =3D fts_read(ftsp)) !=3D NULL;) {
 		switch (curr->fts_info) {
 		case FTS_NS:
 		case FTS_DNR:
 		case FTS_ERR:
-			fn =3D printescaped(curr->fts_path);
-			warnx("%s: %s", fn, strerror(curr->fts_errno));
-			free(fn);
+			warnx("%s: %s", curr->fts_path,
+					strerror(curr->fts_errno));
 			rval =3D 1;
 			continue;
 		case FTS_DC:			/* Warn, continue. */
-			fn =3D printescaped(curr->fts_path);
-			warnx("%s: directory causes a cycle", fn);
-			free(fn);
+			warnx("%s: directory causes a cycle", curr->fts_path);
 			rval =3D 1;
 			continue;
 		}
@@ -302,12 +300,8 @@
 		if (type !=3D FILE_TO_FILE) {
 			if ((curr->fts_namelen +
 			    to.target_end - to.p_path + 1) > MAXPATHLEN) {
-				char *tn;
-				tn =3D printescaped(to.p_path);
-				fn =3D printescaped(curr->fts_name);
-				warnx("%s/%s: name too long (not copied)", tn, fn);
-				free(fn);
-				free(tn);
+				warnx("%s/%s: name too long (not copied)",
+						to.p_path, curr->fts_name);
 				rval =3D 1;
 				continue;
 			}
@@ -373,13 +367,8 @@
 			}
 			if (!S_ISDIR(curr->fts_statp->st_mode) &&
 			    S_ISDIR(to_stat.st_mode)) {
-				char *tn;
-				tn =3D printescaped(to.p_path);
-				fn =3D printescaped(curr->fts_path);
 		warnx("cannot overwrite directory %s with non-directory %s",
-				    tn, fn);
-				free(tn);
-				free(fn);
+				    to.p_path, curr->fts_path);
 				rval =3D 1;
 				continue;
 			}
@@ -400,12 +389,9 @@
 			break;
 		case S_IFDIR:
 			if (!Rflag && !rflag) {
-				if (curr->fts_info =3D=3D FTS_D) {
-					fn =3D printescaped(curr->fts_path);
+				if (curr->fts_info =3D=3D FTS_D)
 					warnx("%s is a directory (not copied).",
-					    fn);
-					free(fn);
-				}
+					    curr->fts_path);
 				(void)fts_set(ftsp, curr, FTS_SKIP);
 				rval =3D 1;
 				break;
@@ -430,12 +416,12 @@
 					if (mkdir(to.p_path,=20
 					    curr->fts_statp->st_mode | S_IRWXU) < 0)
 						err(EXIT_FAILURE, "%s",
-						    printescaped(to.p_path));
+						    to.p_path);
 						/* NOTREACHED */
 				} else if (!S_ISDIR(to_stat.st_mode)) {
 					errno =3D ENOTDIR;
 					err(EXIT_FAILURE, "%s",
-						printescaped(to.p_path));
+						to.p_path);
 					/* NOTREACHED */
 				}
 			}
@@ -455,9 +441,8 @@
 			}
 			else
                         {
-				fn =3D printescaped(curr->fts_path);
-                        	warnx("directory %s encountered when not expected=
.", fn);
-				free(fn);
+                        	warnx("directory %s encountered when not expected=
.",
+						curr->fts_path);
                         	rval =3D 1;
                                 break;
                         }
@@ -486,12 +471,16 @@
 			break;
 		}
 		if (vflag) {
+			char *fn;
 			char *tn;
-			fn =3D printescaped(curr->fts_path);
-			tn =3D printescaped(to.p_path);
+		=09
+			fn =3D eflag ? safe_print(curr->fts_path) : curr->fts_path;
+			tn =3D eflag ? safe_print(to.p_path) : to.p_path;
 			(void)printf("%s -> %s\n", fn, tn);
+			if (eflag) {
 			free(fn);
 			free(tn);
+			}
 		}
 	}
 	if (errno) {
Index: cp/extern.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/cp/extern.h,v
retrieving revision 1.8
diff -b -u -r1.8 extern.h
--- cp/extern.h	2003/08/07 09:05:03	1.8
+++ cp/extern.h	2003/08/30 19:34:35
@@ -42,7 +42,7 @@
=20
 extern PATH_T to;
 extern uid_t myuid;
-extern int fflag, iflag, pflag, stdout_ok;
+extern int eflag, fflag, iflag, pflag;
 extern mode_t myumask;
=20
 #include <sys/cdefs.h>
@@ -55,7 +55,7 @@
 int	set_utimes(const char *, struct stat *);
 int	setfile(struct stat *, int);
 void	usage(void);
-char	*printescaped(const char *);
+char	*safe_print(const char *);
 __END_DECLS
=20
 #endif /* !_EXTERN_H_ */
Index: cp/utils.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/cp/utils.c,v
retrieving revision 1.25
diff -b -u -r1.25 utils.c
--- cp/utils.c	2003/08/07 09:05:03	1.25
+++ cp/utils.c	2003/08/30 19:34:35
@@ -95,7 +95,12 @@
 	 */
 	if (!dne) {
 		if (iflag) {
-			(void)fprintf(stderr, "overwrite %s? ", to.p_path);
+			char *fn;
+
+			fn =3D eflag ? safe_print(to.p_path) : to.p_path;
+			(void)fprintf(stderr, "overwrite %s? ", fn);
+			if (eflag)
+				free(fn);
 			checkch =3D ch =3D getchar();
 			while (ch !=3D '\n' && ch !=3D EOF)
 				ch =3D getchar();
@@ -327,32 +332,29 @@
 usage(void)
 {
 	(void)fprintf(stderr,
-	    "usage: %s [-R [-H | -L | -P]] [-f | -i] [-pv] src target\n"
-	    "       %s [-R [-H | -L | -P]] [-f | -i] [-pv] src1 ... srcN director=
y\n",
+	    "usage: %s [-R [-H | -L | -P]] [-f | -i] [-epv] src target\n"
+	    "       %s [-R [-H | -L | -P]] [-f | -i] [-epv] src1 ... srcN directo=
ry\n",
 	    getprogname(), getprogname());
 	exit(1);
 	/* NOTREACHED */
 }
=20
 char *
-printescaped(const char *src)
+safe_print(const char *src)
 {
 	size_t len;
-	char *retval;
+	char *name;
=20
 	len =3D strlen(src);
-	if (len !=3D 0 && SIZE_T_MAX/len <=3D 4) {
+	if (len !=3D 0 && SIZE_MAX/len <=3D 4) {
 		errx(EXIT_FAILURE, "%s: name too long", src);
 		/* NOTREACHED */
 	}
=20
-	retval =3D (char *)malloc(4*len+1);
-	if (retval !=3D NULL) {
-		if (stdout_ok)
-			(void)strvis(retval, src, VIS_NL | VIS_CSTYLE);
-		else
-			(void)strcpy(retval, src);
-		return retval;
+	name =3D (char *)malloc(4*len+1);
+	if (name !=3D NULL) {
+		(void)strvis(name, src, VIS_NL | VIS_CSTYLE);
+		return name;
 	} else
 		errx(EXIT_FAILURE, "out of memory!");
 		/* NOTREACHED */
Index: rm/rm.1
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/rm/rm.1,v
retrieving revision 1.17
diff -b -u -r1.17 rm.1
--- rm/rm.1	2003/08/07 09:05:28	1.17
+++ rm/rm.1	2003/08/30 19:34:37
@@ -41,7 +41,7 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl f | Fl i
-.Op Fl dPRrvW
+.Op Fl edPRrvW
 .Ar
 .Sh DESCRIPTION
 The
@@ -56,6 +56,12 @@
 .Bl -tag -width flag
 .It Fl d
 Attempt to remove directories as well as other types of files.
+.It Fl e
+If the
+.Fl i
+or
+.Fl v
+flag is specified, print octal escapes for nongraphic characters.
 .It Fl f
 Attempt to remove the files without prompting for confirmation,
 regardless of the file's permissions.
Index: rm/rm.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/rm/rm.c,v
retrieving revision 1.37
diff -b -u -r1.37 rm.c
--- rm/rm.c	2003/08/13 03:27:19	1.37
+++ rm/rm.c	2003/08/30 19:34:37
@@ -60,11 +60,11 @@
 #include <unistd.h>
 #include <vis.h>
=20
-int dflag, eval, fflag, iflag, Pflag, stdin_ok, stdout_ok, vflag, Wflag;
+int dflag, eval, eflag, fflag, iflag, Pflag, stdin_ok, vflag, Wflag;
=20
 int	check(char *, char *, struct stat *);
 void	checkdot(char **);
-char 	*printescaped(const char *);
+char 	*safe_print(const char *);
 void	rm_file(char **);
 void	rm_overwrite(char *, struct stat *);
 void	rm_tree(char **);
@@ -95,8 +95,11 @@
 	(void)setlocale(LC_ALL, "");
=20
 	Pflag =3D rflag =3D 0;
-	while ((ch =3D getopt(argc, argv, "dfiPRrvW")) !=3D -1)
+	while ((ch =3D getopt(argc, argv, "defiPRrvW")) !=3D -1)
 		switch (ch) {
+		case 'e':
+			eflag =3D 1;
+			break;
 		case 'd':
 			dflag =3D 1;
 			break;
@@ -135,7 +138,6 @@
=20
 	if (*argv) {
 		stdin_ok =3D isatty(STDIN_FILENO);
-		stdout_ok =3D isatty(STDOUT_FILENO);
=20
 		if (rflag)
 			rm_tree(argv);
@@ -153,7 +155,6 @@
 	FTS *fts;
 	FTSENT *p;
 	int flags, needstat, rval;
-	char *fn;
 		=09
 	/*
 	 * Remove a file hierarchy.  If forcing removal (-f), or interactive
@@ -180,14 +181,13 @@
 		switch (p->fts_info) {
 		case FTS_DNR:
 			if (!fflag || p->fts_errno !=3D ENOENT) {
-				fn =3D printescaped(p->fts_path);
-				warnx("%s: %s", fn, strerror(p->fts_errno));
-				free(fn);
+				warnx("%s: %s", p->fts_path,
+						strerror(p->fts_errno));
 				eval =3D 1;
 			}
 			continue;
 		case FTS_ERR:
-			errx(EXIT_FAILURE, "%s: %s", printescaped(p->fts_path),
+			errx(EXIT_FAILURE, "%s: %s", p->fts_path,
 					strerror(p->fts_errno));
 			/* NOTREACHED */
 		case FTS_NS:
@@ -198,9 +198,8 @@
 			if (fflag && NONEXISTENT(p->fts_errno))
 				continue;
 			if (needstat) {
-				fn =3D printescaped(p->fts_path);
-				warnx("%s: %s", fn, strerror(p->fts_errno));
-				free(fn);
+				warnx("%s: %s", p->fts_path,
+						strerror(p->fts_errno));
 				eval =3D 1;
 				continue;
 			}
@@ -253,13 +252,14 @@
 			break;
 		}
 		if (rval !=3D 0) {
-			fn =3D printescaped(p->fts_path);
-			warn("%s", fn);
-			free(fn);
+			warn("%s", p->fts_path);
 			eval =3D 1;
 		} else if (vflag) {
-			fn =3D printescaped(p->fts_path);
+			char *fn;
+
+			fn =3D eflag ? safe_print(p->fts_path) : p->fts_path;
 			(void)printf("%s\n", fn);
+			if (eflag)
 			free(fn);
 		}
 	}
@@ -272,7 +272,7 @@
 {
 	struct stat sb;
 	int rval;
-	char *f, *fn;
+	char *f;
=20
 	/*
 	 * Remove a file.  POSIX 1003.2 states that, by default, attempting
@@ -285,25 +285,19 @@
 				sb.st_mode =3D S_IFWHT|S_IWUSR|S_IRUSR;
 			} else {
 				if (!fflag || !NONEXISTENT(errno)) {
-					fn =3D printescaped(f);
-					warn("%s", fn);
-					free(fn);
+					warn("%s", f);
 					eval =3D 1;
 				}
 				continue;
 			}
 		} else if (Wflag) {
-			fn =3D printescaped(f);
-			warnx("%s: %s", fn, strerror(EEXIST));
-			free(fn);
+			warnx("%s: %s", f, strerror(EEXIST));
 			eval =3D 1;
 			continue;
 		}
=20
 		if (S_ISDIR(sb.st_mode) && !dflag) {
-			fn =3D printescaped(f);
-			warnx("%s: is a directory", fn);
-			free(fn);
+			warnx("%s: is a directory", f);
 			eval =3D 1;
 			continue;
 		}
@@ -319,14 +313,15 @@
 			rval =3D unlink(f);
 		}
 		if (rval && (!fflag || !NONEXISTENT(errno))) {
-			fn =3D printescaped(f);
-			warn("%s", fn);
-			free(fn);
+			warn("%s", f);
 			eval =3D 1;
 		}
 		if (vflag && rval =3D=3D 0) {
-			fn =3D printescaped(f);
+			char *fn;
+
+			fn =3D eflag ? safe_print(f) : f;
 			(void)printf("%s\n", fn);
+			if (eflag)
 			free(fn);
 		}
 	}
@@ -350,7 +345,6 @@
 	off_t len;
 	int fd, wlen;
 	char buf[8 * 1024];
-	char *fn;
=20
 	fd =3D -1;
 	if (sbp =3D=3D NULL) {
@@ -382,9 +376,7 @@
 		return;
=20
 err:	eval =3D 1;
-	fn =3D printescaped(file);
-	warn("%s", fn);
-	free(fn);
+	warn("%s", file);
 }
=20
 int
@@ -392,12 +384,14 @@
 {
 	int ch, first;
 	char modep[15];
-	char *fn;
=20
 	/* Check -i first. */
 	if (iflag) {
-		fn =3D printescaped(path);
+		char *fn;
+
+		fn =3D eflag ? safe_print(path) : path;
 		(void)fprintf(stderr, "remove '%s'? ", fn);
+		if (eflag)
 		free(fn);
 	} else {
 		/*
@@ -410,12 +404,10 @@
 		    !(access(name, W_OK) && (errno !=3D ETXTBSY)))
 			return (1);
 		strmode(sp->st_mode, modep);
-		fn =3D  printescaped(path);
 		(void)fprintf(stderr, "override %s%s%s/%s for '%s'? ",
 		    modep + 1, modep[9] =3D=3D ' ' ? "" : " ",
 		    user_from_uid(sp->st_uid, 0),
-		    group_from_gid(sp->st_gid, 0), fn);
-		free(fn);
+		    group_from_gid(sp->st_gid, 0), path);
 	}
 	(void)fflush(stderr);
=20
@@ -466,24 +458,21 @@
 }
=20
 char *
-printescaped(const char *src)
+safe_print(const char *src)
 {
 	size_t len;
-	char *retval;
+	char *name;
=20
 	len =3D strlen(src);
-	if (len !=3D 0 && SIZE_T_MAX/len <=3D 4) {
+	if (len !=3D 0 && SIZE_MAX/len <=3D 4) {
 		errx(EXIT_FAILURE, "%s: name too long", src);
 		/* NOTREACHED */
 	}
=20
-	retval =3D (char *)malloc(4*len+1);
-	if (retval !=3D NULL) {
-		if (stdout_ok)
-			(void)strvis(retval, src, VIS_NL | VIS_CSTYLE);
-		else
-			(void)strlcpy(retval, src, 4 * len + 1);
-		return retval;
+	name =3D (char *)malloc(4*len+1);
+	if (name !=3D NULL) {
+		(void)strvis(name, src, VIS_NL | VIS_CSTYLE);
+		return name;
 	} else
 		errx(EXIT_FAILURE, "out of memory!");
 		/* NOTREACHED */
@@ -493,7 +482,7 @@
 usage(void)
 {
=20
-	(void)fprintf(stderr, "usage: %s [-f|-i] [-dPRrvW] file ...\n",
+	(void)fprintf(stderr, "usage: %s [-f|-i] [-edPRrvW] file ...\n",
 	    getprogname());
 	exit(1);
 	/* NOTREACHED */
Index: ls/extern.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/ls/extern.h,v
retrieving revision 1.14
diff -b -u -r1.14 extern.h
--- ls/extern.h	2003/08/07 09:05:14	1.14
+++ ls/extern.h	2003/08/30 19:34:37
@@ -50,6 +50,7 @@
 void	 printlong(DISPLAY *);
 void	 printscol(DISPLAY *);
 void	 printstream(DISPLAY *);
+int	 safe_print(const char *);
 void	 usage(void);
=20
 #include "stat_flags.h"
Index: ls/ls.1
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/ls/ls.1,v
retrieving revision 1.40
diff -b -u -r1.40 ls.1
--- ls/ls.1	2003/08/07 09:05:14	1.40
+++ ls/ls.1	2003/08/30 19:34:38
@@ -40,7 +40,7 @@
 .Nd list directory contents
 .Sh SYNOPSIS
 .Nm
-.Op Fl ACFLRSTWacdfgiklmnopqrstux1
+.Op Fl ACFLRSTWabcdfgiklmnopqrstux1
 .Op Ar
 .Sh DESCRIPTION
 For each operand that names a
@@ -115,6 +115,12 @@
 Include directory entries whose names begin with a
 dot
 .Pq Sq \&. .
+.It Fl b
+if the
+.Fl i
+or
+.Fl v
+flag is specified, print octal escapes for nongraphic characters.
 .It Fl c
 Use time when file status was last changed for sorting or printing.
 .It Fl d
Index: ls/ls.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/ls/ls.c,v
retrieving revision 1.50
diff -b -u -r1.50 ls.c
--- ls/ls.c	2003/08/07 09:05:15	1.50
+++ ls/ls.c	2003/08/30 19:34:39
@@ -86,6 +86,7 @@
 int f_accesstime;		/* use time of last access */
 int f_column;			/* columnated format */
 int f_columnacross;		/* columnated format, sorted across */
+int f_escape;			/* print octal escapes for nongraphic characters */
 int f_flags;			/* show flags associated with a file */
 int f_grouponly;		/* long listing without owner */
 int f_inode;			/* print inode */
@@ -133,7 +134,7 @@
 		f_listdot =3D 1;
=20
 	fts_options =3D FTS_PHYSICAL;
-	while ((ch =3D getopt(argc, argv, "1ACFLRSTWacdfgiklmnopqrstux")) !=3D -1=
) {
+	while ((ch =3D getopt(argc, argv, "1ACFLRSTWabcdfgiklmnopqrstux")) !=3D -=
1) {
 		switch (ch) {
 		/*
 		 * The -1, -C, -l, -m and -x options all override each other so
@@ -194,6 +195,11 @@
 		case 'A':
 			f_listdot =3D 1;
 			break;
+		/* the -b option turns off the -q option. */
+		case 'b':
+			f_escape =3D 1;
+			f_nonprint =3D 0;
+			break;
 		/* The -d option turns off the -R option. */
 		case 'd':
 			f_listdir =3D 1;
@@ -218,8 +224,10 @@
 		case 'p':
 			f_typedir =3D 1;
 			break;
+		/* the -q option turns off the -b option. */
 		case 'q':
 			f_nonprint =3D 1;
+			f_escape =3D 0;
 			break;
 		case 'r':
 			f_reversesort =3D 1;
Index: ls/ls.h
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/ls/ls.h,v
retrieving revision 1.13
diff -b -u -r1.13 ls.h
--- ls/ls.h	2003/08/07 09:05:15	1.13
+++ ls/ls.h	2003/08/30 19:34:39
@@ -37,8 +37,10 @@
 #define NO_PRINT	1
=20
 extern long blocksize;		/* block size units */
+extern int stdout_ok;		/* stdout connected to a tty */
=20
 extern int f_accesstime;	/* use time of last access */
+extern int f_escape;		/* print octal escapes for nongraphic characters */
 extern int f_flags;		/* show flags associated with a file */
 extern int f_grouponly;		/* long listing without owner */
 extern int f_inode;		/* print inode */
Index: ls/print.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/ls/print.c,v
retrieving revision 1.35
diff -b -u -r1.35 print.c
--- ls/print.c	2003/08/07 09:05:15	1.35
+++ ls/print.c	2003/08/30 19:34:40
@@ -129,7 +129,9 @@
 			printtime(sp->st_ctime);
 		else
 			printtime(sp->st_mtime);
-		if (f_nonprint)
+		if (f_escape)
+			(void)safe_print(p->fts_name);
+		else if (f_nonprint)
 			(void)printescaped(p->fts_name);
 		else
 			(void)printf("%s", p->fts_name);
@@ -295,7 +297,9 @@
 	if (f_size)
 		chcnt +=3D printf("%*llu ", sizefield,
 		    (long long)howmany(sp->st_blocks, blocksize));
-	if (f_nonprint)
+	if (f_escape)
+		chcnt +=3D safe_print(p->fts_name);
+	else if (f_nonprint)
 	    chcnt +=3D printescaped(p->fts_name);
 	else
 	    chcnt +=3D printf("%s", p->fts_name);
@@ -373,8 +377,10 @@
 	}
 	path[lnklen] =3D '\0';
 	(void)printf(" -> ");
-	if (f_nonprint)
-		printescaped(path);
+	if (f_escape)
+		(void)safe_print(path);
+	else if (f_nonprint)
+		(void)printescaped(path);
 	else
 		(void)printf("%s", path);
 }
Index: ls/util.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/ls/util.c,v
retrieving revision 1.24
diff -b -u -r1.24 util.c
--- ls/util.c	2003/08/07 09:05:16	1.24
+++ ls/util.c	2003/08/30 19:34:40
@@ -45,15 +45,41 @@
 #include <sys/stat.h>
=20
 #include <ctype.h>
+#include <err.h>
 #include <fts.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <vis.h>
=20
 #include "ls.h"
 #include "extern.h"
=20
 int
+safe_print(const char *src)
+{
+	size_t len;
+	char *name;
+
+	len =3D strlen(src);
+	if (len !=3D 0 && SIZE_T_MAX/len <=3D 4) {
+		errx(EXIT_FAILURE, "%s: name too long", src);
+		/* NOTREACHED */
+	}
+
+	name =3D (char *)malloc(4*len+1);
+	if (name !=3D NULL) {
+		len =3D strvis(name, src, VIS_NL | VIS_CSTYLE);
+		printf("%s", name);
+		free(name);
+		return len;
+	} else
+		errx(EXIT_FAILURE, "out of memory!");
+		/* NOTREACHED */
+}
+
+int
 printescaped(const char *src)
 {
 	unsigned char c;
@@ -64,7 +90,7 @@
 			(void)putchar(c);
 		else
 			(void)putchar('?');
-	return (n);
+	return n;
 }
=20
 void
@@ -72,7 +98,7 @@
 {
=20
 	(void)fprintf(stderr,
-	    "usage: ls [-ACFLRSTWacdfgiklmnopqrstux1] [file ...]\n");
+	    "usage: ls [-ACFLRSTWabcdfgiklmnopqrstux1] [file ...]\n");
 	exit(EXIT_FAILURE);
 	/* NOTREACHED */
 }
Index: mv/mv.1
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/mv/mv.1,v
retrieving revision 1.24
diff -b -u -r1.24 mv.1
--- mv/mv.1	2003/08/07 09:05:18	1.24
+++ mv/mv.1	2003/08/30 19:34:40
@@ -40,10 +40,10 @@
 .Nd move files
 .Sh SYNOPSIS
 .Nm
-.Op Fl fiv
+.Op Fl efiv
 .Ar source target
 .Nm
-.Op Fl fiv
+.Op Fl efiv
 .Ar source ... directory
 .Sh DESCRIPTION
 In its first form, the
@@ -69,6 +69,12 @@
 .Pp
 The following options are available:
 .Bl -tag -width flag
+.It Fl e
+If the
+.Fl i
+or
+.Fl v
+flag is specified, print octal escapes for nongraphic characters.
 .It Fl f
 Do not prompt for confirmation before overwriting the destination
 path.
Index: mv/mv.c
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
RCS file: /cvsroot/src/bin/mv/mv.c,v
retrieving revision 1.32
diff -b -u -r1.32 mv.c
--- mv/mv.c	2003/08/13 03:22:03	1.32
+++ mv/mv.c	2003/08/30 19:34:41
@@ -65,15 +65,15 @@
=20
 #include "pathnames.h"
=20
-int fflg, iflg, vflg;
-int stdin_ok, stdout_ok;
+int eflg, fflg, iflg, vflg;
+int stdin_ok;
=20
 int	copy(char *, char *);
 int	do_move(char *, char *);
 int	fastcopy(char *, char *, struct stat *);
 void	usage(void);
 int	main(int, char *[]);
-char	*printescaped(const char *);
+char	*safe_print(const char *);
=20
 int
 main(int argc, char *argv[])
@@ -86,8 +86,11 @@
 	setprogname(argv[0]);
 	(void)setlocale(LC_ALL, "");
=20
-	while ((ch =3D getopt(argc, argv, "ifv")) !=3D -1)
+	while ((ch =3D getopt(argc, argv, "eifv")) !=3D -1)
 		switch (ch) {
+		case 'e':
+			eflg =3D 1;
+			break;
 		case 'i':
 			fflg =3D 0;
 			iflg =3D 1;
@@ -110,7 +113,6 @@
 		usage();
=20
 	stdin_ok =3D isatty(STDIN_FILENO);
-	stdout_ok =3D isatty(STDOUT_FILENO);
=20
 	/*
 	 * If the stat on the target fails or the target isn't a directory,
@@ -138,9 +140,7 @@
 			++p;
=20
 		if ((baselen + (len =3D strlen(p))) >=3D MAXPATHLEN) {
-			char *fn =3D printescaped(*argv);
-			warnx("%s: destination pathname too long", fn);
-			free(fn);
+			warnx("%s: destination pathname too long", *argv);
 			rval =3D 1;
 		} else {
 			memmove(endp, p, len + 1);
@@ -157,10 +157,6 @@
 {
 	struct stat sb;
 	char modep[15];
-	char *fn, *tn;
-
-	fn =3D printescaped(from);
-	tn =3D printescaped(to);
=20
 	/*
 	 * (1)	If the destination path exists, the -f option is not specified
@@ -180,37 +176,35 @@
 		int ch;
=20
 		if (iflg) {
+			char *tn;
+
 			if (access(from, F_OK)) {
-				warn("rename %s", fn);
-				free(fn);
-				free(tn);
+				warn("rename %s", from);
 				return (1);
 			}
+			tn =3D eflg ? safe_print(to) : to;
 			(void)fprintf(stderr, "overwrite %s? ", tn);
+			if (eflg)
+				free(tn);
 		} else if (stdin_ok && access(to, W_OK) && !stat(to, &sb)) {
 			if (access(from, F_OK)) {
-				warn("rename %s", fn);
-				free(fn);
-				free(tn);
+				warn("rename %s", from);
 				return (1);
 			}
 			strmode(sb.st_mode, modep);
 			(void)fprintf(stderr, "override %s%s%s/%s for %s? ",
 			    modep + 1, modep[9] =3D=3D ' ' ? "" : " ",
 			    user_from_uid(sb.st_uid, 0),
-			    group_from_gid(sb.st_gid, 0), tn);
+			    group_from_gid(sb.st_gid, 0), to);
 		} else
 			ask =3D 0;
 		if (ask) {
 			if ((ch =3D getchar()) !=3D EOF && ch !=3D '\n')
 				while (getchar() !=3D '\n');
-			if (ch !=3D 'y' && ch !=3D 'Y') {
-				free(fn);
-				free(tn);
+			if (ch !=3D 'y' && ch !=3D 'Y')
 				return (0);
 			}
 		}
-	}
=20
 	/*
 	 * (2)	If rename() succeeds, mv shall do nothing more with the
@@ -226,17 +220,22 @@
 	 *	current source file...
 	 */
 	if (!rename(from, to)) {
-		if (vflg)
+		if (vflg) {
+			char *fn, *tn;
+
+			fn =3D eflg ? safe_print(from) : from;
+			tn =3D eflg ? safe_print(to) : to;
 			printf("%s -> %s\n", fn, tn);
+			if (eflg) {
 		free(fn);
 		free(tn);
+			}
+		}
 		return (0);
 	}
=20
 	if (errno !=3D EXDEV) {
-		warn("rename %s to %s", fn, tn);
-		free(fn);
-		free(tn);
+		warn("rename %s to %s", from, to);
 		return (1);
 	}
=20
@@ -248,9 +247,7 @@
 	 */
 	if (!lstat(to, &sb)) {
 		if ((S_ISDIR(sb.st_mode)) ? rmdir(to) : unlink(to)) {
-			warn("can't remove %s", tn);
-			free(fn);
-			free(tn);
+			warn("can't remove %s", to);
 			return (1);
 		}
 	}
@@ -260,15 +257,10 @@
 	 *	as a file hierarchy rooted in the destination path...
 	 */
 	if (lstat(from, &sb)) {
-		warn("%s", fn);
-		free(fn);
-		free(tn);
+		warn("%s", from);
 		return (1);
 	}
=20
-	free(fn);
-	free(tn);
-
 	return (S_ISREG(sb.st_mode) ?
 	    fastcopy(from, to, &sb) : copy(from, to));
 }
@@ -280,44 +272,32 @@
 	static u_int blen;
 	static char *bp;
 	int nread, from_fd, to_fd;
-	char *fn, *tn;
-
-	fn =3D printescaped(from);
-	tn =3D printescaped(to);
=20
 	if ((from_fd =3D open(from, O_RDONLY, 0)) < 0) {
-		warn("%s", fn);
-		free(fn);
-		free(tn);
+		warn("%s", from);
 		return (1);
 	}
 	if ((to_fd =3D
 	    open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) {
-		warn("%s", tn);
-		free(fn);
-		free(tn);
+		warn("%s", to);
 		(void)close(from_fd);
 		return (1);
 	}
 	if (!blen && !(bp =3D malloc(blen =3D sbp->st_blksize))) {
 		warn(NULL);
-		free(fn);
-		free(tn);
 		return (1);
 	}
 	while ((nread =3D read(from_fd, bp, blen)) > 0)
 		if (write(to_fd, bp, nread) !=3D nread) {
-			warn("%s", tn);
+			warn("%s", to);
 			goto err;
 		}
 	if (nread < 0) {
-		warn("%s", fn);
+		warn("%s", from);
 err:		if (unlink(to))
-			warn("%s: remove", tn);
+			warn("%s: remove", to);
 		(void)close(from_fd);
 		(void)close(to_fd);
-		free(fn);
-		free(tn);
 		return (1);
 	}
 	(void)close(from_fd);
@@ -335,36 +315,39 @@
 #else
 	if (futimes(to_fd, tval))
 #endif
-		warn("%s: set times", tn);
+		warn("%s: set times", to);
 	if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
 		if (errno !=3D EPERM)
-			warn("%s: set owner/group", tn);
+			warn("%s: set owner/group", to);
 		sbp->st_mode &=3D ~(S_ISUID | S_ISGID);
 	}
 	if (fchmod(to_fd, sbp->st_mode))
-		warn("%s: set mode", tn);
+		warn("%s: set mode", to);
 	if (fchflags(to_fd, sbp->st_flags) && (errno !=3D EOPNOTSUPP))
-		warn("%s: set flags (was: 0%07o)", tn, sbp->st_flags);
+		warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);
=20
 	if (close(to_fd)) {
-		warn("%s", tn);
-		free(fn);
-		free(tn);
+		warn("%s", to);
 		return (1);
 	}
=20
 	if (unlink(from)) {
-		warn("%s: remove", fn);
-		free(fn);
-		free(tn);
+		warn("%s: remove", from);
 		return (1);
 	}
=20
-	if (vflg)
-		printf("%s -> %s\n", fn, tn);
+	if (vflg) {
+		char *fn, *tn;
=20
+		fn =3D eflg ? safe_print(from) : from;
+		tn =3D eflg ? safe_print(to) : to;
+		printf("%s -> %s\n", fn, tn);
+		if (eflg) {
 	free(fn);
 	free(tn);
+		}
+	}
+
 	return (0);
 }
=20
@@ -374,7 +357,16 @@
 	int pid, status;
=20
 	if ((pid =3D vfork()) =3D=3D 0) {
-		execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", from, to, NULL);
+		char flags[8];
+
+		(void)strlcpy(flags, "-PRp", sizeof(flags));
+
+		if (eflg)
+			(void)strlcat(flags, "e", sizeof(flags));
+		if (vflg)=20
+			(void)strlcat(flags, "v", sizeof(flags));
+
+		execl(_PATH_CP, "mv", flags, from, to, NULL);
 		warn("%s", _PATH_CP);
 		_exit(1);
 	}
@@ -415,32 +407,29 @@
 void
 usage(void)
 {
-	(void)fprintf(stderr, "usage: %s [-fiv] source target\n"
-	    "       %s [-fiv] source ... directory\n", getprogname(),
+	(void)fprintf(stderr, "usage: %s [-efiv] source target\n"
+	    "       %s [-efiv] source ... directory\n", getprogname(),
 	    getprogname());
 	exit(1);
 	/* NOTREACHED */
 }
=20
 char *
-printescaped(const char *src)
+safe_print(const char *src)
 {
 	size_t len;
-	char *retval;
+	char *name;
=20
 	len =3D strlen(src);
-	if (len !=3D 0 && SIZE_T_MAX/len <=3D 4) {
+	if (len !=3D 0 && SIZE_MAX/len <=3D 4) {
 		errx(EXIT_FAILURE, "%s: name too long", src);
 		/* NOTREACHED */
 	}
=20
-	retval =3D (char *)malloc(4*len+1);
-	if (retval !=3D NULL) {
-		if (stdout_ok)
-			(void)strvis(retval, src, VIS_NL | VIS_CSTYLE);
-		else
-			(void)strlcpy(retval, src, 4 * len + 1);
-		return retval;
+	name =3D (char *)malloc(4*len+1);
+	if (name !=3D NULL) {
+		(void)strvis(name, src, VIS_NL | VIS_CSTYLE);
+		return name;
 	} else
 		errx(EXIT_FAILURE, "out of memory!");
 		/* NOTREACHED */

--envbJBWh7q8WU6mo--

--UHN/qo2QbUvPLonB
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.1 (NetBSD)

iD8DBQE/W4fBfFtkr68iakwRAjXcAKCgOyyOB1SJOTZ0M+WsYLXoQVnipACgrqkg
uJIwMvGjaN6PEJSAAJqWQV8=
=D6ex
-----END PGP SIGNATURE-----

--UHN/qo2QbUvPLonB--