job.c revision 95c2d3023b88b9097d9822eb47ace5466e6d1cf4
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*LINTLIBRARY*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <libintl.h>
#include <pwd.h>
#include <sys/stat.h>
#include <papi_impl.h>
/*
* for an older application that may have been linked with a pre-v1.0
* PAPI implementation.
*/
papi_status_t
papiAttributeListAdd(papi_attribute_t ***attrs, int flags, char *name,
papi_attribute_value_type_t type, papi_attribute_value_t *value)
{
return (papiAttributeListAddValue(attrs, flags, name, type, value));
}
#ifdef LP_USE_PAPI_ATTR
static papi_status_t psm_modifyAttrsFile(papi_attribute_t **attrs, char *file);
static papi_status_t psm_modifyAttrsList(char *file, papi_attribute_t **attrs,
papi_attribute_t ***newAttrs);
#endif
void
papiJobFree(papi_job_t job)
{
job_t *tmp = (job_t *)job;
if (tmp != NULL) {
papiAttributeListFree(tmp->attributes);
free(tmp);
}
}
void
papiJobListFree(papi_job_t *jobs)
{
if (jobs != NULL) {
int i;
for (i = 0; jobs[i] != NULL; i++) {
papiJobFree(jobs[i]);
}
free(jobs);
}
}
papi_attribute_t **
papiJobGetAttributeList(papi_job_t job)
{
job_t *tmp = (job_t *)job;
if (tmp != NULL)
return (tmp->attributes);
return (NULL);
}
char *
papiJobGetPrinterName(papi_job_t job)
{
job_t *tmp = (job_t *)job;
char *result = NULL;
if (tmp != NULL)
papiAttributeListGetString(tmp->attributes, NULL,
"printer-name", &result);
return (result);
}
int32_t
papiJobGetId(papi_job_t job)
{
job_t *tmp = (job_t *)job;
int result = -1;
if (tmp != NULL)
papiAttributeListGetInteger(tmp->attributes, NULL, "job-id",
&result);
return (result);
}
static REQUEST *
create_request(papi_service_t svc, char *printer, papi_attribute_t **attributes)
{
REQUEST *r;
if ((r = calloc(1, sizeof (*r))) != NULL) {
r->priority = -1;
r->destination = printer_name_from_uri_id(printer, -1);
job_attributes_to_lpsched_request(svc, r, attributes);
}
return (r);
}
static papi_status_t
authorized(service_t *svc, int32_t id)
{
papi_status_t result = PAPI_NOT_AUTHORIZED; /* assume the worst */
char file[32];
REQUEST *r;
snprintf(file, sizeof (file), "%d-0", id);
if ((r = getrequest(file)) != NULL) {
uid_t uid = getuid();
struct passwd *pw = NULL;
char *user = "intruder"; /* assume an intruder */
if ((pw = getpwuid(uid)) != NULL)
user = pw->pw_name; /* use the process owner */
if ((uid == 0) || (uid == 71)) { /* root/lp can forge this */
papi_status_t s;
s = papiAttributeListGetString(svc->attributes, NULL,
"user-name", &user);
if (s != PAPI_OK) /* true root/lp are almighty */
result = PAPI_OK;
}
if ((result != PAPI_OK) && (strcmp(user, r->user) == 0))
result = PAPI_OK;
freerequest(r);
} else
result = PAPI_NOT_FOUND;
return (result);
}
static papi_status_t
copy_file(char *from, char *to)
{
int ifd, ofd;
char buf[BUFSIZ];
int rc;
if ((ifd = open(from, O_RDONLY)) < 0)
return (PAPI_DOCUMENT_ACCESS_ERROR);
if ((ofd = open(to, O_WRONLY)) < 0) {
close(ifd);
return (PAPI_NOT_POSSIBLE);
}
while ((rc = read(ifd, buf, sizeof (buf))) > 0)
write(ofd, buf, rc);
close(ifd);
close(ofd);
return (PAPI_OK);
}
#ifdef LP_USE_PAPI_ATTR
/*
* *****************************************************************************
*
* Description: Create a file containing all the attributes in the attribute
* list passed to this function.
* This file is then passed through lpsched and given to either
* a slow-filter or to the printer's interface script to process
* the attributes.
*
* Parameters: attrs - list of attributes and their values
* file - file pathname to create and put the attributes into.
*
* *****************************************************************************
*/
static papi_status_t
psm_copy_attrsToFile(papi_attribute_t **attrs, char *file)
{
papi_status_t result = PAPI_OK;
if ((attrs != NULL) && (*attrs != NULL)) {
FILE *out = NULL;
if ((out = fopen(file, "w")) != NULL) {
papiAttributeListPrint(out, attrs, "");
fclose(out);
} else {
result = PAPI_NOT_POSSIBLE;
}
}
return (result);
} /* psm_copy_attrsToFile */
/*
* *****************************************************************************
*
* Description: Modify the given attribute 'file' with the attributes from the
* 'attrs' list. Attributes already in the file will be replaced
* with the new value. New attributes will be added into the file.
*
* Parameters: attrs - list of attributes and their values
* file - file pathname to create and put the attributes into.
*
* *****************************************************************************
*/
static papi_status_t
psm_modifyAttrsFile(papi_attribute_t **attrs, char *file)
{
papi_status_t result = PAPI_OK;
papi_attribute_t **newAttrs = NULL;
struct stat tmpBuf;
FILE *fd = NULL;
if ((attrs != NULL) && (*attrs != NULL) && (file != NULL)) {
/*
* check file exist before try to modify it, if it doesn't
* exist assume there is an error
*/
if (stat(file, &tmpBuf) == 0) {
/*
* if file is currently empty just write the given
* attributes to the file otherwise exact the attributes
* from the file and modify them accordingly before
* writing them back to the file
*/
if (tmpBuf.st_size == 0) {
newAttrs = (papi_attribute_t **)attrs;
fd = fopen(file, "w");
if (fd != NULL) {
papiAttributeListPrint(fd,
newAttrs, "");
fclose(fd);
} else {
result = PAPI_NOT_POSSIBLE;
}
} else {
result =
psm_modifyAttrsList(file, attrs, &newAttrs);
fd = fopen(file, "w");
if (fd != NULL) {
papiAttributeListPrint(fd,
newAttrs, "");
fclose(fd);
} else {
result = PAPI_NOT_POSSIBLE;
}
papiAttributeListFree(newAttrs);
}
} else {
result = PAPI_NOT_POSSIBLE;
}
}
return (result);
} /* psm_modifyAttrsFile */
/*
* *****************************************************************************
*
* Description: Extracts the attributes in the given attribute 'file' and
* creates a new list 'newAttrs' containing the modified list of
* attributes.
*
* Parameters: file - pathname of file containing attributes to be modified
* attrs - list of attributes and their values to modify
* newAttrs - returns the modified list of attributes
*
* *****************************************************************************
*/
static papi_status_t
psm_modifyAttrsList(char *file, papi_attribute_t **attrs,
papi_attribute_t ***newAttrs)
{
papi_status_t result = PAPI_OK;
papi_attribute_t *nextAttr = NULL;
papi_attribute_value_t **values = NULL;
void *iter = NULL;
FILE *fd = NULL;
register int fD = 0;
char aBuff[200];
char *a = NULL;
char *p = NULL;
int count = 0;
int n = 0;
fd = fopen(file, "r");
if (fd != NULL) {
fD = fileno(fd);
a = &aBuff[0];
p = &aBuff[0];
count = read(fD, &aBuff[0], sizeof (aBuff) - 1);
while ((result == PAPI_OK) && (count > 0)) {
aBuff[count+n] = '\0';
if (count == sizeof (aBuff) - n - 1) {
p = strrchr(aBuff, '\n');
if (p != NULL) {
/* terminate at last complete line */
*p = '\0';
}
}
result = papiAttributeListFromString(
newAttrs, PAPI_ATTR_EXCL, aBuff);
if (result == PAPI_OK) {
/*
* handle any part lines and then read the next
* buffer from the file
*/
n = 0;
if (p != a) {
p++; /* skip NL */
n = sizeof (aBuff) - 1 - (p - a);
strncpy(aBuff, p, n);
}
count = read(fD, &aBuff[n],
sizeof (aBuff) - n - 1);
p = &aBuff[0];
}
}
fclose(fd);
}
/* now modify the attribute list with the new attributes in 'attrs' */
nextAttr = papiAttributeListGetNext((papi_attribute_t **)attrs, &iter);
while ((result == PAPI_OK) && (nextAttr != NULL)) {
values = nextAttr->values;
if ((values != NULL) && (*values != NULL)) {
result = papiAttributeListAddValue(newAttrs,
PAPI_ATTR_REPLACE,
nextAttr->name,
nextAttr->type, *values);
values++;
}
while ((result == PAPI_OK) &&
(values != NULL) && (*values != NULL)) {
result = papiAttributeListAddValue(newAttrs,
PAPI_ATTR_APPEND,
nextAttr->name,
nextAttr->type, *values);
values++;
}
nextAttr =
papiAttributeListGetNext((papi_attribute_t **)attrs, &iter);
}
return (result);
} /* papi_modifyAttrsList() */
#endif
papi_status_t
papiJobSubmit(papi_service_t handle, char *printer,
papi_attribute_t **job_attributes,
papi_job_ticket_t *job_ticket,
char **files, papi_job_t *job)
{
papi_status_t status;
service_t *svc = handle;
struct stat statbuf;
job_t *j;
int file_no;
char *request_id = NULL;
REQUEST *request;
int i;
char *c;
char *tmp = NULL;
char lpfile[BUFSIZ];
if ((svc == NULL) || (printer == NULL) || (files == NULL) ||
(job == NULL))
return (PAPI_BAD_ARGUMENT);
if (job_ticket != NULL)
return (PAPI_OPERATION_NOT_SUPPORTED);
if (files != NULL)
for (file_no = 0; files[file_no] != NULL; file_no++) {
if (access(files[file_no], R_OK) < 0) {
detailed_error(svc,
gettext("Cannot access file: %s: %s"),
files[file_no], strerror(errno));
return (PAPI_BAD_ARGUMENT);
}
stat(files[file_no], &statbuf);
if (statbuf.st_size == 0) {
detailed_error(svc,
gettext("Zero byte (empty) file: %s"),
files[file_no]);
return (PAPI_BAD_ARGUMENT);
}
}
if ((*job = j = calloc(1, sizeof (*j))) == NULL)
return (PAPI_TEMPORARY_ERROR);
/* file_no + 1 for the control file (-0) */
status = lpsched_alloc_files(svc, file_no + 1, &request_id);
if (status != PAPI_OK)
return (status);
request = create_request(svc, (char *)printer,
(papi_attribute_t **)job_attributes);
for (i = 0; files[i] != NULL; i++) {
papi_status_t status;
snprintf(lpfile, sizeof (lpfile), "%s%s-%d",
"/var/spool/lp/temp/", request_id, i+1);
status = copy_file(files[i], lpfile);
if (status != PAPI_OK) {
detailed_error(svc,
gettext("unable to copy: %s -> %s: %s"),
files[i], lpfile, strerror(errno));
freerequest(request);
return (PAPI_DEVICE_ERROR);
}
addlist(&(request->file_list), lpfile);
}
#ifdef LP_USE_PAPI_ATTR
/*
* store the job attributes in the PAPI job attribute file that was
* created by lpsched_alloc_files(), the attributes will then pass
* through lpsched and be given to the slow-filters and the printer's
* interface script to process them
*/
snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
status = psm_copy_attrsToFile(job_attributes, lpfile);
if (status != PAPI_OK) {
detailed_error(svc, "unable to copy attributes to file: %s: %s",
lpfile, strerror(errno));
return (PAPI_DEVICE_ERROR);
}
#endif
/* store the meta-data file */
snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
if (putrequest(lpfile, request) < 0) {
detailed_error(svc, gettext("unable to save request: %s: %s"),
lpfile, strerror(errno));
freerequest(request);
return (PAPI_DEVICE_ERROR);
}
status = lpsched_commit_job(svc, lpfile, &tmp);
if (status != PAPI_OK) {
unlink(lpfile);
freerequest(request);
return (status);
}
lpsched_request_to_job_attributes(request, j);
freerequest(request);
if ((c = strrchr(tmp, '-')) != NULL)
c++;
papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
"job-id", atoi(c));
papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
"job-uri", tmp);
return (PAPI_OK);
}
papi_status_t
papiJobSubmitByReference(papi_service_t handle, char *printer,
papi_attribute_t **job_attributes,
papi_job_ticket_t *job_ticket,
char **files, papi_job_t *job)
{
service_t *svc = handle;
struct stat statbuf;
job_t *j;
int file_no;
short status;
char *request_id = NULL;
REQUEST *request;
char *c;
char *tmp = NULL;
char lpfile[BUFSIZ];
char **file_list = NULL;
if ((svc == NULL) || (printer == NULL) || (files == NULL) ||
(job == NULL))
return (PAPI_BAD_ARGUMENT);
if (job_ticket != NULL)
return (PAPI_OPERATION_NOT_SUPPORTED);
if (files != NULL)
for (file_no = 0; files[file_no] != NULL; file_no++) {
if (access(files[file_no], R_OK) < 0) {
detailed_error(svc,
gettext("Cannot access file: %s: %s"),
files[file_no], strerror(errno));
return (PAPI_DOCUMENT_ACCESS_ERROR);
}
stat(files[file_no], &statbuf);
if (statbuf.st_size == 0) {
detailed_error(svc,
gettext("Zero byte (empty) file: %s"),
files[file_no]);
return (PAPI_BAD_ARGUMENT);
}
if (files[file_no][0] != '/') {
char path[MAXPATHLEN];
if (getcwd(path, sizeof (path)) == NULL) {
detailed_error(svc, gettext(
"getcwd for file: %s: %s"),
files[file_no],
strerror(errno));
return (PAPI_DOCUMENT_ACCESS_ERROR);
}
strlcat(path, "/", sizeof (path));
if (strlcat(path, files[file_no], sizeof (path))
>= sizeof (path)) {
detailed_error(svc, gettext(
"pathname too long: %s"),
files[file_no]);
return (PAPI_DOCUMENT_ACCESS_ERROR);
}
addlist(&file_list, path);
} else
addlist(&file_list, (char *)files[file_no]);
}
if ((*job = j = calloc(1, sizeof (*j))) == NULL)
return (PAPI_TEMPORARY_ERROR);
/* 1 for the control file (-0) */
status = lpsched_alloc_files(svc, 1, &request_id);
if (status != PAPI_OK)
return (status);
request = create_request(svc, (char *)printer,
(papi_attribute_t **)job_attributes);
request->file_list = file_list;
#ifdef LP_USE_PAPI_ATTR
/*
* store the job attributes in the PAPI job attribute file that was
* created by lpsched_alloc_files(), the attributes will then pass
* through lpsched and be given to the slow-filters and the printer's
* interface script to process them
*/
snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
status = psm_copy_attrsToFile(job_attributes, lpfile);
if (status != PAPI_OK) {
detailed_error(svc, "unable to copy attributes to file: %s: %s",
lpfile, strerror(errno));
return (PAPI_DEVICE_ERROR);
}
#endif
/* store the meta-data file */
snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
if (putrequest(lpfile, request) < 0) {
detailed_error(svc, gettext("unable to save request: %s: %s"),
lpfile, strerror(errno));
freerequest(request);
return (PAPI_DEVICE_ERROR);
}
status = lpsched_commit_job(svc, lpfile, &tmp);
if (status != PAPI_OK) {
unlink(lpfile);
freerequest(request);
return (status);
}
lpsched_request_to_job_attributes(request, j);
freerequest(request);
if ((c = strrchr(tmp, '-')) != NULL)
c++;
papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
"job-id", atoi(c));
papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
"job-uri", tmp);
return (PAPI_OK);
}
papi_status_t
papiJobValidate(papi_service_t handle, char *printer,
papi_attribute_t **job_attributes,
papi_job_ticket_t *job_ticket,
char **files, papi_job_t *job)
{
papi_status_t status;
papi_attribute_t **attributes = NULL;
int i;
papiAttributeListAddString(&attributes, PAPI_ATTR_REPLACE,
"job-hold-until", "indefinite");
for (i = 0; job_attributes[i]; i++)
list_append(&attributes, job_attributes[i]);
status = papiJobSubmitByReference(handle, printer,
(papi_attribute_t **)attributes,
job_ticket, files, job);
if (status == PAPI_OK) {
int id = papiJobGetId(*job);
if (id != -1)
papiJobCancel(handle, printer, id);
}
attributes[1] = NULL; /* after attr[0], they are in another list */
papiAttributeListFree(attributes);
return (status);
}
papi_status_t
papiJobStreamOpen(papi_service_t handle, char *printer,
papi_attribute_t **job_attributes,
papi_job_ticket_t *job_ticket, papi_stream_t *stream)
{
papi_status_t status;
service_t *svc = handle;
job_stream_t *s = NULL;
char *request_id = NULL;
char lpfile[BUFSIZ];
if ((svc == NULL) || (printer == NULL) || (stream == NULL))
return (PAPI_BAD_ARGUMENT);
if (job_ticket != NULL)
return (PAPI_OPERATION_NOT_SUPPORTED);
if ((*stream = s = calloc(1, sizeof (*s))) == NULL)
return (PAPI_TEMPORARY_ERROR);
/* 1 for data, 1 for the meta-data (-0) */
status = lpsched_alloc_files(svc, 2, &request_id);
if (status != PAPI_OK)
return (status);
s->request = create_request(svc, (char *)printer,
(papi_attribute_t **)job_attributes);
snprintf(lpfile, sizeof (lpfile), "/var/spool/lp/temp/%s-1",
request_id);
s->fd = open(lpfile, O_WRONLY);
addlist(&(s->request->file_list), lpfile);
#ifdef LP_USE_PAPI_ATTR
/*
* store the job attributes in the PAPI job attribute file that was
* created by lpsched_alloc_files(), the attributes will then pass
* through lpsched and be given to the slow-filters and the printer's
* interface script to process them
*/
snprintf(lpfile, sizeof (lpfile), "%s%s-%s",
"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
status = psm_copy_attrsToFile(job_attributes, lpfile);
if (status != PAPI_OK) {
detailed_error(svc, "unable to copy attributes to file: %s: %s",
lpfile, strerror(errno));
close(s->fd);
free(s);
return (PAPI_DEVICE_ERROR);
}
#endif
/* store the meta-data file */
snprintf(lpfile, sizeof (lpfile), "%s-0", request_id);
s->meta_data_file = strdup(lpfile);
if (putrequest(lpfile, s->request) < 0) {
detailed_error(svc, gettext("unable to save request: %s: %s"),
lpfile, strerror(errno));
s->request = NULL;
return (PAPI_DEVICE_ERROR);
}
return (PAPI_OK);
}
papi_status_t
papiJobStreamWrite(papi_service_t handle,
papi_stream_t stream, void *buffer, size_t buflen)
{
service_t *svc = handle;
job_stream_t *s = stream;
if ((svc == NULL) || (stream == NULL) || (buffer == NULL))
return (PAPI_BAD_ARGUMENT);
if (write(s->fd, buffer, buflen) != buflen)
return (PAPI_DEVICE_ERROR);
return (PAPI_OK);
}
papi_status_t
papiJobStreamClose(papi_service_t handle,
papi_stream_t stream, papi_job_t *job)
{
papi_status_t status = PAPI_OK;
service_t *svc = handle;
job_stream_t *s = stream;
job_t *j = NULL;
char *tmp = NULL, *c;
if ((svc == NULL) || (stream == NULL) || (job == NULL))
return (PAPI_BAD_ARGUMENT);
if ((*job = j = calloc(1, sizeof (*j))) == NULL)
return (PAPI_TEMPORARY_ERROR);
close(s->fd);
lpsched_request_to_job_attributes(s->request, j);
if (s->meta_data_file != NULL) {
status = lpsched_commit_job(svc, s->meta_data_file, &tmp);
if (status != PAPI_OK) {
unlink(s->meta_data_file);
return (status);
}
if ((c = strrchr(tmp, '-')) != NULL)
c++;
papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
"job-id", atoi(c));
papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
"job-uri", tmp);
free(s->meta_data_file);
}
freerequest(s->request);
free(s);
return (PAPI_OK);
}
papi_status_t
papiJobQuery(papi_service_t handle, char *printer, int32_t job_id,
char **requested_attrs,
papi_job_t *job)
{
service_t *svc = handle;
job_t *j;
char *dest;
char req_id[32];
short rc;
char *form = NULL,
*request_id = NULL,
*charset = NULL,
*user = NULL,
*slabel = NULL,
*file = NULL;
time_t date = 0;
size_t size = 0;
short rank = 0,
state = 0;
if ((handle == NULL) || (printer == NULL) || (job_id < 0))
return (PAPI_BAD_ARGUMENT);
dest = printer_name_from_uri_id(printer, job_id);
snprintf(req_id, sizeof (req_id), "%s-%d", dest, job_id);
free(dest);
rc = snd_msg(svc, S_INQUIRE_REQUEST_RANK, 0, "", "", req_id, "", "");
if (rc < 0)
return (PAPI_SERVICE_UNAVAILABLE);
if (rcv_msg(svc, R_INQUIRE_REQUEST_RANK, &rc, &request_id,
&user, &slabel, &size, &date, &state, &dest, &form,
&charset, &rank, &file) < 0) {
detailed_error(svc,
gettext("failed to read response from scheduler"));
return (PAPI_DEVICE_ERROR);
}
if ((request_id == NULL) || (request_id[0] == NULL))
return (PAPI_NOT_FOUND);
if ((*job = j = calloc(1, sizeof (*j))) == NULL)
return (PAPI_TEMPORARY_ERROR);
job_status_to_attributes(j, request_id, user, slabel, size, date, state,
dest, form, charset, rank, file);
snprintf(req_id, sizeof (req_id), "%d-0", job_id);
lpsched_read_job_configuration(svc, j, req_id);
return (PAPI_OK);
}
papi_status_t
papiJobMove(papi_service_t handle, char *printer, int32_t job_id,
char *destination)
{
papi_status_t result = PAPI_OK;
long bits;
service_t *svc = handle;
char req_id[64];
char *queue;
char *user = NULL;
if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
(destination == NULL))
return (PAPI_BAD_ARGUMENT);
queue = printer_name_from_uri_id(printer, job_id);
snprintf(req_id, sizeof (req_id), "%s-%d", queue, job_id);
free(queue);
if (papiAttributeListGetString(svc->attributes, NULL, "user-name",
&user) == PAPI_OK) {
REQUEST *r = getrequest(req_id);
if ((r != NULL) && (r->user != NULL) &&
(strcmp(r->user, user) != 0))
result = PAPI_NOT_AUTHORIZED;
freerequest(r);
}
if (result == PAPI_OK) {
short status = MOK;
char *dest = printer_name_from_uri_id(destination, -1);
if ((snd_msg(svc, S_MOVE_REQUEST, req_id, dest) < 0) ||
(rcv_msg(svc, R_MOVE_REQUEST, &status, &bits) < 0))
status = MTRANSMITERR;
free(dest);
result = lpsched_status_to_papi_status(status);
}
return (result);
}
papi_status_t
papiJobCancel(papi_service_t handle, char *printer, int32_t job_id)
{
papi_status_t result = PAPI_OK;
service_t *svc = handle;
char req_id[64];
char *dest;
char *user = NULL;
if ((svc == NULL) || (printer == NULL) || (job_id < 0))
return (PAPI_BAD_ARGUMENT);
dest = printer_name_from_uri_id(printer, job_id);
snprintf(req_id, sizeof (req_id), "%s-%d", dest, job_id);
free(dest);
if (papiAttributeListGetString(svc->attributes, NULL, "user-name",
&user) == PAPI_OK) {
REQUEST *r = getrequest(req_id);
if ((r != NULL) && (r->user != NULL) &&
(strcmp(r->user, user) != 0))
result = PAPI_NOT_AUTHORIZED;
freerequest(r);
}
if (result == PAPI_OK) {
short status = MOK;
if ((snd_msg(svc, S_CANCEL_REQUEST, req_id) < 0) ||
(rcv_msg(svc, R_CANCEL_REQUEST, &status) < 0))
status = MTRANSMITERR;
result = lpsched_status_to_papi_status(status);
}
return (result);
}
papi_status_t
hold_release_job(papi_service_t handle, char *printer,
int32_t job_id, int flag)
{
papi_status_t status;
service_t *svc = handle;
REQUEST *r = NULL;
char *file;
char *dest;
if ((svc == NULL) || (printer == NULL) || (job_id < 0))
return (PAPI_BAD_ARGUMENT);
if ((status = authorized(svc, job_id)) != PAPI_OK)
return (status);
dest = printer_name_from_uri_id(printer, job_id);
status = lpsched_start_change(svc, dest, job_id, &file);
if (status != PAPI_OK)
return (status);
if ((r = getrequest(file)) != NULL) {
r->actions &= ~ACT_RESUME;
switch (flag) {
case 0:
r->actions |= ACT_HOLD;
break;
case 1:
r->actions |= ACT_RESUME;
break;
case 2:
r->actions |= ACT_IMMEDIATE;
break;
}
if (putrequest(file, r) < 0) {
detailed_error(svc,
gettext("failed to write job: %s: %s"),
file, strerror(errno));
freerequest(r);
return (PAPI_DEVICE_ERROR);
}
freerequest(r);
} else {
detailed_error(svc, gettext("failed to read job: %s: %s"),
file, strerror(errno));
return (PAPI_DEVICE_ERROR);
}
status = lpsched_end_change(svc, dest, job_id);
return (status);
}
papi_status_t
papiJobHold(papi_service_t handle, char *printer, int32_t job_id)
{
return (hold_release_job(handle, printer, job_id, 0));
}
papi_status_t
papiJobRelease(papi_service_t handle, char *printer, int32_t job_id)
{
return (hold_release_job(handle, printer, job_id, 1));
}
papi_status_t
papiJobPromote(papi_service_t handle, char *printer, int32_t job_id)
{
return (hold_release_job(handle, printer, job_id, 2));
}
papi_status_t
papiJobModify(papi_service_t handle, char *printer, int32_t job_id,
papi_attribute_t **attributes, papi_job_t *job)
{
papi_status_t status;
job_t *j = NULL;
service_t *svc = handle;
char *file = NULL;
char *dest;
REQUEST *r = NULL;
char lpfile[BUFSIZ];
if ((svc == NULL) || (printer == NULL) || (job_id < 0) ||
(attributes == NULL))
return (PAPI_BAD_ARGUMENT);
if ((*job = j = calloc(1, sizeof (*j))) == NULL)
return (PAPI_TEMPORARY_ERROR);
dest = printer_name_from_uri_id(printer, job_id);
status = lpsched_start_change(svc, dest, job_id, &file);
if (status != PAPI_OK)
return (status);
if ((r = getrequest(file)) != NULL) {
job_attributes_to_lpsched_request(handle, r,
(papi_attribute_t **)attributes);
#ifdef LP_USE_PAPI_ATTR
/*
* store the job attributes in the PAPI job attribute file
* that was created by the origonal job request. We need to
* modify the attributes in the file as per the new attributes
*/
snprintf(lpfile, sizeof (lpfile), "%s%d-%s",
"/var/spool/lp/temp/", job_id, LP_PAPIATTRNAME);
status = psm_modifyAttrsFile(attributes, lpfile);
if (status != PAPI_OK) {
detailed_error(svc,
"unable to modify the attributes file: %s: %s",
lpfile, strerror(errno));
return (PAPI_DEVICE_ERROR);
}
#endif
if (putrequest(file, r) < 0) {
detailed_error(svc,
gettext("failed to write job: %s: %s"),
file, strerror(errno));
freerequest(r);
return (PAPI_DEVICE_ERROR);
}
} else {
detailed_error(svc, gettext("failed to read job: %s: %s"),
file, strerror(errno));
return (PAPI_DEVICE_ERROR);
}
status = lpsched_end_change(svc, dest, job_id);
lpsched_request_to_job_attributes(r, j);
papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
"job-id", job_id);
freerequest(r);
return (status);
}
/*
* Extension to PAPI, a variation of this is slated for post-1.0
*/
#define DUMMY_FILE "/var/spool/lp/fifos/FIFO"
papi_status_t
papiJobCreate(papi_service_t handle, char *printer,
papi_attribute_t **job_attributes,
papi_job_ticket_t *job_ticket, papi_job_t *job)
{
papi_status_t status;
service_t *svc = handle;
job_t *j = NULL;
REQUEST *request;
char *request_id = NULL;
char *c;
char *tmp = NULL;
char metadata_file[MAXPATHLEN];
if ((svc == NULL) || (printer == NULL) || (job == NULL))
return (PAPI_BAD_ARGUMENT);
if (job_ticket != NULL)
return (PAPI_JOB_TICKET_NOT_SUPPORTED);
if ((*job = j = calloc(1, sizeof (*j))) == NULL)
return (PAPI_TEMPORARY_ERROR);
/* 1 for the control file (-0) */
status = lpsched_alloc_files(svc, 1, &request_id);
if (status != PAPI_OK)
return (status);
/* convert the attributes to an lpsched REQUEST structure */
request = create_request(svc, (char *)printer,
(papi_attribute_t **)job_attributes);
if (request == NULL)
return (PAPI_TEMPORARY_ERROR);
addlist(&request->file_list, DUMMY_FILE); /* add a dummy file */
request->actions |= ACT_HOLD; /* hold the job */
#ifdef LP_USE_PAPI_ATTR
/*
* store the job attributes in the PAPI job attribute file that was
* created by lpsched_alloc_files(), the attributes will then pass
* through lpsched and be given to the slow-filters and the printer's
* interface script to process them
*/
snprintf(metadata_file, sizeof (metadata_file), "%s%s-%s",
"/var/spool/lp/temp/", request_id, LP_PAPIATTRNAME);
status = psm_copy_attrsToFile(job_attributes, metadata_file);
if (status != PAPI_OK) {
detailed_error(svc, "unable to copy attributes to file: %s: %s",
metadata_file, strerror(errno));
free(request_id);
return (PAPI_DEVICE_ERROR);
}
#endif
/* store the REQUEST on disk */
snprintf(metadata_file, sizeof (metadata_file), "%s-0", request_id);
free(request_id);
if (putrequest(metadata_file, request) < 0) {
detailed_error(svc, gettext("unable to save request: %s: %s"),
metadata_file, strerror(errno));
return (PAPI_DEVICE_ERROR);
}
status = lpsched_commit_job(svc, metadata_file, &tmp);
if (status != PAPI_OK) {
unlink(metadata_file);
return (status);
}
lpsched_request_to_job_attributes(request, j);
if ((c = strrchr(tmp, '-')) != NULL)
c++;
papiAttributeListAddInteger(&j->attributes, PAPI_ATTR_REPLACE,
"job-id", atoi(c));
papiAttributeListAddString(&j->attributes, PAPI_ATTR_REPLACE,
"job-uri", tmp);
return (PAPI_OK);
}
papi_status_t
papiJobCommit(papi_service_t handle, char *printer, int32_t id)
{
papi_status_t status = PAPI_OK;
service_t *svc = handle;
REQUEST *r = NULL;
char *metadata_file;
char *dest;
if ((svc == NULL) || (printer == NULL))
return (PAPI_BAD_ARGUMENT);
dest = printer_name_from_uri_id(printer, id);
/* tell the scheduler that we want to change the job */
status = lpsched_start_change(svc, dest, id, &metadata_file);
if (status != PAPI_OK)
return (status);
if ((r = getrequest(metadata_file)) != NULL) {
r->actions &= ~ACT_RESUME;
r->actions |= ACT_RESUME;
dellist(&r->file_list, DUMMY_FILE);
if (putrequest(metadata_file, r) < 0) {
detailed_error(svc,
gettext("failed to write job: %s: %s"),
metadata_file, strerror(errno));
freerequest(r);
return (PAPI_DEVICE_ERROR);
}
} else {
detailed_error(svc, gettext("failed to read job: %s: %s"),
metadata_file, strerror(errno));
return (PAPI_DEVICE_ERROR);
}
status = lpsched_end_change(svc, dest, id);
freerequest(r);
return (status);
}
papi_status_t
papiJobStreamAdd(papi_service_t handle, char *printer, int32_t id,
papi_stream_t *stream)
{
papi_status_t status;
service_t *svc = handle;
job_stream_t *s = NULL;
char *metadata_file = NULL;
char *dest;
char path[MAXPATHLEN];
/* allocate space for the stream */
if ((*stream = s = calloc(1, sizeof (*s))) == NULL)
return (PAPI_TEMPORARY_ERROR);
dest = printer_name_from_uri_id(printer, id);
/* create/open data file (only root or lp can really do this */
snprintf(path, sizeof (path), "/var/spool/lp/temp/%d-XXXXXX", id);
if ((s->fd = mkstemp(path)) < 0) {
detailed_error(svc, gettext("unable to create sink (%s): %s"),
path, strerror(errno));
free(s);
return (PAPI_NOT_AUTHORIZED);
}
/* add data file to job */
status = lpsched_start_change(svc, dest, id, &metadata_file);
if (status != PAPI_OK) {
close(s->fd);
free(s);
unlink(path);
return (status);
}
if ((s->request = getrequest(metadata_file)) == NULL) {
detailed_error(svc, gettext("unable to load request: %s: %s"),
metadata_file, strerror(errno));
close(s->fd);
free(s);
unlink(path);
return (PAPI_NOT_POSSIBLE);
}
addlist(&(s->request->file_list), path);
if (putrequest(metadata_file, s->request) < 0) {
detailed_error(svc, gettext("unable to save request: %s: %s"),
metadata_file, strerror(errno));
close(s->fd);
free(s);
unlink(path);
return (PAPI_NOT_POSSIBLE);
}
status = lpsched_end_change(svc, dest, id);
if (status != PAPI_OK)
return (status);
return (PAPI_OK);
}