lpd-job.c revision 4bd2082ff2d009263265d7de938de336894b6009
/*
* 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 2007 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*
*/
/* $Id: lpd-job.c 157 2006-04-26 15:07:55Z ktou $ */
#pragma ident "%Z%%M% %I% %E% SMI"
#define __EXTENSIONS__ /* for strtok_r() */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <pwd.h>
#include <libintl.h>
#include <papi_impl.h>
enum { LPD_RFC, LPD_SVR4 };
static char
mime_type_to_rfc1179_type(char *mime)
{
static struct { char *mime; char rfc; } cvt[] = {
{ "text/plain", 'f' },
{ "application/octet-stream", 'l' },
{ "application/postscript", 'f' }, /* rfc incorrectly has 'o' */
{ "application/x-pr", 'p' },
{ "application/x-cif", 'c' },
{ "application/x-dvi", 'd' },
{ "application/x-fortran", 'r' },
{ "application/x-plot", 'g' },
{ "application/x-ditroff", 'n' },
{ "application/x-troff", 't' },
{ "application/x-raster", 'v' },
{ NULL, 0}
};
char result = '\0';
if (mime != NULL) {
int i;
for (i = 0; cvt[i].mime != NULL; i++)
if (strcasecmp(cvt[i].mime, mime) == 0) {
result = cvt[i].rfc;
break;
}
}
return (result);
}
static papi_status_t
add_lpd_control_line(char **metadata, char code, char *value)
{
size_t size = 0;
char line[BUFSIZ];
if ((metadata == NULL) || (value == NULL))
return (PAPI_BAD_REQUEST);
if (*metadata != NULL)
size = strlen(*metadata);
size += strlen(value) + 3;
if (*metadata == NULL) {
*metadata = (char *)calloc(1, size);
} else {
void *tmp;
tmp = realloc(*metadata, size);
if (tmp)
*metadata = (char *)tmp;
else
return (PAPI_TEMPORARY_ERROR);
}
snprintf(line, sizeof (line), "%c%s\n", code, value);
strlcat(*metadata, line, size);
return (PAPI_OK);
}
static papi_status_t
add_svr4_control_line(char **metadata, char code, char *value)
{
char line[BUFSIZ];
if ((metadata == NULL) || (value == NULL))
return (PAPI_BAD_REQUEST);
snprintf(line, sizeof (line), "%c%s", code, value);
return (add_lpd_control_line(metadata, '5', line));
}
static papi_status_t
add_hpux_control_line(char **metadata, char *value)
{
char line[BUFSIZ];
if ((metadata == NULL) || (value == NULL))
return (PAPI_BAD_REQUEST);
snprintf(line, sizeof (line), " O%s", value);
return (add_lpd_control_line(metadata, 'N', line));
}
static papi_status_t
add_int_control_line(char **metadata, char code, int value, int flag)
{
char buf[16];
snprintf(buf, sizeof (buf), "%d", value);
if (flag == LPD_SVR4)
return (add_svr4_control_line(metadata, code, buf));
else
return (add_lpd_control_line(metadata, code, buf));
}
static papi_status_t
lpd_add_rfc1179_attributes(service_t *svc, papi_attribute_t **attributes,
char **metadata, papi_attribute_t ***used)
{
papi_status_t status = PAPI_OK;
char *s;
int integer;
char bool;
char host[BUFSIZ];
char *user = "nobody";
uid_t uid = getuid();
struct passwd *pw;
if (svc == NULL)
return (PAPI_BAD_REQUEST);
/* There is nothing to do */
if (attributes == NULL)
return (PAPI_OK);
gethostname(host, sizeof (host));
add_lpd_control_line(metadata, 'H', host);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"job-originating-host-name", host);
if ((pw = getpwuid(uid)) != NULL)
user = pw->pw_name;
if (uid == 0)
papiAttributeListGetString(svc->attributes, NULL, "username",
&user);
add_lpd_control_line(metadata, 'P', user);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"job-originating-user-name", user);
/* Class for Banner Page */
s = NULL;
papiAttributeListGetString(attributes, NULL, "rfc-1179-class", &s);
if (s != NULL) {
add_lpd_control_line(metadata, 'C', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"rfc-1179-class", s);
}
/* Print Banner Page */
s = NULL;
papiAttributeListGetString(attributes, NULL, "job-sheets", &s);
if ((s != NULL) && (strcmp(s, "standard") == 0)) {
add_lpd_control_line(metadata, 'L', user);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"job-sheets", s);
}
/* Jobname */
s = NULL;
papiAttributeListGetString(attributes, NULL, "job-name", &s);
if (s != NULL) {
add_lpd_control_line(metadata, 'J', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"job-name", s);
}
/* User to mail when job is done - lpr -m */
bool = PAPI_FALSE;
papiAttributeListGetBoolean(attributes, NULL, "rfc-1179-mail", &bool);
if (bool == PAPI_TRUE) {
add_lpd_control_line(metadata, 'M', user);
papiAttributeListAddBoolean(used, PAPI_ATTR_EXCL,
"rfc-1179-mail", bool);
}
/* Title for pr */
s = NULL;
papiAttributeListGetString(attributes, NULL, "pr-title", &s);
if (s != NULL) {
add_lpd_control_line(metadata, 'T', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"pr-title", s);
}
/* Indent - used with pr filter */
integer = 0;
papiAttributeListGetInteger(attributes, NULL, "pr-indent", &integer);
if (integer >= 1) {
add_int_control_line(metadata, 'I', integer, LPD_RFC);
papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
"pr-indent", integer);
}
/* Width - used with pr filter */
integer = 0;
papiAttributeListGetInteger(attributes, NULL, "pr-width", &integer);
if (integer >= 1) {
add_int_control_line(metadata, 'W', integer, LPD_RFC);
papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
"pr-width", integer);
}
/* file with Times Roman font lpr -1 */
s = NULL;
papiAttributeListGetString(attributes, NULL, "rfc-1179-font-r", &s);
if (s != NULL) {
add_lpd_control_line(metadata, '1', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"rfc-1179-font-r", s);
}
/* file with Times Roman font lpr -2 */
s = NULL;
papiAttributeListGetString(attributes, NULL, "rfc-1179-font-i", &s);
if (s != NULL) {
add_lpd_control_line(metadata, '2', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"rfc-1179-font-i", s);
}
/* file with Times Roman font lpr -3 */
s = NULL;
papiAttributeListGetString(attributes, NULL, "rfc-1179-font-b", &s);
if (s != NULL) {
add_lpd_control_line(metadata, '3', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"rfc-1179-font-b", s);
}
/* file with Times Roman font lpr -4 */
s = NULL;
papiAttributeListGetString(attributes, NULL, "rfc-1179-font-s", &s);
if (s != NULL) {
add_lpd_control_line(metadata, '4', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"rfc-1179-font-s", s);
}
return (status);
}
/*
* lpd_add_svr4_attributes
* Solaris 2.x LP - BSD protocol extensions
*/
static papi_status_t
lpd_add_svr4_attributes(service_t *svc, papi_attribute_t **attributes,
char **metadata, papi_attribute_t ***used)
{
char *s;
int integer;
if (svc == NULL)
return (PAPI_BAD_REQUEST);
/* media */
s = NULL;
papiAttributeListGetString(attributes, NULL, "media", &s);
if (s != NULL) {
add_svr4_control_line(metadata, 'f', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"media", s);
}
/* Handling */
s = NULL;
papiAttributeListGetString(attributes, NULL, "job_hold_until", &s);
if ((s != NULL) && (strcmp(s, "indefinite"))) {
add_svr4_control_line(metadata, 'H', "hold");
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"media", "hold");
} else if ((s != NULL) && (strcmp(s, "no-hold"))) {
add_svr4_control_line(metadata, 'H', "release");
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"media", "release");
} else if ((s != NULL) && (strcmp(s, "immediate"))) {
add_int_control_line(metadata, 'q', 0, LPD_SVR4);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"media", "immediate");
}
/* Pages */
s = NULL;
papiAttributeListGetString(attributes, NULL, "page-ranges", &s);
if (s != NULL) {
add_svr4_control_line(metadata, 'P', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"page-ranges", s);
}
/* Priority : lp -q */
integer = -1;
papiAttributeListGetInteger(attributes, NULL, "priority", &integer);
if (integer != -1) {
add_int_control_line(metadata, 'q', integer, LPD_SVR4);
papiAttributeListAddInteger(used, PAPI_ATTR_EXCL,
"priority", integer);
}
/* Charset : lp -S */
s = NULL;
papiAttributeListGetString(attributes, NULL, "lp-charset", &s);
if (s != NULL) {
add_svr4_control_line(metadata, 'S', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"lp-charset", s);
}
/* Type : done when adding file */
/* Mode : lp -y */
s = NULL;
papiAttributeListGetString(attributes, NULL, "lp-modes", &s);
if (s != NULL) {
add_svr4_control_line(metadata, 'y', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"lp-modes", s);
}
/* Options lp -o */
s = NULL;
papiAttributeListGetString(attributes, NULL, "lp-options", &s);
if (s != NULL) {
add_svr4_control_line(metadata, 'o', s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"lp-options", s);
}
return (PAPI_OK);
}
papi_status_t
lpd_add_hpux_attributes(service_t *svc, papi_attribute_t **attributes,
char **metadata, papi_attribute_t ***used)
{
char *s = NULL;
/* Options lp -o */
s = NULL;
papiAttributeListGetString(attributes, NULL, "lp-options", &s);
if (s != NULL) {
add_hpux_control_line(metadata, s);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"lp-options", s);
}
return (PAPI_OK);
}
papi_status_t
lpd_job_add_attributes(service_t *svc, papi_attribute_t **attributes,
char **metadata, papi_attribute_t ***used)
{
if ((svc == NULL) || (metadata == NULL))
return (PAPI_BAD_REQUEST);
lpd_add_rfc1179_attributes(svc, attributes, metadata, used);
if (svc->uri->fragment != NULL) {
if ((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
(strcasecmp(svc->uri->fragment, "svr4") == 0))
lpd_add_svr4_attributes(svc, attributes, metadata,
used);
else if (strcasecmp(svc->uri->fragment, "hpux") == 0)
lpd_add_hpux_attributes(svc, attributes, metadata,
used);
/*
* others could be added here:
* lprng, sco, aix, digital unix, xerox, ...
*/
}
return (PAPI_OK);
}
papi_status_t
lpd_job_add_files(service_t *svc, papi_attribute_t **attributes,
char **files, char **metadata, papi_attribute_t ***used)
{
char *format = "text/plain";
char rfc_fmt = 'l';
int copies = 1;
char host[BUFSIZ];
int i;
if ((svc == NULL) || (attributes == NULL) || (files == NULL) ||
(metadata == NULL))
return (PAPI_BAD_ARGUMENT);
papiAttributeListGetString(attributes, NULL, "document-format",
&format);
papiAttributeListAddString(used, PAPI_ATTR_EXCL,
"document-format", format);
if ((rfc_fmt = mime_type_to_rfc1179_type(format)) == '\0') {
if ((svc->uri->fragment != NULL) &&
((strcasecmp(svc->uri->fragment, "solaris") == 0) ||
(strcasecmp(svc->uri->fragment, "svr4") == 0)))
add_svr4_control_line(metadata, 'T', format);
rfc_fmt = 'l';
}
papiAttributeListGetInteger(attributes, NULL, "copies", &copies);
if (copies < 1)
copies = 1;
papiAttributeListAddInteger(used, PAPI_ATTR_EXCL, "copies", copies);
gethostname(host, sizeof (host));
for (i = 0; files[i] != NULL; i++) {
char name[BUFSIZ];
char key;
int j;
if ((strcmp("standard input", files[i]) != 0) &&
(access(files[i], R_OK) < 0)) {
detailed_error(svc, gettext("aborting request, %s: %s"),
files[i], strerror(errno));
return (PAPI_NOT_AUTHORIZED);
}
if (i < 26)
key = 'A' + i;
else if (i < 52)
key = 'a' + (i - 26);
else if (i < 62)
key = '0' + (i - 52);
else {
detailed_error(svc,
gettext("too many files, truncated at 62"));
return (PAPI_OK_SUBST);
}
snprintf(name, sizeof (name), "df%cXXX%s", key, host);
for (j = 0; j < copies; j++)
add_lpd_control_line(metadata, rfc_fmt, name);
add_lpd_control_line(metadata, 'U', name);
add_lpd_control_line(metadata, 'N', (char *)files[i]);
}
return (PAPI_OK);
}
papi_status_t
lpd_submit_job(service_t *svc, char *metadata, papi_attribute_t ***attributes,
int *ofd)
{
papi_status_t status = PAPI_INTERNAL_ERROR;
int fd;
char path[32];
char *list[2];
if ((svc == NULL) || (metadata == NULL))
return (PAPI_BAD_ARGUMENT);
strcpy(path, "/tmp/lpd-job-XXXXXX");
fd = mkstemp(path);
write(fd, metadata, strlen(metadata));
close(fd);
list[0] = path;
list[1] = NULL;
if (((fd = lpd_open(svc, 's', list, 15)) < 0) && (errno != EBADMSG)) {
switch (errno) {
case ENOSPC:
status = PAPI_TEMPORARY_ERROR;
break;
case EIO:
status = PAPI_TEMPORARY_ERROR;
break;
case ECONNREFUSED:
status = PAPI_SERVICE_UNAVAILABLE;
break;
case ENOENT:
status = PAPI_NOT_ACCEPTING;
break;
case EBADMSG:
case EBADF:
status = PAPI_OK;
break;
default:
status = PAPI_TIMEOUT;
break;
}
} else
status = PAPI_OK;
if (ofd != NULL)
*ofd = fd;
else
close(fd);
/* read the ID and add it to to the job */
if ((fd = open(path, O_RDONLY)) >= 0) {
int job_id = 0;
read(fd, &job_id, sizeof (job_id));
papiAttributeListAddInteger(attributes, PAPI_ATTR_REPLACE,
"job-id", job_id);
close(fd);
}
unlink(path);
return (status);
}