cups-lpd with a space limited print spool

Sebastian James seb at esfnet.co.uk
Thu Jul 27 07:08:18 PDT 2006


Sorry, I got it wrong again. Here it is:

--- cups-lpd.orig.c	2006-07-27 15:04:41.000000000 +0100
+++ cups-lpd.c	2006-07-27 15:03:48.000000000 +0100
@@ -72,6 +72,7 @@
  * currently match the Solaris LPD mini-daemon.
  */

+
 /*
  * Prototypes...
  */
@@ -86,6 +87,42 @@
 char	*smart_gets(char *s, int len, FILE *fp);


+/* Whether to apply the disk usage checking code for systems with
+   limited file storage */
+#define CHECK_DISK_SPACE_FEATURE 1
+
+#ifdef CHECK_DISK_SPACE_FEATURE
+
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+
+/* BUFFER is the smallest amount of free space allowed on the cups
+   temporary file store before cups-lpd will start to pause while
+   processing jobs. BUFFER should be given in bytes. BUFFER should be
+   twice as big as the largest print job which is expected to be
+   handled by cups-lpd. If BUFFER is set to 8 MB, a print file of 4 MB
+   would be accepted and the data received, but a following job (of
+   any size) would wait.  The accepted job would then be duplicated as
+   it's passed to the cupsd via the print_file() function.
+
+   NB! NB! If a print file of 4MB<size<=8MB is sent to cups-lpd.c, it
+   would be received, but never printed, so this code really does
+   depend on your knowing the size of your print jobs. It's intended
+   for those implementing commercial printing systems with limited
+   storage space for print jobs. */
+
+#define BUFFER      8388608 /* 8 MB */
+#define HALF_BUFFER 4194304 /* half of the above */
+
+#define FORCE_MAX_JOB_SIZE 1 /* Define this if no job of size greater
+				than HALF_BUFFER should be accepted */
+
+/* These two functions are used as checks on allowable free space. */
+int     check_free_space_for_a_duplicate (const char * file);
+int     tempdir_free_space (int bytes_limit);
+
+#endif /* CHECK_DISK_SPACE_FEATURE */
+
 /*
  * 'main()' - Process an incoming LPD request...
  */
@@ -402,6 +439,9 @@
   char		uri[HTTP_MAX_URI];	/* Printer URI */
   cups_lang_t	*language;		/* Language to use */
   int		jobid;			/* New job ID */
+#ifdef CHECK_DISK_SPACE_FEATURE
+  int           rtn;                    /* return value of check_free_space... */
+#endif


  /*
@@ -465,6 +505,25 @@

   snprintf(uri, sizeof(uri), "/printers/%s", name);

+#ifdef CHECK_DISK_SPACE_FEATURE
+  /*
+   * Find the size of the file and make sure we have 1 times that amount
+   * of free space prior to processing it, as the cupsDoFileRequest will copy
+   * the file prior to spooling it to the printer.
+   */
+  while (!(rtn = check_free_space_for_a_duplicate (file)))
+  {
+    syslog (LOG_INFO,
+	    "ramdisk is full, wait for space to become "
+	    "available before passing job on to cupsd");
+    usleep (5000000); /* 5 sec */
+  }
+
+  if (rtn == -1)
+    syslog (LOG_ERR, "check_free_space_for_a_duplicate() returned an error.");
+
+#endif /* CHECK_DISK_SPACE_FEATURE */
+
   response = cupsDoFileRequest(http, request, uri, file);

   if (response == NULL)
@@ -536,6 +595,9 @@
   int		num_options;		/* Number of options */
   cups_option_t	*options;		/* Options */
   int		banner;			/* Print banner? */
+#ifdef FORCE_MAX_JOB_SIZE
+  int           bytes_total = 0;        /* Total bytes received */
+#endif


   status   = 0;
@@ -699,6 +761,16 @@
     * Copy the data or control file from the client...
     */

+#ifdef CHECK_DISK_SPACE_FEATURE
+    /* Wait till there is BUFFER Mbytes free before
+       starting to receive the data */
+    while (tempdir_free_space (BUFFER) != 1)
+    {
+      syslog (LOG_ERR, "tempdir_free_space() said 'not enough space', pause 5s.");
+      usleep (5000000);
+    }
+#endif /* CHECK_DISK_SPACE_FEATURE */
+
     for (i = atoi(count); i > 0; i -= bytes)
     {
       if (i > sizeof(line))
@@ -716,6 +788,20 @@
         status = 1;
 	break;
       }
+#ifdef FORCE_MAX_JOB_SIZE
+      else
+      {
+	bytes_total += bytes;
+	if (bytes_total > HALF_BUFFER)
+	{
+	  /* if FORCE_MAX_JOB_SIZE is set, we don't allow a job in
+	   which is greater than half the size of our "minimum
+	   available free print file space" value */
+	  status = 1;
+	  break;
+	}
+      }
+#endif /* FORCE_MAX_JOB_SIZE */
     }

    /*
@@ -1422,6 +1508,124 @@
 }


+#ifdef CHECK_DISK_SPACE_FEATURE
+
+/*
+ * 'check_free_space_for_a_duplicate()' - Check we have enough free space
+ * to create a duplicate of "file" on the filesystem containing "file".
+ *
+ * NB: This assumes the cups-lpd temporary file is created in the same
+ * directory as the cups temporary file. Is that true? It is for my
+ * application, but may not be for all?
+ *
+ * This check is important on cups systems where the print spool filesystem
+ * is limited in size.
+ *
+ */
+
+int
+check_free_space_for_a_duplicate (const char * file)
+{
+  struct statvfs    *tmpstat;        /* Used by statvfs() function */
+  struct stat       *buf;            /* Used by stat() function */
+  int               statret;         /* To hold the rtn value of stat() and statvfs() */
+  unsigned long     file_size = 0;   /* The size of the file to be printed */
+  unsigned long     free_space = 0;  /* The free space available on the filesystem holding file */
+
+  /* Find disk usage of file */
+  buf = malloc (sizeof (struct stat));
+  memset (buf, 0, sizeof(struct stat));
+
+  if ((statret = stat (file, buf)) != 0) {
+    syslog (LOG_ERR, "%s: stat() returned error %d\n",
+	    __FUNCTION__, statret);
+    free (buf);
+    return -1;
+  }
+
+  if (S_ISREG(buf->st_mode))
+  {
+    file_size = buf->st_size;
+    free (buf);
+  }
+  else
+  {
+    /* Error reading file */
+    syslog (LOG_ERR, "%s: Error reading file", __FUNCTION__);
+    free (buf);
+    return -1;
+  }
+
+  /* Find free space available */
+  tmpstat = malloc (sizeof (struct statvfs));
+
+  /* Here we have a hardcoded directory - how to get this from cups? */
+  if ((statret = statvfs (file, tmpstat)))
+  {
+    syslog (LOG_ERR, "%s: statvfs() returned error %d\n",
+	    __FUNCTION__, statret);
+    free (tmpstat);
+    return -1;
+  }
+
+  /* 512 blocks is 2 MB on /tmp on the vortex */
+  free_space = tmpstat->f_bfree * tmpstat->f_bsize;
+
+  syslog (LOG_INFO, "file_size = %ld (%2f MB), free_space = %ld (%2f MB)",
+	  file_size, (float)file_size/1048576,
+	  free_space, (float)free_space/1048576);
+
+  if (free_space > file_size)
+  {
+    free (tmpstat);
+    return 1;
+  }
+  else
+  {
+    free (tmpstat);
+    return 0;
+  }
+
+}
+
+
+/*
+ * Seb's hacky "how much free space on /tmp" fn.  The hackyness is
+ * that it's specific to my system where print files are stored in
+ * /tmp/ - that is, in cupsd.conf: TempDir=/tmp
+ *
+ * Is there a cups API function which returns the value of TempDir
+ * from cupsd.conf?
+ */
+int tempdir_free_space (int bytes_limit)
+{
+  struct statvfs   *tmpstat;
+  int              statret;
+
+  tmpstat = malloc (sizeof (struct statvfs));
+
+  /* Before generating each file, test that there is
+     bytes_limit bytes free on the /tmp filesystem */
+  if ((statret = statvfs ("/tmp", tmpstat)))
+  {
+    syslog (LOG_ERR, "statvfs returned error %d", statret);
+    return -1;
+  }
+
+  if ((tmpstat->f_bfree * tmpstat->f_bsize) > bytes_limit)
+  {
+    free (tmpstat);
+    return 1;
+  }
+  else
+  {
+    free (tmpstat);
+    return 0;
+  }
+}
+
+#endif /* CHECK_DISK_SPACE_FEATURE */
+
 /*
  * End of "$Id: cups-lpd.c,v 1.49 2005/01/03 19:29:59 mike Exp $".
  */





More information about the cups mailing list