Skip to content

Commit

Permalink
Address persistence and a system-wide server (Issue #128, Issue #148)
Browse files Browse the repository at this point in the history
- _papplMainloopRunServer now chooses a default spool directory and state file
  based on the base name of the printer application, and those files go in
  persistent locations.
- _papplMainloopConnect now tries connecting to a root server if the per-user
  server cannot be found, before starting a per-user server.
- _papplMainloopGetServerPath now takes a UID argument.
  • Loading branch information
michaelrsweet committed Apr 15, 2021
1 parent b1e9e6e commit b88be1a
Show file tree
Hide file tree
Showing 8 changed files with 227 additions and 18 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ Changes in v1.1b1

- Added `PAPPL_SOPTIONS_NO_TLS` option to disable TLS support.
- Added Wi-Fi callbacks to support configuration over IPP-USB (Issue #45)
- `papplMainLoop` now uses a persistent location for state and spool files by
default (Issue #128)
- `papplMainLoop` now supports clients talking to a system-wide server running
as root (Issue #148)


Changes in v1.0.3
Expand Down
8 changes: 8 additions & 0 deletions config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
#define PAPPL_VERSION_MINOR 0


// Location of PAPPL state and spool data (when run as root)
#define PAPPL_LOCALSTATEDIR "/usr/local/var"


// Location of PAPPL domain socket (when run as root)
#define PAPPL_RUNSTATEDIR "/usr/local/var/run"


// Location of CUPS config files
#define CUPS_SERVERROOT "/etc/cups"

Expand Down
59 changes: 59 additions & 0 deletions configure
Original file line number Diff line number Diff line change
Expand Up @@ -5070,6 +5070,65 @@ then :
fi


if test "$localstatedir" = "\${prefix}/var"
then :

if test "$host_os_name" = darwin
then :


printf "%s\n" "#define PAPPL_LOCALSTATEDIR \"/Library\"" >>confdefs.h


else $as_nop


printf "%s\n" "#define PAPPL_LOCALSTATEDIR \"$prefix/var\"" >>confdefs.h


fi

else $as_nop


printf "%s\n" "#define PAPPL_LOCALSTATEDIR \"$localstatedir\"" >>confdefs.h


fi

if test "$runstatedir" = "\${localstatedir}/run"
then :

if test "$host_os_name" = darwin
then :


printf "%s\n" "#define PAPPL_RUNSTATEDIR \"/private/var/run\"" >>confdefs.h


elif test "$localstatedir" = "\${prefix}/var"
then :


printf "%s\n" "#define PAPPL_RUNSTATEDIR \"$prefix/var/run\"" >>confdefs.h


else $as_nop


printf "%s\n" "#define PAPPL_RUNSTATEDIR \"$localstatedir/run\"" >>confdefs.h


fi

else $as_nop


printf "%s\n" "#define PAPPL_RUNSTATEDIR \"$runstatedir\"" >>confdefs.h


fi


ac_config_files="$ac_config_files Makedefs pappl/pappl.pc"

Expand Down
23 changes: 23 additions & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,29 @@ AC_ARG_WITH([ldflags], AS_HELP_STRING([--with-ldflags=...], [Specify additional
LDFLAGS="$withval $LDFLAGS"
])

dnl State and run directories for root servers...
AS_IF([test "$localstatedir" = "\${prefix}/var"], [
AS_IF([test "$host_os_name" = darwin], [
AC_DEFINE_UNQUOTED([PAPPL_LOCALSTATEDIR], ["/Library"], [Location of PAPPL state and spool data (when run as root)])
], [
AC_DEFINE_UNQUOTED([PAPPL_LOCALSTATEDIR], ["$prefix/var"], [Location of PAPPL state and spool data (when run as root)])
])
], [
AC_DEFINE_UNQUOTED([PAPPL_LOCALSTATEDIR], ["$localstatedir"], [Location of PAPPL state and spool data (when run as root)])
])

AS_IF([test "$runstatedir" = "\${localstatedir}/run"], [
AS_IF([test "$host_os_name" = darwin], [
AC_DEFINE_UNQUOTED([PAPPL_RUNSTATEDIR], ["/private/var/run"], [Location of PAPPL domain socket (when run as root)])
], [test "$localstatedir" = "\${prefix}/var"], [
AC_DEFINE_UNQUOTED([PAPPL_RUNSTATEDIR], ["$prefix/var/run"], [Location of PAPPL domain socket (when run as root)])
], [
AC_DEFINE_UNQUOTED([PAPPL_RUNSTATEDIR], ["$localstatedir/run"], [Location of PAPPL domain socket (when run as root)])
])
], [
AC_DEFINE_UNQUOTED([PAPPL_RUNSTATEDIR], ["$runstatedir"], [Location of PAPPL domain socket (when run as root)])
])


dnl Generate the Makefile and pkg-config file...
AC_CONFIG_FILES([Makedefs pappl/pappl.pc])
Expand Down
2 changes: 1 addition & 1 deletion pappl/mainloop-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ extern void _papplMainloopAddPrinterURI(ipp_t *request, const char *printer_name
extern http_t *_papplMainloopConnect(const char *base_name, bool auto_start) _PAPPL_PRIVATE;
extern http_t *_papplMainloopConnectURI(const char *base_name, const char *printer_uri, char *resource, size_t rsize) _PAPPL_PRIVATE;
extern char *_papplMainloopGetDefaultPrinter(http_t *http, char *buffer, size_t bufsize) _PAPPL_PRIVATE;
extern char *_papplMainloopGetServerPath(const char *base_name, char *buffer, size_t bufsize) _PAPPL_PRIVATE;
extern char *_papplMainloopGetServerPath(const char *base_name, uid_t uid, char *buffer, size_t bufsize) _PAPPL_PRIVATE;


//
Expand Down
106 changes: 97 additions & 9 deletions pappl/mainloop-subcommands.c
Original file line number Diff line number Diff line change
Expand Up @@ -519,15 +519,35 @@ _papplMainloopRunServer(
pappl_system_t *system; // System object
char sockname[1024], // Socket filename
statename[1024];// State filename
const char *home = getenv("HOME");
// Home directory
const char *snap_common = getenv("SNAP_COMMON");
// Common data directory for snaps
const char *tmpdir = getenv("TMPDIR");
// Temporary directory
const char *xdg_config_home = getenv("XDG_CONFIG_HOME");
// Freedesktop per-user config directory


// Make sure we know the temporary directory...
#ifdef __APPLE__
if (!tmpdir)
tmpdir = "/private/tmp";
#else
if (!tmpdir)
tmpdir = "/tmp";
#endif // __APPLE__

// Create the system object...
if (system_cb)
{
// Developer-supplied system object...
system = (system_cb)(num_options, options, data);
}
else
{
// Default system object...
char spoolname[1024]; // Default spool directory
const char *directory = cupsGetOption("spool-directory", num_options, options),
// Spool directory
*logfile = cupsGetOption("log-file", num_options, options),
Expand Down Expand Up @@ -567,6 +587,39 @@ _papplMainloopRunServer(
}
}

// Make sure we have a spool directory...
if (!directory)
{
if (snap_common)
{
// Running inside a snap (https://snapcraft.io), so use the snap's common
// data directory...
snprintf(spoolname, sizeof(spoolname), "%s/%s.d", snap_common, base_name);
}
else if (!getuid())
{
// Running as root, so put the state file in the local state directory
#ifdef __APPLE__
snprintf(spoolname, sizeof(spoolname), PAPPL_LOCALSTATEDIR "/Caches/%s", base_name);

#else
if (access(PAPPL_LOCALSTATEDIR "/spool", X_OK) && errno == ENOENT)
mkdir(PAPPL_LOCALSTATEDIR "/spool", 0777);
// Make sure base directory exists

snprintf(spoolname, sizeof(spoolname), PAPPL_LOCALSTATEDIR "/spool/%s", base_name);
#endif // __APPLE__
}
else
{
// As a last resort, put the state in the temporary directory (where it
// will be lost on the nest reboot/logout...
snprintf(spoolname, sizeof(spoolname), "%s/%s%d.d", tmpdir, base_name, (int)getuid());
}

directory = spoolname;
}

// Create the system object...
system = papplSystemCreate(PAPPL_SOPTIONS_MULTI_QUEUE | PAPPL_SOPTIONS_WEB_INTERFACE, base_name, port, "_print,_universal", directory, logfile, loglevel, cupsGetOption("auth-service", num_options, options), false);

Expand Down Expand Up @@ -605,25 +658,60 @@ _papplMainloopRunServer(
papplSystemSetPrinterDrivers(system, num_drivers, drivers, autoadd_cb, /* create_cb */NULL, driver_cb, data);

// Listen for connections...
papplSystemAddListeners(system, _papplMainloopGetServerPath(base_name, sockname, sizeof(sockname)));
papplSystemAddListeners(system, _papplMainloopGetServerPath(base_name, getuid(), sockname, sizeof(sockname)));

// Finish initialization...
if (!system->save_cb)
{
const char *tmpdir = getenv("TMPDIR");
// Temporary directory

// Register a callback for saving state information, then load any
// previous state...
if (snap_common)
{
// Running inside a snap (https://snapcraft.io), so use the snap's common
// data directory...
snprintf(statename, sizeof(statename), "%s/%s.state", snap_common, base_name);
}
else if (!getuid())
{
// Running as root, so put the state file in the local state directory
#ifdef __APPLE__
if (!tmpdir)
tmpdir = "/private/tmp";
snprintf(statename, sizeof(statename), PAPPL_LOCALSTATEDIR "/Application Support/%s.state", base_name);

#else
if (!tmpdir)
tmpdir = "/tmp";
if (access(PAPPL_LOCALSTATEDIR "/lib", X_OK) && errno == ENOENT)
mkdir(PAPPL_LOCALSTATEDIR "/lib", 0777);
// Make sure base directory exists

snprintf(statename, sizeof(statename), PAPPL_LOCALSTATEDIR "/lib/%s.state", base_name);
#endif // __APPLE__
}
else if (xdg_config_home)
{
// Use Freedesktop per-user config directory
snprintf(statename, sizeof(statename), "%s/%s.state", xdg_config_home, base_name);
}
else if (home)
{
#ifdef __APPLE__
// Put the state in "~/Library/Application Support"
snprintf(statename, sizeof(statename), "%s/Library/Application Support/%s.state", home, base_name);

#else
// Put the state under a ".config" directory in the home directory
snprintf(statename, sizeof(statename), "%s/.config", home);
if (access(statename, X_OK) && errno == ENOENT)
mkdir(statename, 0777); // Make ~/.config as needed

snprintf(statename, sizeof(statename), "%s/.config/%s.state", home, base_name);
#endif // __APPL__
}
else
{
// As a last resort, put the state in the temporary directory (where it
// will be lost on the nest reboot/logout...
snprintf(statename, sizeof(statename), "%s/%s%d.state", tmpdir, base_name, (int)getuid());
}

snprintf(statename, sizeof(statename), "%s/%s%d.state", tmpdir, base_name, (int)getuid());
papplSystemLoadState(system, statename);
papplSystemSetSaveCallback(system, (pappl_save_cb_t)papplSystemSaveState, (void *)statename);
}
Expand Down
35 changes: 27 additions & 8 deletions pappl/mainloop-support.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,13 @@ _papplMainloopConnect(


// See if the server is running...
http = httpConnect2(_papplMainloopGetServerPath(base_name, sockname, sizeof(sockname)), 0, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
http = httpConnect2(_papplMainloopGetServerPath(base_name, getuid(), sockname, sizeof(sockname)), 0, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);

if (!http && getuid())
{
// Try root server...
http = httpConnect2(_papplMainloopGetServerPath(base_name, 0, sockname, sizeof(sockname)), 0, NULL, AF_UNSPEC, HTTP_ENCRYPTION_IF_REQUESTED, 1, 30000, NULL);
}

if (!http && auto_start)
{
Expand Down Expand Up @@ -346,6 +352,8 @@ _papplMainloopConnect(
posix_spawnattr_destroy(&server_attrs);

// Wait for it to start...
_papplMainloopGetServerPath(base_name, getuid(), sockname, sizeof(sockname));

do
{
usleep(250000);
Expand Down Expand Up @@ -449,22 +457,33 @@ _papplMainloopGetDefaultPrinter(
char * // O - Socket filename
_papplMainloopGetServerPath(
const char *base_name, // I - Base name
uid_t uid, // I - UID for server
char *buffer, // I - Buffer for filename
size_t bufsize) // I - Size of buffer
{
const char *tmpdir = getenv("TMPDIR");
if (uid)
{
// Per-user server...
const char *tmpdir = getenv("TMPDIR");
// Temporary directory

#ifdef __APPLE__
if (!tmpdir)
tmpdir = "/private/tmp";
if (!tmpdir)
tmpdir = "/private/tmp";
#else
if (!tmpdir)
tmpdir = "/tmp";
if (!tmpdir)
tmpdir = "/tmp";
#endif // __APPLE__

snprintf(buffer, bufsize, "%s/%s%d.sock", tmpdir, base_name, (int)getuid());
_PAPPL_DEBUG("Creating domain socket as '%s'.\n", buffer);
snprintf(buffer, bufsize, "%s/%s%d.sock", tmpdir, base_name, (int)uid);
}
else
{
// System server running as root
snprintf(buffer, bufsize, PAPPL_RUNSTATEDIR "/%s.sock", base_name);
}

_PAPPL_DEBUG("Using domain socket '%s'.\n", buffer);

return (buffer);
}
Expand Down
8 changes: 8 additions & 0 deletions xcode/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,14 @@
#define PAPPL_VERSION_MINOR 1


// Location of PAPPL state and spool data (when run as root)
#define PAPPL_LOCALSTATEDIR "/Library"


// Location of PAPPL domain socket (when run as root)
#define PAPPL_RUNSTATEDIR "/private/var/run"


// Location of CUPS config files
#define CUPS_SERVERROOT "/private/etc/cups"

Expand Down

0 comments on commit b88be1a

Please sign in to comment.