summaryrefslogtreecommitdiff
path: root/usr/src/lib/print/job.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/print/job.c')
-rw-r--r--usr/src/lib/print/job.c348
1 files changed, 194 insertions, 154 deletions
diff --git a/usr/src/lib/print/job.c b/usr/src/lib/print/job.c
index f2be713ac7..128b331df4 100644
--- a/usr/src/lib/print/job.c
+++ b/usr/src/lib/print/job.c
@@ -48,6 +48,8 @@
#include <print/list.h>
+#define MAX_RETRIES (5)
+
/*
* These specify important strings in the job routines
*/
@@ -693,183 +695,221 @@ job_store(job_t *job)
return (0);
}
+int
+get_job_from_cfile(jobfile_t *file, char *cFile, char *xFile, job_t *tmp)
+{
+ jobfile_t *file1;
+ int n_cnt;
+ char *p, *cfp;
+
+ /* map in the control data */
+ if ((file->jf_size = map_in_file(cFile, &file->jf_data, 0)) <= 0) {
+ syslog(LOG_INFO, "could not read control file (%s): %m, "
+ "canceling %d destined for %s:%s",
+ (file->jf_spl_path ? file->jf_spl_path:"NULL"),
+ tmp->job_id,
+ (tmp->job_server ? tmp->job_server : "NULL"),
+ (tmp->job_printer ? tmp->job_printer : "NULL"));
+ return (0);
+ }
+ file->jf_mmapped = 1;
+ tmp->job_cf = file;
+
+ /* look for usr, host, & data files */
+
+ /*
+ * Bugid 4137904 - "File Name" can be
+ * anywhere in control file.
+ * Bugid 4179341 - "File Name" can be missing
+ * in control file.
+ * Keep a separate pointer to the control file.
+ * When a CF_UNLINK entry is found use the second
+ * pointer to search for a corresponding 'N' entry.
+ * The behavior is to associate the first CF_UNLINK
+ * entry with the first 'N' entry and so on.
+ * Note: n_cnt is only used to determine if we
+ * should test for 'N' at the beginning of
+ * the file.
+ */
+ cfp = file->jf_data;
+ n_cnt = 0;
+ for (p = file->jf_data - 1; p != NULL; p = strchr(p, '\n')) {
+ switch (*(++p)) {
+ case CF_USER:
+ tmp->job_user = strcdup(++p, '\n');
+ break;
+ case CF_HOST:
+ tmp->job_host = strcdup(++p, '\n');
+ break;
+ case CF_UNLINK:
+ if ((file1 = calloc(1, sizeof (*file))) == NULL) {
+ syslog(LOG_DEBUG, "cf_unlink: calloc() failed");
+ munmap(file->jf_data, file->jf_size);
+ file->jf_mmapped = 0;
+ return (0);
+ }
+ file1->jf_src_path = strdup(xFile);
+ file1->jf_spl_path = strcdup(++p, '\n');
+ file1->jf_size = file_size(file1->jf_spl_path);
+
+ if (cfp != NULL) {
+ /*
+ * Beginning of file. Check for first
+ * character == 'N'
+ */
+ if ((n_cnt == 0) && (*cfp == 'N')) {
+ cfp++;
+ n_cnt++;
+ } else {
+ cfp = strstr(cfp, "\nN");
+ if (cfp != NULL) {
+ cfp += 2;
+ n_cnt++;
+ }
+ }
+ if (cfp != NULL) {
+ file1->jf_name = strcdup(cfp, '\n');
+ /*
+ * Move cfp to end of line or
+ * set to NULL if end of file.
+ */
+ cfp = strchr(cfp, '\n');
+ }
+ }
+ tmp->job_df_list = (jobfile_t **)list_append((void **)
+ tmp->job_df_list, (void *)file1);
+ break;
+ }
+ }
+ if (tmp->job_df_list == NULL) {
+ munmap(file->jf_data, file->jf_size);
+ file->jf_mmapped = 0;
+ return (0);
+ }
+
+ return (1);
+}
/*
- * job_retreive() will retrieve the disk copy of a job associated with the
+ * job_retrieve() will retrieve the disk copy of a job associated with the
* transfer file name passed in. It returns a pointer to a job structure
* or a NULL if the job was not on disk.
*/
job_t *
job_retrieve(char *xFile, char *spool)
{
+ int n;
+ int retry_cnt = 0;
+ char *s;
+ jobfile_t *file, *file1;
+ char cFile[BUFSIZ];
+ char buf[BUFSIZ];
+ int fd, n_cnt, lck = 1;
+ char *p, *cfp;
+ flock_t flk;
job_t *tmp;
syslog(LOG_DEBUG, "job_retrieve(%s)", xFile);
- if ((tmp = (job_t *)calloc(1, sizeof (*tmp))) != NULL) {
- jobfile_t *file;
- char buf[BUFSIZ];
- int fd, n_cnt, lck = 1;
- char *p, *cfp;
- flock_t flk;
+ if ((tmp = (job_t *)calloc(1, sizeof (*tmp))) == NULL) {
+ return (NULL);
+ }
- flk.l_type = F_RDLCK;
- flk.l_whence = 1;
- flk.l_start = 0;
- flk.l_len = 0;
+ if ((file = calloc(1, sizeof (*file))) == NULL) {
+ free(tmp);
+ return (NULL);
+ }
- (void) memset(buf, NULL, sizeof (buf));
+ flk.l_type = F_RDLCK;
+ flk.l_whence = 1;
+ flk.l_start = 0;
+ flk.l_len = 0;
- /* get printer & server */
- if (((fd = open(xFile, O_RDONLY)) >= 0) &&
- ((lck = fcntl(fd, F_SETLK, &flk)) == 0) &&
- (read(fd, buf, sizeof (buf)) > 0)) {
- char *s;
+ (void) memset(buf, NULL, sizeof (buf));
+ /* get job id, from binding file name */
+ (void) strlcpy(buf, xFile + strlen(_xfer_file_prefix) + 1,
+ sizeof (buf));
+
+ buf[3] = NULL;
+ tmp->job_id = atoi(buf);
+
+ /* Construct data file and control file names */
+ (void) strlcpy(cFile, _control_file_prefix, sizeof (cFile));
+ (void) strlcat(cFile, xFile + strlen(_xfer_file_prefix),
+ sizeof (cFile));
+
+ /* remove data file and control file whenever xFile is removed */
+ if ((fd = open(xFile, O_RDONLY)) < 0) {
+ syslog(LOG_DEBUG, "job_retrieve(%s) open failed errno=%d",
+ xFile, errno);
+ if (get_job_from_cfile(file, cFile, xFile, tmp))
+ job_destroy(tmp);
+ free(file);
+ free(tmp);
+ (void) unlink(xFile);
+ (void) unlink(cFile);
+ return (NULL);
+ }
+
+ /*
+ * If failed to get a lock on the file, just return NULL. It will
+ * be retried later.
+ */
+ if ((lck = fcntl(fd, F_SETLK, &flk)) < 0) {
+ syslog(LOG_DEBUG, "job_retrieve(%s) lock failed errno=%d",
+ xFile, errno);
+ close(fd);
+ free(file);
+ free(tmp);
+ return (NULL);
+ }
+ /*
+ * Retry a few times if we failed to read or read returns 0, just
+ * to make sure we tried hard before giving up. In practice,
+ * there were cases of read() returning 0. To handle that
+ * scenario just try a few times.
+ */
+ for (retry_cnt = 0; retry_cnt < MAX_RETRIES; retry_cnt++) {
+ if ((n = read(fd, buf, sizeof (buf))) > 0) {
+ close(fd);
if ((s = strtok(buf, ":\n")) != NULL)
tmp->job_server = strdup(s);
if ((s = strtok(NULL, ":\n")) != NULL)
tmp->job_printer = strdup(s);
- close(fd);
- } else {
- free(tmp);
- if (fd >= 0)
- close(fd);
- if (lck == 0)
- (void) unlink(xFile);
- return (NULL);
+ syslog(LOG_DEBUG, "job_retrieve(%s) success - %s:%s",
+ xFile, tmp->job_server, tmp->job_printer);
+ break;
}
+ }
+ /*
+ * If failed to read after MAX_RETRIES, return NULL and remove xFile,
+ * and cFile.
+ */
+ if (retry_cnt == MAX_RETRIES) {
+ syslog(LOG_DEBUG, "job_retrieve(%s) unsuccessful", xFile);
+ if (get_job_from_cfile(file, cFile, xFile, tmp))
+ job_destroy(tmp);
+ free(file);
+ free(tmp);
+ (void) unlink(xFile);
+ (void) unlink(cFile);
+ return (NULL);
+ }
- /*
- * If file is corrupted, then job_server & job_printer
- * can be NULL. In that case return NULL
- */
- if (tmp->job_server == NULL || tmp->job_printer == NULL)
- return (NULL);
-
- /* get job id, from binding file name */
- (void) strlcpy(buf, xFile + strlen(_xfer_file_prefix) + 1,
- sizeof (buf));
- buf[3] = NULL;
- tmp->job_id = atoi(buf);
-
- /*
- * add control file and binding file names. the will should
- * always only differ by the prefix.
- */
- if ((file = calloc(1, sizeof (*file))) == NULL)
- return (NULL);
-
- (void) strlcpy(buf, _control_file_prefix, sizeof (buf));
- (void) strlcat(buf, xFile + strlen(_xfer_file_prefix),
- sizeof (buf));
- file->jf_src_path = strdup(xFile);
- file->jf_spl_path = strdup(buf);
-
- /* map in the control data */
- if ((file->jf_size = map_in_file(buf, &file->jf_data, 0))
- <= 0) {
- syslog(LOG_INFO,
- "could not read control (%s): %m, canceling %d destined for %s@%s",
- (file->jf_spl_path ? file->jf_spl_path:"NULL"),
- tmp->job_id,
- (tmp->job_printer ? tmp->job_printer : "NULL"),
- (tmp->job_server ? tmp->job_server : "NULL"));
- (void) unlink(file->jf_spl_path); /* control file */
- (void) unlink(file->jf_src_path); /* binding file */
- free(tmp);
- free(file);
- return (NULL);
- }
- file->jf_mmapped = 1;
- tmp->job_cf = file;
-
- /* look for usr, host, & data files */
-
- /*
- * Bugid 4137904 - "File Name" can be
- * anywhere in control file.
- * Bugid 4179341 - "File Name" can be missing
- * in control file.
- * Keep a separate pointer to the control file.
- * When a CF_UNLINK entry is found use the second
- * pointer to search for a corresponding 'N' entry.
- * The behavior is to associate the first CF_UNLINK
- * entry with the first 'N' entry and so on.
- * Note: n_cnt is only used to determine if we
- * should test for 'N' at the beginning of
- * the file.
- */
- cfp = file->jf_data;
- n_cnt = 0;
- for (p = file->jf_data - 1; p != NULL; p = strchr(p, '\n')) {
- switch (*(++p)) {
- case CF_USER:
- tmp->job_user = strcdup(++p, '\n');
- break;
- case CF_HOST:
- tmp->job_host = strcdup(++p, '\n');
- break;
- case CF_UNLINK:
- if ((file = calloc(1, sizeof (*file)))
- == NULL) {
- syslog(LOG_DEBUG,
- "cf_unlink: calloc() failed");
- if (tmp != NULL)
- free(tmp);
- return (NULL);
- }
- file ->jf_spl_path = strcdup(++p, '\n');
- file->jf_size = file_size(file->jf_spl_path);
+ file->jf_src_path = strdup(xFile);
+ file->jf_spl_path = strdup(cFile);
- if (cfp != NULL) {
- /*
- * Beginning of file. Check for first
- * character == 'N'
- */
- if ((n_cnt == 0) && (*cfp == 'N')) {
- cfp++;
- n_cnt++;
- } else {
- cfp = strstr(cfp, "\nN");
- if (cfp != NULL) {
- cfp += 2;
- n_cnt++;
- }
- }
- if (cfp != NULL) {
- file->jf_name =
- strcdup(cfp, '\n');
- /*
- * Move cfp to end of line or
- * set to NULL if end of file.
- */
- cfp = strchr(cfp, '\n');
- }
- }
- tmp->job_df_list = (jobfile_t **)
- list_append((void **)
- tmp->job_df_list,
- (void *)file);
- break;
- }
- }
- if (tmp->job_df_list == NULL) {
- syslog(LOG_DEBUG,
- "Invalid control file (%s). Missing 'U' entry. "
- "Canceling %d destined for %s@%s",
- (file->jf_spl_path ? file->jf_spl_path:"NULL"),
- tmp->job_id,
- (tmp->job_printer ? tmp->job_printer : "NULL"),
- (tmp->job_server ? tmp->job_server : "NULL"));
- (void) unlink(file->jf_spl_path); /* control file */
- (void) unlink(file->jf_src_path); /* binding file */
- free(tmp);
- free(file);
- return (NULL);
- } else {
- tmp->job_spool_dir = strdup(spool);
- }
+ if (!get_job_from_cfile(file, cFile, xFile, tmp)) {
+ (void) unlink(file->jf_spl_path); /* control file */
+ (void) unlink(file->jf_src_path); /* binding file */
+ free(file->jf_src_path);
+ free(file->jf_spl_path);
+ free(file);
+ free(tmp);
+ return (NULL);
}
+
+ tmp->job_spool_dir = strdup(spool);
return (tmp);
}