cups 打印服务器:如何保留本地和远程作业直到释放?

cups 打印服务器:如何保留本地和远程作业直到释放?

我想告诉我的 cups 打印服务器保留所有打印作业,直到它们被手动释放。

使用cupsdisable --hold <printer or class>会暂停打印机,并且lpoptions -p <printer> -o hold-job-until=indefinite适用于本地提交的打印作业,但不适用于远程发送的作业。如何配置杯子以保留所有作业,直到手动释放它们为止?

答案1

我没有找到杯子的配置选项,该选项确实将每个传入的打印作业设置为暂停。我编写了一个 bash 脚本来完成这项工作:

#!/bin/bash

# cups_hold_new_jobs [<printer>]

# Resume a cups printer, set all queued and newly incoming jobs on
# hold, pause printer and exit.

# Runs as long as there are jobs in the print queue. Start from cron.

DEBUG=false


# --------- do not edit below ---------
VERSION=0.3
VERSION_INFO="(c) 2024 by Adrian Zaugg under GNU General Public License Version 3."

# initiate job list
declare -a JOBS

# set defaults
LOCK="/run/$(basename "$0")"
LOCKED=false
OWNPIDPPID="$$  $PPID   "


# get job list
function get_job_list() {
    JOBS=($(lpstat -o "$PRINTER" | sed -e 's/^\('"$PRINTER"'-[0-9]\+\).*$/\1/g'))
}


# DEBUG variable must be set to true or false
if [[ "$DEBUG" != "true" && "$DEBUG" != "false" ]]; then
    DEBUG=false
fi

# cups must be running
if [ $(lpstat -r | grep -c "is running") -eq 0 ]; then
    $DEBUG && echo "[INFO] CUPS is not running. Nothing to do." >&2
    exit 0
fi

# get printer (or class?)
PRINTER="$1"

# get default printer if none was given as an argument or check given printer name
if [ -z "$PRINTER" ]; then
    PRINTER="$(lpstat -p -d 2>/dev/null | grep "^system default destination: " | sed -e 's/^system default destination: //')"
    # check
    if [ -z "$PRINTER" ]; then
        echo "[ERROR] No printer given on command line and unable to detect default printer." >&2
        exit 1
    else
        $DEBUG && echo "No printer given on command line, using default printer: $PRINTER" >&2
    fi
else
    # no space, hash, slash or newline in printer names allowed
    PRINTER="$(echo "$PRINTER" | head -1 | sed -e "s%/.*$%%" -e "s/#.*$//" -e "s/ .*$//")"
    if [ ${#PRINTER} -lt ${#1} ]; then
        echo "[ERROR] Disallowed characters in printer name found."
        exit 1
    fi

    # check given printer exists
    ERR="$(lpstat -p "$PRINTER" 2>&1)"
    if [ $? -ne 0 ]; then
        # printer does not exist or other error
        echo "[ERROR] No printer printer \"$PRINTER\" found." >&2
        exit 1
    else
        $DEBUG && echo "Using printer: $PRINTER" >&2
    fi
fi

# lock
while ! $LOCKED; do
    mkdir "$LOCK" 2>/dev/null
    if [ $? -eq 0 ]; then
        LOCKED=true
        break;
    elif [ $(ps -e -o pid,ppid,command | sed -n "s/\([0-9]\{1,\}\)[^0-9]\{1,\}\([0-9]\{1,\}\)[^0-9]\(.*\)$/\1\t\2\t\3/p" | \
             grep -v "$OWNPIDPPID" | grep -cE 'bash .*/'"$(basename "${0}")"'$') -gt 1 ]; then
        # process already started
        $DEBUG && echo "Another instance of this script is already running." >&2
        exit 0
    else
        # stale lock, remove it
        rmdir "$LOCK" 2>/dev/null
        if [ $? -ne 0 ]; then
            echo "[ERROR] Removing stale lock $LOCK failed." >&2
            exit 1
        else
            $DEBUG && echo "Removed stale lock." >&2
        fi
    fi
done

# pause printer
if [ $(lpstat -p "$PRINTER" | grep -c -m 1 "$PRINTER disabled") -eq 0 ]; then
    cupsdisable "$PRINTER"
    $DEBUG && echo "Printer paused." >&2
fi
PRINTER_PAUSED=true

# loop as long as there are jobs in the queue
get_job_list
until [ ${#JOBS[@]} -eq 0 ]; do

    # find index of last held job in new job list
    last_held_job_index=0
    unset job_id
    while [[ "${JOBS[$last_held_job_index]}" != "$last_held_job_id" && $last_held_job_index -le ${#JOBS[@]} ]]; do
        last_held_job_index=$(($last_held_job_index+1))
    done
    if [ $last_held_job_index -eq ${#JOBS[@]} ]; then
        # job not found
        last_held_job_index=-1
    fi

    # set newly queued jobs on hold
    i=0
    for job_id in ${JOBS[@]}; do
        # compare index to marker of last held index
        if [ $i -gt $last_held_job_index ]; then
            # set job on hold
            ERR="$(lp -i "$job_id" -H hold 2>&1)"
            if [ $? -eq 0 ]; then
                echo -e "[INFO] holding job $job_id" >&2
            else
                echo "[ERROR] Failed to hold job \"$job_id\": $ERR" >&2
            fi
            # remember last index
            last_held_job_index=$i
        fi
        i=$(($i+1))
    done
    last_held_job_id="${JOBS[$last_held_job_index]}"

    # wait a bit
    sleep 1

    # reread jobs in print queue
    get_job_list

    # enable printer now
    if $PRINTER_PAUSED; then
        cupsenable "$PRINTER"
        PRINTER_PAUSED=false
    fi
done

# queue is now empty disable printer
if $PRINTER_PAUSED; then
    $DEBUG && echo "Queue is empty." >&2
else
    cupsdisable "$PRINTER"
    echo "[INFO] Queue is empty now, pausing printer $PRINTER." >&2
fi

# unlock
if $LOCKED; then rmdir "$LOCK"; fi

exit 0

该脚本在启动时暂停打印机,将所有现有作业设置为暂停,对新传入的作业执行相同的操作,取消暂停打印机并等待队列变空。退出后,它会再次暂停打印机。

这个想法是,打印作业可以由其所有者手动释放或取消(或通过杯子设置 MaxHoldTime 自动取消)。这是简单拉式打印系统的一部分。

这是脚本的第一个版本,它在竞争条件下受到影响,必须由 cron 调用,缺少帮助文本,未针对类、asf 进行测试。如果我添加功能或修复,我会发布下载链接在这个答案中。使用它由您自己负责。不要在生产中使用,它在这里给出一个如何完成的想法。

很高兴听到有一种更简单的方法来告诉 cups 暂停所有传入的作业无需大量额外软件即可构建跟随我的打印系统。


下载:复制上述内容失败,因为选项卡可能会丢失,请使用下载链接:https://ente.limmat.ch/ftp/pub/software/bash/cups/

相关内容