Hi,

I had a customer which had reported that the ksh run into problem if
the /tmp partition on his system had no space left due to a process
gone wild:

  Last login: Tue Oct 23 15:12:00 2012 from ...
  /etc/profile: line 12: write to 1 failed [No space left on device]
  /etc/profile: line 41: write to 1 failed [No space left on device]
  /etc/profile: line 87: write to 1 failed [No space left on device]
  /etc/profile: line 88: write to 1 failed [No space left on device]
  /etc/profile: line 91: write to 1 failed [No space left on device]
  /etc/profile: line 92: write to 1 failed [No space left on device]
  /etc/profile: line 93: write to 1 failed [No space left on device]
  /usr/bin/manpath: can't set the locale; make sure $LC_* and $LANG are correct
  /etc/profile: line 207: write to 1 failed [No space left on device]
  /etc/profile[324]: .: line 606: write to 4 failed [No space left on device]

also the ksh93u-2012-02-29 sometimes crash in src/cmd/ksh93/sh/subshell.c
which seems to be fixed in current ksh.  Nevertheless IMHO the ksh should
check not only if access is allowed in /tmp or /usr/tmp (which points to
/var/tmp) but also if there is enough room left.  If no space is left on
the temporary device it would be perfect to use pipe() as fallback for
stdout.

See the attached patch for a suggested solution.  The change in
src/lib/libast/path/pathtemp.c uses statvfs() to check if the device
has at least space of the sitze of one page left.  The change in
src/lib/libast/sfio/sftmp.c use the /dev/shm tmpfs which is used for
POSIX shared memory objects.  One could use shm_open()/shm_unlink()
but the file descriptor then has FD_CLOEXEC set in its flags.


     Werner

-- 
  "Having a smoking section in a restaurant is like having
          a peeing section in a swimming pool." -- Edward Burr
--- src/lib/libast/path/pathtemp.c
+++ src/lib/libast/path/pathtemp.c	2012-10-25 10:35:14.510345073 +0000
@@ -73,15 +73,49 @@
 #include <ls.h>
 #include <tv.h>
 #include <tm.h>
+#include <error.h>
 
 #define ATTEMPT		10
 
 #define TMP_ENV		"TMPDIR"
 #define TMP_PATH_ENV	"TMPPATH"
 #define TMP1		"/tmp"
-#define TMP2		"/usr/tmp"
+#define TMP2		"/var/tmp"
 
-#define VALID(d)	(*(d)&&!eaccess(d,W_OK|X_OK))
+static inline int xaccess(const char *path, int mode)
+{
+	static size_t pgsz;
+	struct statvfs vfs;
+	int ret;
+
+	if (!pgsz)
+		pgsz = strtoul(astconf("PAGESIZE",NiL,NiL),NiL,0);
+
+	if (!path || !*path)
+	{
+		errno = EFAULT;
+		goto err;
+	}
+
+	do
+		ret = statvfs(path, &vfs);
+	while (ret < 0 && errno == EINTR);
+
+	if (ret < 0)
+		goto err;
+
+	if (vfs.f_frsize*vfs.f_bavail < pgsz)
+	{
+		errno = ENOSPC;
+		goto err;
+	}
+
+	return eaccess(path, mode);
+err:
+	return -1;
+}
+
+#define VALID(d)	(*(d)&&!xaccess(d,W_OK|X_OK))
 
 static struct
 {
@@ -182,7 +216,7 @@ pathtemp(char* buf, size_t len, const ch
 		tv.tv_nsec = 0;
 	else
 		tvgettime(&tv);
-	if (!(d = (char*)dir) || *d && eaccess(d, W_OK|X_OK))
+	if (!(d = (char*)dir) || (*d && xaccess(d, W_OK|X_OK)))
 	{
 		if (!tmp.vec)
 		{
@@ -227,7 +261,7 @@ pathtemp(char* buf, size_t len, const ch
 			tmp.dir = tmp.vec;
 			d = *tmp.dir++;
 		}
-		if (!d && (!*(d = astconf("TMP", NiL, NiL)) || eaccess(d, W_OK|X_OK)) && eaccess(d = TMP1, W_OK|X_OK) && eaccess(d = TMP2, W_OK|X_OK))
+		if (!d && (!*(d = astconf("TMP", NiL, NiL)) || xaccess(d, W_OK|X_OK)) && xaccess(d = TMP1, W_OK|X_OK) && xaccess(d = TMP2, W_OK|X_OK))
 			return 0;
 	}
 	if (!len)
--- src/lib/libast/sfio/sftmp.c
+++ src/lib/libast/sfio/sftmp.c	2012-10-25 12:09:18.026344912 +0000
@@ -20,6 +20,14 @@
 *                                                                      *
 ***********************************************************************/
 #include	"sfhdr.h"
+#if _PACKAGE_ast
+# if defined(__linux__) && _lib_statfs
+#  include <sys/statfs.h>
+#  ifndef  TMPFS_MAGIC
+#   define TMPFS_MAGIC	0x01021994
+#  endif
+# endif
+#endif
 
 /*	Create a temporary stream for read/write.
 **	The stream is originally created as a memory-resident stream.
@@ -207,7 +215,24 @@ Sfio_t*	f;
 	int		fd;
 
 #if _PACKAGE_ast
+# if defined(__linux__) && _lib_statfs
+	/*
+	 * Use the area of POSIX shared memory objects for the new temporary file descriptor
+	 * that is do not access HD or SSD but only the memory based tmpfs of the POSIX SHM
+	 */
+	static int doshm;
+	static char *shm = "/dev/shm";
+	if (!doshm)
+	{
+		struct statfs fs;
+		if (statfs(shm, &fs) < 0 || fs.f_type != TMPFS_MAGIC || eaccess(shm, W_OK|X_OK))
+			shm = NiL;
+		doshm++;
+	}
+	if(!(file = pathtemp(NiL,PATH_MAX,shm,"sf",&fd)))
+# else
 	if(!(file = pathtemp(NiL,PATH_MAX,NiL,"sf",&fd)))
+# endif
 		return -1;
 	_rmtmp(f, file);
 	free(file);
_______________________________________________
ast-developers mailing list
ast-developers@research.att.com
https://mailman.research.att.com/mailman/listinfo/ast-developers

Reply via email to