--- old/usr/src/cmd/tail/forward.c	Fri Jan 18 13:59:17 2013
+++ new/usr/src/cmd/tail/forward.c	Fri Jan 18 13:59:17 2013
@@ -31,9 +31,7 @@
  */
 
 /*
- * Solaris porting notes:  the original FreeBSD version made use of the
- *                         BSD kqueue event notification framework; this
- *                         was changed to use usleep()
+ * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  */
 
 #include <sys/param.h>
@@ -53,6 +51,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <unistd.h>
 
 #include "extern.h"
@@ -63,9 +62,11 @@
 
 /* defines for inner loop actions */
 #define	USE_SLEEP	0
+#define	USE_PORT	1
 #define	ADD_EVENTS	2
 
-int action = USE_SLEEP;
+int port;
+int action = USE_PORT;
 
 static const file_info_t *last;
 
@@ -261,6 +262,65 @@
 }
 
 static void
+associate(file_info_t *file, boolean_t assoc)
+{
+	char buf[64];
+
+	if (action != USE_PORT || file->fp == NULL)
+		return;
+
+	if (!S_ISREG(file->st.st_mode)) {
+		/*
+		 * For FIFOs, we use PORT_SOURCE_FD as our port event source.
+		 */
+		if (assoc) {
+			(void) port_associate(port, PORT_SOURCE_FD,
+			    fileno(file->fp), POLLIN, file);
+		} else {
+			(void) port_dissociate(port, PORT_SOURCE_FD,
+			    fileno(file->fp));
+		}
+
+		return;
+	}
+
+	bzero(&file->fobj, sizeof (file->fobj));
+
+	/*
+	 * We pull a bit of a stunt here.  PORT_SOURCE_FILE only allows us to
+	 * specify a file name -- not a file descriptor.  If we were to specify
+	 * the name of the file to port_associate() and that file were moved
+	 * aside, we would not be able to reassociate an event because we would
+	 * not know a name that would resolve to the new file (indeed, there
+	 * might not be such a name -- the file may have been unlinked).  But
+	 * there _is_ a name that we know maps to the file and doesn't change:
+	 * the name of the representation of the open file descriptor in /proc.
+	 * We therefore associate with this name (and the underlying file),
+	 * not the name of the file as specified at the command line.
+	 */
+	(void) snprintf(buf,
+	    sizeof (buf), "/proc/self/fd/%d", fileno(file->fp));
+
+	/*
+	 * Note that portfs uses the address of the specified file_obj_t to
+	 * tag an association; if one creates a different association with a
+	 * (different) file_ob_t that happens to be at the same address,
+	 * the first association will be implicitly removed.  To assure that
+	 * each file has a disjoint file_obj_t, we allocate the memory for it
+	 * in the file_info, not on the stack.
+	 */
+	file->fobj.fo_name = buf;
+
+	if (assoc) {
+		(void) port_associate(port, PORT_SOURCE_FILE,
+		    (uintptr_t)&file->fobj, FILE_MODIFIED | FILE_TRUNC, file);
+	} else {
+		(void) port_dissociate(port, PORT_SOURCE_FILE,
+		    (uintptr_t)&file->fobj);
+	}
+}
+
+static void
 set_events(file_info_t *files)
 {
 	int i;
@@ -271,6 +331,8 @@
 			continue;
 
 		(void) fstat(fileno(file->fp), &file->st);
+
+		associate(file, B_TRUE);
 	}
 }
 
@@ -284,6 +346,8 @@
 	int active, ev_change, i, n = -1;
 	struct stat sb2;
 	file_info_t *file;
+	struct timespec ts;
+	port_event_t ev;
 
 	/* Position each of the files */
 
@@ -307,6 +371,12 @@
 		return;
 
 	last = --file;
+
+	if (action == USE_PORT &&
+	    (stat("/proc/self/fd", &sb2) == -1 || !S_ISDIR(sb2.st_mode) ||
+	    (port = port_create()) == -1))
+		action = USE_SLEEP;
+
 	set_events(files);
 
 	for (;;) {
@@ -341,12 +411,13 @@
 				    sb2.st_dev != file->st.st_dev ||
 				    sb2.st_nlink == 0) {
 					(void) show(file);
+					associate(file, B_FALSE);
 					file->fp = freopen(file->file_name, "r",
 					    file->fp);
-					if (file->fp != NULL)
+					if (file->fp != NULL) {
 						(void) memcpy(&file->st, &sb2,
 						    sizeof (struct stat));
-					else if (errno != ENOENT)
+					} else if (errno != ENOENT)
 						ierr(file->file_name);
 					ev_change++;
 				}
@@ -361,6 +432,26 @@
 			set_events(files);
 
 		switch (action) {
+		case USE_PORT:
+			ts.tv_sec = 1;
+			ts.tv_nsec = 0;
+
+			/*
+			 * In the -F case we set a timeout to ensure that
+			 * we re-stat the file at least once every second.
+			 */
+			n = port_get(port, &ev, Fflag ? &ts : NULL);
+
+			if (n == 0) {
+				file = (file_info_t *)ev.portev_user;
+				associate(file, B_TRUE);
+
+				if (ev.portev_events & FILE_TRUNC)
+					(void) fseek(file->fp, 0, SEEK_SET);
+			}
+
+			break;
+
 		case USE_SLEEP:
 			(void) usleep(250000);
 			break;
