Skip to content

Add setup script and README for Brother HL-L1222-V Android IPP print server on Raspberry Pi (openSUSE)#28

Open
ib-bsb-br wants to merge 1 commit into
mainfrom
codex/create-tutorial-for-brother-hl-l1222-v-setup-on-raspberry-pi-xgqrzh
Open

Add setup script and README for Brother HL-L1222-V Android IPP print server on Raspberry Pi (openSUSE)#28
ib-bsb-br wants to merge 1 commit into
mainfrom
codex/create-tutorial-for-brother-hl-l1222-v-setup-on-raspberry-pi-xgqrzh

Conversation

@ib-bsb-br

@ib-bsb-br ib-bsb-br commented Apr 29, 2026

Copy link
Copy Markdown
Owner

Motivation

  • Provide an automated, repeatable setup to configure a Raspberry Pi 4B+ running openSUSE Tumbleweed as a CUPS-backed print server for a USB-connected Brother HL-L1222/HL-L1222-V.
  • Enable Android devices on the same Wi-Fi to print via IPP/Mopria and configure discovery and firewall for LAN printing.
  • Document the recommended Wi-Fi IPP workflow and caveat Bluetooth printing limitations for modern Android/CUPS stacks.

Description

  • Add an executable setup script scripts/setup_hl_l1222_android_print.sh that installs required packages with zypper, enables services via systemctl, and configures CUPS, Avahi, Firewalld, and Bluetooth.
  • Script edits /etc/cups/cupsd.conf to enable network listening, sharing, and web interface, opens firewall rules for ipp and mdns via firewall-cmd, and attempts to auto-detect the Brother USB URI using lpinfo.
  • The script creates or replaces the CUPS queue with lpadmin using the everywhere model, sets default options (one-sided, A4), enables sharing, restarts CUPS, and issues a test print and lpstat -t status.
  • Update README.md with usage instructions, the recommended IPP ipp://<raspberrypi-ip>/printers/Brother_HL_L1222_V workflow, and notes about Bluetooth and driver options.

Testing

  • No automated tests were run for this change.

Codex Task

Summary by Sourcery

Add a setup script and documentation for configuring a Raspberry Pi (openSUSE Tumbleweed) as an IPP/Mopria-compatible print server for a USB-connected Brother HL-L1222/HL-L1222-V printer.

New Features:

  • Introduce a Bash setup script to install and configure CUPS, Avahi, firewall, and Bluetooth services for the Brother HL-L1222/HL-L1222-V on openSUSE Tumbleweed.
  • Automatically detect the USB-connected Brother printer, create a shared CUPS queue using an IPP Everywhere model, and perform a test print with status output.

Documentation:

  • Expand README with usage instructions, Wi-Fi IPP connection details for Android devices, and notes on Bluetooth limitations and driver options.

Summary by cubic

Adds a one-command setup to turn a Raspberry Pi 4B+ (openSUSE Tumbleweed) into a CUPS-backed IPP print server for a USB Brother HL‑L1222/HL‑L1222‑V, enabling Android Wi‑Fi printing via Mopria. Updates the README with run steps, the IPP URI, and Bluetooth caveats.

  • New Features
    • Adds scripts/setup_hl_l1222_android_print.sh to auto-configure the print server.
    • Installs and enables stack via zypper/systemctl: cups, cups-filters, ghostscript, avahi, nss-mdns, firewalld, ipp-usb, bluez, bluez-tools.
    • Configures CUPS (/etc/cups/cupsd.conf) to listen on port 631, enable sharing and web UI, allow @LOCAL; opens firewall for ipp and mdns.
    • Creates the Brother_HL_L1222_V queue using the detected USB URI and everywhere model; sets A4 and one-sided; shares the printer; prints a test page and shows status.
    • Updates README.md with usage and Android setup, including ipp://<raspberrypi-ip>/printers/Brother_HL_L1222_V and a note that Bluetooth printing is not reliably supported.

Written for commit a5e8e49. Summary will update on new commits. Review in cubic

@sourcery-ai

sourcery-ai Bot commented Apr 29, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds an automated bash setup script and documentation to configure a Raspberry Pi 4B+ running openSUSE Tumbleweed as a CUPS-based IPP print server for a USB-connected Brother HL-L1222/HL-L1222-V, enabling Android Wi-Fi/Mopria printing with appropriate services, firewall rules, and printer queue configuration.

Sequence diagram for Raspberry Pi print server setup script execution

sequenceDiagram
  participant User
  participant SetupScript
  participant Zypper
  participant Systemd
  participant CUPS
  participant Avahi
  participant Firewalld
  participant Bluetooth
  participant USBPrinter

  User->>SetupScript: sudo bash setup_hl_l1222_android_print.sh
  SetupScript->>SetupScript: Validate_root_and_required_commands

  SetupScript->>Zypper: refresh
  SetupScript->>Zypper: install cups cups-filters ghostscript avahi nss-mdns firewalld ipp-usb bluez bluez-tools

  SetupScript->>Systemd: enable --now cups.service
  Systemd-->>CUPS: start_cupsd
  SetupScript->>Systemd: enable --now avahi-daemon.service
  Systemd-->>Avahi: start_avahi
  SetupScript->>Systemd: enable --now firewalld.service
  Systemd-->>Firewalld: start_firewalld
  SetupScript->>Systemd: enable --now bluetooth.service
  Systemd-->>Bluetooth: start_bluetooth

  SetupScript->>CUPS: update_cupsd_conf_for_network_listening_and_sharing
  SetupScript->>Firewalld: add_service ipp
  SetupScript->>Firewalld: add_service mdns
  SetupScript->>Firewalld: reload

  USBPrinter-->>SetupScript: lpinfo -v output (usb Brother URI)
  SetupScript->>CUPS: lpadmin -p Brother_HL_L1222_V -E -v usb_uri -m everywhere
  SetupScript->>CUPS: lpadmin options sides=one-sided media=A4 printer-is-shared=true

  SetupScript->>Systemd: restart cups.service
  Systemd-->>CUPS: restart_cupsd

  SetupScript->>CUPS: lp testprint to Brother_HL_L1222_V
  CUPS->>USBPrinter: send_test_page

  SetupScript-->>User: show lpstat -t and IPP URL for Android
Loading

File-Level Changes

Change Details Files
Introduce a bash setup script that provisions the full printing stack, configures CUPS for LAN sharing, opens firewall/IP discovery, auto-detects the Brother USB printer, and creates a shared CUPS queue suitable for Android IPP/Mopria printing.
  • Add a root-only bash script with strict error handling that verifies required tools and installs CUPS, filters, avahi, firewalld, ipp-usb, and Bluetooth packages via zypper.
  • Enable and start cups, avahi-daemon, firewalld, and bluetooth services using systemd.
  • Modify cupsd.conf to listen on TCP port 631, enable browsing, sharing, web interface, and allow access from @Local for root and admin locations.
  • Open firewall services for ipp and mdns and reload the firewall configuration.
  • Auto-detect a Brother USB printer URI using lpinfo, aborting with guidance if not found and printing available devices.
  • Create or replace a CUPS queue with a fixed name using the everywhere model, set it as default, configure one-sided A4 printing, enable sharing, and restart CUPS.
  • Trigger a test print and display lpstat -t output, then print step-by-step Android IPP connection instructions including the resolved host IP and printer URI, plus Bluetooth caveats.
scripts/setup_hl_l1222_android_print.sh
Replace the placeholder README with user-facing documentation describing the Raspberry Pi Brother print-server use case, how to run the setup script, and how Android devices should connect via IPP.
  • Document the purpose of the repository as a Brother HL-L1222-V Android print server on Raspberry Pi 4B+ running openSUSE Tumbleweed.
  • Add a high-level description of what the setup enables, including Android Wi-Fi IPP/Mopria printing and LAN printer sharing.
  • Document Bluetooth limitations and position Wi-Fi IPP as the primary supported path while noting Bluetooth is still enabled for experimentation.
  • List the setup script path and provide the exact sudo command to run it.
  • Describe post-setup steps for Android, including enabling Mopria Print Service and using an ipp:///printers/Brother_HL_L1222_V URI.
  • Note that the script uses the CUPS everywhere model by default and that users can swap in an official Brother PPD/driver if available.
README.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a setup script and documentation for a Raspberry Pi print server. Key feedback includes switching to the brlaser driver, removing ipp-usb to avoid conflicts, and using cupsctl for more reliable configuration. Additionally, the test print file path should be corrected for compatibility.

# practical network printing path and optional USB OTG fallback guidance.

PRINTER_NAME="Brother_HL_L1222_V"
PPD_MODEL="everywhere"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The Brother HL-L1222-V is a GDI (host-based) printer and does not support the IPP Everywhere protocol. Using everywhere as the PPD model will likely result in "Filter failed" errors or no output. This printer typically requires the brlaser driver.

Suggested change
PPD_MODEL="everywhere"
PPD_MODEL="drv:///brlaser.drv/brl1222v.ppd"

Comment on lines +36 to +65
if ! grep -q '^Port 631' "$CUPSD_CONF"; then
sed -i 's/^Listen localhost:631/# &/' "$CUPSD_CONF" || true
echo 'Port 631' >> "$CUPSD_CONF"
fi

if ! grep -q '^Browsing Yes' "$CUPSD_CONF"; then
echo 'Browsing Yes' >> "$CUPSD_CONF"
fi

if ! grep -q '^DefaultShared Yes' "$CUPSD_CONF"; then
echo 'DefaultShared Yes' >> "$CUPSD_CONF"
fi

if ! grep -q '^WebInterface Yes' "$CUPSD_CONF"; then
echo 'WebInterface Yes' >> "$CUPSD_CONF"
fi

if ! grep -q '<Location />' "$CUPSD_CONF"; then
cat >> "$CUPSD_CONF" <<'CUPSLOC'
<Location />
Order allow,deny
Allow @LOCAL
</Location>

<Location /admin>
Order allow,deny
Allow @LOCAL
</Location>
CUPSLOC
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Manually editing cupsd.conf with sed and echo is brittle and not idempotent. Specifically, the check if ! grep -q '<Location />' will almost always fail on a standard CUPS installation because that block usually exists by default, meaning the Allow @LOCAL directive will never be added. This will prevent network clients from accessing the printer. Using cupsctl is the recommended, robust way to enable sharing and remote access.

Suggested change
if ! grep -q '^Port 631' "$CUPSD_CONF"; then
sed -i 's/^Listen localhost:631/# &/' "$CUPSD_CONF" || true
echo 'Port 631' >> "$CUPSD_CONF"
fi
if ! grep -q '^Browsing Yes' "$CUPSD_CONF"; then
echo 'Browsing Yes' >> "$CUPSD_CONF"
fi
if ! grep -q '^DefaultShared Yes' "$CUPSD_CONF"; then
echo 'DefaultShared Yes' >> "$CUPSD_CONF"
fi
if ! grep -q '^WebInterface Yes' "$CUPSD_CONF"; then
echo 'WebInterface Yes' >> "$CUPSD_CONF"
fi
if ! grep -q '<Location />' "$CUPSD_CONF"; then
cat >> "$CUPSD_CONF" <<'CUPSLOC'
<Location />
Order allow,deny
Allow @LOCAL
</Location>
<Location /admin>
Order allow,deny
Allow @LOCAL
</Location>
CUPSLOC
fi
cupsctl --remote-any --share-printers --user-interface

zypper --non-interactive refresh
zypper --non-interactive install \
cups cups-filters ghostscript avahi nss-mdns \
firewalld ipp-usb bluez bluez-tools

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The ipp-usb package can conflict with the standard CUPS USB backend for printers that do not natively support IPP-over-USB (like the HL-L1222). The ipp-usb daemon may claim the USB interface, preventing CUPS from accessing it. Additionally, cups-drivers-brlaser should be included to provide the necessary driver.

Suggested change
firewalld ipp-usb bluez bluez-tools
firewalld cups-drivers-brlaser bluez bluez-tools

systemctl restart cups.service

echo "[7/8] Printing a test page..."
lp -d "$PRINTER_NAME" /usr/share/cups/data/testprint || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The path /usr/share/cups/data/testprint may not exist or may require a specific file extension (like .ps or .pdf) depending on the CUPS version and installed filters. If this file is missing, the test print will fail.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • Consider using cupsctl (e.g., cupsctl --share-printers --remote-any --web-interface=yes) or a drop-in config snippet instead of directly editing /etc/cups/cupsd.conf, and at minimum create a backup of the original file before mutating it to make the script safer and more reversible.
  • The IP detection hostname -I | awk '{print $1}' may pick an unexpected interface on devices with multiple addresses (VPNs, Docker, etc.); consider filtering for a specific interface or prompting the user to choose from the available IPs.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Consider using `cupsctl` (e.g., `cupsctl --share-printers --remote-any --web-interface=yes`) or a drop-in config snippet instead of directly editing `/etc/cups/cupsd.conf`, and at minimum create a backup of the original file before mutating it to make the script safer and more reversible.
- The IP detection `hostname -I | awk '{print $1}'` may pick an unexpected interface on devices with multiple addresses (VPNs, Docker, etc.); consider filtering for a specific interface or prompting the user to choose from the available IPs.

## Individual Comments

### Comment 1
<location path="scripts/setup_hl_l1222_android_print.sh" line_range="67-70" />
<code_context>
+CUPSLOC
+fi
+
+echo "[3/8] Opening firewall for IPP + mDNS..."
+firewall-cmd --permanent --add-service=ipp || true
+firewall-cmd --permanent --add-service=mdns || true
+firewall-cmd --reload || true
+
+echo "[4/8] Detecting USB printer URI..."
</code_context>
<issue_to_address>
**suggestion (bug_risk):** Silencing firewall-cmd failures may hide real configuration problems.

Because every `firewall-cmd` call is suffixed with `|| true`, failures (e.g., firewalld not running, missing zones/services, or permission issues) are silently ignored and the script still appears to succeed, even if printing won’t work. Since you enable `firewalld.service` earlier, consider treating at least the first `firewall-cmd` invocation as mandatory and failing with a clear error if it doesn’t succeed, while leaving later calls non-fatal if desired.

```suggestion
echo "[3/8] Opening firewall for IPP + mDNS..."
if ! firewall-cmd --permanent --add-service=ipp; then
  echo "Error: Failed to configure firewall for IPP via firewall-cmd."
  echo "Ensure firewalld is installed, running, and that you have sufficient permissions, then re-run this script."
  exit 1
fi
firewall-cmd --permanent --add-service=mdns || true
firewall-cmd --reload || true
```
</issue_to_address>

### Comment 2
<location path="scripts/setup_hl_l1222_android_print.sh" line_range="105-106" />
<code_context>
+echo "[8/8] Final status"
+lpstat -t
+
+IP_ADDR="$(hostname -I | awk '{print $1}')"
+cat <<MSG
+
+Setup complete.
+
+Android printing method (recommended):
+1) Connect phone to same Wi-Fi as Raspberry Pi.
+2) Ensure Mopria Print Service is enabled on Android.
+3) Add/find printer: ipp://$IP_ADDR/printers/$PRINTER_NAME
+
+Bluetooth note:
</code_context>
<issue_to_address>
**suggestion:** Using `hostname -I | awk '{print $1}'` may select an unexpected or unusable IP address.

On hosts with multiple interfaces (Wi‑Fi, Ethernet, VPNs, docker, etc.), `hostname -I` often returns several addresses, and the first one may be unreachable from Android (e.g., link-local or internal). It would be more robust to target a specific interface (e.g., via `ip -4 addr show <iface>` and filtering out link-local addresses) or, at minimum, detect multiple candidates and prompt the user to choose the correct IP.

```suggestion
# Detect candidate IPv4 addresses (non-loopback, global scope)
CANDIDATE_IPS=()

if command -v ip >/dev/null 2>&1; then
  # Use `ip` if available for more reliable address detection
  while IFS= read -r ip; do
    CANDIDATE_IPS+=("$ip")
  done < <(ip -4 addr show scope global | awk '/inet / {print $2}' | cut -d/ -f1)
fi

# Fallback to hostname -I if `ip` produced nothing
if [ "${#CANDIDATE_IPS[@]}" -eq 0 ]; then
  for ip in $(hostname -I 2>/dev/null); do
    # skip obvious loopback addresses just in case
    case "$ip" in
      127.*) continue ;;
    esac
    CANDIDATE_IPS+=("$ip")
  done
fi

# If we still have nothing, leave IP_ADDR empty
IP_ADDR=""
if [ "${#CANDIDATE_IPS[@]}" -eq 1 ]; then
  IP_ADDR="${CANDIDATE_IPS[0]}"
elif [ "${#CANDIDATE_IPS[@]}" -gt 1 ]; then
  echo
  echo "Multiple candidate IP addresses were detected for this Raspberry Pi:"
  i=1
  for ip in "${CANDIDATE_IPS[@]}"; do
    echo "  [$i] $ip"
    i=$((i+1))
  done
  echo
  # prompt user to choose; default to first if they just press Enter
  read -rp "Select the IP address that your Android device can reach [1]: " choice
  case "$choice" in
    ""|*[!0-9]*)
      IP_ADDR="${CANDIDATE_IPS[0]}"
      ;;
    *)
      idx=$((choice-1))
      if [ "$idx" -ge 0 ] && [ "$idx" -lt "${#CANDIDATE_IPS[@]}" ]; then
        IP_ADDR="${CANDIDATE_IPS[$idx]}"
      else
        IP_ADDR="${CANDIDATE_IPS[0]}"
      fi
      ;;
  esac
fi

cat <<MSG
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +67 to +70
echo "[3/8] Opening firewall for IPP + mDNS..."
firewall-cmd --permanent --add-service=ipp || true
firewall-cmd --permanent --add-service=mdns || true
firewall-cmd --reload || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Silencing firewall-cmd failures may hide real configuration problems.

Because every firewall-cmd call is suffixed with || true, failures (e.g., firewalld not running, missing zones/services, or permission issues) are silently ignored and the script still appears to succeed, even if printing won’t work. Since you enable firewalld.service earlier, consider treating at least the first firewall-cmd invocation as mandatory and failing with a clear error if it doesn’t succeed, while leaving later calls non-fatal if desired.

Suggested change
echo "[3/8] Opening firewall for IPP + mDNS..."
firewall-cmd --permanent --add-service=ipp || true
firewall-cmd --permanent --add-service=mdns || true
firewall-cmd --reload || true
echo "[3/8] Opening firewall for IPP + mDNS..."
if ! firewall-cmd --permanent --add-service=ipp; then
echo "Error: Failed to configure firewall for IPP via firewall-cmd."
echo "Ensure firewalld is installed, running, and that you have sufficient permissions, then re-run this script."
exit 1
fi
firewall-cmd --permanent --add-service=mdns || true
firewall-cmd --reload || true

Comment on lines +105 to +106
IP_ADDR="$(hostname -I | awk '{print $1}')"
cat <<MSG

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Using hostname -I | awk '{print $1}' may select an unexpected or unusable IP address.

On hosts with multiple interfaces (Wi‑Fi, Ethernet, VPNs, docker, etc.), hostname -I often returns several addresses, and the first one may be unreachable from Android (e.g., link-local or internal). It would be more robust to target a specific interface (e.g., via ip -4 addr show <iface> and filtering out link-local addresses) or, at minimum, detect multiple candidates and prompt the user to choose the correct IP.

Suggested change
IP_ADDR="$(hostname -I | awk '{print $1}')"
cat <<MSG
# Detect candidate IPv4 addresses (non-loopback, global scope)
CANDIDATE_IPS=()
if command -v ip >/dev/null 2>&1; then
# Use `ip` if available for more reliable address detection
while IFS= read -r ip; do
CANDIDATE_IPS+=("$ip")
done < <(ip -4 addr show scope global | awk '/inet / {print $2}' | cut -d/ -f1)
fi
# Fallback to hostname -I if `ip` produced nothing
if [ "${#CANDIDATE_IPS[@]}" -eq 0 ]; then
for ip in $(hostname -I 2>/dev/null); do
# skip obvious loopback addresses just in case
case "$ip" in
127.*) continue ;;
esac
CANDIDATE_IPS+=("$ip")
done
fi
# If we still have nothing, leave IP_ADDR empty
IP_ADDR=""
if [ "${#CANDIDATE_IPS[@]}" -eq 1 ]; then
IP_ADDR="${CANDIDATE_IPS[0]}"
elif [ "${#CANDIDATE_IPS[@]}" -gt 1 ]; then
echo
echo "Multiple candidate IP addresses were detected for this Raspberry Pi:"
i=1
for ip in "${CANDIDATE_IPS[@]}"; do
echo " [$i] $ip"
i=$((i+1))
done
echo
# prompt user to choose; default to first if they just press Enter
read -rp "Select the IP address that your Android device can reach [1]: " choice
case "$choice" in
""|*[!0-9]*)
IP_ADDR="${CANDIDATE_IPS[0]}"
;;
*)
idx=$((choice-1))
if [ "$idx" -ge 0 ] && [ "$idx" -lt "${#CANDIDATE_IPS[@]}" ]; then
IP_ADDR="${CANDIDATE_IPS[$idx]}"
else
IP_ADDR="${CANDIDATE_IPS[0]}"
fi
;;
esac
fi
cat <<MSG

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 6 potential issues.

Open in Devin Review

Comment on lines +17 to +20
REQ_CMDS=(zypper systemctl lpinfo lpadmin lpstat)
for c in "${REQ_CMDS[@]}"; do
command -v "$c" >/dev/null || { echo "Missing command: $c"; exit 1; }
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 CUPS commands checked before CUPS package is installed, causing script failure on fresh systems

Lines 17-20 check for lpinfo, lpadmin, and lpstat via command -v, but these are all provided by the cups package which isn't installed until lines 24-26. On a fresh openSUSE system (the target environment), these commands won't exist, and the script will exit with "Missing command: lpinfo" before it ever reaches the zypper install cups step. This completely prevents the script from running on any system that doesn't already have CUPS — which is exactly the system this setup script is meant to configure.

Suggested change
REQ_CMDS=(zypper systemctl lpinfo lpadmin lpstat)
for c in "${REQ_CMDS[@]}"; do
command -v "$c" >/dev/null || { echo "Missing command: $c"; exit 1; }
done
REQ_CMDS=(zypper systemctl)
for c in "${REQ_CMDS[@]}"; do
command -v "$c" >/dev/null || { echo "Missing command: $c"; exit 1; }
done
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +53 to +65
if ! grep -q '<Location />' "$CUPSD_CONF"; then
cat >> "$CUPSD_CONF" <<'CUPSLOC'
<Location />
Order allow,deny
Allow @LOCAL
</Location>

<Location /admin>
Order allow,deny
Allow @LOCAL
</Location>
CUPSLOC
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Existing <Location /> block in default CUPS config prevents Allow @LOCAL from being added

Line 53 uses grep -q '<Location />' to decide whether to append the <Location /> block with Allow @LOCAL. However, a default CUPS installation already ships a <Location /> block that restricts access to localhost only (no Allow @LOCAL). The grep will find this existing block and skip adding the Allow @LOCAL directive, meaning Android clients on the LAN will be denied access to the printer — defeating the entire purpose of the script.

Default CUPS cupsd.conf typically contains
<Location />
  Order allow,deny
</Location>

Since this block exists, the grep matches, the script's Allow @LOCAL block is never appended, and network clients are denied.

Prompt for agents
The script checks whether `<Location />` exists in cupsd.conf and only appends the Allow @LOCAL block if it doesn't. But the default CUPS config already has a `<Location />` block (restricting access to localhost), so the check always matches and the Allow @LOCAL directive is never added.

The fix needs to handle both cases:
1. If `<Location />` exists but doesn't contain `Allow @LOCAL`, inject the Allow @LOCAL directive into the existing block.
2. If `<Location />` doesn't exist at all, append the full block.

Similar logic is needed for `<Location /admin>`.

One approach: use sed to find the existing `<Location />` block and add `Allow @LOCAL` inside it if not already present. For example:
  sed -i '/<Location \/>/,/<\/Location>/ { /Order allow,deny/a\  Allow @LOCAL' } cupsd.conf

Alternatively, replace the existing `<Location />` blocks entirely with the desired configuration using a more robust sed or awk transformation. The key file is /etc/cups/cupsd.conf and the functions involved are the cupsd.conf configuration section around line 53 of setup_hl_l1222_android_print.sh.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +36 to +51
if ! grep -q '^Port 631' "$CUPSD_CONF"; then
sed -i 's/^Listen localhost:631/# &/' "$CUPSD_CONF" || true
echo 'Port 631' >> "$CUPSD_CONF"
fi

if ! grep -q '^Browsing Yes' "$CUPSD_CONF"; then
echo 'Browsing Yes' >> "$CUPSD_CONF"
fi

if ! grep -q '^DefaultShared Yes' "$CUPSD_CONF"; then
echo 'DefaultShared Yes' >> "$CUPSD_CONF"
fi

if ! grep -q '^WebInterface Yes' "$CUPSD_CONF"; then
echo 'WebInterface Yes' >> "$CUPSD_CONF"
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚩 cupsd.conf modifications are append-only and not idempotent across re-runs

The cupsd.conf modifications at lines 36-65 use a pattern of grep -q to check existence and then echo >> "$CUPSD_CONF" to append. If the script is run multiple times (e.g., after a failed USB detection), and between runs the config already has Port 631 from a previous run, the guards prevent duplication — which is good. However, appending directives like Port 631, Browsing Yes, etc. to the END of the file may cause issues if the default config has conflicting directives earlier (e.g., Listen localhost:631 and Browsing No). CUPS uses the last-wins semantic for some directives but not all. The sed -i 's/^Listen localhost:631/# &/' on line 37 partially addresses this for the Listen directive, but similar conflicting directives (Browsing No, DefaultShared No) are not commented out before appending replacements.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

firewall-cmd --reload || true

echo "[4/8] Detecting USB printer URI..."
USB_URI="$(lpinfo -v | awk '/^direct usb:\/\/Brother\//{print $2; exit}')"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: USB URI detection awk pattern may not match all lpinfo output formats

Line 73 uses awk '/^direct usb:\/\/Brother\//{print $2; exit}' to extract the USB URI from lpinfo -v. The regex assumes the output starts with direct usb://Brother/ with exactly one space between direct and usb://. Some CUPS versions pad the scheme class field with multiple spaces or tabs. If the whitespace differs, the regex won't match even though the printer is connected. The $2 field extraction via awk's default whitespace splitting would still work for extracting the URI, but the regex anchor ^direct usb:// is fragile. A safer pattern might be /usb:\/\/Brother\//{print $2; exit} without anchoring to ^direct . This wasn't flagged as a bug because the standard lpinfo -v format on openSUSE with CUPS 2.x typically uses a single space, but it's worth noting.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +99 to +100
echo "[7/8] Printing a test page..."
lp -d "$PRINTER_NAME" /usr/share/cups/data/testprint || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Test page is printed unconditionally on every run

Line 100 prints a test page (lp -d "$PRINTER_NAME" /usr/share/cups/data/testprint || true) every time the script is run. If an operator re-runs the script (e.g., to fix config), a physical page will be printed each time, wasting paper. This is not a bug per se, but could be surprising for re-runs. A --no-test flag or a prompt would be a more user-friendly approach.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment on lines +73 to +79
USB_URI="$(lpinfo -v | awk '/^direct usb:\/\/Brother\//{print $2; exit}')"
if [[ -z "$USB_URI" ]]; then
echo "No Brother USB URI auto-detected. Available devices:"
lpinfo -v
echo "Connect the printer via USB and re-run this script."
exit 1
fi

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📝 Info: Script uses set -euo pipefail but pipes lpinfo -v through awk without handling pipefail

Line 73: USB_URI="$(lpinfo -v | awk '...')" — with pipefail enabled, if lpinfo -v fails (e.g., CUPS service not fully started yet after the enable --now on line 29), the pipeline exit status will be non-zero and set -e will terminate the script before reaching the friendlier error message at lines 74-78. The || true pattern used elsewhere (e.g., line 100) is not applied here, which is actually reasonable since a failed lpinfo is a real error, but the error message won't be the script's helpful diagnostic — it'll be an abrupt exit. This is a minor UX concern, not a correctness bug.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a5e8e49d51

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +17 to +20
REQ_CMDS=(zypper systemctl lpinfo lpadmin lpstat)
for c in "${REQ_CMDS[@]}"; do
command -v "$c" >/dev/null || { echo "Missing command: $c"; exit 1; }
done

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Run CUPS command checks after installing dependencies

The preflight loop checks lpinfo, lpadmin, and lpstat before the script installs cups, so a fresh target host without CUPS exits immediately at "Missing command" and never reaches the installation step. This makes the setup non-bootstrapping in exactly the environment this script is meant to provision.

Useful? React with 👍 / 👎.

Comment on lines +53 to +54
if ! grep -q '<Location />' "$CUPSD_CONF"; then
cat >> "$CUPSD_CONF" <<'CUPSLOC'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Modify existing CUPS Location ACL instead of skipping it

The LAN access block is only appended when <Location /> is absent, but standard cupsd.conf files already contain that section. In that common case this script does not relax the existing ACLs for local-network clients, so CUPS may still reject remote Android IPP requests even though Port 631 and sharing are enabled.

Useful? React with 👍 / 👎.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="scripts/setup_hl_l1222_android_print.sh">

<violation number="1" location="scripts/setup_hl_l1222_android_print.sh:17">
P1: The preflight command check requires CUPS tools before they are installed, which can make the setup fail immediately on clean hosts.</violation>

<violation number="2" location="scripts/setup_hl_l1222_android_print.sh:41">
P1: The script appends `Browsing Yes` and `DefaultShared Yes` but does not comment out the conflicting `Browsing No` / `DefaultShared No` directives that typically exist in the default `cupsd.conf`. While `Listen localhost:631` is correctly commented out via `sed` before appending `Port 631`, the same treatment is missing here. CUPS may use the earlier conflicting value, leaving sharing and browsing disabled.</violation>

<violation number="3" location="scripts/setup_hl_l1222_android_print.sh:53">
P0: Default CUPS `cupsd.conf` already contains a `<Location />` block (restricting access to localhost). Since `grep -q '<Location />'` finds the existing block, the `Allow @LOCAL` directive is never appended, so Android LAN clients will still be denied access—defeating the purpose of this script.

The fix should inject `Allow @LOCAL` into the existing `<Location />` block if it doesn't already contain it, or use `cupsctl --remote-any --share-printers` which handles this robustly.</violation>

<violation number="4" location="scripts/setup_hl_l1222_android_print.sh:68">
P2: Do not swallow firewall-cmd failures; this can report success while network printing is still blocked.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

echo 'WebInterface Yes' >> "$CUPSD_CONF"
fi

if ! grep -q '<Location />' "$CUPSD_CONF"; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P0: Default CUPS cupsd.conf already contains a <Location /> block (restricting access to localhost). Since grep -q '<Location />' finds the existing block, the Allow @LOCAL directive is never appended, so Android LAN clients will still be denied access—defeating the purpose of this script.

The fix should inject Allow @LOCAL into the existing <Location /> block if it doesn't already contain it, or use cupsctl --remote-any --share-printers which handles this robustly.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/setup_hl_l1222_android_print.sh, line 53:

<comment>Default CUPS `cupsd.conf` already contains a `<Location />` block (restricting access to localhost). Since `grep -q '<Location />'` finds the existing block, the `Allow @LOCAL` directive is never appended, so Android LAN clients will still be denied access—defeating the purpose of this script.

The fix should inject `Allow @LOCAL` into the existing `<Location />` block if it doesn't already contain it, or use `cupsctl --remote-any --share-printers` which handles this robustly.</comment>

<file context>
@@ -0,0 +1,118 @@
+  echo 'WebInterface Yes' >> "$CUPSD_CONF"
+fi
+
+if ! grep -q '<Location />' "$CUPSD_CONF"; then
+  cat >> "$CUPSD_CONF" <<'CUPSLOC'
+<Location />
</file context>

echo 'Port 631' >> "$CUPSD_CONF"
fi

if ! grep -q '^Browsing Yes' "$CUPSD_CONF"; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The script appends Browsing Yes and DefaultShared Yes but does not comment out the conflicting Browsing No / DefaultShared No directives that typically exist in the default cupsd.conf. While Listen localhost:631 is correctly commented out via sed before appending Port 631, the same treatment is missing here. CUPS may use the earlier conflicting value, leaving sharing and browsing disabled.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/setup_hl_l1222_android_print.sh, line 41:

<comment>The script appends `Browsing Yes` and `DefaultShared Yes` but does not comment out the conflicting `Browsing No` / `DefaultShared No` directives that typically exist in the default `cupsd.conf`. While `Listen localhost:631` is correctly commented out via `sed` before appending `Port 631`, the same treatment is missing here. CUPS may use the earlier conflicting value, leaving sharing and browsing disabled.</comment>

<file context>
@@ -0,0 +1,118 @@
+  echo 'Port 631' >> "$CUPSD_CONF"
+fi
+
+if ! grep -q '^Browsing Yes' "$CUPSD_CONF"; then
+  echo 'Browsing Yes' >> "$CUPSD_CONF"
+fi
</file context>

exit 1
fi

REQ_CMDS=(zypper systemctl lpinfo lpadmin lpstat)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: The preflight command check requires CUPS tools before they are installed, which can make the setup fail immediately on clean hosts.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/setup_hl_l1222_android_print.sh, line 17:

<comment>The preflight command check requires CUPS tools before they are installed, which can make the setup fail immediately on clean hosts.</comment>

<file context>
@@ -0,0 +1,118 @@
+  exit 1
+fi
+
+REQ_CMDS=(zypper systemctl lpinfo lpadmin lpstat)
+for c in "${REQ_CMDS[@]}"; do
+  command -v "$c" >/dev/null || { echo "Missing command: $c"; exit 1; }
</file context>

fi

echo "[3/8] Opening firewall for IPP + mDNS..."
firewall-cmd --permanent --add-service=ipp || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Do not swallow firewall-cmd failures; this can report success while network printing is still blocked.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At scripts/setup_hl_l1222_android_print.sh, line 68:

<comment>Do not swallow firewall-cmd failures; this can report success while network printing is still blocked.</comment>

<file context>
@@ -0,0 +1,118 @@
+fi
+
+echo "[3/8] Opening firewall for IPP + mDNS..."
+firewall-cmd --permanent --add-service=ipp || true
+firewall-cmd --permanent --add-service=mdns || true
+firewall-cmd --reload || true
</file context>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant