From d921af68f45be27c851ef93b24ca15f1e093d4a5 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Mon, 15 Aug 2022 07:41:22 -0400 Subject: [PATCH 01/19] Initial skeleton of new DNS-SD API (Issue #19) --- cups/dnssd.c | 93 +++++++++++++++++++++++++ cups/dnssd.h | 86 +++++++++++++++++++++++ xcode/libcups.xcodeproj/project.pbxproj | 16 +++++ 3 files changed, 195 insertions(+) create mode 100644 cups/dnssd.c create mode 100644 cups/dnssd.h diff --git a/cups/dnssd.c b/cups/dnssd.c new file mode 100644 index 000000000..b94f0c47c --- /dev/null +++ b/cups/dnssd.c @@ -0,0 +1,93 @@ +// +// DNS-SD API definitions for CUPS. +// +// Copyright © 2022 by OpenPrinting. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#include +#include "cups.h" +#include "dnssd.h" +#include "debug-internal.h" + +#if _WIN32 +# include +#elif defined(HAVE_MDNSRESPONDER) +# include +# include +#else // HAVE_AVAHI +# include +# include +# include +# include +# include +# include +# include + +struct _cups_dns_srv_s // DNS SRV record +{ + AvahiEntryGroup *srv; // SRV record + AvahiStringList *txt; // TXT record +}; +#endif // _WIN32 + + +// +// Private structures... +// + +struct _cups_dnssd_s // DNS-SD context +{ +}; + +struct _cups_dnssd_browse_s // DNS-SD browse request +{ + cups_dnssd_t *dnssd; // DNS-SD context + cups_dnssd_browse_cb_t cb; // Browse callback + void *cb_data; // Browse callback data + +#if _WIN32 +#elif defined(HAVE_MDNSRESPONDER) +#else // HAVE_AVAHI +#endif // _WIN32 +}; + +struct _cups_dns_query_s // DNS-SD query request +{ + cups_dnssd_t *dnssd; // DNS-SD context + cups_dnssd_query_cb_t cb; // Query callback + void *cb_data; // Query callback data + +#if _WIN32 +#elif defined(HAVE_MDNSRESPONDER) +#else // HAVE_AVAHI +#endif // _WIN32 +}; + +struct _cups_dns_resolve_s // DNS-SD resolve request +{ + cups_dnssd_t *dnssd; // DNS-SD context + cups_dnssd_resolve_cb_t cb; // Resolve callback + void *cb_data; // Resolve callback data + +#if _WIN32 +#elif defined(HAVE_MDNSRESPONDER) +#else // HAVE_AVAHI +#endif // _WIN32 +}; + +struct _cups_dns_service_s // DNS-SD service registration +{ + cups_dnssd_t *dnssd; // DNS-SD context + char *name; // Service name + cups_dnssd_service_cb_t cb; // Service callback + void *cb_data; // Service callback data + +#if _WIN32 +#elif defined(HAVE_MDNSRESPONDER) +#else // HAVE_AVAHI +#endif // _WIN32 +}; + diff --git a/cups/dnssd.h b/cups/dnssd.h new file mode 100644 index 000000000..a5598ef05 --- /dev/null +++ b/cups/dnssd.h @@ -0,0 +1,86 @@ +// +// DNS-SD API definitions for CUPS. +// +// Copyright © 2022 by OpenPrinting. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#ifndef _CUPS_DNSSD_H_ +# define _CUPS_DNSSD_H_ +# include "cups.h" +# ifdef __cplusplus +extern "C" { +# endif // __cplusplus + + +// +// Types and constants... +// + +# define CUPS_DNSSD_IF_INDEX_ANY 0 +# define CUPS_DNSSD_IF_INDEX_LOCAL ((uint32_t)-1) + +typedef struct _cups_dnssd_s cups_dnssd_t; // DNS-SD context + +enum cups_dnssd_flags_e // DNS-SD callback flag values +{ + CUPS_DNSSD_FLAGS_NONE = 0, // No flags + CUPS_DNSSD_FLAGS_ADD = 1, // Added + CUPS_DNSSD_FLAGS_REMOVE = 2, // Removed + CUPS_DNSSD_FLAGS_ERROR = 4 // Error occurred +}; +typedef unsigned cups_dnssd_flags_t; // DNS-SD callback flag bitmask + +typedef struct _cups_dnssd_browse_s cups_dnssd_browse_t; + // DNS browse request +typedef void (*cups_dnssd_browse_cb_t)(cups_dnssd_browse_t *browse, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain); + // DNS-SD browse callback + +typedef void (*cups_dnssd_error_cb_t)(void *cb_data, const char *message); + // DNS-SD error callback + +typedef struct _cups_dnssd_query_s cups_dnssd_query_t; + // DNS query request +typedef void (*cups_dnssd_query_cb_t)(cups_dnssd_query_t * query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain, size_t num_txt, cups_option_t *txt); + // DNS-SD query callback + +typedef struct _cups_dnssd_resolve_s cups_dnssd_resolve_t; + // DNS resolve request +typedef void (*cups_dnssd_resolve_cb_t)(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt); + // DNS-SD resolve callback + +typedef struct _cups_dnssd_service_s cups_dnssd_service_t; + // DNS service registration +typedef void (*cups_dnssd_service_cb_t)(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags, const char *name, const char *regtype, const char *domain); + // DNS-SD service registration callback + + +// +// Functions... +// + +extern void cupsDNSSDDelete(cups_dnssd_t *dns) _CUPS_PUBLIC; +extern cups_dnssd_t *cupsDNSSDNew(cups_dnssd_error_cb_t error_cb, void *cb_data) _CUPS_PUBLIC; + +extern void cupsDNSSDBrowseDelete(cups_dnssd_browse_t *browser) _CUPS_PUBLIC; +extern cups_dnssd_browse_t *cupsDNSSDBrowseNew(cups_dnssd_t *dns, uint32_t if_index, const char *types, const char *domains, cups_dnssd_browse_cb_t browse_cb, void *cb_data) _CUPS_PUBLIC; + +extern void cupsDNSSDQueryDelete(cups_dnssd_query_t *query) _CUPS_PUBLIC; +extern cups_dnssd_query_t *cupsDNSSDQueryNew(cups_dnssd_t *dns, uint32_t if_index, const char *types, const char *domains, cups_dnssd_query_cb_t query_cb, void *cb_data) _CUPS_PUBLIC; + +extern void cupsDNSSDResolveDelete(cups_dnssd_resolve_t *res) _CUPS_PUBLIC; +extern cups_dnssd_resolve_t *cupsDNSSDResolveNew(cups_dnssd_t *dns, uint32_t if_index, const char *types, const char *domains, cups_dnssd_resolve_cb_t resolve_cb, void *cb_data) _CUPS_PUBLIC; + +extern bool cupsDNSSDServiceAdd(cups_dnssd_service_t *service, uint32_t if_index, const char *types, const char *domains, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt) _CUPS_PUBLIC; +extern void cupsDNSSDServiceDelete(cups_dnssd_service_t *service) _CUPS_PUBLIC; +extern cups_dnssd_service_t *cupsDNSSDServiceNew(cups_dnssd_t *dns, const char *name, cups_dnssd_service_cb_t cb, void *cb_data) _CUPS_PUBLIC; +extern bool cupsDNSSDServicePublish(cups_dnssd_service_t *service) _CUPS_PUBLIC; +extern bool cupsDNSSDServiceSetLocation(cups_dnssd_service_t *service, const char *geo_uri) _CUPS_PUBLIC; + + +# ifdef __cplusplus +} +# endif // __cplusplus +#endif // !_CUPS_DNSSD_H_ diff --git a/xcode/libcups.xcodeproj/project.pbxproj b/xcode/libcups.xcodeproj/project.pbxproj index 33074edc4..b82318da3 100644 --- a/xcode/libcups.xcodeproj/project.pbxproj +++ b/xcode/libcups.xcodeproj/project.pbxproj @@ -199,6 +199,12 @@ 278CA9062884D9B100367E41 /* rand.c in Sources */ = {isa = PBXBuildFile; fileRef = 278CA9042884D9B100367E41 /* rand.c */; }; 278CA9072884D9B100367E41 /* rand.c in Sources */ = {isa = PBXBuildFile; fileRef = 278CA9042884D9B100367E41 /* rand.c */; }; 279AE6F52395B80F004DD600 /* libpam.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 279AE6F42395B80F004DD600 /* libpam.tbd */; }; + 27A8096128A9B9D500B20BC8 /* dnssd.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A8095F28A9B9D500B20BC8 /* dnssd.h */; }; + 27A8096228A9B9D500B20BC8 /* dnssd.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A8095F28A9B9D500B20BC8 /* dnssd.h */; }; + 27A8096328A9B9D500B20BC8 /* dnssd.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A8095F28A9B9D500B20BC8 /* dnssd.h */; }; + 27A8096428A9B9D500B20BC8 /* dnssd.c in Sources */ = {isa = PBXBuildFile; fileRef = 27A8096028A9B9D500B20BC8 /* dnssd.c */; }; + 27A8096528A9B9D500B20BC8 /* dnssd.c in Sources */ = {isa = PBXBuildFile; fileRef = 27A8096028A9B9D500B20BC8 /* dnssd.c */; }; + 27A8096628A9B9D500B20BC8 /* dnssd.c in Sources */ = {isa = PBXBuildFile; fileRef = 27A8096028A9B9D500B20BC8 /* dnssd.c */; }; 27CAFC61282C895700FE02FC /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27CAFC5F282C895700FE02FC /* libssl.a */; }; 27CAFC62282C895700FE02FC /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27CAFC60282C895700FE02FC /* libcrypto.a */; }; 27CAFC63282C898300FE02FC /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27CAFC60282C895700FE02FC /* libcrypto.a */; }; @@ -958,6 +964,8 @@ 278C58E8136B64B000836530 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = ""; }; 278CA9042884D9B100367E41 /* rand.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rand.c; path = ../cups/rand.c; sourceTree = ""; }; 279AE6F42395B80F004DD600 /* libpam.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libpam.tbd; path = usr/lib/libpam.tbd; sourceTree = SDKROOT; }; + 27A8095F28A9B9D500B20BC8 /* dnssd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssd.h; path = ../cups/dnssd.h; sourceTree = ""; }; + 27A8096028A9B9D500B20BC8 /* dnssd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd.c; path = ../cups/dnssd.c; sourceTree = ""; }; 27CAFC5F282C895700FE02FC /* libssl.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libssl.a; path = ../../../../../usr/local/lib/libssl.a; sourceTree = ""; }; 27CAFC60282C895700FE02FC /* libcrypto.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libcrypto.a; path = ../../../../../usr/local/lib/libcrypto.a; sourceTree = ""; }; 27CAFC6F282C8ADF00FE02FC /* tls-openssl.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "tls-openssl.c"; path = "../cups/tls-openssl.c"; sourceTree = ""; }; @@ -1514,6 +1522,8 @@ 72CF95E218A13543000FCAE4 /* dest-options.c */, 72220ED4133305BB00FCA411 /* dir.h */, 72220ED3133305BB00FCA411 /* dir.c */, + 27A8095F28A9B9D500B20BC8 /* dnssd.h */, + 27A8096028A9B9D500B20BC8 /* dnssd.c */, 72220ED6133305BB00FCA411 /* encode.c */, 72220ED9133305BB00FCA411 /* file.h */, 72220ED7133305BB00FCA411 /* file-private.h */, @@ -1658,6 +1668,7 @@ 270696441CADF3E200FFE5FB /* ipp-private.h in Headers */, 270696451CADF3E200FFE5FB /* language-private.h in Headers */, 270696461CADF3E200FFE5FB /* md5-internal.h in Headers */, + 27A8096228A9B9D500B20BC8 /* dnssd.h in Headers */, 270696481CADF3E200FFE5FB /* pwg-private.h in Headers */, 2706964A1CADF3E200FFE5FB /* string-private.h in Headers */, 7253C46C216ED5E500494ADD /* raster-private.h in Headers */, @@ -1681,6 +1692,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( + 27A8096328A9B9D500B20BC8 /* dnssd.h in Headers */, 722A24F52178D091000CAB20 /* debug-private.h in Headers */, 274FF6C61333B1C400317ECB /* dir.h in Headers */, 27D3966727BA81C6003D3D8E /* raster-testpage.h in Headers */, @@ -1701,6 +1713,7 @@ 72220F21133305BB00FCA411 /* ipp.h in Headers */, 72220F25133305BB00FCA411 /* language.h in Headers */, 722A24F32178D091000CAB20 /* debug-private.h in Headers */, + 27A8096128A9B9D500B20BC8 /* dnssd.h in Headers */, 72220F41133305BB00FCA411 /* transcode.h in Headers */, 72220F44133305BB00FCA411 /* base.h in Headers */, 72220ECD1333056300FCA411 /* cups-private.h in Headers */, @@ -2240,6 +2253,7 @@ 270696091CADF3E200FFE5FB /* dir.c in Sources */, 2706960B1CADF3E200FFE5FB /* encode.c in Sources */, 2706960C1CADF3E200FFE5FB /* file.c in Sources */, + 27A8096528A9B9D500B20BC8 /* dnssd.c in Sources */, 2706960F1CADF3E200FFE5FB /* getputfile.c in Sources */, 270696101CADF3E200FFE5FB /* globals.c in Sources */, 270696111CADF3E200FFE5FB /* http-addr.c in Sources */, @@ -2360,6 +2374,7 @@ 274FF6B51333B1C400317ECB /* thread.c in Sources */, 274FF6B61333B1C400317ECB /* transcode.c in Sources */, 274FF6B71333B1C400317ECB /* usersys.c in Sources */, + 27A8096628A9B9D500B20BC8 /* dnssd.c in Sources */, 274FF6B81333B1C400317ECB /* util.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2444,6 +2459,7 @@ 72220F40133305BB00FCA411 /* transcode.c in Sources */, 72220F42133305BB00FCA411 /* usersys.c in Sources */, 72220F43133305BB00FCA411 /* util.c in Sources */, + 27A8096428A9B9D500B20BC8 /* dnssd.c in Sources */, 72CF95E318A13543000FCAE4 /* dest-job.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; From b4ad4fe4ad24a8b391ca04790fa5295a8a1783ec Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 18 Aug 2022 07:46:55 -0400 Subject: [PATCH 02/19] Prefix the libcups3 install to allow CUPS 2 and 3 to coexist (Issue #21) --- .gitignore | 2 +- CHANGES.md | 2 + Makedefs.in | 2 + Makefile | 12 +- configure | 66 +++++++-- configure.ac | 46 ++++-- cups/Makefile | 123 ++++++++-------- cups/cupspm.md | 6 +- cups.pc.in => cups3.pc.in | 0 doc/cupspm.epub | Bin 221550 -> 221671 bytes doc/cupspm.html | 15 +- tools/Makefile | 22 +-- xcode/libcups.xcodeproj/project.pbxproj | 136 +++++++++--------- .../xcshareddata/xcschemes/libcups.xcscheme | 4 +- 14 files changed, 264 insertions(+), 172 deletions(-) rename cups.pc.in => cups3.pc.in (100%) diff --git a/.gitignore b/.gitignore index 1817e0203..9be4f87fd 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ /config.log /config.status /configure~ -/cups.pc +/cups3.pc /Makedefs /cups/fuzzipp /cups/libcups.dylib diff --git a/CHANGES.md b/CHANGES.md index 48ba415df..be7d5802c 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -11,6 +11,8 @@ libcups v3.0b1 (Month DD, YYYY) - Now require ZLIB. - Now require POSIX or Windows threading support. - Now require the `poll` function (`WSAPoll` on Windows). +- Now install with a prefix by default to allow coexistance with CUPS 2.x + (Issue #21) - Added new `GENERATE-FILE` directive for `ipptool` test files. - Added new `ATTR-IF-DEFINED` and `ATTR-IF-NOT-DEFINED` directives to IPP data files (Issue #3) diff --git a/Makedefs.in b/Makedefs.in index 3c78bb098..4b4901107 100644 --- a/Makedefs.in +++ b/Makedefs.in @@ -61,8 +61,10 @@ LOCALTARGET = @LOCALTARGET@ # Libraries... # +CUPS_PC = @CUPS_PC@ LIBCUPS = @LIBCUPS@ LIBCUPS_STATIC = @LIBCUPS_STATIC@ +LINKCUPS = -L../cups @LINKCUPS@ # diff --git a/Makefile b/Makefile index 71f8a0e75..d33bed16f 100644 --- a/Makefile +++ b/Makefile @@ -76,9 +76,12 @@ install: echo Installing all in $$dir... ;\ (cd $$dir; $(MAKE) $(MFLAGS) install) || exit 1;\ done - echo Installing cups.pc file... + echo Installing $(CUPS_PC) file... $(INSTALL_DIR) $(BUILDROOT)$(libdir)/pkgconfig - $(INSTALL_DATA) cups.pc $(BUILDROOT)$(libdir)/pkgconfig/cups.pc + $(INSTALL_DATA) cups3.pc $(BUILDROOT)$(libdir)/pkgconfig/cups3.pc + if test "$(CUPS_PC)" = cups.pc; then \ + $(LN) cups3.pc $(BUILDROOT)$(libdir)/pkgconfig/cups.pc; \ + fi # @@ -90,7 +93,10 @@ uninstall: echo Uninstalling in $$dir... ;\ (cd $$dir; $(MAKE) $(MFLAGS) uninstall) || exit 1;\ done - $(RM) $(BUILDROOT)$(libdir)/pkgconfig/cups.pc + $(RM) $(BUILDROOT)$(libdir)/pkgconfig/cups3.pc + if test "$(CUPS_PC)" = cups.pc; then \ + $(RM) $(BUILDROOT)$(libdir)/pkgconfig/cups.pc; \ + fi -$(RMDIR) $(BUILDROOT)$(libdir)/pkgconfig diff --git a/configure b/configure index a46313d29..d82ad2119 100755 --- a/configure +++ b/configure @@ -655,6 +655,7 @@ CSFLAGS LIBCUPS_STATIC LIBCUPS INSTALL_STATIC +CUPS_PC PKGCONFIG_AVAHI PKGCONFIG_REQUIRES_PRIVATE PKGCONFIG_REQUIRES @@ -662,6 +663,7 @@ PKGCONFIG_LIBS_PRIVATE PKGCONFIG_LIBS PKGCONFIG_CFLAGS PKGCONFIG +LINKCUPS ARFLAGS LN RMDIR @@ -734,6 +736,7 @@ SHELL' ac_subst_files='' ac_user_opts=' enable_option_checking +enable_libcups3_prefix with_dnssd with_tls enable_static @@ -1374,6 +1377,8 @@ Optional Features: --disable-option-checking ignore unrecognized --enable/--with options --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-libcups3-prefix + do not add libcups3 prefix to header/library files --disable-static do not install static library --disable-shared do not install shared library --enable-debug turn on debugging, default=no @@ -4027,6 +4032,32 @@ INSTALL="$(pwd)/install-sh" printf "%s\n" "using $INSTALL" >&6; } +# Check whether --enable-libcups3-prefix was given. +if test ${enable_libcups3_prefix+y} +then : + enableval=$enable_libcups3_prefix; +fi + + +if test x$enable_libcups3_prefix != xno +then : + + CUPS_PC="cups3.pc" + INCLUDE_PREFIX="/libcups3" + LIBCUPS_BASE="libcups3" + LINKCUPS="-lcups3" + +else $as_nop + + CUPS_PC="cups.pc" + INCLUDE_PREFIX="" + LIBCUPS_BASE="libcups" + LINKCUPS="-lcups" + +fi + + + if test -n "$ac_tool_prefix"; then # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args. set dummy ${ac_tool_prefix}pkg-config; ac_word=$2 @@ -4137,7 +4168,7 @@ fi PKGCONFIG_CFLAGS="" -PKGCONFIG_LIBS="-L\${libdir} -lcups" +PKGCONFIG_LIBS="-L\${libdir} $LINKCUPS" PKGCONFIG_LIBS_PRIVATE="-lz -lm" PKGCONFIG_REQUIRES="" PKGCONFIG_REQUIRES_PRIVATE="zlib" @@ -5157,25 +5188,27 @@ then : fi +LIBCUPS_STATIC="$LIBCUPS_BASE.a" + if test x$enable_shared != xno then : case "$host_os_name" in #( linux* | gnu* | *bsd*) : - LIBCUPS="libcups.so.3" + LIBCUPS="$LIBCUPS_BASE.so.3" DSO="\$(CC)" DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared" ;; #( darwin*) : - LIBCUPS="libcups.3.dylib" + LIBCUPS="$LIBCUPS_BASE.3.dylib" DSO="\$(CC)" DSOFLAGS="$DSOFLAGS -Wl,-no_warn_inits -dynamiclib -single_module -lc" ;; #( sunos*) : - LIBCUPS="libcups.so.3" + LIBCUPS="$LIBCUPS_BASE.so.3" DSO="\$(CC)" DSOFLAGS="$DSOFLAGS -Wl,-h,\`basename \$@\` -G" ;; #( @@ -5183,7 +5216,7 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Warning: Shared libraries may not work, trying -shared option." >&5 printf "%s\n" "$as_me: Warning: Shared libraries may not work, trying -shared option." >&6;} - LIBCUPS="libcups.so.3" + LIBCUPS="$LIBCUPS_BASE.so.3" DSO="\$(CC)" DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared" ;; #( @@ -5197,20 +5230,17 @@ then : { printf "%s\n" "$as_me:${as_lineno-$LINENO}: Installing static libraries..." >&5 printf "%s\n" "$as_me: Installing static libraries..." >&6;} INSTALL_STATIC="install-static" - LIBCUPS_STATIC="libcups.a" else $as_nop INSTALL_STATIC="" - LIBCUPS_STATIC="" fi else $as_nop INSTALL_STATIC="" - LIBCUPS="libcups.a" - LIBCUPS_STATIC="" + LIBCUPS="$LIBCUPS_BASE.a" PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE" PKGCONFIG_LIBS_PRIVATE="" PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES $PKGCONFIG_REQUIRES_PRIVATE" @@ -5223,6 +5253,7 @@ fi + # Check whether --enable-debug was given. if test ${enable_debug+y} then : @@ -5446,6 +5477,7 @@ then : fi + if test "$prefix" = NONE then : @@ -5458,12 +5490,24 @@ else $as_nop fi +if test "$includedir" = NONE -o "$includedir" = "\${prefix}/include" +then : + + includedir="$realprefix/include$INCLUDE_PREFIX" + +fi +if test "$includedir" != "/usr/include" -a "$includedir" != "/usr/local/include" +then : + + PKGCONFIG_CFLAGS="-I\${includedir} $PKGCONFIG_CFLAGS" + +fi PKGCONFIG_REQUIRES="$(echo $PKGCONFIG_REQUIRES | sed -e '1,$s/,$//')" PKGCONFIG_REQUIRES_PRIVATE="$(echo $PKGCONFIG_REQUIRES_PRIVATE | sed -e '1,$s/,$//')" -ac_config_files="$ac_config_files Makedefs cups.pc packaging/libcups.list" +ac_config_files="$ac_config_files Makedefs cups3.pc packaging/libcups.list" cat >confcache <<\_ACEOF # This file is a shell script that caches the results of configure @@ -6152,7 +6196,7 @@ do case $ac_config_target in "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;; "Makedefs") CONFIG_FILES="$CONFIG_FILES Makedefs" ;; - "cups.pc") CONFIG_FILES="$CONFIG_FILES cups.pc" ;; + "cups3.pc") CONFIG_FILES="$CONFIG_FILES cups3.pc" ;; "packaging/libcups.list") CONFIG_FILES="$CONFIG_FILES packaging/libcups.list" ;; *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;; diff --git a/configure.ac b/configure.ac index 883cd23f0..7380e3c43 100644 --- a/configure.ac +++ b/configure.ac @@ -101,11 +101,28 @@ AC_SUBST([INSTALL]) AC_MSG_RESULT([using $INSTALL]) +dnl Library prefix... +AC_ARG_ENABLE([libcups3-prefix], AS_HELP_STRING([--disable-libcups3-prefix], [do not add libcups3 prefix to header/library files])) + +AS_IF([test x$enable_libcups3_prefix != xno], [ + CUPS_PC="cups3.pc" + INCLUDE_PREFIX="/libcups3" + LIBCUPS_BASE="libcups3" + LINKCUPS="-lcups3" +], [ + CUPS_PC="cups.pc" + INCLUDE_PREFIX="" + LIBCUPS_BASE="libcups" + LINKCUPS="-lcups" +]) +AC_SUBST([LINKCUPS]) + + dnl Check for pkg-config, which is used for some other tests later on... AC_PATH_TOOL([PKGCONFIG], [pkg-config]) PKGCONFIG_CFLAGS="" -PKGCONFIG_LIBS="-L\${libdir} -lcups" +PKGCONFIG_LIBS="-L\${libdir} $LINKCUPS" PKGCONFIG_LIBS_PRIVATE="-lz -lm" PKGCONFIG_REQUIRES="" PKGCONFIG_REQUIRES_PRIVATE="zlib" @@ -396,22 +413,24 @@ dnl Library targets... AC_ARG_ENABLE([static], AS_HELP_STRING([--disable-static], [do not install static library])) AC_ARG_ENABLE([shared], AS_HELP_STRING([--disable-shared], [do not install shared library])) +LIBCUPS_STATIC="$LIBCUPS_BASE.a" + AS_IF([test x$enable_shared != xno], [ AS_CASE(["$host_os_name"], [linux* | gnu* | *bsd*], [ - LIBCUPS="libcups.so.3" + LIBCUPS="$LIBCUPS_BASE.so.3" DSO="\$(CC)" DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared" ], [darwin*], [ - LIBCUPS="libcups.3.dylib" + LIBCUPS="$LIBCUPS_BASE.3.dylib" DSO="\$(CC)" DSOFLAGS="$DSOFLAGS -Wl,-no_warn_inits -dynamiclib -single_module -lc" ], [sunos*], [ - LIBCUPS="libcups.so.3" + LIBCUPS="$LIBCUPS_BASE.so.3" DSO="\$(CC)" DSOFLAGS="$DSOFLAGS -Wl,-h,\`basename \$@\` -G" ], [*], [ AC_MSG_NOTICE([Warning: Shared libraries may not work, trying -shared option.]) - LIBCUPS="libcups.so.3" + LIBCUPS="$LIBCUPS_BASE.so.3" DSO="\$(CC)" DSOFLAGS="$DSOFLAGS -Wl,-soname,\`basename \$@\` -shared" ]) @@ -419,21 +438,19 @@ AS_IF([test x$enable_shared != xno], [ AS_IF([test x$enable_static != xno], [ AC_MSG_NOTICE([Installing static libraries...]) INSTALL_STATIC="install-static" - LIBCUPS_STATIC="libcups.a" ], [ INSTALL_STATIC="" - LIBCUPS_STATIC="" ]) ], [ INSTALL_STATIC="" - LIBCUPS="libcups.a" - LIBCUPS_STATIC="" + LIBCUPS="$LIBCUPS_BASE.a" PKGCONFIG_LIBS="$PKGCONFIG_LIBS $PKGCONFIG_LIBS_PRIVATE" PKGCONFIG_LIBS_PRIVATE="" PKGCONFIG_REQUIRES="$PKGCONFIG_REQUIRES $PKGCONFIG_REQUIRES_PRIVATE" PKGCONFIG_REQUIRES_PRIVATE="" ]) +AC_SUBST([CUPS_PC]) AC_SUBST([INSTALL_STATIC]) AC_SUBST([LIBCUPS]) AC_SUBST([LIBCUPS_STATIC]) @@ -548,7 +565,8 @@ AC_ARG_WITH([ldflags], AS_HELP_STRING([--with-ldflags=...], [Specify additional LDFLAGS="$withval $LDFLAGS" ]) -dnl State and run directories for root servers... + +dnl Fix prefix and includedir... AS_IF([test "$prefix" = NONE], [ # Default prefix isn't bound until AC_OUTPUT... realprefix="/usr/local" @@ -556,6 +574,12 @@ AS_IF([test "$prefix" = NONE], [ realprefix="$prefix" ]) +AS_IF([test "$includedir" = NONE -o "$includedir" = "\${prefix}/include"], [ + includedir="$realprefix/include$INCLUDE_PREFIX" +]) +AS_IF([test "$includedir" != "/usr/include" -a "$includedir" != "/usr/local/include"], [ + PKGCONFIG_CFLAGS="-I\${includedir} $PKGCONFIG_CFLAGS" +]) dnl Clean up pkg-config "requires" content... [PKGCONFIG_REQUIRES="$(echo $PKGCONFIG_REQUIRES | sed -e '1,$s/,$//')"] @@ -563,5 +587,5 @@ dnl Clean up pkg-config "requires" content... dnl Provide autoconf with a list of files to generate and output them... -AC_CONFIG_FILES([Makedefs cups.pc packaging/libcups.list]) +AC_CONFIG_FILES([Makedefs cups3.pc packaging/libcups.list]) AC_OUTPUT diff --git a/cups/Makefile b/cups/Makefile index cb899f79f..5767b5078 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -102,7 +102,7 @@ HEADERS = \ # LIBTARGETS = \ - libcups.a \ + $(LIBCUPS_STATIC) \ $(LIBCUPS) UNITTARGETS = \ @@ -190,16 +190,16 @@ install: all $(INSTALL_STATIC) for file in $(HEADERS); do \ $(INSTALL_DATA) $$file $(BUILDROOT)$(includedir)/cups; \ done - echo "Installing libraries to $(BUILDROOT)$(libdir)..." + echo "Installing library to $(BUILDROOT)$(libdir)..." $(INSTALL_DIR) $(BUILDROOT)$(libdir) $(INSTALL_LIB) $(LIBCUPS) $(BUILDROOT)$(libdir) - if test $(LIBCUPS) = "libcups.so.3"; then \ + if test $(LIBCUPS) = "libcups.so.3" -o $(LIBCUPS) = "libcups3.so.3"; then \ $(RM) $(BUILDROOT)$(libdir)/`basename $(LIBCUPS) .3`; \ $(LN) $(LIBCUPS) $(BUILDROOT)$(libdir)/`basename $(LIBCUPS) .3`; \ fi - if test $(LIBCUPS) = "libcups.3.dylib"; then \ - $(RM) $(BUILDROOT)$(libdir)/libcups.dylib; \ - $(LN) $(LIBCUPS) $(BUILDROOT)$(libdir)/libcups.dylib; \ + if test $(LIBCUPS) = "libcups.3.dylib" -o $(LIBCUPS) = "libcups3.3.dylib"; then \ + $(RM) $(BUILDROOT)$(libdir)/`basename $(LIBCUPS) .3.dylib`.dylib; \ + $(LN) $(LIBCUPS) $(BUILDROOT)$(libdir)/`basename $(LIBCUPS) .3.dylib`.dylib; \ fi if test "x$(SYMROOT)" != "x"; then \ echo "Copying debug symbols to $(SYMROOT)..."; \ @@ -209,10 +209,10 @@ install: all $(INSTALL_STATIC) fi install-static: - echo "Installing static libraries to $(BUILDROOT)$(libdir)..." + echo "Installing static library to $(BUILDROOT)$(libdir)..." $(INSTALL_DIR) $(BUILDROOT)$(libdir) - $(INSTALL_LIB) libcups.a $(BUILDROOT)$(libdir) - $(RANLIB) $(BUILDROOT)$(libdir)/libcups.a + $(INSTALL_LIB) $(LIBCUPS_STATIC) $(BUILDROOT)$(libdir) + $(RANLIB) $(BUILDROOT)$(libdir)/$(LIBCUPS_STATIC) # @@ -220,11 +220,14 @@ install-static: # uninstall: - $(RM) $(BUILDROOT)$(libdir)/libcups.3.dylib - $(RM) $(BUILDROOT)$(libdir)/libcups.a - $(RM) $(BUILDROOT)$(libdir)/libcups.dylib - $(RM) $(BUILDROOT)$(libdir)/libcups.so - $(RM) $(BUILDROOT)$(libdir)/libcups.so.3 + $(RM) $(BUILDROOT)$(libdir)/$(LIBCUPS) + $(RM) $(BUILDROOT)$(libdir)/$(LIBCUPS_STATIC) + if test $(LIBCUPS) = "libcups.so.3" -o $(LIBCUPS) = "libcups3.so.3"; then \ + $(RM) $(BUILDROOT)$(libdir)/`basename $(LIBCUPS) .3`; \ + fi + if test $(LIBCUPS) = "libcups.3.dylib" -o $(LIBCUPS) = "libcups3.3.dylib"; then \ + $(RM) $(BUILDROOT)$(libdir)/`basename $(LIBCUPS) .3.dylib`.dylib; \ + fi -$(RMDIR) $(BUILDROOT)$(libdir) for file in $(HEADERS); do \ $(RM) $(BUILDROOT)$(includedir)/cups/$$file; \ @@ -233,10 +236,10 @@ uninstall: # -# libcups.so.3 +# libcups.so.3 / libcups3.so.3 # -libcups.so.3: $(LIBOBJS) +libcups.so.3 libcups3.so.3: $(LIBOBJS) echo Linking $@... $(CC) $(DSOFLAGS) $(OPTIM) -o $@ $(LIBOBJS) $(LIBS) $(RM) `basename $@ .3` @@ -244,24 +247,24 @@ libcups.so.3: $(LIBOBJS) # -# libcups.3.dylib +# libcups.3.dylib / libcups3.3.dylib # -libcups.3.dylib: $(LIBOBJS) +libcups.3.dylib libcups3.3.dylib: $(LIBOBJS) echo Linking $@... $(CC) $(DSOFLAGS) $(OPTIM) -o $@ -install_name $(libdir)/$@ \ -current_version 3.0.0 -compatibility_version 3.0.0 \ $(LIBOBJS) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ - $(RM) libcups.dylib - $(LN) $@ libcups.dylib + $(RM) `basename $@ .3.dylib`.dylib + $(LN) $@ `basename $@ .3.dylib`.dylib # -# libcups.a +# libcups.a / libcups3.a # -libcups.a: $(LIBOBJS) +libcups.a / libcups3.a: $(LIBOBJS) echo Archiving $@... $(RM) $@ $(AR) $(ARFLAGS) $@ $(LIBOBJS) @@ -287,9 +290,9 @@ libcups3.def: $(LIBOBJS) $(IMAGEOBJS) Makefile # fuzzipp (dependency on static CUPS library is intentional) # -fuzzipp: fuzzipp.o libcups.a +fuzzipp: fuzzipp.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ fuzzipp.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ fuzzipp.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -297,9 +300,9 @@ fuzzipp: fuzzipp.o libcups.a # rasterbench (dependency on static CUPS library is intentional) # -rasterbench: rasterbench.o libcups.a +rasterbench: rasterbench.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ rasterbench.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ rasterbench.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -307,9 +310,9 @@ rasterbench: rasterbench.o libcups.a # testarray (dependency on static CUPS library is intentional) # -testarray: testarray.o libcups.a +testarray: testarray.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testarray.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testarray.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -317,9 +320,9 @@ testarray: testarray.o libcups.a # testclient (dependency on static libraries is intentional) # -testclient: testclient.o libcups.a +testclient: testclient.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testclient.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testclient.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -327,9 +330,9 @@ testclient: testclient.o libcups.a # testcreds (dependency on static CUPS library is intentional) # -testcreds: testcreds.o libcups.a +testcreds: testcreds.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testcreds.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testcreds.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -337,9 +340,9 @@ testcreds: testcreds.o libcups.a # testcups (dependency on static CUPS library is intentional) # -testcups: testcups.o libcups.a +testcups: testcups.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testcups.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testcups.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -347,9 +350,9 @@ testcups: testcups.o libcups.a # testdest (dependency on static CUPS library is intentional) # -testdest: testdest.o libcups.a +testdest: testdest.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testdest.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testdest.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -357,9 +360,9 @@ testdest: testdest.o libcups.a # testfile (dependency on static CUPS library is intentional) # -testfile: testfile.o libcups.a +testfile: testfile.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testfile.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testfile.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -367,9 +370,9 @@ testfile: testfile.o libcups.a # testgetdests (dependency on static CUPS library is intentional) # -testgetdests: testgetdests.o libcups.a +testgetdests: testgetdests.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testgetdests.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testgetdests.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -377,9 +380,9 @@ testgetdests: testgetdests.o libcups.a # testhttp (dependency on static CUPS library is intentional) # -testhttp: testhttp.o libcups.a +testhttp: testhttp.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testhttp.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testhttp.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -387,9 +390,9 @@ testhttp: testhttp.o libcups.a # testipp (dependency on static CUPS library is intentional) # -testipp: testipp.o libcups.a +testipp: testipp.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testipp.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testipp.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -397,9 +400,9 @@ testipp: testipp.o libcups.a # testi18n (dependency on static CUPS library is intentional) # -testi18n: testi18n.o libcups.a +testi18n: testi18n.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testi18n.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testi18n.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -407,9 +410,9 @@ testi18n: testi18n.o libcups.a # testlang (dependency on static CUPS library is intentional) # -testlang: testlang.o libcups.a +testlang: testlang.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testlang.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testlang.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ echo Creating locale directory structure... $(RM) -r locale @@ -428,9 +431,9 @@ testlang: testlang.o libcups.a # testoptions (dependency on static CUPS library is intentional) # -testoptions: testoptions.o libcups.a +testoptions: testoptions.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testoptions.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testoptions.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -438,9 +441,9 @@ testoptions: testoptions.o libcups.a # testpwg (dependency on static CUPS library is intentional) # -testpwg: testpwg.o libcups.a test.ppd +testpwg: testpwg.o $(LIBCUPS_STATIC) test.ppd echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testpwg.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testpwg.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ echo Running PWG API tests... ./testpwg test.ppd @@ -450,9 +453,9 @@ testpwg: testpwg.o libcups.a test.ppd # testraster (dependency on static CUPS library is intentional) # -testraster: testraster.o libcups.a +testraster: testraster.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testraster.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testraster.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -460,9 +463,9 @@ testraster: testraster.o libcups.a # testtestpage (dependency on static CUPS library is intentional) # -testtestpage: testtestpage.o libcups.a +testtestpage: testtestpage.o $(LIBCUPS_STATIC) echo Compiling $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testtestpage.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testtestpage.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -470,9 +473,9 @@ testtestpage: testtestpage.o libcups.a # testthreads (dependency on static CUPS library is intentional) # -testthreads: testthreads.o libcups.a +testthreads: testthreads.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ testthreads.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testthreads.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -480,9 +483,9 @@ testthreads: testthreads.o libcups.a # tlscheck (dependency on static CUPS library is intentional) # -tlscheck: tlscheck.o libcups.a +tlscheck: tlscheck.o $(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ tlscheck.o libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ tlscheck.o $(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ diff --git a/cups/cupspm.md b/cups/cupspm.md index d67409613..d7a50d644 100644 --- a/cups/cupspm.md +++ b/cups/cupspm.md @@ -94,8 +94,8 @@ Click *Next* and enter a name for the project, for example "firstcups". Click *Next* and choose a project directory. The click *Next* to create the project. In the project window, click on the *Build Phases* group and expand the -*Link Binary with Libraries* section. Click *+*, type "libcups" to show the -library, and then double-click on `libcups.tbd`. +*Link Binary with Libraries* section. Click *+*, choose "Other...", and then +find and choose the `libcups3.dylib` file in `/usr/local/lib`. Finally, click on the `main.c` file in the sidebar and copy the example program to the file. Build and run (CMD+R) to see the list of destinations. @@ -107,7 +107,7 @@ From the command-line, create a file called `simple.c` using your favorite editor, copy the example to this file, and save. Then run the following command to compile it with GCC and run it: - gcc -o simple `pkg-config --cflags cups` simple.c `pkg-config --libs cups` + gcc -o simple `pkg-config --cflags cups3` simple.c `pkg-config --libs cups3` ./simple The `pkg-config` command provides the compiler flags diff --git a/cups.pc.in b/cups3.pc.in similarity index 100% rename from cups.pc.in rename to cups3.pc.in diff --git a/doc/cupspm.epub b/doc/cupspm.epub index f8c0ea659a9e9726fa602d83972983d5820e40e2..4ad7cc4c896e95571d2bdb5b342d5c1a34916a27 100644 GIT binary patch delta 71319 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�e(i%L{Me`_B5QldndOH=1gSs*(^!(ESO?0F>(eN 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 F{{iINF)9E6 diff --git a/doc/cupspm.html b/doc/cupspm.html index fa6b7cfc3..eb8694fea 100644 --- a/doc/cupspm.html +++ b/doc/cupspm.html @@ -382,6 +382,7 @@

Contents

  • cupsGetNamedDest
  • cupsGetOption
  • cupsGetPassword
  • +
  • cupsGetRand
  • cupsGetResponse
  • cupsGetServer
  • cupsGetUser
  • @@ -831,11 +832,11 @@

    Compiling Progra

    Compiling with Xcode

    In Xcode, choose New Project... from the File menu (or press SHIFT+CMD+N), then select the Command Line Tool under the macOS Application project type. Click Next and enter a name for the project, for example "firstcups". Click Next and choose a project directory. The click Next to create the project.

    -

    In the project window, click on the Build Phases group and expand the Link Binary with Libraries section. Click +, type "libcups" to show the library, and then double-click on libcups.tbd.

    +

    In the project window, click on the Build Phases group and expand the Link Binary with Libraries section. Click +, choose "Other...", and then find and choose the libcups3.dylib file in /usr/local/lib.

    Finally, click on the main.c file in the sidebar and copy the example program to the file. Build and run (CMD+R) to see the list of destinations.

    Compiling with GCC

    From the command-line, create a file called simple.c using your favorite editor, copy the example to this file, and save. Then run the following command to compile it with GCC and run it:

    -
    gcc -o simple `pkg-config --cflags cups` simple.c `pkg-config --libs cups`
    +
    gcc -o simple `pkg-config --cflags cups3` simple.c `pkg-config --libs cups3`
     ./simple
     

    The pkg-config command provides the compiler flags (pkg-config --cflags cups) and libraries (pkg-config --libs cups) needed for the local system.

    @@ -3574,6 +3575,16 @@

    Discussion

    thread in a program. Multi-threaded programs that override the setting via the cupsSetPasswordCB function need to do so in each thread for the same function to be used.

    +

    cupsGetRand

    +

    Return a 32-bit pseudo-random number.

    +

    +unsigned cupsGetRand(void);

    +

    Return Value

    +

    Random number

    +

    Discussion

    +

    This function returns a 32-bit pseudo-random number suitable for use as +one-time identifiers or nonces. The random numbers are generated/seeded +using system entropy.

    cupsGetResponse

    Get a response to an IPP request.

    diff --git a/tools/Makefile b/tools/Makefile index d5fd32d91..adc3c593b 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -137,7 +137,7 @@ test: local ippeveprinter: ippeveprinter.o ../cups/$(LIBCUPS) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippeveprinter.o -L../cups -lcups $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippeveprinter.o $(LINKCUPS) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -145,9 +145,9 @@ ippeveprinter: ippeveprinter.o ../cups/$(LIBCUPS) # ippeveprinter-static # -ippeveprinter-static: ippeveprinter.o ../cups/libcups.a +ippeveprinter-static: ippeveprinter.o ../cups/$(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippeveprinter.o $(PAMLIBS) ../cups/libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippeveprinter.o $(PAMLIBS) ../cups/$(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -157,7 +157,7 @@ ippeveprinter-static: ippeveprinter.o ../cups/libcups.a ippevepcl: ippevepcl.o ../cups/$(LIBCUPS) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippevepcl.o -L../cups -lcups $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippevepcl.o $(LINKCUPS) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -167,7 +167,7 @@ ippevepcl: ippevepcl.o ../cups/$(LIBCUPS) ippeveps: ippeveps.o ../cups/$(LIBCUPS) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippeveps.o -L../cups -lcups $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippeveps.o $(LINKCUPS) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -177,7 +177,7 @@ ippeveps: ippeveps.o ../cups/$(LIBCUPS) ippfind: ippfind.o ../cups/$(LIBCUPS) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippfind.o $(DNSSDLIBS) -L../cups -lcups $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippfind.o $(DNSSDLIBS) $(LINKCUPS) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -185,9 +185,9 @@ ippfind: ippfind.o ../cups/$(LIBCUPS) # ippfind-static # -ippfind-static: ippfind.o ../cups/libcups.a +ippfind-static: ippfind.o ../cups/$(LIBCUPS_STATIC) echo Linking $@ - $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippfind.o ../cups/libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ ippfind.o ../cups/$(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -197,7 +197,7 @@ ippfind-static: ippfind.o ../cups/libcups.a ipptool: ipptool.o ../cups/$(LIBCUPS) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ ipptool.o -L../cups -lcups $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ ipptool.o $(LINKCUPS) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ @@ -205,9 +205,9 @@ ipptool: ipptool.o ../cups/$(LIBCUPS) # ipptool-static # -ipptool-static: ipptool.o ../cups/libcups.a +ipptool-static: ipptool.o ../cups/$(LIBCUPS_STATIC) echo Linking $@... - $(CC) $(LDFLAGS) $(OPTIM) -o $@ ipptool.o ../cups/libcups.a $(LIBS) + $(CC) $(LDFLAGS) $(OPTIM) -o $@ ipptool.o ../cups/$(LIBCUPS_STATIC) $(LIBS) $(CODE_SIGN) $(CSFLAGS) $@ diff --git a/xcode/libcups.xcodeproj/project.pbxproj b/xcode/libcups.xcodeproj/project.pbxproj index b82318da3..24042f61f 100644 --- a/xcode/libcups.xcodeproj/project.pbxproj +++ b/xcode/libcups.xcodeproj/project.pbxproj @@ -130,9 +130,9 @@ 273B1EB5226B3E5200428143 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC5D1926750C000F61D3 /* Security.framework */; }; 273B1EBF226B3EF300428143 /* ippevepcl.c in Sources */ = {isa = PBXBuildFile; fileRef = 273B1EBE226B3EE300428143 /* ippevepcl.c */; }; 273B1EC0226B3EFF00428143 /* ippeveps.c in Sources */ = {isa = PBXBuildFile; fileRef = 273B1EBC226B3EE300428143 /* ippeveps.c */; }; - 273B1EC7226B41F700428143 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; }; - 273B1ECA226B420C00428143 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; }; - 273B1ECD226B421E00428143 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; }; + 273B1EC7226B41F700428143 /* libcups3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups3.dylib */; }; + 273B1ECA226B420C00428143 /* libcups3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups3.dylib */; }; + 273B1ECD226B421E00428143 /* libcups3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups3.dylib */; }; 273BF6C71333B5370022CAAB /* testcups.c in Sources */ = {isa = PBXBuildFile; fileRef = 273BF6C61333B5370022CAAB /* testcups.c */; }; 274770D72345342B0089BC31 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72A4332F155844CF002E172D /* libcups_static.a */; }; 274770D82345342B0089BC31 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 278C58E5136B64AF00836530 /* CoreFoundation.framework */; }; @@ -167,7 +167,7 @@ 274FF6B81333B1C400317ECB /* util.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220F09133305BB00FCA411 /* util.c */; }; 274FF6C61333B1C400317ECB /* dir.h in Headers */ = {isa = PBXBuildFile; fileRef = 72220ED4133305BB00FCA411 /* dir.h */; settings = {ATTRIBUTES = (); }; }; 276683FA1337F7A9000D33D0 /* ipptool.c in Sources */ = {isa = PBXBuildFile; fileRef = 276683F91337F7A9000D33D0 /* ipptool.c */; }; - 276683FD1337F7B8000D33D0 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; }; + 276683FD1337F7B8000D33D0 /* libcups3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups3.dylib */; }; 2767FC5219266A36000F61D3 /* testdest.c in Sources */ = {isa = PBXBuildFile; fileRef = 2767FC5119266A36000F61D3 /* testdest.c */; }; 2767FC58192674E0000F61D3 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72A4332F155844CF002E172D /* libcups_static.a */; }; 2767FC5F1926750C000F61D3 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC591926750C000F61D3 /* CoreFoundation.framework */; }; @@ -402,7 +402,7 @@ 72CF95E318A13543000FCAE4 /* dest-job.c in Sources */ = {isa = PBXBuildFile; fileRef = 72CF95E018A13543000FCAE4 /* dest-job.c */; }; 72CF95E418A13543000FCAE4 /* dest-localization.c in Sources */ = {isa = PBXBuildFile; fileRef = 72CF95E118A13543000FCAE4 /* dest-localization.c */; }; 72CF95E518A13543000FCAE4 /* dest-options.c in Sources */ = {isa = PBXBuildFile; fileRef = 72CF95E218A13543000FCAE4 /* dest-options.c */; }; - 72CF95EC18A19134000FCAE4 /* libcups.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups.dylib */; }; + 72CF95EC18A19134000FCAE4 /* libcups3.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 72220EAE1333047D00FCA411 /* libcups3.dylib */; }; 72CF95F318A19165000FCAE4 /* ippfind.c in Sources */ = {isa = PBXBuildFile; fileRef = 72CF95F218A19165000FCAE4 /* ippfind.c */; }; /* End PBXBuildFile section */ @@ -919,7 +919,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ - 2706965A1CADF3E200FFE5FB /* libcups_ios.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcups_ios.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 2706965A1CADF3E200FFE5FB /* libcups3_ios.a */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcups3_ios.a; sourceTree = BUILT_PRODUCTS_DIR; }; 270B267E17F5C06700C8A3A9 /* tls-gnutls.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = "tls-gnutls.c"; path = "../cups/tls-gnutls.c"; sourceTree = ""; }; 270D02241D707E0200EA9403 /* testcreds */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testcreds; sourceTree = BUILT_PRODUCTS_DIR; }; 270D02251D707E3700EA9403 /* testcreds.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testcreds.c; path = ../cups/testcreds.c; sourceTree = ""; }; @@ -978,7 +978,7 @@ 27D3968227BB390D003D3D8E /* libresolv.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libresolv.tbd; path = usr/lib/libresolv.tbd; sourceTree = SDKROOT; }; 27F89DA21B3AC43B00E5A4B7 /* testraster.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = testraster.c; path = ../cups/testraster.c; sourceTree = ""; }; 720E854120164E7A00C6C411 /* ipp-file.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = "ipp-file.c"; path = "../cups/ipp-file.c"; sourceTree = ""; }; - 72220EAE1333047D00FCA411 /* libcups.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcups.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + 72220EAE1333047D00FCA411 /* libcups3.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libcups3.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 72220EB81333056300FCA411 /* array.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = array.c; path = ../cups/array.c; sourceTree = ""; }; 72220EB91333056300FCA411 /* array.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = array.h; path = ../cups/array.h; sourceTree = ""; }; 72220EBB1333056300FCA411 /* auth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = auth.c; path = ../cups/auth.c; sourceTree = ""; }; @@ -1126,7 +1126,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 273B1EC7226B41F700428143 /* libcups.dylib in Frameworks */, + 273B1EC7226B41F700428143 /* libcups3.dylib in Frameworks */, 273B1EA1226B3E4800428143 /* CoreFoundation.framework in Frameworks */, 273B1EA2226B3E4800428143 /* libresolv.dylib in Frameworks */, 273B1EA3226B3E4800428143 /* libz.dylib in Frameworks */, @@ -1138,7 +1138,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 273B1ECD226B421E00428143 /* libcups.dylib in Frameworks */, + 273B1ECD226B421E00428143 /* libcups3.dylib in Frameworks */, 273B1EB2226B3E5200428143 /* CoreFoundation.framework in Frameworks */, 273B1EB3226B3E5200428143 /* libresolv.dylib in Frameworks */, 273B1EB4226B3E5200428143 /* libz.dylib in Frameworks */, @@ -1194,7 +1194,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 276683FD1337F7B8000D33D0 /* libcups.dylib in Frameworks */, + 276683FD1337F7B8000D33D0 /* libcups3.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1384,7 +1384,7 @@ buildActionMask = 2147483647; files = ( 279AE6F52395B80F004DD600 /* libpam.tbd in Frameworks */, - 273B1ECA226B420C00428143 /* libcups.dylib in Frameworks */, + 273B1ECA226B420C00428143 /* libcups3.dylib in Frameworks */, 2767FC6619267538000F61D3 /* CoreFoundation.framework in Frameworks */, 2767FC6719267538000F61D3 /* libresolv.dylib in Frameworks */, 2767FC6819267538000F61D3 /* libz.dylib in Frameworks */, @@ -1411,7 +1411,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( - 72CF95EC18A19134000FCAE4 /* libcups.dylib in Frameworks */, + 72CF95EC18A19134000FCAE4 /* libcups3.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1480,7 +1480,7 @@ 72A4332F155844CF002E172D /* libcups_static.a */, 72CF95F118A19134000FCAE4 /* ipptool copy */, 2767FC5019266A0D000F61D3 /* testdest */, - 2706965A1CADF3E200FFE5FB /* libcups_ios.a */, + 2706965A1CADF3E200FFE5FB /* libcups3_ios.a */, 724FA5481CC037370092477B /* testarray */, 724FA5811CC037810092477B /* testfile */, 724FA5941CC037980092477B /* testi18n */, @@ -1603,7 +1603,7 @@ 278C58E6136B64B000836530 /* Kerberos.framework */, 278C58E7136B64B000836530 /* Security.framework */, 278C58E8136B64B000836530 /* SystemConfiguration.framework */, - 72220EAE1333047D00FCA411 /* libcups.dylib */, + 72220EAE1333047D00FCA411 /* libcups3.dylib */, ); name = Frameworks; sourceTree = ""; @@ -1736,9 +1736,9 @@ /* End PBXHeadersBuildPhase section */ /* Begin PBXNativeTarget section */ - 270695FD1CADF3E200FFE5FB /* libcups_ios */ = { + 270695FD1CADF3E200FFE5FB /* libcups3_ios */ = { isa = PBXNativeTarget; - buildConfigurationList = 270696571CADF3E200FFE5FB /* Build configuration list for PBXNativeTarget "libcups_ios" */; + buildConfigurationList = 270696571CADF3E200FFE5FB /* Build configuration list for PBXNativeTarget "libcups3_ios" */; buildPhases = ( 270695FE1CADF3E200FFE5FB /* Sources */, 270696331CADF3E200FFE5FB /* Frameworks */, @@ -1748,9 +1748,9 @@ ); dependencies = ( ); - name = libcups_ios; + name = libcups3_ios; productName = libcups; - productReference = 2706965A1CADF3E200FFE5FB /* libcups_ios.a */; + productReference = 2706965A1CADF3E200FFE5FB /* libcups3_ios.a */; productType = "com.apple.product-type.library.dynamic"; }; 270D02131D707E0200EA9403 /* testcreds */ = { @@ -1861,9 +1861,9 @@ productReference = 274770E02345342B0089BC31 /* testthreads */; productType = "com.apple.product-type.tool"; }; - 274FF6891333B1C400317ECB /* libcups_static */ = { + 274FF6891333B1C400317ECB /* libcups3_static */ = { isa = PBXNativeTarget; - buildConfigurationList = 274FF6DD1333B1C400317ECB /* Build configuration list for PBXNativeTarget "libcups_static" */; + buildConfigurationList = 274FF6DD1333B1C400317ECB /* Build configuration list for PBXNativeTarget "libcups3_static" */; buildPhases = ( 274FF68A1333B1C400317ECB /* Sources */, 274FF6B91333B1C400317ECB /* Frameworks */, @@ -1873,7 +1873,7 @@ ); dependencies = ( ); - name = libcups_static; + name = libcups3_static; productName = libcups; productReference = 72A4332F155844CF002E172D /* libcups_static.a */; productType = "com.apple.product-type.library.dynamic"; @@ -1968,9 +1968,9 @@ productReference = 27D3967527BA81D3003D3D8E /* testtestpage */; productType = "com.apple.product-type.tool"; }; - 72220EAD1333047D00FCA411 /* libcups */ = { + 72220EAD1333047D00FCA411 /* libcups3 */ = { isa = PBXNativeTarget; - buildConfigurationList = 72220EB21333047D00FCA411 /* Build configuration list for PBXNativeTarget "libcups" */; + buildConfigurationList = 72220EB21333047D00FCA411 /* Build configuration list for PBXNativeTarget "libcups3" */; buildPhases = ( 72220EAA1333047D00FCA411 /* Sources */, 72220EAB1333047D00FCA411 /* Frameworks */, @@ -1980,9 +1980,9 @@ ); dependencies = ( ); - name = libcups; + name = libcups3; productName = libcups; - productReference = 72220EAE1333047D00FCA411 /* libcups.dylib */; + productReference = 72220EAE1333047D00FCA411 /* libcups3.dylib */; productType = "com.apple.product-type.library.dynamic"; }; 724FA5371CC037370092477B /* testarray */ = { @@ -2212,9 +2212,9 @@ targets = ( 274FF5DE13332D3000317ECB /* All */, 273BF6D91333B6260022CAAB /* Tests */, - 72220EAD1333047D00FCA411 /* libcups */, - 270695FD1CADF3E200FFE5FB /* libcups_ios */, - 274FF6891333B1C400317ECB /* libcups_static */, + 72220EAD1333047D00FCA411 /* libcups3 */, + 270695FD1CADF3E200FFE5FB /* libcups3_ios */, + 274FF6891333B1C400317ECB /* libcups3_static */, 2778BBC9275DA09B0070DA11 /* fuzzipp */, 273B1E9A226B3E4800428143 /* ippevepcl */, 726AD6F6135E88F0002C930D /* ippeveprinter */, @@ -2557,7 +2557,7 @@ /* Begin PBXTargetDependency section */ 270D02141D707E0200EA9403 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 270D02151D707E0200EA9403 /* PBXContainerItemProxy */; }; 270D02281D707E5100EA9403 /* PBXTargetDependency */ = { @@ -2567,7 +2567,7 @@ }; 271284911CC11FA500E517C7 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 271284901CC11FA500E517C7 /* PBXContainerItemProxy */; }; 2712849F1CC11FA500E517C7 /* PBXTargetDependency */ = { @@ -2602,7 +2602,7 @@ }; 271286581CC1309000E517C7 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 271286591CC1309000E517C7 /* PBXContainerItemProxy */; }; 271286E01CC13EF400E517C7 /* PBXTargetDependency */ = { @@ -2622,27 +2622,27 @@ }; 273B1EC6226B41E600428143 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 72220EAD1333047D00FCA411 /* libcups */; + target = 72220EAD1333047D00FCA411 /* libcups3 */; targetProxy = 273B1EC5226B41E600428143 /* PBXContainerItemProxy */; }; 273B1EC9226B420500428143 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 72220EAD1333047D00FCA411 /* libcups */; + target = 72220EAD1333047D00FCA411 /* libcups3 */; targetProxy = 273B1EC8226B420500428143 /* PBXContainerItemProxy */; }; 273B1ECC226B421700428143 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 72220EAD1333047D00FCA411 /* libcups */; + target = 72220EAD1333047D00FCA411 /* libcups3 */; targetProxy = 273B1ECB226B421700428143 /* PBXContainerItemProxy */; }; 273BF6C91333B5410022CAAB /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 273BF6C81333B5410022CAAB /* PBXContainerItemProxy */; }; 274770D22345342B0089BC31 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 274770D32345342B0089BC31 /* PBXContainerItemProxy */; }; 274770E42345347D0089BC31 /* PBXTargetDependency */ = { @@ -2652,12 +2652,12 @@ }; 274FF5E313332D4300317ECB /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 72220EAD1333047D00FCA411 /* libcups */; + target = 72220EAD1333047D00FCA411 /* libcups3 */; targetProxy = 274FF5E213332D4300317ECB /* PBXContainerItemProxy */; }; 276683FC1337F7B3000D33D0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 72220EAD1333047D00FCA411 /* libcups */; + target = 72220EAD1333047D00FCA411 /* libcups3 */; targetProxy = 276683FB1337F7B3000D33D0 /* PBXContainerItemProxy */; }; 276683FF1337F7C5000D33D0 /* PBXTargetDependency */ = { @@ -2667,7 +2667,7 @@ }; 2767FC4719266A0D000F61D3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 2767FC4819266A0D000F61D3 /* PBXContainerItemProxy */; }; 2767FC5619267469000F61D3 /* PBXTargetDependency */ = { @@ -2677,7 +2677,7 @@ }; 2778BBCA275DA09B0070DA11 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 2778BBCB275DA09B0070DA11 /* PBXContainerItemProxy */; }; 2778BBDD275DA0ED0070DA11 /* PBXTargetDependency */ = { @@ -2692,12 +2692,12 @@ }; 278C58D8136B642F00836530 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 278C58D7136B642F00836530 /* PBXContainerItemProxy */; }; 27D3966927BA81D3003D3D8E /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 27D3966A27BA81D3003D3D8E /* PBXContainerItemProxy */; }; 27D3967927BA8224003D3D8E /* PBXTargetDependency */ = { @@ -2707,47 +2707,47 @@ }; 724FA5381CC037370092477B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 724FA5391CC037370092477B /* PBXContainerItemProxy */; }; 724FA5711CC037810092477B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 724FA5721CC037810092477B /* PBXContainerItemProxy */; }; 724FA5841CC037980092477B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 724FA5851CC037980092477B /* PBXContainerItemProxy */; }; 724FA5971CC037AA0092477B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 724FA5981CC037AA0092477B /* PBXContainerItemProxy */; }; 724FA5AA1CC037C60092477B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 724FA5AB1CC037C60092477B /* PBXContainerItemProxy */; }; 724FA5D01CC037F00092477B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 724FA5D11CC037F00092477B /* PBXContainerItemProxy */; }; 724FA5F81CC038190092477B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 724FA5F91CC038190092477B /* PBXContainerItemProxy */; }; 724FA60C1CC0382B0092477B /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 724FA60D1CC0382B0092477B /* PBXContainerItemProxy */; }; 729181AF201155C1005E7560 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 729181B0201155C1005E7560 /* PBXContainerItemProxy */; }; 729181C32011560E005E7560 /* PBXTargetDependency */ = { @@ -2767,12 +2767,12 @@ }; 72BEA8D819AFA8BB0085F0F3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 274FF6891333B1C400317ECB /* libcups_static */; + target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 72BEA8D719AFA8BB0085F0F3 /* PBXContainerItemProxy */; }; 72CF95E718A19134000FCAE4 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = 72220EAD1333047D00FCA411 /* libcups */; + target = 72220EAD1333047D00FCA411 /* libcups3 */; targetProxy = 72CF95E818A19134000FCAE4 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -2787,10 +2787,10 @@ COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_EXTENSION = a; EXECUTABLE_PREFIX = ""; - PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups; + PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; - PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups; + PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; SDKROOT = iphoneos; SKIP_INSTALL = YES; STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = static; @@ -2807,10 +2807,10 @@ COMBINE_HIDPI_IMAGES = YES; EXECUTABLE_EXTENSION = a; EXECUTABLE_PREFIX = ""; - PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups; + PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; - PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups; + PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; SDKROOT = iphoneos; SKIP_INSTALL = YES; STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = static; @@ -2973,9 +2973,9 @@ EXECUTABLE_PREFIX = ""; INSTALL_PATH = /usr/local/lib; MACH_O_TYPE = staticlib; - PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups; + PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; PRODUCT_NAME = libcups_static; - PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups; + PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = static; }; name = Debug; @@ -2989,9 +2989,9 @@ EXECUTABLE_PREFIX = ""; INSTALL_PATH = /usr/local/lib; MACH_O_TYPE = staticlib; - PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups; + PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; PRODUCT_NAME = libcups_static; - PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups; + PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; STANDARD_C_PLUS_PLUS_LIBRARY_TYPE = static; }; name = Release; @@ -3097,9 +3097,9 @@ DYLIB_CURRENT_VERSION = "$(CURRENT_PROJECT_VERSION)"; EXECUTABLE_PREFIX = ""; INSTALL_PATH = /usr/lib; - PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups; + PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups; + PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; }; name = Debug; }; @@ -3112,9 +3112,9 @@ DYLIB_CURRENT_VERSION = "$(CURRENT_PROJECT_VERSION)"; EXECUTABLE_PREFIX = ""; INSTALL_PATH = /usr/lib; - PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/cups; + PRIVATE_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; PRODUCT_NAME = "$(TARGET_NAME)"; - PUBLIC_HEADERS_FOLDER_PATH = /usr/include/cups; + PUBLIC_HEADERS_FOLDER_PATH = /usr/local/include/libcups3/cups; }; name = Release; }; @@ -3459,7 +3459,7 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 270696571CADF3E200FFE5FB /* Build configuration list for PBXNativeTarget "libcups_ios" */ = { + 270696571CADF3E200FFE5FB /* Build configuration list for PBXNativeTarget "libcups3_ios" */ = { isa = XCConfigurationList; buildConfigurations = ( 270696581CADF3E200FFE5FB /* Debug */, @@ -3540,7 +3540,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 274FF6DD1333B1C400317ECB /* Build configuration list for PBXNativeTarget "libcups_static" */ = { + 274FF6DD1333B1C400317ECB /* Build configuration list for PBXNativeTarget "libcups3_static" */ = { isa = XCConfigurationList; buildConfigurations = ( 274FF6DE1333B1C400317ECB /* Debug */, @@ -3594,7 +3594,7 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 72220EB21333047D00FCA411 /* Build configuration list for PBXNativeTarget "libcups" */ = { + 72220EB21333047D00FCA411 /* Build configuration list for PBXNativeTarget "libcups3" */ = { isa = XCConfigurationList; buildConfigurations = ( 72220EB01333047D00FCA411 /* Debug */, diff --git a/xcode/libcups.xcodeproj/xcshareddata/xcschemes/libcups.xcscheme b/xcode/libcups.xcodeproj/xcshareddata/xcschemes/libcups.xcscheme index 5d3aa10df..574396417 100644 --- a/xcode/libcups.xcodeproj/xcshareddata/xcschemes/libcups.xcscheme +++ b/xcode/libcups.xcodeproj/xcshareddata/xcschemes/libcups.xcscheme @@ -16,7 +16,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "72220EAD1333047D00FCA411" BuildableName = "libcups.dylib" - BlueprintName = "libcups" + BlueprintName = "libcups3" ReferencedContainer = "container:libcups.xcodeproj"> @@ -52,7 +52,7 @@ BuildableIdentifier = "primary" BlueprintIdentifier = "72220EAD1333047D00FCA411" BuildableName = "libcups.dylib" - BlueprintName = "libcups" + BlueprintName = "libcups3" ReferencedContainer = "container:libcups.xcodeproj"> From 28ada4ecc0360fa085146c7bff6989c0fb24a377 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 18 Aug 2022 08:05:24 -0400 Subject: [PATCH 03/19] Update config.guess/sub to support RISC-V arch. --- config.guess | 332 ++++++++++++++++++--------------------------------- config.sub | 84 ++++++++----- 2 files changed, 170 insertions(+), 246 deletions(-) diff --git a/config.guess b/config.guess index 9afd67620..7ea49fadc 100755 --- a/config.guess +++ b/config.guess @@ -1,8 +1,8 @@ -#! /bin/sh +#!/usr/bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2013 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2013-11-29' +timestamp='2016-10-02' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -24,12 +24,12 @@ timestamp='2013-11-29' # program. This Exception is an additional permission under section 7 # of the GNU General Public License, version 3 ("GPLv3"). # -# Originally written by Per Bothner. +# Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess # -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . me=`echo "$0" | sed -e 's,.*/,,'` @@ -50,7 +50,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -149,7 +149,7 @@ Linux|GNU|GNU/*) LIBC=gnu #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'` + eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` ;; esac @@ -168,19 +168,29 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ + /sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || \ + echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; + earmv*) + arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + machine=${arch}${endian}-unknown + ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. + # to ELF recently (or will in the future) and ABI. case "${UNAME_MACHINE_ARCH}" in + earm*) + os=netbsdelf + ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ @@ -197,6 +207,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in os=netbsd ;; esac + # Determine ABI tags. + case "${UNAME_MACHINE_ARCH}" in + earm*) + expr='s/^earmv[0-9]/-eabi/;s/eb$//' + abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + ;; + esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need @@ -207,13 +224,13 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" + echo "${machine}-${os}${release}${abi}" exit ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` @@ -223,6 +240,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; + *:LibertyBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} + exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; @@ -235,6 +256,9 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; + *:Sortix:*:*) + echo ${UNAME_MACHINE}-unknown-sortix + exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) @@ -251,42 +275,42 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; + UNAME_MACHINE=alpha ;; "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; + UNAME_MACHINE=alphaev5 ;; "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; + UNAME_MACHINE=alphaev56 ;; "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; + UNAME_MACHINE=alphapca56 ;; "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; + UNAME_MACHINE=alphapca57 ;; "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; + UNAME_MACHINE=alphaev6 ;; "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; + UNAME_MACHINE=alphaev67 ;; "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; + UNAME_MACHINE=alphaev68 ;; "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; + UNAME_MACHINE=alphaev69 ;; "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; + UNAME_MACHINE=alphaev7 ;; "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; + UNAME_MACHINE=alphaev79 ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` # Reset EXIT trap before exiting to avoid spurious non-zero exit code. exitcode=$? trap '' 0 @@ -359,16 +383,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) eval $set_cc_for_build - SUN_ARCH="i386" + SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then - SUN_ARCH="x86_64" + SUN_ARCH=x86_64 fi fi echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` @@ -393,7 +417,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} @@ -579,8 +603,9 @@ EOF else IBM_ARCH=powerpc fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` + if [ -x /usr/bin/lslpp ] ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi @@ -617,13 +642,13 @@ EOF sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 + 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + 32) HP_ARCH=hppa2.0n ;; + 64) HP_ARCH=hppa2.0w ;; + '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi @@ -662,11 +687,11 @@ EOF exit (0); } EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = "hppa2.0w" ] + if [ ${HP_ARCH} = hppa2.0w ] then eval $set_cc_for_build @@ -679,12 +704,12 @@ EOF # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | grep -q __LP64__ then - HP_ARCH="hppa2.0w" + HP_ARCH=hppa2.0w else - HP_ARCH="hppa64" + HP_ARCH=hppa64 fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} @@ -789,14 +814,14 @@ EOF echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) @@ -826,7 +851,7 @@ EOF *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; - i*:MSYS*:*) + *:MSYS*:*) echo ${UNAME_MACHINE}-pc-msys exit ;; i*:windows32*:*) @@ -878,7 +903,7 @@ EOF exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix @@ -901,7 +926,7 @@ EOF EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep -q ld.so.1 - if test "$?" = 0 ; then LIBC="gnulibc1" ; fi + if test "$?" = 0 ; then LIBC=gnulibc1 ; fi echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; arc:Linux:*:* | arceb:Linux:*:*) @@ -932,6 +957,9 @@ EOF crisv32:Linux:*:*) echo ${UNAME_MACHINE}-axis-linux-${LIBC} exit ;; + e2k:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; frv:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -944,6 +972,9 @@ EOF ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; + k1om:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; @@ -969,10 +1000,13 @@ EOF eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } ;; - or1k:Linux:*:*) + mips64el:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; - or32:Linux:*:*) + openrisc*:Linux:*:*) + echo or1k-unknown-linux-${LIBC} + exit ;; + or32:Linux:*:* | or1k*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} exit ;; padre:Linux:*:*) @@ -1001,6 +1035,9 @@ EOF ppcle:Linux:*:*) echo powerpcle-unknown-linux-${LIBC} exit ;; + riscv32:Linux:*:* | riscv64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux-${LIBC} exit ;; @@ -1020,7 +1057,7 @@ EOF echo ${UNAME_MACHINE}-dec-linux-${LIBC} exit ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + echo ${UNAME_MACHINE}-pc-linux-${LIBC} exit ;; xtensa*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-${LIBC} @@ -1099,7 +1136,7 @@ EOF # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i586. # Note: whatever this is, it MUST be the same as what config.sub - # prints for the "djgpp" host, or else GDB configury will decide that + # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. echo i586-pc-msdosdjgpp exit ;; @@ -1248,6 +1285,9 @@ EOF SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; + SX-ACE:SUPER-UX:*:*) + echo sxace-nec-superux${UNAME_RELEASE} + exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; @@ -1261,9 +1301,9 @@ EOF UNAME_PROCESSOR=powerpc fi if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if [ "$CC_FOR_BUILD" != no_compiler_found ]; then if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then case $UNAME_PROCESSOR in @@ -1285,7 +1325,7 @@ EOF exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then + if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi @@ -1316,7 +1356,7 @@ EOF # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = "386"; then + if test "$cputype" = 386; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" @@ -1358,7 +1398,7 @@ EOF echo i386-pc-xenix exit ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos @@ -1369,171 +1409,25 @@ EOF x86_64:VMkernel:*:*) echo ${UNAME_MACHINE}-unknown-esx exit ;; -esac - -eval $set_cc_for_build -cat >$dummy.c < -# include -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -# if !defined (ultrix) -# include -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - c34*) - echo c34-convex-bsd - exit ;; - c38*) - echo c38-convex-bsd + amd64:Isilon\ OneFS:*:*) + echo x86_64-unknown-onefs exit ;; - c4*) - echo c4-convex-bsd - exit ;; - esac -fi +esac cat >&2 < in order to provide the needed -information to handle your system. +If $0 has already been updated, send the following data and any +information you think might be pertinent to config-patches@gnu.org to +provide the necessary information to handle your system. config.guess timestamp = $timestamp diff --git a/config.sub b/config.sub index 61cb4bc22..ba15a57a5 100755 --- a/config.sub +++ b/config.sub @@ -1,8 +1,8 @@ -#! /bin/sh +#!/usr/bin/sh # Configuration validation subroutine script. -# Copyright 1992-2013 Free Software Foundation, Inc. +# Copyright 1992-2016 Free Software Foundation, Inc. -timestamp='2013-10-01' +timestamp='2016-09-05' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by @@ -25,7 +25,7 @@ timestamp='2013-10-01' # of the GNU General Public License, version 3 ("GPLv3"). -# Please send patches with a ChangeLog entry to config-patches@gnu.org. +# Please send patches to . # # Configuration subroutine to validate and canonicalize a configuration type. # Supply the specified configuration type as an argument. @@ -33,7 +33,7 @@ timestamp='2013-10-01' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD +# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -53,8 +53,7 @@ timestamp='2013-10-01' me=`echo "$0" | sed -e 's,.*/,,'` usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS +Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. @@ -68,7 +67,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2013 Free Software Foundation, Inc. +Copyright 1992-2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -117,8 +116,8 @@ maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | \ - kopensolaris*-gnu* | \ + knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ + kopensolaris*-gnu* | cloudabi*-eabi* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` @@ -255,12 +254,13 @@ case $basic_machine in | arc | arceb \ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ | avr | avr32 \ + | ba \ | be32 | be64 \ | bfin \ | c4x | c8051 | clipper \ | d10v | d30v | dlx | dsp16xx \ - | epiphany \ - | fido | fr30 | frv \ + | e2k | epiphany \ + | fido | fr30 | frv | ft32 \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | hexagon \ | i370 | i860 | i960 | ia64 \ @@ -283,8 +283,10 @@ case $basic_machine in | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r6 | mipsisa32r6el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r6 | mipsisa64r6el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipsr5900 | mipsr5900el \ @@ -296,14 +298,14 @@ case $basic_machine in | nds32 | nds32le | nds32be \ | nios | nios2 | nios2eb | nios2el \ | ns16k | ns32k \ - | open8 \ - | or1k | or32 \ + | open8 | or1k | or1knd | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle \ | pyramid \ + | riscv32 | riscv64 \ | rl78 | rx \ | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ @@ -311,6 +313,7 @@ case $basic_machine in | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ | ubicom32 \ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ + | visium \ | we32k \ | x86 | xc16x | xstormy16 | xtensa \ | z8k | z80) @@ -325,6 +328,9 @@ case $basic_machine in c6x) basic_machine=tic6x-unknown ;; + leon|leon[3-9]) + basic_machine=sparc-$basic_machine + ;; m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) basic_machine=$basic_machine-unknown os=-none @@ -370,12 +376,13 @@ case $basic_machine in | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ + | ba-* \ | be32-* | be64-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* \ | c8051-* | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ + | e2k-* | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ @@ -402,8 +409,10 @@ case $basic_machine in | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa32r6-* | mipsisa32r6el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64r6-* | mipsisa64r6el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipsr5900-* | mipsr5900el-* \ @@ -415,16 +424,18 @@ case $basic_machine in | nios-* | nios2-* | nios2eb-* | nios2el-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | open8-* \ + | or1k*-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ | pyramid-* \ + | riscv32-* | riscv64-* \ | rl78-* | romp-* | rs6000-* | rx-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ | tahoe-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tile*-* \ @@ -432,6 +443,7 @@ case $basic_machine in | ubicom32-* \ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ | vax-* \ + | visium-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* \ | xstormy16-* | xtensa*-* \ @@ -508,6 +520,9 @@ case $basic_machine in basic_machine=i386-pc os=-aros ;; + asmjs) + basic_machine=asmjs-unknown + ;; aux) basic_machine=m68k-apple os=-aux @@ -628,6 +643,14 @@ case $basic_machine in basic_machine=m68k-bull os=-sysv3 ;; + e500v[12]) + basic_machine=powerpc-unknown + os=$os"spe" + ;; + e500v[12]-*) + basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + os=$os"spe" + ;; ebmon29k) basic_machine=a29k-amd os=-ebmon @@ -769,6 +792,9 @@ case $basic_machine in basic_machine=m68k-isi os=-sysv ;; + leon-*|leon[3-9]-*) + basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` + ;; m68knommu) basic_machine=m68k-unknown os=-linux @@ -824,6 +850,10 @@ case $basic_machine in basic_machine=powerpc-unknown os=-morphos ;; + moxiebox) + basic_machine=moxie-unknown + os=-moxiebox + ;; msdos) basic_machine=i386-pc os=-msdos @@ -1000,7 +1030,7 @@ case $basic_machine in ppc-* | ppcbe-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppcle | powerpclittle | ppc-le | powerpc-little) + ppcle | powerpclittle) basic_machine=powerpcle-unknown ;; ppcle-* | powerpclittle-*) @@ -1010,7 +1040,7 @@ case $basic_machine in ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) + ppc64le | powerpc64little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) @@ -1356,27 +1386,28 @@ case $os in | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \ | -sym* | -kopensolaris* | -plan9* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* | -aros* \ + | -aos* | -aros* | -cloudabi* | -sortix* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -bitrig* | -openbsd* | -solidbsd* \ + | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* | -cegcc* \ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ + | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \ | -linux-newlib* | -linux-musl* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ + | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*) + | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \ + | -onefs* | -tirtos* | -phoenix*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) @@ -1508,6 +1539,8 @@ case $os in ;; -nacl*) ;; + -ios) + ;; -none) ;; *) @@ -1594,9 +1627,6 @@ case $basic_machine in mips*-*) os=-elf ;; - or1k-*) - os=-elf - ;; or32-*) os=-coff ;; From 1677510b41d63e86118d214fd3bb532aebd68d9c Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 18 Aug 2022 08:20:03 -0400 Subject: [PATCH 04/19] Update config.guess/sub to absolute latest from GNU Savannah config repo. --- config.guess | 1638 ++++++++++++++++++------------- config.sub | 2659 ++++++++++++++++++++++++++------------------------ 2 files changed, 2335 insertions(+), 1962 deletions(-) diff --git a/config.guess b/config.guess index 7ea49fadc..1817bdce9 100755 --- a/config.guess +++ b/config.guess @@ -1,12 +1,14 @@ -#!/usr/bin/sh +#! /bin/sh # Attempt to guess a canonical system name. -# Copyright 1992-2016 Free Software Foundation, Inc. +# Copyright 1992-2022 Free Software Foundation, Inc. -timestamp='2016-10-02' +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-05-25' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -15,7 +17,7 @@ timestamp='2016-10-02' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -27,11 +29,19 @@ timestamp='2016-10-02' # Originally written by Per Bothner; maintained since 2000 by Ben Elliston. # # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess +# https://git.savannah.gnu.org/cgit/config.git/plain/config.guess # # Please send patches to . +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + + me=`echo "$0" | sed -e 's,.*/,,'` usage="\ @@ -39,7 +49,7 @@ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -50,7 +60,7 @@ version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. -Copyright 1992-2016 Free Software Foundation, Inc. +Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -84,7 +94,8 @@ if test $# != 0; then exit 1 fi -trap 'exit 1' 1 2 15 +# Just in case it came from the environment. +GUESS= # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires @@ -96,66 +107,90 @@ trap 'exit 1' 1 2 15 # Portable tmp directory creation inspired by the Autoconf team. -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; - for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' +tmp= +# shellcheck disable=SC2172 +trap 'test -z "$tmp" || rm -fr "$tmp"' 0 1 2 13 15 + +set_cc_for_build() { + # prevent multiple calls if $tmp is already set + test "$tmp" && return 0 + : "${TMPDIR=/tmp}" + # shellcheck disable=SC2039,SC3028 + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir "$tmp" 2>/dev/null) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir "$tmp" 2>/dev/null) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } + dummy=$tmp/dummy + case ${CC_FOR_BUILD-},${HOST_CC-},${CC-} in + ,,) echo "int x;" > "$dummy.c" + for driver in cc gcc c89 c99 ; do + if ($driver -c -o "$dummy.o" "$dummy.c") >/dev/null 2>&1 ; then + CC_FOR_BUILD=$driver + break + fi + done + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; + esac +} # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then +if test -f /.attbin/uname ; then PATH=$PATH:/.attbin ; export PATH fi UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown -case "${UNAME_SYSTEM}" in +case $UNAME_SYSTEM in Linux|GNU|GNU/*) - # If the system lacks a compiler, then just pick glibc. - # We could probably try harder. - LIBC=gnu + LIBC=unknown - eval $set_cc_for_build - cat <<-EOF > $dummy.c + set_cc_for_build + cat <<-EOF > "$dummy.c" #include #if defined(__UCLIBC__) LIBC=uclibc #elif defined(__dietlibc__) LIBC=dietlibc - #else + #elif defined(__GLIBC__) LIBC=gnu + #else + #include + /* First heuristic to detect musl libc. */ + #ifdef __DEFINED_va_list + LIBC=musl + #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + cc_set_libc=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^LIBC' | sed 's, ,,g'` + eval "$cc_set_libc" + + # Second heuristic to detect musl libc. + if [ "$LIBC" = unknown ] && + command -v ldd >/dev/null && + ldd --version 2>&1 | grep -q ^musl; then + LIBC=musl + fi + + # If the system lacks a compiler, then just pick glibc. + # We could probably try harder. + if [ "$LIBC" = unknown ]; then + LIBC=gnu + fi ;; esac # Note: order is significant - the case branches are not exclusive. -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in +case $UNAME_MACHINE:$UNAME_SYSTEM:$UNAME_RELEASE:$UNAME_VERSION in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*, @@ -167,32 +202,32 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \ - /sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || \ + /sbin/sysctl -n hw.machine_arch 2>/dev/null || \ + /usr/sbin/sysctl -n hw.machine_arch 2>/dev/null || \ echo unknown)` - case "${UNAME_MACHINE_ARCH}" in + case $UNAME_MACHINE_ARCH in + aarch64eb) machine=aarch64_be-unknown ;; armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; earmv*) - arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'` - endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'` + arch=`echo "$UNAME_MACHINE_ARCH" | sed -e 's,^e\(armv[0-9]\).*$,\1,'` + endian=`echo "$UNAME_MACHINE_ARCH" | sed -ne 's,^.*\(eb\)$,\1,p'` machine=${arch}${endian}-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + *) machine=$UNAME_MACHINE_ARCH-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently (or will in the future) and ABI. - case "${UNAME_MACHINE_ARCH}" in + case $UNAME_MACHINE_ARCH in earm*) os=netbsdelf ;; arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build + set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ELF__ then @@ -208,10 +243,10 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in ;; esac # Determine ABI tags. - case "${UNAME_MACHINE_ARCH}" in + case $UNAME_MACHINE_ARCH in earm*) expr='s/^earmv[0-9]/-eabi/;s/eb$//' - abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"` + abi=`echo "$UNAME_MACHINE_ARCH" | sed -e "$expr"` ;; esac # The OS release @@ -219,47 +254,68 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in + case $UNAME_VERSION in Debian*) release='-gnu' ;; *) - release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2` + release=`echo "$UNAME_RELEASE" | sed -e 's/[-_].*//' | cut -d. -f1,2` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}${abi}" - exit ;; + GUESS=$machine-${os}${release}${abi-} + ;; *:Bitrig:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE_ARCH-unknown-bitrig$UNAME_RELEASE + ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE_ARCH-unknown-openbsd$UNAME_RELEASE + ;; + *:SecBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/SecBSD.//'` + GUESS=$UNAME_MACHINE_ARCH-unknown-secbsd$UNAME_RELEASE + ;; *:LibertyBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE_ARCH-unknown-libertybsd$UNAME_RELEASE + ;; + *:MidnightBSD:*:*) + GUESS=$UNAME_MACHINE-unknown-midnightbsd$UNAME_RELEASE + ;; *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-unknown-ekkobsd$UNAME_RELEASE + ;; *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-unknown-solidbsd$UNAME_RELEASE + ;; + *:OS108:*:*) + GUESS=$UNAME_MACHINE-unknown-os108_$UNAME_RELEASE + ;; macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} - exit ;; + GUESS=powerpc-unknown-mirbsd$UNAME_RELEASE + ;; *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-unknown-mirbsd$UNAME_RELEASE + ;; *:Sortix:*:*) - echo ${UNAME_MACHINE}-unknown-sortix - exit ;; + GUESS=$UNAME_MACHINE-unknown-sortix + ;; + *:Twizzler:*:*) + GUESS=$UNAME_MACHINE-unknown-twizzler + ;; + *:Redox:*:*) + GUESS=$UNAME_MACHINE-unknown-redox + ;; + mips:OSF1:*.*) + GUESS=mips-dec-osf1 + ;; alpha:OSF1:*:*) + # Reset EXIT trap before exiting to avoid spurious non-zero exit code. + trap '' 0 case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` @@ -273,7 +329,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case "$ALPHA_CPU_TYPE" in + case $ALPHA_CPU_TYPE in "EV4 (21064)") UNAME_MACHINE=alpha ;; "EV4.5 (21064)") @@ -310,126 +366,121 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` - # Reset EXIT trap before exiting to avoid spurious non-zero exit code. - exitcode=$? - trap '' 0 - exit $exitcode ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; + OSF_REL=`echo "$UNAME_RELEASE" | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` + GUESS=$UNAME_MACHINE-dec-osf$OSF_REL + ;; Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; + GUESS=m68k-unknown-sysv4 + ;; *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos - exit ;; + GUESS=$UNAME_MACHINE-unknown-amigaos + ;; *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos - exit ;; + GUESS=$UNAME_MACHINE-unknown-morphos + ;; *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; + GUESS=i370-ibm-openedition + ;; *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; + GUESS=s390-ibm-zvmoe + ;; *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; + GUESS=powerpc-ibm-os400 + ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit ;; + GUESS=arm-acorn-riscix$UNAME_RELEASE + ;; arm*:riscos:*:*|arm*:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; + GUESS=arm-unknown-riscos + ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; + GUESS=hppa1.1-hitachi-hiuxmpp + ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; + case `(/bin/universe) 2>/dev/null` in + att) GUESS=pyramid-pyramid-sysv3 ;; + *) GUESS=pyramid-pyramid-bsd ;; + esac + ;; NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; + GUESS=pyramid-pyramid-svr4 + ;; DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; + GUESS=sparc-icl-nx6 + ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; + sparc) GUESS=sparc-icl-nx7 ;; + esac + ;; s390x:SunOS:*:*) - echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$UNAME_MACHINE-ibm-solaris2$SUN_REL + ;; sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-hal-solaris2$SUN_REL + ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris2$SUN_REL + ;; i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*) - echo i386-pc-auroraux${UNAME_RELEASE} - exit ;; + GUESS=i386-pc-auroraux$UNAME_RELEASE + ;; i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) - eval $set_cc_for_build + set_cc_for_build SUN_ARCH=i386 # If there is a compiler, see if it is configured for 64-bit objects. # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. # This test works for both compilers. - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then + if test "$CC_FOR_BUILD" != no_compiler_found; then if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + (CCOPTS="" $CC_FOR_BUILD -m64 -E - 2>/dev/null) | \ grep IS_64BIT_ARCH >/dev/null then SUN_ARCH=x86_64 fi fi - echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=$SUN_ARCH-pc-solaris2$SUN_REL + ;; sun4*:SunOS:6*:*) # According to config.sub, this is the proper way to canonicalize # SunOS6. Hard to guess exactly what SunOS6 will be like, but # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=sparc-sun-solaris3$SUN_REL + ;; sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in + case `/usr/bin/arch -k` in Series*|S4*) UNAME_RELEASE=`uname -v` ;; esac # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/'` + GUESS=sparc-sun-sunos$SUN_REL + ;; sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit ;; + GUESS=m68k-sun-sunos$UNAME_RELEASE + ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3 - case "`/bin/arch`" in + test "x$UNAME_RELEASE" = x && UNAME_RELEASE=3 + case `/bin/arch` in sun3) - echo m68k-sun-sunos${UNAME_RELEASE} + GUESS=m68k-sun-sunos$UNAME_RELEASE ;; sun4) - echo sparc-sun-sunos${UNAME_RELEASE} + GUESS=sparc-sun-sunos$UNAME_RELEASE ;; esac - exit ;; + ;; aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} - exit ;; + GUESS=sparc-auspex-sunos$UNAME_RELEASE + ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor @@ -439,44 +490,44 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-atari-mint$UNAME_RELEASE + ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-milan-mint$UNAME_RELEASE + ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-hades-mint$UNAME_RELEASE + ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; + GUESS=m68k-unknown-mint$UNAME_RELEASE + ;; m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} - exit ;; + GUESS=m68k-apple-machten$UNAME_RELEASE + ;; powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} - exit ;; + GUESS=powerpc-apple-machten$UNAME_RELEASE + ;; RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; + GUESS=mips-dec-mach_bsd4.3 + ;; RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit ;; + GUESS=mips-dec-ultrix$UNAME_RELEASE + ;; VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit ;; + GUESS=vax-dec-ultrix$UNAME_RELEASE + ;; 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} - exit ;; + GUESS=clipper-intergraph-clix$UNAME_RELEASE + ;; mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { @@ -485,95 +536,96 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssysv\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + printf ("mips-mips-riscos%ssvr4\\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + printf ("mips-mips-riscos%sbsd\\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && + dummyarg=`echo "$UNAME_RELEASE" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`"$dummy" "$dummyarg"` && { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} - exit ;; + GUESS=mips-mips-riscos$UNAME_RELEASE + ;; Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; + GUESS=powerpc-motorola-powermax + ;; Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; + GUESS=powerpc-harris-powermax + ;; Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; + GUESS=powerpc-harris-powerunix + ;; m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; + GUESS=m88k-harris-cxux7 + ;; m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; + GUESS=m88k-motorola-sysv4 + ;; m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + if test "$UNAME_PROCESSOR" = mc88100 || test "$UNAME_PROCESSOR" = mc88110 then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] + if test "$TARGET_BINARY_INTERFACE"x = m88kdguxelfx || \ + test "$TARGET_BINARY_INTERFACE"x = x then - echo m88k-dg-dgux${UNAME_RELEASE} + GUESS=m88k-dg-dgux$UNAME_RELEASE else - echo m88k-dg-dguxbcs${UNAME_RELEASE} + GUESS=m88k-dg-dguxbcs$UNAME_RELEASE fi else - echo i586-dg-dgux${UNAME_RELEASE} + GUESS=i586-dg-dgux$UNAME_RELEASE fi - exit ;; + ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; + GUESS=m88k-dolphin-sysv3 + ;; M88*:*:R3*:*) # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; + GUESS=m88k-motorola-sysv3 + ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; + GUESS=m88k-tektronix-sysv3 + ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; + GUESS=m68k-tektronix-bsd + ;; *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit ;; + IRIX_REL=`echo "$UNAME_RELEASE" | sed -e 's/-/_/g'` + GUESS=mips-sgi-irix$IRIX_REL + ;; ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + GUESS=romp-ibm-aix # uname -m gives an 8 hex-code CPU id + ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; + GUESS=i386-ibm-aix + ;; ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then + if test -x /usr/bin/oslevel ; then IBM_REV=`/usr/bin/oslevel` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} - exit ;; + GUESS=$UNAME_MACHINE-ibm-aix$IBM_REV + ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #include main() @@ -584,77 +636,77 @@ EOF exit(0); } EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + if $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` then - echo "$SYSTEM_NAME" + GUESS=$SYSTEM_NAME else - echo rs6000-ibm-aix3.2.5 + GUESS=rs6000-ibm-aix3.2.5 fi elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 + GUESS=rs6000-ibm-aix3.2.4 else - echo rs6000-ibm-aix3.2 + GUESS=rs6000-ibm-aix3.2 fi - exit ;; + ;; *:AIX:*:[4567]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + if /usr/sbin/lsattr -El "$IBM_CPU_ID" | grep ' POWER' >/dev/null 2>&1; then IBM_ARCH=rs6000 else IBM_ARCH=powerpc fi - if [ -x /usr/bin/lslpp ] ; then - IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | + if test -x /usr/bin/lslpp ; then + IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc | \ awk -F: '{ print $3 }' | sed s/[0-9]*$/0/` else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + IBM_REV=$UNAME_VERSION.$UNAME_RELEASE fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit ;; + GUESS=$IBM_ARCH-ibm-aix$IBM_REV + ;; *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) - echo romp-ibm-bsd4.4 - exit ;; + GUESS=rs6000-ibm-aix + ;; + ibmrt:4.4BSD:*|romp-ibm:4.4BSD:*) + GUESS=romp-ibm-bsd4.4 + ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 + GUESS=romp-ibm-bsd$UNAME_RELEASE # 4.3 with uname added to + ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; + GUESS=rs6000-bull-bosx + ;; DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; + GUESS=m68k-bull-sysv3 + ;; 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; + GUESS=m68k-hp-bsd + ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; + GUESS=m68k-hp-bsd4.4 + ;; 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + case $UNAME_MACHINE in + 9000/31?) HP_ARCH=m68000 ;; + 9000/[34]??) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then + if test -x /usr/bin/getconf; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in + case $sc_cpu_version in 523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0 528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in + case $sc_kernel_bits in 32) HP_ARCH=hppa2.0n ;; 64) HP_ARCH=hppa2.0w ;; '') HP_ARCH=hppa2.0 ;; # HP-UX 10.20 esac ;; esac fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + if test "$HP_ARCH" = ""; then + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #define _HPUX_SOURCE #include @@ -687,13 +739,13 @@ EOF exit (0); } EOF - (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + (CCOPTS="" $CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null) && HP_ARCH=`"$dummy"` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac - if [ ${HP_ARCH} = hppa2.0w ] + if test "$HP_ARCH" = hppa2.0w then - eval $set_cc_for_build + set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler @@ -712,15 +764,15 @@ EOF HP_ARCH=hppa64 fi fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit ;; + GUESS=$HP_ARCH-hp-hpux$HPUX_REV + ;; ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} - exit ;; + HPUX_REV=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*.[0B]*//'` + GUESS=ia64-hp-hpux$HPUX_REV + ;; 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + sed 's/^ //' << EOF > "$dummy.c" #include int main () @@ -745,38 +797,38 @@ EOF exit (0); } EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + $CC_FOR_BUILD -o "$dummy" "$dummy.c" && SYSTEM_NAME=`"$dummy"` && { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit ;; + GUESS=unknown-hitachi-hiuxwe2 + ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:*) + GUESS=hppa1.1-hp-bsd + ;; 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; + GUESS=hppa1.0-hp-bsd + ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) - echo hppa1.1-hp-osf - exit ;; + GUESS=hppa1.0-hp-mpeix + ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:*) + GUESS=hppa1.1-hp-osf + ;; hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; + GUESS=hppa1.0-hp-osf + ;; i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk + if test -x /usr/sbin/sysversion ; then + GUESS=$UNAME_MACHINE-unknown-osf1mk else - echo ${UNAME_MACHINE}-unknown-osf1 + GUESS=$UNAME_MACHINE-unknown-osf1 fi - exit ;; + ;; parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; + GUESS=hppa1.1-hp-lites + ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; + GUESS=c1-convex-bsd + ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd @@ -784,139 +836,148 @@ EOF fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; + GUESS=c34-convex-bsd + ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; + GUESS=c38-convex-bsd + ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; + GUESS=c4-convex-bsd + ;; CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=ymp-cray-unicos$CRAY_REL + ;; CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + echo "$UNAME_MACHINE"-cray-unicos"$UNAME_RELEASE" \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=t90-cray-unicos$CRAY_REL + ;; CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=alphaev5-cray-unicosmk$CRAY_REL + ;; CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=sv1-cray-unicos$CRAY_REL + ;; *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; + CRAY_REL=`echo "$UNAME_RELEASE" | sed -e 's/\.[^.]*$/.X/'` + GUESS=craynv-cray-unicosmp$CRAY_REL + ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz` FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_REL=`echo "$UNAME_RELEASE" | sed -e 's/ /_/'` + GUESS=${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; + FUJITSU_REL=`echo "$UNAME_RELEASE" | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'` + GUESS=sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL} + ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-pc-bsdi$UNAME_RELEASE + ;; sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} - exit ;; + GUESS=sparc-unknown-bsdi$UNAME_RELEASE + ;; *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-unknown-bsdi$UNAME_RELEASE + ;; + arm:FreeBSD:*:*) + UNAME_PROCESSOR=`uname -p` + set_cc_for_build + if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_PCS_VFP + then + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabi + else + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL-gnueabihf + fi + ;; *:FreeBSD:*:*) UNAME_PROCESSOR=`/usr/bin/uname -p` - case ${UNAME_PROCESSOR} in + case $UNAME_PROCESSOR in amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + UNAME_PROCESSOR=x86_64 ;; + i386) + UNAME_PROCESSOR=i586 ;; esac - exit ;; + FREEBSD_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_PROCESSOR-unknown-freebsd$FREEBSD_REL + ;; i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit ;; + GUESS=$UNAME_MACHINE-pc-cygwin + ;; *:MINGW64*:*) - echo ${UNAME_MACHINE}-pc-mingw64 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw64 + ;; *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-mingw32 + ;; *:MSYS*:*) - echo ${UNAME_MACHINE}-pc-msys - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-msys + ;; i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 - exit ;; + GUESS=$UNAME_MACHINE-pc-pw32 + ;; + *:SerenityOS:*:*) + GUESS=$UNAME_MACHINE-pc-serenity + ;; *:Interix*:*) - case ${UNAME_MACHINE} in + case $UNAME_MACHINE in x86) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; + GUESS=i586-pc-interix$UNAME_RELEASE + ;; authenticamd | genuineintel | EM64T) - echo x86_64-unknown-interix${UNAME_RELEASE} - exit ;; + GUESS=x86_64-unknown-interix$UNAME_RELEASE + ;; IA64) - echo ia64-unknown-interix${UNAME_RELEASE} - exit ;; + GUESS=ia64-unknown-interix$UNAME_RELEASE + ;; esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - 8664:Windows_NT:*) - echo x86_64-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin - exit ;; + GUESS=$UNAME_MACHINE-pc-uwin + ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; + GUESS=x86_64-pc-cygwin + ;; prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; + SUN_REL=`echo "$UNAME_RELEASE" | sed -e 's/[^.]*//'` + GUESS=powerpcle-unknown-solaris2$SUN_REL + ;; *:GNU:*:*) # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit ;; + GNU_ARCH=`echo "$UNAME_MACHINE" | sed -e 's,[-/].*$,,'` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's,/.*$,,'` + GUESS=$GNU_ARCH-unknown-$LIBC$GNU_REL + ;; *:GNU/*:*:*) # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC} - exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix - exit ;; - aarch64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GNU_SYS=`echo "$UNAME_SYSTEM" | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"` + GNU_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-$GNU_SYS$GNU_REL-$LIBC + ;; + *:Minix:*:*) + GUESS=$UNAME_MACHINE-unknown-minix + ;; + aarch64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; aarch64_be:Linux:*:*) UNAME_MACHINE=aarch64_be - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' /proc/cpuinfo 2>/dev/null` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; @@ -927,183 +988,236 @@ EOF esac objdump --private-headers /bin/sh | grep -q ld.so.1 if test "$?" = 0 ; then LIBC=gnulibc1 ; fi - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; - arc:Linux:*:* | arceb:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + arc:Linux:*:* | arceb:Linux:*:* | arc32:Linux:*:* | arc64:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; arm*:Linux:*:*) - eval $set_cc_for_build + set_cc_for_build if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_EABI__ then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC else if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \ | grep -q __ARM_PCS_VFP then - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabi else - echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf + GUESS=$UNAME_MACHINE-unknown-linux-${LIBC}eabihf fi fi - exit ;; + ;; avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; cris:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; crisv32:Linux:*:*) - echo ${UNAME_MACHINE}-axis-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-axis-linux-$LIBC + ;; e2k:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; frv:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; hexagon:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-pc-linux-$LIBC + ;; ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; k1om:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; + loongarch32:Linux:*:* | loongarch64:Linux:*:* | loongarchx32:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; mips:Linux:*:* | mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c + set_cc_for_build + IS_GLIBC=0 + test x"${LIBC}" = xgnu && IS_GLIBC=1 + sed 's/^ //' << EOF > "$dummy.c" #undef CPU - #undef ${UNAME_MACHINE} - #undef ${UNAME_MACHINE}el + #undef mips + #undef mipsel + #undef mips64 + #undef mips64el + #if ${IS_GLIBC} && defined(_ABI64) + LIBCABI=gnuabi64 + #else + #if ${IS_GLIBC} && defined(_ABIN32) + LIBCABI=gnuabin32 + #else + LIBCABI=${LIBC} + #endif + #endif + + #if ${IS_GLIBC} && defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa64r6 + #else + #if ${IS_GLIBC} && !defined(__mips64) && defined(__mips_isa_rev) && __mips_isa_rev>=6 + CPU=mipsisa32r6 + #else + #if defined(__mips64) + CPU=mips64 + #else + CPU=mips + #endif + #endif + #endif + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=${UNAME_MACHINE}el + MIPS_ENDIAN=el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=${UNAME_MACHINE} + MIPS_ENDIAN= #else - CPU= + MIPS_ENDIAN= #endif #endif EOF - eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'` - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; } + cc_set_vars=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^CPU\|^MIPS_ENDIAN\|^LIBCABI'` + eval "$cc_set_vars" + test "x$CPU" != x && { echo "$CPU${MIPS_ENDIAN}-unknown-linux-$LIBCABI"; exit; } ;; mips64el:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; openrisc*:Linux:*:*) - echo or1k-unknown-linux-${LIBC} - exit ;; + GUESS=or1k-unknown-linux-$LIBC + ;; or32:Linux:*:* | or1k*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; padre:Linux:*:*) - echo sparc-unknown-linux-${LIBC} - exit ;; + GUESS=sparc-unknown-linux-$LIBC + ;; parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-${LIBC} - exit ;; + GUESS=hppa64-unknown-linux-$LIBC + ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-${LIBC} ;; - PA8*) echo hppa2.0-unknown-linux-${LIBC} ;; - *) echo hppa-unknown-linux-${LIBC} ;; + PA7*) GUESS=hppa1.1-unknown-linux-$LIBC ;; + PA8*) GUESS=hppa2.0-unknown-linux-$LIBC ;; + *) GUESS=hppa-unknown-linux-$LIBC ;; esac - exit ;; + ;; ppc64:Linux:*:*) - echo powerpc64-unknown-linux-${LIBC} - exit ;; + GUESS=powerpc64-unknown-linux-$LIBC + ;; ppc:Linux:*:*) - echo powerpc-unknown-linux-${LIBC} - exit ;; + GUESS=powerpc-unknown-linux-$LIBC + ;; ppc64le:Linux:*:*) - echo powerpc64le-unknown-linux-${LIBC} - exit ;; + GUESS=powerpc64le-unknown-linux-$LIBC + ;; ppcle:Linux:*:*) - echo powerpcle-unknown-linux-${LIBC} - exit ;; - riscv32:Linux:*:* | riscv64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=powerpcle-unknown-linux-$LIBC + ;; + riscv32:Linux:*:* | riscv32be:Linux:*:* | riscv64:Linux:*:* | riscv64be:Linux:*:*) + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-ibm-linux-$LIBC + ;; sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; tile*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-dec-linux-$LIBC + ;; x86_64:Linux:*:*) - echo ${UNAME_MACHINE}-pc-linux-${LIBC} - exit ;; + set_cc_for_build + CPU=$UNAME_MACHINE + LIBCABI=$LIBC + if test "$CC_FOR_BUILD" != no_compiler_found; then + ABI=64 + sed 's/^ //' << EOF > "$dummy.c" + #ifdef __i386__ + ABI=x86 + #else + #ifdef __ILP32__ + ABI=x32 + #endif + #endif +EOF + cc_set_abi=`$CC_FOR_BUILD -E "$dummy.c" 2>/dev/null | grep '^ABI' | sed 's, ,,g'` + eval "$cc_set_abi" + case $ABI in + x86) CPU=i686 ;; + x32) LIBCABI=${LIBC}x32 ;; + esac + fi + GUESS=$CPU-pc-linux-$LIBCABI + ;; xtensa*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-${LIBC} - exit ;; + GUESS=$UNAME_MACHINE-unknown-linux-$LIBC + ;; i*86:DYNIX/ptx:4*:*) # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. # earlier versions are messed up and put the nodename in both # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; + GUESS=i386-sequent-sysv4 + ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit ;; + GUESS=$UNAME_MACHINE-pc-sysv4.2uw$UNAME_VERSION + ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx - exit ;; + GUESS=$UNAME_MACHINE-pc-os2-emx + ;; i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop - exit ;; + GUESS=$UNAME_MACHINE-unknown-stop + ;; i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos - exit ;; + GUESS=$UNAME_MACHINE-unknown-atheos + ;; i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable - exit ;; + GUESS=$UNAME_MACHINE-pc-syllable + ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=i386-unknown-lynxos$UNAME_RELEASE + ;; i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp - exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + GUESS=$UNAME_MACHINE-pc-msdosdjgpp + ;; + i*86:*:4.*:*) + UNAME_REL=`echo "$UNAME_RELEASE" | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + GUESS=$UNAME_MACHINE-univel-sysv$UNAME_REL else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + GUESS=$UNAME_MACHINE-pc-sysv$UNAME_REL fi - exit ;; + ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in @@ -1111,12 +1225,12 @@ EOF *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - exit ;; + GUESS=$UNAME_MACHINE-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + ;; i*86:*:3.2:*) if test -f /usr/options/cb.name; then UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 @@ -1126,11 +1240,11 @@ EOF && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + GUESS=$UNAME_MACHINE-pc-sco$UNAME_REL else - echo ${UNAME_MACHINE}-pc-sysv32 + GUESS=$UNAME_MACHINE-pc-sysv32 fi - exit ;; + ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about @@ -1138,31 +1252,31 @@ EOF # Note: whatever this is, it MUST be the same as what config.sub # prints for the "djgpp" host, or else GDB configure will decide that # this is a cross-build. - echo i586-pc-msdosdjgpp - exit ;; + GUESS=i586-pc-msdosdjgpp + ;; Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; + GUESS=i386-pc-mach3 + ;; paragon:*:*:*) - echo i860-intel-osf1 - exit ;; + GUESS=i860-intel-osf1 + ;; i860:*:4.*:*) # i860-SVR4 if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + GUESS=i860-stardent-sysv$UNAME_RELEASE # Stardent Vistra i860-SVR4 else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + GUESS=i860-unknown-sysv$UNAME_RELEASE # Unknown i860-SVR4 fi - exit ;; + ;; mini*:CTIX:SYS*5:*) # "miniframe" - echo m68010-convergent-sysv - exit ;; + GUESS=m68010-convergent-sysv + ;; mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; + GUESS=m68k-convergent-sysv + ;; M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; + GUESS=m68k-diab-dnix + ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) @@ -1170,9 +1284,9 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; @@ -1181,249 +1295,440 @@ EOF test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + && { echo i486-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + && { echo i586-ncr-sysv4.3"$OS_REL"; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=m68k-unknown-lynxos$UNAME_RELEASE + ;; mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; + GUESS=m68k-atari-sysv4 + ;; TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=sparc-unknown-lynxos$UNAME_RELEASE + ;; rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=rs6000-unknown-lynxos$UNAME_RELEASE + ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} - exit ;; + GUESS=powerpc-unknown-lynxos$UNAME_RELEASE + ;; SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} - exit ;; + GUESS=mips-dde-sysv$UNAME_RELEASE + ;; RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; + GUESS=mips-sni-sysv4 + ;; *:SINIX-*:*:*) if uname -p 2>/dev/null >/dev/null ; then UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 + GUESS=$UNAME_MACHINE-sni-sysv4 else - echo ns32k-sni-sysv + GUESS=ns32k-sni-sysv fi - exit ;; + ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says - echo i586-unisys-sysv4 - exit ;; + GUESS=i586-unisys-sysv4 + ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; + GUESS=hppa1.1-stratus-sysv4 + ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. - echo i860-stratus-sysv4 - exit ;; + GUESS=i860-stratus-sysv4 + ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. - echo ${UNAME_MACHINE}-stratus-vos - exit ;; + GUESS=$UNAME_MACHINE-stratus-vos + ;; *:VOS:*:*) # From Paul.Green@stratus.com. - echo hppa1.1-stratus-vos - exit ;; + GUESS=hppa1.1-stratus-vos + ;; mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} - exit ;; + GUESS=m68k-apple-aux$UNAME_RELEASE + ;; news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; + GUESS=mips-sony-newsos6 + ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} + if test -d /usr/nec; then + GUESS=mips-nec-sysv$UNAME_RELEASE else - echo mips-unknown-sysv${UNAME_RELEASE} + GUESS=mips-unknown-sysv$UNAME_RELEASE fi - exit ;; + ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; + GUESS=powerpc-be-beos + ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; + GUESS=powerpc-apple-beos + ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; + GUESS=i586-pc-beos + ;; BePC:Haiku:*:*) # Haiku running on Intel PC compatible. - echo i586-pc-haiku - exit ;; - x86_64:Haiku:*:*) - echo x86_64-unknown-haiku - exit ;; + GUESS=i586-pc-haiku + ;; + ppc:Haiku:*:*) # Haiku running on Apple PowerPC + GUESS=powerpc-apple-haiku + ;; + *:Haiku:*:*) # Haiku modern gcc (not bound by BeOS compat) + GUESS=$UNAME_MACHINE-unknown-haiku + ;; SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx4-nec-superux$UNAME_RELEASE + ;; SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx5-nec-superux$UNAME_RELEASE + ;; SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx6-nec-superux$UNAME_RELEASE + ;; SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx7-nec-superux$UNAME_RELEASE + ;; SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx8-nec-superux$UNAME_RELEASE + ;; SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sx8r-nec-superux$UNAME_RELEASE + ;; SX-ACE:SUPER-UX:*:*) - echo sxace-nec-superux${UNAME_RELEASE} - exit ;; + GUESS=sxace-nec-superux$UNAME_RELEASE + ;; Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit ;; + GUESS=powerpc-apple-rhapsody$UNAME_RELEASE + ;; *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-apple-rhapsody$UNAME_RELEASE + ;; + arm64:Darwin:*:*) + GUESS=aarch64-apple-darwin$UNAME_RELEASE + ;; *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - eval $set_cc_for_build - if test "$UNAME_PROCESSOR" = unknown ; then - UNAME_PROCESSOR=powerpc + UNAME_PROCESSOR=`uname -p` + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + if command -v xcode-select > /dev/null 2> /dev/null && \ + ! xcode-select --print-path > /dev/null 2> /dev/null ; then + # Avoid executing cc if there is no toolchain installed as + # cc will be a stub that puts up a graphical alert + # prompting the user to install developer tools. + CC_FOR_BUILD=no_compiler_found + else + set_cc_for_build fi - if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then - if [ "$CC_FOR_BUILD" != no_compiler_found ]; then - if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ - (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ - grep IS_64BIT_ARCH >/dev/null - then - case $UNAME_PROCESSOR in - i386) UNAME_PROCESSOR=x86_64 ;; - powerpc) UNAME_PROCESSOR=powerpc64 ;; - esac - fi + if test "$CC_FOR_BUILD" != no_compiler_found; then + if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + case $UNAME_PROCESSOR in + i386) UNAME_PROCESSOR=x86_64 ;; + powerpc) UNAME_PROCESSOR=powerpc64 ;; + esac + fi + # On 10.4-10.6 one might compile for PowerPC via gcc -arch ppc + if (echo '#ifdef __POWERPC__'; echo IS_PPC; echo '#endif') | \ + (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_PPC >/dev/null + then + UNAME_PROCESSOR=powerpc fi elif test "$UNAME_PROCESSOR" = i386 ; then - # Avoid executing cc on OS X 10.9, as it ships with a stub - # that puts up a graphical alert prompting to install - # developer tools. Any system running Mac OS X 10.7 or - # later (Darwin 11 and later) is required to have a 64-bit - # processor. This is not true of the ARM version of Darwin - # that Apple uses in portable devices. - UNAME_PROCESSOR=x86_64 + # uname -m returns i386 or x86_64 + UNAME_PROCESSOR=$UNAME_MACHINE fi - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_PROCESSOR-apple-darwin$UNAME_RELEASE + ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = x86; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_PROCESSOR-$UNAME_MACHINE-nto-qnx$UNAME_RELEASE + ;; *:QNX:*:4*) - echo i386-pc-qnx - exit ;; - NEO-?:NONSTOP_KERNEL:*:*) - echo neo-tandem-nsk${UNAME_RELEASE} - exit ;; + GUESS=i386-pc-qnx + ;; + NEO-*:NONSTOP_KERNEL:*:*) + GUESS=neo-tandem-nsk$UNAME_RELEASE + ;; NSE-*:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} - exit ;; + GUESS=nse-tandem-nsk$UNAME_RELEASE + ;; + NSR-*:NONSTOP_KERNEL:*:*) + GUESS=nsr-tandem-nsk$UNAME_RELEASE + ;; + NSV-*:NONSTOP_KERNEL:*:*) + GUESS=nsv-tandem-nsk$UNAME_RELEASE + ;; + NSX-*:NONSTOP_KERNEL:*:*) + GUESS=nsx-tandem-nsk$UNAME_RELEASE + ;; *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; + GUESS=mips-compaq-nonstopux + ;; BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; + GUESS=bs2000-siemens-sysv + ;; DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} - exit ;; + GUESS=$UNAME_MACHINE-$UNAME_SYSTEM-$UNAME_RELEASE + ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. - if test "$cputype" = 386; then + if test "${cputype-}" = 386; then UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" + elif test "x${cputype-}" != x; then + UNAME_MACHINE=$cputype fi - echo ${UNAME_MACHINE}-unknown-plan9 - exit ;; + GUESS=$UNAME_MACHINE-unknown-plan9 + ;; *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; + GUESS=pdp10-unknown-tops10 + ;; *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; + GUESS=pdp10-unknown-tenex + ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; + GUESS=pdp10-dec-tops20 + ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; + GUESS=pdp10-xkl-tops20 + ;; *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; + GUESS=pdp10-unknown-tops20 + ;; *:ITS:*:*) - echo pdp10-unknown-its - exit ;; + GUESS=pdp10-unknown-its + ;; SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} - exit ;; + GUESS=mips-sei-seiux$UNAME_RELEASE + ;; *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit ;; + DRAGONFLY_REL=`echo "$UNAME_RELEASE" | sed -e 's/[-(].*//'` + GUESS=$UNAME_MACHINE-unknown-dragonfly$DRAGONFLY_REL + ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; + case $UNAME_MACHINE in + A*) GUESS=alpha-dec-vms ;; + I*) GUESS=ia64-dec-vms ;; + V*) GUESS=vax-dec-vms ;; esac ;; *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; + GUESS=i386-pc-xenix + ;; i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'` - exit ;; + SKYOS_REL=`echo "$UNAME_RELEASE" | sed -e 's/ .*$//'` + GUESS=$UNAME_MACHINE-pc-skyos$SKYOS_REL + ;; i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos - exit ;; - i*86:AROS:*:*) - echo ${UNAME_MACHINE}-pc-aros - exit ;; + GUESS=$UNAME_MACHINE-pc-rdos + ;; + i*86:Fiwix:*:*) + GUESS=$UNAME_MACHINE-pc-fiwix + ;; + *:AROS:*:*) + GUESS=$UNAME_MACHINE-unknown-aros + ;; x86_64:VMkernel:*:*) - echo ${UNAME_MACHINE}-unknown-esx - exit ;; + GUESS=$UNAME_MACHINE-unknown-esx + ;; amd64:Isilon\ OneFS:*:*) - echo x86_64-unknown-onefs - exit ;; + GUESS=x86_64-unknown-onefs + ;; + *:Unleashed:*:*) + GUESS=$UNAME_MACHINE-unknown-unleashed$UNAME_RELEASE + ;; +esac + +# Do we have a guess based on uname results? +if test "x$GUESS" != x; then + echo "$GUESS" + exit +fi + +# No uname command or uname output not recognized. +set_cc_for_build +cat > "$dummy.c" < +#include +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined (vax) || defined (__vax) || defined (__vax__) || defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#include +#if defined(_SIZE_T_) || defined(SIGLOST) +#include +#endif +#endif +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); +#endif + +#if defined (vax) +#if !defined (ultrix) +#include +#if defined (BSD) +#if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +#else +#if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#endif +#else + printf ("vax-dec-bsd\n"); exit (0); +#endif +#else +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname un; + uname (&un); + printf ("vax-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("vax-dec-ultrix\n"); exit (0); +#endif +#endif +#endif +#if defined(ultrix) || defined(_ultrix) || defined(__ultrix) || defined(__ultrix__) +#if defined(mips) || defined(__mips) || defined(__mips__) || defined(MIPS) || defined(__MIPS__) +#if defined(_SIZE_T_) || defined(SIGLOST) + struct utsname *un; + uname (&un); + printf ("mips-dec-ultrix%s\n", un.release); exit (0); +#else + printf ("mips-dec-ultrix\n"); exit (0); +#endif +#endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o "$dummy" "$dummy.c" 2>/dev/null && SYSTEM_NAME=`"$dummy"` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. +test -d /usr/apollo && { echo "$ISP-apollo-$SYSTYPE"; exit; } + +echo "$0: unable to guess system type" >&2 + +case $UNAME_MACHINE:$UNAME_SYSTEM in + mips:Linux | mips64:Linux) + # If we got here on MIPS GNU/Linux, output extra information. + cat >&2 <&2 <&2 </dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} +UNAME_MACHINE = "$UNAME_MACHINE" +UNAME_RELEASE = "$UNAME_RELEASE" +UNAME_SYSTEM = "$UNAME_SYSTEM" +UNAME_VERSION = "$UNAME_VERSION" EOF +fi exit 1 # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" diff --git a/config.sub b/config.sub index ba15a57a5..dba16e84c 100755 --- a/config.sub +++ b/config.sub @@ -1,12 +1,14 @@ -#!/usr/bin/sh +#! /bin/sh # Configuration validation subroutine script. -# Copyright 1992-2016 Free Software Foundation, Inc. +# Copyright 1992-2022 Free Software Foundation, Inc. -timestamp='2016-09-05' +# shellcheck disable=SC2006,SC2268 # see below for rationale + +timestamp='2022-01-03' # This file is free software; you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 3 of the License, or +# the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, but @@ -15,7 +17,7 @@ timestamp='2016-09-05' # General Public License for more details. # # You should have received a copy of the GNU General Public License -# along with this program; if not, see . +# along with this program; if not, see . # # As a special exception to the GNU General Public License, if you # distribute this file as part of a program that contains a @@ -33,7 +35,7 @@ timestamp='2016-09-05' # Otherwise, we print the canonical config type on stdout and succeed. # You can get the latest version of this script from: -# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub +# https://git.savannah.gnu.org/cgit/config.git/plain/config.sub # This file is supposed to be the same for all GNU packages # and recognize all the CPU types, system types and aliases @@ -50,6 +52,13 @@ timestamp='2016-09-05' # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. +# The "shellcheck disable" line above the timestamp inhibits complaints +# about features and limitations of the classic Bourne shell that were +# superseded or lifted in POSIX. However, this script identifies a wide +# variety of pre-POSIX systems that do not have POSIX shells at all, and +# even some reasonably current systems (Solaris 10 as case-in-point) still +# have a pre-POSIX /bin/sh. + me=`echo "$0" | sed -e 's,.*/,,'` usage="\ @@ -57,7 +66,7 @@ Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS Canonicalize a configuration name. -Operation modes: +Options: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit @@ -67,7 +76,7 @@ Report bugs and patches to ." version="\ GNU config.sub ($timestamp) -Copyright 1992-2016 Free Software Foundation, Inc. +Copyright 1992-2022 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." @@ -89,12 +98,12 @@ while test $# -gt 0 ; do - ) # Use stdin as input. break ;; -* ) - echo "$me: invalid option $1$help" + echo "$me: invalid option $1$help" >&2 exit 1 ;; *local*) # First pass through any local machine types. - echo $1 + echo "$1" exit ;; * ) @@ -110,1242 +119,1186 @@ case $# in exit 1;; esac -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \ - linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \ - knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \ - kopensolaris*-gnu* | cloudabi*-eabi* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - android-linux) - os=-linux-android - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac +# Split fields of configuration type +# shellcheck disable=SC2162 +saved_IFS=$IFS +IFS="-" read field1 field2 field3 field4 <&2 + exit 1 ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + *-*-*-*) + basic_machine=$field1-$field2 + basic_os=$field3-$field4 ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` + *-*-*) + # Ambiguous whether COMPANY is present, or skipped and KERNEL-OS is two + # parts + maybe_os=$field2-$field3 + case $maybe_os in + nto-qnx* | linux-* | uclinux-uclibc* \ + | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* \ + | netbsd*-eabi* | kopensolaris*-gnu* | cloudabi*-eabi* \ + | storm-chaos* | os2-emx* | rtmk-nova*) + basic_machine=$field1 + basic_os=$maybe_os + ;; + android-linux) + basic_machine=$field1-unknown + basic_os=linux-android + ;; + *) + basic_machine=$field1-$field2 + basic_os=$field3 + ;; + esac ;; - -psos*) - os=-psos + *-*) + # A lone config we happen to match not fitting any pattern + case $field1-$field2 in + decstation-3100) + basic_machine=mips-dec + basic_os= + ;; + *-*) + # Second component is usually, but not always the OS + case $field2 in + # Prevent following clause from handling this valid os + sun*os*) + basic_machine=$field1 + basic_os=$field2 + ;; + zephyr*) + basic_machine=$field1-unknown + basic_os=$field2 + ;; + # Manufacturers + dec* | mips* | sequent* | encore* | pc533* | sgi* | sony* \ + | att* | 7300* | 3300* | delta* | motorola* | sun[234]* \ + | unicom* | ibm* | next | hp | isi* | apollo | altos* \ + | convergent* | ncr* | news | 32* | 3600* | 3100* \ + | hitachi* | c[123]* | convex* | sun | crds | omron* | dg \ + | ultra | tti* | harris | dolphin | highlevel | gould \ + | cbm | ns | masscomp | apple | axis | knuth | cray \ + | microblaze* | sim | cisco \ + | oki | wec | wrs | winbond) + basic_machine=$field1-$field2 + basic_os= + ;; + *) + basic_machine=$field1 + basic_os=$field2 + ;; + esac + ;; + esac ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint + *) + # Convert single-component short-hands not valid as part of + # multi-component configurations. + case $field1 in + 386bsd) + basic_machine=i386-pc + basic_os=bsd + ;; + a29khif) + basic_machine=a29k-amd + basic_os=udi + ;; + adobe68k) + basic_machine=m68010-adobe + basic_os=scout + ;; + alliant) + basic_machine=fx80-alliant + basic_os= + ;; + altos | altos3068) + basic_machine=m68k-altos + basic_os= + ;; + am29k) + basic_machine=a29k-none + basic_os=bsd + ;; + amdahl) + basic_machine=580-amdahl + basic_os=sysv + ;; + amiga) + basic_machine=m68k-unknown + basic_os= + ;; + amigaos | amigados) + basic_machine=m68k-unknown + basic_os=amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + basic_os=sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + basic_os=sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + basic_os=bsd + ;; + aros) + basic_machine=i386-pc + basic_os=aros + ;; + aux) + basic_machine=m68k-apple + basic_os=aux + ;; + balance) + basic_machine=ns32k-sequent + basic_os=dynix + ;; + blackfin) + basic_machine=bfin-unknown + basic_os=linux + ;; + cegcc) + basic_machine=arm-unknown + basic_os=cegcc + ;; + convex-c1) + basic_machine=c1-convex + basic_os=bsd + ;; + convex-c2) + basic_machine=c2-convex + basic_os=bsd + ;; + convex-c32) + basic_machine=c32-convex + basic_os=bsd + ;; + convex-c34) + basic_machine=c34-convex + basic_os=bsd + ;; + convex-c38) + basic_machine=c38-convex + basic_os=bsd + ;; + cray) + basic_machine=j90-cray + basic_os=unicos + ;; + crds | unos) + basic_machine=m68k-crds + basic_os= + ;; + da30) + basic_machine=m68k-da30 + basic_os= + ;; + decstation | pmax | pmin | dec3100 | decstatn) + basic_machine=mips-dec + basic_os= + ;; + delta88) + basic_machine=m88k-motorola + basic_os=sysv3 + ;; + dicos) + basic_machine=i686-pc + basic_os=dicos + ;; + djgpp) + basic_machine=i586-pc + basic_os=msdosdjgpp + ;; + ebmon29k) + basic_machine=a29k-amd + basic_os=ebmon + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + basic_os=ose + ;; + gmicro) + basic_machine=tron-gmicro + basic_os=sysv + ;; + go32) + basic_machine=i386-pc + basic_os=go32 + ;; + h8300hms) + basic_machine=h8300-hitachi + basic_os=hms + ;; + h8300xray) + basic_machine=h8300-hitachi + basic_os=xray + ;; + h8500hms) + basic_machine=h8500-hitachi + basic_os=hms + ;; + harris) + basic_machine=m88k-harris + basic_os=sysv3 + ;; + hp300 | hp300hpux) + basic_machine=m68k-hp + basic_os=hpux + ;; + hp300bsd) + basic_machine=m68k-hp + basic_os=bsd + ;; + hppaosf) + basic_machine=hppa1.1-hp + basic_os=osf + ;; + hppro) + basic_machine=hppa1.1-hp + basic_os=proelf + ;; + i386mach) + basic_machine=i386-mach + basic_os=mach + ;; + isi68 | isi) + basic_machine=m68k-isi + basic_os=sysv + ;; + m68knommu) + basic_machine=m68k-unknown + basic_os=linux + ;; + magnum | m3230) + basic_machine=mips-mips + basic_os=sysv + ;; + merlin) + basic_machine=ns32k-utek + basic_os=sysv + ;; + mingw64) + basic_machine=x86_64-pc + basic_os=mingw64 + ;; + mingw32) + basic_machine=i686-pc + basic_os=mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + basic_os=mingw32ce + ;; + monitor) + basic_machine=m68k-rom68k + basic_os=coff + ;; + morphos) + basic_machine=powerpc-unknown + basic_os=morphos + ;; + moxiebox) + basic_machine=moxie-unknown + basic_os=moxiebox + ;; + msdos) + basic_machine=i386-pc + basic_os=msdos + ;; + msys) + basic_machine=i686-pc + basic_os=msys + ;; + mvs) + basic_machine=i370-ibm + basic_os=mvs + ;; + nacl) + basic_machine=le32-unknown + basic_os=nacl + ;; + ncr3000) + basic_machine=i486-ncr + basic_os=sysv4 + ;; + netbsd386) + basic_machine=i386-pc + basic_os=netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + basic_os=linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + basic_os=newsos + ;; + news1000) + basic_machine=m68030-sony + basic_os=newsos + ;; + necv70) + basic_machine=v70-nec + basic_os=sysv + ;; + nh3000) + basic_machine=m68k-harris + basic_os=cxux + ;; + nh[45]000) + basic_machine=m88k-harris + basic_os=cxux + ;; + nindy960) + basic_machine=i960-intel + basic_os=nindy + ;; + mon960) + basic_machine=i960-intel + basic_os=mon960 + ;; + nonstopux) + basic_machine=mips-compaq + basic_os=nonstopux + ;; + os400) + basic_machine=powerpc-ibm + basic_os=os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + basic_os=ose + ;; + os68k) + basic_machine=m68k-none + basic_os=os68k + ;; + paragon) + basic_machine=i860-intel + basic_os=osf + ;; + parisc) + basic_machine=hppa-unknown + basic_os=linux + ;; + psp) + basic_machine=mipsallegrexel-sony + basic_os=psp + ;; + pw32) + basic_machine=i586-unknown + basic_os=pw32 + ;; + rdos | rdos64) + basic_machine=x86_64-pc + basic_os=rdos + ;; + rdos32) + basic_machine=i386-pc + basic_os=rdos + ;; + rom68k) + basic_machine=m68k-rom68k + basic_os=coff + ;; + sa29200) + basic_machine=a29k-amd + basic_os=udi + ;; + sei) + basic_machine=mips-sei + basic_os=seiux + ;; + sequent) + basic_machine=i386-sequent + basic_os= + ;; + sps7) + basic_machine=m68k-bull + basic_os=sysv2 + ;; + st2000) + basic_machine=m68k-tandem + basic_os= + ;; + stratus) + basic_machine=i860-stratus + basic_os=sysv4 + ;; + sun2) + basic_machine=m68000-sun + basic_os= + ;; + sun2os3) + basic_machine=m68000-sun + basic_os=sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + basic_os=sunos4 + ;; + sun3) + basic_machine=m68k-sun + basic_os= + ;; + sun3os3) + basic_machine=m68k-sun + basic_os=sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + basic_os=sunos4 + ;; + sun4) + basic_machine=sparc-sun + basic_os= + ;; + sun4os3) + basic_machine=sparc-sun + basic_os=sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + basic_os=sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + basic_os=solaris2 + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + basic_os= + ;; + sv1) + basic_machine=sv1-cray + basic_os=unicos + ;; + symmetry) + basic_machine=i386-sequent + basic_os=dynix + ;; + t3e) + basic_machine=alphaev5-cray + basic_os=unicos + ;; + t90) + basic_machine=t90-cray + basic_os=unicos + ;; + toad1) + basic_machine=pdp10-xkl + basic_os=tops20 + ;; + tpf) + basic_machine=s390x-ibm + basic_os=tpf + ;; + udi29k) + basic_machine=a29k-amd + basic_os=udi + ;; + ultra3) + basic_machine=a29k-nyu + basic_os=sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + basic_os=none + ;; + vaxv) + basic_machine=vax-dec + basic_os=sysv + ;; + vms) + basic_machine=vax-dec + basic_os=vms + ;; + vsta) + basic_machine=i386-pc + basic_os=vsta + ;; + vxworks960) + basic_machine=i960-wrs + basic_os=vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + basic_os=vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + basic_os=vxworks + ;; + xbox) + basic_machine=i686-pc + basic_os=mingw32 + ;; + ymp) + basic_machine=ymp-cray + basic_os=unicos + ;; + *) + basic_machine=$1 + basic_os= + ;; + esac ;; esac -# Decode aliases for certain CPU-COMPANY combinations. +# Decode 1-component or ad-hoc basic machines case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | aarch64 | aarch64_be \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arceb \ - | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \ - | avr | avr32 \ - | ba \ - | be32 | be64 \ - | bfin \ - | c4x | c8051 | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | e2k | epiphany \ - | fido | fr30 | frv | ft32 \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | hexagon \ - | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ - | k1om \ - | le32 | le64 \ - | lm32 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | microblazeel | mcore | mep | metag \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64octeon | mips64octeonel \ - | mips64orion | mips64orionel \ - | mips64r5900 | mips64r5900el \ - | mips64vr | mips64vrel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa32r6 | mipsisa32r6el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64r6 | mipsisa64r6el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipsr5900 | mipsr5900el \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | moxie \ - | mt \ - | msp430 \ - | nds32 | nds32le | nds32be \ - | nios | nios2 | nios2eb | nios2el \ - | ns16k | ns32k \ - | open8 | or1k | or1knd | or32 \ - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle \ - | pyramid \ - | riscv32 | riscv64 \ - | rl78 | rx \ - | score \ - | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu \ - | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \ - | ubicom32 \ - | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \ - | visium \ - | we32k \ - | x86 | xc16x | xstormy16 | xtensa \ - | z8k | z80) - basic_machine=$basic_machine-unknown - ;; - c54x) - basic_machine=tic54x-unknown - ;; - c55x) - basic_machine=tic55x-unknown - ;; - c6x) - basic_machine=tic6x-unknown - ;; - leon|leon[3-9]) - basic_machine=sparc-$basic_machine - ;; - m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip) - basic_machine=$basic_machine-unknown - os=-none + # Here we handle the default manufacturer of certain CPU types. It is in + # some cases the only manufacturer, in others, it is the most popular. + w89k) + cpu=hppa1.1 + vendor=winbond ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + op50n) + cpu=hppa1.1 + vendor=oki ;; - ms1) - basic_machine=mt-unknown + op60c) + cpu=hppa1.1 + vendor=oki ;; - - strongarm | thumb | xscale) - basic_machine=arm-unknown + ibm*) + cpu=i370 + vendor=ibm ;; - xgate) - basic_machine=$basic_machine-unknown - os=-none + orion105) + cpu=clipper + vendor=highlevel ;; - xscaleeb) - basic_machine=armeb-unknown + mac | mpw | mac-mpw) + cpu=m68k + vendor=apple ;; - - xscaleel) - basic_machine=armel-unknown + pmac | pmac-mpw) + cpu=powerpc + vendor=apple ;; - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i*86 | x86_64) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | aarch64-* | aarch64_be-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | ba-* \ - | be32-* | be64-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* \ - | c8051-* | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | e2k-* | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | hexagon-* \ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | k1om-* \ - | le32-* | le64-* \ - | lm32-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ - | microblaze-* | microblazeel-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64octeon-* | mips64octeonel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64r5900-* | mips64r5900el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa32r6-* | mipsisa32r6el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64r6-* | mipsisa64r6el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipsr5900-* | mipsr5900el-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nds32-* | nds32le-* | nds32be-* \ - | nios-* | nios2-* | nios2eb-* | nios2el-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | open8-* \ - | or1k*-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \ - | pyramid-* \ - | riscv32-* | riscv64-* \ - | rl78-* | romp-* | rs6000-* | rx-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \ - | tahoe-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tile*-* \ - | tron-* \ - | ubicom32-* \ - | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \ - | vax-* \ - | visium-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* \ - | xstormy16-* | xtensa*-* \ - | ymp-* \ - | z8k-* | z80-*) - ;; - # Recognize the basic CPU types without company name, with glob match. - xtensa*) - basic_machine=$basic_machine-unknown - ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att + cpu=m68000 + vendor=att ;; 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aros) - basic_machine=i386-pc - os=-aros - ;; - asmjs) - basic_machine=asmjs-unknown - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - blackfin) - basic_machine=bfin-unknown - os=-linux - ;; - blackfin-*) - basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + cpu=we32k + vendor=att ;; bluegene*) - basic_machine=powerpc-ibm - os=-cnk - ;; - c54x-*) - basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c55x-*) - basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c6x-*) - basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - cegcc) - basic_machine=arm-unknown - os=-cegcc - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16 | cr16-*) - basic_machine=cr16-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec + cpu=powerpc + vendor=ibm + basic_os=cnk ;; decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 + cpu=pdp10 + vendor=dec + basic_os=tops10 ;; decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 + cpu=pdp10 + vendor=dec + basic_os=tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - dicos) - basic_machine=i686-pc - os=-dicos + cpu=m68k + vendor=motorola ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - os=-sysv3 - ;; - e500v[12]) - basic_machine=powerpc-unknown - os=$os"spe" - ;; - e500v[12]-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - os=$os"spe" - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd + dpx2*) + cpu=m68k + vendor=bull + basic_os=sysv3 ;; encore | umax | mmax) - basic_machine=ns32k-encore + cpu=ns32k + vendor=encore ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose + elxsi) + cpu=elxsi + vendor=elxsi + basic_os=${basic_os:-bsd} ;; fx2800) - basic_machine=i860-alliant + cpu=i860 + vendor=alliant ;; genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 + cpu=ns32k + vendor=ns ;; h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp + cpu=hppa1.0 + vendor=hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp + cpu=m68000 + vendor=hp ;; hp9k3[2-9][0-9]) - basic_machine=m68k-hp + cpu=m68k + vendor=hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp + cpu=hppa1.0 + vendor=hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp + cpu=hppa1.1 + vendor=hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp + cpu=hppa1.1 + vendor=hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp + cpu=hppa1.1 + vendor=hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp + cpu=hppa1.1 + vendor=hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm + cpu=hppa1.0 + vendor=hp ;; i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv32 ;; i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv4 ;; i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=sysv ;; i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 + cpu=`echo "$1" | sed -e 's/86.*/86/'` + vendor=pc + basic_os=solaris2 ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta + j90 | j90-cray) + cpu=j90 + vendor=cray + basic_os=${basic_os:-unicos} ;; iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) + cpu=mips + vendor=sgi + case $basic_os in + irix*) ;; *) - os=-irix4 + basic_os=irix4 ;; esac ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - leon-*|leon[3-9]-*) - basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'` - ;; - m68knommu) - basic_machine=m68k-unknown - os=-linux - ;; - m68knommu-*) - basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - microblaze*) - basic_machine=microblaze-xilinx - ;; - mingw64) - basic_machine=x86_64-pc - os=-mingw64 - ;; - mingw32) - basic_machine=i686-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - moxiebox) - basic_machine=moxie-unknown - os=-moxiebox - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - msys) - basic_machine=i686-pc - os=-msys - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - nacl) - basic_machine=le32-unknown - os=-nacl + cpu=m68000 + vendor=convergent ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos + *mint | mint[0-9]* | *MiNT | *MiNT[0-9]*) + cpu=m68k + vendor=atari + basic_os=mint ;; news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) + cpu=mips + vendor=sony + basic_os=newsos + ;; + next | m*-next) + cpu=m68k + vendor=next + case $basic_os in + openstep*) + ;; + nextstep*) ;; - -ns2*) - os=-nextstep2 + ns2*) + basic_os=nextstep2 ;; *) - os=-nextstep3 + basic_os=nextstep3 ;; esac ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; np1) - basic_machine=np1-gould - ;; - neo-tandem) - basic_machine=neo-tandem - ;; - nse-tandem) - basic_machine=nse-tandem - ;; - nsr-tandem) - basic_machine=nsr-tandem + cpu=np1 + vendor=gould ;; op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k + cpu=hppa1.1 + vendor=oki + basic_os=proelf ;; pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - parisc) - basic_machine=hppa-unknown - os=-linux - ;; - parisc-*) - basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` - os=-linux + cpu=hppa1.1 + vendor=hitachi + basic_os=hiuxwe2 ;; pbd) - basic_machine=sparc-tti + cpu=sparc + vendor=tti ;; pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc + cpu=m68k + vendor=tti ;; - pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + pc532) + cpu=ns32k + vendor=pc532 ;; pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm - ;; - ppc | ppcbe) basic_machine=powerpc-unknown + cpu=pn + vendor=gould ;; - ppc-* | ppcbe-*) - basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + power) + cpu=power + vendor=ibm ;; ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos | rdos64) - basic_machine=x86_64-pc - os=-rdos - ;; - rdos32) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff + cpu=i386 + vendor=ibm ;; rm[46]00) - basic_machine=mips-siemens + cpu=mips + vendor=siemens ;; rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm + cpu=romp + vendor=ibm ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi + sde) + cpu=mipsisa32 + vendor=sde + basic_os=${basic_os:-elf} ;; - sb1) - basic_machine=mipsisa64sb1-unknown + simso-wrs) + cpu=sparclite + vendor=wrs + basic_os=vxworks ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown + tower | tower-32) + cpu=m68k + vendor=ncr ;; - sde) - basic_machine=mipsisa32-sde - os=-elf + vpp*|vx|vx-*) + cpu=f301 + vendor=fujitsu ;; - sei) - basic_machine=mips-sei - os=-seiux + w65) + cpu=w65 + vendor=wdc ;; - sequent) - basic_machine=i386-sequent + w89k-*) + cpu=hppa1.1 + vendor=winbond + basic_os=proelf ;; - sh) - basic_machine=sh-hitachi - os=-hms + none) + cpu=none + vendor=none ;; - sh5el) - basic_machine=sh5le-unknown + leon|leon[3-9]) + cpu=sparc + vendor=$basic_machine ;; - sh64) - basic_machine=sh64-unknown + leon-*|leon[3-9]-*) + cpu=sparc + vendor=`echo "$basic_machine" | sed 's/-.*//'` ;; - sparclite-wrs | simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks + + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read cpu vendor <&2 - exit 1 + # Recognize the canonical CPU types that are allowed with any + # company name. + case $cpu in + 1750a | 580 \ + | a29k \ + | aarch64 | aarch64_be \ + | abacus \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] \ + | alphapca5[67] | alpha64pca5[67] \ + | am33_2.0 \ + | amdgcn \ + | arc | arceb | arc32 | arc64 \ + | arm | arm[lb]e | arme[lb] | armv* \ + | avr | avr32 \ + | asmjs \ + | ba \ + | be32 | be64 \ + | bfin | bpf | bs2000 \ + | c[123]* | c30 | [cjt]90 | c4x \ + | c8051 | clipper | craynv | csky | cydra \ + | d10v | d30v | dlx | dsp16xx \ + | e2k | elxsi | epiphany \ + | f30[01] | f700 | fido | fr30 | frv | ft32 | fx80 \ + | h8300 | h8500 \ + | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | hexagon \ + | i370 | i*86 | i860 | i960 | ia16 | ia64 \ + | ip2k | iq2000 \ + | k1om \ + | le32 | le64 \ + | lm32 \ + | loongarch32 | loongarch64 | loongarchx32 \ + | m32c | m32r | m32rle \ + | m5200 | m68000 | m680[012346]0 | m68360 | m683?2 | m68k \ + | m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x \ + | m88110 | m88k | maxq | mb | mcore | mep | metag \ + | microblaze | microblazeel \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64eb | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa32r3 | mipsisa32r3el \ + | mipsisa32r5 | mipsisa32r5el \ + | mipsisa32r6 | mipsisa32r6el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64r3 | mipsisa64r3el \ + | mipsisa64r5 | mipsisa64r5el \ + | mipsisa64r6 | mipsisa64r6el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipsr5900 | mipsr5900el \ + | mipstx39 | mipstx39el \ + | mmix \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nds32 | nds32le | nds32be \ + | nfp \ + | nios | nios2 | nios2eb | nios2el \ + | none | np1 | ns16k | ns32k | nvptx \ + | open8 \ + | or1k* \ + | or32 \ + | orion \ + | picochip \ + | pdp10 | pdp11 | pj | pjl | pn | power \ + | powerpc | powerpc64 | powerpc64le | powerpcle | powerpcspe \ + | pru \ + | pyramid \ + | riscv | riscv32 | riscv32be | riscv64 | riscv64be \ + | rl78 | romp | rs6000 | rx \ + | s390 | s390x \ + | score \ + | sh | shl \ + | sh[1234] | sh[24]a | sh[24]ae[lb] | sh[23]e | she[lb] | sh[lb]e \ + | sh[1234]e[lb] | sh[12345][lb]e | sh[23]ele | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet \ + | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v | sv1 | sx* \ + | spu \ + | tahoe \ + | thumbv7* \ + | tic30 | tic4x | tic54x | tic55x | tic6x | tic80 \ + | tron \ + | ubicom32 \ + | v70 | v850 | v850e | v850e1 | v850es | v850e2 | v850e2v3 \ + | vax \ + | visium \ + | w65 \ + | wasm32 | wasm64 \ + | we32k \ + | x86 | x86_64 | xc16x | xgate | xps100 \ + | xstormy16 | xtensa* \ + | ymp \ + | z8k | z80) + ;; + + *) + echo Invalid configuration \`"$1"\': machine \`"$cpu-$vendor"\' not recognized 1>&2 + exit 1 + ;; + esac ;; esac # Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` +case $vendor in + digital*) + vendor=dec ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + commodore*) + vendor=cbm ;; *) ;; @@ -1353,203 +1306,215 @@ esac # Decode manufacturer-specific aliases for certain operating systems. -if [ x"$os" != x"" ] +if test x$basic_os != x then -case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -auroraux) - os=-auroraux + +# First recognize some ad-hoc cases, or perhaps split kernel-os, or else just +# set os. +case $basic_os in + gnu/linux*) + kernel=linux + os=`echo "$basic_os" | sed -e 's|gnu/linux|gnu|'` + ;; + os2-emx) + kernel=os2 + os=`echo "$basic_os" | sed -e 's|os2-emx|emx|'` + ;; + nto-qnx*) + kernel=nto + os=`echo "$basic_os" | sed -e 's|nto-qnx|qnx|'` + ;; + *-*) + # shellcheck disable=SC2162 + saved_IFS=$IFS + IFS="-" read kernel os <&2 - exit 1 + # No normalization, but not necessarily accepted, that comes below. ;; esac + else # Here we handle the default operating systems that come with various machines. @@ -1562,261 +1527,363 @@ else # will signal an error saying that MANUFACTURER isn't an operating # system, and we'll never get to this point. -case $basic_machine in +kernel= +case $cpu-$vendor in score-*) - os=-elf + os=elf ;; spu-*) - os=-elf + os=elf ;; *-acorn) - os=-riscix1.2 + os=riscix1.2 ;; arm*-rebel) - os=-linux + kernel=linux + os=gnu ;; arm*-semi) - os=-aout + os=aout ;; c4x-* | tic4x-*) - os=-coff + os=coff ;; c8051-*) - os=-elf + os=elf + ;; + clipper-intergraph) + os=clix ;; hexagon-*) - os=-elf + os=elf ;; tic54x-*) - os=-coff + os=coff ;; tic55x-*) - os=-coff + os=coff ;; tic6x-*) - os=-coff + os=coff ;; # This must come before the *-dec entry. pdp10-*) - os=-tops20 + os=tops20 ;; pdp11-*) - os=-none + os=none ;; *-dec | vax-*) - os=-ultrix4.2 + os=ultrix4.2 ;; m68*-apollo) - os=-domain + os=domain ;; i386-sun) - os=-sunos4.0.2 + os=sunos4.0.2 ;; m68000-sun) - os=-sunos3 + os=sunos3 ;; m68*-cisco) - os=-aout + os=aout ;; mep-*) - os=-elf + os=elf ;; mips*-cisco) - os=-elf + os=elf ;; mips*-*) - os=-elf + os=elf ;; or32-*) - os=-coff + os=coff ;; *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 + os=sysv3 ;; sparc-* | *-sun) - os=-sunos4.1.1 + os=sunos4.1.1 ;; - *-be) - os=-beos + pru-*) + os=elf ;; - *-haiku) - os=-haiku + *-be) + os=beos ;; *-ibm) - os=-aix + os=aix ;; *-knuth) - os=-mmixware + os=mmixware ;; *-wec) - os=-proelf + os=proelf ;; *-winbond) - os=-proelf + os=proelf ;; *-oki) - os=-proelf + os=proelf ;; *-hp) - os=-hpux + os=hpux ;; *-hitachi) - os=-hiux + os=hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv + os=sysv ;; *-cbm) - os=-amigaos + os=amigaos ;; *-dg) - os=-dgux + os=dgux ;; *-dolphin) - os=-sysv3 + os=sysv3 ;; m68k-ccur) - os=-rtu + os=rtu ;; m88k-omron*) - os=-luna + os=luna ;; - *-next ) - os=-nextstep + *-next) + os=nextstep ;; *-sequent) - os=-ptx + os=ptx ;; *-crds) - os=-unos + os=unos ;; *-ns) - os=-genix + os=genix ;; i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 + os=mvs ;; *-gould) - os=-sysv + os=sysv ;; *-highlevel) - os=-bsd + os=bsd ;; *-encore) - os=-bsd + os=bsd ;; *-sgi) - os=-irix + os=irix ;; *-siemens) - os=-sysv4 + os=sysv4 ;; *-masscomp) - os=-rtu + os=rtu ;; f30[01]-fujitsu | f700-fujitsu) - os=-uxpv + os=uxpv ;; *-rom68k) - os=-coff + os=coff ;; *-*bug) - os=-coff + os=coff ;; *-apple) - os=-macos + os=macos ;; *-atari*) - os=-mint + os=mint + ;; + *-wrs) + os=vxworks ;; *) - os=-none + os=none ;; esac + fi +# Now, validate our (potentially fixed-up) OS. +case $os in + # Sometimes we do "kernel-libc", so those need to count as OSes. + musl* | newlib* | relibc* | uclibc*) + ;; + # Likewise for "kernel-abi" + eabi* | gnueabi*) + ;; + # VxWorks passes extra cpu info in the 4th filed. + simlinux | simwindows | spe) + ;; + # Now accept the basic system types. + # The portable systems comes first. + # Each alternative MUST end in a * to match a version number. + gnu* | android* | bsd* | mach* | minix* | genix* | ultrix* | irix* \ + | *vms* | esix* | aix* | cnk* | sunos | sunos[34]* \ + | hpux* | unos* | osf* | luna* | dgux* | auroraux* | solaris* \ + | sym* | plan9* | psp* | sim* | xray* | os68k* | v88r* \ + | hiux* | abug | nacl* | netware* | windows* \ + | os9* | macos* | osx* | ios* \ + | mpw* | magic* | mmixware* | mon960* | lnews* \ + | amigaos* | amigados* | msdos* | newsos* | unicos* | aof* \ + | aos* | aros* | cloudabi* | sortix* | twizzler* \ + | nindy* | vxsim* | vxworks* | ebmon* | hms* | mvs* \ + | clix* | riscos* | uniplus* | iris* | isc* | rtu* | xenix* \ + | mirbsd* | netbsd* | dicos* | openedition* | ose* \ + | bitrig* | openbsd* | secbsd* | solidbsd* | libertybsd* | os108* \ + | ekkobsd* | freebsd* | riscix* | lynxos* | os400* \ + | bosx* | nextstep* | cxux* | aout* | elf* | oabi* \ + | ptx* | coff* | ecoff* | winnt* | domain* | vsta* \ + | udi* | lites* | ieee* | go32* | aux* | hcos* \ + | chorusrdb* | cegcc* | glidix* | serenity* \ + | cygwin* | msys* | pe* | moss* | proelf* | rtems* \ + | midipix* | mingw32* | mingw64* | mint* \ + | uxpv* | beos* | mpeix* | udk* | moxiebox* \ + | interix* | uwin* | mks* | rhapsody* | darwin* \ + | openstep* | oskit* | conix* | pw32* | nonstopux* \ + | storm-chaos* | tops10* | tenex* | tops20* | its* \ + | os2* | vos* | palmos* | uclinux* | nucleus* | morphos* \ + | scout* | superux* | sysv* | rtmk* | tpf* | windiss* \ + | powermax* | dnix* | nx6 | nx7 | sei* | dragonfly* \ + | skyos* | haiku* | rdos* | toppers* | drops* | es* \ + | onefs* | tirtos* | phoenix* | fuchsia* | redox* | bme* \ + | midnightbsd* | amdhsa* | unleashed* | emscripten* | wasi* \ + | nsk* | powerunix* | genode* | zvmoe* | qnx* | emx* | zephyr* \ + | fiwix* ) + ;; + # This one is extra strict with allowed versions + sco3.2v2 | sco3.2v[4-9]* | sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + ;; + none) + ;; + *) + echo Invalid configuration \`"$1"\': OS \`"$os"\' not recognized 1>&2 + exit 1 + ;; +esac + +# As a final step for OS-related things, validate the OS-kernel combination +# (given a valid OS), if there is a kernel. +case $kernel-$os in + linux-gnu* | linux-dietlibc* | linux-android* | linux-newlib* \ + | linux-musl* | linux-relibc* | linux-uclibc* ) + ;; + uclinux-uclibc* ) + ;; + -dietlibc* | -newlib* | -musl* | -relibc* | -uclibc* ) + # These are just libc implementations, not actual OSes, and thus + # require a kernel. + echo "Invalid configuration \`$1': libc \`$os' needs explicit kernel." 1>&2 + exit 1 + ;; + kfreebsd*-gnu* | kopensolaris*-gnu*) + ;; + vxworks-simlinux | vxworks-simwindows | vxworks-spe) + ;; + nto-qnx*) + ;; + os2-emx) + ;; + *-eabi* | *-gnueabi*) + ;; + -*) + # Blank kernel with real OS is always fine. + ;; + *-*) + echo "Invalid configuration \`$1': Kernel \`$kernel' not known to work with OS \`$os'." 1>&2 + exit 1 + ;; +esac + # Here we handle the case where we know the os, and the CPU type, but not the # manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) +case $vendor in + unknown) + case $cpu-$os in + *-riscix*) vendor=acorn ;; - -sunos*) + *-sunos*) vendor=sun ;; - -cnk*|-aix*) + *-cnk* | *-aix*) vendor=ibm ;; - -beos*) + *-beos*) vendor=be ;; - -hpux*) + *-hpux*) vendor=hp ;; - -mpeix*) + *-mpeix*) vendor=hp ;; - -hiux*) + *-hiux*) vendor=hitachi ;; - -unos*) + *-unos*) vendor=crds ;; - -dgux*) + *-dgux*) vendor=dg ;; - -luna*) + *-luna*) vendor=omron ;; - -genix*) + *-genix*) vendor=ns ;; - -mvs* | -opened*) + *-clix*) + vendor=intergraph + ;; + *-mvs* | *-opened*) + vendor=ibm + ;; + *-os400*) vendor=ibm ;; - -os400*) + s390-* | s390x-*) vendor=ibm ;; - -ptx*) + *-ptx*) vendor=sequent ;; - -tpf*) + *-tpf*) vendor=ibm ;; - -vxsim* | -vxworks* | -windiss*) + *-vxsim* | *-vxworks* | *-windiss*) vendor=wrs ;; - -aux*) + *-aux*) vendor=apple ;; - -hms*) + *-hms*) vendor=hitachi ;; - -mpw* | -macos*) + *-mpw* | *-macos*) vendor=apple ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + *-*mint | *-mint[0-9]* | *-*MiNT | *-MiNT[0-9]*) vendor=atari ;; - -vos*) + *-vos*) vendor=stratus ;; esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac -echo $basic_machine$os +echo "$cpu-$vendor-${kernel:+$kernel-}$os" exit # Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) +# eval: (add-hook 'before-save-hook 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" From e841e8c7df3bb8ff0bedcba5f4756c7380fcf254 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 18 Aug 2022 10:51:07 -0400 Subject: [PATCH 05/19] Add a roll to the default color printer. --- CHANGES.md | 1 + tools/ippeveprinter.c | 145 +++++++++++++----- .../xcshareddata/xcschemes/libcups.xcscheme | 4 +- 3 files changed, 113 insertions(+), 37 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index be7d5802c..0b03ea2bc 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -18,6 +18,7 @@ libcups v3.0b1 (Month DD, YYYY) files (Issue #3) - Added `ippFile` API for working with IPP data files as used by `ipptool`, `ippexeprinter`, and other tools (Issue #14) +- Added a roll to the default color ippeveprinter printer. - Updated the CUPS API for consistency. - Removed all obsolete/deprecated CUPS 2.x APIs. - Removed (obsolete) Kerberos support. diff --git a/tools/ippeveprinter.c b/tools/ippeveprinter.c index c814af714..f24e3f7cf 100644 --- a/tools/ippeveprinter.c +++ b/tools/ippeveprinter.c @@ -268,8 +268,9 @@ static ippeve_client_t *create_client(ippeve_printer_t *printer, int sock); static ippeve_job_t *create_job(ippeve_client_t *client); static int create_job_file(ippeve_job_t *job, char *fname, size_t fnamesize, const char *dir, const char *ext); static int create_listener(const char *name, int port, int family); -static ipp_t *create_media_col(const char *media, const char *source, const char *type, int width, int length, int bottom, int left, int right, int top); +static ipp_t *create_media_col(const char *media, const char *source, const char *type, ipp_t *media_size, int bottom, int left, int right, int top); static ipp_t *create_media_size(int width, int length); +static ipp_t *create_media_size_range(int min_width, int max_width, int min_length, int max_length); static ippeve_printer_t *create_printer(const char *servername, int serverport, const char *name, const char *location, const char *icons, const char *strings, cups_array_t *docformats, const char *subtypes, const char *directory, const char *command, const char *device_uri, const char *output_format, ipp_t *attrs); static void debug_attributes(const char *title, ipp_t *ipp, int response); static void delete_client(ippeve_client_t *client); @@ -1282,16 +1283,13 @@ static ipp_t * /* O - media-col collection */ create_media_col(const char *media, /* I - Media name */ const char *source, /* I - Media source, if any */ const char *type, /* I - Media type, if any */ - int width, /* I - x-dimension in 2540ths */ - int length, /* I - y-dimension in 2540ths */ + ipp_t *media_size,/* I - media-size collection value */ int bottom, /* I - Bottom margin in 2540ths */ int left, /* I - Left margin in 2540ths */ int right, /* I - Right margin in 2540ths */ int top) /* I - Top margin in 2540ths */ { - ipp_t *media_col = ippNew(), /* media-col value */ - *media_size = create_media_size(width, length); - /* media-size value */ + ipp_t *media_col = ippNew(); /* media-col value */ char media_key[256]; /* media-key value */ const char *media_key_suffix = ""; /* media-key suffix */ @@ -1299,18 +1297,22 @@ create_media_col(const char *media, /* I - Media name */ if (bottom == 0 && left == 0 && right == 0 && top == 0) media_key_suffix = "_borderless"; - if (type && source) - snprintf(media_key, sizeof(media_key), "%s_%s_%s%s", media, source, type, media_key_suffix); - else if (type) - snprintf(media_key, sizeof(media_key), "%s__%s%s", media, type, media_key_suffix); - else if (source) - snprintf(media_key, sizeof(media_key), "%s_%s%s", media, source, media_key_suffix); - else - snprintf(media_key, sizeof(media_key), "%s%s", media, media_key_suffix); + if (media) + { + if (type && source) + snprintf(media_key, sizeof(media_key), "%s_%s_%s%s", media, source, type, media_key_suffix); + else if (type) + snprintf(media_key, sizeof(media_key), "%s__%s%s", media, type, media_key_suffix); + else if (source) + snprintf(media_key, sizeof(media_key), "%s_%s%s", media, source, media_key_suffix); + else + snprintf(media_key, sizeof(media_key), "%s%s", media, media_key_suffix); - ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-key", NULL, media_key); + ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-key", NULL, media_key); + } ippAddCollection(media_col, IPP_TAG_PRINTER, "media-size", media_size); - ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-size-name", NULL, media); + if (media) + ippAddString(media_col, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-size-name", NULL, media); if (bottom >= 0) ippAddInteger(media_col, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin", bottom); if (left >= 0) @@ -1341,8 +1343,28 @@ create_media_size(int width, /* I - x-dimension in 2540ths */ ipp_t *media_size = ippNew(); /* media-size value */ - ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "x-dimension", width); - ippAddInteger(media_size, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "y-dimension", length); + ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "x-dimension", width); + ippAddInteger(media_size, IPP_TAG_ZERO, IPP_TAG_INTEGER, "y-dimension", length); + + return (media_size); +} + + +/* + * 'create_media_size_range()' - Create a ranged media-size value. + */ + +static ipp_t * /* O - media-col collection */ +create_media_size_range(int min_width, /* I - Minimum x-dimension in 2540ths */ + int max_width, /* I - Maximum x-dimension in 2540ths */ + int min_length, /* I - Minimum x-dimension in 2540ths */ + int max_length) /* I - Maximum y-dimension in 2540ths */ +{ + ipp_t *media_size = ippNew(); /* media-size value */ + + + ippAddRange(media_size, IPP_TAG_ZERO, "x-dimension", min_width, max_width); + ippAddRange(media_size, IPP_TAG_ZERO, "y-dimension", min_length, max_length); return (media_size); } @@ -4238,6 +4260,8 @@ load_legacy_attributes( "iso_a6_105x148mm", /* A6 */ "na_5x7_5x7in", /* Photo 5x7 aka 2L */ "iso_a5_148x210mm", /* A5 */ + "roll_min_4x1in", /* Roll */ + "roll_max_8.5x39.6in" /* Roll */ }; static const char * const media_ready[] = { /* media-ready values */ @@ -4247,7 +4271,8 @@ load_legacy_attributes( static const char * const media_ready_color[] = { /* media-ready values */ "na_letter_8.5x11in", /* Letter */ - "na_index-4x6_4x6in" /* Photo 4x6 */ + "na_index-4x6_4x6in", /* Photo 4x6 */ + "roll_current_8.5x0in" /* 8.5" roll */ }; static const char * const media_source_supported[] = { /* media-source-supported values */ @@ -4260,7 +4285,8 @@ load_legacy_attributes( { /* media-source-supported values */ "auto", "main", - "photo" + "photo", + "roll" }; static const char * const media_type_supported[] = { /* media-type-supported values */ @@ -4360,7 +4386,8 @@ load_legacy_attributes( { /* printer-input-tray values */ "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=-2;level=-2;status=0;name=auto", "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=250;level=-2;status=0;name=main", - "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=25;level=-2;status=0;name=photo" + "type=sheetFeedAutoRemovableTray;mediafeed=0;mediaxfeed=0;maxcapacity=25;level=-2;status=0;name=photo", + "type=continuousRoll;mediafeed=0;mediaxfeed=0;maxcapacity=100;level=-2;status=0;name=roll" }; static const char * const printer_supply[] = { /* printer-supply values */ @@ -4530,8 +4557,7 @@ load_legacy_attributes( ippAddIntegers(attrs, IPP_TAG_PRINTER, IPP_TAG_INTEGER, "media-bottom-margin-supported", (int)(sizeof(media_bottom_margin_supported_color) / sizeof(media_bottom_margin_supported_color[0])), media_bottom_margin_supported_color); /* media-col-database and media-col-default */ - attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-col-database", num_media, NULL); - for (i = 0; i < num_media; i ++) + for (i = 0, attr = NULL; i < num_media; i ++) { int bottom, left, /* media-xxx-margins */ right, top; @@ -4572,8 +4598,31 @@ load_legacy_attributes( top = ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0]; } - col = create_media_col(media[i], source, NULL, pwg->width, pwg->length, bottom, left, right, top); - ippSetCollection(attrs, &attr, i, col); + if (!strncmp(media[i], "roll_min_", 9) && i < (num_media - 1)) + { + // Roll min/max range... + pwg_media_t *pwg2; // Max size + ipp_t *media_size; // media-size member attribute + + i ++; + pwg2 = pwgMediaForPWG(media[i]); + + media_size = ippNew(); + ippAddRange(media_size, IPP_TAG_ZERO, "x-dimension", pwg->width, pwg2->width); + ippAddRange(media_size, IPP_TAG_ZERO, "y-dimension", pwg->length, pwg2->length); + + col = create_media_col(NULL, source, NULL, media_size, bottom, left, right, top); + } + else + { + // Sheet size + col = create_media_col(media[i], source, NULL, create_media_size(pwg->width, pwg->length), bottom, left, right, top); + } + + if (attr) + ippSetCollection(attrs, &attr, ippGetCount(attr), col); + else + attr = ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-database", col); ippDelete(col); } @@ -4582,9 +4631,9 @@ load_legacy_attributes( pwg = pwgMediaForPWG(ready[0]); if (pwg->width == 21000) - col = create_media_col(ready[0], "main", "stationery", pwg->width, pwg->length, ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0], media_lr_margin_supported[0], media_lr_margin_supported[0], ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0]); + col = create_media_col(ready[0], "main", "stationery", create_media_size(pwg->width, pwg->length), ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0], media_lr_margin_supported[0], media_lr_margin_supported[0], ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0]); else - col = create_media_col(ready[0], "main", "stationery", pwg->width, pwg->length, ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0], media_lr_margin_supported[1], media_lr_margin_supported[1], ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0]); + col = create_media_col(ready[0], "main", "stationery", create_media_size(pwg->width, pwg->length), ppm_color > 0 ? media_bottom_margin_supported_color[1] : media_bottom_margin_supported[0], media_lr_margin_supported[1], media_lr_margin_supported[1], ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0]); ippAddCollection(attrs, IPP_TAG_PRINTER, "media-col-default", col); @@ -4638,7 +4687,7 @@ load_legacy_attributes( top = ppm_color > 0 ? media_top_margin_supported_color[1] : media_top_margin_supported[0]; } - col = create_media_col(ready[i], source, type, pwg->width, pwg->length, bottom, left, right, top); + col = create_media_col(ready[i], source, type, create_media_size(pwg->width, pwg->length), bottom, left, right, top); ippSetCollection(attrs, &attr, i, col); ippDelete(col); } @@ -4665,13 +4714,31 @@ load_legacy_attributes( ippAddStrings(attrs, IPP_TAG_PRINTER, IPP_CONST_TAG(IPP_TAG_KEYWORD), "media-supported", num_media, NULL, media); /* media-size-supported */ - attr = ippAddCollections(attrs, IPP_TAG_PRINTER, "media-size-supported", num_media, NULL); - for (i = 0; i < num_media; i ++) + for (i = 0, attr = NULL; i < num_media; i ++) { pwg = pwgMediaForPWG(media[i]); - col = create_media_size(pwg->width, pwg->length); - ippSetCollection(attrs, &attr, i, col); + if (!strncmp(media[i], "roll_min_", 9) && i < (num_media - 1)) + { + // Roll min/max range... + pwg_media_t *pwg2; // Max size + + i ++; + pwg2 = pwgMediaForPWG(media[i]); + + col = create_media_size_range(pwg->width, pwg2->width, pwg->length, pwg2->length); + } + else + { + // Sheet size... + col = create_media_size(pwg->width, pwg->length); + } + + if (attr) + ippSetCollection(attrs, &attr, ippGetCount(attr), col); + else + attr = ippAddCollection(attrs, IPP_TAG_PRINTER, "media-size-supported", col); + ippDelete(col); } @@ -7090,7 +7157,7 @@ show_media(ippeve_client_t *client) /* I - Client connection */ else media_ready = ippAddString(printer->attrs, IPP_TAG_PRINTER, IPP_TAG_KEYWORD, "media-ready", NULL, media_size); - media_col = create_media_col(media_size, media_source, media_type, media->width, media->length, -1, -1, -1, -1); + media_col = create_media_col(media_size, media_source, media_type, create_media_size(media->width, media->length), -1, -1, -1, -1); if (media_col_ready) ippSetCollection(printer->attrs, &media_col_ready, ippGetCount(media_col_ready), media_col); @@ -7107,7 +7174,10 @@ show_media(ippeve_client_t *client) /* I - Client connection */ else ready_sheets = 0; - snprintf(tray_str, sizeof(tray_str), "type=sheetFeedAuto%sRemovableTray;mediafeed=%d;mediaxfeed=%d;maxcapacity=%d;level=%d;status=0;name=%s;", !strcmp(media_source, "by-pass-tray") ? "Non" : "", media ? media->length : 0, media ? media->width : 0, strcmp(media_source, "by-pass-tray") ? 250 : 25, ready_sheets, media_source); + if (!strcmp(media_source, "roll")) + snprintf(tray_str, sizeof(tray_str), "type=continuousRoll;mediafeed=%d;mediaxfeed=%d;maxcapacity=%d;level=%d;status=0;name=%s;", media ? media->length : 0, media ? media->width : 0, 100, ready_sheets, media_source); + else + snprintf(tray_str, sizeof(tray_str), "type=sheetFeedAuto%sRemovableTray;mediafeed=%d;mediaxfeed=%d;maxcapacity=%d;level=%d;status=0;name=%s;", !strcmp(media_source, "by-pass-tray") ? "Non" : "", media ? media->length : 0, media ? media->width : 0, strcmp(media_source, "by-pass-tray") ? 250 : 25, ready_sheets, media_source); ippSetOctetString(printer->attrs, &input_tray, i, tray_str, strlen(tray_str)); @@ -7148,6 +7218,9 @@ show_media(ippeve_client_t *client) /* I - Client connection */ ready_source = ippGetString(ippFindAttribute(media_col, "media-source", IPP_TAG_ZERO), 0, NULL); ready_type = ippGetString(ippFindAttribute(media_col, "media-type", IPP_TAG_ZERO), 0, NULL); + if (!ready_size) + ready_size = ippGetString(media_ready, j, NULL); + if (ready_source && !strcmp(ready_source, media_source)) break; @@ -7165,11 +7238,13 @@ show_media(ippeve_client_t *client) /* I - Client connection */ if (printer->web_forms) { html_printf(client, ""); } diff --git a/xcode/libcups.xcodeproj/xcshareddata/xcschemes/libcups.xcscheme b/xcode/libcups.xcodeproj/xcshareddata/xcschemes/libcups.xcscheme index 574396417..cef1b92dd 100644 --- a/xcode/libcups.xcodeproj/xcshareddata/xcschemes/libcups.xcscheme +++ b/xcode/libcups.xcodeproj/xcshareddata/xcschemes/libcups.xcscheme @@ -15,7 +15,7 @@ @@ -51,7 +51,7 @@ From 3de01a0f30fd11e2cab17055f13bd21bcaf9e686 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 18 Aug 2022 16:17:00 -0400 Subject: [PATCH 06/19] Initial mDNSResponder implementation. --- cups/dnssd.c | 1164 +++++++++++++++++++++++++++++++++++++++++++++++++- cups/dnssd.h | 47 +- 2 files changed, 1197 insertions(+), 14 deletions(-) diff --git a/cups/dnssd.c b/cups/dnssd.c index b94f0c47c..3ab27f379 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -8,7 +8,7 @@ // #include -#include "cups.h" +#include "cups-private.h" #include "dnssd.h" #include "debug-internal.h" @@ -40,6 +40,25 @@ struct _cups_dns_srv_s // DNS SRV record struct _cups_dnssd_s // DNS-SD context { + cups_mutex_t mutex; // Mutex for context + size_t name_changes; // Number of hostname changes + cups_dnssd_error_cb_t cb; // Error callback function + void *cb_data; // Error callback data + cups_array_t *browses, // Browse requests + *queries, // Query requests + *resolves, // Resolve requests + *services; // Registered services + +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) + DNSServiceRef ref; // Master service reference + cups_thread_t monitor; // Monitoring thread + +#else // HAVE_AVAHI + AvahiClient *client; // Avahi client connection + AvahiThreadedPoll *monitor; // Monitoring thread +#endif // _WIN32 }; struct _cups_dnssd_browse_s // DNS-SD browse request @@ -50,11 +69,12 @@ struct _cups_dnssd_browse_s // DNS-SD browse request #if _WIN32 #elif defined(HAVE_MDNSRESPONDER) + DNSServiceRef ref; // Browse reference #else // HAVE_AVAHI #endif // _WIN32 }; -struct _cups_dns_query_s // DNS-SD query request +struct _cups_dnssd_query_s // DNS-SD query request { cups_dnssd_t *dnssd; // DNS-SD context cups_dnssd_query_cb_t cb; // Query callback @@ -62,11 +82,12 @@ struct _cups_dns_query_s // DNS-SD query request #if _WIN32 #elif defined(HAVE_MDNSRESPONDER) + DNSServiceRef ref; // Query reference #else // HAVE_AVAHI #endif // _WIN32 }; -struct _cups_dns_resolve_s // DNS-SD resolve request +struct _cups_dnssd_resolve_s // DNS-SD resolve request { cups_dnssd_t *dnssd; // DNS-SD context cups_dnssd_resolve_cb_t cb; // Resolve callback @@ -74,20 +95,1155 @@ struct _cups_dns_resolve_s // DNS-SD resolve request #if _WIN32 #elif defined(HAVE_MDNSRESPONDER) + DNSServiceRef ref; // Resolve reference #else // HAVE_AVAHI #endif // _WIN32 }; -struct _cups_dns_service_s // DNS-SD service registration +struct _cups_dnssd_service_s // DNS-SD service registration { cups_dnssd_t *dnssd; // DNS-SD context char *name; // Service name cups_dnssd_service_cb_t cb; // Service callback void *cb_data; // Service callback data + unsigned char loc[16]; // LOC record data + bool loc_set; // Is the location data set? #if _WIN32 #elif defined(HAVE_MDNSRESPONDER) + size_t num_refs; // Number of service references + DNSServiceRef refs[16]; // Service references + DNSRecordRef loc_refs[16]; // Service location records #else // HAVE_AVAHI #endif // _WIN32 }; + +// +// Local functions... +// + +static void delete_browse(cups_dnssd_browse_t *browse); +static void delete_query(cups_dnssd_query_t *query); +static void delete_resolve(cups_dnssd_resolve_t *resolve); +static void delete_service(cups_dnssd_service_t *service); + +#ifdef HAVE_MDNSRESPONDER +static void *mdns_monitor(cups_dnssd_t *dnssd); +static void mdns_browse_cb(DNSServiceRef ref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType error, const char *name, const char *regtype, const char *domain, cups_dnssd_browse_t *browse); +static void mdns_query_cb(DNSServiceRef ref, DNSServiceFlags flags, uint32_t if_index, DNSServiceErrorType error, const char *name, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, cups_dnssd_query_t *query); +static void mdns_resolve_cb(DNSServiceRef ref, DNSServiceFlags flags, uint32_t if_index, DNSServiceErrorType error, const char *fullname, const char *host, uint16_t port, uint16_t txtlen, const unsigned char *txt, cups_dnssd_resolve_t *resolve); +static void mdns_service_cb(DNSServiceRef ref, DNSServiceFlags flags, DNSServiceErrorType error, const char *name, const char *regtype, const char *domain, cups_dnssd_service_t *service); +static const char *mdns_strerror(DNSServiceErrorType errorCode); +static cups_dnssd_flags_t mdns_to_cups(DNSServiceFlags flags, DNSServiceErrorType error); +#endif // HAVE_MDNSRESPONDER +static void report_error(cups_dnssd_t *dnssd, const char *message, ...) _CUPS_FORMAT(2,3); + + +// +// 'cupsDNSSDAssembleFullName()' - Create a full service name from the instance +// name, registration type, and domain. +// + +bool // O - `true` on success, `false` on failure +cupsDNSSDAssembleFullName( + char *fullname, // I - Buffer for full name + size_t fullsize, // I - Size of buffer + const char *name, // I - Service instance name + const char *type, // I - Registration type + const char *domain) // I - Domain +{ + if (!fullname || !fullsize || !name || !type) + return (false); + + return (snprintf(fullname, fullsize, "%s.%s.%s", name, type, domain ? domain : "local") < (int)(fullsize - 1)); +} + + +// +// 'cupsDNSSDDecodeTXT()' - Decode a TXT record into key/value pairs. +// +// This function converts the DNS TXT record encoding of key/value pairs into +// `cups_option_t` elements that can be accessed using the @link cupsGetOption@ +// function and freed using the @link cupsFreeOptions@ function. +// + +size_t // O - Number of key/value pairs +cupsDNSSDDecodeTXT( + const unsigned char *txtrec, // I - TXT record data + uint16_t txtlen, // I - TXT record length + cups_option_t **txt) // O - Key/value pairs +{ + size_t num_txt = 0; // Number of key/value pairs + unsigned char keylen; // Length of key/value + char key[256], // Key/value buffer + *value; // Pointer to value + const unsigned char *txtptr, // Pointer into TXT record data + *txtend; // End of TXT record data + + + // Range check input... + if (txt) + *txt = NULL; + if (!txtrec || !txtlen || !txt) + return (0); + + // Loop through the record... + for (txtptr = txtrec, txtend = txtrec + txtlen; txtptr < txtend; txtptr += keylen) + { + // Format is a length byte followed by "key=value" + keylen = *txtptr++; + if (keylen == 0 || (txtptr + keylen) > txtend) + break; // Bogus length + + // Copy the data to a C string... + memcpy(key, txtptr, keylen); + key[keylen] = '\0'; + + if ((value = strchr(key, '=')) != NULL) + { + // Got value separator, add it... + *value++ = '\0'; + + num_txt = cupsAddOption(key, value, num_txt, txt); + } + else + { + // No value, stop... + break; + } + } + + // Return the number of pairs we parsed... + return (num_txt); + +} + + +// +// 'cupsDNSSDSeparateFullName()' - Separate a full service name into an instance +// name, registration type, and domain. +// + +bool // O - `true` on success, `false` on error +cupsDNSSDSeparateFullName( + const char *fullname, // I - Full service name + char *name, // I - Instance name buffer + size_t namesize, // I - Size of instance name buffer + char *type, // I - Registration type buffer + size_t typesize, // I - Size of registration type buffer + char *domain, // I - Domain name buffer + size_t domainsize) // I - Size of domain name buffer +{ + // TODO: Implement cupsDNSSDSeparateFullName + (void)fullname; + (void)name; + (void)namesize; + (void)type; + (void)typesize; + (void)domain; + (void)domainsize; + + return (false); +} + + +// +// 'cupsDNSSDDelete()' - Delete a DNS-SD context and all its requests. +// + +void +cupsDNSSDDelete(cups_dnssd_t *dnssd) // I - DNS-SD context +{ + if (!dnssd) + return; + + cupsMutexLock(&dnssd->mutex); + + cupsArrayDelete(dnssd->browses); + cupsArrayDelete(dnssd->queries); + cupsArrayDelete(dnssd->resolves); + cupsArrayDelete(dnssd->services); + +#if _WIN32 + cupsThreadCancel(&dnssd->monitor); + DNSServiceRefDeallocate(dnssd->ref); + +#elif defined(HAVE_MDNSRESPONDER) + +#else // HAVE_AVAHI + +#endif // _WIN32 + + cupsMutexUnlock(&dnssd->mutex); + cupsMutexDestroy(&dnssd->mutex); + free(dnssd); +} + + +// +// 'cupsDNSSDNew()' - Create a new DNS-SD context. +// +// This function creates a new DNS-SD context for browsing, querying, resolving, +// and/or registering services. +// + +cups_dnssd_t * // O - DNS-SD context +cupsDNSSDNew( + cups_dnssd_error_cb_t error_cb, // I - Error callback function + void *cb_data) // I - Error callback data +{ + cups_dnssd_t *dnssd; // DNS-SD context + + + // Allocate memory... + if ((dnssd = (cups_dnssd_t *)calloc(1, sizeof(cups_dnssd_t))) == NULL) + return (NULL); + + // Save the error callback... + dnssd->cb = error_cb; + dnssd->cb_data = cb_data; + + // Initialize the mutex... + cupsMutexInit(&dnssd->mutex); + + // Setup the DNS-SD connection and monitor thread... +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) + DNSServiceErrorType error; // Error code + + if ((error = DNSServiceCreateConnection(&dnssd->ref)) == kDNSServiceErr_NoError) + { + if ((dnssd->monitor = cupsThreadCreate((void *(*)(void *))mdns_monitor, dnssd)) == 0) + { + report_error(dnssd, "Unable to create DNS-SD thread: %s", strerror(errno)); + cupsDNSSDDelete(dnssd); + return (NULL); + } + + cupsThreadDetach(dnssd->monitor); + } + else + { + report_error(dnssd, "Unable to initialize DNS-SD: %s", mdns_strerror(error)); + cupsDNSSDDelete(dnssd); + return (NULL); + } + +#else // HAVE_AVAHI + +#endif // _WIN32 + + return (dnssd); +} + + + +// +// 'cupsDNSSDBrowseDelete()' - Cancel and delete a browse request. +// + +void +cupsDNSSDBrowseDelete( + cups_dnssd_browse_t *browse) // I - Browse request +{ + if (browse) + { + cups_dnssd_t *dnssd = browse->dnssd; + + cupsMutexLock(&dnssd->mutex); + cupsArrayRemove(dnssd->browses, browse); + cupsMutexUnlock(&dnssd->mutex); + } +} + + +// +// 'cupsDNSSDBrowseNew()' - . +// + +cups_dnssd_browse_t * // O - Browse request or `NULL` on error +cupsDNSSDBrowseNew( + cups_dnssd_t *dnssd, // I - DNS-SD context + uint32_t if_index, // I - Interface index or `CUPS_DNSSD_IF_ANY` or `CUPS_DNSSD_IF_LOCAL` + const char *types, // I - Service types + const char *domain, // I - Domain name or `NULL` for default + cups_dnssd_browse_cb_t browse_cb, // I - Browse callback function + void *cb_data) // I - Browse callback data +{ + cups_dnssd_browse_t *browse; // Browse request + + + // Range check input... + if (!dnssd || !types || !browse_cb) + return (NULL); + + // Allocate memory for the browser... + if ((browse = (cups_dnssd_browse_t *)calloc(1, sizeof(cups_dnssd_browse_t))) == NULL) + return (NULL); + + browse->dnssd = dnssd; + browse->cb = browse_cb; + browse->cb_data = cb_data; + + cupsMutexLock(&dnssd->mutex); + + if (!dnssd->browses) + { + // Create an array of browsers... + if ((dnssd->browses = cupsArrayNew(NULL, NULL, NULL, 0, NULL, (cups_afree_cb_t)delete_browse)) == NULL) + { + // Unable to create... + free(browse); + browse = NULL; + goto done; + } + } + +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) + DNSServiceErrorType error; // Error, if any + + browse->ref = dnssd->ref; + if ((error = DNSServiceBrowse(&browse->ref, kDNSServiceFlagsShareConnection, if_index, types, domain, (DNSServiceBrowseReply)mdns_browse_cb, browse)) != kDNSServiceErr_NoError) + { + report_error(dnssd, "Unable to create DNS-SD browse request: %s", mdns_strerror(error)); + free(browse); + browse = NULL; + goto done; + } + +#else // HAVE_AVAHI + +#endif // _WIN32 + + cupsArrayAdd(dnssd->browses, browse); + + done: + + cupsMutexUnlock(&dnssd->mutex); + + return (browse); +} + + + +// +// 'cupsDNSSDQueryDelete()' - Cancel and delete a query request. +// + +void +cupsDNSSDQueryDelete( + cups_dnssd_query_t *query) // I - Query request +{ + if (query) + { + cups_dnssd_t *dnssd = query->dnssd; + + cupsMutexLock(&dnssd->mutex); + cupsArrayRemove(dnssd->queries, query); + cupsMutexUnlock(&dnssd->mutex); + } +} + + +// +// 'cupsDNSSDQueryNew()' - Create a new query request. +// +// This function creates a new DNS-SD query request for the specified record +// type. The "fullname" parameter specifies the full DNS name of the service +// (instance name, type, and domain) being queried. +// + +cups_dnssd_query_t * // O - Query request or `NULL` on error +cupsDNSSDQueryNew( + cups_dnssd_t *dnssd, // I - DNS-SD context + uint32_t if_index, // I - Interface index or `CUPS_DNSSD_IF_ANY` or `CUPS_DNSSD_IF_LOCAL` + const char *fullname, // I - Full DNS name including types and domain + uint16_t rrtype, // I - Record type to query (`CUPS_DNSSD_RRTYPE_TXT`, etc.) + cups_dnssd_query_cb_t query_cb, // I - Query callback function + void *cb_data) // I - Query callback data +{ + cups_dnssd_query_t *query; // Query request + + + // Range check input... + if (!dnssd || !fullname || !query_cb) + return (NULL); + + // Allocate memory for the queryr... + if ((query = (cups_dnssd_query_t *)calloc(1, sizeof(cups_dnssd_query_t))) == NULL) + return (NULL); + + query->dnssd = dnssd; + query->cb = query_cb; + query->cb_data = cb_data; + + cupsMutexLock(&dnssd->mutex); + + if (!dnssd->queries) + { + // Create an array of queryrs... + if ((dnssd->queries = cupsArrayNew(NULL, NULL, NULL, 0, NULL, (cups_afree_cb_t)delete_query)) == NULL) + { + // Unable to create... + free(query); + query = NULL; + goto done; + } + } + +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) + DNSServiceErrorType error; // Error, if any + + query->ref = dnssd->ref; + if ((error = DNSServiceQueryRecord(&query->ref, kDNSServiceFlagsShareConnection, if_index, fullname, rrtype, kDNSServiceClass_IN, (DNSServiceQueryRecordReply)mdns_query_cb, query)) != kDNSServiceErr_NoError) + { + report_error(dnssd, "Unable to create DNS-SD query request: %s", mdns_strerror(error)); + free(query); + query = NULL; + goto done; + } + +#else // HAVE_AVAHI + +#endif // _WIN32 + + cupsArrayAdd(dnssd->queries, query); + + done: + + cupsMutexUnlock(&dnssd->mutex); + + return (query); +} + + + +// +// 'cupsDNSSDResolveDelete()' - . +// + +void +cupsDNSSDResolveDelete( + cups_dnssd_resolve_t *res) // I - Resolve request +{ + if (res) + { + cups_dnssd_t *dnssd = res->dnssd; + + cupsMutexLock(&dnssd->mutex); + cupsArrayRemove(dnssd->resolves, res); + cupsMutexUnlock(&dnssd->mutex); + } +} + + +// +// 'cupsDNSSDResolveNew()' - . +// + +cups_dnssd_resolve_t * // O - Resolve request or `NULL` on error +cupsDNSSDResolveNew( + cups_dnssd_t *dnssd, // I - DNS-SD context + uint32_t if_index, // I - Interface index or `CUPS_DNSSD_IF_ANY` or `CUPS_DNSSD_IF_LOCAL` + const char *name, // I - Service name + const char *type, // I - Service type + const char *domain, // I - Domain name or `NULL` for default + cups_dnssd_resolve_cb_t resolve_cb, // I - Resolve callback function + void *cb_data) // I - Resolve callback data +{ + cups_dnssd_resolve_t *resolve; // Resolve request + + + // Range check input... + if (!dnssd || !name || !type || !resolve_cb) + return (NULL); + + // Allocate memory for the queryr... + if ((resolve = (cups_dnssd_resolve_t *)calloc(1, sizeof(cups_dnssd_resolve_t))) == NULL) + return (NULL); + + resolve->dnssd = dnssd; + resolve->cb = resolve_cb; + resolve->cb_data = cb_data; + + cupsMutexLock(&dnssd->mutex); + + if (!dnssd->resolves) + { + // Create an array of queryrs... + if ((dnssd->resolves = cupsArrayNew(NULL, NULL, NULL, 0, NULL, (cups_afree_cb_t)delete_resolve)) == NULL) + { + // Unable to create... + free(resolve); + resolve = NULL; + goto done; + } + } + +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) + DNSServiceErrorType error; // Error, if any + + resolve->ref = dnssd->ref; + if ((error = DNSServiceResolve(&resolve->ref, kDNSServiceFlagsShareConnection, if_index, name, type, domain, (DNSServiceResolveReply)mdns_resolve_cb, resolve)) != kDNSServiceErr_NoError) + { + report_error(dnssd, "Unable to create DNS-SD query request: %s", mdns_strerror(error)); + free(resolve); + resolve = NULL; + goto done; + } + +#else // HAVE_AVAHI + +#endif // _WIN32 + + cupsArrayAdd(dnssd->resolves, resolve); + + done: + + cupsMutexUnlock(&dnssd->mutex); + + return (resolve); +} + + +// +// 'cupsDNSSDServiceAdd()' - . +// + +bool // O - `true` on success, `false` on failure +cupsDNSSDServiceAdd( + cups_dnssd_service_t *service, // I - Service + uint32_t if_index, // I - Interface index or `CUPS_DNSSD_IF_ANY` or `CUPS_DNSSD_IF_LOCAL` + const char *types, // I - Service types + const char *domain, // I - Domain name or `NULL` for default + const char *host, // I - Host name or `NULL` for default + uint16_t port, // I - Port number or `0` for none + size_t num_txt, // I - Number of TXT record values + cups_option_t *txt) // I - TXT record values +{ + bool ret = true; // Return value + size_t i; // Looping var + + + // Range check input... + if (!service || !types) + return (false); + +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) + DNSServiceErrorType error; // Error, if any + TXTRecordRef txtrec, // TXT record + *txtptr = NULL; // Pointer to TXT record, if any + + // Limit number of services with this name... + if (service->num_refs >= (sizeof(service->refs) / sizeof(service->refs[0]))) + { + report_error(service->dnssd, "Unable to create DNS-SD service registration: Too many services with this name."); + ret = false; + goto done; + } + + // Create the TXT record as needed... + if (num_txt) + { + TXTRecordCreate(&txtrec, 1024, NULL); + for (i = 0; i < num_txt; i ++) + TXTRecordSetValue(&txtrec, txt[i].name, (uint8_t)strlen(txt[i].value), txt[i].value); + + txtptr = &txtrec; + } + + service->refs[service->num_refs] = service->dnssd->ref; + if ((error = DNSServiceRegister(service->refs + service->num_refs, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, service->name, types, domain, host, htons(port), txtptr ? TXTRecordGetLength(txtptr) : 0, txtptr ? TXTRecordGetBytesPtr(txtptr) : NULL, (DNSServiceRegisterReply)mdns_service_cb, service)) != kDNSServiceErr_NoError) + { + if (txtptr) + TXTRecordDeallocate(txtptr); + + report_error(service->dnssd, "Unable to create DNS-SD service registration: %s", mdns_strerror(error)); + ret = false; + goto done; + } + + if (txtptr) + TXTRecordDeallocate(txtptr); + + if (service->loc_set) + { + if ((error = DNSServiceAddRecord(service->refs[service->num_refs], service->loc_refs + service->num_refs, 0, kDNSServiceType_LOC, sizeof(service->loc), service->loc, 0)) != kDNSServiceErr_NoError) + { + report_error(service->dnssd, "Unable to add DNS-SD service location data: %s", mdns_strerror(error)); + } + } + + service->num_refs ++; + +#else // HAVE_AVAHI + +#endif // _WIN32 + + done: + + return (ret); +} + + +// +// 'cupsDNSSDServiceDelete()' - . +// + +void +cupsDNSSDServiceDelete( + cups_dnssd_service_t *service) // I - Service +{ + if (service) + { + cups_dnssd_t *dnssd = service->dnssd; + + cupsMutexLock(&dnssd->mutex); + cupsArrayRemove(dnssd->services, service); + cupsMutexUnlock(&dnssd->mutex); + } +} + + +// +// 'cupsDNSSDServiceNew()' - . +// + +cups_dnssd_service_t * // O - Service or `NULL` on error +cupsDNSSDServiceNew( + cups_dnssd_t *dnssd, // I - DNS-SD context + const char *name, // I - Name of service + cups_dnssd_service_cb_t cb, // I - Service registration callback function + void *cb_data) // I - Service registration callback data +{ + cups_dnssd_service_t *service; // Service registration + + + // Range check input... + if (!dnssd || !name || !cb) + return (NULL); + + // Allocate memory for the queryr... + if ((service = (cups_dnssd_service_t *)calloc(1, sizeof(cups_dnssd_service_t))) == NULL) + return (NULL); + + service->dnssd = dnssd; + service->cb = cb; + service->cb_data = cb_data; + service->name = strdup(name); + + cupsMutexLock(&dnssd->mutex); + + if (!dnssd->services) + { + // Create an array of queryrs... + if ((dnssd->services = cupsArrayNew(NULL, NULL, NULL, 0, NULL, (cups_afree_cb_t)delete_service)) == NULL) + { + // Unable to create... + free(service); + service = NULL; + goto done; + } + } + + cupsArrayAdd(dnssd->services, service); + + done: + + cupsMutexUnlock(&dnssd->mutex); + + return (service); +} + + +// +// 'cupsDNSSDServicePublish()' - . +// + +bool // O - `true` on success, `false` on failure +cupsDNSSDServicePublish( + cups_dnssd_service_t *service) // I - Service +{ + bool ret = true; // Return value + + + (void)service; + + return (ret); +} + + +// +// 'cupsDNSSDServiceSetLocation()' - Set the geolocation (LOC record) of a +// service. +// +// This function sets the geolocation of a service using a 'geo:' URI (RFC 5870) +// of the form +// 'geo:LATITUDE,LONGITUDE[,ALTITUDE][;crs=CRSLABEL][;u=UNCERTAINTY]'. The +// specified coordinates and uncertainty are converted into a DNS LOC record +// for the service name label. +// +// Only the "wgs84" CRSLABEL string is supported. +// + +bool // O - `true` on success, `false` on failure +cupsDNSSDServiceSetLocation( + cups_dnssd_service_t *service, // I - Service + const char *geo_uri) // I - Geolocation as a 'geo:' URI +{ + const char *geo_ptr; // Pointer into 'geo;' URI + double lat = 0.0, lon = 0.0; // Latitude and longitude in degrees + double alt = 0.0; // Altitude in meters + double u = 5.0; // Uncertainty in meters + unsigned int lat_ksec, lon_ksec; // Latitude and longitude in thousandths of arc seconds, biased by 2^31 + unsigned int alt_cm; // Altitude in centimeters, biased by 10,000,000cm + unsigned char prec; // Precision value + + + // See if this is a WGS-84 coordinate... + if ((geo_ptr = strstr(geo_uri, ";crs=")) != NULL && strncmp(geo_ptr + 5, "wgs84", 5)) + { + // Not WGS-84... + _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Only WGS-84 coordinates are supported."), true); + return (false); + } + + // Pull apart the "geo:" URI and convert to the integer representation for + // the LOC record... + sscanf(geo_uri, "geo:%lf,%lf,%lf", &lat, &lon, &alt); + lat_ksec = (unsigned)((int)(lat * 3600000.0) + 0x40000000 + 0x40000000); + lon_ksec = (unsigned)((int)(lon * 3600000.0) + 0x40000000 + 0x40000000); + alt_cm = (unsigned)((int)(alt * 100.0) + 10000000); + + if ((geo_ptr = strstr(geo_uri, ";u=")) != NULL) + u = strtod(geo_ptr + 3, NULL); + + if (u < 0.0) + u = 0.0; + + for (prec = 0, u = u * 100.0; u >= 10.0 && prec < 15; u = u * 0.01) + prec ++; + + if (u < 10.0) + prec |= (unsigned char)((int)u << 4); + else + prec |= (unsigned char)0x90; + + // Build the LOC record... + service->loc[0] = 0x00; // Version + service->loc[1] = 0x51; // Size (50cm) + service->loc[2] = prec; // Horizontal precision + service->loc[3] = prec; // Vertical precision + + service->loc[4] = (unsigned char)(lat_ksec >> 24); + // Latitude (32-bit big-endian) + service->loc[5] = (unsigned char)(lat_ksec >> 16); + service->loc[6] = (unsigned char)(lat_ksec >> 8); + service->loc[7] = (unsigned char)(lat_ksec); + + service->loc[8] = (unsigned char)(lon_ksec >> 24); + // Latitude (32-bit big-endian) + service->loc[9] = (unsigned char)(lon_ksec >> 16); + service->loc[10] = (unsigned char)(lon_ksec >> 8); + service->loc[11] = (unsigned char)(lon_ksec); + + service->loc[12] = (unsigned char)(alt_cm >> 24); + // Altitude (32-bit big-endian) + service->loc[13] = (unsigned char)(alt_cm >> 16); + service->loc[14] = (unsigned char)(alt_cm >> 8); + service->loc[15] = (unsigned char)(alt_cm); + + service->loc_set = true; + + return (true); +} + + +// +// 'delete_browse()' - Delete a browse request. +// + +static void +delete_browse( + cups_dnssd_browse_t *browse) // I - Browse request +{ +#if _WIN32 +#elif defined(HAVE_MDNSRESPONDER) + DNSServiceRefDeallocate(browse->ref); + +#else // HAVE_AVAHI +#endif // _WIN32 + + free(browse); +} + + +// +// 'delete_query()' - Delete a query request. +// + +static void +delete_query( + cups_dnssd_query_t *query) // I - Query request +{ +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) + DNSServiceRefDeallocate(query->ref); + +#else // HAVE_AVAHI + +#endif // _WIN32 + +} + + +// +// 'delete_resolve()' - Delete a resolve request. +// + +static void +delete_resolve( + cups_dnssd_resolve_t *resolve) // I - Resolve request +{ +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) + DNSServiceRefDeallocate(resolve->ref); + +#else // HAVE_AVAHI + +#endif // _WIN32 + +} + + +// +// 'delete_service()' - Delete a service registration. +// + +static void +delete_service( + cups_dnssd_service_t *service) // I - Service +{ + free(service->name); + +#if _WIN32 +#elif defined(HAVE_MDNSRESPONDER) + size_t i; // Looping var + + for (i = 0; i < service->num_refs; i ++) + DNSServiceRefDeallocate(service->refs[i]); +#else // HAVE_AVAHI +#endif // _WIN32 + + free(service); +} + + +#ifdef HAVE_MDNSRESPONDER +// +// 'mdns_browse_cb()' - Handle DNS-SD browse callbacks from mDNSResponder. +// + +static void +mdns_browse_cb( + DNSServiceRef ref, // I - Service reference + DNSServiceFlags flags, // I - Browse flags + uint32_t if_index, // I - Interface index + DNSServiceErrorType error, // I - Error code, if any + const char *name, // I - Service name + const char *regtype, // I - Registration type + const char *domain, // I - Domain + cups_dnssd_browse_t *browse) // I - Browse request +{ + (void)ref; + + if (error != kDNSServiceErr_NoError) + report_error(browse->dnssd, "DNS-SD browse error: %s", mdns_strerror(error)); + + (browse->cb)(browse, browse->cb_data, mdns_to_cups(flags, error), if_index, name, regtype, domain); +} + + +// +// 'mdns_monitor()' - Monitor DNS-SD messages from mDNSResponder. +// + +static void * // O - Return value (always `NULL`) +mdns_monitor(cups_dnssd_t *dnssd) // I - DNS-SD context +{ + DNSServiceErrorType error; // Current error + + for (;;) + { + if ((error = DNSServiceProcessResult(dnssd->ref)) != kDNSServiceErr_NoError) + { + report_error(dnssd, "Unable to read response from DNS-SD service: %s", mdns_strerror(error)); + break; + } + } + + return (NULL); +} + + +// +// 'mdns_query_cb()' - Handle DNS-SD query callbacks from mDNSResponder. +// + +static void +mdns_query_cb( + DNSServiceRef ref, // I - Service reference + DNSServiceFlags flags, // I - Query flags + uint32_t if_index, // I - Interface index + DNSServiceErrorType error, // I - Error code, if any + const char *name, // I - Service name + uint16_t rrtype, // I - Record type + uint16_t rrclass, // I - Record class + uint16_t rdlen, // I - Response length + const void *rdata, // I - Response data + uint32_t ttl, // I - Time-to-live value + cups_dnssd_query_t *query) // I - Query request +{ + (void)ref; + (void)rrclass; + (void)ttl; + + if (error != kDNSServiceErr_NoError) + report_error(query->dnssd, "DNS-SD query error: %s", mdns_strerror(error)); + + (query->cb)(query, query->cb_data, mdns_to_cups(flags, error), if_index, name, rrtype, rdata, rdlen); +} + + +// +// 'mdns_resolve_cb()' - Handle DNS-SD resolution callbacks from mDNSResponder. +// + +static void +mdns_resolve_cb( + DNSServiceRef ref, // I - Service reference + DNSServiceFlags flags, // I - Registration flags + uint32_t if_index, // I - Interface index + DNSServiceErrorType error, // I - Error code, if any + const char *fullname, // I - Full name of service + const char *host, // I - Hostname of service + uint16_t port, // I - Port number in network byte order + uint16_t txtlen, // I - Length of TXT record + const unsigned char *txtrec, // I - TXT record + cups_dnssd_resolve_t *resolve) // I - Resolve request +{ + size_t num_txt; // Number of TXT key/value pairs + cups_option_t *txt; // TXT key/value pairs + + + (void)ref; + + if (error != kDNSServiceErr_NoError) + report_error(resolve->dnssd, "DNS-SD resolve error: %s", mdns_strerror(error)); + + num_txt = cupsDNSSDDecodeTXT(txtrec, txtlen, &txt); + + (resolve->cb)(resolve, resolve->cb_data, mdns_to_cups(flags, error), if_index, fullname, host, ntohs(port), num_txt, txt); + + cupsFreeOptions(num_txt, txt); +} + + +// +// 'mdns_service_cb()' - Handle DNS-SD service registration callbacks from +// mDNSResponder. +// + +static void +mdns_service_cb( + DNSServiceRef ref, // I - Service reference + DNSServiceFlags flags, // I - Registration flags + DNSServiceErrorType error, // I - Error code, if any + const char *name, // I - Service name + const char *regtype, // I - Registration type + const char *domain, // I - Domain + cups_dnssd_service_t *service) // I - Service registration +{ + (void)ref; + + if (error != kDNSServiceErr_NoError) + report_error(service->dnssd, "DNS-SD service registration error: %s", mdns_strerror(error)); + + (service->cb)(service, service->cb_data, mdns_to_cups(flags, error), name, regtype, domain); +} + + +// +// 'mdns_strerror()' - Convert an error code to a string. +// + +static const char * // O - Error message +mdns_strerror( + DNSServiceErrorType errorCode) // I - Error code +{ + switch (errorCode) + { + case kDNSServiceErr_NoError : + return ("No error"); + + case kDNSServiceErr_Unknown : + default : + return ("Unknown error"); + + case kDNSServiceErr_NoSuchName : + return ("Name not found"); + + case kDNSServiceErr_NoMemory : + return ("Out of memory"); + + case kDNSServiceErr_BadParam : + return ("Bad parameter"); + + case kDNSServiceErr_BadReference : + return ("Bad service reference"); + + case kDNSServiceErr_BadState : + return ("Bad state"); + + case kDNSServiceErr_BadFlags : + return ("Bad flags argument"); + + case kDNSServiceErr_Unsupported : + return ("Unsupported feature"); + + case kDNSServiceErr_NotInitialized : + return ("Not initialized"); + + case kDNSServiceErr_AlreadyRegistered : + return ("Name already registered"); + + case kDNSServiceErr_NameConflict : + return ("Name conflicts"); + + case kDNSServiceErr_Invalid : + return ("Invalid argument"); + + case kDNSServiceErr_Firewall : + return ("Firewall prevents access"); + + case kDNSServiceErr_Incompatible : + return ("Client library incompatible with background daemon"); + + case kDNSServiceErr_BadInterfaceIndex : + return ("Bad interface index"); + + case kDNSServiceErr_Refused : + return ("Connection refused"); + + case kDNSServiceErr_NoSuchRecord : + return ("DNS record not found"); + + case kDNSServiceErr_NoAuth : + return ("No authoritative answer"); + + case kDNSServiceErr_NoSuchKey : + return ("TXT record key not found"); + + case kDNSServiceErr_NATTraversal : + return ("Unable to traverse via NAT"); + + case kDNSServiceErr_DoubleNAT : + return ("Double NAT is in use"); + + case kDNSServiceErr_BadTime : + return ("Bad time value"); + + case kDNSServiceErr_BadSig : + return ("Bad signal"); + + case kDNSServiceErr_BadKey : + return ("Bad TXT record key"); + + case kDNSServiceErr_Transient : + return ("Transient error"); + + case kDNSServiceErr_ServiceNotRunning : + return ("Background daemon not running"); + + case kDNSServiceErr_NATPortMappingUnsupported : + return ("NAT doesn't support PCP, NAT-PMP or UPnP"); + + case kDNSServiceErr_NATPortMappingDisabled : + return ("NAT supports PCP, NAT-PMP or UPnP, but it's disabled by the administrator"); + + case kDNSServiceErr_NoRouter : + return ("No router configured, probably no network connectivity"); + + case kDNSServiceErr_PollingMode : + return ("Polling error"); + + case kDNSServiceErr_Timeout : + return ("Timeout"); + + case kDNSServiceErr_DefunctConnection : + return ("Connection lost"); + } +} + + +// +// 'mdns_to_cups()' - Convert mDNSResponder flags to CUPS DNS-SD flags... +// + +static cups_dnssd_flags_t // O - CUPS DNS-SD flags +mdns_to_cups( + DNSServiceFlags flags, // I - mDNSResponder flags + DNSServiceErrorType error) // I - mDNSResponder error code +{ + cups_dnssd_flags_t cups_flags = CUPS_DNSSD_FLAGS_NONE; + // CUPS DNS-SD flags + + + if (flags & kDNSServiceFlagsAdd) + cups_flags |= CUPS_DNSSD_FLAGS_ADD; + if (flags & kDNSServiceFlagsMoreComing) + cups_flags |= CUPS_DNSSD_FLAGS_MORE; + if (error != kDNSServiceErr_NoError) + cups_flags |= CUPS_DNSSD_FLAGS_ERROR; + + return (cups_flags); +} +#endif // HAVE_MDNSRESPONDER + + +// +// 'report_error()' - Report an error. +// + +static void +report_error(cups_dnssd_t *dnssd, // I - DNS-SD context + const char *message, // I - printf-style message string + ...) // I - Additional arguments as needed +{ + va_list ap; // Pointer to arguments + char buffer[8192]; // Formatted message + + + // Format the message... + va_start(ap, message); + vsnprintf(buffer, sizeof(buffer), message, ap); + va_end(ap); + + // Send it... + if (dnssd->cb) + (dnssd->cb)(dnssd->cb_data, buffer); + else + fprintf(stderr, "%s\n", buffer); +} diff --git a/cups/dnssd.h b/cups/dnssd.h index a5598ef05..c8b00ecf7 100644 --- a/cups/dnssd.h +++ b/cups/dnssd.h @@ -28,11 +28,34 @@ enum cups_dnssd_flags_e // DNS-SD callback flag values { CUPS_DNSSD_FLAGS_NONE = 0, // No flags CUPS_DNSSD_FLAGS_ADD = 1, // Added - CUPS_DNSSD_FLAGS_REMOVE = 2, // Removed - CUPS_DNSSD_FLAGS_ERROR = 4 // Error occurred + CUPS_DNSSD_FLAGS_ERROR = 2, // Error occurred + CUPS_DNSSD_FLAGS_MORE = 4 // More coming }; typedef unsigned cups_dnssd_flags_t; // DNS-SD callback flag bitmask +typedef enum cups_dnssd_rrtype_e // DNS record type values +{ + CUPS_DNSSD_RRTYPE_A = 1, // Host address + CUPS_DNSSD_RRTYPE_NS, // Name server + CUPS_DNSSD_RRTYPE_CNAME = 5, // Canonical name + CUPS_DNSSD_RRTYPE_WKS = 11, // Well known service + CUPS_DNSSD_RRTYPE_PTR, // Domain name pointer + CUPS_DNSSD_RRTYPE_TXT = 16, // One or more text strings + CUPS_DNSSD_RRTYPE_RT = 21, // Router + CUPS_DNSSD_RRTYPE_SIG = 24, // Security signature + CUPS_DNSSD_RRTYPE_KEY, // Security key + CUPS_DNSSD_RRTYPE_AAAA = 28, // IPv6 Address. + CUPS_DNSSD_RRTYPE_LOC, // Location Information. + CUPS_DNSSD_RRTYPE_KX = 36, // Key Exchange + CUPS_DNSSD_RRTYPE_CERT, // Certification record + CUPS_DNSSD_RRTYPE_RRSIG = 46, // RRSIG + CUPS_DNSSD_RRTYPE_DNSKEY = 48, // DNSKEY + CUPS_DNSSD_RRTYPE_DHCID, // DHCP Client Identifier + CUPS_DNSSD_RRTYPE_HTTPS = 65, // HTTPS Service Binding + CUPS_DNSSD_RRTYPE_SPF = 99, // Sender Policy Framework for E-Mail + CUPS_DNSSD_RRTYPE_ANY = 255 // Wildcard match +} cups_dnssd_rrtype_t; + typedef struct _cups_dnssd_browse_s cups_dnssd_browse_t; // DNS browse request typedef void (*cups_dnssd_browse_cb_t)(cups_dnssd_browse_t *browse, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain); @@ -43,12 +66,12 @@ typedef void (*cups_dnssd_error_cb_t)(void *cb_data, const char *message); typedef struct _cups_dnssd_query_s cups_dnssd_query_t; // DNS query request -typedef void (*cups_dnssd_query_cb_t)(cups_dnssd_query_t * query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain, size_t num_txt, cups_option_t *txt); +typedef void (*cups_dnssd_query_cb_t)(cups_dnssd_query_t * query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen); // DNS-SD query callback typedef struct _cups_dnssd_resolve_s cups_dnssd_resolve_t; // DNS resolve request -typedef void (*cups_dnssd_resolve_cb_t)(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt); +typedef void (*cups_dnssd_resolve_cb_t)(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt); // DNS-SD resolve callback typedef struct _cups_dnssd_service_s cups_dnssd_service_t; @@ -61,24 +84,28 @@ typedef void (*cups_dnssd_service_cb_t)(cups_dnssd_service_t *service, void *cb_ // Functions... // -extern void cupsDNSSDDelete(cups_dnssd_t *dns) _CUPS_PUBLIC; +extern void cupsDNSSDDelete(cups_dnssd_t *dnssd) _CUPS_PUBLIC; extern cups_dnssd_t *cupsDNSSDNew(cups_dnssd_error_cb_t error_cb, void *cb_data) _CUPS_PUBLIC; extern void cupsDNSSDBrowseDelete(cups_dnssd_browse_t *browser) _CUPS_PUBLIC; -extern cups_dnssd_browse_t *cupsDNSSDBrowseNew(cups_dnssd_t *dns, uint32_t if_index, const char *types, const char *domains, cups_dnssd_browse_cb_t browse_cb, void *cb_data) _CUPS_PUBLIC; +extern cups_dnssd_browse_t *cupsDNSSDBrowseNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *types, const char *domain, cups_dnssd_browse_cb_t browse_cb, void *cb_data) _CUPS_PUBLIC; extern void cupsDNSSDQueryDelete(cups_dnssd_query_t *query) _CUPS_PUBLIC; -extern cups_dnssd_query_t *cupsDNSSDQueryNew(cups_dnssd_t *dns, uint32_t if_index, const char *types, const char *domains, cups_dnssd_query_cb_t query_cb, void *cb_data) _CUPS_PUBLIC; +extern cups_dnssd_query_t *cupsDNSSDQueryNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *fullname, uint16_t rrtype, cups_dnssd_query_cb_t query_cb, void *cb_data) _CUPS_PUBLIC; extern void cupsDNSSDResolveDelete(cups_dnssd_resolve_t *res) _CUPS_PUBLIC; -extern cups_dnssd_resolve_t *cupsDNSSDResolveNew(cups_dnssd_t *dns, uint32_t if_index, const char *types, const char *domains, cups_dnssd_resolve_cb_t resolve_cb, void *cb_data) _CUPS_PUBLIC; +extern cups_dnssd_resolve_t *cupsDNSSDResolveNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *name, const char *type, const char *domain, cups_dnssd_resolve_cb_t resolve_cb, void *cb_data) _CUPS_PUBLIC; -extern bool cupsDNSSDServiceAdd(cups_dnssd_service_t *service, uint32_t if_index, const char *types, const char *domains, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt) _CUPS_PUBLIC; +extern bool cupsDNSSDServiceAdd(cups_dnssd_service_t *service, uint32_t if_index, const char *types, const char *domain, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt) _CUPS_PUBLIC; extern void cupsDNSSDServiceDelete(cups_dnssd_service_t *service) _CUPS_PUBLIC; -extern cups_dnssd_service_t *cupsDNSSDServiceNew(cups_dnssd_t *dns, const char *name, cups_dnssd_service_cb_t cb, void *cb_data) _CUPS_PUBLIC; +extern cups_dnssd_service_t *cupsDNSSDServiceNew(cups_dnssd_t *dnssd, const char *name, cups_dnssd_service_cb_t cb, void *cb_data) _CUPS_PUBLIC; extern bool cupsDNSSDServicePublish(cups_dnssd_service_t *service) _CUPS_PUBLIC; extern bool cupsDNSSDServiceSetLocation(cups_dnssd_service_t *service, const char *geo_uri) _CUPS_PUBLIC; +extern bool cupsDNSSDAssembleFullName(char *fullname, size_t fullsize, const char *name, const char *type, const char *domain); +extern size_t cupsDNSSDDecodeTXT(const unsigned char *txtrec, uint16_t txtlen, cups_option_t **txt) _CUPS_PUBLIC; +extern bool cupsDNSSDSeparateFullName(const char *fullname, char *name, size_t namesize, char *type, size_t typesize, char *domain, size_t domainsize); + # ifdef __cplusplus } From cc606942e581942a1b992b5c02e9825bf852da45 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Fri, 19 Aug 2022 19:07:51 -0400 Subject: [PATCH 07/19] Initial unit test program. --- .gitignore | 1 + cups/Makefile | 14 ++ cups/dnssd.h | 2 +- cups/testdnssd.c | 257 ++++++++++++++++++++++++ xcode/libcups.xcodeproj/project.pbxproj | 116 +++++++++++ 5 files changed, 389 insertions(+), 1 deletion(-) create mode 100644 cups/testdnssd.c diff --git a/.gitignore b/.gitignore index 9be4f87fd..6dc8ad04d 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ /cups/testcreds /cups/testcups /cups/testdest +/cups/testdnssd /cups/testfile /cups/testgetdests /cups/testhttp diff --git a/cups/Makefile b/cups/Makefile index 5767b5078..55ade0392 100644 --- a/cups/Makefile +++ b/cups/Makefile @@ -23,6 +23,7 @@ LIBOBJS = \ dest-localization.o \ dest-options.o \ dir.o \ + dnssd.o \ encode.o \ file.o \ getputfile.o \ @@ -59,6 +60,7 @@ TESTOBJS = \ testclient.o \ testcreds.o \ testdest.o \ + testdnssd.o \ testfile.o \ testgetdests.o \ testhttp.o \ @@ -87,6 +89,7 @@ HEADERS = \ base.h \ cups.h \ dir.h \ + dnssd.h \ file.h \ http.h \ ipp.h \ @@ -112,6 +115,7 @@ UNITTARGETS = \ testclient \ testcreds \ testdest \ + testdnssd \ testfile \ testgetdests \ testhttp \ @@ -356,6 +360,16 @@ testdest: testdest.o $(LIBCUPS_STATIC) $(CODE_SIGN) $(CSFLAGS) $@ +# +# testdnssd (dependency on static CUPS library is intentional) +# + +testdnssd: testdnssd.o $(LIBCUPS_STATIC) + echo Linking $@... + $(CC) $(LDFLAGS) $(OPTIM) -o $@ testdnssd.o $(LIBCUPS_STATIC) $(LIBS) + $(CODE_SIGN) $(CSFLAGS) $@ + + # # testfile (dependency on static CUPS library is intentional) # diff --git a/cups/dnssd.h b/cups/dnssd.h index c8b00ecf7..c184f1bb4 100644 --- a/cups/dnssd.h +++ b/cups/dnssd.h @@ -66,7 +66,7 @@ typedef void (*cups_dnssd_error_cb_t)(void *cb_data, const char *message); typedef struct _cups_dnssd_query_s cups_dnssd_query_t; // DNS query request -typedef void (*cups_dnssd_query_cb_t)(cups_dnssd_query_t * query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen); +typedef void (*cups_dnssd_query_cb_t)(cups_dnssd_query_t *query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen); // DNS-SD query callback typedef struct _cups_dnssd_resolve_s cups_dnssd_resolve_t; diff --git a/cups/testdnssd.c b/cups/testdnssd.c new file mode 100644 index 000000000..6457dc033 --- /dev/null +++ b/cups/testdnssd.c @@ -0,0 +1,257 @@ +// +// DNS-SD API test program for CUPS. +// +// Copyright © 2022 by OpenPrinting. +// +// Licensed under Apache License v2.0. See the file "LICENSE" for more +// information. +// + +#include "test-internal.h" +#include "dnssd.h" +#include "thread.h" + + +// +// Local structures... +// + +typedef struct testdata_s // Test data structure +{ + cups_mutex_t mutex; // Mutex for access + size_t browse_count; // Number of browse callbacks + size_t error_count; // Number of error callbacks + size_t query_count; // Number of query callbacks + size_t resolve_count; // Number of resolve callbacks + size_t service_count; // Number of service callbacks +} testdata_t; + + +// +// Local functions... +// + +static void browse_cb(cups_dnssd_browse_t *browse, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain); +static void error_cb(void *cb_data, const char *message); +//static void query_cb(cups_dnssd_query_t *query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen); +//static void resolve_cb(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt); +static void service_cb(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags, const char *name, const char *regtype, const char *domain); +static void usage(const char *arg); + + +// +// 'main()' - Main entry. +// + +int // O - Exit status +main(int argc, // I - Number of command-line arguments + char *argv[]) // I - Command-line arguments +{ + int i; // Looping var + cups_dnssd_t *dnssd; // DNS-SD context + cups_dnssd_browse_t *browse; // DNS-SD browse request +// cups_dnssd_query_t *query; // DNS-SD query request +// cups_dnssd_resolve_t *resolve; // DNS-SD resolve request + cups_dnssd_service_t *service; // DNS-SD service registration + size_t num_txt; // Number of TXT record key/value pairs + cups_option_t *txt; // TXT record key/value pairs + testdata_t testdata; // Test data + + + // Clear test data... + memset(&testdata, 0, sizeof(testdata)); + + if (argc == 1) + { + // Do unit tests... + testBegin("cupsDNSSDNew"); + if ((dnssd = cupsDNSSDNew(error_cb, &testdata)) != NULL) + testEnd(true); + else + return (1); + + testBegin("cupsDNSSDBrowseNew(_ipp._tcp)"); + if ((browse = cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp", NULL, browse_cb, &testdata)) != NULL) + testEnd(true); + else + return (1); + + testBegin("cupsDNSSDServiceNew(Test Printer)"); + if ((service = cupsDNSSDServiceNew(dnssd, "Test Printer", service_cb, &testdata)) != NULL) + testEnd(true); + else + return (1); + + num_txt = cupsAddOption("rp", "ipp/print", 0, &txt); + + testBegin("cupsDNSSDServiceAdd(_http._tcp)"); + if (cupsDNSSDServiceAdd(service, CUPS_DNSSD_IF_INDEX_ANY, "_http._tcp,_printer", NULL, NULL, 631, 0, NULL)) + testEnd(true); + else + return (1); + + testBegin("cupsDNSSDServiceAdd(_ipp._tcp)"); + if (cupsDNSSDServiceAdd(service, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp,_print", NULL, NULL, 631, num_txt, txt)) + testEnd(true); + else + return (1); + + cupsFreeOptions(num_txt, txt); + + testBegin("Wait for callbacks"); + + for (i = 0; i < 30; i ++) + { + if (testdata.service_count != 0 && testdata.browse_count != 0) + break; + + sleep(1); + } + + testEnd(i < 30); + + cupsDNSSDDelete(dnssd); + } + else + { + usage(argv[1]); + } + + return (0); +} + + +// +// 'browse_cb()' - Browse callback. +// + +static void +browse_cb( + cups_dnssd_browse_t *browse, // I - Browse request + void *cb_data, // I - Callback data + cups_dnssd_flags_t flags, // I - Bit flags + uint32_t if_index, // I - Interface index + const char *name, // I - Service name + const char *regtype, // I - Registration type + const char *domain) // I - Domain +{ + testdata_t *data = (testdata_t *)cb_data; + // Test data + + + fprintf(stderr, "Browse flags=%02X if_index=%u name=\"%s\" regtype=\"%s\" domain=\"%s\"\n", flags, if_index, name, regtype, domain); + + cupsMutexLock(&data->mutex); + data->browse_count ++; + cupsMutexUnlock(&data->mutex); +} + + +// +// 'error_cb()' - Display an error. +// + +static void +error_cb(void *cb_data, // I - Callback data + const char *message) // I - Error message +{ + testdata_t *data = (testdata_t *)cb_data; + // Test data + + + testEndMessage(false, "%s", message); + + cupsMutexLock(&data->mutex); + data->error_count ++; + cupsMutexUnlock(&data->mutex); +} + + +#if 0 +// +// 'query_cb()' - Query callback. +// + +static void +query_cb( + cups_dnssd_query_t *query, + void *cb_data, + cups_dnssd_flags_t flags, + uint32_t if_index, + const char *fullname, + uint16_t rrtype, + const void *qdata, + uint16_t qlen) +{ + testdata_t *data = (testdata_t *)cb_data; + // Test data + + + fprintf(stderr, "Query: flags=%02X if_index=%u fullname=\"%s\" rrtype=%u qdata=%p qlen=%u\n", flags, if_index, fullname, rrtype, qdata, qlen); + + cupsMutexLock(&data->mutex); + data->query_count ++; + cupsMutexUnlock(&data->mutex); +} + + +static void +resolve_cb( + cups_dnssd_resolve_t *res, + void *cb_data, + cups_dnssd_flags_t flags, + uint32_t if_index, + const char *fullname, + const char *host, + uint16_t port, + size_t num_txt, + cups_option_t *txt) +{ + testdata_t *data = (testdata_t *)cb_data; + // Test data + + + fprintf(stderr, "Resolve: flags=%02X if_index=%u fullname=\"%s\" host=\"%s\" port=%u num_txt=%u, txt=%p\n", flags, if_index, fullname, host, port, (unsigned)num_txt, txt); + + cupsMutexLock(&data->mutex); + data->resolve_count ++; + cupsMutexUnlock(&data->mutex); +} +#endif // 0 + + +static void +service_cb( + cups_dnssd_service_t *service, + void *cb_data, + cups_dnssd_flags_t flags, + const char *name, + const char *regtype, + const char *domain) +{ + testdata_t *data = (testdata_t *)cb_data; + // Test data + + + fprintf(stderr, "Service: flags=%02X name=\"%s\" regtype=\"%s\" domain=\"%s\"\n", flags, name, regtype, domain); + + cupsMutexLock(&data->mutex); + data->service_count ++; + cupsMutexUnlock(&data->mutex); +} + + +// +// 'usage()' - Show program usage. +// + +static void +usage(const char *arg) // I - Argument for usage message +{ + if (arg) + printf("testdnssd: Unknown option \"%s\".\n", arg); + + puts("Usage:"); + + exit(arg != NULL); +} diff --git a/xcode/libcups.xcodeproj/project.pbxproj b/xcode/libcups.xcodeproj/project.pbxproj index 24042f61f..d3d5c26a0 100644 --- a/xcode/libcups.xcodeproj/project.pbxproj +++ b/xcode/libcups.xcodeproj/project.pbxproj @@ -19,6 +19,7 @@ 729181C32011560E005E7560 /* PBXTargetDependency */, 270D02281D707E5100EA9403 /* PBXTargetDependency */, 2767FC5619267469000F61D3 /* PBXTargetDependency */, + 2794E90D28AFFC3F00BEDC04 /* PBXTargetDependency */, 271284AB1CC11FA500E517C7 /* PBXTargetDependency */, 278C58D6136B641D00836530 /* PBXTargetDependency */, 271284AF1CC11FA500E517C7 /* PBXTargetDependency */, @@ -198,6 +199,15 @@ 278CA9052884D9B100367E41 /* rand.c in Sources */ = {isa = PBXBuildFile; fileRef = 278CA9042884D9B100367E41 /* rand.c */; }; 278CA9062884D9B100367E41 /* rand.c in Sources */ = {isa = PBXBuildFile; fileRef = 278CA9042884D9B100367E41 /* rand.c */; }; 278CA9072884D9B100367E41 /* rand.c in Sources */ = {isa = PBXBuildFile; fileRef = 278CA9042884D9B100367E41 /* rand.c */; }; + 2794E8FF28AFFC2400BEDC04 /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27CAFC60282C895700FE02FC /* libcrypto.a */; }; + 2794E90028AFFC2400BEDC04 /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 27CAFC5F282C895700FE02FC /* libssl.a */; }; + 2794E90128AFFC2400BEDC04 /* libcups_static.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 72A4332F155844CF002E172D /* libcups_static.a */; }; + 2794E90228AFFC2400BEDC04 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC591926750C000F61D3 /* CoreFoundation.framework */; }; + 2794E90328AFFC2400BEDC04 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC5A1926750C000F61D3 /* libiconv.dylib */; }; + 2794E90428AFFC2400BEDC04 /* libresolv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC5B1926750C000F61D3 /* libresolv.dylib */; }; + 2794E90528AFFC2400BEDC04 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC5C1926750C000F61D3 /* libz.dylib */; }; + 2794E90628AFFC2400BEDC04 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC5D1926750C000F61D3 /* Security.framework */; }; + 2794E90F28AFFC6600BEDC04 /* testdnssd.c in Sources */ = {isa = PBXBuildFile; fileRef = 2794E90E28AFFC6600BEDC04 /* testdnssd.c */; }; 279AE6F52395B80F004DD600 /* libpam.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 279AE6F42395B80F004DD600 /* libpam.tbd */; }; 27A8096128A9B9D500B20BC8 /* dnssd.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A8095F28A9B9D500B20BC8 /* dnssd.h */; }; 27A8096228A9B9D500B20BC8 /* dnssd.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A8095F28A9B9D500B20BC8 /* dnssd.h */; }; @@ -603,6 +613,20 @@ remoteGlobalIDString = 274FF6891333B1C400317ECB; remoteInfo = libcups_static; }; + 2794E8FB28AFFC2400BEDC04 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 72BF96371333042100B1EAD7 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 274FF6891333B1C400317ECB; + remoteInfo = libcups_static; + }; + 2794E90C28AFFC3F00BEDC04 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 72BF96371333042100B1EAD7 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 2794E8F928AFFC2400BEDC04; + remoteInfo = testdnssd; + }; 27D3966A27BA81D3003D3D8E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 72BF96371333042100B1EAD7 /* Project object */; @@ -808,6 +832,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 2794E90728AFFC2400BEDC04 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 27D3967127BA81D3003D3D8E /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -963,6 +996,8 @@ 278C58E7136B64B000836530 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = /System/Library/Frameworks/Security.framework; sourceTree = ""; }; 278C58E8136B64B000836530 /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = /System/Library/Frameworks/SystemConfiguration.framework; sourceTree = ""; }; 278CA9042884D9B100367E41 /* rand.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rand.c; path = ../cups/rand.c; sourceTree = ""; }; + 2794E90B28AFFC2400BEDC04 /* testdnssd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = testdnssd; sourceTree = BUILT_PRODUCTS_DIR; }; + 2794E90E28AFFC6600BEDC04 /* testdnssd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = testdnssd.c; path = ../cups/testdnssd.c; sourceTree = ""; }; 279AE6F42395B80F004DD600 /* libpam.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libpam.tbd; path = usr/lib/libpam.tbd; sourceTree = SDKROOT; }; 27A8095F28A9B9D500B20BC8 /* dnssd.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = dnssd.h; path = ../cups/dnssd.h; sourceTree = ""; }; 27A8096028A9B9D500B20BC8 /* dnssd.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnssd.c; path = ../cups/dnssd.c; sourceTree = ""; }; @@ -1242,6 +1277,21 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 2794E8FE28AFFC2400BEDC04 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 2794E8FF28AFFC2400BEDC04 /* libcrypto.a in Frameworks */, + 2794E90028AFFC2400BEDC04 /* libssl.a in Frameworks */, + 2794E90128AFFC2400BEDC04 /* libcups_static.a in Frameworks */, + 2794E90228AFFC2400BEDC04 /* CoreFoundation.framework in Frameworks */, + 2794E90328AFFC2400BEDC04 /* libiconv.dylib in Frameworks */, + 2794E90428AFFC2400BEDC04 /* libresolv.dylib in Frameworks */, + 2794E90528AFFC2400BEDC04 /* libz.dylib in Frameworks */, + 2794E90628AFFC2400BEDC04 /* Security.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 27D3966D27BA81D3003D3D8E /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1440,6 +1490,7 @@ 270D02251D707E3700EA9403 /* testcreds.c */, 273BF6C61333B5370022CAAB /* testcups.c */, 2767FC5119266A36000F61D3 /* testdest.c */, + 2794E90E28AFFC6600BEDC04 /* testdnssd.c */, 727EF045192E3544001EF690 /* testfile.c */, 278C58E2136B647200836530 /* testhttp.c */, 727EF046192E3544001EF690 /* testi18n.c */, @@ -1497,6 +1548,7 @@ 274770E02345342B0089BC31 /* testthreads */, 2778BBD9275DA09B0070DA11 /* fuzzipp */, 27D3967527BA81D3003D3D8E /* testtestpage */, + 2794E90B28AFFC2400BEDC04 /* testdnssd */, ); name = Products; sourceTree = ""; @@ -1950,6 +2002,24 @@ productReference = 278C58CB136B640300836530 /* testhttp */; productType = "com.apple.product-type.tool"; }; + 2794E8F928AFFC2400BEDC04 /* testdnssd */ = { + isa = PBXNativeTarget; + buildConfigurationList = 2794E90828AFFC2400BEDC04 /* Build configuration list for PBXNativeTarget "testdnssd" */; + buildPhases = ( + 2794E8FC28AFFC2400BEDC04 /* Sources */, + 2794E8FE28AFFC2400BEDC04 /* Frameworks */, + 2794E90728AFFC2400BEDC04 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 2794E8FA28AFFC2400BEDC04 /* PBXTargetDependency */, + ); + name = testdnssd; + productName = testcups; + productReference = 2794E90B28AFFC2400BEDC04 /* testdnssd */; + productType = "com.apple.product-type.tool"; + }; 27D3966827BA81D3003D3D8E /* testtestpage */ = { isa = PBXNativeTarget; buildConfigurationList = 27D3967227BA81D3003D3D8E /* Build configuration list for PBXNativeTarget "testtestpage" */; @@ -2226,6 +2296,7 @@ 270D02131D707E0200EA9403 /* testcreds */, 273BF6BC1333B5000022CAAB /* testcups */, 2767FC4619266A0D000F61D3 /* testdest */, + 2794E8F928AFFC2400BEDC04 /* testdnssd */, 724FA5701CC037810092477B /* testfile */, 278C58CA136B640300836530 /* testhttp */, 724FA5831CC037980092477B /* testi18n */, @@ -2411,6 +2482,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 2794E8FC28AFFC2400BEDC04 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 2794E90F28AFFC6600BEDC04 /* testdnssd.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 27D3966B27BA81D3003D3D8E /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -2695,6 +2774,16 @@ target = 274FF6891333B1C400317ECB /* libcups3_static */; targetProxy = 278C58D7136B642F00836530 /* PBXContainerItemProxy */; }; + 2794E8FA28AFFC2400BEDC04 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 274FF6891333B1C400317ECB /* libcups3_static */; + targetProxy = 2794E8FB28AFFC2400BEDC04 /* PBXContainerItemProxy */; + }; + 2794E90D28AFFC3F00BEDC04 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 2794E8F928AFFC2400BEDC04 /* testdnssd */; + targetProxy = 2794E90C28AFFC3F00BEDC04 /* PBXContainerItemProxy */; + }; 27D3966927BA81D3003D3D8E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 274FF6891333B1C400317ECB /* libcups3_static */; @@ -3070,6 +3159,24 @@ }; name = Release; }; + 2794E90928AFFC2400BEDC04 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 2794E90A28AFFC2400BEDC04 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_WEAK = YES; + CODE_SIGN_IDENTITY = "-"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; 27D3967327BA81D3003D3D8E /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -3585,6 +3692,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 2794E90828AFFC2400BEDC04 /* Build configuration list for PBXNativeTarget "testdnssd" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 2794E90928AFFC2400BEDC04 /* Debug */, + 2794E90A28AFFC2400BEDC04 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 27D3967227BA81D3003D3D8E /* Build configuration list for PBXNativeTarget "testtestpage" */ = { isa = XCConfigurationList; buildConfigurations = ( From 51f94d3fb5c55eb5ba0a9af470ea115fdf3e956d Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Fri, 19 Aug 2022 20:04:35 -0400 Subject: [PATCH 08/19] Add cupsDNSSD...GetContext functions, test resolves. --- cups/dnssd.c | 62 ++++++++++++++++++++++--- cups/dnssd.h | 4 ++ cups/testdnssd.c | 115 +++++++++++++++++++++++++++++++++++++++++------ 3 files changed, 160 insertions(+), 21 deletions(-) diff --git a/cups/dnssd.c b/cups/dnssd.c index 3ab27f379..9307e8713 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -360,7 +360,19 @@ cupsDNSSDBrowseDelete( // -// 'cupsDNSSDBrowseNew()' - . +// 'cupsDNSSDBrowseGetContext()' - Get the DNS-SD context for the browse request. +// + +cups_dnssd_t * // O - Context or `NULL` +cupsDNSSDBrowseGetContext( + cups_dnssd_browse_t *browse) // I - Browse request +{ + return (browse ? browse->dnssd : NULL); +} + + +// +// 'cupsDNSSDBrowseNew()' - Create a new DNS-SD browse request. // cups_dnssd_browse_t * // O - Browse request or `NULL` on error @@ -449,6 +461,18 @@ cupsDNSSDQueryDelete( } +// +// 'cupsDNSSDQueryGetContext()' - Get the DNS-SD context for the query request. +// + +cups_dnssd_t * // O - DNS-SD context or `NULL` +cupsDNSSDQueryGetContext( + cups_dnssd_query_t *query) // I - Query request +{ + return (query ? query->dnssd : NULL); +} + + // // 'cupsDNSSDQueryNew()' - Create a new query request. // @@ -525,7 +549,7 @@ cupsDNSSDQueryNew( // -// 'cupsDNSSDResolveDelete()' - . +// 'cupsDNSSDResolveDelete()' - Cancel and free a resolve request. // void @@ -544,7 +568,19 @@ cupsDNSSDResolveDelete( // -// 'cupsDNSSDResolveNew()' - . +// 'cupsDNSSDResolveGetContext()' - Get the DNS-SD context for the resolve request. +// + +cups_dnssd_t * // O - DNS-SD context or `NULL` +cupsDNSSDResolveGetContext( + cups_dnssd_resolve_t *resolve) // I - Resolve request +{ + return (resolve ? resolve->dnssd : NULL); +} + + +// +// 'cupsDNSSDResolveNew()' - Create a new DNS-SD resolve request. // cups_dnssd_resolve_t * // O - Resolve request or `NULL` on error @@ -615,7 +651,7 @@ cupsDNSSDResolveNew( // -// 'cupsDNSSDServiceAdd()' - . +// 'cupsDNSSDServiceAdd()' - Add a service instance. // bool // O - `true` on success, `false` on failure @@ -697,7 +733,7 @@ cupsDNSSDServiceAdd( // -// 'cupsDNSSDServiceDelete()' - . +// 'cupsDNSSDServiceDelete()' - Cancel and free a service registration. // void @@ -716,7 +752,19 @@ cupsDNSSDServiceDelete( // -// 'cupsDNSSDServiceNew()' - . +// 'cupsDNSSDServiceGetContext()' - Get the DNS-SD context for the service registration. +// + +cups_dnssd_t * // O - DNS-SD context or `NULL` +cupsDNSSDServiceGetContext( + cups_dnssd_service_t *service) // I - Service registration +{ + return (service ? service->dnssd : NULL); +} + + +// +// 'cupsDNSSDServiceNew()' - Create a new named service. // cups_dnssd_service_t * // O - Service or `NULL` on error @@ -767,7 +815,7 @@ cupsDNSSDServiceNew( // -// 'cupsDNSSDServicePublish()' - . +// 'cupsDNSSDServicePublish()' - Publish a service. // bool // O - `true` on success, `false` on failure diff --git a/cups/dnssd.h b/cups/dnssd.h index c184f1bb4..5c07252ce 100644 --- a/cups/dnssd.h +++ b/cups/dnssd.h @@ -88,16 +88,20 @@ extern void cupsDNSSDDelete(cups_dnssd_t *dnssd) _CUPS_PUBLIC; extern cups_dnssd_t *cupsDNSSDNew(cups_dnssd_error_cb_t error_cb, void *cb_data) _CUPS_PUBLIC; extern void cupsDNSSDBrowseDelete(cups_dnssd_browse_t *browser) _CUPS_PUBLIC; +extern cups_dnssd_t *cupsDNSSDBrowseGetContext(cups_dnssd_browse_t *browser) _CUPS_PUBLIC; extern cups_dnssd_browse_t *cupsDNSSDBrowseNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *types, const char *domain, cups_dnssd_browse_cb_t browse_cb, void *cb_data) _CUPS_PUBLIC; extern void cupsDNSSDQueryDelete(cups_dnssd_query_t *query) _CUPS_PUBLIC; +extern cups_dnssd_t *cupsDNSSDQueryGetContext(cups_dnssd_query_t *query) _CUPS_PUBLIC; extern cups_dnssd_query_t *cupsDNSSDQueryNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *fullname, uint16_t rrtype, cups_dnssd_query_cb_t query_cb, void *cb_data) _CUPS_PUBLIC; extern void cupsDNSSDResolveDelete(cups_dnssd_resolve_t *res) _CUPS_PUBLIC; +extern cups_dnssd_t *cupsDNSSDResolveGetContext(cups_dnssd_resolve_t *res) _CUPS_PUBLIC; extern cups_dnssd_resolve_t *cupsDNSSDResolveNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *name, const char *type, const char *domain, cups_dnssd_resolve_cb_t resolve_cb, void *cb_data) _CUPS_PUBLIC; extern bool cupsDNSSDServiceAdd(cups_dnssd_service_t *service, uint32_t if_index, const char *types, const char *domain, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt) _CUPS_PUBLIC; extern void cupsDNSSDServiceDelete(cups_dnssd_service_t *service) _CUPS_PUBLIC; +extern cups_dnssd_t *cupsDNSSDServiceGetContext(cups_dnssd_service_t *service) _CUPS_PUBLIC; extern cups_dnssd_service_t *cupsDNSSDServiceNew(cups_dnssd_t *dnssd, const char *name, cups_dnssd_service_cb_t cb, void *cb_data) _CUPS_PUBLIC; extern bool cupsDNSSDServicePublish(cups_dnssd_service_t *service) _CUPS_PUBLIC; extern bool cupsDNSSDServiceSetLocation(cups_dnssd_service_t *service, const char *geo_uri) _CUPS_PUBLIC; diff --git a/cups/testdnssd.c b/cups/testdnssd.c index 6457dc033..d61ad7151 100644 --- a/cups/testdnssd.c +++ b/cups/testdnssd.c @@ -19,6 +19,7 @@ typedef struct testdata_s // Test data structure { cups_mutex_t mutex; // Mutex for access + cups_array_t *messages; // Messages from callbacks size_t browse_count; // Number of browse callbacks size_t error_count; // Number of error callbacks size_t query_count; // Number of query callbacks @@ -34,7 +35,7 @@ typedef struct testdata_s // Test data structure static void browse_cb(cups_dnssd_browse_t *browse, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain); static void error_cb(void *cb_data, const char *message); //static void query_cb(cups_dnssd_query_t *query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen); -//static void resolve_cb(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt); +static void resolve_cb(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt); static void service_cb(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags, const char *name, const char *regtype, const char *domain); static void usage(const char *arg); @@ -47,11 +48,12 @@ int // O - Exit status main(int argc, // I - Number of command-line arguments char *argv[]) // I - Command-line arguments { - int i; // Looping var + int i, // Looping var + ret = 0; // Return value cups_dnssd_t *dnssd; // DNS-SD context cups_dnssd_browse_t *browse; // DNS-SD browse request // cups_dnssd_query_t *query; // DNS-SD query request -// cups_dnssd_resolve_t *resolve; // DNS-SD resolve request + cups_dnssd_resolve_t *resolve; // DNS-SD resolve request cups_dnssd_service_t *service; // DNS-SD service registration size_t num_txt; // Number of TXT record key/value pairs cups_option_t *txt; // TXT record key/value pairs @@ -60,6 +62,7 @@ main(int argc, // I - Number of command-line arguments // Clear test data... memset(&testdata, 0, sizeof(testdata)); + testdata.messages = cupsArrayNew(NULL, NULL, NULL, 0, (cups_acopy_cb_t)strdup, (cups_afree_cb_t)free); if (argc == 1) { @@ -72,37 +75,94 @@ main(int argc, // I - Number of command-line arguments testBegin("cupsDNSSDBrowseNew(_ipp._tcp)"); if ((browse = cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp", NULL, browse_cb, &testdata)) != NULL) + { testEnd(true); + } else - return (1); + { + ret = 1; + goto done; + } + + testBegin("cupsDNSSDBrowseGetContext"); + testEnd(cupsDNSSDBrowseGetContext(browse) == dnssd); + + testBegin("cupsDNSSDBrowseNew(_http._tcp)"); + if ((browse = cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_http._tcp", NULL, browse_cb, &testdata)) != NULL) + { + testEnd(true); + } + else + { + ret = 1; + goto done; + } + + testBegin("cupsDNSSDBrowseGetContext"); + testEnd(cupsDNSSDBrowseGetContext(browse) == dnssd); testBegin("cupsDNSSDServiceNew(Test Printer)"); if ((service = cupsDNSSDServiceNew(dnssd, "Test Printer", service_cb, &testdata)) != NULL) + { testEnd(true); + } else - return (1); + { + ret = 1; + goto done; + } num_txt = cupsAddOption("rp", "ipp/print", 0, &txt); testBegin("cupsDNSSDServiceAdd(_http._tcp)"); if (cupsDNSSDServiceAdd(service, CUPS_DNSSD_IF_INDEX_ANY, "_http._tcp,_printer", NULL, NULL, 631, 0, NULL)) + { testEnd(true); + } else - return (1); + { + ret = 1; + goto done; + } testBegin("cupsDNSSDServiceAdd(_ipp._tcp)"); if (cupsDNSSDServiceAdd(service, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp,_print", NULL, NULL, 631, num_txt, txt)) + { testEnd(true); + } else - return (1); + { + ret = 1; + goto done; + } + + testBegin("cupsDNSSDServicePublish"); + testEnd(cupsDNSSDServicePublish(service)); + + testBegin("cupsDNSSDServiceGetContext"); + testEnd(cupsDNSSDServiceGetContext(service) == dnssd); cupsFreeOptions(num_txt, txt); + testBegin("cupsDNSSDResolveNew(Test Printer._ipp._tcp.local.)"); + if ((resolve = cupsDNSSDResolveNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "Test Printer", "_ipp._tcp", "local.", resolve_cb, &testdata)) != NULL) + { + testEnd(true); + } + else + { + ret = 1; + goto done; + } + + testBegin("cupsDNSSDResolveGetContext"); + testEnd(cupsDNSSDResolveGetContext(resolve) == dnssd); + testBegin("Wait for callbacks"); for (i = 0; i < 30; i ++) { - if (testdata.service_count != 0 && testdata.browse_count != 0) + if (testdata.service_count != 0 && testdata.browse_count != 0 && testdata.resolve_count != 0) break; sleep(1); @@ -110,14 +170,23 @@ main(int argc, // I - Number of command-line arguments testEnd(i < 30); + done: + cupsDNSSDDelete(dnssd); + + const char *message; // Current message + + for (message = (const char *)cupsArrayGetFirst(testdata.messages); message; message = (const char *)cupsArrayGetNext(testdata.messages)) + puts(message); + + cupsArrayDelete(testdata.messages); } else { usage(argv[1]); } - return (0); + return (ret); } @@ -137,11 +206,15 @@ browse_cb( { testdata_t *data = (testdata_t *)cb_data; // Test data + char message[1024]; // Message string + + snprintf(message, sizeof(message), "B flags=%02X if_index=%u name=\"%s\" regtype=\"%s\" domain=\"%s\"", flags, if_index, name, regtype, domain); - fprintf(stderr, "Browse flags=%02X if_index=%u name=\"%s\" regtype=\"%s\" domain=\"%s\"\n", flags, if_index, name, regtype, domain); + cupsDNSSDResolveNew(cupsDNSSDBrowseGetContext(browse), CUPS_DNSSD_IF_INDEX_ANY, name, regtype, domain, resolve_cb, cb_data); cupsMutexLock(&data->mutex); + cupsArrayAdd(data->messages, message); data->browse_count ++; cupsMutexUnlock(&data->mutex); } @@ -185,14 +258,17 @@ query_cb( { testdata_t *data = (testdata_t *)cb_data; // Test data + char message[1024]; // Message string - fprintf(stderr, "Query: flags=%02X if_index=%u fullname=\"%s\" rrtype=%u qdata=%p qlen=%u\n", flags, if_index, fullname, rrtype, qdata, qlen); + snprintf(message, sizeof(message), "Q flags=%02X if_index=%u fullname=\"%s\" rrtype=%u qdata=%p qlen=%u", flags, if_index, fullname, rrtype, qdata, qlen); cupsMutexLock(&data->mutex); + cupsArrayAdd(data->messages, message); data->query_count ++; cupsMutexUnlock(&data->mutex); } +#endif // 0 static void @@ -209,15 +285,24 @@ resolve_cb( { testdata_t *data = (testdata_t *)cb_data; // Test data + int i; // Looping var + char message[2048], // Message string + *mptr; // Pointer into message string + const char *prefix = ", txt="; // Prefix string - fprintf(stderr, "Resolve: flags=%02X if_index=%u fullname=\"%s\" host=\"%s\" port=%u num_txt=%u, txt=%p\n", flags, if_index, fullname, host, port, (unsigned)num_txt, txt); + snprintf(message, sizeof(message), "R flags=%02X if_index=%u fullname=\"%s\" host=\"%s\" port=%u num_txt=%u", flags, if_index, fullname, host, port, (unsigned)num_txt); + for (mptr = message + strlen(message), i = 0; i < num_txt; i ++, mptr += strlen(mptr)) + { + snprintf(mptr, sizeof(message) - (size_t)(mptr - message), "%s\"%s=%s\"", prefix, txt[i].name, txt[i].value); + prefix = ","; + } cupsMutexLock(&data->mutex); + cupsArrayAdd(data->messages, message); data->resolve_count ++; cupsMutexUnlock(&data->mutex); } -#endif // 0 static void @@ -231,11 +316,13 @@ service_cb( { testdata_t *data = (testdata_t *)cb_data; // Test data + char message[1024]; // Message string - fprintf(stderr, "Service: flags=%02X name=\"%s\" regtype=\"%s\" domain=\"%s\"\n", flags, name, regtype, domain); + snprintf(message, sizeof(message), "S flags=%02X name=\"%s\" regtype=\"%s\" domain=\"%s\"", flags, name, regtype, domain); cupsMutexLock(&data->mutex); + cupsArrayAdd(data->messages, message); data->service_count ++; cupsMutexUnlock(&data->mutex); } From 8e2a9aeace2cba8e8e90161e9620f443eff5238e Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Fri, 19 Aug 2022 20:17:54 -0400 Subject: [PATCH 09/19] Documentation. --- cups/testdnssd.c | 58 +++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/cups/testdnssd.c b/cups/testdnssd.c index d61ad7151..0ffce7af8 100644 --- a/cups/testdnssd.c +++ b/cups/testdnssd.c @@ -191,7 +191,7 @@ main(int argc, // I - Number of command-line arguments // -// 'browse_cb()' - Browse callback. +// 'browse_cb()' - Record browse request callback usage. // static void @@ -242,19 +242,19 @@ error_cb(void *cb_data, // I - Callback data #if 0 // -// 'query_cb()' - Query callback. +// 'query_cb()' - Record query request callback usage. // static void query_cb( - cups_dnssd_query_t *query, - void *cb_data, - cups_dnssd_flags_t flags, - uint32_t if_index, - const char *fullname, - uint16_t rrtype, - const void *qdata, - uint16_t qlen) + cups_dnssd_query_t *query, // I - Query request + void *cb_data, // I - Callback data + cups_dnssd_flags_t flags, // I - Flags + uint32_t if_index, // I - Interface index + const char *fullname, // I - Full service name + uint16_t rrtype, // I - Record type + const void *qdata, // I - Record data + uint16_t qlen) // I - Length of record data { testdata_t *data = (testdata_t *)cb_data; // Test data @@ -271,17 +271,21 @@ query_cb( #endif // 0 +// +// 'resolve_cb()' - Record resolve request callback usage. +// + static void resolve_cb( - cups_dnssd_resolve_t *res, - void *cb_data, - cups_dnssd_flags_t flags, - uint32_t if_index, - const char *fullname, - const char *host, - uint16_t port, - size_t num_txt, - cups_option_t *txt) + cups_dnssd_resolve_t *res, // I - Resolve request + void *cb_data, // I - Callback data + cups_dnssd_flags_t flags, // I - Flags + uint32_t if_index, // I - Interface index + const char *fullname, // I - Full service name + const char *host, // I - Hostname + uint16_t port, // I - Port number + size_t num_txt, // I - Number of key/value pairs in TXT record + cups_option_t *txt) // I - Key/value pairs { testdata_t *data = (testdata_t *)cb_data; // Test data @@ -305,14 +309,18 @@ resolve_cb( } +// +// 'service_cb()' - Record service registration callback usage. +// + static void service_cb( - cups_dnssd_service_t *service, - void *cb_data, - cups_dnssd_flags_t flags, - const char *name, - const char *regtype, - const char *domain) + cups_dnssd_service_t *service, // I - Service registration + void *cb_data, // I - Callback data + cups_dnssd_flags_t flags, // I - Flags + const char *name, // I - Service name + const char *regtype, // I - Registration type + const char *domain) // I - Domain name { testdata_t *data = (testdata_t *)cb_data; // Test data From 9ee2110557710cee1a1d92328d1d595b6244ec40 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Fri, 19 Aug 2022 20:40:12 -0400 Subject: [PATCH 10/19] Test query requests, too. --- cups/dnssd.c | 13 ++++++++++++- cups/testdnssd.c | 24 ++++++++++++++++++------ 2 files changed, 30 insertions(+), 7 deletions(-) diff --git a/cups/dnssd.c b/cups/dnssd.c index 9307e8713..780c9b424 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -156,7 +156,18 @@ cupsDNSSDAssembleFullName( if (!fullname || !fullsize || !name || !type) return (false); - return (snprintf(fullname, fullsize, "%s.%s.%s", name, type, domain ? domain : "local") < (int)(fullsize - 1)); +#if _WIN32 + return (false); + +#elif defined(HAVE_MDNSRESPONDER) + if (fullsize < kDNSServiceMaxDomainName) + return (false); + + return (DNSServiceConstructFullName(fullname, name, type, domain) == kDNSServiceErr_NoError); +#else // HAVE_AVAHI + + return (false); +#endif // _WIN32 } diff --git a/cups/testdnssd.c b/cups/testdnssd.c index 0ffce7af8..265a716f2 100644 --- a/cups/testdnssd.c +++ b/cups/testdnssd.c @@ -34,7 +34,7 @@ typedef struct testdata_s // Test data structure static void browse_cb(cups_dnssd_browse_t *browse, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain); static void error_cb(void *cb_data, const char *message); -//static void query_cb(cups_dnssd_query_t *query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen); +static void query_cb(cups_dnssd_query_t *query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen); static void resolve_cb(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt); static void service_cb(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags, const char *name, const char *regtype, const char *domain); static void usage(const char *arg); @@ -207,12 +207,16 @@ browse_cb( testdata_t *data = (testdata_t *)cb_data; // Test data char message[1024]; // Message string + char fullname[1024]; // Full service name snprintf(message, sizeof(message), "B flags=%02X if_index=%u name=\"%s\" regtype=\"%s\" domain=\"%s\"", flags, if_index, name, regtype, domain); cupsDNSSDResolveNew(cupsDNSSDBrowseGetContext(browse), CUPS_DNSSD_IF_INDEX_ANY, name, regtype, domain, resolve_cb, cb_data); + cupsDNSSDAssembleFullName(fullname, sizeof(fullname), name, regtype, domain); + cupsDNSSDQueryNew(cupsDNSSDBrowseGetContext(browse), CUPS_DNSSD_IF_INDEX_ANY, fullname, CUPS_DNSSD_RRTYPE_TXT, query_cb, cb_data); + cupsMutexLock(&data->mutex); cupsArrayAdd(data->messages, message); data->browse_count ++; @@ -240,7 +244,6 @@ error_cb(void *cb_data, // I - Callback data } -#if 0 // // 'query_cb()' - Record query request callback usage. // @@ -258,17 +261,26 @@ query_cb( { testdata_t *data = (testdata_t *)cb_data; // Test data - char message[1024]; // Message string + uint16_t i; // Looping var + char message[2048], // Message string + *mptr; // Pointer into message string + const unsigned char *qptr; // Pointer into record data - snprintf(message, sizeof(message), "Q flags=%02X if_index=%u fullname=\"%s\" rrtype=%u qdata=%p qlen=%u", flags, if_index, fullname, rrtype, qdata, qlen); + snprintf(message, sizeof(message), "Q flags=%02X if_index=%u fullname=\"%s\" rrtype=%u qlen=%u qdata=<", flags, if_index, fullname, rrtype, qlen); + for (mptr = message + strlen(message), i = 0, qptr = (const unsigned char *)qdata; i < qlen; i ++, mptr += strlen(mptr), qptr ++) + snprintf(mptr, sizeof(message) - (size_t)(mptr - message), "%02X", *qptr); + if (mptr < (message + sizeof(message) - 1)) + { + *mptr++ = '>'; + *mptr = '\0'; + } cupsMutexLock(&data->mutex); cupsArrayAdd(data->messages, message); data->query_count ++; cupsMutexUnlock(&data->mutex); } -#endif // 0 // @@ -292,7 +304,7 @@ resolve_cb( int i; // Looping var char message[2048], // Message string *mptr; // Pointer into message string - const char *prefix = ", txt="; // Prefix string + const char *prefix = " txt="; // Prefix string snprintf(message, sizeof(message), "R flags=%02X if_index=%u fullname=\"%s\" host=\"%s\" port=%u num_txt=%u", flags, if_index, fullname, host, port, (unsigned)num_txt); From f34b28a3d76019031140fadf7c5090a5e1218a0d Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Sun, 21 Aug 2022 19:16:12 -0400 Subject: [PATCH 11/19] DNS-SD API cleanup, add Avahi implementation (needs testing) --- cups/dnssd.c | 575 ++++++++++++++++++++++-- cups/dnssd.h | 12 +- cups/testdnssd.c | 15 +- xcode/libcups.xcodeproj/project.pbxproj | 2 + 4 files changed, 566 insertions(+), 38 deletions(-) diff --git a/cups/dnssd.c b/cups/dnssd.c index 780c9b424..08631bdba 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -12,6 +12,12 @@ #include "dnssd.h" #include "debug-internal.h" +#ifdef __APPLE__ +# include +# include +# include +#endif // __APPLE__ + #if _WIN32 # include #elif defined(HAVE_MDNSRESPONDER) @@ -41,7 +47,7 @@ struct _cups_dns_srv_s // DNS SRV record struct _cups_dnssd_s // DNS-SD context { cups_mutex_t mutex; // Mutex for context - size_t name_changes; // Number of hostname changes + size_t config_changes; // Number of hostname/network changes cups_dnssd_error_cb_t cb; // Error callback function void *cb_data; // Error callback data cups_array_t *browses, // Browse requests @@ -49,6 +55,10 @@ struct _cups_dnssd_s // DNS-SD context *resolves, // Resolve requests *services; // Registered services +#ifdef __APPLE__ + SCDynamicStoreRef sc; // Dyanmic store context for host info +#endif // __APPLE__ + #if _WIN32 #elif defined(HAVE_MDNSRESPONDER) @@ -71,6 +81,7 @@ struct _cups_dnssd_browse_s // DNS-SD browse request #elif defined(HAVE_MDNSRESPONDER) DNSServiceRef ref; // Browse reference #else // HAVE_AVAHI + AvahiServiceBrowser *browser; // Browser #endif // _WIN32 }; @@ -84,6 +95,7 @@ struct _cups_dnssd_query_s // DNS-SD query request #elif defined(HAVE_MDNSRESPONDER) DNSServiceRef ref; // Query reference #else // HAVE_AVAHI + AvahiRecordBrowser *browser; // Browser #endif // _WIN32 }; @@ -97,6 +109,7 @@ struct _cups_dnssd_resolve_s // DNS-SD resolve request #elif defined(HAVE_MDNSRESPONDER) DNSServiceRef ref; // Resolve reference #else // HAVE_AVAHI + AvahiServiceResolver *resolver; // Resolver #endif // _WIN32 }; @@ -115,6 +128,7 @@ struct _cups_dnssd_service_s // DNS-SD service registration DNSServiceRef refs[16]; // Service references DNSRecordRef loc_refs[16]; // Service location records #else // HAVE_AVAHI + AvahiEntryGroup *group; // Group of services under this name #endif // _WIN32 }; @@ -127,8 +141,16 @@ static void delete_browse(cups_dnssd_browse_t *browse); static void delete_query(cups_dnssd_query_t *query); static void delete_resolve(cups_dnssd_resolve_t *resolve); static void delete_service(cups_dnssd_service_t *service); +static void record_config_change(cups_dnssd_t *dnssd, cups_dnssd_flags_t flags); +static void report_error(cups_dnssd_t *dnssd, const char *message, ...) _CUPS_FORMAT(2,3); -#ifdef HAVE_MDNSRESPONDER +#ifdef __APPLE__ +static void apple_sc_cb(SCDynamicStoreRef sc, CFArrayRef changed, cups_dnssd_t *dnssd); +#endif // __APPLE__ + +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) static void *mdns_monitor(cups_dnssd_t *dnssd); static void mdns_browse_cb(DNSServiceRef ref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType error, const char *name, const char *regtype, const char *domain, cups_dnssd_browse_t *browse); static void mdns_query_cb(DNSServiceRef ref, DNSServiceFlags flags, uint32_t if_index, DNSServiceErrorType error, const char *name, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, cups_dnssd_query_t *query); @@ -136,8 +158,14 @@ static void mdns_resolve_cb(DNSServiceRef ref, DNSServiceFlags flags, uint32_t static void mdns_service_cb(DNSServiceRef ref, DNSServiceFlags flags, DNSServiceErrorType error, const char *name, const char *regtype, const char *domain, cups_dnssd_service_t *service); static const char *mdns_strerror(DNSServiceErrorType errorCode); static cups_dnssd_flags_t mdns_to_cups(DNSServiceFlags flags, DNSServiceErrorType error); -#endif // HAVE_MDNSRESPONDER -static void report_error(cups_dnssd_t *dnssd, const char *message, ...) _CUPS_FORMAT(2,3); + +#else // HAVE_AVAHI +static void avahi_browse_cb(AvahiServiceBrowser *browser, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, cups_dnssd_browse_t *browse); +static void avahi_client_cb(AvahiClient *c, AvahiClientState state, cups_dnssd_t *dnssd); +static void avahi_query_cb(AvahiRecordBrowser *browser, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiBrowserEvent event, const char *fullName, uint16_t rrclass, uint16_t rrtype, const void *rdata, size_t rdlen, AvahiLookupResultFlags flags, cups_dnssd_query_t *query); +static void avahi_resolve_cb(AvahiServiceResolver *resolver, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txtrec, AvahiLookupResultFlags flags, cups_dnssd_resolve_t *resolve); +static void avahi_service_cb(AvahiEntryGroup *srv, AvahiEntryGroupState state, cups_dnssd_service_t *service); +#endif // _WIN32 // @@ -164,9 +192,9 @@ cupsDNSSDAssembleFullName( return (false); return (DNSServiceConstructFullName(fullname, name, type, domain) == kDNSServiceErr_NoError); -#else // HAVE_AVAHI - return (false); +#else // HAVE_AVAHI + return (!avahi_service_name_join(fullname, fullsize, name, type, domain)); #endif // _WIN32 } @@ -292,6 +320,78 @@ cupsDNSSDDelete(cups_dnssd_t *dnssd) // I - DNS-SD context } +// +// 'cupsDNSSDGetHostName()' - Get the current mDNS host name for the system. +// +// This function gets the current mDNS (".local") host name for the system. +// + +const char * // O - Local host name or `NULL` for none +cupsDNSSDGetHostName( + cups_dnssd_t *dnssd, // I - DNS-SD context + char *buffer, // I - Host name buffer + size_t bufsize) // I - Size of host name buffer +{ + // Range check input... + if (buffer) + *buffer = '\0'; + + if (!dnssd || !buffer || !bufsize) + return (NULL); + +#if _WIN32 || defined(HAVE_MDNSRESPONDER) + char *bufptr; // Pointer into buffer +# ifdef __APPLE__ + CFStringRef localname; // Local host name as a CF string + + if ((localname = SCDynamicStoreCopyLocalHostName(dnssd->sc)) != NULL) + { + CFStringGetCString(localname, buffer, (CFIndex)bufsize, kCFStringEncodingUTF8); + CFRelease(localname); + } + else +# endif // __APPLE__ + gethostname(buffer, bufsize); + + if ((bufptr = strchr(buffer, '.')) != NULL) + { + // Replace domain with .local as needed... + if (strcmp(bufptr, ".local")) + cupsCopyString(bufptr, ".local", bufsize - (size_t)(bufptr - buffer)); + } + else + { + // Add .local... + cupsConcatString(buffer, ".local", bufsize); + } + +#else // HAVE_AVAHI + cupsCopyString(buffer, avahi_client_get_host_name_fqdn(dnssd->client), bufsize); +#endif // _WIN32 + + return (buffer); +} + + +// +// 'cupsDNSSDGetConfigChanges()' - Get the number of host name/network configuration changes seen. +// +// This function returns the numebr of host name or network configuration +// changes that have been seen since the context was created. The value can be +// used to track when local services need to be updated. Registered services +// will also get a callback with the `CUPS_DNSSD_FLAGS_HOST_CHANGE` bit set in +// the "flags" argument for host name changes and/or +// `CUPS_DNSSD_FLAGS_NETWORK_CHANGE` for network changes. +// + +size_t // O - Number of host name changes +cupsDNSSDGetConfigChanges( + cups_dnssd_t *dnssd) // I - DNS-SD context +{ + return (dnssd ? dnssd->config_changes : 0); +} + + // // 'cupsDNSSDNew()' - Create a new DNS-SD context. // @@ -318,6 +418,16 @@ cupsDNSSDNew( // Initialize the mutex... cupsMutexInit(&dnssd->mutex); +#ifdef __APPLE__ + // Use the system configuration dynamic store for host info... + SCDynamicStoreContext scinfo; // Information for callback + + memset(&scinfo, 0, sizeof(scinfo)); + scinfo.info = dnssd; + + dnssd->sc = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("libcups3"), (SCDynamicStoreCallBack)apple_sc_cb, &scinfo); +#endif // __APPLE__ + // Setup the DNS-SD connection and monitor thread... #if _WIN32 @@ -326,6 +436,7 @@ cupsDNSSDNew( if ((error = DNSServiceCreateConnection(&dnssd->ref)) == kDNSServiceErr_NoError) { + // Start the background monitoring thread... if ((dnssd->monitor = cupsThreadCreate((void *(*)(void *))mdns_monitor, dnssd)) == 0) { report_error(dnssd, "Unable to create DNS-SD thread: %s", strerror(errno)); @@ -337,13 +448,35 @@ cupsDNSSDNew( } else { + // Unable to create connection... report_error(dnssd, "Unable to initialize DNS-SD: %s", mdns_strerror(error)); cupsDNSSDDelete(dnssd); return (NULL); } #else // HAVE_AVAHI + int error; // Error code + if ((dnssd->monitor = avahi_threaded_poll_new()) == NULL) + { + // Unable to create the background thread... + report_error(dnssd, "Unable to initialize DNS-SD thread: %s", strerror(errno)); + cupsDNSSDDelete(dnssd); + return (NULL); + } + else if ((dnssd->client = avahi_client_new(avahi_threaded_poll_get(dnssd->monitor), AVAHI_CLIENT_NO_FAIL, (AvahiClientCallback)avahi_client_cb, dnssd, &error)) == NULL) + { + // Unable to create the client... + report_error(dnssd, "Unable to initialize DNS-SD: %s", avahi_strerror(error)); + avahi_threaded_poll_free(dnssd->monitor); + cupsDNSSDDelete(dnssd); + return (NULL); + } + else + { + // Start the background thread... + avahi_threaded_poll_start(dnssd->monitor); + } #endif // _WIN32 return (dnssd); @@ -439,7 +572,17 @@ cupsDNSSDBrowseNew( } #else // HAVE_AVAHI + avahi_threaded_poll_lock(dnssd->monitor); + browse->browser = avahi_service_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, types, NULL, 0, avahi_browse_cb, browse); + avahi_threaded_poll_unlock(dnssd->monitor); + if (!browse->browser) + { + report_error(dnssd, "Unable to create DNS-SD browse request: %s", avahi_strerror(avahi_client_errno(dnssd->client))); + free(browse); + browse = NULL; + goto done; + } #endif // _WIN32 cupsArrayAdd(dnssd->browses, browse); @@ -545,7 +688,17 @@ cupsDNSSDQueryNew( } #else // HAVE_AVAHI + avahi_threaded_poll_lock(dnssd->monitor); + query->browser = avahi_record_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, fullname, AVAHI_DNS_CLASS_IN, rrtype, 0, (AvahiRecordBrowserCallback)avahi_query_cb, query); + avahi_threaded_poll_unlock(dnssd->monitor); + if (!query->browser) + { + report_error(dnssd, "Unable to create DNS-SD query request: %s", avahi_strerror(avahi_client_errno(dnssd->client))); + free(query); + query = NULL; + goto done; + } #endif // _WIN32 cupsArrayAdd(dnssd->queries, query); @@ -648,7 +801,17 @@ cupsDNSSDResolveNew( } #else // HAVE_AVAHI + avahi_threaded_poll_lock(dnssd->monitor); + resolve->resolver = avahi_service_resolver_new(dnssd->client, if_index, AVAHI_PROTO_UNSPEC, name, type, domain, AVAHI_PROTO_UNSPEC, /*flags*/0, (AvahiServiceResolverCallback)avahi_resolve_cb, resolve); + avahi_threaded_poll_unlock(dnssd->monitor); + if (!resolve->resolver) + { + report_error(dnssd, "Unable to create DNS-SD resolve request: %s", avahi_strerror(avahi_client_errno(dnssd->client))); + free(resolve); + resolve = NULL; + goto done; + } #endif // _WIN32 cupsArrayAdd(dnssd->resolves, resolve); @@ -734,7 +897,61 @@ cupsDNSSDServiceAdd( service->num_refs ++; #else // HAVE_AVAHI + int error; // Error code + AvahiStringList *txtrec = NULL; // TXT record string list + char *regtype, // Registration type + *subtypes; // Subtypes (if any) + + // Build the string list from the TXT array... + for (i = 0; i < num_txt; i ++) + txtrec = avahi_string_list_add_printf(txtrec, "%s=%s", txt[i].name, txt[i].value); + + // Copy the registration type... + if ((regtype = strdup(types)) == NULL) + { + report_error(service->dnssd, "Unable to duplicate registration types: %s", strerror(errno)); + ret = false; + goto done; + } + + if ((subtypes = strchr(regtype, ',')) != NULL) + *subtypes++ = '\0'; + + // Add the service entry... + avahi_threaded_poll_lock(service->dnssd->monitor); + if ((error = avahi_entry_group_add_service_strlst(service->group, if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, regtype, domain, host, port, txt)) < 0) + { + report_error(service->dnssd, "Unable to register '%s.%s': %s", service->name, regtype, avahi_strerror(error)); + ret = false; + } + else if (subtypes) + { + char subtype[256]; // Subtype string + char *start, *end; // Pointers into sub-types... + + for (start = subtypes; ret && start && *start; start = end) + { + if ((end = strchr(start, ',')) != NULL) + *end++ = '\0'; + else + end = start + strlen(start); + + snprintf(subtype, sizeof(subtype), "%s._sub.%s", start, regtype); + if ((error = avahi_entry_group_add_service_subtype(service->group, if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, regtype, domain, subtype)) < 0) + { + report_error(service->dnssd, "Unable to register '%s.%s': %s", service->name, subtype, avahi_strerror(error)); + ret = false; + } + } + } + + free(regtype); + + avahi_threaded_poll_unlock(service->dnssd->monitor); + + if (txt) + avahi_string_list_free(txt); #endif // _WIN32 done: @@ -774,6 +991,18 @@ cupsDNSSDServiceGetContext( } +// +// 'cupsDNSSDServiceGetName()' - Get the service instance name for the service registration. +// + +const char * // O - Service instance name +cupsDNSSDServiceGetName( + cups_dnssd_service_t *service) // I - Service registration +{ + return (service ? service->name : NULL); +} + + // // 'cupsDNSSDServiceNew()' - Create a new named service. // @@ -792,7 +1021,7 @@ cupsDNSSDServiceNew( if (!dnssd || !name || !cb) return (NULL); - // Allocate memory for the queryr... + // Allocate memory for the service... if ((service = (cups_dnssd_service_t *)calloc(1, sizeof(cups_dnssd_service_t))) == NULL) return (NULL); @@ -801,6 +1030,22 @@ cupsDNSSDServiceNew( service->cb_data = cb_data; service->name = strdup(name); +#if _WIN32 +#elif defined(HAVE_MDNSRESPONDER) +#else // HAVE_AVAHI + avahi_threaded_poll_lock(dnssd->monitor); + service->group = avahi_entry_group_new(dnssd->client, (AvahiEntryGroupCallback)avahi_service_cb, service); + avahi_threaded_poll_unlock(dnssd->monitor); + + if (!service->group) + { + report_error(dnssd, "Unable to create DNS-SD service registration: %s", avahi_strerror(avahi_client_errno(dnssd->client))); + free(service); + service = NULL; + goto done; + } +#endif // _WIN32 + cupsMutexLock(&dnssd->mutex); if (!dnssd->services) @@ -836,7 +1081,15 @@ cupsDNSSDServicePublish( bool ret = true; // Return value +#if _WIN32 + (void)service; +#elif defined(HAVE_MDNSRESPONDER) (void)service; +#else // HAVE_AVAHI + avahi_threaded_poll_lock(service->dnssd->monitor); + avahi_entry_group_commit(service->group); + avahi_threaded_poll_unlock(service->dnssd->monitor); +#endif // _WIN32 return (ret); } @@ -860,6 +1113,7 @@ cupsDNSSDServiceSetLocation( cups_dnssd_service_t *service, // I - Service const char *geo_uri) // I - Geolocation as a 'geo:' URI { + bool ret = true; // Return value const char *geo_ptr; // Pointer into 'geo;' URI double lat = 0.0, lon = 0.0; // Latitude and longitude in degrees double alt = 0.0; // Altitude in meters @@ -924,7 +1178,26 @@ cupsDNSSDServiceSetLocation( service->loc_set = true; - return (true); +#if _WIN32 + // Add LOC record in cupsDNSSDServiceAdd() + +#elif defined(HAVE_MDNSRESPONDER) + // Add LOC record in cupsDNSSDServiceAdd() + +#else // HAVE_AVAHI + // Add LOC record now... + avahi_threaded_poll_lock(service->dnssd->monitor); + + if ((error = avahi_entry_group_add_record(service->group, if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_LOC, /*ttl*/75 * 60, service->loc, sizeof(service->loc))) < 0) + { + report_error(service->dnssd, "Unable to register LOC record for '%s': %s", service->name, avahi_strerror(error)); + ret = false; + } + + avahi_threaded_poll_unlock(service->dnssd->monitor); +#endif // _WIN32 + + return (ret); } @@ -941,6 +1214,9 @@ delete_browse( DNSServiceRefDeallocate(browse->ref); #else // HAVE_AVAHI + avahi_threaded_poll_lock(browse->dnssd->monitor); + avahi_service_browser_free(browse->browser); + avahi_threaded_poll_unlock(browse->dnssd->monitor); #endif // _WIN32 free(browse); @@ -961,7 +1237,9 @@ delete_query( DNSServiceRefDeallocate(query->ref); #else // HAVE_AVAHI - + avahi_threaded_poll_lock(query->dnssd->monitor); + avahi_record_browser_free(query->browser); + avahi_threaded_poll_unlock(query->dnssd->monitor); #endif // _WIN32 } @@ -981,7 +1259,9 @@ delete_resolve( DNSServiceRefDeallocate(resolve->ref); #else // HAVE_AVAHI - + avahi_threaded_poll_lock(resolve->dnssd->monitor); + avahi_service_resolver_free(resolve->resolver); + avahi_threaded_poll_unlock(resolve->dnssd->monitor); #endif // _WIN32 } @@ -1003,14 +1283,103 @@ delete_service( for (i = 0; i < service->num_refs; i ++) DNSServiceRefDeallocate(service->refs[i]); + #else // HAVE_AVAHI + avahi_threaded_poll_lock(service->dnssd->monitor); + avahi_entry_group_free(service->group); + avahi_threaded_poll_unlock(service->dnssd->monitor); #endif // _WIN32 free(service); } -#ifdef HAVE_MDNSRESPONDER +// +// 'record_config_change()' - Record that the local hostname or network has +// changed and notify any service callbacks. +// + +static void +record_config_change(cups_dnssd_t *dnssd, // I - DNS-SD context + cups_dnssd_flags_t flags) // I - Flags for what changed +{ + cups_dnssd_service_t *service; // Current service + + + cupsMutexLock(&dnssd->mutex); + + dnssd->config_changes ++; + + for (service = (cups_dnssd_service_t *)cupsArrayGetFirst(dnssd->services); service; service = (cups_dnssd_service_t *)cupsArrayGetNext(dnssd->services)) + (service->cb)(service, service->cb_data, flags); + + cupsMutexUnlock(&dnssd->mutex); +} + +// +// 'report_error()' - Report an error. +// + +static void +report_error(cups_dnssd_t *dnssd, // I - DNS-SD context + const char *message, // I - printf-style message string + ...) // I - Additional arguments as needed +{ + va_list ap; // Pointer to arguments + char buffer[8192]; // Formatted message + + + // Format the message... + va_start(ap, message); + vsnprintf(buffer, sizeof(buffer), message, ap); + va_end(ap); + + // Send it... + if (dnssd->cb) + (dnssd->cb)(dnssd->cb_data, buffer); + else + fprintf(stderr, "%s\n", buffer); +} + + +#ifdef __APPLE__ +// +// 'apple_sc_cb()' - Track host name changes. +// + +static void +apple_sc_cb(SCDynamicStoreRef sc, // I - Dynamic store context + CFArrayRef changed, // I - Changed keys + cups_dnssd_t *dnssd) // I - DNS-SD context +{ + cups_dnssd_flags_t flags = CUPS_DNSSD_FLAGS_NETWORK_CHANGE; + // Change flags + CFIndex i, // Looping var + count; // Number of values + + + (void)sc; + + // See if we had a local hostname change - anything else will be a network + // change... + for (i = 0, count = CFArrayGetCount(changed); i < count; i ++) + { + if (CFArrayGetValueAtIndex(changed, i) == kSCPropNetLocalHostName) + { + flags = CUPS_DNSSD_FLAGS_HOST_CHANGE; + break; + } + } + + // Record the change and do any callbacks as needed... + record_config_change(dnssd, flags); +} +#endif // __APPLE__ + + +#if _WIN32 + +#elif defined(HAVE_MDNSRESPONDER) // // 'mdns_browse_cb()' - Handle DNS-SD browse callbacks from mDNSResponder. // @@ -1136,11 +1505,14 @@ mdns_service_cb( cups_dnssd_service_t *service) // I - Service registration { (void)ref; + (void)name; + (void)regtype; + (void)domain; if (error != kDNSServiceErr_NoError) report_error(service->dnssd, "DNS-SD service registration error: %s", mdns_strerror(error)); - (service->cb)(service, service->cb_data, mdns_to_cups(flags, error), name, regtype, domain); + (service->cb)(service, service->cb_data, mdns_to_cups(flags, error)); } @@ -1279,30 +1651,177 @@ mdns_to_cups( return (cups_flags); } -#endif // HAVE_MDNSRESPONDER +#else // HAVE_AVAHI // -// 'report_error()' - Report an error. +// 'avahi_browse_cb()' - Handle browse callbacks from Avahi. // static void -report_error(cups_dnssd_t *dnssd, // I - DNS-SD context - const char *message, // I - printf-style message string - ...) // I - Additional arguments as needed +avahi_browse_cb( + AvahiServiceBrowser *browser, // I - Avahi browser + AvahiIfIndex if_index, // I - Interface index + AvahiProtocol protocol, // I - Network protocol (unused) + AvahiBrowserEvent event, // I - What happened + const char *name, // I - Service name + const char *type, // I - Service type + const char *domain, // I - Domain + AvahiLookupResultFlags flags, // I - Flags + cups_dnssd_browse_t *browse) // I - CUPS browse request { - va_list ap; // Pointer to arguments - char buffer[8192]; // Formatted message + cups_dnssd_flags_t cups_flags; // CUPS DNS-SD flags - // Format the message... - va_start(ap, message); - vsnprintf(buffer, sizeof(buffer), message, ap); - va_end(ap); + (void)protocol; + (void)flags; - // Send it... - if (dnssd->cb) - (dnssd->cb)(dnssd->cb_data, buffer); - else - fprintf(stderr, "%s\n", buffer); + switch (event) + { + case AVAHI_BROWSER_NEW : + cups_flags = CUPS_DNSSD_FLAGS_ADD; + break; + case AVAHI_BROWSE_DELETE : + cups_flags = CUPS_DNSSD_FLAGS_NONE; + break; + case AVAHI_BROWSE_ERROR : + cups_flags = CUPS_DNSSD_FLAGS_ERROR; + break; + + default : + // Other events don't get passed through... + return; + } + + (browse->cb)(browse, browse->cb_data, cups_flags, if_index, name, regtype, domain); +} + + +// +// 'avahi_client_cb()' - Client callback for Avahi. +// +// Called whenever the client or server state changes... +// + +static void +avahi_client_cb( + AvahiClient *c, // I - Client + AvahiClientState state, // I - Current state + cups_dnssd_t *dnssd) // I - DNS-SD context +{ + if (!c) + return; + + if (state == AVAHI_CLIENT_FAILURE) + { + if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) + report_error(dnssd, "Avahi server crashed."); + } + else if (state == AVAHI_CLIENT_S_RUNNING) + { + dnssd->name_changes ++; + } +} + + +// +// 'avahi_query_cb()' - Query callback for Avahi. +// + +static void +avahi_query_cb( + AvahiRecordBrowser *browser, // I - Browser + AvahiIfIndex if_index, // I - Interface index + AvahiProtocol protocol, // I - Network protocol (not used) + AvahiBrowserEvent event, // I - What happened + const char *fullName, // I - Full service name + uint16_t rrclass, // I - Record class (not used) + uint16_t rrtype, // I - Record type + const void *rdata, // I - Record data + size_t rdlen, // I - Size of record data + AvahiLookupResultFlags flags, // I - Flags + cups_dnssd_query_t *query) // I - Query request +{ + (void)browser; + (void)protocol; + (void)rrclass; + + if (error != kDNSServiceErr_NoError) + report_error(query->dnssd, "DNS-SD query error: %s", mdns_strerror(error)); + + (query->cb)(query, query->cb_data, event == AVAHI_RESOLVER_FOUND ? CUPS_DNSSD_FLAGS_NONE : CUPS_DNSSD_FLAGS_ERROR, if_index, name, rrtype, rdata, rdlen); } + + +// +// 'avahi_resolve_cb()' - Resolver callback for Avahi. +// + +static void +avahi_resolve_cb( + AvahiServiceResolver *resolver, // I - Service resolver + AvahiIfIndex if_index, // I - Interface index + AvahiProtocol protocol, // I - Network protocol (not used) + AvahiResolverEvent event, // I - What happened + const char *name, // I - Service name + const char *type, // I - Service type + const char *domain, // I - Domain + const char *host_name, // I - Host name + const AvahiAddress *address, // I - Address + uint16_t port, // I - Port number + AvahiStringList *txtrec, // I - TXT record + AvahiLookupResultFlags flags, // I - Flags + cups_dnssd_resolve_t *resolve) // I - Resolve request +{ + AvahiStringList *txtpair; // Current pair + size_t num_txt = 0; // Number of TXT key/value pairs + cups_option_t *txt = NULL; // TXT key/value pairs + char fullname[1024]; // Full service name + + + if (!resolver) + return; + + (void)resolver; + (void)protocol; + (void)address; + (void)flags; + + // Convert TXT key/value pairs into CUPS option array... + for (txtpair = txtrec; txtpair; txtpair = avahi_string_list_get_next(txtpair)) + { + char *key, *value; // Key and value + + avahi_string_list_get_pair(txtpair, &key, &value, NULL); + + num_txt = cupsAddOption(key, value, num_txt, txt); + + avahi_free(key); + avahi_free(value); + } + + // Create a full name for the service... + cupsDNSSDAssembleFullName(fullname, sizeof(fullname), name, type, domain); + + // Do the resolve callback and free the TXT record stuff... + (resolve->cb)(resolve, resolve->cb_data, event == AVAHI_RESOLVER_FOUND ? CUPS_DNSSD_FLAGS_NONE : CUPS_DNSSD_FLAGS_ERROR, if_index, fullname, host, ntohs(port), num_txt, txt); + + cupsFreeOptions(num_txt, txt); +} + + +// +// 'avahi_service_cb()' - Service callback for Avahi. +// + +static void +avahi_service_cb( + AvahiEntryGroup *srv, // I - Service + AvahiEntryGroupState state, // I - Registration state + cups_dnssd_service_t *service) // I - Service registration +{ + (void)srv; + + (service->cb)(service, service->cb_data, state == AVAHI_ENTRY_GROUP_COLLISION ? CUPS_DNSSD_FLAGS_COLLISION : CUPS_DNSSD_FLAGS_NONE); +} +#endif // _WIN32 diff --git a/cups/dnssd.h b/cups/dnssd.h index 5c07252ce..2012d1b8e 100644 --- a/cups/dnssd.h +++ b/cups/dnssd.h @@ -27,9 +27,12 @@ typedef struct _cups_dnssd_s cups_dnssd_t; // DNS-SD context enum cups_dnssd_flags_e // DNS-SD callback flag values { CUPS_DNSSD_FLAGS_NONE = 0, // No flags - CUPS_DNSSD_FLAGS_ADD = 1, // Added + CUPS_DNSSD_FLAGS_ADD = 1, // Added (removed if not set) CUPS_DNSSD_FLAGS_ERROR = 2, // Error occurred - CUPS_DNSSD_FLAGS_MORE = 4 // More coming + CUPS_DNSSD_FLAGS_COLLISION = 4, // Collision occurred + CUPS_DNSSD_FLAGS_HOST_CHANGE = 8, // Host name changed + CUPS_DNSSD_FLAGS_NETWORK_CHANGE = 16, // Network connection changed + CUPS_DNSSD_FLAGS_MORE = 128 // More coming }; typedef unsigned cups_dnssd_flags_t; // DNS-SD callback flag bitmask @@ -76,7 +79,7 @@ typedef void (*cups_dnssd_resolve_cb_t)(cups_dnssd_resolve_t *res, void *cb_data typedef struct _cups_dnssd_service_s cups_dnssd_service_t; // DNS service registration -typedef void (*cups_dnssd_service_cb_t)(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags, const char *name, const char *regtype, const char *domain); +typedef void (*cups_dnssd_service_cb_t)(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags); // DNS-SD service registration callback @@ -85,6 +88,8 @@ typedef void (*cups_dnssd_service_cb_t)(cups_dnssd_service_t *service, void *cb_ // extern void cupsDNSSDDelete(cups_dnssd_t *dnssd) _CUPS_PUBLIC; +extern size_t cupsDNSSDGetConfigChanges(cups_dnssd_t *dnssd) _CUPS_PUBLIC; +extern const char *cupsDNSSDGetHostName(cups_dnssd_t *dnssd, char *buffer, size_t bufsize) _CUPS_PUBLIC; extern cups_dnssd_t *cupsDNSSDNew(cups_dnssd_error_cb_t error_cb, void *cb_data) _CUPS_PUBLIC; extern void cupsDNSSDBrowseDelete(cups_dnssd_browse_t *browser) _CUPS_PUBLIC; @@ -102,6 +107,7 @@ extern cups_dnssd_resolve_t *cupsDNSSDResolveNew(cups_dnssd_t *dnssd, uint32_t i extern bool cupsDNSSDServiceAdd(cups_dnssd_service_t *service, uint32_t if_index, const char *types, const char *domain, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt) _CUPS_PUBLIC; extern void cupsDNSSDServiceDelete(cups_dnssd_service_t *service) _CUPS_PUBLIC; extern cups_dnssd_t *cupsDNSSDServiceGetContext(cups_dnssd_service_t *service) _CUPS_PUBLIC; +extern const char *cupsDNSSDServiceGetName(cups_dnssd_service_t *service) _CUPS_PUBLIC; extern cups_dnssd_service_t *cupsDNSSDServiceNew(cups_dnssd_t *dnssd, const char *name, cups_dnssd_service_cb_t cb, void *cb_data) _CUPS_PUBLIC; extern bool cupsDNSSDServicePublish(cups_dnssd_service_t *service) _CUPS_PUBLIC; extern bool cupsDNSSDServiceSetLocation(cups_dnssd_service_t *service, const char *geo_uri) _CUPS_PUBLIC; diff --git a/cups/testdnssd.c b/cups/testdnssd.c index 265a716f2..adffdc28a 100644 --- a/cups/testdnssd.c +++ b/cups/testdnssd.c @@ -36,7 +36,7 @@ static void browse_cb(cups_dnssd_browse_t *browse, void *cb_data, cups_dnssd_fla static void error_cb(void *cb_data, const char *message); static void query_cb(cups_dnssd_query_t *query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen); static void resolve_cb(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt); -static void service_cb(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags, const char *name, const char *regtype, const char *domain); +static void service_cb(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags); static void usage(const char *arg); @@ -267,6 +267,8 @@ query_cb( const unsigned char *qptr; // Pointer into record data + (void)query; + snprintf(message, sizeof(message), "Q flags=%02X if_index=%u fullname=\"%s\" rrtype=%u qlen=%u qdata=<", flags, if_index, fullname, rrtype, qlen); for (mptr = message + strlen(message), i = 0, qptr = (const unsigned char *)qdata; i < qlen; i ++, mptr += strlen(mptr), qptr ++) snprintf(mptr, sizeof(message) - (size_t)(mptr - message), "%02X", *qptr); @@ -301,12 +303,14 @@ resolve_cb( { testdata_t *data = (testdata_t *)cb_data; // Test data - int i; // Looping var + size_t i; // Looping var char message[2048], // Message string *mptr; // Pointer into message string const char *prefix = " txt="; // Prefix string + (void)res; + snprintf(message, sizeof(message), "R flags=%02X if_index=%u fullname=\"%s\" host=\"%s\" port=%u num_txt=%u", flags, if_index, fullname, host, port, (unsigned)num_txt); for (mptr = message + strlen(message), i = 0; i < num_txt; i ++, mptr += strlen(mptr)) { @@ -329,17 +333,14 @@ static void service_cb( cups_dnssd_service_t *service, // I - Service registration void *cb_data, // I - Callback data - cups_dnssd_flags_t flags, // I - Flags - const char *name, // I - Service name - const char *regtype, // I - Registration type - const char *domain) // I - Domain name + cups_dnssd_flags_t flags) // I - Flags { testdata_t *data = (testdata_t *)cb_data; // Test data char message[1024]; // Message string - snprintf(message, sizeof(message), "S flags=%02X name=\"%s\" regtype=\"%s\" domain=\"%s\"", flags, name, regtype, domain); + snprintf(message, sizeof(message), "S flags=%02X name=\"%s\"", flags, cupsDNSSDServiceGetName(service)); cupsMutexLock(&data->mutex); cupsArrayAdd(data->messages, message); diff --git a/xcode/libcups.xcodeproj/project.pbxproj b/xcode/libcups.xcodeproj/project.pbxproj index d3d5c26a0..111a93919 100644 --- a/xcode/libcups.xcodeproj/project.pbxproj +++ b/xcode/libcups.xcodeproj/project.pbxproj @@ -208,6 +208,7 @@ 2794E90528AFFC2400BEDC04 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC5C1926750C000F61D3 /* libz.dylib */; }; 2794E90628AFFC2400BEDC04 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC5D1926750C000F61D3 /* Security.framework */; }; 2794E90F28AFFC6600BEDC04 /* testdnssd.c in Sources */ = {isa = PBXBuildFile; fileRef = 2794E90E28AFFC6600BEDC04 /* testdnssd.c */; }; + 2794E91028B2E20A00BEDC04 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC5E1926750C000F61D3 /* SystemConfiguration.framework */; }; 279AE6F52395B80F004DD600 /* libpam.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 279AE6F42395B80F004DD600 /* libpam.tbd */; }; 27A8096128A9B9D500B20BC8 /* dnssd.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A8095F28A9B9D500B20BC8 /* dnssd.h */; }; 27A8096228A9B9D500B20BC8 /* dnssd.h in Headers */ = {isa = PBXBuildFile; fileRef = 27A8095F28A9B9D500B20BC8 /* dnssd.h */; }; @@ -1281,6 +1282,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 2794E91028B2E20A00BEDC04 /* SystemConfiguration.framework in Frameworks */, 2794E8FF28AFFC2400BEDC04 /* libcrypto.a in Frameworks */, 2794E90028AFFC2400BEDC04 /* libssl.a in Frameworks */, 2794E90128AFFC2400BEDC04 /* libcups_static.a in Frameworks */, From 90086e71582f9e258b5cf108b99d1686d7a2902f Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Mon, 22 Aug 2022 09:52:41 -0400 Subject: [PATCH 12/19] Fix Avahi builds, still need to address threaded poll bug. --- cups/dnssd.c | 51 +++++++++++++++++++++++++----------------------- cups/dnssd.h | 4 ++-- cups/testdnssd.c | 6 +++--- 3 files changed, 32 insertions(+), 29 deletions(-) diff --git a/cups/dnssd.c b/cups/dnssd.c index 08631bdba..f60e5afaa 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -1,5 +1,5 @@ // -// DNS-SD API definitions for CUPS. +// DNS-SD API functions for CUPS. // // Copyright © 2022 by OpenPrinting. // @@ -28,9 +28,11 @@ # include # include # include +# include # include # include # include +# define AVAHI_DNS_TYPE_LOC 29 // Per RFC 1876 struct _cups_dns_srv_s // DNS SRV record { @@ -117,6 +119,7 @@ struct _cups_dnssd_service_s // DNS-SD service registration { cups_dnssd_t *dnssd; // DNS-SD context char *name; // Service name + uint32_t if_index; // Interface index cups_dnssd_service_cb_t cb; // Service callback void *cb_data; // Service callback data unsigned char loc[16]; // LOC record data @@ -573,7 +576,7 @@ cupsDNSSDBrowseNew( #else // HAVE_AVAHI avahi_threaded_poll_lock(dnssd->monitor); - browse->browser = avahi_service_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, types, NULL, 0, avahi_browse_cb, browse); + browse->browser = avahi_service_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, types, NULL, 0, (AvahiServiceBrowserCallback)avahi_browse_cb, browse); avahi_threaded_poll_unlock(dnssd->monitor); if (!browse->browser) @@ -831,7 +834,6 @@ cupsDNSSDResolveNew( bool // O - `true` on success, `false` on failure cupsDNSSDServiceAdd( cups_dnssd_service_t *service, // I - Service - uint32_t if_index, // I - Interface index or `CUPS_DNSSD_IF_ANY` or `CUPS_DNSSD_IF_LOCAL` const char *types, // I - Service types const char *domain, // I - Domain name or `NULL` for default const char *host, // I - Host name or `NULL` for default @@ -873,7 +875,7 @@ cupsDNSSDServiceAdd( } service->refs[service->num_refs] = service->dnssd->ref; - if ((error = DNSServiceRegister(service->refs + service->num_refs, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, if_index, service->name, types, domain, host, htons(port), txtptr ? TXTRecordGetLength(txtptr) : 0, txtptr ? TXTRecordGetBytesPtr(txtptr) : NULL, (DNSServiceRegisterReply)mdns_service_cb, service)) != kDNSServiceErr_NoError) + if ((error = DNSServiceRegister(service->refs + service->num_refs, kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, service->if_index, service->name, types, domain, host, htons(port), txtptr ? TXTRecordGetLength(txtptr) : 0, txtptr ? TXTRecordGetBytesPtr(txtptr) : NULL, (DNSServiceRegisterReply)mdns_service_cb, service)) != kDNSServiceErr_NoError) { if (txtptr) TXTRecordDeallocate(txtptr); @@ -920,7 +922,7 @@ cupsDNSSDServiceAdd( // Add the service entry... avahi_threaded_poll_lock(service->dnssd->monitor); - if ((error = avahi_entry_group_add_service_strlst(service->group, if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, regtype, domain, host, port, txt)) < 0) + if ((error = avahi_entry_group_add_service_strlst(service->group, service->if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, regtype, domain, host, port, txtrec)) < 0) { report_error(service->dnssd, "Unable to register '%s.%s': %s", service->name, regtype, avahi_strerror(error)); ret = false; @@ -938,7 +940,7 @@ cupsDNSSDServiceAdd( end = start + strlen(start); snprintf(subtype, sizeof(subtype), "%s._sub.%s", start, regtype); - if ((error = avahi_entry_group_add_service_subtype(service->group, if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, regtype, domain, subtype)) < 0) + if ((error = avahi_entry_group_add_service_subtype(service->group, service->if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, regtype, domain, subtype)) < 0) { report_error(service->dnssd, "Unable to register '%s.%s': %s", service->name, subtype, avahi_strerror(error)); ret = false; @@ -950,8 +952,8 @@ cupsDNSSDServiceAdd( avahi_threaded_poll_unlock(service->dnssd->monitor); - if (txt) - avahi_string_list_free(txt); + if (txtrec) + avahi_string_list_free(txtrec); #endif // _WIN32 done: @@ -1010,6 +1012,7 @@ cupsDNSSDServiceGetName( cups_dnssd_service_t * // O - Service or `NULL` on error cupsDNSSDServiceNew( cups_dnssd_t *dnssd, // I - DNS-SD context + uint32_t if_index, // I - Interface index or `CUPS_DNSSD_IF_ANY` or `CUPS_DNSSD_IF_LOCAL` const char *name, // I - Name of service cups_dnssd_service_cb_t cb, // I - Service registration callback function void *cb_data) // I - Service registration callback data @@ -1025,10 +1028,11 @@ cupsDNSSDServiceNew( if ((service = (cups_dnssd_service_t *)calloc(1, sizeof(cups_dnssd_service_t))) == NULL) return (NULL); - service->dnssd = dnssd; - service->cb = cb; - service->cb_data = cb_data; - service->name = strdup(name); + service->dnssd = dnssd; + service->cb = cb; + service->cb_data = cb_data; + service->name = strdup(name); + service->if_index = if_index; #if _WIN32 #elif defined(HAVE_MDNSRESPONDER) @@ -1186,9 +1190,11 @@ cupsDNSSDServiceSetLocation( #else // HAVE_AVAHI // Add LOC record now... + int error; // Error code + avahi_threaded_poll_lock(service->dnssd->monitor); - if ((error = avahi_entry_group_add_record(service->group, if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_LOC, /*ttl*/75 * 60, service->loc, sizeof(service->loc))) < 0) + if ((error = avahi_entry_group_add_record(service->group, service->if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_LOC, /*ttl*/75 * 60, service->loc, sizeof(service->loc))) < 0) { report_error(service->dnssd, "Unable to register LOC record for '%s': %s", service->name, avahi_strerror(error)); ret = false; @@ -1681,10 +1687,10 @@ avahi_browse_cb( case AVAHI_BROWSER_NEW : cups_flags = CUPS_DNSSD_FLAGS_ADD; break; - case AVAHI_BROWSE_DELETE : + case AVAHI_BROWSER_REMOVE : cups_flags = CUPS_DNSSD_FLAGS_NONE; break; - case AVAHI_BROWSE_ERROR : + case AVAHI_BROWSER_FAILURE : cups_flags = CUPS_DNSSD_FLAGS_ERROR; break; @@ -1693,7 +1699,7 @@ avahi_browse_cb( return; } - (browse->cb)(browse, browse->cb_data, cups_flags, if_index, name, regtype, domain); + (browse->cb)(browse, browse->cb_data, cups_flags, if_index, name, type, domain); } @@ -1719,7 +1725,7 @@ avahi_client_cb( } else if (state == AVAHI_CLIENT_S_RUNNING) { - dnssd->name_changes ++; + record_config_change(dnssd, CUPS_DNSSD_FLAGS_HOST_CHANGE); } } @@ -1734,7 +1740,7 @@ avahi_query_cb( AvahiIfIndex if_index, // I - Interface index AvahiProtocol protocol, // I - Network protocol (not used) AvahiBrowserEvent event, // I - What happened - const char *fullName, // I - Full service name + const char *fullname, // I - Full service name uint16_t rrclass, // I - Record class (not used) uint16_t rrtype, // I - Record type const void *rdata, // I - Record data @@ -1746,10 +1752,7 @@ avahi_query_cb( (void)protocol; (void)rrclass; - if (error != kDNSServiceErr_NoError) - report_error(query->dnssd, "DNS-SD query error: %s", mdns_strerror(error)); - - (query->cb)(query, query->cb_data, event == AVAHI_RESOLVER_FOUND ? CUPS_DNSSD_FLAGS_NONE : CUPS_DNSSD_FLAGS_ERROR, if_index, name, rrtype, rdata, rdlen); + (query->cb)(query, query->cb_data, event == AVAHI_BROWSER_NEW ? CUPS_DNSSD_FLAGS_NONE : CUPS_DNSSD_FLAGS_ERROR, if_index, fullname, rrtype, rdata, rdlen); } @@ -1766,7 +1769,7 @@ avahi_resolve_cb( const char *name, // I - Service name const char *type, // I - Service type const char *domain, // I - Domain - const char *host_name, // I - Host name + const char *host, // I - Host name const AvahiAddress *address, // I - Address uint16_t port, // I - Port number AvahiStringList *txtrec, // I - TXT record @@ -1794,7 +1797,7 @@ avahi_resolve_cb( avahi_string_list_get_pair(txtpair, &key, &value, NULL); - num_txt = cupsAddOption(key, value, num_txt, txt); + num_txt = cupsAddOption(key, value, num_txt, &txt); avahi_free(key); avahi_free(value); diff --git a/cups/dnssd.h b/cups/dnssd.h index 2012d1b8e..b2da0ee93 100644 --- a/cups/dnssd.h +++ b/cups/dnssd.h @@ -104,11 +104,11 @@ extern void cupsDNSSDResolveDelete(cups_dnssd_resolve_t *res) _CUPS_PUBLIC; extern cups_dnssd_t *cupsDNSSDResolveGetContext(cups_dnssd_resolve_t *res) _CUPS_PUBLIC; extern cups_dnssd_resolve_t *cupsDNSSDResolveNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *name, const char *type, const char *domain, cups_dnssd_resolve_cb_t resolve_cb, void *cb_data) _CUPS_PUBLIC; -extern bool cupsDNSSDServiceAdd(cups_dnssd_service_t *service, uint32_t if_index, const char *types, const char *domain, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt) _CUPS_PUBLIC; +extern bool cupsDNSSDServiceAdd(cups_dnssd_service_t *service, const char *types, const char *domain, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt) _CUPS_PUBLIC; extern void cupsDNSSDServiceDelete(cups_dnssd_service_t *service) _CUPS_PUBLIC; extern cups_dnssd_t *cupsDNSSDServiceGetContext(cups_dnssd_service_t *service) _CUPS_PUBLIC; extern const char *cupsDNSSDServiceGetName(cups_dnssd_service_t *service) _CUPS_PUBLIC; -extern cups_dnssd_service_t *cupsDNSSDServiceNew(cups_dnssd_t *dnssd, const char *name, cups_dnssd_service_cb_t cb, void *cb_data) _CUPS_PUBLIC; +extern cups_dnssd_service_t *cupsDNSSDServiceNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *name, cups_dnssd_service_cb_t cb, void *cb_data) _CUPS_PUBLIC; extern bool cupsDNSSDServicePublish(cups_dnssd_service_t *service) _CUPS_PUBLIC; extern bool cupsDNSSDServiceSetLocation(cups_dnssd_service_t *service, const char *geo_uri) _CUPS_PUBLIC; diff --git a/cups/testdnssd.c b/cups/testdnssd.c index adffdc28a..5998e6067 100644 --- a/cups/testdnssd.c +++ b/cups/testdnssd.c @@ -102,7 +102,7 @@ main(int argc, // I - Number of command-line arguments testEnd(cupsDNSSDBrowseGetContext(browse) == dnssd); testBegin("cupsDNSSDServiceNew(Test Printer)"); - if ((service = cupsDNSSDServiceNew(dnssd, "Test Printer", service_cb, &testdata)) != NULL) + if ((service = cupsDNSSDServiceNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "Test Printer", service_cb, &testdata)) != NULL) { testEnd(true); } @@ -115,7 +115,7 @@ main(int argc, // I - Number of command-line arguments num_txt = cupsAddOption("rp", "ipp/print", 0, &txt); testBegin("cupsDNSSDServiceAdd(_http._tcp)"); - if (cupsDNSSDServiceAdd(service, CUPS_DNSSD_IF_INDEX_ANY, "_http._tcp,_printer", NULL, NULL, 631, 0, NULL)) + if (cupsDNSSDServiceAdd(service, "_http._tcp,_printer", /*host*/NULL, /*domain*/NULL, 631, /*num_txt*/0, /*txt*/NULL)) { testEnd(true); } @@ -126,7 +126,7 @@ main(int argc, // I - Number of command-line arguments } testBegin("cupsDNSSDServiceAdd(_ipp._tcp)"); - if (cupsDNSSDServiceAdd(service, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp,_print", NULL, NULL, 631, num_txt, txt)) + if (cupsDNSSDServiceAdd(service, "_ipp._tcp,_print", /*host*/NULL, /*domain*/NULL, 631, num_txt, txt)) { testEnd(true); } From 570fd2988153fc45b5c6307e8cef8f47603d936a Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Tue, 23 Aug 2022 20:31:24 -0400 Subject: [PATCH 13/19] Test using AvahiSimplePoll instead of AvahiThreadedPoll. --- cups/dnssd.c | 97 +++++++++++++++++++++++++++--------------------- cups/testdnssd.c | 1 + 2 files changed, 56 insertions(+), 42 deletions(-) diff --git a/cups/dnssd.c b/cups/dnssd.c index f60e5afaa..76e0fb223 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -31,14 +31,9 @@ # include # include # include -# include +//# include +# include # define AVAHI_DNS_TYPE_LOC 29 // Per RFC 1876 - -struct _cups_dns_srv_s // DNS SRV record -{ - AvahiEntryGroup *srv; // SRV record - AvahiStringList *txt; // TXT record -}; #endif // _WIN32 @@ -69,7 +64,9 @@ struct _cups_dnssd_s // DNS-SD context #else // HAVE_AVAHI AvahiClient *client; // Avahi client connection - AvahiThreadedPoll *monitor; // Monitoring thread +// AvahiThreadedPoll *poll; // Avahi poll class + AvahiSimplePoll *poll; // Avahi poll class + cups_thread_t monitor; // Monitoring thread #endif // _WIN32 }; @@ -165,6 +162,7 @@ static cups_dnssd_flags_t mdns_to_cups(DNSServiceFlags flags, DNSServiceErrorTyp #else // HAVE_AVAHI static void avahi_browse_cb(AvahiServiceBrowser *browser, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, cups_dnssd_browse_t *browse); static void avahi_client_cb(AvahiClient *c, AvahiClientState state, cups_dnssd_t *dnssd); +static void *avahi_monitor(cups_dnssd_t *dnssd); static void avahi_query_cb(AvahiRecordBrowser *browser, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiBrowserEvent event, const char *fullName, uint16_t rrclass, uint16_t rrtype, const void *rdata, size_t rdlen, AvahiLookupResultFlags flags, cups_dnssd_query_t *query); static void avahi_resolve_cb(AvahiServiceResolver *resolver, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txtrec, AvahiLookupResultFlags flags, cups_dnssd_resolve_t *resolve); static void avahi_service_cb(AvahiEntryGroup *srv, AvahiEntryGroupState state, cups_dnssd_service_t *service); @@ -308,13 +306,13 @@ cupsDNSSDDelete(cups_dnssd_t *dnssd) // I - DNS-SD context cupsArrayDelete(dnssd->services); #if _WIN32 - cupsThreadCancel(&dnssd->monitor); - DNSServiceRefDeallocate(dnssd->ref); - #elif defined(HAVE_MDNSRESPONDER) + cupsThreadCancel(dnssd->monitor); + DNSServiceRefDeallocate(dnssd->ref); #else // HAVE_AVAHI - + cupsThreadCancel(dnssd->monitor); + avahi_simple_poll_free(dnssd->poll); #endif // _WIN32 cupsMutexUnlock(&dnssd->mutex); @@ -460,33 +458,35 @@ cupsDNSSDNew( #else // HAVE_AVAHI int error; // Error code - if ((dnssd->monitor = avahi_threaded_poll_new()) == NULL) + if ((dnssd->poll = avahi_simple_poll_new()) == NULL) { // Unable to create the background thread... - report_error(dnssd, "Unable to initialize DNS-SD thread: %s", strerror(errno)); + report_error(dnssd, "Unable to initialize DNS-SD: %s", strerror(errno)); cupsDNSSDDelete(dnssd); return (NULL); } - else if ((dnssd->client = avahi_client_new(avahi_threaded_poll_get(dnssd->monitor), AVAHI_CLIENT_NO_FAIL, (AvahiClientCallback)avahi_client_cb, dnssd, &error)) == NULL) + else if ((dnssd->client = avahi_client_new(avahi_simple_poll_get(dnssd->poll), AVAHI_CLIENT_NO_FAIL, (AvahiClientCallback)avahi_client_cb, dnssd, &error)) == NULL) { // Unable to create the client... report_error(dnssd, "Unable to initialize DNS-SD: %s", avahi_strerror(error)); - avahi_threaded_poll_free(dnssd->monitor); + avahi_simple_poll_free(dnssd->poll); cupsDNSSDDelete(dnssd); return (NULL); } - else + else if ((dnssd->monitor = cupsThreadCreate((void *(*)(void *))avahi_monitor, dnssd)) == 0) { - // Start the background thread... - avahi_threaded_poll_start(dnssd->monitor); + report_error(dnssd, "Unable to create DNS-SD thread: %s", strerror(errno)); + cupsDNSSDDelete(dnssd); + return (NULL); } + + cupsThreadDetach(dnssd->monitor); #endif // _WIN32 return (dnssd); } - // // 'cupsDNSSDBrowseDelete()' - Cancel and delete a browse request. // @@ -575,9 +575,9 @@ cupsDNSSDBrowseNew( } #else // HAVE_AVAHI - avahi_threaded_poll_lock(dnssd->monitor); +// avahi_threaded_poll_lock(dnssd->monitor); browse->browser = avahi_service_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, types, NULL, 0, (AvahiServiceBrowserCallback)avahi_browse_cb, browse); - avahi_threaded_poll_unlock(dnssd->monitor); + //avahi_threaded_poll_unlock(dnssd->monitor); if (!browse->browser) { @@ -691,9 +691,9 @@ cupsDNSSDQueryNew( } #else // HAVE_AVAHI - avahi_threaded_poll_lock(dnssd->monitor); + //avahi_threaded_poll_lock(dnssd->monitor); query->browser = avahi_record_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, fullname, AVAHI_DNS_CLASS_IN, rrtype, 0, (AvahiRecordBrowserCallback)avahi_query_cb, query); - avahi_threaded_poll_unlock(dnssd->monitor); + //avahi_threaded_poll_unlock(dnssd->monitor); if (!query->browser) { @@ -804,9 +804,9 @@ cupsDNSSDResolveNew( } #else // HAVE_AVAHI - avahi_threaded_poll_lock(dnssd->monitor); + //avahi_threaded_poll_lock(dnssd->monitor); resolve->resolver = avahi_service_resolver_new(dnssd->client, if_index, AVAHI_PROTO_UNSPEC, name, type, domain, AVAHI_PROTO_UNSPEC, /*flags*/0, (AvahiServiceResolverCallback)avahi_resolve_cb, resolve); - avahi_threaded_poll_unlock(dnssd->monitor); + //avahi_threaded_poll_unlock(dnssd->monitor); if (!resolve->resolver) { @@ -920,7 +920,7 @@ cupsDNSSDServiceAdd( *subtypes++ = '\0'; // Add the service entry... - avahi_threaded_poll_lock(service->dnssd->monitor); + //avahi_threaded_poll_lock(service->dnssd->monitor); if ((error = avahi_entry_group_add_service_strlst(service->group, service->if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, regtype, domain, host, port, txtrec)) < 0) { @@ -950,7 +950,7 @@ cupsDNSSDServiceAdd( free(regtype); - avahi_threaded_poll_unlock(service->dnssd->monitor); + //avahi_threaded_poll_unlock(service->dnssd->monitor); if (txtrec) avahi_string_list_free(txtrec); @@ -1037,9 +1037,9 @@ cupsDNSSDServiceNew( #if _WIN32 #elif defined(HAVE_MDNSRESPONDER) #else // HAVE_AVAHI - avahi_threaded_poll_lock(dnssd->monitor); + //avahi_threaded_poll_lock(dnssd->monitor); service->group = avahi_entry_group_new(dnssd->client, (AvahiEntryGroupCallback)avahi_service_cb, service); - avahi_threaded_poll_unlock(dnssd->monitor); + //avahi_threaded_poll_unlock(dnssd->monitor); if (!service->group) { @@ -1090,9 +1090,9 @@ cupsDNSSDServicePublish( #elif defined(HAVE_MDNSRESPONDER) (void)service; #else // HAVE_AVAHI - avahi_threaded_poll_lock(service->dnssd->monitor); + //avahi_threaded_poll_lock(service->dnssd->monitor); avahi_entry_group_commit(service->group); - avahi_threaded_poll_unlock(service->dnssd->monitor); + //avahi_threaded_poll_unlock(service->dnssd->monitor); #endif // _WIN32 return (ret); @@ -1192,7 +1192,7 @@ cupsDNSSDServiceSetLocation( // Add LOC record now... int error; // Error code - avahi_threaded_poll_lock(service->dnssd->monitor); + //avahi_threaded_poll_lock(service->dnssd->monitor); if ((error = avahi_entry_group_add_record(service->group, service->if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_LOC, /*ttl*/75 * 60, service->loc, sizeof(service->loc))) < 0) { @@ -1200,7 +1200,7 @@ cupsDNSSDServiceSetLocation( ret = false; } - avahi_threaded_poll_unlock(service->dnssd->monitor); + //avahi_threaded_poll_unlock(service->dnssd->monitor); #endif // _WIN32 return (ret); @@ -1220,9 +1220,9 @@ delete_browse( DNSServiceRefDeallocate(browse->ref); #else // HAVE_AVAHI - avahi_threaded_poll_lock(browse->dnssd->monitor); + //avahi_threaded_poll_lock(browse->dnssd->monitor); avahi_service_browser_free(browse->browser); - avahi_threaded_poll_unlock(browse->dnssd->monitor); + //avahi_threaded_poll_unlock(browse->dnssd->monitor); #endif // _WIN32 free(browse); @@ -1243,9 +1243,9 @@ delete_query( DNSServiceRefDeallocate(query->ref); #else // HAVE_AVAHI - avahi_threaded_poll_lock(query->dnssd->monitor); + //avahi_threaded_poll_lock(query->dnssd->monitor); avahi_record_browser_free(query->browser); - avahi_threaded_poll_unlock(query->dnssd->monitor); + //avahi_threaded_poll_unlock(query->dnssd->monitor); #endif // _WIN32 } @@ -1265,9 +1265,9 @@ delete_resolve( DNSServiceRefDeallocate(resolve->ref); #else // HAVE_AVAHI - avahi_threaded_poll_lock(resolve->dnssd->monitor); + //avahi_threaded_poll_lock(resolve->dnssd->monitor); avahi_service_resolver_free(resolve->resolver); - avahi_threaded_poll_unlock(resolve->dnssd->monitor); + //avahi_threaded_poll_unlock(resolve->dnssd->monitor); #endif // _WIN32 } @@ -1291,9 +1291,9 @@ delete_service( DNSServiceRefDeallocate(service->refs[i]); #else // HAVE_AVAHI - avahi_threaded_poll_lock(service->dnssd->monitor); + //avahi_threaded_poll_lock(service->dnssd->monitor); avahi_entry_group_free(service->group); - avahi_threaded_poll_unlock(service->dnssd->monitor); + //avahi_threaded_poll_unlock(service->dnssd->monitor); #endif // _WIN32 free(service); @@ -1730,6 +1730,19 @@ avahi_client_cb( } +// +// 'avahi_monitor()' - Background thread for Avahi. +// + +static void * // O - Exit status +avahi_monitor(cups_dnssd_t *dnssd) // I - DNS-SD context +{ + avahi_simple_poll_loop(dnssd->poll); + fputs("avahi_monitor: DONE\n", stderr); + return (NULL); +} + + // // 'avahi_query_cb()' - Query callback for Avahi. // diff --git a/cups/testdnssd.c b/cups/testdnssd.c index 5998e6067..ecf6deeb6 100644 --- a/cups/testdnssd.c +++ b/cups/testdnssd.c @@ -165,6 +165,7 @@ main(int argc, // I - Number of command-line arguments if (testdata.service_count != 0 && testdata.browse_count != 0 && testdata.resolve_count != 0) break; + testProgress(); sleep(1); } From 4330455b3f9c70439bd94bcef79d44da4cb1026f Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Wed, 24 Aug 2022 18:03:01 -0400 Subject: [PATCH 14/19] Update documentation for DNS-SD API. --- CHANGES.md | 1 + cups/dnssd.c | 245 ++++++++++++++++---- cups/dnssd.h | 5 +- doc/cupspm.epub | Bin 221671 -> 225830 bytes doc/cupspm.html | 580 ++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 780 insertions(+), 51 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 0b03ea2bc..b2a600a8f 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -19,6 +19,7 @@ libcups v3.0b1 (Month DD, YYYY) - Added `ippFile` API for working with IPP data files as used by `ipptool`, `ippexeprinter`, and other tools (Issue #14) - Added a roll to the default color ippeveprinter printer. +- Added new DNS-SD API (Issue #19) - Updated the CUPS API for consistency. - Removed all obsolete/deprecated CUPS 2.x APIs. - Removed (obsolete) Kerberos support. diff --git a/cups/dnssd.c b/cups/dnssd.c index 76e0fb223..575779750 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -31,7 +31,6 @@ # include # include # include -//# include # include # define AVAHI_DNS_TYPE_LOC 29 // Per RFC 1876 #endif // _WIN32 @@ -64,7 +63,6 @@ struct _cups_dnssd_s // DNS-SD context #else // HAVE_AVAHI AvahiClient *client; // Avahi client connection -// AvahiThreadedPoll *poll; // Avahi poll class AvahiSimplePoll *poll; // Avahi poll class cups_thread_t monitor; // Monitoring thread #endif // _WIN32 @@ -173,6 +171,10 @@ static void avahi_service_cb(AvahiEntryGroup *srv, AvahiEntryGroupState state, // 'cupsDNSSDAssembleFullName()' - Create a full service name from the instance // name, registration type, and domain. // +// This function combines an instance name ("Example Name"), registration type +// ("_ipp._tcp"), and domain ("local.") to create a properly escaped full +// service name ("Example\032Name._ipp._tcp.local."). +// bool // O - `true` on success, `false` on failure cupsDNSSDAssembleFullName( @@ -264,6 +266,10 @@ cupsDNSSDDecodeTXT( // 'cupsDNSSDSeparateFullName()' - Separate a full service name into an instance // name, registration type, and domain. // +// This function separates a full service name such as +// "Example\032Name._ipp._tcp.local.") into its instance name ("Example Name"), +// registration type ("_ipp._tcp"), and domain ("local."). +// bool // O - `true` on success, `false` on error cupsDNSSDSeparateFullName( @@ -275,16 +281,105 @@ cupsDNSSDSeparateFullName( char *domain, // I - Domain name buffer size_t domainsize) // I - Size of domain name buffer { - // TODO: Implement cupsDNSSDSeparateFullName - (void)fullname; - (void)name; - (void)namesize; - (void)type; - (void)typesize; - (void)domain; - (void)domainsize; + // Range check input.. + if (!fullname || !name || !namesize || type || !typesize || !domain || !domainsize) + { + if (name) + *name = '\0'; + if (type) + *type = '\0'; + if (domain) + *domain = '\0'; - return (false); + return (false); + } + +#if _WIN32 || defined(HAVE_MDNSRESPONDER) + bool ret = true; // Return value + char *ptr, // Pointer into name/type/domain + *end; // Pointer to end of name/type/domain + + // Get the service name... + for (ptr = name, end = name + namesize - 1; *fullname; fullname ++) + { + if (*fullname == '.') + { + // Service type separator... + break; + } + else if (*fullname == '\\' && isdigit(fullname[1] & 255) && isdigit(fullname[2] & 255) && isdigit(fullname[3] & 255)) + { + // Escaped character + if (ptr < end) + *ptr++ = (fullname[1] - '0') * 100 + (fullname[2] - '0') * 10 + fullname[3] - '0'; + else + ret = false; + + fullname += 3; + } + else if (ptr < end) + *ptr++ = *fullname; + else + ret = false; + } + *ptr = '\0'; + + if (*fullname) + fullname ++; + + // Get the type... + for (ptr = type, end = type + typesize - 1; *fullname; fullname ++) + { + if (*fullname == '.' && fullname[1] != '_') + { + // Service type separator... + break; + } + else if (*fullname == '\\' && isdigit(fullname[1] & 255) && isdigit(fullname[2] & 255) && isdigit(fullname[3] & 255)) + { + // Escaped character + if (ptr < end) + *ptr++ = (fullname[1] - '0') * 100 + (fullname[2] - '0') * 10 + fullname[3] - '0'; + else + ret = false; + + fullname += 3; + } + else if (ptr < end) + *ptr++ = *fullname; + else + ret = false; + } + *ptr = '\0'; + + if (*fullname) + fullname ++; + + // Get the domain... + for (ptr = domain, end = domain + domainsize - 1; *fullname; fullname ++) + { + if (*fullname == '\\' && isdigit(fullname[1] & 255) && isdigit(fullname[2] & 255) && isdigit(fullname[3] & 255)) + { + // Escaped character + if (ptr < end) + *ptr++ = (fullname[1] - '0') * 100 + (fullname[2] - '0') * 10 + fullname[3] - '0'; + else + ret = false; + + fullname += 3; + } + else if (ptr < end) + *ptr++ = *fullname; + else + ret = false; + } + *ptr = '\0'; + + return (ret); + +#else // HAVE_AVAHI + return (!avahi_service_name_split(fullname, name, namesize, type, typesize, domain, domainsize)); +#endif // _WIN32 || HAVE_MDNSRESPONDER } @@ -375,9 +470,10 @@ cupsDNSSDGetHostName( // -// 'cupsDNSSDGetConfigChanges()' - Get the number of host name/network configuration changes seen. +// 'cupsDNSSDGetConfigChanges()' - Get the number of host name/network +// configuration changes seen. // -// This function returns the numebr of host name or network configuration +// This function returns the number of host name or network configuration // changes that have been seen since the context was created. The value can be // used to track when local services need to be updated. Registered services // will also get a callback with the `CUPS_DNSSD_FLAGS_HOST_CHANGE` bit set in @@ -397,7 +493,9 @@ cupsDNSSDGetConfigChanges( // 'cupsDNSSDNew()' - Create a new DNS-SD context. // // This function creates a new DNS-SD context for browsing, querying, resolving, -// and/or registering services. +// and/or registering services. Call @link cupsDNSSDDelete@ to stop any pending +// browses, queries, or resolves, unregister any services, and free the DNS-SD +// context. // cups_dnssd_t * // O - DNS-SD context @@ -521,11 +619,31 @@ cupsDNSSDBrowseGetContext( // // 'cupsDNSSDBrowseNew()' - Create a new DNS-SD browse request. // +// This function creates a new DNS-SD browse request for the specified service +// types and optional domain and interface index. The "types" argument can be a +// single service type ("_ipp._tcp") or a service type and comma-delimited list +// of sub-types ("_ipp._tcp,_print,_universal"). +// +// Newly discovered services are reported using the required browse callback +// function, with the "flags" argument set to `CUPS_DNSSD_FLAGS_ADD` for newly +// discovered services, `CUPS_DNSSD_FLAGS_NONE` for removed services, or +// `CUPS_DNSSD_FLAGS_ERROR` on an error: +// +// ``` +// void +// browse_cb(cups_dnssd_browse_t *browse, void *cb_data, +// cups_dnssd_flags_t flags, uint32_t if_index, +// const char *name, const char *regtype, const char *domain) +// { +// // Process added/removed service +// } +// ``` +// cups_dnssd_browse_t * // O - Browse request or `NULL` on error cupsDNSSDBrowseNew( cups_dnssd_t *dnssd, // I - DNS-SD context - uint32_t if_index, // I - Interface index or `CUPS_DNSSD_IF_ANY` or `CUPS_DNSSD_IF_LOCAL` + uint32_t if_index, // I - Interface index, `CUPS_DNSSD_IF_ANY`, or `CUPS_DNSSD_IF_LOCAL` const char *types, // I - Service types const char *domain, // I - Domain name or `NULL` for default cups_dnssd_browse_cb_t browse_cb, // I - Browse callback function @@ -575,9 +693,7 @@ cupsDNSSDBrowseNew( } #else // HAVE_AVAHI -// avahi_threaded_poll_lock(dnssd->monitor); browse->browser = avahi_service_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, types, NULL, 0, (AvahiServiceBrowserCallback)avahi_browse_cb, browse); - //avahi_threaded_poll_unlock(dnssd->monitor); if (!browse->browser) { @@ -633,9 +749,22 @@ cupsDNSSDQueryGetContext( // // 'cupsDNSSDQueryNew()' - Create a new query request. // -// This function creates a new DNS-SD query request for the specified record -// type. The "fullname" parameter specifies the full DNS name of the service -// (instance name, type, and domain) being queried. +// This function creates a new DNS-SD query request for the specified full +// service name and DNS record type. The "fullname" parameter specifies the +// full DNS name of the service (instance name, type, and domain) being queried. +// Responses to the query are reported using the required query callback +// function with the "flags" argument set to `CUPS_DNSSD_FLAGS_NONE` on success +// or `CUPS_DNSSD_FLAGS_ERROR` on error: +// +// ``` +// void +// query_cb(cups_dnssd_query_t *query, void *cb_data, +// cups_dnssd_flags_t flags, uint32_t if_index, +// const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen) +// { +// // Process query record +// } +// ``` // cups_dnssd_query_t * // O - Query request or `NULL` on error @@ -691,9 +820,7 @@ cupsDNSSDQueryNew( } #else // HAVE_AVAHI - //avahi_threaded_poll_lock(dnssd->monitor); query->browser = avahi_record_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, fullname, AVAHI_DNS_CLASS_IN, rrtype, 0, (AvahiRecordBrowserCallback)avahi_query_cb, query); - //avahi_threaded_poll_unlock(dnssd->monitor); if (!query->browser) { @@ -749,6 +876,22 @@ cupsDNSSDResolveGetContext( // // 'cupsDNSSDResolveNew()' - Create a new DNS-SD resolve request. // +// This function creates a new DNS-SD resolver for the specified instance name, +// service type, and optional domain and interface index. Resikved services +// are reported using the required resolve callback function, with the "flags" +// argument set to `CUPS_DNSSD_FLAGS_NONE` on success or +// `CUPS_DNSSD_FLAGS_ERROR` on error: +// +// ``` +// void +// resolve_cb(cups_dnssd_resolve_t *resolve, void *cb_data, +// cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, +// const char *host, uint16_t port, size_t num_txt, cups_option_t *txt) +// { +// // Process resolved service +// } +// ``` +// cups_dnssd_resolve_t * // O - Resolve request or `NULL` on error cupsDNSSDResolveNew( @@ -804,9 +947,7 @@ cupsDNSSDResolveNew( } #else // HAVE_AVAHI - //avahi_threaded_poll_lock(dnssd->monitor); resolve->resolver = avahi_service_resolver_new(dnssd->client, if_index, AVAHI_PROTO_UNSPEC, name, type, domain, AVAHI_PROTO_UNSPEC, /*flags*/0, (AvahiServiceResolverCallback)avahi_resolve_cb, resolve); - //avahi_threaded_poll_unlock(dnssd->monitor); if (!resolve->resolver) { @@ -830,6 +971,14 @@ cupsDNSSDResolveNew( // // 'cupsDNSSDServiceAdd()' - Add a service instance. // +// This function adds a service instance for the specified service types, +// domain, host, and port. The "types" argument can be a single service type +// ("_ipp._tcp") or a service type and comma-delimited list of sub-types +// ("_ipp._tcp,_print,_universal"). +// +// Call the @link cupsDNSSDServicePublish@ function after all service instances +// have been added. +// bool // O - `true` on success, `false` on failure cupsDNSSDServiceAdd( @@ -920,8 +1069,6 @@ cupsDNSSDServiceAdd( *subtypes++ = '\0'; // Add the service entry... - //avahi_threaded_poll_lock(service->dnssd->monitor); - if ((error = avahi_entry_group_add_service_strlst(service->group, service->if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, regtype, domain, host, port, txtrec)) < 0) { report_error(service->dnssd, "Unable to register '%s.%s': %s", service->name, regtype, avahi_strerror(error)); @@ -950,8 +1097,6 @@ cupsDNSSDServiceAdd( free(regtype); - //avahi_threaded_poll_unlock(service->dnssd->monitor); - if (txtrec) avahi_string_list_free(txtrec); #endif // _WIN32 @@ -982,7 +1127,8 @@ cupsDNSSDServiceDelete( // -// 'cupsDNSSDServiceGetContext()' - Get the DNS-SD context for the service registration. +// 'cupsDNSSDServiceGetContext()' - Get the DNS-SD context for the service +// registration. // cups_dnssd_t * // O - DNS-SD context or `NULL` @@ -1008,11 +1154,21 @@ cupsDNSSDServiceGetName( // // 'cupsDNSSDServiceNew()' - Create a new named service. // +// This function creates a new DNS-SD service registration for the given service +// instance name and interface. Specific services using the name are added +// using the @link cupsDNSSDServiceAdd@ function. +// +// The required service callback is called for select events, with the "flags" +// argument set to `CUPS_DNSSD_FLAGS_NONE` for a successful registration, +// `CUPS_DNSSD_FLAGS_COLLISION` when there is a name collision, or +// `CUPS_DNSSD_FLAGS_ERROR` when there is a problem completing the service +// registration. +// cups_dnssd_service_t * // O - Service or `NULL` on error cupsDNSSDServiceNew( cups_dnssd_t *dnssd, // I - DNS-SD context - uint32_t if_index, // I - Interface index or `CUPS_DNSSD_IF_ANY` or `CUPS_DNSSD_IF_LOCAL` + uint32_t if_index, // I - Interface index, `CUPS_DNSSD_IF_ANY`, or `CUPS_DNSSD_IF_LOCAL` const char *name, // I - Name of service cups_dnssd_service_cb_t cb, // I - Service registration callback function void *cb_data) // I - Service registration callback data @@ -1037,9 +1193,7 @@ cupsDNSSDServiceNew( #if _WIN32 #elif defined(HAVE_MDNSRESPONDER) #else // HAVE_AVAHI - //avahi_threaded_poll_lock(dnssd->monitor); service->group = avahi_entry_group_new(dnssd->client, (AvahiEntryGroupCallback)avahi_service_cb, service); - //avahi_threaded_poll_unlock(dnssd->monitor); if (!service->group) { @@ -1077,6 +1231,9 @@ cupsDNSSDServiceNew( // // 'cupsDNSSDServicePublish()' - Publish a service. // +// This function publishes the DNS-SD services added using the +// @link cupsDNSSDServiceAdd@ function. +// bool // O - `true` on success, `false` on failure cupsDNSSDServicePublish( @@ -1090,9 +1247,7 @@ cupsDNSSDServicePublish( #elif defined(HAVE_MDNSRESPONDER) (void)service; #else // HAVE_AVAHI - //avahi_threaded_poll_lock(service->dnssd->monitor); avahi_entry_group_commit(service->group); - //avahi_threaded_poll_unlock(service->dnssd->monitor); #endif // _WIN32 return (ret); @@ -1107,9 +1262,9 @@ cupsDNSSDServicePublish( // of the form // 'geo:LATITUDE,LONGITUDE[,ALTITUDE][;crs=CRSLABEL][;u=UNCERTAINTY]'. The // specified coordinates and uncertainty are converted into a DNS LOC record -// for the service name label. +// for the service name label. Only the "wgs84" CRSLABEL string is supported. // -// Only the "wgs84" CRSLABEL string is supported. +// You must call this function prior to @link cupsDNSSDServiceAdd@. // bool // O - `true` on success, `false` on failure @@ -1127,6 +1282,10 @@ cupsDNSSDServiceSetLocation( unsigned char prec; // Precision value + // Range check input... + if (!service || !geo_uri) + return (false); + // See if this is a WGS-84 coordinate... if ((geo_ptr = strstr(geo_uri, ";crs=")) != NULL && strncmp(geo_ptr + 5, "wgs84", 5)) { @@ -1192,15 +1351,11 @@ cupsDNSSDServiceSetLocation( // Add LOC record now... int error; // Error code - //avahi_threaded_poll_lock(service->dnssd->monitor); - if ((error = avahi_entry_group_add_record(service->group, service->if_index, AVAHI_PROTO_UNSPEC, /*flags*/0, service->name, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_LOC, /*ttl*/75 * 60, service->loc, sizeof(service->loc))) < 0) { report_error(service->dnssd, "Unable to register LOC record for '%s': %s", service->name, avahi_strerror(error)); ret = false; } - - //avahi_threaded_poll_unlock(service->dnssd->monitor); #endif // _WIN32 return (ret); @@ -1220,9 +1375,7 @@ delete_browse( DNSServiceRefDeallocate(browse->ref); #else // HAVE_AVAHI - //avahi_threaded_poll_lock(browse->dnssd->monitor); avahi_service_browser_free(browse->browser); - //avahi_threaded_poll_unlock(browse->dnssd->monitor); #endif // _WIN32 free(browse); @@ -1243,9 +1396,7 @@ delete_query( DNSServiceRefDeallocate(query->ref); #else // HAVE_AVAHI - //avahi_threaded_poll_lock(query->dnssd->monitor); avahi_record_browser_free(query->browser); - //avahi_threaded_poll_unlock(query->dnssd->monitor); #endif // _WIN32 } @@ -1265,9 +1416,7 @@ delete_resolve( DNSServiceRefDeallocate(resolve->ref); #else // HAVE_AVAHI - //avahi_threaded_poll_lock(resolve->dnssd->monitor); avahi_service_resolver_free(resolve->resolver); - //avahi_threaded_poll_unlock(resolve->dnssd->monitor); #endif // _WIN32 } @@ -1291,9 +1440,7 @@ delete_service( DNSServiceRefDeallocate(service->refs[i]); #else // HAVE_AVAHI - //avahi_threaded_poll_lock(service->dnssd->monitor); avahi_entry_group_free(service->group); - //avahi_threaded_poll_unlock(service->dnssd->monitor); #endif // _WIN32 free(service); @@ -1738,7 +1885,7 @@ static void * // O - Exit status avahi_monitor(cups_dnssd_t *dnssd) // I - DNS-SD context { avahi_simple_poll_loop(dnssd->poll); - fputs("avahi_monitor: DONE\n", stderr); + return (NULL); } diff --git a/cups/dnssd.h b/cups/dnssd.h index b2da0ee93..c9ac37df4 100644 --- a/cups/dnssd.h +++ b/cups/dnssd.h @@ -19,10 +19,11 @@ extern "C" { // Types and constants... // -# define CUPS_DNSSD_IF_INDEX_ANY 0 +# define CUPS_DNSSD_IF_INDEX_ANY 0 # define CUPS_DNSSD_IF_INDEX_LOCAL ((uint32_t)-1) -typedef struct _cups_dnssd_s cups_dnssd_t; // DNS-SD context +typedef struct _cups_dnssd_s cups_dnssd_t; + // DNS-SD context enum cups_dnssd_flags_e // DNS-SD callback flag values { diff --git a/doc/cupspm.epub b/doc/cupspm.epub index 4ad7cc4c896e95571d2bdb5b342d5c1a34916a27..371ac47bf01acf840c59389af92eecebb06d7188 100644 GIT binary patch delta 78847 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%0Ao0LS(#=N%T~a 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

    #mkpS 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 delta 74654 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 V`~OI#$fdkGf=J)p8i3yL{|7%hVkQ6p diff --git a/doc/cupspm.html b/doc/cupspm.html index eb8694fea..08361d701 100644 --- a/doc/cupspm.html +++ b/doc/cupspm.html @@ -319,6 +319,29 @@

    Contents

  • cupsCopyDestInfo
  • cupsCopyString
  • cupsCreateDestJob
  • +
  • cupsDNSSDAssembleFullName
  • +
  • cupsDNSSDBrowseDelete
  • +
  • cupsDNSSDBrowseGetContext
  • +
  • cupsDNSSDBrowseNew
  • +
  • cupsDNSSDDecodeTXT
  • +
  • cupsDNSSDDelete
  • +
  • cupsDNSSDGetConfigChanges
  • +
  • cupsDNSSDGetHostName
  • +
  • cupsDNSSDNew
  • +
  • cupsDNSSDQueryDelete
  • +
  • cupsDNSSDQueryGetContext
  • +
  • cupsDNSSDQueryNew
  • +
  • cupsDNSSDResolveDelete
  • +
  • cupsDNSSDResolveGetContext
  • +
  • cupsDNSSDResolveNew
  • +
  • cupsDNSSDSeparateFullName
  • +
  • cupsDNSSDServiceAdd
  • +
  • cupsDNSSDServiceDelete
  • +
  • cupsDNSSDServiceGetContext
  • +
  • cupsDNSSDServiceGetName
  • +
  • cupsDNSSDServiceNew
  • +
  • cupsDNSSDServicePublish
  • +
  • cupsDNSSDServiceSetLocation
  • cupsDirClose
  • cupsDirOpen
  • cupsDirRead
  • @@ -673,6 +696,17 @@

    Contents

  • cups_dest_t
  • cups_dinfo_t
  • cups_dir_t
  • +
  • cups_dnssd_browse_cb_t
  • +
  • cups_dnssd_error_cb_t
  • +
  • cups_dnssd_flags_t
  • +
  • cups_dnssd_query_cb_t
  • +
  • cups_dnssd_query_t
  • +
  • cups_dnssd_resolve_cb_t
  • +
  • cups_dnssd_resolve_t
  • +
  • cups_dnssd_browse_t
  • +
  • cups_dnssd_service_cb_t
  • +
  • cups_dnssd_service_t
  • +
  • cups_dnssd_t
  • cups_edge_t
  • cups_file_t
  • cups_job_t
  • @@ -750,6 +784,8 @@

    Contents

  • cups_bool_e
  • cups_cspace_e
  • cups_cut_e
  • +
  • cups_dnssd_flags_e
  • +
  • cups_dnssd_rrtype_e
  • cups_edge_e
  • cups_jog_e
  • cups_mediapos_e
  • @@ -2473,6 +2509,459 @@

    Return Value

    Discussion

    Returns IPP_STATUS_OK or IPP_STATUS_OK_SUBST on success, saving the job ID in the variable pointed to by "job_id".

    +

    cupsDNSSDAssembleFullName

    +

    Create a full service name from the instance +name, registration type, and domain.

    +

    +bool cupsDNSSDAssembleFullName(char *fullname, size_t fullsize, const char *name, const char *type, const char *domain);

    +

    Parameters

    + + + + + + + + + + + +
    fullnameBuffer for full name
    fullsizeSize of buffer
    nameService instance name
    typeRegistration type
    domainDomain
    +

    Return Value

    +

    true on success, false on failure

    +

    Discussion

    +

    This function combines an instance name ("Example Name"), registration type +("_ipp._tcp"), and domain ("local.") to create a properly escaped full +service name ("Example032Name._ipp._tcp.local.").

    +

    cupsDNSSDBrowseDelete

    +

    Cancel and delete a browse request.

    +

    +void cupsDNSSDBrowseDelete(cups_dnssd_browse_t *browse);

    +

    Parameters

    + + + +
    browseBrowse request
    +

    cupsDNSSDBrowseGetContext

    +

    Get the DNS-SD context for the browse request.

    +

    +cups_dnssd_t *cupsDNSSDBrowseGetContext(cups_dnssd_browse_t *browse);

    +

    Parameters

    + + + +
    browseBrowse request
    +

    Return Value

    +

    Context or NULL

    +

    cupsDNSSDBrowseNew

    +

    Create a new DNS-SD browse request.

    +

    +cups_dnssd_browse_t *cupsDNSSDBrowseNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *types, const char *domain, cups_dnssd_browse_cb_t browse_cb, void *cb_data);

    +

    Parameters

    + + + + + + + + + + + + + +
    dnssdDNS-SD context
    if_indexInterface index, CUPS_DNSSD_IF_ANY, or CUPS_DNSSD_IF_LOCAL
    typesService types
    domainDomain name or NULL for default
    browse_cbBrowse callback function
    cb_dataBrowse callback data
    +

    Return Value

    +

    Browse request or NULL on error

    +

    Discussion

    +

    This function creates a new DNS-SD browse request for the specified service +types and optional domain and interface index. The "types" argument can be a +single service type ("_ipp._tcp") or a service type and comma-delimited list +of sub-types ("_ipp._tcp,_print,_universal").
    +
    +Newly discovered services are reported using the required browse callback +function, with the "flags" argument set to CUPS_DNSSD_FLAGS_ADD for newly +discovered services, CUPS_DNSSD_FLAGS_NONE for removed services, or +CUPS_DNSSD_FLAGS_ERROR on an error: + +

    +void
    +browse_cb(cups_dnssd_browse_t *browse, void *cb_data,
    +cups_dnssd_flags_t flags, uint32_t if_index,
    +const char *name, const char *regtype, const char *domain)
    +{
    +// Process added/removed service
    +}
    +```
    +gned integer +representing a hash into the array. The hash value is of type size_t

    +

    cupsDNSSDDecodeTXT

    +

    Decode a TXT record into key/value pairs.

    +

    +size_t cupsDNSSDDecodeTXT(const unsigned char *txtrec, uint16_t txtlen, cups_option_t **txt);

    +

    Parameters

    + + + + + + + +
    txtrecTXT record data
    txtlenTXT record length
    txtKey/value pairs
    +

    Return Value

    +

    Number of key/value pairs

    +

    Discussion

    +

    This function converts the DNS TXT record encoding of key/value pairs into +cups_option_t elements that can be accessed using the cupsGetOption +function and freed using the cupsFreeOptions function.

    +

    cupsDNSSDDelete

    +

    Delete a DNS-SD context and all its requests.

    +

    +void cupsDNSSDDelete(cups_dnssd_t *dnssd);

    +

    Parameters

    + + + +
    dnssdDNS-SD context
    +

    cupsDNSSDGetConfigChanges

    +

    Get the number of host name/network +configuration changes seen.

    +

    +size_t cupsDNSSDGetConfigChanges(cups_dnssd_t *dnssd);

    +

    Parameters

    + + + +
    dnssdDNS-SD context
    +

    Return Value

    +

    Number of host name changes

    +

    Discussion

    +

    This function returns the number of host name or network configuration +changes that have been seen since the context was created. The value can be +used to track when local services need to be updated. Registered services +will also get a callback with the CUPS_DNSSD_FLAGS_HOST_CHANGE bit set in +the "flags" argument for host name changes and/or +CUPS_DNSSD_FLAGS_NETWORK_CHANGE for network changes.

    +

    cupsDNSSDGetHostName

    +

    Get the current mDNS host name for the system.

    +

    +const char *cupsDNSSDGetHostName(cups_dnssd_t *dnssd, char *buffer, size_t bufsize);

    +

    Parameters

    + + + + + + + +
    dnssdDNS-SD context
    bufferHost name buffer
    bufsizeSize of host name buffer
    +

    Return Value

    +

    Local host name or NULL for none

    +

    Discussion

    +

    This function gets the current mDNS (".local") host name for the system.

    +

    cupsDNSSDNew

    +

    Create a new DNS-SD context.

    +

    +cups_dnssd_t *cupsDNSSDNew(cups_dnssd_error_cb_t error_cb, void *cb_data);

    +

    Parameters

    + + + + + +
    error_cbError callback function
    cb_dataError callback data
    +

    Return Value

    +

    DNS-SD context

    +

    Discussion

    +

    This function creates a new DNS-SD context for browsing, querying, resolving, +and/or registering services. Call cupsDNSSDDelete to stop any pending +browses, queries, or resolves, unregister any services, and free the DNS-SD +context.

    +

    cupsDNSSDQueryDelete

    +

    Cancel and delete a query request.

    +

    +void cupsDNSSDQueryDelete(cups_dnssd_query_t *query);

    +

    Parameters

    + + + +
    queryQuery request
    +

    cupsDNSSDQueryGetContext

    +

    Get the DNS-SD context for the query request.

    +

    +cups_dnssd_t *cupsDNSSDQueryGetContext(cups_dnssd_query_t *query);

    +

    Parameters

    + + + +
    queryQuery request
    +

    Return Value

    +

    DNS-SD context or NULL

    +

    cupsDNSSDQueryNew

    +

    Create a new query request.

    +

    +cups_dnssd_query_t *cupsDNSSDQueryNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *fullname, uint16_t rrtype, cups_dnssd_query_cb_t query_cb, void *cb_data);

    +

    Parameters

    + + + + + + + + + + + + + +
    dnssdDNS-SD context
    if_indexInterface index or CUPS_DNSSD_IF_ANY or CUPS_DNSSD_IF_LOCAL
    fullnameFull DNS name including types and domain
    rrtypeRecord type to query (CUPS_DNSSD_RRTYPE_TXT, etc.)
    query_cbQuery callback function
    cb_dataQuery callback data
    +

    Return Value

    +

    Query request or NULL on error

    +

    Discussion

    +

    This function creates a new DNS-SD query request for the specified full +service name and DNS record type. The "fullname" parameter specifies the +full DNS name of the service (instance name, type, and domain) being queried. +Responses to the query are reported using the required query callback +function with the "flags" argument set to CUPS_DNSSD_FLAGS_NONE on success +or CUPS_DNSSD_FLAGS_ERROR on error: + +

    +void
    +query_cb(cups_dnssd_query_t *query, void *cb_data,
    +cups_dnssd_flags_t flags, uint32_t if_index,
    +const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen)
    +{
    +// Process query record
    +}
    +```
    +lags_t flags, uint32_t if_index, +const char name, const char regtype, const char *domain) +{ +// Process added/removed service +} +`

    +

    cupsDNSSDResolveDelete

    +

    Cancel and free a resolve request.

    +

    +void cupsDNSSDResolveDelete(cups_dnssd_resolve_t *res);

    +

    Parameters

    + + + +
    resResolve request
    +

    cupsDNSSDResolveGetContext

    +

    Get the DNS-SD context for the resolve request.

    +

    +cups_dnssd_t *cupsDNSSDResolveGetContext(cups_dnssd_resolve_t *resolve);

    +

    Parameters

    + + + +
    resolveResolve request
    +

    Return Value

    +

    DNS-SD context or NULL

    +

    cupsDNSSDResolveNew

    +

    Create a new DNS-SD resolve request.

    +

    +cups_dnssd_resolve_t *cupsDNSSDResolveNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *name, const char *type, const char *domain, cups_dnssd_resolve_cb_t resolve_cb, void *cb_data);

    +

    Parameters

    + + + + + + + + + + + + + + + +
    dnssdDNS-SD context
    if_indexInterface index or CUPS_DNSSD_IF_ANY or CUPS_DNSSD_IF_LOCAL
    nameService name
    typeService type
    domainDomain name or NULL for default
    resolve_cbResolve callback function
    cb_dataResolve callback data
    +

    Return Value

    +

    Resolve request or NULL on error

    +

    Discussion

    +

    This function creates a new DNS-SD resolver for the specified instance name, +service type, and optional domain and interface index. Resikved services +are reported using the required resolve callback function, with the "flags" +argument set to CUPS_DNSSD_FLAGS_NONE on success or +CUPS_DNSSD_FLAGS_ERROR on error: + +

    +void
    +resolve_cb(cups_dnssd_resolve_t *resolve, void *cb_data,
    +cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname,
    +const char *host, uint16_t port, size_t num_txt, cups_option_t *txt)
    +{
    +// Process resolved service
    +}
    +```
    + *qdata, uint16_t qlen) +{ +// Process query record +} +`

    +

    cupsDNSSDSeparateFullName

    +

    Separate a full service name into an instance +name, registration type, and domain.

    +

    +bool cupsDNSSDSeparateFullName(const char *fullname, char *name, size_t namesize, char *type, size_t typesize, char *domain, size_t domainsize);

    +

    Parameters

    + + + + + + + + + + + + + + + +
    fullnameFull service name
    nameInstance name buffer
    namesizeSize of instance name buffer
    typeRegistration type buffer
    typesizeSize of registration type buffer
    domainDomain name buffer
    domainsizeSize of domain name buffer
    +

    Return Value

    +

    true on success, false on error

    +

    Discussion

    +

    This function separates a full service name such as +"Example032Name._ipp._tcp.local.") into its instance name ("Example Name"), +registration type ("_ipp._tcp"), and domain ("local.").

    +

    cupsDNSSDServiceAdd

    +

    Add a service instance.

    +

    +bool cupsDNSSDServiceAdd(cups_dnssd_service_t *service, const char *types, const char *domain, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt);

    +

    Parameters

    + + + + + + + + + + + + + + + +
    serviceService
    typesService types
    domainDomain name or NULL for default
    hostHost name or NULL for default
    portPort number or 0 for none
    num_txtNumber of TXT record values
    txtTXT record values
    +

    Return Value

    +

    true on success, false on failure

    +

    Discussion

    +

    This function adds a service instance for the specified service types, +domain, host, and port. The "types" argument can be a single service type +("_ipp._tcp") or a service type and comma-delimited list of sub-types +("_ipp._tcp,_print,_universal").
    +
    +Call the cupsDNSSDServicePublish function after all service instances +have been added.

    +

    cupsDNSSDServiceDelete

    +

    Cancel and free a service registration.

    +

    +void cupsDNSSDServiceDelete(cups_dnssd_service_t *service);

    +

    Parameters

    + + + +
    serviceService
    +

    cupsDNSSDServiceGetContext

    +

    Get the DNS-SD context for the service +registration.

    +

    +cups_dnssd_t *cupsDNSSDServiceGetContext(cups_dnssd_service_t *service);

    +

    Parameters

    + + + +
    serviceService registration
    +

    Return Value

    +

    DNS-SD context or NULL

    +

    cupsDNSSDServiceGetName

    +

    Get the service instance name for the service registration.

    +

    +const char *cupsDNSSDServiceGetName(cups_dnssd_service_t *service);

    +

    Parameters

    + + + +
    serviceService registration
    +

    Return Value

    +

    Service instance name

    +

    cupsDNSSDServiceNew

    +

    Create a new named service.

    +

    +cups_dnssd_service_t *cupsDNSSDServiceNew(cups_dnssd_t *dnssd, uint32_t if_index, const char *name, cups_dnssd_service_cb_t cb, void *cb_data);

    +

    Parameters

    + + + + + + + + + + + +
    dnssdDNS-SD context
    if_indexInterface index, CUPS_DNSSD_IF_ANY, or CUPS_DNSSD_IF_LOCAL
    nameName of service
    cbService registration callback function
    cb_dataService registration callback data
    +

    Return Value

    +

    Service or NULL on error

    +

    Discussion

    +

    This function creates a new DNS-SD service registration for the given service +instance name and interface. Specific services using the name are added +using the cupsDNSSDServiceAdd function.
    +
    +The required service callback is called for select events, with the "flags" +argument set to CUPS_DNSSD_FLAGS_NONE for a successful registration, +CUPS_DNSSD_FLAGS_COLLISION when there is a name collision, or +CUPS_DNSSD_FLAGS_ERROR when there is a problem completing the service +registration.

    +

    cupsDNSSDServicePublish

    +

    Publish a service.

    +

    +bool cupsDNSSDServicePublish(cups_dnssd_service_t *service);

    +

    Parameters

    + + + +
    serviceService
    +

    Return Value

    +

    true on success, false on failure

    +

    Discussion

    +

    This function publishes the DNS-SD services added using the +cupsDNSSDServiceAdd function.

    +

    cupsDNSSDServiceSetLocation

    +

    Set the geolocation (LOC record) of a +service.

    +

    +bool cupsDNSSDServiceSetLocation(cups_dnssd_service_t *service, const char *geo_uri);

    +

    Parameters

    + + + + + +
    serviceService
    geo_uriGeolocation as a 'geo:' URI
    +

    Return Value

    +

    true on success, false on failure

    +

    Discussion

    +

    This function sets the geolocation of a service using a 'geo:' URI (RFC 5870) +of the form +'geo:LATITUDE,LONGITUDE[,ALTITUDE][;crs=CRSLABEL][;u=UNCERTAINTY]'. The +specified coordinates and uncertainty are converted into a DNS LOC record +for the service name label. Only the "wgs84" CRSLABEL string is supported.
    +
    +You must call this function prior to cupsDNSSDServiceAdd.

    cupsDirClose

    Close a directory.

    @@ -8343,6 +8832,61 @@

    cups_dir_t

    typedef struct _cups_dir_s cups_dir_t;

    +

    cups_dnssd_browse_cb_t

    +

    DNS-SD browse callback

    +

    +typedef void(*)(cups_dnssd_browse_t *browse, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain)cups_dnssd_browse_cb_t; +

    +

    cups_dnssd_error_cb_t

    +

    DNS-SD error callback

    +

    +typedef void(*)(void *cb_data, const char *message)cups_dnssd_error_cb_t; +

    +

    cups_dnssd_flags_t

    +

    DNS-SD callback flag bitmask

    +

    +typedef unsigned cups_dnssd_flags_t; +

    +

    cups_dnssd_query_cb_t

    +

    DNS-SD query callback

    +

    +typedef void(*)(cups_dnssd_query_t *query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen) cups_dnssd_query_cb_t; +

    +

    cups_dnssd_query_t

    +

    DNS query request

    +

    +typedef struct _cups_dnssd_query_s cups_dnssd_query_t; +

    +

    cups_dnssd_resolve_cb_t

    +

    DNS-SD resolve callback

    +

    +typedef void(*)(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt)cups_dnssd_resolve_cb_t; +

    +

    cups_dnssd_resolve_t

    +

    DNS resolve request

    +

    +typedef struct _cups_dnssd_resolve_s cups_dnssd_resolve_t; +

    +

    cups_dnssd_browse_t

    +

    DNS record type values

    +

    +typedef typedef struct _cups_dnssd_browse_s cups_dnssd_browse_t; +

    +

    cups_dnssd_service_cb_t

    +

    DNS-SD service registration callback

    +

    +typedef void(*)(cups_dnssd_service_t *service, void *cb_data, cups_dnssd_flags_t flags) cups_dnssd_service_cb_t; +

    +

    cups_dnssd_service_t

    +

    DNS service registration

    +

    +typedef struct _cups_dnssd_service_s cups_dnssd_service_t; +

    +

    cups_dnssd_t

    +

    DNS-SD context

    +

    +typedef struct _cups_dnssd_s cups_dnssd_t; +

    cups_edge_t

    LeadingEdge attribute values

    @@ -9028,6 +9572,42 @@

    Constants

    CUPS_CUT_PAGE Cut the roll after this page CUPS_CUT_SET Cut the roll after this set +

    cups_dnssd_flags_e

    +

    DNS-SD callback flag values

    +

    Constants

    + + + + + + + + +
    CUPS_DNSSD_FLAGS_ADD Added (removed if not set)
    CUPS_DNSSD_FLAGS_COLLISION Collision occurred
    CUPS_DNSSD_FLAGS_ERROR Error occurred
    CUPS_DNSSD_FLAGS_HOST_CHANGE Host name changed
    CUPS_DNSSD_FLAGS_MORE More coming
    CUPS_DNSSD_FLAGS_NETWORK_CHANGE Network connection changed
    CUPS_DNSSD_FLAGS_NONE No flags
    +

    cups_dnssd_rrtype_e

    +

    DNS record type values

    +

    Constants

    + + + + + + + + + + + + + + + + + + + + +
    CUPS_DNSSD_RRTYPE_A Host address
    CUPS_DNSSD_RRTYPE_AAAA IPv6 Address.
    CUPS_DNSSD_RRTYPE_ANY Wildcard match
    CUPS_DNSSD_RRTYPE_CERT Certification record
    CUPS_DNSSD_RRTYPE_CNAME Canonical name
    CUPS_DNSSD_RRTYPE_DHCID DHCP Client Identifier
    CUPS_DNSSD_RRTYPE_DNSKEY DNSKEY
    CUPS_DNSSD_RRTYPE_HTTPS HTTPS Service Binding
    CUPS_DNSSD_RRTYPE_KEY Security key
    CUPS_DNSSD_RRTYPE_KX Key Exchange
    CUPS_DNSSD_RRTYPE_LOC Location Information.
    CUPS_DNSSD_RRTYPE_NS Name server
    CUPS_DNSSD_RRTYPE_PTR Domain name pointer
    CUPS_DNSSD_RRTYPE_RRSIG RRSIG
    CUPS_DNSSD_RRTYPE_RT Router
    CUPS_DNSSD_RRTYPE_SIG Security signature
    CUPS_DNSSD_RRTYPE_SPF Sender Policy Framework for E-Mail
    CUPS_DNSSD_RRTYPE_TXT One or more text strings
    CUPS_DNSSD_RRTYPE_WKS Well known service

    cups_edge_e

    LeadingEdge attribute values

    Constants

    From 1eab751380765c7cb8cfb7ccd69992fd5eb25f40 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Thu, 25 Aug 2022 13:33:11 -0400 Subject: [PATCH 15/19] Use new DNS-SD API to implement httpResolveURI API. --- cups/dnssd.c | 2 +- cups/http-support.c | 659 ++++-------------------- xcode/libcups.xcodeproj/project.pbxproj | 2 + 3 files changed, 94 insertions(+), 569 deletions(-) diff --git a/cups/dnssd.c b/cups/dnssd.c index 575779750..0644889d2 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -282,7 +282,7 @@ cupsDNSSDSeparateFullName( size_t domainsize) // I - Size of domain name buffer { // Range check input.. - if (!fullname || !name || !namesize || type || !typesize || !domain || !domainsize) + if (!fullname || !name || !namesize || !type || !typesize || !domain || !domainsize) { if (name) *name = '\0'; diff --git a/cups/http-support.c b/cups/http-support.c index 4a3a73a4c..e048899e5 100644 --- a/cups/http-support.c +++ b/cups/http-support.c @@ -11,19 +11,7 @@ #include "cups-private.h" #include "debug-internal.h" -#ifdef HAVE_MDNSRESPONDER -# include -# ifdef _WIN32 -# include -# else -# include -# endif // _WIN32 -#elif defined(HAVE_AVAHI) -# include -# include -# include -# include -#endif // HAVE_MDNSRESPONDER +#include "dnssd.h" // @@ -32,9 +20,7 @@ typedef struct _http_uribuf_s // URI buffer { -#ifdef HAVE_AVAHI - AvahiSimplePoll *poll; // Poll state -#endif // HAVE_AVAHI + cups_dnssd_t *dnssd; // DNS-SD context char *buffer; // Pointer to buffer size_t bufsize; // Size of buffer http_resolve_t options; // Options passed to httpResolveURI @@ -116,15 +102,7 @@ static const char * const http_states[] = static const char *http_copy_decode(char *dst, const char *src, size_t dstsize, const char *term, bool decode); static char *http_copy_encode(char *dst, const char *src, char *dstend, const char *reserved, const char *term, bool encode); -#ifdef HAVE_MDNSRESPONDER -static void DNSSD_API http_resolve_cb(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, const char *hostTarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context); -#endif // HAVE_MDNSRESPONDER - -#ifdef HAVE_AVAHI -static void http_client_cb(AvahiClient *client, AvahiClientState state, void *simple_poll); -static int http_poll_cb(struct pollfd *pollfds, unsigned int num_pollfds, int timeout, void *context); -static void http_resolve_cb(AvahiServiceResolver *resolver, AvahiIfIndex interface, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txt, AvahiLookupResultFlags flags, void *context); -#endif // HAVE_AVAHI +static void http_resolve_cb(cups_dnssd_resolve_t *res, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, const char *host, uint16_t port, size_t num_txt, cups_option_t *txt); // @@ -1511,51 +1489,24 @@ httpResolveURI( // Resolve it as needed... if (strstr(hostname, "._tcp")) { -#ifdef HAVE_DNSSD - char *regtype, // Pointer to type in hostname - *domain, // Pointer to domain in hostname + time_t domain_time, // Domain lookup time, if any + end_time; // End time for resolve + cups_dnssd_t *dnssd; // DNS-SD context + uint32_t if_index; // Interface index + char name[256], // Service instance name + regtype[256], // Registration type + domain[256], // Domain name *uuid, // Pointer to UUID in URI *uuidend; // Pointer to end of UUID in URI _http_uribuf_t uribuf; // URI buffer -# ifdef HAVE_MDNSRESPONDER - DNSServiceRef ref, // DNS-SD master service reference - domainref = NULL,// DNS-SD service reference for domain - ippref = NULL, // DNS-SD service reference for network IPP - ippsref = NULL, // DNS-SD service reference for network IPPS - localref; // DNS-SD service reference for .local - int extrasent = 0; // Send the domain/IPP/IPPS resolves? - struct pollfd polldata; // Polling data -# elif defined(HAVE_AVAHI) - AvahiClient *client; // Client information - int error; // Status -# endif // HAVE_MDNSRESPONDER // Separate the hostname into service name, registration type, and domain... - for (regtype = strstr(hostname, "._tcp") - 2; regtype > hostname; regtype --) - { - if (regtype[0] == '.' && regtype[1] == '_') - { - // Found ._servicetype in front of ._tcp... - *regtype++ = '\0'; - break; - } - } - - if (regtype <= hostname) + if (!cupsDNSSDSeparateFullName(hostname, name, sizeof(name), regtype, sizeof(regtype), domain, sizeof(domain))) { DEBUG_puts("2httpResolveURI: Bad hostname, returning NULL"); return (NULL); } - for (domain = strchr(regtype, '.'); domain; domain = strchr(domain + 1, '.')) - { - if (domain[1] != '_') - break; - } - - if (domain) - *domain++ = '\0'; - if ((uuid = strstr(resource, "?uuid=")) != NULL) { *uuid = '\0'; @@ -1572,144 +1523,46 @@ httpResolveURI( uribuf.resource = resource; uribuf.uuid = uuid; - DEBUG_printf(("2httpResolveURI: Resolving hostname=\"%s\", regtype=\"%s\", domain=\"%s\"\n", hostname, regtype, domain)); + DEBUG_printf(("2httpResolveURI: Resolving name=\"%s\", regtype=\"%s\", domain=\"%s\"\n", name, regtype, domain)); uri = NULL; -# ifdef HAVE_MDNSRESPONDER - if (DNSServiceCreateConnection(&ref) == kDNSServiceErr_NoError) - { - uint32_t myinterface = kDNSServiceInterfaceIndexAny; - // Lookup on any interface - - if (!strcmp(scheme, "ippusb")) - myinterface = kDNSServiceInterfaceIndexLocalOnly; - - localref = ref; - if (DNSServiceResolve(&localref, kDNSServiceFlagsShareConnection, myinterface, hostname, regtype, "local.", http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) - { - int fds; // Number of ready descriptors - time_t timeout, // Poll timeout - start_time = time(NULL),// Start time - end_time = start_time + 90; - // End time - - while (time(NULL) < end_time) - { - if (cb && !(*cb)(cb_data)) - { - DEBUG_puts("2httpResolveURI: callback returned 0 (stop)"); - break; - } - - // Wakeup every 2 seconds to emit a "looking for printer" message... - if ((timeout = end_time - time(NULL)) > 2) - timeout = 2; + if (!strcmp(scheme, "ippusb")) + if_index = CUPS_DNSSD_IF_INDEX_LOCAL; + else + if_index = CUPS_DNSSD_IF_INDEX_ANY; - polldata.fd = DNSServiceRefSockFD(ref); - polldata.events = POLLIN; + dnssd = cupsDNSSDNew(NULL, NULL); - if ((fds = poll(&polldata, 1, (int)(1000 * timeout))) < 0) - { - if (errno != EINTR && errno != EAGAIN) - { - DEBUG_printf(("2httpResolveURI: poll error: %s", strerror(errno))); - break; - } - } - else if (fds == 0) - { - // Wait 2 seconds for a response to the local resolve; if nothing - // comes in, do an additional domain resolution... - if (extrasent == 0 && domain && _cups_strcasecmp(domain, "local.")) - { - domainref = ref; - if (DNSServiceResolve(&domainref, kDNSServiceFlagsShareConnection, myinterface, hostname, regtype, domain, http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) - extrasent = 1; - } - else if (extrasent == 0 && !strcmp(scheme, "ippusb")) - { - ippsref = ref; - if (DNSServiceResolve(&ippsref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexAny, hostname, "_ipps._tcp", domain, http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) - extrasent = 1; - } - else if (extrasent == 1 && !strcmp(scheme, "ippusb")) - { - ippref = ref; - if (DNSServiceResolve(&ippref, kDNSServiceFlagsShareConnection, kDNSServiceInterfaceIndexAny, hostname, "_ipp._tcp", domain, http_resolve_cb, &uribuf) == kDNSServiceErr_NoError) - extrasent = 2; - } - } - else - { - if (DNSServiceProcessResult(ref) == kDNSServiceErr_NoError && resolved_uri[0]) - { - uri = resolved_uri; - break; - } - } - } - - if (extrasent) - { - if (domainref) - DNSServiceRefDeallocate(domainref); - if (ippref) - DNSServiceRefDeallocate(ippref); - if (ippsref) - DNSServiceRefDeallocate(ippsref); - } + if (!cupsDNSSDResolveNew(dnssd, if_index, name, regtype, "local.", http_resolve_cb, &uribuf)) + { + cupsDNSSDDelete(dnssd); + return (NULL); + } - DNSServiceRefDeallocate(localref); - } + domain_time = time(NULL) + 2; + end_time = time(NULL) + 90; - DNSServiceRefDeallocate(ref); - } -# else // HAVE_AVAHI - if ((uribuf.poll = avahi_simple_poll_new()) != NULL) + while (!resolved_uri[0] && time(NULL) < end_time) { - avahi_simple_poll_set_func(uribuf.poll, http_poll_cb, NULL); - - if ((client = avahi_client_new(avahi_simple_poll_get(uribuf.poll), 0, http_client_cb, &uribuf, &error)) != NULL) + // Start the domain resolve as needed... + if (time(NULL) >= domain_time && _cups_strcasecmp(domain, "local.")) { - if (avahi_service_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, hostname, regtype, "local.", AVAHI_PROTO_UNSPEC, 0, http_resolve_cb, &uribuf) != NULL) - { - time_t start_time = time(NULL), - // Start time - end_time = start_time + 90; - // End time - int pstatus; // Poll status - - pstatus = avahi_simple_poll_iterate(uribuf.poll, 2000); - - if (pstatus == 0 && !resolved_uri[0] && domain && _cups_strcasecmp(domain, "local.")) - { - // Resolve for .local hasn't returned anything, try the listed - // domain... - avahi_service_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, hostname, regtype, domain, AVAHI_PROTO_UNSPEC, 0, http_resolve_cb, &uribuf); - } + cupsDNSSDResolveNew(dnssd, if_index, name, regtype, domain, http_resolve_cb, &uribuf); + domain_time = end_time; + } - while (!pstatus && !resolved_uri[0] && time(NULL) < end_time) - { - if ((pstatus = avahi_simple_poll_iterate(uribuf.poll, 2000)) != 0) - break; - } + // Sleep 1/4 second to allow time for resolve... + usleep(250000); - // Collect the result (if we got one). - if (resolved_uri[0]) - uri = resolved_uri; - } + if (resolved_uri[0]) + break; + } - avahi_client_free(client); - } + cupsDNSSDDelete(dnssd); - avahi_simple_poll_free(uribuf.poll); - } -# endif // HAVE_MDNSRESPONDER -#else // !HAVE_DNSSD - // No DNS-SD support... - uri = NULL; -#endif // HAVE_DNSSD + // Save the results of the resolve... + uri = *resolved_uri ? resolved_uri : NULL; } else { @@ -1724,35 +1577,6 @@ httpResolveURI( } -#ifdef HAVE_AVAHI -/* - * 'http_client_cb()' - Client callback for resolving URI. - */ - -static void -http_client_cb( - AvahiClient *client, // I - Client information - AvahiClientState state, // I - Current state - void *context) // I - Pointer to URI buffer -{ - DEBUG_printf(("7http_client_cb(client=%p, state=%d, context=%p)", client, - state, context)); - - /* - * If the connection drops, quit. - */ - - if (state == AVAHI_CLIENT_FAILURE) - { - _http_uribuf_t *uribuf = (_http_uribuf_t *)context; - // URI buffer - - avahi_simple_poll_quit(uribuf->poll); - } -} -#endif // HAVE_AVAHI - - /* * 'http_copy_decode()' - Copy and decode a URI. */ @@ -1875,147 +1699,100 @@ http_copy_encode(char *dst, // O - Destination buffer } -#ifdef HAVE_MDNSRESPONDER -/* - * 'http_resolve_cb()' - Build a device URI for the given service name. - */ +// +// 'http_resolve_cb()' - Build a device URI for the given service name. +// -static void DNSSD_API +static void http_resolve_cb( - DNSServiceRef sdRef, // I - Service reference - DNSServiceFlags flags, // I - Results flags - uint32_t interfaceIndex, // I - Interface number - DNSServiceErrorType errorCode, // I - Error, if any - const char *fullName, // I - Full service name - const char *hostTarget, // I - Hostname - uint16_t port, // I - Port number - uint16_t txtLen, // I - Length of TXT record - const unsigned char *txtRecord, // I - TXT record data - void *context) // I - Pointer to URI buffer + cups_dnssd_resolve_t *res, // I - Resolver + void *cb_data, // I - Pointer to URI buffer + cups_dnssd_flags_t flags, // I - Results flags + uint32_t if_index, // I - Interface index + const char *fullname, // I - Full service name + const char *host, // I - Hostname + uint16_t port, // I - Port number + size_t num_txt, // I - Number of TXT key/value pairs + cups_option_t *txt) // I - TXT key/value pairs { - _http_uribuf_t *uribuf = (_http_uribuf_t *)context; + _http_uribuf_t *uribuf = (_http_uribuf_t *)cb_data; // URI buffer const char *scheme, // URI scheme *hostptr, // Pointer into hostTarget *reskey, // "rp" or "rfo" *resdefault; // Default path - char resource[257], // Remote path - fqdn[256]; // FQDN of the .local name - const void *value; // Value from TXT record - uint8_t valueLen; // Length of value + char fqdn[256]; // FQDN of the .local name + const char *value, // Value from TXT record + *resource; // Resource path - DEBUG_printf(("4http_resolve_cb(sdRef=%p, flags=%x, interfaceIndex=%u, errorCode=%d, fullName=\"%s\", hostTarget=\"%s\", port=%u, txtLen=%u, txtRecord=%p, context=%p)", (void *)sdRef, flags, interfaceIndex, errorCode, fullName, hostTarget, port, txtLen, (void *)txtRecord, context)); - - /* - * If we have a UUID, compare it... - */ + DEBUG_printf(("4http_resolve_cb(res=%p, cb_data=%p, flags=%x, if_index=%u, fullname=\"%s\", host=\"%s\", port=%u, num_txt=%u, txt=%p)", (void *)res, cb_data, flags, if_index, fullname, host, port, (unsigned)num_txt, (void *)txt)); - if (uribuf->uuid && - (value = TXTRecordGetValuePtr(txtLen, txtRecord, "UUID", - &valueLen)) != NULL) + // If we have a UUID, compare it... + if (uribuf->uuid && (value = cupsGetOption("UUID", num_txt, txt)) != NULL) { - char uuid[256]; // UUID value - - memcpy(uuid, value, valueLen); - uuid[valueLen] = '\0'; - - if (_cups_strcasecmp(uuid, uribuf->uuid)) + if (_cups_strcasecmp(value, uribuf->uuid)) { - DEBUG_printf(("5http_resolve_cb: Found UUID %s, looking for %s.", uuid, - uribuf->uuid)); + DEBUG_printf(("5http_resolve_cb: Found UUID %s, looking for %s.", value, uribuf->uuid)); return; } } - /* - * Figure out the scheme from the full name... - */ - - if (strstr(fullName, "._ipps") || strstr(fullName, "._ipp-tls")) + // Figure out the scheme from the full name... + if (strstr(fullname, "._ipps") || strstr(fullname, "._ipp-tls")) scheme = "ipps"; - else if (strstr(fullName, "._ipp") || strstr(fullName, "._fax-ipp")) + else if (strstr(fullname, "._ipp") || strstr(fullname, "._fax-ipp")) scheme = "ipp"; - else if (strstr(fullName, "._http.")) + else if (strstr(fullname, "._http.")) scheme = "http"; - else if (strstr(fullName, "._https.")) + else if (strstr(fullname, "._https.")) scheme = "https"; - else if (strstr(fullName, "._printer.")) + else if (strstr(fullname, "._printer.")) scheme = "lpd"; - else if (strstr(fullName, "._pdl-datastream.")) + else if (strstr(fullname, "._pdl-datastream.")) scheme = "socket"; else scheme = "riousbprint"; - /* - * Extract the "remote printer" key from the TXT record... - */ - - if ((uribuf->options & HTTP_RESOLVE_FAXOUT) && - (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && - !TXTRecordGetValuePtr(txtLen, txtRecord, "printer-type", &valueLen)) + // Extract the "remote printer" key from the TXT record... + if ((uribuf->options & HTTP_RESOLVE_FAXOUT) && (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && !cupsGetOption("printer-type", num_txt, txt)) { reskey = "rfo"; - resdefault = "/ipp/faxout"; + resdefault = "ipp/faxout"; } else { reskey = "rp"; - resdefault = "/"; + resdefault = ""; } - if ((value = TXTRecordGetValuePtr(txtLen, txtRecord, reskey, - &valueLen)) != NULL) + if ((resource = cupsGetOption(reskey, num_txt, txt)) != NULL) { - if (((char *)value)[0] == '/') - { - /* - * Value (incorrectly) has a leading slash already... - */ - - memcpy(resource, value, valueLen); - resource[valueLen] = '\0'; - } - else + // Use the resource path from the TXT record... + if (*resource == '/') { - /* - * Convert to resource by concatenating with a leading "/"... - */ - - resource[0] = '/'; - memcpy(resource + 1, value, valueLen); - resource[valueLen + 1] = '\0'; + // Value (incorrectly) has a leading slash already... + resource ++; } } else { - /* - * Use the default value... - */ - - cupsCopyString(resource, resdefault, sizeof(resource)); + // Use the default resource path... + resource = resdefault; } - /* - * Lookup the FQDN if needed... - */ - - if ((uribuf->options & HTTP_RESOLVE_FQDN) && - (hostptr = hostTarget + strlen(hostTarget) - 7) > hostTarget && - !_cups_strcasecmp(hostptr, ".local.")) + // Lookup the FQDN if needed... + if ((uribuf->options & HTTP_RESOLVE_FQDN) && (hostptr = host + strlen(host) - 7) > host && !_cups_strcasecmp(hostptr, ".local.")) { - /* - * OK, we got a .local name but the caller needs a real domain. Start by - * getting the IP address of the .local name and then do reverse-lookups... - */ - + // OK, we got a .local name but the caller needs a real domain. Start by + // getting the IP address of the .local name and then do reverse-lookups... http_addrlist_t *addrlist, // List of addresses *addr; // Current address - DEBUG_printf(("5http_resolve_cb: Looking up \"%s\".", hostTarget)); + DEBUG_printf(("5http_resolve_cb: Looking up \"%s\".", host)); snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port)); - if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL) + if ((addrlist = httpAddrGetList(host, AF_UNSPEC, fqdn)) != NULL) { for (addr = addrlist; addr; addr = addr->next) { @@ -2025,18 +1802,15 @@ http_resolve_cb( { DEBUG_printf(("5http_resolve_cb: Found \"%s\".", fqdn)); - if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn || - _cups_strcasecmp(hostptr, ".local")) + if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn || _cups_strcasecmp(hostptr, ".local")) { - hostTarget = fqdn; + host = fqdn; break; } } #ifdef DEBUG else - DEBUG_printf(("5http_resolve_cb: \"%s\" did not resolve: %d", - httpAddrGetString(&(addr->addr), fqdn, sizeof(fqdn)), - error)); + DEBUG_printf(("5http_resolve_cb: \"%s\" did not resolve: %d", httpAddrGetString(&(addr->addr), fqdn, sizeof(fqdn)), error)); #endif // DEBUG } @@ -2044,262 +1818,11 @@ http_resolve_cb( } } - /* - * Assemble the final device URI... - */ - - if ((!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && - !strcmp(uribuf->resource, "/cups")) - httpAssembleURIf(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme, NULL, hostTarget, ntohs(port), "%s?snmp=false", resource); + // Assemble the final URI... + if ((!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && !strcmp(uribuf->resource, "/cups")) + httpAssembleURIf(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme, NULL, host, port, "/%s?snmp=false", resource); else - httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme, NULL, hostTarget, ntohs(port), resource); + httpAssembleURIf(HTTP_URI_CODING_ALL, uribuf->buffer, uribuf->bufsize, scheme, NULL, host, port, "/%s", resource); DEBUG_printf(("5http_resolve_cb: Resolved URI is \"%s\"...", uribuf->buffer)); } - -#elif defined(HAVE_AVAHI) -/* - * 'http_poll_cb()' - Wait for input on the specified file descriptors. - * - * Note: This function is needed because avahi_simple_poll_iterate is broken - * and always uses a timeout of 0 (!) milliseconds. - * (Avahi Ticket #364) - * - * @private@ - */ - -static int // O - Number of file descriptors matching -http_poll_cb( - struct pollfd *pollfds, // I - File descriptors - unsigned int num_pollfds, // I - Number of file descriptors - int timeout, // I - Timeout in milliseconds (used) - void *context) // I - User data (unused) -{ - (void)timeout; - (void)context; - - return (poll(pollfds, num_pollfds, 2000)); -} - - -/* - * 'http_resolve_cb()' - Build a device URI for the given service name. - */ - -static void -http_resolve_cb( - AvahiServiceResolver *resolver, // I - Resolver (unused) - AvahiIfIndex interface, // I - Interface index - AvahiProtocol protocol, // I - Network protocol (unused) - AvahiResolverEvent event, // I - Event (found, etc.) - const char *name, // I - Service name - const char *type, // I - Registration type - const char *domain, // I - Domain (unused) - const char *hostTarget, // I - Hostname - const AvahiAddress *address, // I - Address (unused) - uint16_t port, // I - Port number - AvahiStringList *txt, // I - TXT record - AvahiLookupResultFlags flags, // I - Lookup flags (unused) - void *context) // I - Pointer to URI buffer -{ - _http_uribuf_t *uribuf = (_http_uribuf_t *)context; - // URI buffer - const char *scheme, // URI scheme - *hostptr, // Pointer into hostTarget - *reskey, // "rp" or "rfo" - *resdefault; // Default path - char resource[257], // Remote path - fqdn[256]; // FQDN of the .local name - char ifname[IF_NAMESIZE]; - // Interface name - AvahiStringList *pair; // Current TXT record key/value pair - char *value; // Value for "rp" key - size_t valueLen = 0; // Length of "rp" key - - - DEBUG_printf(("4http_resolve_cb(resolver=%p, " - "interface=%d, protocol=%d, event=%d, name=\"%s\", " - "type=\"%s\", domain=\"%s\", hostTarget=\"%s\", address=%p, " - "port=%d, txt=%p, flags=%d, context=%p)", - resolver, interface, protocol, event, name, type, domain, - hostTarget, address, port, txt, flags, context)); - - if (event != AVAHI_RESOLVER_FOUND) - { - avahi_service_resolver_free(resolver); - avahi_simple_poll_quit(uribuf->poll); - return; - } - - /* - * If we have a UUID, compare it... - */ - - if (uribuf->uuid && (pair = avahi_string_list_find(txt, "UUID")) != NULL) - { - char uuid[256]; // UUID value - - avahi_string_list_get_pair(pair, NULL, &value, &valueLen); - - memcpy(uuid, value, valueLen); - uuid[valueLen] = '\0'; - - avahi_free(value); - - if (_cups_strcasecmp(uuid, uribuf->uuid)) - { - DEBUG_printf(("5http_resolve_cb: Found UUID %s, looking for %s.", uuid, - uribuf->uuid)); - return; - } - } - - /* - * Figure out the scheme from the full name... - */ - - if (!strncmp(type, "_ipps.", 6) || !strncmp(type, "_ipp-tls.", 9)) - scheme = "ipps"; - else if (!strncmp(type, "_ipp.", 5) || !strncmp(type, "_fax-ipp.", 9)) - scheme = "ipp"; - else if (!strncmp(type, "_http.", 6)) - scheme = "http"; - else if (!strncmp(type, "_https.", 7)) - scheme = "https"; - else if (!strncmp(type, "_printer.", 9)) - scheme = "lpd"; - else if (!strncmp(type, "_pdl-datastream.", 16)) - scheme = "socket"; - else - { - avahi_service_resolver_free(resolver); - avahi_simple_poll_quit(uribuf->poll); - return; - } - - /* - * Extract the remote resource key from the TXT record... - */ - - if ((uribuf->options & HTTP_RESOLVE_FAXOUT) && - (!strcmp(scheme, "ipp") || !strcmp(scheme, "ipps")) && - !avahi_string_list_find(txt, "printer-type")) - { - reskey = "rfo"; - resdefault = "/ipp/faxout"; - } - else - { - reskey = "rp"; - resdefault = "/"; - } - - if ((pair = avahi_string_list_find(txt, reskey)) != NULL) - { - avahi_string_list_get_pair(pair, NULL, &value, &valueLen); - - if (value[0] == '/') - { - /* - * Value (incorrectly) has a leading slash already... - */ - - memcpy(resource, value, valueLen); - resource[valueLen] = '\0'; - } - else - { - /* - * Convert to resource by concatenating with a leading "/"... - */ - - resource[0] = '/'; - memcpy(resource + 1, value, valueLen); - resource[valueLen + 1] = '\0'; - } - - avahi_free(value); - } - else - { - /* - * Use the default value... - */ - - cupsCopyString(resource, resdefault, sizeof(resource)); - } - - /* - * Get the name of the interface this is coming from... - */ - - if (!if_indextoname((unsigned int)interface, ifname)) - { - DEBUG_printf(("Unable to find interface name for interface %d: %s\n", interface, strerror(errno))); - ifname[0] = '\0'; - } - - if (!strcmp(ifname, "lo")) - { - /* - * If this service is registered on loopback interface ("lo"), force the host - * name to "localhost"... - */ - - DEBUG_puts("Service comes from loopback interface \"lo\", setting \"localhost\" as host name."); - hostTarget = "localhost"; - } - else if ((uribuf->options & HTTP_RESOLVE_FQDN) && - (hostptr = hostTarget + strlen(hostTarget) - 6) > hostTarget && - !_cups_strcasecmp(hostptr, ".local")) - { - /* - * OK, we got a .local name but the caller needs a real domain. Start by - * getting the IP address of the .local name and then do reverse-lookups... - */ - - http_addrlist_t *addrlist, // List of addresses - *addr; // Current address - - DEBUG_printf(("5http_resolve_cb: Looking up \"%s\".", hostTarget)); - - snprintf(fqdn, sizeof(fqdn), "%d", ntohs(port)); - if ((addrlist = httpAddrGetList(hostTarget, AF_UNSPEC, fqdn)) != NULL) - { - for (addr = addrlist; addr; addr = addr->next) - { - int error = getnameinfo(&(addr->addr.addr), (socklen_t)httpAddrGetLength(&(addr->addr)), fqdn, sizeof(fqdn), NULL, 0, NI_NAMEREQD); - - if (!error) - { - DEBUG_printf(("5http_resolve_cb: Found \"%s\".", fqdn)); - - if ((hostptr = fqdn + strlen(fqdn) - 6) <= fqdn || - _cups_strcasecmp(hostptr, ".local")) - { - hostTarget = fqdn; - break; - } - } -#ifdef DEBUG - else - DEBUG_printf(("5http_resolve_cb: \"%s\" did not resolve: %d", - httpAddrGetString(&(addr->addr), fqdn, sizeof(fqdn)), - error)); -#endif // DEBUG - } - - httpAddrFreeList(addrlist); - } - } - - /* - * Assemble the final device URI using the resolved hostname... - */ - - httpAssembleURI(HTTP_URI_CODING_ALL, uribuf->buffer, (int)uribuf->bufsize, scheme, NULL, hostTarget, port, resource); - DEBUG_printf(("5http_resolve_cb: Resolved URI is \"%s\".", uribuf->buffer)); - - avahi_simple_poll_quit(uribuf->poll); -} -#endif // HAVE_MDNSRESPONDER diff --git a/xcode/libcups.xcodeproj/project.pbxproj b/xcode/libcups.xcodeproj/project.pbxproj index 111a93919..324424f01 100644 --- a/xcode/libcups.xcodeproj/project.pbxproj +++ b/xcode/libcups.xcodeproj/project.pbxproj @@ -276,6 +276,7 @@ 27D3968C27BB3972003D3D8E /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D3968227BB390D003D3D8E /* libresolv.tbd */; }; 27D3968D27BB397F003D3D8E /* libiconv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D3967E27BB38E6003D3D8E /* libiconv.tbd */; }; 27D3968E27BB3989003D3D8E /* libresolv.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 27D3968227BB390D003D3D8E /* libresolv.tbd */; }; + 27E934E028B7E951001A0EA4 /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2767FC5E1926750C000F61D3 /* SystemConfiguration.framework */; }; 720E854320164E7B00C6C411 /* ipp-file.c in Sources */ = {isa = PBXBuildFile; fileRef = 720E854120164E7A00C6C411 /* ipp-file.c */; }; 720E854420164E7B00C6C411 /* ipp-file.c in Sources */ = {isa = PBXBuildFile; fileRef = 720E854120164E7A00C6C411 /* ipp-file.c */; }; 72220EC51333056300FCA411 /* array.c in Sources */ = {isa = PBXBuildFile; fileRef = 72220EB81333056300FCA411 /* array.c */; }; @@ -1312,6 +1313,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 27E934E028B7E951001A0EA4 /* SystemConfiguration.framework in Frameworks */, 27CAFC61282C895700FE02FC /* libssl.a in Frameworks */, 27CAFC62282C895700FE02FC /* libcrypto.a in Frameworks */, 728FB7F11536167A005426E1 /* libiconv.dylib in Frameworks */, From d70251c03f7120687852bdd5d5d8b9d32c72b445 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Mon, 29 Aug 2022 18:16:55 -0400 Subject: [PATCH 16/19] Migrate cupsEnumDests to cupsDNSSD API. --- cups/dest.c | 594 ++++++++---------------------------------------- cups/dnssd.c | 42 +++- doc/cupspm.epub | Bin 225830 -> 225932 bytes doc/cupspm.html | 171 +++++++------- 4 files changed, 216 insertions(+), 591 deletions(-) diff --git a/cups/dest.c b/cups/dest.c index 8cb68438d..3fcc9d738 100644 --- a/cups/dest.c +++ b/cups/dest.c @@ -25,19 +25,7 @@ # include #endif // !_WIN32 -#ifdef HAVE_MDNSRESPONDER -# include -#endif /* HAVE_MDNSRESPONDER */ - -#ifdef HAVE_AVAHI -# include -# include -# include -# include -# include -# include -#define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX -#endif /* HAVE_AVAHI */ +#include "dnssd.h" /* @@ -57,19 +45,14 @@ # define kUseLastPrinter CFSTR("UseLastPrinter") #endif /* __APPLE__ */ -#ifdef HAVE_DNSSD -# define _CUPS_DNSSD_GET_DESTS 250 /* Milliseconds for cupsGetDests */ -# define _CUPS_DNSSD_MAXTIME 50 /* Milliseconds for maximum quantum of time */ -#else -# define _CUPS_DNSSD_GET_DESTS 0 /* Milliseconds for cupsGetDests */ -#endif /* HAVE_DNSSD */ +#define _CUPS_DNSSD_GET_DESTS 250 /* Milliseconds for cupsGetDests */ +#define _CUPS_DNSSD_MAXTIME 50 /* Milliseconds for maximum quantum of time */ /* * Types... */ -#ifdef HAVE_DNSSD typedef enum _cups_dnssd_state_e /* Enumerated device state */ { _CUPS_DNSSD_NEW, @@ -82,14 +65,8 @@ typedef enum _cups_dnssd_state_e /* Enumerated device state */ typedef struct _cups_dnssd_data_s /* Enumeration data */ { -# ifdef HAVE_MDNSRESPONDER - DNSServiceRef main_ref; /* Main service reference */ -# else /* HAVE_AVAHI */ - AvahiSimplePoll *simple_poll; /* Polling interface */ - AvahiClient *client; /* Client information */ - bool got_data; /* Did we get data? */ - size_t browsers; /* How many browsers are running? */ -# endif /* HAVE_MDNSRESPONDER */ + cups_rwlock_t rwlock; /* Reader/writer lock */ + cups_dnssd_t *dnssd; /* DNS-SD context */ cups_dest_cb_t cb; /* Callback */ void *user_data; /* User data pointer */ cups_ptype_t type, /* Printer type filter */ @@ -104,24 +81,19 @@ typedef struct _cups_dnssd_data_s /* Enumeration data */ typedef struct _cups_dnssd_device_s /* Enumerated device */ { _cups_dnssd_state_t state; /* State of device listing */ -# ifdef HAVE_MDNSRESPONDER - DNSServiceRef ref; /* Service reference for query */ -# else /* HAVE_AVAHI */ - AvahiRecordBrowser *ref; /* Browser for query */ -# endif /* HAVE_MDNSRESPONDER */ - char *fullName, /* Full name */ + cups_dnssd_query_t *query; /* DNS-SD query request */ + char *fullname, /* Full name */ *regtype, /* Registration type */ *domain; /* Domain name */ cups_ptype_t type; /* Device registration type */ cups_dest_t dest; /* Destination record */ } _cups_dnssd_device_t; -typedef struct _cups_dnssd_resolve_s /* Data for resolving URI */ +typedef struct _cups_dnssd_resdata_s /* Data for resolving URI */ { int *cancel; /* Pointer to "cancel" variable */ struct timeval end_time; /* Ending time */ -} _cups_dnssd_resolve_t; -#endif /* HAVE_DNSSD */ +} _cups_dnssd_resdata_t; typedef struct _cups_getdata_s { @@ -154,27 +126,15 @@ static CFStringRef appleGetPrinter(CFArrayRef locations, CFStringRef network, CF #endif /* _CUPS_LOCATION_DEFAULTS */ static cups_dest_t *cups_add_dest(const char *name, const char *instance, size_t *num_dests, cups_dest_t **dests); static int cups_compare_dests(cups_dest_t *a, cups_dest_t *b); -#ifdef HAVE_DNSSD -# ifdef HAVE_MDNSRESPONDER -static void cups_dnssd_browse_cb(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context); -# else /* HAVE_AVAHI */ -static void cups_dnssd_browse_cb(AvahiServiceBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *serviceName, const char *regtype, const char *replyDomain, AvahiLookupResultFlags flags, void *context); -static void cups_dnssd_client_cb(AvahiClient *client, AvahiClientState state, void *context); -# endif /* HAVE_MDNSRESPONDER */ +static void cups_dest_browse_cb(cups_dnssd_browse_t *browse, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *name, const char *regtype, const char *domain); static int cups_dnssd_compare_devices(_cups_dnssd_device_t *a, _cups_dnssd_device_t *b); static void cups_dnssd_free_device(_cups_dnssd_device_t *device, _cups_dnssd_data_t *data); static _cups_dnssd_device_t *cups_dnssd_get_device(_cups_dnssd_data_t *data, const char *serviceName, const char *regtype, const char *replyDomain); -# ifdef HAVE_MDNSRESPONDER -static void cups_dnssd_query_cb(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, void *context); -# else /* HAVE_AVAHI */ -static int cups_dnssd_poll_cb(struct pollfd *pollfds, unsigned int num_pollfds, int timeout, void *context); -static void cups_dnssd_query_cb(AvahiRecordBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, uint16_t rrclass, uint16_t rrtype, const void *rdata, size_t rdlen, AvahiLookupResultFlags flags, void *context); -# endif /* HAVE_MDNSRESPONDER */ -static const char *cups_dnssd_resolve(cups_dest_t *dest, const char *uri, int msec, int *cancel, cups_dest_cb_t cb, void *user_data); -static bool cups_dnssd_resolve_cb(void *context); +static void cups_dest_query_cb(cups_dnssd_query_t *query, void *cb_data, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen); +static const char *cups_dest_resolve(cups_dest_t *dest, const char *uri, int msec, int *cancel, cups_dest_cb_t cb, void *user_data); +static bool cups_dest_resolve_cb(void *context); static void cups_dnssd_unquote(char *dst, const char *src, size_t dstsize); static int cups_elapsed(struct timeval *t); -#endif /* HAVE_DNSSD */ static bool cups_enum_dests(http_t *http, unsigned flags, int msec, int *cancel, cups_ptype_t type, cups_ptype_t mask, cups_dest_cb_t cb, void *user_data); static size_t cups_find_dest(const char *name, const char *instance, size_t num_dests, cups_dest_t *dests, size_t prev, int *rdiff); static bool cups_get_cb(_cups_getdata_t *data, unsigned flags, cups_dest_t *dest); @@ -583,7 +543,7 @@ cupsConnectDest( { #ifdef HAVE_DNSSD if (strstr(uri, "._tcp")) - uri = cups_dnssd_resolve(dest, uri, msec, cancel, cb, user_data); + uri = cups_dest_resolve(dest, uri, msec, cancel, cb, user_data); #endif /* HAVE_DNSSD */ } } @@ -593,7 +553,7 @@ cupsConnectDest( { #ifdef HAVE_DNSSD if (strstr(uri, "._tcp")) - uri = cups_dnssd_resolve(dest, uri, msec, cancel, cb, user_data); + uri = cups_dest_resolve(dest, uri, msec, cancel, cb, user_data); #endif /* HAVE_DNSSD */ } @@ -1009,7 +969,7 @@ _cupsGetDestResource( #ifdef HAVE_DNSSD if (((flags & CUPS_DEST_FLAGS_DEVICE) || !printer_uri) && device_uri && strstr(device_uri, "._tcp")) { - if ((device_uri = cups_dnssd_resolve(dest, device_uri, 5000, NULL, NULL, NULL)) != NULL) + if ((device_uri = cups_dest_resolve(dest, device_uri, 5000, NULL, NULL, NULL)) != NULL) { DEBUG_printf(("1_cupsGetDestResource: Resolved device-uri=\"%s\".", device_uri)); } @@ -2382,34 +2342,31 @@ cups_compare_dests(cups_dest_t *a, /* I - First destination */ } -#ifdef HAVE_DNSSD -# ifdef HAVE_MDNSRESPONDER /* - * 'cups_dnssd_browse_cb()' - Browse for printers. + * 'cups_dest_browse_cb()' - Browse for printers. */ static void -cups_dnssd_browse_cb( - DNSServiceRef sdRef, /* I - Service reference */ - DNSServiceFlags flags, /* I - Option flags */ - uint32_t interfaceIndex, /* I - Interface number */ - DNSServiceErrorType errorCode, /* I - Error, if any */ +cups_dest_browse_cb( + cups_dnssd_browse_t *browse, /* I - DNS-SD browser */ + void *context, /* I - Enumeration data */ + cups_dnssd_flags_t flags, /* I - Flags */ + uint32_t if_index, /* I - Interface */ const char *serviceName, /* I - Name of service/device */ const char *regtype, /* I - Type of service */ - const char *replyDomain, /* I - Service domain */ - void *context) /* I - Enumeration data */ + const char *replyDomain) /* I - Service domain */ { _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; /* Enumeration data */ - DEBUG_printf(("5cups_dnssd_browse_cb(sdRef=%p, flags=%x, interfaceIndex=%d, errorCode=%d, serviceName=\"%s\", regtype=\"%s\", replyDomain=\"%s\", context=%p)", (void *)sdRef, flags, interfaceIndex, errorCode, serviceName, regtype, replyDomain, context)); + DEBUG_printf(("5cups_dest_browse_cb(browse=%p, context=%p, flags=%x, if_index=%d, serviceName=\"%s\", regtype=\"%s\", replyDomain=\"%s\")", (void *)browse, context, flags, if_index, serviceName, regtype, replyDomain)); /* - * Don't do anything on error... + * Don't do anything on error, only add services... */ - if (errorCode != kDNSServiceErr_NoError) + if ((flags & CUPS_DNSSD_FLAGS_ERROR) || !(flags & CUPS_DNSSD_FLAGS_ADD)) return; /* @@ -2418,97 +2375,6 @@ cups_dnssd_browse_cb( cups_dnssd_get_device(data, serviceName, regtype, replyDomain); } - - -# else /* HAVE_AVAHI */ -/* - * 'cups_dnssd_browse_cb()' - Browse for printers. - */ - -static void -cups_dnssd_browse_cb( - AvahiServiceBrowser *browser, /* I - Browser */ - AvahiIfIndex interface, /* I - Interface index (unused) */ - AvahiProtocol protocol, /* I - Network protocol (unused) */ - AvahiBrowserEvent event, /* I - What happened */ - const char *name, /* I - Service name */ - const char *type, /* I - Registration type */ - const char *domain, /* I - Domain */ - AvahiLookupResultFlags flags, /* I - Flags */ - void *context) /* I - Devices array */ -{ -#ifdef DEBUG - AvahiClient *client = avahi_service_browser_get_client(browser); - /* Client information */ -#endif /* DEBUG */ - _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; - /* Enumeration data */ - - - (void)interface; - (void)protocol; - (void)context; - - DEBUG_printf(("cups_dnssd_browse_cb(..., name=\"%s\", type=\"%s\", domain=\"%s\", ...);", name, type, domain)); - - switch (event) - { - case AVAHI_BROWSER_FAILURE: - DEBUG_printf(("cups_dnssd_browse_cb: %s", avahi_strerror(avahi_client_errno(client)))); - avahi_simple_poll_quit(data->simple_poll); - break; - - case AVAHI_BROWSER_NEW: - /* - * This object is new on the network. - */ - - cups_dnssd_get_device(data, name, type, domain); - break; - - case AVAHI_BROWSER_REMOVE : - case AVAHI_BROWSER_CACHE_EXHAUSTED : - break; - - case AVAHI_BROWSER_ALL_FOR_NOW : - DEBUG_puts("cups_dnssd_browse_cb: ALL_FOR_NOW"); - data->browsers --; - break; - } -} - - -/* - * 'cups_dnssd_client_cb()' - Avahi client callback function. - */ - -static void -cups_dnssd_client_cb( - AvahiClient *client, /* I - Client information (unused) */ - AvahiClientState state, /* I - Current state */ - void *context) /* I - User data (unused) */ -{ - _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; - /* Enumeration data */ - - - (void)client; - - DEBUG_printf(("cups_dnssd_client_cb(client=%p, state=%d, context=%p)", client, state, context)); - - /* - * If the connection drops, quit. - */ - - if (state == AVAHI_CLIENT_FAILURE) - { - DEBUG_puts("cups_dnssd_client_cb: Avahi connection failed."); - avahi_simple_poll_quit(data->simple_poll); - } -} -# endif /* HAVE_MDNSRESPONDER */ - - /* * 'cups_dnssd_compare_device()' - Compare two devices. */ @@ -2533,16 +2399,8 @@ cups_dnssd_free_device( { DEBUG_printf(("5cups_dnssd_free_device(device=%p(%s), data=%p)", (void *)device, device->dest.name, (void *)data)); -# ifdef HAVE_MDNSRESPONDER - if (device->ref) - DNSServiceRefDeallocate(device->ref); -# else /* HAVE_AVAHI */ - if (device->ref) - avahi_record_browser_free(device->ref); -# endif /* HAVE_MDNSRESPONDER */ - _cupsStrFree(device->domain); - _cupsStrFree(device->fullName); + _cupsStrFree(device->fullname); _cupsStrFree(device->regtype); _cupsStrFree(device->dest.name); @@ -2565,8 +2423,7 @@ cups_dnssd_get_device( { _cups_dnssd_device_t key, /* Search key */ *device; /* Device */ - char fullName[kDNSServiceMaxDomainName], - /* Full name for query */ + char fullname[1024], /* Full name for query */ name[128]; /* Queue name */ @@ -2580,7 +2437,13 @@ cups_dnssd_get_device( key.dest.name = name; - if ((device = cupsArrayFind(data->devices, &key)) != NULL) + cupsRWLockRead(&data->rwlock); + + device = cupsArrayFind(data->devices, &key); + + cupsRWUnlock(&data->rwlock); + + if (device) { /* * Yes, see if we need to do anything with this... @@ -2588,8 +2451,7 @@ cups_dnssd_get_device( int update = 0; /* Non-zero if we need to update */ - if (!_cups_strcasecmp(replyDomain, "local.") && - _cups_strcasecmp(device->domain, replyDomain)) + if (!_cups_strcasecmp(replyDomain, "local.") && _cups_strcasecmp(device->domain, replyDomain)) { /* * Update the "global" listing to use the .local domain name instead. @@ -2604,8 +2466,7 @@ cups_dnssd_get_device( update = 1; } - if (!_cups_strcasecmp(regtype, "_ipps._tcp") && - _cups_strcasecmp(device->regtype, regtype)) + if (!_cups_strcasecmp(regtype, "_ipps._tcp") && _cups_strcasecmp(device->regtype, regtype)) { /* * Prefer IPPS over IPP. @@ -2647,32 +2508,21 @@ cups_dnssd_get_device( device->dest.num_options = cupsAddOption("printer-info", serviceName, 0, &device->dest.options); + cupsRWLockWrite(&data->rwlock); cupsArrayAdd(data->devices, device); + cupsRWUnlock(&data->rwlock); } /* * Set the "full name" of this service, which is used for queries... */ -# ifdef HAVE_MDNSRESPONDER - DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain); -# else /* HAVE_AVAHI */ - avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName, regtype, replyDomain); -# endif /* HAVE_MDNSRESPONDER */ - - _cupsStrFree(device->fullName); - device->fullName = _cupsStrAlloc(fullName); + cupsDNSSDAssembleFullName(fullname, sizeof(fullname), serviceName, regtype, replyDomain); + _cupsStrFree(device->fullname); + device->fullname = _cupsStrAlloc(fullname); - if (device->ref) - { -# ifdef HAVE_MDNSRESPONDER - DNSServiceRefDeallocate(device->ref); -# else /* HAVE_AVAHI */ - avahi_record_browser_free(device->ref); -# endif /* HAVE_MDNSRESPONDER */ - - device->ref = 0; - } + cupsDNSSDQueryDelete(device->query); + device->query = NULL; if (device->state == _CUPS_DNSSD_ACTIVE) { @@ -2686,87 +2536,21 @@ cups_dnssd_get_device( } -# ifdef HAVE_AVAHI -/* - * 'cups_dnssd_poll_cb()' - Wait for input on the specified file descriptors. - * - * Note: This function is needed because avahi_simple_poll_iterate is broken - * and always uses a timeout of 0 (!) milliseconds. - * (https://github.com/lathiat/avahi/issues/127) - * - * @private@ - */ - -static int /* O - Number of file descriptors matching */ -cups_dnssd_poll_cb( - struct pollfd *pollfds, /* I - File descriptors */ - unsigned int num_pollfds, /* I - Number of file descriptors */ - int timeout, /* I - Timeout in milliseconds (unused) */ - void *context) /* I - User data (unused) */ -{ - _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; - /* Enumeration data */ - int val; /* Return value */ - - - DEBUG_printf(("cups_dnssd_poll_cb(pollfds=%p, num_pollfds=%d, timeout=%d, context=%p)", pollfds, num_pollfds, timeout, context)); - - (void)timeout; - - val = poll(pollfds, num_pollfds, _CUPS_DNSSD_MAXTIME); - - DEBUG_printf(("cups_dnssd_poll_cb: poll() returned %d", val)); - - if (val < 0) - { - DEBUG_printf(("cups_dnssd_poll_cb: %s", strerror(errno))); - } - else if (val > 0) - { - data->got_data = true; - } - - return (val); -} -# endif /* HAVE_AVAHI */ - - /* - * 'cups_dnssd_query_cb()' - Process query data. + * 'cups_dest_query_cb()' - Process query data. */ static void -cups_dnssd_query_cb( -# ifdef HAVE_MDNSRESPONDER - DNSServiceRef sdRef, /* I - Service reference */ - DNSServiceFlags flags, /* I - Data flags */ - uint32_t interfaceIndex, /* I - Interface */ - DNSServiceErrorType errorCode, /* I - Error, if any */ - const char *fullName, /* I - Full service name */ +cups_dest_query_cb( + cups_dnssd_query_t *query, /* I - Query request */ + void *context, /* I - Enumeration data */ + cups_dnssd_flags_t flags, /* I - DNS-SD flags */ + uint32_t if_index, /* I - Interface */ + const char *fullname, /* I - Full service name */ uint16_t rrtype, /* I - Record type */ - uint16_t rrclass, /* I - Record class */ - uint16_t rdlen, /* I - Length of record data */ const void *rdata, /* I - Record data */ - uint32_t ttl, /* I - Time-to-live */ -# else /* HAVE_AVAHI */ - AvahiRecordBrowser *browser, /* I - Record browser */ - AvahiIfIndex interfaceIndex, - /* I - Interface index (unused) */ - AvahiProtocol protocol, /* I - Network protocol (unused) */ - AvahiBrowserEvent event, /* I - What happened? */ - const char *fullName, /* I - Service name */ - uint16_t rrclass, /* I - Record class */ - uint16_t rrtype, /* I - Record type */ - const void *rdata, /* I - TXT record */ - size_t rdlen, /* I - Length of TXT record */ - AvahiLookupResultFlags flags, /* I - Flags */ -# endif /* HAVE_MDNSRESPONDER */ - void *context) /* I - Enumeration data */ + uint16_t rdlen) /* I - Length of record data */ { -# if defined(DEBUG) && defined(HAVE_AVAHI) - AvahiClient *client = avahi_record_browser_get_client(browser); - /* Client information */ -# endif /* DEBUG && HAVE_AVAHI */ _cups_dnssd_data_t *data = (_cups_dnssd_data_t *)context; /* Enumeration data */ char serviceName[256],/* Service name */ @@ -2776,37 +2560,22 @@ cups_dnssd_query_cb( *device; /* Device */ -# ifdef HAVE_MDNSRESPONDER - DEBUG_printf(("5cups_dnssd_query_cb(sdRef=%p, flags=%x, interfaceIndex=%d, errorCode=%d, fullName=\"%s\", rrtype=%u, rrclass=%u, rdlen=%u, rdata=%p, ttl=%u, context=%p)", (void *)sdRef, flags, interfaceIndex, errorCode, fullName, rrtype, rrclass, rdlen, rdata, ttl, context)); - - /* - * Only process "add" data... - */ - - if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) - return; - -# else /* HAVE_AVAHI */ - DEBUG_printf(("cups_dnssd_query_cb(browser=%p, interfaceIndex=%d, protocol=%d, event=%d, fullName=\"%s\", rrclass=%u, rrtype=%u, rdata=%p, rdlen=%u, flags=%x, context=%p)", browser, interfaceIndex, protocol, event, fullName, rrclass, rrtype, rdata, (unsigned)rdlen, flags, context)); + (void)query; + (void)if_index; + (void)rrtype; /* * Only process "add" data... */ - if (event != AVAHI_BROWSER_NEW) - { - if (event == AVAHI_BROWSER_FAILURE) - DEBUG_printf(("cups_dnssd_query_cb: %s", avahi_strerror(avahi_client_errno(client)))); - + if (!(flags & CUPS_DNSSD_FLAGS_ADD) || (flags & CUPS_DNSSD_FLAGS_ERROR)) return; - } -# endif /* HAVE_MDNSRESPONDER */ /* * Lookup the service in the devices array. */ - cups_dnssd_unquote(serviceName, fullName, sizeof(serviceName)); + cups_dnssd_unquote(serviceName, fullname, sizeof(serviceName)); if ((ptr = strstr(serviceName, "._")) != NULL) *ptr = '\0'; @@ -2871,11 +2640,11 @@ cups_dnssd_query_cb( memcpy(value, txt, (size_t)(txtnext - txt)); value[txtnext - txt] = '\0'; - DEBUG_printf(("6cups_dnssd_query_cb: %s=%s", key, value)); + DEBUG_printf(("6cups_dest_query_cb: %s=%s", key, value)); } else { - DEBUG_printf(("6cups_dnssd_query_cb: '%s' with no value.", key)); + DEBUG_printf(("6cups_dest_query_cb: '%s' with no value.", key)); continue; } @@ -3025,7 +2794,7 @@ cups_dnssd_query_cb( * Save the URI... */ - cups_dnssd_unquote(uriname, device->fullName, sizeof(uriname)); + cups_dnssd_unquote(uriname, device->fullname, sizeof(uriname)); httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), !strcmp(device->regtype, "_ipps._tcp") ? "ipps" : "ipp", NULL, uriname, 0, saw_printer_type ? "/cups" : "/"); @@ -3036,16 +2805,16 @@ cups_dnssd_query_cb( } else DEBUG_printf(("6cups_dnssd_query: Ignoring TXT record for '%s'.", - fullName)); + fullname)); } /* - * 'cups_dnssd_resolve()' - Resolve a Bonjour printer URI. + * 'cups_dest_resolve()' - Resolve a Bonjour printer URI. */ static const char * /* O - Resolved URI or NULL */ -cups_dnssd_resolve( +cups_dest_resolve( cups_dest_t *dest, /* I - Destination */ const char *uri, /* I - Current printer URI */ int msec, /* I - Time in milliseconds */ @@ -3054,7 +2823,7 @@ cups_dnssd_resolve( void *user_data) /* I - User data for callback */ { char tempuri[1024]; /* Temporary URI buffer */ - _cups_dnssd_resolve_t resolve; /* Resolve data */ + _cups_dnssd_resdata_t resolve; /* Resolve data */ /* @@ -3080,7 +2849,7 @@ cups_dnssd_resolve( if (cb) (*cb)(user_data, CUPS_DEST_FLAGS_UNCONNECTED | CUPS_DEST_FLAGS_RESOLVING, dest); - if ((uri = httpResolveURI(uri, tempuri, sizeof(tempuri), HTTP_RESOLVE_DEFAULT, cups_dnssd_resolve_cb, &resolve)) == NULL) + if ((uri = httpResolveURI(uri, tempuri, sizeof(tempuri), HTTP_RESOLVE_DEFAULT, cups_dest_resolve_cb, &resolve)) == NULL) { _cupsSetError(IPP_STATUS_ERROR_INTERNAL, _("Unable to resolve printer-uri."), 1); @@ -3101,13 +2870,13 @@ cups_dnssd_resolve( /* - * 'cups_dnssd_resolve_cb()' - See if we should continue resolving. + * 'cups_dest_resolve_cb()' - See if we should continue resolving. */ static bool /* O - `true` to continue, `false` to stop */ -cups_dnssd_resolve_cb(void *context) /* I - Resolve data */ +cups_dest_resolve_cb(void *context) /* I - Resolve data */ { - _cups_dnssd_resolve_t *resolve = (_cups_dnssd_resolve_t *)context; + _cups_dnssd_resdata_t *resolve = (_cups_dnssd_resdata_t *)context; /* Resolve data */ struct timeval curtime; /* Current time */ @@ -3118,7 +2887,7 @@ cups_dnssd_resolve_cb(void *context) /* I - Resolve data */ if (resolve->cancel && *(resolve->cancel)) { - DEBUG_puts("4cups_dnssd_resolve_cb: Canceled."); + DEBUG_puts("4cups_dest_resolve_cb: Canceled."); return (false); } @@ -3128,7 +2897,7 @@ cups_dnssd_resolve_cb(void *context) /* I - Resolve data */ gettimeofday(&curtime, NULL); - DEBUG_printf(("4cups_dnssd_resolve_cb: curtime=%d.%06d, end_time=%d.%06d", (int)curtime.tv_sec, (int)curtime.tv_usec, (int)resolve->end_time.tv_sec, (int)resolve->end_time.tv_usec)); + DEBUG_printf(("4cups_dest_resolve_cb: curtime=%d.%06d, end_time=%d.%06d", (int)curtime.tv_sec, (int)curtime.tv_usec, (int)resolve->end_time.tv_sec, (int)resolve->end_time.tv_usec)); return (curtime.tv_sec < resolve->end_time.tv_sec || (curtime.tv_sec == resolve->end_time.tv_sec && curtime.tv_usec < resolve->end_time.tv_usec)); } @@ -3187,7 +2956,6 @@ cups_elapsed(struct timeval *t) /* IO - Previous time */ return (msecs); } -#endif /* HAVE_DNSSD */ /* @@ -3206,36 +2974,19 @@ cups_enum_dests( void *user_data) /* I - User data */ { size_t i, j, k, /* Looping vars */ - num_dests; /* Number of destinations */ + num_dests, /* Number of destinations */ + num_devices; /* Number of devices */ cups_dest_t *dests = NULL, /* Destinations */ *dest; /* Current destination */ cups_option_t *option; /* Current option */ const char *user_default; /* Default printer from environment */ -#ifdef HAVE_DNSSD size_t count, /* Number of queries started */ completed; /* Number of completed queries */ int remaining; /* Remainder of timeout */ struct timeval curtime; /* Current time */ _cups_dnssd_data_t data; /* Data for callback */ _cups_dnssd_device_t *device; /* Current device */ -# ifdef HAVE_MDNSRESPONDER - int nfds, /* Number of files responded */ - main_fd; /* File descriptor for lookups */ - DNSServiceRef ipp_ref = NULL; /* IPP browser */ -# ifdef HAVE_TLS - DNSServiceRef ipps_ref = NULL; /* IPPS browser */ -# endif /* HAVE_TLS */ - struct pollfd pfd; /* Polling data */ -# else /* HAVE_AVAHI */ - int error; /* Error value */ - AvahiServiceBrowser *ipp_ref = NULL; /* IPP browser */ -# ifdef HAVE_TLS - AvahiServiceBrowser *ipps_ref = NULL; /* IPPS browser */ -# endif /* HAVE_TLS */ -# endif /* HAVE_MDNSRESPONDER */ -#else - _cups_getdata_t data; /* Data for callback */ -#endif /* HAVE_DNSSD */ + cups_dnssd_t *dnssd = NULL; /* DNS-SD context */ char filename[1024]; /* Local lpoptions file */ _cups_globals_t *cg = _cupsGlobals(); /* Pointer to library globals */ @@ -3311,13 +3062,13 @@ cups_enum_dests( * Get ready to enumerate... */ -#ifdef HAVE_DNSSD + cupsRWInit(&data.rwlock); + data.type = type; data.mask = mask; data.cb = cb; data.user_data = user_data; data.devices = cupsArrayNew((cups_array_cb_t)cups_dnssd_compare_devices, NULL, NULL, 0, NULL, (cups_afree_cb_t)cups_dnssd_free_device); -#endif /* HAVE_DNSSD */ if (!(mask & CUPS_PRINTER_DISCOVERED) || !(type & CUPS_PRINTER_DISCOVERED)) { @@ -3343,9 +3094,7 @@ cups_enum_dests( for (i = num_dests, dest = dests; i > 0 && (!cancel || !*cancel); i --, dest ++) { cups_dest_t *user_dest; /* Destination from lpoptions */ -#ifdef HAVE_DNSSD const char *device_uri; /* Device URI */ -#endif /* HAVE_DNSSD */ if ((user_dest = cupsGetDest(dest->name, NULL, data.num_dests, data.dests)) != NULL) { @@ -3374,7 +3123,6 @@ cups_enum_dests( else if (!(*cb)(user_data, i > 1 ? CUPS_DEST_FLAGS_MORE : CUPS_DEST_FLAGS_NONE, dest)) break; -#ifdef HAVE_DNSSD if (!dest->instance && (device_uri = cupsGetOption("device-uri", dest->num_options, dest->options)) != NULL && !strncmp(device_uri, "dnssd://", 8)) { /* @@ -3406,7 +3154,6 @@ cups_enum_dests( } } } -#endif /* HAVE_DNSSD */ } cupsFreeDests(num_dests, dests); @@ -3422,15 +3169,13 @@ cups_enum_dests( if ((mask & CUPS_PRINTER_DISCOVERED) && !(type & CUPS_PRINTER_DISCOVERED)) goto enum_finished; -#ifdef HAVE_DNSSD /* - * Get Bonjour-shared printers... + * Get DNS-SD printers... */ gettimeofday(&curtime, NULL); -# ifdef HAVE_MDNSRESPONDER - if (DNSServiceCreateConnection(&data.main_ref) != kDNSServiceErr_NoError) + if ((dnssd = cupsDNSSDNew(NULL, NULL)) == NULL) { DEBUG_puts("1cups_enum_dests: Unable to create service browser, returning 0."); @@ -3440,13 +3185,10 @@ cups_enum_dests( return (false); } - main_fd = DNSServiceRefSockFD(data.main_ref); - - ipp_ref = data.main_ref; - if (DNSServiceBrowse(&ipp_ref, kDNSServiceFlagsShareConnection, 0, "_ipp._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data) != kDNSServiceErr_NoError) + if (!cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipp._tcp", /*domain*/NULL, cups_dest_browse_cb, &data)) { DEBUG_puts("1cups_enum_dests: Unable to create IPP browser, returning 0."); - DNSServiceRefDeallocate(data.main_ref); + cupsDNSSDDelete(dnssd); cupsFreeDests(data.num_dests, data.dests); cupsArrayDelete(data.devices); @@ -3454,76 +3196,16 @@ cups_enum_dests( return (false); } -# ifdef HAVE_TLS - ipps_ref = data.main_ref; - if (DNSServiceBrowse(&ipps_ref, kDNSServiceFlagsShareConnection, 0, "_ipps._tcp", NULL, (DNSServiceBrowseReply)cups_dnssd_browse_cb, &data) != kDNSServiceErr_NoError) + if (!cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, "_ipps._tcp", /*domain*/NULL, cups_dest_browse_cb, &data)) { DEBUG_puts("1cups_enum_dests: Unable to create IPPS browser, returning 0."); - DNSServiceRefDeallocate(data.main_ref); + cupsDNSSDDelete(dnssd); cupsFreeDests(data.num_dests, data.dests); cupsArrayDelete(data.devices); return (false); } -# endif /* HAVE_TLS */ - -# else /* HAVE_AVAHI */ - if ((data.simple_poll = avahi_simple_poll_new()) == NULL) - { - DEBUG_puts("1cups_enum_dests: Unable to create Avahi poll, returning 0."); - - cupsFreeDests(data.num_dests, data.dests); - cupsArrayDelete(data.devices); - - return (false); - } - - avahi_simple_poll_set_func(data.simple_poll, cups_dnssd_poll_cb, &data); - - data.client = avahi_client_new(avahi_simple_poll_get(data.simple_poll), 0, cups_dnssd_client_cb, &data, &error); - if (!data.client) - { - DEBUG_puts("1cups_enum_dests: Unable to create Avahi client, returning 0."); - avahi_simple_poll_free(data.simple_poll); - - cupsFreeDests(data.num_dests, data.dests); - cupsArrayDelete(data.devices); - - return (false); - } - - data.browsers = 1; - if ((ipp_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipp._tcp", NULL, 0, cups_dnssd_browse_cb, &data)) == NULL) - { - DEBUG_puts("1cups_enum_dests: Unable to create Avahi IPP browser, returning 0."); - - avahi_client_free(data.client); - avahi_simple_poll_free(data.simple_poll); - - cupsFreeDests(data.num_dests, data.dests); - cupsArrayDelete(data.devices); - - return (false); - } - -# ifdef HAVE_TLS - data.browsers ++; - if ((ipps_ref = avahi_service_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_ipps._tcp", NULL, 0, cups_dnssd_browse_cb, &data)) == NULL) - { - DEBUG_puts("1cups_enum_dests: Unable to create Avahi IPPS browser, returning 0."); - - avahi_service_browser_free(ipp_ref); - avahi_client_free(data.client); - avahi_simple_poll_free(data.simple_poll); - - cupsFreeDests(data.num_dests, data.dests); - cupsArrayDelete(data.devices); - - return (false); - } -# endif /* HAVE_TLS */ -# endif /* HAVE_MDNSRESPONDER */ if (msec < 0) remaining = INT_MAX; @@ -3540,87 +3222,40 @@ cups_enum_dests( cups_elapsed(&curtime); -# ifdef HAVE_MDNSRESPONDER - pfd.fd = main_fd; - pfd.events = POLLIN; - - if ((nfds = poll(&pfd, 1, remaining > _CUPS_DNSSD_MAXTIME ? _CUPS_DNSSD_MAXTIME : remaining)) > 0) - DNSServiceProcessResult(data.main_ref); -# ifdef _WIN32 - else if (nfds < 0 && WSAGetLastError() != WSAEINTR && WSAGetLastError() != WSAEWOULDBLOCK) - break; -# else - else if (nfds < 0 && errno != EINTR && errno != EAGAIN) - break; -# endif /* _WIN32 */ + remaining -= cups_elapsed(&curtime); -# else /* HAVE_AVAHI */ - data.got_data = false; + cupsRWLockRead(&data.rwlock); - if ((error = avahi_simple_poll_iterate(data.simple_poll, _CUPS_DNSSD_MAXTIME)) > 0) + for (i = 0, num_devices = cupsArrayGetCount(data.devices), count = 0, completed = 0; i < num_devices; i ++) { - /* - * We've been told to exit the loop. Perhaps the connection to - * Avahi failed. - */ - - break; - } - - DEBUG_printf(("1cups_enum_dests: got_data=%s", data.got_data ? "true" : "false")); -# endif /* HAVE_MDNSRESPONDER */ - - remaining -= cups_elapsed(&curtime); + device = cupsArrayGetElement(data.devices, i); - for (device = (_cups_dnssd_device_t *)cupsArrayGetFirst(data.devices), - count = 0, completed = 0; - device; - device = (_cups_dnssd_device_t *)cupsArrayGetNext(data.devices)) - { - if (device->ref) + if (device->query) count ++; if (device->state == _CUPS_DNSSD_ACTIVE) completed ++; - if (!device->ref && device->state == _CUPS_DNSSD_NEW) + if (!device->query && device->state == _CUPS_DNSSD_NEW) { - DEBUG_printf(("1cups_enum_dests: Querying '%s'.", device->fullName)); - -# ifdef HAVE_MDNSRESPONDER - device->ref = data.main_ref; + DEBUG_printf(("1cups_enum_dests: Querying '%s'.", device->fullname)); - if (DNSServiceQueryRecord(&(device->ref), kDNSServiceFlagsShareConnection, 0, device->fullName, kDNSServiceType_TXT, kDNSServiceClass_IN, (DNSServiceQueryRecordReply)cups_dnssd_query_cb, &data) == kDNSServiceErr_NoError) + if ((device->query = cupsDNSSDQueryNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, device->fullname, CUPS_DNSSD_RRTYPE_TXT, cups_dest_query_cb, &data)) != NULL) { count ++; } else { - device->ref = 0; device->state = _CUPS_DNSSD_ERROR; DEBUG_puts("1cups_enum_dests: Query failed."); } - -# else /* HAVE_AVAHI */ - if ((device->ref = avahi_record_browser_new(data.client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, device->fullName, AVAHI_DNS_CLASS_IN, AVAHI_DNS_TYPE_TXT, 0, cups_dnssd_query_cb, &data)) != NULL) - { - DEBUG_printf(("1cups_enum_dests: Query ref=%p", device->ref)); - count ++; - } - else - { - device->state = _CUPS_DNSSD_ERROR; - - DEBUG_printf(("1cups_enum_dests: Query failed: %s", avahi_strerror(avahi_client_errno(data.client)))); - } -# endif /* HAVE_MDNSRESPONDER */ } - else if (device->ref && device->state == _CUPS_DNSSD_PENDING) + else if (device->query && device->state == _CUPS_DNSSD_PENDING) { completed ++; - DEBUG_printf(("1cups_enum_dests: Query for \"%s\" is complete.", device->fullName)); + DEBUG_printf(("1cups_enum_dests: Query for \"%s\" is complete.", device->fullname)); if ((device->type & mask) == type) { @@ -3676,19 +3311,15 @@ cups_enum_dests( } } -# ifdef HAVE_AVAHI - DEBUG_printf(("1cups_enum_dests: remaining=%d, browsers=%u, completed=%u, count=%u, devices count=%u", remaining, (unsigned)data.browsers, (unsigned)completed, (unsigned)count, (unsigned)cupsArrayGetCount(data.devices))); - - if (data.browsers == 0 && completed == cupsArrayGetCount(data.devices)) - break; -# else DEBUG_printf(("1cups_enum_dests: remaining=%d, completed=%u, count=%u, devices count=%u", remaining, (unsigned)completed, (unsigned)count, (unsigned)cupsArrayGetCount(data.devices))); - if (completed == cupsArrayGetCount(data.devices)) + cupsRWUnlock(&data.rwlock); + + if (completed && completed == cupsArrayGetCount(data.devices)) break; -# endif /* HAVE_AVAHI */ + + usleep(100000); } -#endif /* HAVE_DNSSD */ /* * Return... @@ -3696,39 +3327,12 @@ cups_enum_dests( enum_finished: - cupsFreeDests(data.num_dests, data.dests); + cupsDNSSDDelete(dnssd); -#ifdef HAVE_DNSSD + cupsFreeDests(data.num_dests, data.dests); cupsArrayDelete(data.devices); -# ifdef HAVE_MDNSRESPONDER - if (ipp_ref) - DNSServiceRefDeallocate(ipp_ref); - -# ifdef HAVE_TLS - if (ipps_ref) - DNSServiceRefDeallocate(ipps_ref); -# endif /* HAVE_TLS */ - - if (data.main_ref) - DNSServiceRefDeallocate(data.main_ref); - -# else /* HAVE_AVAHI */ - if (ipp_ref) - avahi_service_browser_free(ipp_ref); -# ifdef HAVE_TLS - if (ipps_ref) - avahi_service_browser_free(ipps_ref); -# endif /* HAVE_TLS */ - - if (data.client) - avahi_client_free(data.client); - if (data.simple_poll) - avahi_simple_poll_free(data.simple_poll); -# endif /* HAVE_MDNSRESPONDER */ -#endif /* HAVE_DNSSD */ - - DEBUG_puts("1cups_enum_dests: Returning 1."); + DEBUG_puts("1cups_enum_dests: Returning true."); return (true); } diff --git a/cups/dnssd.c b/cups/dnssd.c index 0644889d2..04780b21a 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -631,11 +631,16 @@ cupsDNSSDBrowseGetContext( // // ``` // void -// browse_cb(cups_dnssd_browse_t *browse, void *cb_data, -// cups_dnssd_flags_t flags, uint32_t if_index, -// const char *name, const char *regtype, const char *domain) +// browse_cb( +// cups_dnssd_browse_t *browse, +// void *cb_data, +// cups_dnssd_flags_t flags, +// uint32_t if_index, +// const char *name, +// const char *regtype, +// const char *domain) // { -// // Process added/removed service +// // Process added/removed service // } // ``` // @@ -758,11 +763,17 @@ cupsDNSSDQueryGetContext( // // ``` // void -// query_cb(cups_dnssd_query_t *query, void *cb_data, -// cups_dnssd_flags_t flags, uint32_t if_index, -// const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen) +// query_cb( +// cups_dnssd_query_t *query, +// void *cb_data, +// cups_dnssd_flags_t flags, +// uint32_t if_index, +// const char *fullname, +// uint16_t rrtype, +// const void *qdata, +// uint16_t qlen) // { -// // Process query record +// // Process query record // } // ``` // @@ -884,11 +895,18 @@ cupsDNSSDResolveGetContext( // // ``` // void -// resolve_cb(cups_dnssd_resolve_t *resolve, void *cb_data, -// cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname, -// const char *host, uint16_t port, size_t num_txt, cups_option_t *txt) +// resolve_cb( +// cups_dnssd_resolve_t *resolve, +// void *cb_data, +// cups_dnssd_flags_t flags, +// uint32_t if_index, +// const char *fullname, +// const char *host, +// uint16_t port, +// size_t num_txt, +// cups_option_t *txt) // { -// // Process resolved service +// // Process resolved service // } // ``` // diff --git a/doc/cupspm.epub b/doc/cupspm.epub index 371ac47bf01acf840c59389af92eecebb06d7188..36d082898917b9af63303ca7171586247c4814fd 100644 GIT binary patch delta 74410 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 delta 74234 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 z89?!WoFContents
  • cups_password_cb_t
  • cups_ptype_t
  • -
  • cups_raster_cb_t
  • cups_raster_mode_t
  • cups_raster_t
  • cups_rwlock_t
  • @@ -2107,9 +2106,10 @@

    Discussion

    int // Return -1 if a < b, 0 if a == b, and 1 if a > b compare_cb(void *a, void *b, void *d) { -... "a" and "b" are the elements, "d" is the user data pointer + ... "a" and "b" are the elements, "d" is the user data pointer }
  • cups_page_header_t
  • + The hash callback function ("hf") is used to implement cached lookups with the specified hash size ("hsize"). The function receives a pointer to an element and the user data pointer ("d") and returns an unsigned integer @@ -2120,9 +2120,10 @@

    Discussion

    size_t // Return hash value from 0 to (hashsize - 1) hash_cb(void *e, void *d) { -... "e" is the element, "d" is the user data pointer + ... "e" is the element, "d" is the user data pointer } + The copy callback function ("cf") is used to automatically copy/retain elements when added to the array or the array is copied with cupsArrayDup. The function receives a pointer to the element and the @@ -2132,9 +2133,10 @@

    Discussion

    void * // Return pointer to copied/retained element or NULL copy_cb(void *e, void *d) { -... "e" is the element, "d" is the user data pointer + ... "e" is the element, "d" is the user data pointer } + Finally, the free callback function ("cf") is used to automatically free/release elements when removed or the array is deleted. The function receives a pointer to the element and the user data pointer ("d"). @@ -2143,9 +2145,9 @@

    Discussion

    void free_cb(void *e, void *d) { -... "e" is the element, "d" is the user data pointer + ... "e" is the element, "d" is the user data pointer } -``` +

    cupsArrayNewStrings

    Create a new array of delimited strings.

    @@ -2253,7 +2255,7 @@

    Return Value

    Count or -1 on error

    cupsCheckDestSupported

    Check that the option and value are supported -by the destination.

    + by the destination.

    bool cupsCheckDestSupported(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option, const char *value);

    Parameters

    @@ -2406,7 +2408,7 @@

    Discussion

    responsible for calling cupsFreeDests on the returned object(s).

    cupsCopyDestConflicts

    Get conflicts and resolutions for a new -option/value pair.

    + option/value pair.

    int cupsCopyDestConflicts(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, size_t num_options, cups_option_t *options, const char *new_option, const char *new_value, size_t *num_conflicts, cups_option_t **conflicts, size_t *num_resolved, cups_option_t **resolved);

    Parameters

    @@ -2453,7 +2455,7 @@

    Discussion

    to 0 and NULL, respectively, then the conflict cannot be resolved.

    cupsCopyDestInfo

    Get the supported values/capabilities for the -destination.

    + destination.

    cups_dinfo_t *cupsCopyDestInfo(http_t *http, cups_dest_t *dest);

    Parameters

    @@ -2511,7 +2513,7 @@

    Discussion

    in the variable pointed to by "job_id".

    cupsDNSSDAssembleFullName

    Create a full service name from the instance -name, registration type, and domain.

    + name, registration type, and domain.

    bool cupsDNSSDAssembleFullName(char *fullname, size_t fullsize, const char *name, const char *type, const char *domain);

    Parameters

    @@ -2587,15 +2589,19 @@

    Discussion

     void
    -browse_cb(cups_dnssd_browse_t *browse, void *cb_data,
    -cups_dnssd_flags_t flags, uint32_t if_index,
    -const char *name, const char *regtype, const char *domain)
    +browse_cb(
    +    cups_dnssd_browse_t *browse,
    +    void                *cb_data,
    +    cups_dnssd_flags_t  flags,
    +    uint32_t            if_index,
    +    const char          *name,
    +    const char          *regtype,
    +    const char          *domain)
     {
    -// Process added/removed service
    +    // Process added/removed service
     }
    -```
    -gned integer -representing a hash into the array. The hash value is of type size_t

    + +

    cupsDNSSDDecodeTXT

    Decode a TXT record into key/value pairs.

    @@ -2626,7 +2632,7 @@

    Parameters

    cupsDNSSDGetConfigChanges

    Get the number of host name/network -configuration changes seen.

    + configuration changes seen.

    size_t cupsDNSSDGetConfigChanges(cups_dnssd_t *dnssd);

    Parameters

    @@ -2729,19 +2735,20 @@

    Discussion

     void
    -query_cb(cups_dnssd_query_t *query, void *cb_data,
    -cups_dnssd_flags_t flags, uint32_t if_index,
    -const char *fullname, uint16_t rrtype, const void *qdata, uint16_t qlen)
    +query_cb(
    +    cups_dnssd_query_t *query,
    +    void               *cb_data,
    +    cups_dnssd_flags_t flags,
    +    uint32_t           if_index,
    +    const char         *fullname,
    +    uint16_t           rrtype,
    +    const void         *qdata,
    +    uint16_t           qlen)
     {
    -// Process query record
    +    // Process query record
     }
    -```
    -lags_t flags, uint32_t if_index, -const char name, const char regtype, const char *domain) -{ -// Process added/removed service -} -`

    + +

    cupsDNSSDResolveDelete

    Cancel and free a resolve request.

    @@ -2794,21 +2801,24 @@

    Discussion

     void
    -resolve_cb(cups_dnssd_resolve_t *resolve, void *cb_data,
    -cups_dnssd_flags_t flags, uint32_t if_index, const char *fullname,
    -const char *host, uint16_t port, size_t num_txt, cups_option_t *txt)
    +resolve_cb(
    +    cups_dnssd_resolve_t *resolve,
    +    void                 *cb_data,
    +    cups_dnssd_flags_t   flags,
    +    uint32_t             if_index,
    +    const char           *fullname,
    +    const char           *host,
    +    uint16_t             port,
    +    size_t               num_txt,
    +    cups_option_t        *txt)
     {
    -// Process resolved service
    +    // Process resolved service
     }
    -```
    - *qdata, uint16_t qlen) -{ -// Process query record -} -`

    + +

    cupsDNSSDSeparateFullName

    Separate a full service name into an instance -name, registration type, and domain.

    + name, registration type, and domain.

    bool cupsDNSSDSeparateFullName(const char *fullname, char *name, size_t namesize, char *type, size_t typesize, char *domain, size_t domainsize);

    Parameters

    @@ -2876,7 +2886,7 @@

    Parameters

    cupsDNSSDServiceGetContext

    Get the DNS-SD context for the service -registration.

    + registration.

    cups_dnssd_t *cupsDNSSDServiceGetContext(cups_dnssd_service_t *service);

    Parameters

    @@ -2942,7 +2952,7 @@

    Discussion

    cupsDNSSDServiceAdd function.

    cupsDNSSDServiceSetLocation

    Set the geolocation (LOC record) of a -service.

    + service.

    bool cupsDNSSDServiceSetLocation(cups_dnssd_service_t *service, const char *geo_uri);

    Parameters

    @@ -3252,7 +3262,7 @@

    Return Value

    Line read or NULL on end of file or error

    cupsFileGetLine

    Get a CR and/or LF-terminated line that may -contain binary data.

    + contain binary data.

    size_t cupsFileGetLine(cups_file_t *fp, char *buf, size_t buflen);

    Parameters

    @@ -3620,7 +3630,7 @@

    Discussion

    Returns IPP_STATUS_OK or IPP_STATUS_OK_SUBST on success.

    cupsFreeDestInfo

    Free destination information obtained using -cupsCopyDestInfo.

    + cupsCopyDestInfo.

    void cupsFreeDestInfo(cups_dinfo_t *dinfo);

    Parameters

    @@ -3702,7 +3712,7 @@

    Discussion

    supported destinations for the current user.

    cupsGetDestMediaByIndex

    Get a media name, dimension, and margins for a -specific size.

    + specific size.

    bool cupsGetDestMediaByIndex(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, size_t n, unsigned flags, cups_size_t *size);

    Parameters

    @@ -3761,7 +3771,7 @@

    Discussion

  • CUPS_MEDIA_FLAGS_EXACT: find an exact match for the size, and
  • CUPS_MEDIA_FLAGS_READY: if the printer supports media sensing, find the -size amongst the "ready" media.
  • + size amongst the "ready" media.

    The matching result (if any) is returned in the cups_size_t structure.

    @@ -3803,14 +3813,14 @@

    Discussion

  • CUPS_MEDIA_FLAGS_EXACT: find an exact match for the size, and
  • CUPS_MEDIA_FLAGS_READY: if the printer supports media sensing, find the -size amongst the "ready" media.
  • + size amongst the "ready" media.

    The matching result (if any) is returned in the cups_size_t structure.

    Returns true when there is a match and false if there is not a match.

    cupsGetDestMediaCount

    Get the number of sizes supported by a -destination.

    + destination.

    size_t cupsGetDestMediaCount(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags);

    Parameters

    @@ -4040,7 +4050,7 @@

    Return Value

    Option value or NULL

    cupsGetPassword

    Get a password from the user using the current -password callback.

    + password callback.

    const char *cupsGetPassword(const char *prompt, http_t *http, const char *method, const char *resource);

    Parameters

    @@ -4183,7 +4193,7 @@

    Return Value

    Language data

    cupsLangEncoding

    Return the character encoding (us-ascii, etc.) -for the given language.

    + for the given language.

    const char *cupsLangEncoding(cups_lang_t *lang);

    Parameters

    @@ -4221,21 +4231,21 @@

    Return Value

    Language data

    cupsLastError

    Return the last IPP status code received on the current -thread.

    + thread.

    ipp_status_t cupsLastError(void);

    Return Value

    IPP status code from last request

    cupsLastErrorString

    Return the last IPP status-message received on the -current thread.

    + current thread.

    const char *cupsLastErrorString(void);

    Return Value

    "status-message" text from last request

    cupsLocalizeDestMedia

    Get the localized string for a destination media -size.

    + size.

    const char *cupsLocalizeDestMedia(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, unsigned flags, cups_size_t *size);

    Parameters

    @@ -4258,7 +4268,7 @@

    Discussion

    invalid if the destination information is deleted.

    cupsLocalizeDestOption

    Get the localized string for a destination -option.

    + option.

    const char *cupsLocalizeDestOption(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option);

    Parameters

    @@ -4279,7 +4289,7 @@

    Discussion

    invalid if the destination information is deleted.

    cupsLocalizeDestValue

    Get the localized string for a destination -option+value pair.

    + option+value pair.

    const char *cupsLocalizeDestValue(http_t *http, cups_dest_t *dest, cups_dinfo_t *dinfo, const char *option, const char *value);

    Parameters

    @@ -4781,7 +4791,7 @@

    Discussion

    so in each thread for the same callback to be used.

    cupsSetCredentials

    Set the default credentials to be used for SSL/TLS -connections.

    + connections.

    bool cupsSetCredentials(cups_array_t *credentials);

    Parameters

    @@ -5149,7 +5159,7 @@

    Discussion

    after cupsStartDocument to provide a document file.

    httpAcceptConnection

    Accept a new HTTP client connection from the -specified listening socket.

    + specified listening socket.

    http_t *httpAcceptConnection(int fd, bool blocking);

    Parameters

    @@ -5180,7 +5190,7 @@

    Discussion

    Use httpCreateCredentials to create a credentials array.

    httpAddrClose

    Close a socket created by httpAddrConnect or -httpAddrListen.

    + httpAddrListen.

    bool httpAddrClose(http_addr_t *addr, int fd);

    Parameters

    @@ -5198,7 +5208,7 @@

    Discussion

    ensures that domain sockets are removed when closed.

    httpAddrConnect

    Connect to any of the addresses in the list with a -timeout and optional cancel.

    + timeout and optional cancel.

    http_addrlist_t *httpAddrConnect(http_addrlist_t *addrlist, int *sock, int msec, int *cancel);

    Parameters

    @@ -5373,7 +5383,7 @@

    Parameters

    httpAssembleURI

    Assemble a uniform resource identifier from its -components.

    + components.

    http_uri_status_t httpAssembleURI(http_uri_coding_t encoding, char *uri, size_t urilen, const char *scheme, const char *username, const char *host, int port, const char *resource);

    Parameters

    @@ -5404,7 +5414,7 @@

    Discussion

    URI string.

    httpAssembleURIf

    Assemble a uniform resource identifier from its -components with a formatted resource.

    + components with a formatted resource.

    http_uri_status_t httpAssembleURIf(http_uri_coding_t encoding, char *uri, size_t urilen, const char *scheme, const char *username, const char *host, int port, const char *resourcef, ...);

    Parameters

    @@ -5604,7 +5614,7 @@

    Return Value

    Error code (errno) value

    httpFieldValue

    Return the HTTP field enumeration value for a field -name.

    + name.

    http_field_t httpFieldValue(const char *name);

    Parameters

    @@ -5702,7 +5712,7 @@

    Return Value

    true if blocking, false if non-blocking

    httpGetContentEncoding

    Get a common content encoding, if any, between -the client and server.

    + the client and server.

    const char *httpGetContentEncoding(http_t *http);

    Parameters

    @@ -5843,7 +5853,7 @@

    Return Value

    Keep-Alive state

    httpGetLength

    Get the amount of data remaining from the content-length -or transfer-encoding fields.

    + or transfer-encoding fields.

    off_t httpGetLength(http_t *http);

    Parameters

    @@ -5880,7 +5890,7 @@

    Return Value

    Number of bytes available

    httpGetRemaining

    Get the number of remaining bytes in the message -body or current chunk.

    + body or current chunk.

    size_t httpGetRemaining(http_t *http);

    Parameters

    @@ -5962,7 +5972,7 @@

    Return Value

    Line or NULL

    httpInitialize

    Initialize the HTTP interface library and set the -default HTTP proxy (if any).

    + default HTTP proxy (if any).

    void httpInitialize(void);

    httpIsChunked

    @@ -6060,7 +6070,7 @@

    Return Value

    true on success, false on failure

    httpResolveHostname

    Resolve the hostname of the HTTP connection -address.

    + address.

    const char *httpResolveHostname(http_t *http, char *buffer, size_t bufsize);

    Parameters

    @@ -6114,7 +6124,7 @@

    Discussion

    to resolve the specified URI.

    httpSeparateURI

    Separate a Universal Resource Identifier into its -components.

    + components.

    http_uri_status_t httpSeparateURI(http_uri_coding_t decoding, const char *uri, char *scheme, size_t schemelen, char *username, size_t usernamelen, char *host, size_t hostlen, int *port, char *resource, size_t resourcelen);

    Parameters

    @@ -6186,7 +6196,7 @@

    Parameters

    httpSetCredentials

    Set the credentials associated with an encrypted -connection.

    + connection.

    bool httpSetCredentials(http_t *http, cups_array_t *credentials);

    Parameters

    @@ -6309,12 +6319,10 @@

    Discussion

    bool // true to continue, false to stop timeout_cb(http_t *http, void *user_data) { -... "http" contains the HTTP connection, "user_data" contains the callback pointer + ... "http" contains the HTTP connection, "user_data" contains the callback pointer } -``` -lution to be -terminated. The callback is provided the "cb_data" value and returns a -bool

    + +

    httpShutdown

    Shutdown one side of an HTTP connection.

    @@ -7032,7 +7040,7 @@

    Discussion

    (v)snprintf.

    ippContainsInteger

    Determine whether an attribute contains the -specified value or is within the list of ranges.

    + specified value or is within the list of ranges.

    bool ippContainsInteger(ipp_attribute_t *attr, int value);

    Parameters

    @@ -7050,7 +7058,7 @@

    Discussion

    values for the attribute.

    ippContainsString

    Determine whether an attribute contains the -specified string value.

    + specified string value.

    bool ippContainsString(ipp_attribute_t *attr, const char *value);

    Parameters

    @@ -7117,7 +7125,7 @@

    Discussion

    partial copy of the source attribute itself.

    ippCreateRequestedArray

    Create a CUPS array of attribute names from the -given requested-attributes attribute.

    + given requested-attributes attribute.

    cups_array_t *ippCreateRequestedArray(ipp_t *request);

    Parameters

    @@ -7142,7 +7150,7 @@

    Discussion

    array must be freed using cupsArrayDelete.

    ippDateToTime

    Convert from RFC 2579 Date/Time format to time in -seconds.

    + seconds.

    time_t ippDateToTime(const ipp_uchar_t *date);

    Parameters

    @@ -8657,7 +8665,7 @@

    Discussion

    are used.

    pwgInitSize

    Initialize a pwg_size_t structure using IPP Job Template -attributes.

    + attributes.

    bool pwgInitSize(pwg_size_t *size, ipp_t *job, bool *margins_set);

    Parameters

    @@ -8957,11 +8965,6 @@

    cups_ptype_t

    typedef unsigned cups_ptype_t;

    -

    cups_raster_cb_t

    -

    cupsRasterOpenIO callback function

    -

    -typedef ssize_t(*)(void *ctx, unsigned char *buffer, size_t length) cups_raster_cb_t; -

    cups_raster_mode_t

    cupsRasterOpen modes

    From 4b935429252c5ed42697c52b5ee8ae43818f27d2 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Mon, 29 Aug 2022 19:49:12 -0400 Subject: [PATCH 17/19] Migrate to new cupsDNSSD API. --- tools/ippeveprinter.c | 410 +++++------------------------------------- 1 file changed, 49 insertions(+), 361 deletions(-) diff --git a/tools/ippeveprinter.c b/tools/ippeveprinter.c index f24e3f7cf..ee7c9faeb 100644 --- a/tools/ippeveprinter.c +++ b/tools/ippeveprinter.c @@ -18,6 +18,7 @@ #include #include +#include #include #include @@ -43,17 +44,6 @@ extern char **environ; # define O_BINARY 0 /* Windows "binary file" nonsense */ #endif /* !O_BINARY */ -#ifdef HAVE_MDNSRESPONDER -# include -#elif defined(HAVE_AVAHI) -# include -# include -# include -# include -# include -# include -#endif /* HAVE_MDNSRESPONDER */ - #ifdef HAVE_SYS_MOUNT_H # include #endif /* HAVE_SYS_MOUNT_H */ @@ -144,19 +134,6 @@ static const char * const ippeve_preason_strings[] = * Structures... */ -#ifdef HAVE_MDNSRESPONDER -typedef DNSServiceRef ippeve_srv_t; /* Service reference */ -typedef TXTRecordRef ippeve_txt_t; /* TXT record */ - -#elif defined(HAVE_AVAHI) -typedef AvahiEntryGroup *ippeve_srv_t; /* Service reference */ -typedef AvahiStringList *ippeve_txt_t; /* TXT record */ - -#else -typedef void *ippeve_srv_t; /* Service reference */ -typedef void *ippeve_txt_t; /* TXT record */ -#endif /* HAVE_MDNSRESPONDER */ - #if HAVE_LIBPAM typedef struct ippeve_authdata_s /* Authentication data */ { @@ -178,14 +155,8 @@ typedef struct ippeve_printer_s /**** Printer data ****/ /* TODO: One IPv4 and one IPv6 listener are really not sufficient */ int ipv4, /* IPv4 listener */ ipv6; /* IPv6 listener */ -#ifdef HAVE_MDNSRESPONDER - ippeve_srv_t ipp_ref, /* DNS-SD IPP service */ - ipps_ref, /* DNS-SD IPPS service */ - http_ref, /* DNS-SD HTTP service */ - printer_ref; /* DNS-SD LPD service */ -#elif defined(HAVE_AVAHI) - ippeve_srv_t dnssd_ref; /* DNS-SD services */ -#endif /* HAVE_MDNSRESPONDER */ + cups_dnssd_t *dnssd; /* DNS-SD context */ + cups_dnssd_service_t *services; /* DNS-SD services */ char *dnssd_subtypes;/* DNS-SD subtypes */ int dnssd_collision;/* Name collision? */ char *dnssd_name, /* printer-dns-sd-name */ @@ -276,13 +247,7 @@ static void debug_attributes(const char *title, ipp_t *ipp, int response); static void delete_client(ippeve_client_t *client); static void delete_job(ippeve_job_t *job); static void delete_printer(ippeve_printer_t *printer); -#ifdef HAVE_MDNSRESPONDER -static void DNSSD_API dnssd_callback(DNSServiceRef sdRef, DNSServiceFlags flags, DNSServiceErrorType errorCode, const char *name, const char *regtype, const char *domain, ippeve_printer_t *printer); -#elif defined(HAVE_AVAHI) -static void dnssd_callback(AvahiEntryGroup *p, AvahiEntryGroupState state, void *context); -static void dnssd_client_cb(AvahiClient *c, AvahiClientState state, void *userdata); -#endif /* HAVE_MDNSRESPONDER */ -static void dnssd_init(void); +static void dnssd_callback(cups_dnssd_service_t *service, ippeve_printer_t *printer, cups_dnssd_flags_t flags); static int filter_cb(ippeve_filter_t *filter, ipp_t *dst, ipp_attribute_t *attr); static ippeve_job_t *find_job(ippeve_client_t *client); static void finish_document_data(ippeve_client_t *client, ippeve_job_t *job); @@ -318,7 +283,7 @@ static int process_http(ippeve_client_t *client); static int process_ipp(ippeve_client_t *client); static void *process_job(ippeve_job_t *job); static void process_state_message(ippeve_job_t *job, char *message); -static int register_printer(ippeve_printer_t *printer); +static bool register_printer(ippeve_printer_t *printer); static bool respond_http(ippeve_client_t *client, http_status_t code, const char *content_coding, const char *type, size_t length); static void respond_ipp(ippeve_client_t *client, ipp_status_t status, const char *message, ...) _CUPS_FORMAT(3, 4); static void respond_unsupported(ippeve_client_t *client, ipp_attribute_t *attr); @@ -339,13 +304,6 @@ static bool valid_job_attributes(ippeve_client_t *client); * Globals... */ -#ifdef HAVE_MDNSRESPONDER -static DNSServiceRef DNSSDMaster = NULL; -#elif defined(HAVE_AVAHI) -static AvahiThreadedPoll *DNSSDMaster = NULL; -static AvahiClient *DNSSDClient = NULL; -#endif /* HAVE_MDNSRESPONDER */ - static int KeepFiles = 0, /* Keep spooled job files? */ MaxVersion = 20,/* Maximum IPP version (20 = 2.0, 11 = 1.1, etc.) */ Verbosity = 0; /* Verbosity level */ @@ -648,12 +606,6 @@ main(int argc, /* I - Number of command-line args */ _cupsLangPrintf(stderr, _("Using spool directory \"%s\"."), directory); } - /* - * Initialize DNS-SD... - */ - - dnssd_init(); - /* * Create the printer... */ @@ -2096,7 +2048,8 @@ delete_job(ippeve_job_t *job) /* I - Job */ */ static void -delete_printer(ippeve_printer_t *printer) /* I - Printer */ +delete_printer( + ippeve_printer_t *printer) /* I - Printer */ { if (printer->ipv4 >= 0) close(printer->ipv4); @@ -2104,23 +2057,7 @@ delete_printer(ippeve_printer_t *printer) /* I - Printer */ if (printer->ipv6 >= 0) close(printer->ipv6); -#if HAVE_MDNSRESPONDER - if (printer->printer_ref) - DNSServiceRefDeallocate(printer->printer_ref); - if (printer->ipp_ref) - DNSServiceRefDeallocate(printer->ipp_ref); - if (printer->ipps_ref) - DNSServiceRefDeallocate(printer->ipps_ref); - if (printer->http_ref) - DNSServiceRefDeallocate(printer->http_ref); -#elif defined(HAVE_AVAHI) - avahi_threaded_poll_lock(DNSSDMaster); - - if (printer->dnssd_ref) - avahi_entry_group_free(printer->dnssd_ref); - - avahi_threaded_poll_unlock(DNSSDMaster); -#endif /* HAVE_MDNSRESPONDER */ + cupsDNSSDDelete(printer->dnssd); if (printer->dnssd_name) free(printer->dnssd_name); @@ -2146,57 +2083,19 @@ delete_printer(ippeve_printer_t *printer) /* I - Printer */ } -#ifdef HAVE_MDNSRESPONDER -/* - * 'dnssd_callback()' - Handle DNS-SD registration events. - */ - -static void DNSSD_API -dnssd_callback( - DNSServiceRef sdRef, /* I - Service reference */ - DNSServiceFlags flags, /* I - Status flags */ - DNSServiceErrorType errorCode, /* I - Error, if any */ - const char *name, /* I - Service name */ - const char *regtype, /* I - Service type */ - const char *domain, /* I - Domain for service */ - ippeve_printer_t *printer) /* I - Printer */ -{ - (void)sdRef; - (void)flags; - (void)domain; - (void)name; - - if (errorCode == kDNSServiceErr_NameConflict) - { - fputs("DNS-SD service name collision detected.\n", stderr); - printer->dnssd_collision = 1; - } - else if (errorCode) - { - fprintf(stderr, "DNSServiceRegister for %s failed with error %d.\n", regtype, (int)errorCode); - return; - } -} - - -#elif defined(HAVE_AVAHI) /* * 'dnssd_callback()' - Handle DNS-SD registration events. */ static void dnssd_callback( - AvahiEntryGroup *srv, /* I - Service */ - AvahiEntryGroupState state, /* I - Registration state */ - void *context) /* I - Printer */ + cups_dnssd_service_t *service, /* I - Service registration */ + ippeve_printer_t *printer, /* I - Printer */ + cups_dnssd_flags_t flags) /* I - Status flags */ { - ippeve_printer_t *printer = (ippeve_printer_t *)context; - /* Printer */ - - - (void)srv; + (void)service; - if (state == AVAHI_ENTRY_GROUP_COLLISION) + if (flags & CUPS_DNSSD_FLAGS_COLLISION) { fputs("DNS-SD service name collision detected.\n", stderr); printer->dnssd_collision = 1; @@ -2204,73 +2103,6 @@ dnssd_callback( } -/* - * 'dnssd_client_cb()' - Client callback for Avahi. - * - * Called whenever the client or server state changes... - */ - -static void -dnssd_client_cb( - AvahiClient *c, /* I - Client */ - AvahiClientState state, /* I - Current state */ - void *userdata) /* I - User data (printer) */ -{ - if (!c) - return; - - switch (state) - { - default : - fprintf(stderr, "Ignored Avahi state %d.\n", state); - break; - - case AVAHI_CLIENT_FAILURE: - if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) - { - fputs("Avahi server crashed, exiting.\n", stderr); - exit(1); - } - break; - } -} -#endif /* HAVE_MDNSRESPONDER */ - - -/* - * 'dnssd_init()' - Initialize the DNS-SD service connections... - */ - -static void -dnssd_init(void) -{ -#ifdef HAVE_MDNSRESPONDER - if (DNSServiceCreateConnection(&DNSSDMaster) != kDNSServiceErr_NoError) - { - fputs("Error: Unable to initialize DNS-SD.\n", stderr); - exit(1); - } - -#elif defined(HAVE_AVAHI) - int error; /* Error code, if any */ - - if ((DNSSDMaster = avahi_threaded_poll_new()) == NULL) - { - fputs("Error: Unable to initialize DNS-SD.\n", stderr); - exit(1); - } - - if ((DNSSDClient = avahi_client_new(avahi_threaded_poll_get(DNSSDMaster), AVAHI_CLIENT_NO_FAIL, dnssd_client_cb, NULL, &error)) == NULL) - { - fputs("Error: Unable to initialize DNS-SD.\n", stderr); - exit(1); - } - - avahi_threaded_poll_start(DNSSDMaster); -#endif /* HAVE_MDNSRESPONDER */ -} - - /* * 'filter_cb()' - Filter printer attributes based on the requested array. */ @@ -6442,12 +6274,13 @@ process_state_message( * 'register_printer()' - Register a printer object via DNS-SD. */ -static int /* O - 1 on success, 0 on error */ +static bool /* O - `true` on success, `false` on error */ register_printer( ippeve_printer_t *printer) /* I - Printer */ { -#ifdef HAVE_DNSSD - ippeve_txt_t ipp_txt; /* DNS-SD IPP TXT record */ + size_t num_txt; /* Number of DNS-SD IPP TXT key/value pairs */ + cups_option_t *txt; /* DNS-SD IPP TXT key/value pairs */ + uint32_t if_index; /* Interface index */ size_t i, /* Looping var */ count; /* Number of values */ ipp_attribute_t *color_supported, @@ -6458,14 +6291,15 @@ register_printer( *sides_supported, *urf_supported; /* Printer attributes */ const char *value; /* Value string */ - char adminurl[247], /* adminurl value */ + char regtype[256], /* Registration types */ + adminurl[247], /* adminurl value */ formats[252], /* List of supported formats */ urf[252], /* List of supported URF values */ *ptr; /* Pointer into string */ if (printer->dnssd_subtypes && !strcmp(printer->dnssd_subtypes, "off")) - return (1); + return (true); color_supported = ippFindAttribute(printer->attrs, "color-supported", IPP_TAG_BOOLEAN); document_format_supported = ippFindAttribute(printer->attrs, "document-format-supported", IPP_TAG_MIMETYPE); @@ -6532,216 +6366,86 @@ register_printer( printer->dnssd_collision = 0; } -#endif /* HAVE_DNSSD */ - -#ifdef HAVE_MDNSRESPONDER - DNSServiceErrorType error; /* Error from DNS-SD */ - char regtype[256]; /* DNS-SD service type */ - uint32_t ifindex; /* Interface index */ - /* * Build the TXT record for IPP... */ - TXTRecordCreate(&ipp_txt, 1024, NULL); - TXTRecordSetValue(&ipp_txt, "rp", 9, "ipp/print"); + num_txt = cupsAddOption("rp", "ipp/print", 0, &txt); if ((value = ippGetString(printer_make_and_model, 0, NULL)) != NULL) - TXTRecordSetValue(&ipp_txt, "ty", (uint8_t)strlen(value), value); - TXTRecordSetValue(&ipp_txt, "adminurl", (uint8_t)strlen(adminurl), adminurl); + num_txt = cupsAddOption("ty", value, num_txt, &txt); + num_txt = cupsAddOption("adminurl", adminurl, num_txt, &txt); if ((value = ippGetString(printer_location, 0, NULL)) != NULL) - TXTRecordSetValue(&ipp_txt, "note", (uint8_t)strlen(value), value); - TXTRecordSetValue(&ipp_txt, "pdl", (uint8_t)strlen(formats), formats); - TXTRecordSetValue(&ipp_txt, "Color", 1, ippGetBoolean(color_supported, 0) ? "T" : "F"); - TXTRecordSetValue(&ipp_txt, "Duplex", 1, ippGetCount(sides_supported) > 1 ? "T" : "F"); + num_txt = cupsAddOption("note", value, num_txt, &txt); + num_txt = cupsAddOption("pdl", formats, num_txt, &txt); + num_txt = cupsAddOption("Color", ippGetBoolean(color_supported, 0) ? "T" : "F", num_txt, &txt); + num_txt = cupsAddOption("Duplex", ippGetCount(sides_supported) > 1 ? "T" : "F", num_txt, &txt); if ((value = ippGetString(printer_uuid, 0, NULL)) != NULL) - TXTRecordSetValue(&ipp_txt, "UUID", (uint8_t)strlen(value) - 9, value + 9); - TXTRecordSetValue(&ipp_txt, "TLS", 3, "1.3"); + num_txt = cupsAddOption("UUID", value + 9, num_txt, &txt); + num_txt = cupsAddOption("TLS", "1.3", num_txt, &txt); if (urf[0]) - TXTRecordSetValue(&ipp_txt, "URF", (uint8_t)strlen(urf), urf); - TXTRecordSetValue(&ipp_txt, "txtvers", 1, "1"); - TXTRecordSetValue(&ipp_txt, "qtotal", 1, "1"); + num_txt = cupsAddOption("URF", urf, num_txt, &txt); + num_txt = cupsAddOption("txtvers", "1", num_txt, &txt); + num_txt = cupsAddOption("qtotal", "1", num_txt, &txt); /* * Register the _printer._tcp (LPD) service type with a port number of 0 to * defend our service name but not actually support LPD... */ - ifindex = !strcmp(printer->hostname, "localhost") ? kDNSServiceInterfaceIndexLocalOnly : kDNSServiceInterfaceIndexAny; + if_index = !strcmp(printer->hostname, "localhost") ? CUPS_DNSSD_IF_INDEX_LOCAL : CUPS_DNSSD_IF_INDEX_ANY; - if (printer->printer_ref) - DNSServiceRefDeallocate(printer->printer_ref); + if (!printer->dnssd) + printer->dnssd = cupsDNSSDNew(NULL, NULL); - printer->printer_ref = DNSSDMaster; + cupsDNSSDServiceDelete(printer->services); + if ((printer->services = cupsDNSSDServiceNew(printer->dnssd, if_index, printer->dnssd_name, (cups_dnssd_service_cb_t)dnssd_callback, printer)) == NULL) + return (false); - if ((error = DNSServiceRegister(&(printer->printer_ref), kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, ifindex, printer->dnssd_name, "_printer._tcp", NULL /* domain */, NULL /* host */, 0 /* port */, 0 /* txtLen */, NULL /* txtRecord */, (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) - { - _cupsLangPrintf(stderr, _("Unable to register \"%s.%s\": %d"), printer->dnssd_name, "_printer._tcp", error); - return (0); - } + if (!cupsDNSSDServiceAdd(printer->services, "_printer._tcp", /*domain*/NULL, printer->hostname, /*port*/0, /*num_txt*/0, /*txt*/NULL)) + return (false); /* * Then register the _ipp._tcp (IPP) service type with the real port number to * advertise our IPP printer... */ - if (printer->ipp_ref) - DNSServiceRefDeallocate(printer->ipp_ref); - - printer->ipp_ref = DNSSDMaster; - if (printer->dnssd_subtypes && *(printer->dnssd_subtypes)) snprintf(regtype, sizeof(regtype), "_ipp._tcp,%s", printer->dnssd_subtypes); else cupsCopyString(regtype, "_ipp._tcp", sizeof(regtype)); - if ((error = DNSServiceRegister(&(printer->ipp_ref), kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, ifindex, printer->dnssd_name, regtype, NULL /* domain */, NULL /* host */, htons(printer->port), TXTRecordGetLength(&ipp_txt), TXTRecordGetBytesPtr(&ipp_txt), (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) - { - _cupsLangPrintf(stderr, _("Unable to register \"%s.%s\": %d"), printer->dnssd_name, regtype, error); - return (0); - } + if (!cupsDNSSDServiceAdd(printer->services, regtype, /*domain*/NULL, printer->hostname, (uint16_t)printer->port, num_txt, txt)) + return (false); /* * Then register the _ipps._tcp (IPP) service type with the real port number to * advertise our IPPS printer... */ - if (printer->ipps_ref) - DNSServiceRefDeallocate(printer->ipps_ref); - - printer->ipps_ref = DNSSDMaster; - if (printer->dnssd_subtypes && *(printer->dnssd_subtypes)) snprintf(regtype, sizeof(regtype), "_ipps._tcp,%s", printer->dnssd_subtypes); else cupsCopyString(regtype, "_ipps._tcp", sizeof(regtype)); - if ((error = DNSServiceRegister(&(printer->ipps_ref), kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, ifindex, printer->dnssd_name, regtype, NULL /* domain */, NULL /* host */, htons(printer->port), TXTRecordGetLength(&ipp_txt), TXTRecordGetBytesPtr(&ipp_txt), (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) - { - _cupsLangPrintf(stderr, _("Unable to register \"%s.%s\": %d"), printer->dnssd_name, regtype, error); - return (0); - } + if (!cupsDNSSDServiceAdd(printer->services, regtype, /*domain*/NULL, printer->hostname, (uint16_t)printer->port, num_txt, txt)) + return (false); /* * Similarly, register the _http._tcp,_printer (HTTP) service type with the - * real port number to advertise our IPP printer... - */ - - if (printer->http_ref) - DNSServiceRefDeallocate(printer->http_ref); - - printer->http_ref = DNSSDMaster; - - if ((error = DNSServiceRegister(&(printer->http_ref), kDNSServiceFlagsShareConnection | kDNSServiceFlagsNoAutoRename, ifindex, printer->dnssd_name, "_http._tcp,_printer", NULL /* domain */, NULL /* host */, htons(printer->port), 0 /* txtLen */, NULL /* txtRecord */, (DNSServiceRegisterReply)dnssd_callback, printer)) != kDNSServiceErr_NoError) - { - _cupsLangPrintf(stderr, _("Unable to register \"%s.%s\": %d"), printer->dnssd_name, "_http._tcp,_printer", error); - return (0); - } - - TXTRecordDeallocate(&ipp_txt); - -#elif defined(HAVE_AVAHI) - char temp[256]; /* Subtype service string */ - - /* - * Create the TXT record... + * real port number to advertise our IPP printer's web interface... */ - ipp_txt = NULL; - ipp_txt = avahi_string_list_add_printf(ipp_txt, "rp=ipp/print"); - if ((value = ippGetString(printer_make_and_model, 0, NULL)) != NULL) - ipp_txt = avahi_string_list_add_printf(ipp_txt, "ty=%s", value); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "adminurl=%s", adminurl); - if ((value = ippGetString(printer_location, 0, NULL)) != NULL) - ipp_txt = avahi_string_list_add_printf(ipp_txt, "note=%s", value); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "pdl=%s", formats); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "Color=%s", ippGetBoolean(color_supported, 0) ? "T" : "F"); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "Duplex=%s", ippGetCount(sides_supported) > 1 ? "T" : "F"); - if ((value = ippGetString(printer_uuid, 0, NULL)) != NULL) - ipp_txt = avahi_string_list_add_printf(ipp_txt, "UUID=%s", value + 9); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "TLS=1.3"); - if (urf[0]) - ipp_txt = avahi_string_list_add_printf(ipp_txt, "URF=%s", urf); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "txtvers=1"); - ipp_txt = avahi_string_list_add_printf(ipp_txt, "qtotal=1"); - - /* - * Register _printer._tcp (LPD) with port 0 to reserve the service name... - */ - - avahi_threaded_poll_lock(DNSSDMaster); - - if (printer->dnssd_ref) - avahi_entry_group_free(printer->dnssd_ref); - - printer->dnssd_ref = avahi_entry_group_new(DNSSDClient, dnssd_callback, printer); - - avahi_entry_group_add_service_strlst(printer->dnssd_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_printer._tcp", NULL, NULL, 0, NULL); - - /* - * Then register the _ipp._tcp (IPP)... - */ - - avahi_entry_group_add_service_strlst(printer->dnssd_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipp._tcp", NULL, NULL, printer->port, ipp_txt); - if (printer->dnssd_subtypes && *(printer->dnssd_subtypes)) - { - char *temptypes = strdup(printer->dnssd_subtypes), *start, *end; - - for (start = temptypes; *start; start = end) - { - if ((end = strchr(start, ',')) != NULL) - *end++ = '\0'; - else - end = start + strlen(start); - - snprintf(temp, sizeof(temp), "%s._sub._ipp._tcp", start); - avahi_entry_group_add_service_subtype(printer->dnssd_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipp._tcp", NULL, temp); - } - - free(temptypes); - } - - /* - * _ipps._tcp (IPPS) for secure printing... - */ - - avahi_entry_group_add_service_strlst(printer->dnssd_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipps._tcp", NULL, NULL, printer->port, ipp_txt); - if (printer->dnssd_subtypes && *(printer->dnssd_subtypes)) - { - char *temptypes = strdup(printer->dnssd_subtypes), *start, *end; - - for (start = temptypes; *start; start = end) - { - if ((end = strchr(start, ',')) != NULL) - *end++ = '\0'; - else - end = start + strlen(start); - - snprintf(temp, sizeof(temp), "%s._sub._ipps._tcp", start); - avahi_entry_group_add_service_subtype(printer->dnssd_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_ipps._tcp", NULL, temp); - } - - free(temptypes); - } - - /* - * Finally _http.tcp (HTTP) for the web interface... - */ + if (!cupsDNSSDServiceAdd(printer->services, "_http._tcp,_printer", /*domain*/NULL, printer->hostname, (uint16_t)printer->port, num_txt, txt)) + return (false); - avahi_entry_group_add_service_strlst(printer->dnssd_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_http._tcp", NULL, NULL, printer->port, NULL); - avahi_entry_group_add_service_subtype(printer->dnssd_ref, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, printer->dnssd_name, "_http._tcp", NULL, "_printer._sub._http._tcp"); + cupsFreeOptions(num_txt, txt); /* * Commit it... */ - avahi_entry_group_commit(printer->dnssd_ref); - avahi_threaded_poll_unlock(DNSSDMaster); - - avahi_string_list_free(ipp_txt); -#endif /* HAVE_MDNSRESPONDER */ - - return (1); + return (cupsDNSSDServicePublish(printer->services)); } @@ -6923,11 +6627,6 @@ run_printer(ippeve_printer_t *printer) /* I - Printer */ num_fds = 2; -#ifdef HAVE_MDNSRESPONDER - polldata[num_fds ].fd = DNSServiceRefSockFD(DNSSDMaster); - polldata[num_fds ++].events = POLLIN; -#endif /* HAVE_MDNSRESPONDER */ - /* * Loop until we are killed or have a hard error... */ @@ -6981,19 +6680,8 @@ run_printer(ippeve_printer_t *printer) /* I - Printer */ } } - /* - * Process DNS-SD messages... - */ - -#ifdef HAVE_MDNSRESPONDER - if (polldata[2].revents & POLLIN) - DNSServiceProcessResult(DNSSDMaster); -#endif /* HAVE_MDNSRESPONDER */ - -#ifdef HAVE_DNSSD if (printer->dnssd_collision) register_printer(printer); -#endif /* HAVE_DNSSD */ /* * Clean out old jobs... From 2960315b632bc7d9f40ac0f7daeb953390d3352b Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Mon, 29 Aug 2022 20:53:41 -0400 Subject: [PATCH 18/19] Migrate ippfind to cupsDNSSD API. --- tools/ippfind.c | 845 ++++++++---------------------------------------- 1 file changed, 138 insertions(+), 707 deletions(-) diff --git a/tools/ippfind.c b/tools/ippfind.c index 2ff420aa7..e6008b1f4 100644 --- a/tools/ippfind.c +++ b/tools/ippfind.c @@ -24,17 +24,7 @@ # include #endif /* _WIN32 */ #include -#ifdef HAVE_MDNSRESPONDER -# include -#elif defined(HAVE_AVAHI) -# include -# include -# include -# include -# include -# include -# define kDNSServiceMaxDomainName AVAHI_DOMAIN_NAME_MAX -#endif /* HAVE_MDNSRESPONDER */ +#include #ifndef _WIN32 extern char **environ; /* Process environment variables */ @@ -98,13 +88,15 @@ typedef struct ippfind_expr_s /* Expression */ char **args; /* Arguments for exec */ } ippfind_expr_t; +typedef struct ippfind_srvs_s /* Services array */ +{ + cups_rwlock_t rwlock; /* R/W lock */ + cups_array_t *services; /* Services array */ +} ippfind_srvs_t; + typedef struct ippfind_srv_s /* Service information */ { -#ifdef HAVE_MDNSRESPONDER - DNSServiceRef ref; /* Service reference for query */ -#elif defined(HAVE_AVAHI) - AvahiServiceResolver *ref; /* Resolver */ -#endif /* HAVE_MDNSRESPONDER */ + cups_dnssd_resolve_t *resolve; /* Resolve request */ char *name, /* Service name */ *domain, /* Domain name */ *regtype, /* Registration type */ @@ -125,15 +117,7 @@ typedef struct ippfind_srv_s /* Service information */ * Local globals... */ -#ifdef HAVE_MDNSRESPONDER -static DNSServiceRef dnssd_ref; /* Master service reference */ -#elif defined(HAVE_AVAHI) -static AvahiClient *avahi_client = NULL;/* Client information */ -static int avahi_got_data = 0; /* Got data from poll? */ -static AvahiSimplePoll *avahi_poll = NULL; - /* Poll information */ -#endif /* HAVE_MDNSRESPONDER */ - +static cups_dnssd_t *dnssd; /* DNS-SD context */ static int address_family = AF_UNSPEC; /* Address family for LIST */ static int bonjour_error = 0; /* Error browsing/resolving? */ @@ -145,42 +129,15 @@ static int ipp_version = 20; /* IPP version for LIST */ * Local functions... */ -#ifdef HAVE_MDNSRESPONDER -static void DNSSD_API browse_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) _CUPS_NONNULL(1,5,6,7,8); -static void DNSSD_API browse_local_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *serviceName, const char *regtype, const char *replyDomain, void *context) _CUPS_NONNULL(1,5,6,7,8); -#elif defined(HAVE_AVAHI) -static void browse_callback(AvahiServiceBrowser *browser, AvahiIfIndex interface, AvahiProtocol protocol, AvahiBrowserEvent event, const char *serviceName, const char *regtype, const char *replyDomain, AvahiLookupResultFlags flags, void *context); -static void client_callback(AvahiClient *client, AvahiClientState state, void *context); -#endif /* HAVE_MDNSRESPONDER */ - +static void browse_callback(cups_dnssd_browse_t *browse, void *context, cups_dnssd_flags_t flags, uint32_t if_index, const char *serviceName, const char *regtype, const char *replyDomain); static int compare_services(ippfind_srv_t *a, ippfind_srv_t *b); -static const char *dnssd_error_string(int error); static int eval_expr(ippfind_srv_t *service, ippfind_expr_t *expressions); static int exec_program(ippfind_srv_t *service, size_t num_args, char **args); -static ippfind_srv_t *get_service(cups_array_t *services, const char *serviceName, const char *regtype, const char *replyDomain) _CUPS_NONNULL(1,2,3,4); +static ippfind_srv_t *get_service(ippfind_srvs_t *services, const char *serviceName, const char *regtype, const char *replyDomain) _CUPS_NONNULL(1,2,3,4); static double get_time(void); static int list_service(ippfind_srv_t *service); static ippfind_expr_t *new_expr(ippfind_op_t op, bool invert, const char *value, const char *regex, char **args); -#ifdef HAVE_MDNSRESPONDER -static void DNSSD_API resolve_callback(DNSServiceRef sdRef, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType errorCode, const char *fullName, const char *hostTarget, uint16_t port, uint16_t txtLen, const unsigned char *txtRecord, void *context) _CUPS_NONNULL(1,5,6,9, 10); -#elif defined(HAVE_AVAHI) -static int poll_callback(struct pollfd *pollfds, - unsigned int num_pollfds, int timeout, - void *context); -static void resolve_callback(AvahiServiceResolver *res, - AvahiIfIndex interface, - AvahiProtocol protocol, - AvahiResolverEvent event, - const char *serviceName, - const char *regtype, - const char *replyDomain, - const char *host_name, - const AvahiAddress *address, - uint16_t port, - AvahiStringList *txt, - AvahiLookupResultFlags flags, - void *context); -#endif /* HAVE_MDNSRESPONDER */ +static void resolve_callback(cups_dnssd_resolve_t *resolve, void *context, cups_dnssd_flags_t flags, uint32_t if_index, const char *fullName, const char *hostTarget, uint16_t port, size_t num_txt, cups_option_t *txt); static void set_service_uri(ippfind_srv_t *service); static void show_usage(void) _CUPS_NORETURN; static void show_version(void) _CUPS_NORETURN; @@ -204,7 +161,7 @@ main(int argc, /* I - Number of command-line args */ const char *opt, /* Option character */ *search; /* Current browse/resolve string */ cups_array_t *searches; /* Things to browse/resolve */ - cups_array_t *services; /* Service array */ + ippfind_srvs_t services; /* Services array */ ippfind_srv_t *service; /* Current service */ ippfind_expr_t *expressions = NULL, /* Expression tree */ @@ -216,11 +173,6 @@ main(int argc, /* I - Number of command-line args */ ippfind_op_t logic = IPPFIND_OP_AND; /* Logic for next expression */ int invert = 0; /* Invert expression? */ - int err; /* DNS-SD error */ -#ifdef HAVE_MDNSRESPONDER - fd_set sinput; /* Input set for select() */ - struct timeval stimeout; /* Timeout for select() */ -#endif /* HAVE_MDNSRESPONDER */ double endtime; /* End time */ static const char * const ops[] = /* Node operation names */ { @@ -259,7 +211,9 @@ main(int argc, /* I - Number of command-line args */ */ searches = cupsArrayNew(NULL, NULL, NULL, 0, NULL, NULL); - services = cupsArrayNew((cups_array_cb_t)compare_services, NULL, NULL, 0, NULL, NULL); + + cupsRWInit(&services.rwlock); + services.services = cupsArrayNew((cups_array_cb_t)compare_services, NULL, NULL, 0, NULL, NULL); /* * Parse command-line... @@ -1119,33 +1073,8 @@ main(int argc, /* I - Number of command-line args */ * Start up browsing/resolving... */ -#ifdef HAVE_MDNSRESPONDER - if ((err = DNSServiceCreateConnection(&dnssd_ref)) != kDNSServiceErr_NoError) - { - _cupsLangPrintf(stderr, _("ippfind: Unable to use Bonjour: %s"), - dnssd_error_string(err)); - exit(IPPFIND_EXIT_BONJOUR); - } - -#elif defined(HAVE_AVAHI) - if ((avahi_poll = avahi_simple_poll_new()) == NULL) - { - _cupsLangPrintf(stderr, _("ippfind: Unable to use Bonjour: %s"), - strerror(errno)); + if ((dnssd = cupsDNSSDNew(NULL, NULL)) == NULL) exit(IPPFIND_EXIT_BONJOUR); - } - - avahi_simple_poll_set_func(avahi_poll, poll_callback, NULL); - - avahi_client = avahi_client_new(avahi_simple_poll_get(avahi_poll), - 0, client_callback, avahi_poll, &err); - if (!avahi_client) - { - _cupsLangPrintf(stderr, _("ippfind: Unable to use Bonjour: %s"), - dnssd_error_string(err)); - exit(IPPFIND_EXIT_BONJOUR); - } -#endif /* HAVE_MDNSRESPONDER */ for (search = (const char *)cupsArrayGetFirst(searches); search; @@ -1215,29 +1144,13 @@ main(int argc, /* I - Number of command-line args */ if (!domain) domain = "local."; - service = get_service(services, name, regtype, domain); + service = get_service(&services, name, regtype, domain); if (getenv("IPPFIND_DEBUG")) fprintf(stderr, "Resolving name=\"%s\", regtype=\"%s\", domain=\"%s\"\n", name, regtype, domain); -#ifdef HAVE_MDNSRESPONDER - service->ref = dnssd_ref; - err = DNSServiceResolve(&(service->ref), - kDNSServiceFlagsShareConnection, 0, name, - regtype, domain, resolve_callback, - service); - -#elif defined(HAVE_AVAHI) - service->ref = avahi_service_resolver_new(avahi_client, AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, name, - regtype, domain, - AVAHI_PROTO_UNSPEC, 0, - resolve_callback, service); - if (service->ref) - err = 0; - else - err = avahi_client_errno(avahi_client); -#endif /* HAVE_MDNSRESPONDER */ + if ((service->resolve = cupsDNSSDResolveNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, name, regtype, domain, resolve_callback, service)) == NULL) + exit(IPPFIND_EXIT_BONJOUR); } else { @@ -1248,47 +1161,8 @@ main(int argc, /* I - Number of command-line args */ if (getenv("IPPFIND_DEBUG")) fprintf(stderr, "Browsing for regtype=\"%s\", domain=\"%s\"\n", regtype, domain); -#ifdef HAVE_MDNSRESPONDER - DNSServiceRef ref; /* Browse reference */ - - ref = dnssd_ref; - err = DNSServiceBrowse(&ref, kDNSServiceFlagsShareConnection, 0, regtype, - domain, browse_callback, services); - - if (!err) - { - ref = dnssd_ref; - err = DNSServiceBrowse(&ref, kDNSServiceFlagsShareConnection, - kDNSServiceInterfaceIndexLocalOnly, regtype, - domain, browse_local_callback, services); - } - -#elif defined(HAVE_AVAHI) - char *subtype, /* Sub-type, if any */ - subtype_buf[256]; /* Sub-type buffer */ - - if ((subtype = strstr(regtype, ",_")) != NULL) - { - *subtype++ = '\0'; - snprintf(subtype_buf, sizeof(subtype_buf), "%s._sub.%s", subtype, regtype); - regtype = subtype_buf; - } - - if (avahi_service_browser_new(avahi_client, AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, regtype, domain, 0, - browse_callback, services)) - err = 0; - else - err = avahi_client_errno(avahi_client); -#endif /* HAVE_MDNSRESPONDER */ - } - - if (err) - { - _cupsLangPrintf(stderr, _("ippfind: Unable to browse or resolve: %s"), - dnssd_error_string(err)); - - exit(IPPFIND_EXIT_BONJOUR); + if (!cupsDNSSDBrowseNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, regtype, domain, browse_callback, &services)) + exit(IPPFIND_EXIT_BONJOUR); } } @@ -1303,157 +1177,78 @@ main(int argc, /* I - Number of command-line args */ while (get_time() < endtime) { - int process = 0; /* Process services? */ - -#ifdef HAVE_MDNSRESPONDER - int fd = DNSServiceRefSockFD(dnssd_ref); - /* File descriptor for DNS-SD */ - - FD_ZERO(&sinput); - FD_SET(fd, &sinput); - - stimeout.tv_sec = 0; - stimeout.tv_usec = 500000; - - if (select(fd + 1, &sinput, NULL, NULL, &stimeout) < 0) - continue; - - if (FD_ISSET(fd, &sinput)) - { - /* - * Process responses... - */ - - DNSServiceProcessResult(dnssd_ref); - } - else - { - /* - * Time to process services... - */ - - process = 1; - } - -#elif defined(HAVE_AVAHI) - avahi_got_data = 0; - - if (avahi_simple_poll_iterate(avahi_poll, 500) > 0) - { - /* - * We've been told to exit the loop. Perhaps the connection to - * Avahi failed. - */ + /* + * Process any services that we have found... + */ - exit(IPPFIND_EXIT_BONJOUR); - } + size_t j, /* Looping var */ + count, /* Number of services */ + active = 0, /* Number of active resolves */ + resolved = 0, /* Number of resolved services */ + processed = 0; /* Number of processed services */ - if (!avahi_got_data) + cupsRWLockRead(&services.rwlock); + for (j = 0, count = cupsArrayGetCount(services.services); j < count; j ++) { - /* - * Time to process services... - */ - - process = 1; - } -#endif /* HAVE_MDNSRESPONDER */ + service = (ippfind_srv_t *)cupsArrayGetElement(services.services, j); - if (process) - { - /* - * Process any services that we have found... - */ + if (service->is_processed) + processed ++; - size_t active = 0, /* Number of active resolves */ - resolved = 0, /* Number of resolved services */ - processed = 0; /* Number of processed services */ + if (service->is_resolved) + resolved ++; - for (service = (ippfind_srv_t *)cupsArrayGetFirst(services); - service; - service = (ippfind_srv_t *)cupsArrayGetNext(services)) + if (!service->resolve && !service->is_resolved) { - if (service->is_processed) - processed ++; + /* + * Found a service, now resolve it (but limit to 50 active resolves...) + */ - if (service->is_resolved) - resolved ++; + if (active < 50) + { + if ((service->resolve = cupsDNSSDResolveNew(dnssd, CUPS_DNSSD_IF_INDEX_ANY, service->name, service->regtype, service->domain, resolve_callback, service)) == NULL) + exit(IPPFIND_EXIT_BONJOUR); - if (!service->ref && !service->is_resolved) - { - /* - * Found a service, now resolve it (but limit to 50 active resolves...) - */ + active ++; + } + } + else if (service->is_resolved && !service->is_processed) + { + /* + * Resolved, not process this service against the expressions... + */ - if (active < 50) - { -#ifdef HAVE_MDNSRESPONDER - service->ref = dnssd_ref; - err = DNSServiceResolve(&(service->ref), - kDNSServiceFlagsShareConnection, 0, - service->name, service->regtype, - service->domain, resolve_callback, - service); - -#elif defined(HAVE_AVAHI) - service->ref = avahi_service_resolver_new(avahi_client, - AVAHI_IF_UNSPEC, - AVAHI_PROTO_UNSPEC, - service->name, - service->regtype, - service->domain, - AVAHI_PROTO_UNSPEC, 0, - resolve_callback, - service); - if (service->ref) - err = 0; - else - err = avahi_client_errno(avahi_client); -#endif /* HAVE_MDNSRESPONDER */ + cupsDNSSDResolveDelete(service->resolve); + service->resolve = NULL; - if (err) - { - _cupsLangPrintf(stderr, - _("ippfind: Unable to browse or resolve: %s"), - dnssd_error_string(err)); - exit(IPPFIND_EXIT_BONJOUR); - } + if (getenv("IPPFIND_DEBUG")) + fprintf(stderr, "EVAL %s\n", service->uri); - active ++; - } - } - else if (service->is_resolved && !service->is_processed) - { - /* - * Resolved, not process this service against the expressions... - */ + if (eval_expr(service, expressions)) + status = IPPFIND_EXIT_TRUE; - if (service->ref) - { -#ifdef HAVE_MDNSRESPONDER - DNSServiceRefDeallocate(service->ref); -#else - avahi_service_resolver_free(service->ref); -#endif /* HAVE_MDNSRESPONDER */ + service->is_processed = true; + } + else if (service->resolve) + active ++; + } + cupsRWUnlock(&services.rwlock); - service->ref = NULL; - } + /* + * If we have processed all services we have discovered, then we are done. + */ - if (eval_expr(service, expressions)) - status = IPPFIND_EXIT_TRUE; + if (getenv("IPPFIND_DEBUG")) + fprintf(stderr, "STATUS processed=%u, resolved=%u, count=%u\n", (unsigned)processed, (unsigned)resolved, (unsigned)count); - service->is_processed = true; - } - else if (service->ref) - active ++; - } + if (processed > 0 && processed == cupsArrayGetCount(services.services) && bonjour_timeout <= 1.0) + break; - /* - * If we have processed all services we have discovered, then we are done. - */ + /* + * Give the browsers/resolvers some time... + */ - if (processed == cupsArrayGetCount(services) && bonjour_timeout <= 1.0) - break; - } + usleep(250000); } if (bonjour_error) @@ -1463,159 +1258,42 @@ main(int argc, /* I - Number of command-line args */ } -#ifdef HAVE_MDNSRESPONDER /* * 'browse_callback()' - Browse devices. */ -static void DNSSD_API +static void browse_callback( - DNSServiceRef sdRef, /* I - Service reference */ - DNSServiceFlags flags, /* I - Option flags */ - uint32_t interfaceIndex, /* I - Interface number */ - DNSServiceErrorType errorCode, /* I - Error, if any */ - const char *serviceName, /* I - Name of service/device */ - const char *regtype, /* I - Type of service */ - const char *replyDomain, /* I - Service domain */ - void *context) /* I - Services array */ -{ - /* - * Only process "add" data... - */ - - (void)sdRef; - (void)interfaceIndex; - - if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) - return; - - /* - * Get the device... - */ - - get_service((cups_array_t *)context, serviceName, regtype, replyDomain); -} - - -/* - * 'browse_local_callback()' - Browse local devices. - */ - -static void DNSSD_API -browse_local_callback( - DNSServiceRef sdRef, /* I - Service reference */ - DNSServiceFlags flags, /* I - Option flags */ - uint32_t interfaceIndex, /* I - Interface number */ - DNSServiceErrorType errorCode, /* I - Error, if any */ + cups_dnssd_browse_t *browse, /* I - Browse request */ + void *context, /* I - Services array */ + cups_dnssd_flags_t flags, /* I - Flags */ + uint32_t if_index, /* I - Interface */ const char *serviceName, /* I - Name of service/device */ const char *regtype, /* I - Type of service */ - const char *replyDomain, /* I - Service domain */ - void *context) /* I - Services array */ + const char *replyDomain) /* I - Service domain */ { ippfind_srv_t *service; /* Service */ + if (getenv("IPPFIND_DEBUG")) + fprintf(stderr, "B flags=0x%04X, if_index=%u, serviceName=\"%s\", regtype=\"%s\", replyDomain=\"%s\"\n", flags, if_index, serviceName, regtype, replyDomain); + + (void)browse; /* * Only process "add" data... */ - (void)sdRef; - (void)interfaceIndex; - - if (errorCode != kDNSServiceErr_NoError || !(flags & kDNSServiceFlagsAdd)) + if ((flags & CUPS_DNSSD_FLAGS_ERROR) || !(flags & CUPS_DNSSD_FLAGS_ADD)) return; /* * Get the device... */ - service = get_service((cups_array_t *)context, serviceName, regtype, - replyDomain); - service->is_local = 1; + service = get_service((ippfind_srvs_t *)context, serviceName, regtype, replyDomain); + if (if_index == CUPS_DNSSD_IF_INDEX_LOCAL) + service->is_local = 1; } -#endif /* HAVE_MDNSRESPONDER */ - - -#ifdef HAVE_AVAHI -/* - * 'browse_callback()' - Browse devices. - */ - -static void -browse_callback( - AvahiServiceBrowser *browser, /* I - Browser */ - AvahiIfIndex interface, /* I - Interface index (unused) */ - AvahiProtocol protocol, /* I - Network protocol (unused) */ - AvahiBrowserEvent event, /* I - What happened */ - const char *name, /* I - Service name */ - const char *type, /* I - Registration type */ - const char *domain, /* I - Domain */ - AvahiLookupResultFlags flags, /* I - Flags */ - void *context) /* I - Services array */ -{ - AvahiClient *client = avahi_service_browser_get_client(browser); - /* Client information */ - ippfind_srv_t *service; /* Service information */ - - - (void)interface; - (void)protocol; - (void)context; - - switch (event) - { - case AVAHI_BROWSER_FAILURE: - fprintf(stderr, "DEBUG: browse_callback: %s\n", - avahi_strerror(avahi_client_errno(client))); - bonjour_error = 1; - avahi_simple_poll_quit(avahi_poll); - break; - - case AVAHI_BROWSER_NEW: - /* - * This object is new on the network. Create a device entry for it if - * it doesn't yet exist. - */ - - service = get_service((cups_array_t *)context, name, type, domain); - - if (flags & AVAHI_LOOKUP_RESULT_LOCAL) - service->is_local = true; - break; - - case AVAHI_BROWSER_REMOVE: - case AVAHI_BROWSER_ALL_FOR_NOW: - case AVAHI_BROWSER_CACHE_EXHAUSTED: - break; - } -} - - -/* - * 'client_callback()' - Avahi client callback function. - */ - -static void -client_callback( - AvahiClient *client, /* I - Client information (unused) */ - AvahiClientState state, /* I - Current state */ - void *context) /* I - User data (unused) */ -{ - (void)client; - (void)context; - - /* - * If the connection drops, quit. - */ - - if (state == AVAHI_CLIENT_FAILURE) - { - fputs("DEBUG: Avahi connection failed.\n", stderr); - bonjour_error = 1; - avahi_simple_poll_quit(avahi_poll); - } -} -#endif /* HAVE_AVAHI */ /* @@ -1626,123 +1304,7 @@ static int /* O - Result of comparison */ compare_services(ippfind_srv_t *a, /* I - First device */ ippfind_srv_t *b) /* I - Second device */ { - return (strcmp(a->name, b->name)); -} - - -/* - * 'dnssd_error_string()' - Return an error string for an error code. - */ - -static const char * /* O - Error message */ -dnssd_error_string(int error) /* I - Error number */ -{ -# ifdef HAVE_MDNSRESPONDER - switch (error) - { - case kDNSServiceErr_NoError : - return ("OK."); - - default : - case kDNSServiceErr_Unknown : - return ("Unknown error."); - - case kDNSServiceErr_NoSuchName : - return ("Service not found."); - - case kDNSServiceErr_NoMemory : - return ("Out of memory."); - - case kDNSServiceErr_BadParam : - return ("Bad parameter."); - - case kDNSServiceErr_BadReference : - return ("Bad service reference."); - - case kDNSServiceErr_BadState : - return ("Bad state."); - - case kDNSServiceErr_BadFlags : - return ("Bad flags."); - - case kDNSServiceErr_Unsupported : - return ("Unsupported."); - - case kDNSServiceErr_NotInitialized : - return ("Not initialized."); - - case kDNSServiceErr_AlreadyRegistered : - return ("Already registered."); - - case kDNSServiceErr_NameConflict : - return ("Name conflict."); - - case kDNSServiceErr_Invalid : - return ("Invalid name."); - - case kDNSServiceErr_Firewall : - return ("Firewall prevents registration."); - - case kDNSServiceErr_Incompatible : - return ("Client library incompatible."); - - case kDNSServiceErr_BadInterfaceIndex : - return ("Bad interface index."); - - case kDNSServiceErr_Refused : - return ("Server prevents registration."); - - case kDNSServiceErr_NoSuchRecord : - return ("Record not found."); - - case kDNSServiceErr_NoAuth : - return ("Authentication required."); - - case kDNSServiceErr_NoSuchKey : - return ("Encryption key not found."); - - case kDNSServiceErr_NATTraversal : - return ("Unable to traverse NAT boundary."); - - case kDNSServiceErr_DoubleNAT : - return ("Unable to traverse double-NAT boundary."); - - case kDNSServiceErr_BadTime : - return ("Bad system time."); - - case kDNSServiceErr_BadSig : - return ("Bad signature."); - - case kDNSServiceErr_BadKey : - return ("Bad encryption key."); - - case kDNSServiceErr_Transient : - return ("Transient error occurred - please try again."); - - case kDNSServiceErr_ServiceNotRunning : - return ("Server not running."); - - case kDNSServiceErr_NATPortMappingUnsupported : - return ("NAT doesn't support NAT-PMP or UPnP."); - - case kDNSServiceErr_NATPortMappingDisabled : - return ("NAT supports NAT-PNP or UPnP but it is disabled."); - - case kDNSServiceErr_NoRouter : - return ("No Internet/default router configured."); - - case kDNSServiceErr_PollingMode : - return ("Service polling mode error."); - -#ifndef _WIN32 - case kDNSServiceErr_Timeout : - return ("Service timeout."); -#endif /* !_WIN32 */ - } - -# elif defined(HAVE_AVAHI) - return (avahi_strerror(error)); -# endif /* HAVE_MDNSRESPONDER */ + return (_cups_strcasecmp(a->name, b->name)); } @@ -2131,15 +1693,16 @@ exec_program(ippfind_srv_t *service, /* I - Service */ */ static ippfind_srv_t * /* O - Service */ -get_service(cups_array_t *services, /* I - Service array */ - const char *serviceName, /* I - Name of service/device */ - const char *regtype, /* I - Type of service */ - const char *replyDomain) /* I - Service domain */ +get_service(ippfind_srvs_t *services, /* I - Service array */ + const char *serviceName,/* I - Name of service/device */ + const char *regtype, /* I - Type of service */ + const char *replyDomain)/* I - Service domain */ { + size_t i, /* Looping var */ + count; /* Number of services */ ippfind_srv_t key, /* Search key */ *service; /* Service */ - char fullName[kDNSServiceMaxDomainName]; - /* Full name for query */ + char fullName[1024]; /* Full name for query */ /* @@ -2149,13 +1712,20 @@ get_service(cups_array_t *services, /* I - Service array */ key.name = (char *)serviceName; key.regtype = (char *)regtype; - for (service = cupsArrayFind(services, &key); - service; - service = cupsArrayGetNext(services)) - if (_cups_strcasecmp(service->name, key.name)) - break; - else if (!strcmp(service->regtype, key.regtype)) + cupsRWLockRead(&services->rwlock); + for (i = 0, count = cupsArrayGetCount(services->services); i < count; i ++) + { + service = (ippfind_srv_t *)cupsArrayGetElement(services->services, i); + + if (!_cups_strcasecmp(service->name, key.name) && !strcmp(service->regtype, key.regtype)) + { + cupsRWUnlock(&services->rwlock); return (service); + } + else if (_cups_strcasecmp(service->name, key.name) > 0) + break; + } + cupsRWUnlock(&services->rwlock); /* * Yes, add the service... @@ -2168,20 +1738,16 @@ get_service(cups_array_t *services, /* I - Service array */ service->domain = strdup(replyDomain); service->regtype = strdup(regtype); - cupsArrayAdd(services, service); + cupsRWLockWrite(&services->rwlock); + cupsArrayAdd(services->services, service); + cupsRWUnlock(&services->rwlock); /* * Set the "full name" of this service, which is used for queries and * resolves... */ -#ifdef HAVE_MDNSRESPONDER - DNSServiceConstructFullName(fullName, serviceName, regtype, replyDomain); -#else /* HAVE_AVAHI */ - avahi_service_name_join(fullName, kDNSServiceMaxDomainName, serviceName, - regtype, replyDomain); -#endif /* HAVE_MDNSRESPONDER */ - + cupsDNSSDAssembleFullName(fullName, sizeof(fullName), serviceName, regtype, replyDomain); service->fullName = strdup(fullName); return (service); @@ -2507,159 +2073,48 @@ new_expr(ippfind_op_t op, /* I - Operation */ } -#ifdef HAVE_AVAHI -/* - * 'poll_callback()' - Wait for input on the specified file descriptors. - * - * Note: This function is needed because avahi_simple_poll_iterate is broken - * and always uses a timeout of 0 (!) milliseconds. - * (Avahi Ticket #364) - */ - -static int /* O - Number of file descriptors matching */ -poll_callback( - struct pollfd *pollfds, /* I - File descriptors */ - unsigned int num_pollfds, /* I - Number of file descriptors */ - int timeout, /* I - Timeout in milliseconds (unused) */ - void *context) /* I - User data (unused) */ -{ - int val; /* Return value */ - - - (void)timeout; - (void)context; - - val = poll(pollfds, num_pollfds, 500); - - if (val > 0) - avahi_got_data = 1; - - return (val); -} -#endif /* HAVE_AVAHI */ - - /* * 'resolve_callback()' - Process resolve data. */ -#ifdef HAVE_MDNSRESPONDER -static void DNSSD_API +static void resolve_callback( - DNSServiceRef sdRef, /* I - Service reference */ - DNSServiceFlags flags, /* I - Data flags */ - uint32_t interfaceIndex, /* I - Interface */ - DNSServiceErrorType errorCode, /* I - Error, if any */ - const char *fullName, /* I - Full service name */ - const char *hostTarget, /* I - Hostname */ - uint16_t port, /* I - Port number (network byte order) */ - uint16_t txtLen, /* I - Length of TXT record data */ - const unsigned char *txtRecord, /* I - TXT record data */ - void *context) /* I - Service */ + cups_dnssd_resolve_t *resolve, /* I - Resolver */ + void *context, /* I - Service */ + cups_dnssd_flags_t flags, /* I - Flags */ + uint32_t if_index, /* I - Interface index */ + const char *fullName, /* I - Full service name */ + const char *hostTarget, /* I - Hostname */ + uint16_t port, /* I - Port number */ + size_t num_txt, /* I - Number of TXT key/value pairs */ + cups_option_t *txt) /* I - TXT key/value pairs */ { - char key[256], /* TXT key value */ - *value; /* Value from TXT record */ - const unsigned char *txtEnd; /* End of TXT record */ - uint8_t valueLen; /* Length of value */ ippfind_srv_t *service = (ippfind_srv_t *)context; /* Service */ + size_t i; /* Looping var */ + char *value; /* Pointer into value */ - /* - * Only process "add" data... - */ + if (getenv("IPPFIND_DEBUG")) + fprintf(stderr, "R flags=0x%04X, if_index=%u, fullName=\"%s\", hostTarget=\"%s\", port=%u, num_txt=%u, txt=%p\n", flags, if_index, fullName, hostTarget, port, (unsigned)num_txt, txt); - (void)sdRef; - (void)flags; - (void)interfaceIndex; + (void)resolve; + (void)if_index; (void)fullName; - if (errorCode != kDNSServiceErr_NoError) - { - _cupsLangPrintf(stderr, _("ippfind: Unable to browse or resolve: %s"), - dnssd_error_string(errorCode)); - bonjour_error = 1; - return; - } - - service->is_resolved = true; - service->host = strdup(hostTarget); - service->port = ntohs(port); - - value = service->host + strlen(service->host) - 1; - if (value >= service->host && *value == '.') - *value = '\0'; - /* - * Loop through the TXT key/value pairs and add them to an array... + * Only process "add" data... */ - for (txtEnd = txtRecord + txtLen; txtRecord < txtEnd; txtRecord += valueLen) - { - /* - * Ignore bogus strings... - */ - - valueLen = *txtRecord++; - - memcpy(key, txtRecord, valueLen); - key[valueLen] = '\0'; - - if ((value = strchr(key, '=')) == NULL) - continue; - - *value++ = '\0'; - - /* - * Add to array of TXT values... - */ - - service->num_txt = cupsAddOption(key, value, service->num_txt, - &(service->txt)); - } - - set_service_uri(service); -} - - -#elif defined(HAVE_AVAHI) -static void -resolve_callback( - AvahiServiceResolver *resolver, /* I - Resolver */ - AvahiIfIndex interface, /* I - Interface */ - AvahiProtocol protocol, /* I - Address protocol */ - AvahiResolverEvent event, /* I - Event */ - const char *serviceName,/* I - Service name */ - const char *regtype, /* I - Registration type */ - const char *replyDomain,/* I - Domain name */ - const char *hostTarget, /* I - FQDN */ - const AvahiAddress *address, /* I - Address */ - uint16_t port, /* I - Port number */ - AvahiStringList *txt, /* I - TXT records */ - AvahiLookupResultFlags flags, /* I - Lookup flags */ - void *context) /* I - Service */ -{ - char key[256], /* TXT key */ - *value; /* TXT value */ - ippfind_srv_t *service = (ippfind_srv_t *)context; - /* Service */ - AvahiStringList *current; /* Current TXT key/value pair */ - - - (void)address; - - if (event != AVAHI_RESOLVER_FOUND) + if (flags & CUPS_DNSSD_FLAGS_ERROR) { bonjour_error = 1; - - avahi_service_resolver_free(resolver); - avahi_simple_poll_quit(avahi_poll); return; } - service->is_resolved = 1; + service->is_resolved = true; service->host = strdup(hostTarget); - service->port = port; + service->port = ntohs(port); value = service->host + strlen(service->host) - 1; if (value >= service->host && *value == '.') @@ -2669,34 +2124,11 @@ resolve_callback( * Loop through the TXT key/value pairs and add them to an array... */ - for (current = txt; current; current = current->next) - { - /* - * Ignore bogus strings... - */ - - if (current->size > (sizeof(key) - 1)) - continue; - - memcpy(key, current->text, current->size); - key[current->size] = '\0'; - - if ((value = strchr(key, '=')) == NULL) - continue; - - *value++ = '\0'; - - /* - * Add to array of TXT values... - */ - - service->num_txt = cupsAddOption(key, value, service->num_txt, - &(service->txt)); - } + for (i = 0; i < num_txt; i ++) + service->num_txt = cupsAddOption(txt[i].name, txt[i].value, service->num_txt, &service->txt); set_service_uri(service); } -#endif /* HAVE_MDNSRESPONDER */ /* @@ -2752,8 +2184,7 @@ set_service_uri(ippfind_srv_t *service) /* I - Service */ service->resource = strdup(uri); } - httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, - service->host, service->port, service->resource); + httpAssembleURI(HTTP_URI_CODING_ALL, uri, sizeof(uri), scheme, NULL, service->host, service->port, service->resource); service->uri = strdup(uri); } From 25136fd3c5319c3e1eba57c88dcefa7c2192cad2 Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Wed, 31 Aug 2022 20:32:07 -0400 Subject: [PATCH 19/19] Make Windows use mDNSResponder for now. --- cups/dnssd.c | 159 ++++++++++++++++++++++++++------------------------- 1 file changed, 81 insertions(+), 78 deletions(-) diff --git a/cups/dnssd.c b/cups/dnssd.c index 04780b21a..ea44e7b9e 100644 --- a/cups/dnssd.c +++ b/cups/dnssd.c @@ -18,11 +18,11 @@ # include #endif // __APPLE__ -#if _WIN32 -# include -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER # include # include +#elif _WIN32 +# include #else // HAVE_AVAHI # include # include @@ -33,7 +33,7 @@ # include # include # define AVAHI_DNS_TYPE_LOC 29 // Per RFC 1876 -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER // @@ -55,17 +55,17 @@ struct _cups_dnssd_s // DNS-SD context SCDynamicStoreRef sc; // Dyanmic store context for host info #endif // __APPLE__ -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceRef ref; // Master service reference cups_thread_t monitor; // Monitoring thread +#elif _WIN32 + #else // HAVE_AVAHI AvahiClient *client; // Avahi client connection AvahiSimplePoll *poll; // Avahi poll class cups_thread_t monitor; // Monitoring thread -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER }; struct _cups_dnssd_browse_s // DNS-SD browse request @@ -74,12 +74,12 @@ struct _cups_dnssd_browse_s // DNS-SD browse request cups_dnssd_browse_cb_t cb; // Browse callback void *cb_data; // Browse callback data -#if _WIN32 -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceRef ref; // Browse reference +#elif _WIN32 #else // HAVE_AVAHI AvahiServiceBrowser *browser; // Browser -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER }; struct _cups_dnssd_query_s // DNS-SD query request @@ -88,12 +88,12 @@ struct _cups_dnssd_query_s // DNS-SD query request cups_dnssd_query_cb_t cb; // Query callback void *cb_data; // Query callback data -#if _WIN32 -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceRef ref; // Query reference +#elif _WIN32 #else // HAVE_AVAHI AvahiRecordBrowser *browser; // Browser -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER }; struct _cups_dnssd_resolve_s // DNS-SD resolve request @@ -102,12 +102,12 @@ struct _cups_dnssd_resolve_s // DNS-SD resolve request cups_dnssd_resolve_cb_t cb; // Resolve callback void *cb_data; // Resolve callback data -#if _WIN32 -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceRef ref; // Resolve reference +#elif _WIN32 #else // HAVE_AVAHI AvahiServiceResolver *resolver; // Resolver -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER }; struct _cups_dnssd_service_s // DNS-SD service registration @@ -120,14 +120,14 @@ struct _cups_dnssd_service_s // DNS-SD service registration unsigned char loc[16]; // LOC record data bool loc_set; // Is the location data set? -#if _WIN32 -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER size_t num_refs; // Number of service references DNSServiceRef refs[16]; // Service references DNSRecordRef loc_refs[16]; // Service location records +#elif _WIN32 #else // HAVE_AVAHI AvahiEntryGroup *group; // Group of services under this name -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER }; @@ -146,9 +146,7 @@ static void report_error(cups_dnssd_t *dnssd, const char *message, ...) _CUPS_F static void apple_sc_cb(SCDynamicStoreRef sc, CFArrayRef changed, cups_dnssd_t *dnssd); #endif // __APPLE__ -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER static void *mdns_monitor(cups_dnssd_t *dnssd); static void mdns_browse_cb(DNSServiceRef ref, DNSServiceFlags flags, uint32_t interfaceIndex, DNSServiceErrorType error, const char *name, const char *regtype, const char *domain, cups_dnssd_browse_t *browse); static void mdns_query_cb(DNSServiceRef ref, DNSServiceFlags flags, uint32_t if_index, DNSServiceErrorType error, const char *name, uint16_t rrtype, uint16_t rrclass, uint16_t rdlen, const void *rdata, uint32_t ttl, cups_dnssd_query_t *query); @@ -157,6 +155,8 @@ static void mdns_service_cb(DNSServiceRef ref, DNSServiceFlags flags, DNSServic static const char *mdns_strerror(DNSServiceErrorType errorCode); static cups_dnssd_flags_t mdns_to_cups(DNSServiceFlags flags, DNSServiceErrorType error); +#elif _WIN32 + #else // HAVE_AVAHI static void avahi_browse_cb(AvahiServiceBrowser *browser, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, const char *type, const char *domain, AvahiLookupResultFlags flags, cups_dnssd_browse_t *browse); static void avahi_client_cb(AvahiClient *c, AvahiClientState state, cups_dnssd_t *dnssd); @@ -164,7 +164,7 @@ static void *avahi_monitor(cups_dnssd_t *dnssd); static void avahi_query_cb(AvahiRecordBrowser *browser, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiBrowserEvent event, const char *fullName, uint16_t rrclass, uint16_t rrtype, const void *rdata, size_t rdlen, AvahiLookupResultFlags flags, cups_dnssd_query_t *query); static void avahi_resolve_cb(AvahiServiceResolver *resolver, AvahiIfIndex if_index, AvahiProtocol protocol, AvahiResolverEvent event, const char *name, const char *type, const char *domain, const char *host_name, const AvahiAddress *address, uint16_t port, AvahiStringList *txtrec, AvahiLookupResultFlags flags, cups_dnssd_resolve_t *resolve); static void avahi_service_cb(AvahiEntryGroup *srv, AvahiEntryGroupState state, cups_dnssd_service_t *service); -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER // @@ -187,18 +187,18 @@ cupsDNSSDAssembleFullName( if (!fullname || !fullsize || !name || !type) return (false); -#if _WIN32 - return (false); - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER if (fullsize < kDNSServiceMaxDomainName) return (false); return (DNSServiceConstructFullName(fullname, name, type, domain) == kDNSServiceErr_NoError); +#elif _WIN32 + return (false); + #else // HAVE_AVAHI return (!avahi_service_name_join(fullname, fullsize, name, type, domain)); -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER } @@ -400,15 +400,16 @@ cupsDNSSDDelete(cups_dnssd_t *dnssd) // I - DNS-SD context cupsArrayDelete(dnssd->resolves); cupsArrayDelete(dnssd->services); -#if _WIN32 -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER cupsThreadCancel(dnssd->monitor); DNSServiceRefDeallocate(dnssd->ref); +#elif _WIN32 + #else // HAVE_AVAHI cupsThreadCancel(dnssd->monitor); avahi_simple_poll_free(dnssd->poll); -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER cupsMutexUnlock(&dnssd->mutex); cupsMutexDestroy(&dnssd->mutex); @@ -463,7 +464,7 @@ cupsDNSSDGetHostName( #else // HAVE_AVAHI cupsCopyString(buffer, avahi_client_get_host_name_fqdn(dnssd->client), bufsize); -#endif // _WIN32 +#endif // _WIN32 || HAVE_MDNSRESPONDER return (buffer); } @@ -528,9 +529,7 @@ cupsDNSSDNew( #endif // __APPLE__ // Setup the DNS-SD connection and monitor thread... -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceErrorType error; // Error code if ((error = DNSServiceCreateConnection(&dnssd->ref)) == kDNSServiceErr_NoError) @@ -553,6 +552,8 @@ cupsDNSSDNew( return (NULL); } +#elif _WIN32 + #else // HAVE_AVAHI int error; // Error code @@ -579,7 +580,7 @@ cupsDNSSDNew( } cupsThreadDetach(dnssd->monitor); -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER return (dnssd); } @@ -683,9 +684,7 @@ cupsDNSSDBrowseNew( } } -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceErrorType error; // Error, if any browse->ref = dnssd->ref; @@ -697,6 +696,8 @@ cupsDNSSDBrowseNew( goto done; } +#elif _WIN32 + #else // HAVE_AVAHI browse->browser = avahi_service_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, types, NULL, 0, (AvahiServiceBrowserCallback)avahi_browse_cb, browse); @@ -707,7 +708,7 @@ cupsDNSSDBrowseNew( browse = NULL; goto done; } -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER cupsArrayAdd(dnssd->browses, browse); @@ -816,9 +817,7 @@ cupsDNSSDQueryNew( } } -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceErrorType error; // Error, if any query->ref = dnssd->ref; @@ -830,6 +829,8 @@ cupsDNSSDQueryNew( goto done; } +#elif _WIN32 + #else // HAVE_AVAHI query->browser = avahi_record_browser_new(dnssd->client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, fullname, AVAHI_DNS_CLASS_IN, rrtype, 0, (AvahiRecordBrowserCallback)avahi_query_cb, query); @@ -840,7 +841,7 @@ cupsDNSSDQueryNew( query = NULL; goto done; } -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER cupsArrayAdd(dnssd->queries, query); @@ -950,9 +951,7 @@ cupsDNSSDResolveNew( } } -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceErrorType error; // Error, if any resolve->ref = dnssd->ref; @@ -964,6 +963,8 @@ cupsDNSSDResolveNew( goto done; } +#elif _WIN32 + #else // HAVE_AVAHI resolve->resolver = avahi_service_resolver_new(dnssd->client, if_index, AVAHI_PROTO_UNSPEC, name, type, domain, AVAHI_PROTO_UNSPEC, /*flags*/0, (AvahiServiceResolverCallback)avahi_resolve_cb, resolve); @@ -974,7 +975,7 @@ cupsDNSSDResolveNew( resolve = NULL; goto done; } -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER cupsArrayAdd(dnssd->resolves, resolve); @@ -1016,9 +1017,7 @@ cupsDNSSDServiceAdd( if (!service || !types) return (false); -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceErrorType error; // Error, if any TXTRecordRef txtrec, // TXT record *txtptr = NULL; // Pointer to TXT record, if any @@ -1065,6 +1064,8 @@ cupsDNSSDServiceAdd( service->num_refs ++; +#elif _WIN32 + #else // HAVE_AVAHI int error; // Error code AvahiStringList *txtrec = NULL; // TXT record string list @@ -1117,7 +1118,7 @@ cupsDNSSDServiceAdd( if (txtrec) avahi_string_list_free(txtrec); -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER done: @@ -1208,8 +1209,8 @@ cupsDNSSDServiceNew( service->name = strdup(name); service->if_index = if_index; -#if _WIN32 -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER +#elif _WIN32 #else // HAVE_AVAHI service->group = avahi_entry_group_new(dnssd->client, (AvahiEntryGroupCallback)avahi_service_cb, service); @@ -1220,7 +1221,7 @@ cupsDNSSDServiceNew( service = NULL; goto done; } -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER cupsMutexLock(&dnssd->mutex); @@ -1359,10 +1360,10 @@ cupsDNSSDServiceSetLocation( service->loc_set = true; -#if _WIN32 +#ifdef HAVE_MDNSRESPONDER // Add LOC record in cupsDNSSDServiceAdd() -#elif defined(HAVE_MDNSRESPONDER) +#elif _WIN32 // Add LOC record in cupsDNSSDServiceAdd() #else // HAVE_AVAHI @@ -1374,7 +1375,7 @@ cupsDNSSDServiceSetLocation( report_error(service->dnssd, "Unable to register LOC record for '%s': %s", service->name, avahi_strerror(error)); ret = false; } -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER return (ret); } @@ -1388,13 +1389,14 @@ static void delete_browse( cups_dnssd_browse_t *browse) // I - Browse request { -#if _WIN32 -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceRefDeallocate(browse->ref); +#elif _WIN32 + #else // HAVE_AVAHI avahi_service_browser_free(browse->browser); -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER free(browse); } @@ -1408,15 +1410,14 @@ static void delete_query( cups_dnssd_query_t *query) // I - Query request { -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceRefDeallocate(query->ref); +#elif _WIN32 + #else // HAVE_AVAHI avahi_record_browser_free(query->browser); -#endif // _WIN32 - +#endif // HAVE_MDNSRESPONDER } @@ -1428,14 +1429,14 @@ static void delete_resolve( cups_dnssd_resolve_t *resolve) // I - Resolve request { -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER DNSServiceRefDeallocate(resolve->ref); +#elif _WIN32 + #else // HAVE_AVAHI avahi_service_resolver_free(resolve->resolver); -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER } @@ -1450,16 +1451,17 @@ delete_service( { free(service->name); -#if _WIN32 -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER size_t i; // Looping var for (i = 0; i < service->num_refs; i ++) DNSServiceRefDeallocate(service->refs[i]); +#elif _WIN32 + #else // HAVE_AVAHI avahi_entry_group_free(service->group); -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER free(service); } @@ -1548,9 +1550,7 @@ apple_sc_cb(SCDynamicStoreRef sc, // I - Dynamic store context #endif // __APPLE__ -#if _WIN32 - -#elif defined(HAVE_MDNSRESPONDER) +#ifdef HAVE_MDNSRESPONDER // // 'mdns_browse_cb()' - Handle DNS-SD browse callbacks from mDNSResponder. // @@ -1824,6 +1824,9 @@ mdns_to_cups( } +#elif _WIN32 + + #else // HAVE_AVAHI // // 'avahi_browse_cb()' - Handle browse callbacks from Avahi. @@ -2005,4 +2008,4 @@ avahi_service_cb( (service->cb)(service, service->cb_data, state == AVAHI_ENTRY_GROUP_COLLISION ? CUPS_DNSSD_FLAGS_COLLISION : CUPS_DNSSD_FLAGS_NONE); } -#endif // _WIN32 +#endif // HAVE_MDNSRESPONDER