Subject: Re: rm(1) and cp(1) printable characters diff
To: Martin J. Laubach <mjl+usenet-2003-05@emsi.priv.at>
From: Jan Schaumann <jschauma@netmeister.org>
List: tech-userlevel
Date: 07/20/2003 15:33:02
--+pHx0qQiF2pBVqBT
Content-Type: multipart/mixed; boundary="IJpNTDwzlM2Ie8A6"
Content-Disposition: inline


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

"Martin J. Laubach" <mjl+usenet-2003-05@emsi.priv.at> wrote:
> |  Attached is a diff that makes rm(1) and cp(1) behave more like ls(1) w=
rt
> |  to nonprintable characters.  That is, if a filename in question contai=
ns
> |  a non-printable character, it prints that as '?' if stdout is a tty.
> | [..]
> |  $ rm -i "foo^Gbar"
> |  remove 'foo?bar'?
>=20
>   Especially with interactive mode, it would probably make
> more sense to use vis(3), so one can see what magic character
> is there, and not just fold them all into "?".

You're probably right.  I was taking ls(1) as an example, but for ls(1),
SUSv3 actually specifies to use '?', while it doesn't mention anything
about cp(1) or rm(1).

Attached is an updated diff that uses vis(3).

-Jan

--=20
chown -R us:enemy your_base

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

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.32
diff -b -u -r1.32 cp.c
--- cp/cp.c	16 Dec 2002 14:44:14 -0000	1.32
+++ cp/cp.c	20 Jul 2003 19:06:13 -0000
@@ -77,6 +77,7 @@
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
+#include <vis.h>
=20
 #include "extern.h"
=20
@@ -88,7 +89,7 @@
 PATH_T to =3D { to.p_path, "" };
=20
 uid_t myuid;
-int Rflag, fflag, iflag, pflag, rflag, vflag;=20
+int Rflag, fflag, iflag, pflag, rflag, stdin_ok, vflag;=20
 mode_t myumask;
=20
 enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
@@ -96,6 +97,7 @@
 int main(int, char *[]);
 int copy(char *[], enum op, int);
 int mastercmp(const FTSENT **, const FTSENT **);
+char	*printescaped(char *);
=20
 int
 main(int argc, char *argv[])
@@ -153,6 +155,8 @@
 	if (argc < 2)
 		usage();
=20
+        stdin_ok =3D isatty(STDIN_FILENO);
+
 	fts_options =3D FTS_NOCHDIR | FTS_PHYSICAL;
 	if (rflag) {
 		if (Rflag)
@@ -185,7 +189,7 @@
 	/* Save the target base in "to". */
 	target =3D argv[--argc];
 	if (strlen(target) > MAXPATHLEN)
-		errx(1, "%s: name too long", target);
+		errx(1, "%s: name too long", printescaped(target));
 	(void)strcpy(to.p_path, target);
 	to.p_end =3D to.p_path + strlen(to.p_path);
         if (to.p_path =3D=3D to.p_end) {
@@ -274,11 +278,13 @@
 		case FTS_DNR:
 		case FTS_ERR:
 			warnx("%s: %s",
-			    curr->fts_path, strerror(curr->fts_errno));
+			    printescaped(curr->fts_path),
+			    strerror(curr->fts_errno));
 			rval =3D 1;
 			continue;
 		case FTS_DC:			/* Warn, continue. */
-			warnx("%s: directory causes a cycle", curr->fts_path);
+			warnx("%s: directory causes a cycle",
+				       	printescaped(curr->fts_path));
 			rval =3D 1;
 			continue;
 		}
@@ -291,7 +297,8 @@
 			if ((curr->fts_namelen +
 			    to.target_end - to.p_path + 1) > MAXPATHLEN) {
 				warnx("%s/%s: name too long (not copied)",=20
-				    to.p_path, curr->fts_name);
+				    printescaped(to.p_path),
+				    printescaped(curr->fts_name));
 				rval =3D 1;
 				continue;
 			}
@@ -456,7 +463,9 @@
 			break;
 		}
 		if (vflag)
-			(void)printf("%s -> %s\n", curr->fts_path, to.p_path);
+			(void)printf("%s -> %s\n",
+				     printescaped(curr->fts_path),
+				     printescaped(to.p_path));
 	}
 	if (errno)
 		err(1, "fts_read");
@@ -487,4 +496,17 @@
 	if (b_info =3D=3D FTS_D)
 		return (1);
 	return (0);
+}
+
+char *
+printescaped(char *src)
+{
+	char *retval;
+
+	retval =3D (char *)malloc(((strlen(src)*4)+1) * sizeof(char));
+	if (stdin_ok && (retval !=3D NULL)) {
+		(void)strvis(retval, src, VIS_NL | VIS_CSTYLE);
+		return retval;
+	} else=20
+		 return src;
 }
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.34
diff -b -u -r1.34 rm.c
--- rm/rm.c	1 Mar 2003 07:57:33 -0000	1.34
+++ rm/rm.c	20 Jul 2003 19:06:13 -0000
@@ -47,25 +47,27 @@
 #endif
 #endif /* not lint */
=20
-#include <sys/types.h>
 #include <sys/stat.h>
+#include <sys/types.h>
=20
-#include <locale.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <fts.h>
 #include <grp.h>
+#include <locale.h>
 #include <pwd.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
+#include <vis.h>
=20
 int dflag, eval, fflag, iflag, Pflag, stdin_ok, vflag, Wflag;
=20
 int	check(char *, char *, struct stat *);
 void	checkdot(char **);
+char	*printescaped(char *);
 void	rm_file(char **);
 void	rm_overwrite(char *, struct stat *);
 void	rm_tree(char **);
@@ -179,12 +181,14 @@
 		case FTS_DNR:
 			if (!fflag || p->fts_errno !=3D ENOENT) {
 				warnx("%s: %s",
-				    p->fts_path, strerror(p->fts_errno));
+				    printescaped(p->fts_path),
+				    strerror(p->fts_errno));
 				eval =3D 1;
 			}
 			continue;
 		case FTS_ERR:
-			errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
+			errx(1, "%s: %s", printescaped(p->fts_path),
+					strerror(p->fts_errno));
 			/* NOTREACHED */
 		case FTS_NS:
 			/*
@@ -195,7 +199,8 @@
 				continue;
 			if (needstat) {
 				warnx("%s: %s",
-				    p->fts_path, strerror(p->fts_errno));
+				    printescaped(p->fts_path),
+				    strerror(p->fts_errno));
 				eval =3D 1;
 				continue;
 			}
@@ -275,19 +280,19 @@
 				sb.st_mode =3D S_IFWHT|S_IWUSR|S_IRUSR;
 			} else {
 				if (!fflag || !NONEXISTENT(errno)) {
-					warn("%s", f);
+					warn("%s", printescaped(f));
 					eval =3D 1;
 				}
 				continue;
 			}
 		} else if (Wflag) {
-			warnx("%s: %s", f, strerror(EEXIST));
+			warnx("%s: %s", printescaped(f), strerror(EEXIST));
 			eval =3D 1;
 			continue;
 		}
=20
 		if (S_ISDIR(sb.st_mode) && !dflag) {
-			warnx("%s: is a directory", f);
+			warnx("%s: is a directory", printescaped(f));
 			eval =3D 1;
 			continue;
 		}
@@ -371,7 +376,7 @@
=20
 	/* Check -i first. */
 	if (iflag)
-		(void)fprintf(stderr, "remove %s? ", path);
+		(void)fprintf(stderr, "remove '%s'? ", printescaped(path));
 	else {
 		/*
 		 * If it's not a symbolic link and it's unwritable and we're
@@ -383,10 +388,10 @@
 		    !(access(name, W_OK) && (errno !=3D ETXTBSY)))
 			return (1);
 		strmode(sp->st_mode, modep);
-		(void)fprintf(stderr, "override %s%s%s/%s for %s? ",
+		(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), path);
+		    group_from_gid(sp->st_gid, 0), printescaped(path));
 	}
 	(void)fflush(stderr);
=20
@@ -434,6 +439,19 @@
 		} else
 			++t;
 	}
+}
+
+char *
+printescaped(char *src)
+{
+	char *retval;
+
+	retval =3D (char *)malloc(((strlen(src) * 4) + 1) * sizeof(char));
+	if (stdin_ok && (retval !=3D NULL)) {
+		(void)strvis(retval, src, VIS_NL | VIS_CSTYLE);
+		return retval;
+	} else=20
+		return src;
 }
=20
 void

--IJpNTDwzlM2Ie8A6--

--+pHx0qQiF2pBVqBT
Content-Type: application/pgp-signature
Content-Disposition: inline

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

iD8DBQE/Gu5ufFtkr68iakwRApmbAJ41AsYl+ynEZTD+oQhoa2f+EuzTuACgsFf9
B/MYbY+U1G6rXeGB7nn+g/U=
=vddX
-----END PGP SIGNATURE-----

--+pHx0qQiF2pBVqBT--