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