Subject: rm(1) and cp(1) printable characters diff
To: None <tech-userlevel@netbsd.org>
From: Jan Schaumann <jschauma@netbsd.org>
List: tech-userlevel
Date: 07/19/2003 15:04:17
--vEao7xgI/oilGqZ+
Content-Type: multipart/mixed; boundary="3lcZGd9BuhuYXNfi"
Content-Disposition: inline


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

Hi all,

Attached is a diff that makes rm(1) and cp(1) behave more like ls(1) wrt
to nonprintable characters.  That is, if a filename in question contains
a non-printable character, it prints that as '?' if stdout is a tty.

Examples:

$ touch "foo?"
$ touch "*"
$ touch "foo^Gbar"

Before:

$ rm -i "foo?"
remove foo??
$ rm -i "*"
remove *?
$ rm -i "foo^Gbar"
remove foobar?

After:

$ rm -i "foo?"
remove 'foo?'?
$ rm -i "*"
remove '*'?
$ rm -i "foo^Gbar"
remove 'foo?bar'?


Does anybod see any problems with the patch or can suggests a more
elegant way?

Thanks,
-Jan

--=20
Wenn ich tot bin, mir soll mal Einer mit Auferstehung oder so
kommen, ich hau ihm eine rein! (Anonym)

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

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	19 Jul 2003 18:45:33 -0000
@@ -47,15 +47,17 @@
 #endif
 #endif /* not lint */
=20
-#include <sys/types.h>
+#include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/types.h>
=20
-#include <locale.h>
+#include <ctype.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>
@@ -66,6 +68,7 @@
=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 +182,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 +200,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 +281,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 +377,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 +389,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 +440,30 @@
 		} else
 			++t;
 	}
+}
+
+char *
+printescaped(char *src)
+{
+	unsigned char c;
+	int n;
+	char name[MAXPATHLEN + 1];
+	char *retval;
+
+	retval =3D src;
+
+	if (isatty(STDOUT_FILENO)) {
+		for (n =3D 0; (c =3D *src) !=3D '\0'; ++src, ++n)
+			if (isprint(c))
+				name[n] =3D c;
+			else
+				name[n] =3D '?';
+		name[n] =3D '\0';
+		if ((retval =3D strdup(name)) =3D=3D NULL)
+			retval =3D src;
+	}
+
+	return retval;
 }
=20
 void
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	19 Jul 2003 18:45:34 -0000
@@ -69,6 +69,7 @@
 #include <sys/param.h>
 #include <sys/stat.h>
=20
+#include <ctype.h>
 #include <err.h>
 #include <errno.h>
 #include <fts.h>
@@ -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[])
@@ -185,7 +187,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 +276,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 +295,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 +461,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 +494,28 @@
 	if (b_info =3D=3D FTS_D)
 		return (1);
 	return (0);
+}
+
+char *
+printescaped(char *src)
+{
+	unsigned char c;
+	int n;
+	char name[MAXPATHLEN + 1];
+	char *retval;
+
+	retval =3D src;
+
+	if (isatty(STDOUT_FILENO)) {
+		for (n =3D 0; (c =3D *src) !=3D '\0'; ++src, ++n)
+			if (isprint(c))
+				name[n] =3D c;
+			else
+				name[n] =3D '?';
+		name[n] =3D '\0';
+		if ((retval =3D strdup(name)) =3D=3D NULL)
+			retval =3D src;
+	}
+
+	return retval;
 }

--3lcZGd9BuhuYXNfi--

--vEao7xgI/oilGqZ+
Content-Type: application/pgp-signature
Content-Disposition: inline

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

iD8DBQE/GZYxfFtkr68iakwRAldhAKCDYE9awWg2aeRVoHOBTpLzRt8m2QCg04Rm
n4Jlz6AC8fd5DwUToJJqSIc=
=MKah
-----END PGP SIGNATURE-----

--vEao7xgI/oilGqZ+--