Decode fcntl's F_{GET,SET}LEASE, F_NOTIFY, and F_DUPFD_CLOEXEC.
By Mike Frysinger (vapier AT gentoo.org)
* desc.c: Add F_SETLEASE, F_GETLEASE, F_NOTIFY,
F_DUPFD_CLOEXEC to fcntlcmds[]. Create notifyflags[] array.
(sys_fcntl): Handle new flags.

Optimize printing of open modes.
* defs.h: Declare sprint_open_modes(),
remove unused parameter in tprint_open_modes().
* desc.c (sprint_open_modes): Move fuction definition from here...
* file.c (sprint_open_modes): To here.
(tprint_open_modes): Use sprint_open_modes(), it already
generates needed string.
* ipc.c: Remove unused parameter from calls
to tprint_open_modes().
diff --git a/ChangeLog b/ChangeLog
index eb8026a..ce68580 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,21 @@
+2009-03-10  Denys Vlasenko  <dvlasenk@redhat.com>
+
+	Decode fcntl's F_{GET,SET}LEASE, F_NOTIFY, and F_DUPFD_CLOEXEC.
+	By Mike Frysinger (vapier AT gentoo.org)
+	* desc.c: Add F_SETLEASE, F_GETLEASE, F_NOTIFY,
+	F_DUPFD_CLOEXEC to fcntlcmds[]. Create notifyflags[] array.
+	(sys_fcntl): Handle new flags.
+
+	Optimize printing of open modes.
+	* defs.h: Declare sprint_open_modes(),
+	remove unused parameter in tprint_open_modes().
+	* desc.c (sprint_open_modes): Move fuction definition from here...
+	* file.c (sprint_open_modes): To here.
+	(tprint_open_modes): Use sprint_open_modes(), it already
+	generates needed string.
+	* ipc.c: Remove unused parameter from calls
+	to tprint_open_modes().
+
 2009-02-27  Denys Vlasenko  <dvlasenk@redhat.com>
 
 	AVR32 support by Hans-Christian Egtvedt
diff --git a/defs.h b/defs.h
index 9eb8162..2f5683b 100644
--- a/defs.h
+++ b/defs.h
@@ -534,7 +534,8 @@
 extern void tabto P((int));
 extern void call_summary P((FILE *));
 extern void tprint_iov P((struct tcb *, unsigned long, unsigned long));
-extern void tprint_open_modes P((struct tcb *, mode_t));
+extern void tprint_open_modes P((mode_t));
+extern const char *sprint_open_modes P((mode_t));
 extern int is_restart_error P((struct tcb *));
 
 extern int change_syscall P((struct tcb *, int));
diff --git a/desc.c b/desc.c
index cd6259a..3aae990 100644
--- a/desc.c
+++ b/desc.c
@@ -148,6 +148,18 @@
 #ifdef F_UNSHARE
 	{ F_UNSHARE,	"F_UNSHARE"	},
 #endif
+#ifdef F_SETLEASE
+	{ F_SETLEASE,	"F_SETLEASE"	},
+#endif
+#ifdef F_GETLEASE
+	{ F_GETLEASE,	"F_GETLEASE"	},
+#endif
+#ifdef F_NOTIFY
+	{ F_NOTIFY,	"F_NOTIFY"	},
+#endif
+#ifdef F_DUPFD_CLOEXEC
+	{ F_DUPFD_CLOEXEC,"F_DUPFD_CLOEXEC"},
+#endif
 	{ 0,		NULL		},
 };
 
@@ -183,6 +195,33 @@
 	{ 0,		NULL		},
 };
 
+#ifdef F_NOTIFY
+static const struct xlat notifyflags[] = {
+#ifdef DN_ACCESS
+	{ DN_ACCESS,	"DN_ACCESS"	},
+#endif
+#ifdef DN_MODIFY
+	{ DN_MODIFY,	"DN_MODIFY"	},
+#endif
+#ifdef DN_CREATE
+	{ DN_CREATE,	"DN_CREATE"	},
+#endif
+#ifdef DN_DELETE
+	{ DN_DELETE,	"DN_DELETE"	},
+#endif
+#ifdef DN_RENAME
+	{ DN_RENAME,	"DN_RENAME"	},
+#endif
+#ifdef DN_ATTRIB
+	{ DN_ATTRIB,	"DN_ATTRIB"	},
+#endif
+#ifdef DN_MULTISHOT
+	{ DN_MULTISHOT,	"DN_MULTISHOT"	},
+#endif
+	{ 0,		NULL		},
+};
+#endif
+
 static const struct xlat whence[] = {
 	{ SEEK_SET,	"SEEK_SET"	},
 	{ SEEK_CUR,	"SEEK_CUR"	},
@@ -261,40 +300,6 @@
 }
 #endif
 
-/*
- * low bits of the open(2) flags define access mode,
- * other bits are real flags.
- */
-static const char *
-sprint_open_modes(mode_t flags)
-{
-	static char outstr[1024];
-	const char *str = xlookup(open_access_modes, flags & 3);
-	const char *sep = "";
-	const struct xlat *x;
-
-	strcpy(outstr, "flags ");
-	if (str) {
-		strcat(outstr, str);
-		flags &= ~3;
-		if (!flags)
-			return outstr;
-		strcat(outstr, "|");
-	}
-
-	for (x = open_mode_flags; x->str; x++) {
-		if ((flags & x->val) == x->val) {
-			sprintf(outstr + strlen(outstr),
-				"%s%s", sep, x->str);
-			sep = "|";
-			flags &= ~x->val;
-		}
-	}
-	if (flags)
-		sprintf(outstr + strlen(outstr), "%s%#x", sep, flags);
-	return outstr;
-}
-
 int
 sys_fcntl(struct tcb *tcp)
 {
@@ -307,11 +312,14 @@
 			printflags(fdflags, tcp->u_arg[2], "FD_???");
 			break;
 		case F_SETOWN: case F_DUPFD:
+#ifdef F_DUPFD_CLOEXEC
+		case F_DUPFD_CLOEXEC:
+#endif
 			tprintf(", %ld", tcp->u_arg[2]);
 			break;
 		case F_SETFL:
 			tprintf(", ");
-			tprint_open_modes(tcp, tcp->u_arg[2]);
+			tprint_open_modes(tcp->u_arg[2]);
 			break;
 		case F_SETLK: case F_SETLKW:
 #ifdef F_FREESP
@@ -326,30 +334,50 @@
 #endif
 		/* Linux glibc defines SETLK64 as SETLK,
 		   even though the kernel has different values - as does Solaris. */
-#if defined(F_SETLK64) && F_SETLK64+0!=F_SETLK
+#if defined(F_SETLK64) && F_SETLK64 + 0 != F_SETLK
 		case F_SETLK64:
 #endif
-#if defined(F_SETLKW64) && F_SETLKW64+0!=F_SETLKW
+#if defined(F_SETLKW64) && F_SETLKW64 + 0 != F_SETLKW
 		case F_SETLKW64:
 #endif
 			tprintf(", ");
 			printflock64(tcp, tcp->u_arg[2], 0);
 			break;
 #endif
+#ifdef F_NOTIFY
+		case F_NOTIFY:
+			tprintf(", ");
+			printflags(notifyflags, tcp->u_arg[2], "DN_???");
+			break;
+#endif
+#ifdef F_SETLEASE
+		case F_SETLEASE:
+			tprintf(", ");
+			printxval(lockfcmds, tcp->u_arg[2], "F_???");
+			break;
+#endif
 		}
 	}
 	else {
 		switch (tcp->u_arg[1]) {
 		case F_DUPFD:
+#ifdef F_DUPFD_CLOEXEC
+		case F_DUPFD_CLOEXEC:
+#endif
 		case F_SETFD: case F_SETFL:
 		case F_SETLK: case F_SETLKW:
 		case F_SETOWN: case F_GETOWN:
+#ifdef F_NOTIFY
+		case F_NOTIFY:
+#endif
+#ifdef F_SETLEASE
+		case F_SETLEASE:
+#endif
 			break;
 		case F_GETFD:
 			if (syserror(tcp) || tcp->u_rval == 0)
 				return 0;
-			tcp->auxstr =
-				sprintflags("flags ", fdflags, tcp->u_rval);
+			tcp->auxstr = sprintflags("flags ", fdflags, tcp->u_rval);
 			return RVAL_HEX|RVAL_STR;
 		case F_GETFL:
 			if (syserror(tcp))
@@ -368,6 +396,13 @@
 			printflock64(tcp, tcp->u_arg[2], 1);
 			break;
 #endif
+#ifdef F_GETLEASE
+		case F_GETLEASE:
+			if (syserror(tcp))
+				return 0;
+			tcp->auxstr = xlookup(lockfcmds, tcp->u_rval);
+			return RVAL_HEX|RVAL_STR;
+#endif
 		default:
 			tprintf(", %#lx", tcp->u_arg[2]);
 			break;
diff --git a/file.c b/file.c
index 3496bb2..f283a35 100644
--- a/file.c
+++ b/file.c
@@ -239,7 +239,7 @@
 #ifdef O_RSYNC
 	{ O_RSYNC,	"O_RSYNC"	},
 #endif
-#ifdef O_NDELAY
+#if defined(O_NDELAY) && (O_NDELAY != O_NONBLOCK)
 	{ O_NDELAY,	"O_NDELAY"	},
 #endif
 #ifdef O_PRIV
@@ -339,23 +339,61 @@
 #endif
 
 /*
+ * Pity stpcpy() is not standardized...
+ */
+static char *
+str_append(char *dst, const char *src)
+{
+	while ((*dst = *src++) != '\0')
+		dst++;
+	return dst;
+}
+
+/*
  * low bits of the open(2) flags define access mode,
  * other bits are real flags.
  */
-void
-tprint_open_modes(struct tcb *tcp, mode_t flags)
+const char *
+sprint_open_modes(mode_t flags)
 {
-	const char *str = xlookup(open_access_modes, flags & 3);
+	static char outstr[1024];
+	char *p;
+	char sep = 0;
+	const char *str;
+	const struct xlat *x;
 
-	if (str)
-	{
-		tprintf("%s", str);
+	p = str_append(outstr, "flags ");
+	str = xlookup(open_access_modes, flags & 3);
+	if (str) {
+		p = str_append(p, str);
 		flags &= ~3;
 		if (!flags)
-			return;
-		tprintf("|");
+			return outstr;
+		sep = '|';
 	}
-	printflags(open_mode_flags, flags, "O_???");
+
+	for (x = open_mode_flags; x->str; x++) {
+		if ((flags & x->val) == x->val) {
+			if (sep)
+				*p++ = sep;
+			p = str_append(p, x->str);
+			flags &= ~x->val;
+			if (!flags)
+				return outstr;
+			sep = '|';
+		}
+	}
+	/* flags is still nonzero */
+	if (sep)
+		*p++ = sep;
+	sprintf(p, "%#x", flags);
+	return outstr;
+}
+
+void
+tprint_open_modes(mode_t flags)
+{
+	tprintf(sprint_open_modes(flags) + sizeof("flags"));
 }
 
 static int
@@ -365,7 +403,7 @@
 		printpath(tcp, tcp->u_arg[offset]);
 		tprintf(", ");
 		/* flags */
-		tprint_open_modes(tcp, tcp->u_arg[offset + 1]);
+		tprint_open_modes(tcp->u_arg[offset + 1]);
 		if (tcp->u_arg[offset + 1] & O_CREAT) {
 			/* mode */
 			tprintf(", %#lo", tcp->u_arg[offset + 2]);
diff --git a/ipc.c b/ipc.c
index 548d2e1..ab29412 100644
--- a/ipc.c
+++ b/ipc.c
@@ -420,7 +420,7 @@
 		printpath(tcp, tcp->u_arg[0]);
 		tprintf(", ");
 		/* flags */
-		tprint_open_modes(tcp, tcp->u_arg[1]);
+		tprint_open_modes(tcp->u_arg[1]);
 		if (tcp->u_arg[1] & O_CREAT) {
 # ifndef HAVE_MQUEUE_H
 			tprintf(", %lx", tcp->u_arg[2]);
@@ -489,7 +489,7 @@
 			return;
 		}
 		tprintf("{mq_flags=");
-		tprint_open_modes(tcp, attr.mq_flags);
+		tprint_open_modes(attr.mq_flags);
 		tprintf(", mq_maxmsg=%ld, mq_msgsize=%ld, mq_curmsg=%ld}",
 			attr.mq_maxmsg, attr.mq_msgsize, attr.mq_curmsgs);
 # endif