job.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (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
* 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 2005 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*LINTLIBRARY*/
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <dirent.h>
#include <sys/systeminfo.h>
#include <syslog.h>
#include <errno.h>
#include <libintl.h>
#include <grp.h>
/*
* These specify important strings in the job routines
*/
static char *_sequence_file = SEQUENCE_FILE;
static char *_data_file_prefix = DATA_FILE_PREFIX;
static char *_control_file_prefix = CONTROL_FILE_PREFIX;
static char *_xfer_file_prefix = XFER_FILE_PREFIX;
static char *_temp_file_prefix = TEMP_FILE_PREFIX;
/*
* _job_alloc_id() allocates the next request id number from the number space.
* It does this by looking for it in a sequence number file in the
* spooling directory, reading the value, incrementing the file value, and
* returning the previous file value. If the value falls beyond the number
* space, the new value will be the begining of the space. If the sequence
* file doesn't exist, the value will be the start of the number space, and
* a file will be created. If there is some other error opening or reading
* the sequence file, a -1 will be returned.
*/
static int
{
int fd,
id,
rc;
>= sizeof (buf)) {
return (-1);
}
if (fd < 0) {
return (-1);
}
return (-1);
}
return (-1);
}
return (rc);
}
/*
* _job_alloc_file() finds an unused path name in the format:
* spool_dir/(prefix)(x)(id)hostname, where x is in [A-Za-z]. If all
* such paths are in use, the routine returns NULL. If it finds an open
* name, a newly allocated string is returned containing the path.
*/
static char *
char *host)
{
char hostname[128],
*path;
int key_position = 0;
}
if (*key < 'A')
*key = 'A';
*key = 'a';
else if (*key > 'z')
return (NULL);
"%s/%s%c%.3d%s",
return (NULL);
}
return (NULL);
}
}
/*
* _job_unlink_data_file() will unlink the path for the jobfile passed in.
* this is only to be used with job_destroy() so it can iterate through
* the job_df_list.
*/
static int
{
else
return (-1);
}
/*
* job_create() creates, initializes and returns a new job structure. Part of
* the initialization includes generating a job id, and filling in the
* printer and server information.
*/
job_t *
{
int id;
return (NULL);
return (NULL);
}
return (tmp);
}
/*
* job_primative() appends an rfc1179(BSD printing) control message into the
* job structure's control data. If the message would extend beyond the
* memory currently allocated for control data, a new buffer is
* realloc()'d and the message is appended to the new buffer.
*/
int
{
char key = 'A';
return (-1);
return (-1);
}
}
} else
return (-1);
}
>= sizeof (buf)) {
return (-1);
}
value);
return (0);
}
/*
* job_svr4_primative() builds new arguments to call job_primative() with.
* it is strictly for use with the rfc1179 like options that were added
* to the protocol to support SVR4 printing features not supported in the
* protocol.
*/
int
{
return (-1);
>= sizeof (buf)) {
return (-1);
}
}
/*
* job_add_data_file() adds a data file into a job structure. It does this
* by allocating a new temporary spooling file, adding control messages
* to the control data so the job prints and files unlink on the server.
* It copies the path passed in to the temporary file, it also adds
* the temporary file name to the job_df_list.
*/
int
{
*dfName;
return (-1);
int result = -1;
}
if (result != 0)
return (result);
}
return (-1);
return (-1);
}
return (-1);
}
return (-1);
}
job->job_df_next--;
return (-1);
}
if (linked == 0) {
} else
job->job_df_next--;
return (-1);
}
if (path[0] != '/') {
int rc = 0;
/*
*/
if (rc != 0) {
"to initgroups() (errno: %d)", errno);
}
if (rc != 0) {
"to seteuid() to uid (errno: %d)", errno);
}
if (rc != 0) {
"to setegid() to gid (errno: %d)", errno);
}
if (rc != 0) {
"to reset euid (errno: %d)", errno);
}
if (rc != 0) {
"to reset groups (errno: %d)", errno);
}
}
return (-1);
}
(void *)file);
if (type == CF_PRINT_PR)
while (copies--)
if (delete != 0)
}
/*
*
*/
static void
{
return;
if (file->jf_mmapped)
else
}
}
/*
*
*/
static void
{
}
/*
* job_free() frees up memory mmapped for malloced
* being used by the structure.
*/
void
{
return;
if (job->job_df_list)
if (job->job_spool_dir)
}
void
{
return;
return;
/* lose privilege temporarily */
if (name[0] == '\n')
name++;
*p;
continue;
}
continue;
}
*++p = NULL;
}
}
}
(void) seteuid(0); /* get back privilege */
(void) _job_unlink_data_file(cf);
}
/*
* _vjob_store_df() moves a data file from memory to disk. Called by
* list_iterate().
*/
static int
{
return (0);
else
}
/*
* job_create_binding_file() finds and opens a temporary binding file locking
* the file then renaming it to the real name returning the open fd.
*/
static int
{
int fd;
char *tmp,
*src,
*dst;
char key = 'A';
int msize;
/* get a temp file name */
return (-1);
key = 'A';
/* get a binding file name */
return (-1);
return (-1);
}
return (-1);
}
/*
* open the tmp file, lock it, and rename it so are guaranteed to
* have it.
*/
fd = -1;
}
return (fd);
}
/*
* job_store() makes a disk copy of a job structure.
*/
int
{
int lock;
/* create the control_file */
return (-1);
}
return (-1);
}
/*
* create and lock the binding file, so nobody has access to the job
* while it is being created.
*/
return (-1);
/* add the binding information */
return (-1);
}
return (-1);
/* store the data files */
return (0);
}
/*
* job_retreive() 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 *
{
char *p, *cfp;
/* get printer & server */
char *s;
} else {
if (fd >= 0)
if (lck == 0)
return (NULL);
}
/*
* If file is corrupted, then job_server & job_printer
* can be NULL. In that case return NULL
*/
return (NULL);
/* get job id, from binding file name */
sizeof (buf));
/*
* add control file and binding file names. the will should
* always only differ by the prefix.
*/
return (NULL);
sizeof (buf));
/* map in the control data */
<= 0) {
"could not read control (%s): %m, canceling %d destined for %s@%s",
return (NULL);
}
/* 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.
*/
n_cnt = 0;
switch (*(++p)) {
case CF_USER:
break;
case CF_HOST:
break;
case CF_UNLINK:
== NULL) {
"cf_unlink: calloc() failed");
return (NULL);
}
/*
* Beginning of file. Check for first
* character == 'N'
*/
cfp++;
n_cnt++;
} else {
cfp += 2;
n_cnt++;
}
}
/*
* Move cfp to end of line or
* set to NULL if end of file.
*/
}
}
list_append((void **)
(void *)file);
break;
}
}
"Invalid control file (%s). Missing 'U' entry. "
"Canceling %d destined for %s@%s",
return (NULL);
} else {
}
}
return (tmp);
}
/*
* job_compar() compare 2 jobs for creation time ordering
*/
static int
{
int server;
int printer;
s2;
/*
* If there is a null value, assume the job submitted remotely.
* Jobs submitted remotely take precedence over those submitted
* from the server.
*/
return (-1);
return (1);
if (server != 0)
return (server);
if (printer != 0)
return (printer);
return (0);
}
/*
* job_list_append() reads all of the jobs associated with the printer passed
* in and appends them to the list of jobs passed in. The returned result
* is a new list of jobs containing all jobs passed in and jobs for the
* printer specified. If the printer is NULL, all jobs for all printers
* are added to the list.
*/
job_t **
{
struct dirent *d;
int i, found = 0;
/*
* 4239765 - in.lpd segfaults performing strcmp()
* in job_list_append()
*/
server = "";
}
return (NULL);
/* should use scandir */
strlen(_xfer_file_prefix)) != 0)
continue;
continue;
found = 0;
if (list) {
found = 1;
}
} /* if (list) */
if (!found)
(void *)job);
}
} /* while */
/* count the length of the list for qsort() */
if (list) {
;
(int(*)(const void *, const void *))job_compar);
}
return (list);
}
/*
*
* Shared routines for Canceling jobs.
*
*/
/*
* vjob_match_attribute() checks to see if the attribute passed in
* matches the the user or id of the job passed in via stdargs. This is
* intended for use with list_iterate().
*/
int
{
return (1);
else
return (0);
}
/*
* vjob_job() determines if the job passed in is for the printer and server
* of the cancel request, and if it is from the user requesting or the
* user is root, it checsk the attributes. If the job matches all of this
* it cancels the job and prints a message. It is intented to be called
* by list_iterate().
*/
int
{
int killed_process = 0;
int lock;
server);
if (list_iterate((void **)list,
0)) < 0) {
killed_process = 1;
}
(void) printf(
}
}
return (killed_process);
}