diff options
author | jacobs <none@none> | 2007-10-23 07:51:21 -0700 |
---|---|---|
committer | jacobs <none@none> | 2007-10-23 07:51:21 -0700 |
commit | 4e9cfc9a015e8ca7d41f7d018c74dc8a692305b3 (patch) | |
tree | 7637fe253bcc25006346dd639303fbd5ad5adb3c | |
parent | a93a1f58a8763fa69172980b98e3d24720c1136e (diff) | |
download | illumos-gate-4e9cfc9a015e8ca7d41f7d018c74dc8a692305b3.tar.gz |
PSARC/2007/499 Automatic discovery of network attached printers
6607736 Solaris should detect network attached printers
30 files changed, 2402 insertions, 100 deletions
diff --git a/usr/src/cmd/hal/addons/Makefile b/usr/src/cmd/hal/addons/Makefile index b27a0f7295..9afe789d5c 100644 --- a/usr/src/cmd/hal/addons/Makefile +++ b/usr/src/cmd/hal/addons/Makefile @@ -25,7 +25,7 @@ # ident "%Z%%M% %I% %E% SMI" # -SUBDIRS = storage acpi +SUBDIRS = storage acpi network-devices all := TARGET= all install := TARGET= install diff --git a/usr/src/cmd/hal/addons/network-devices/Makefile b/usr/src/cmd/hal/addons/network-devices/Makefile new file mode 100644 index 0000000000..580c5e674c --- /dev/null +++ b/usr/src/cmd/hal/addons/network-devices/Makefile @@ -0,0 +1,81 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +PROG = hald-addon-network-discovery +OBJS = addon-network-discovery.o probe-snmp.o snmp.o logger.o cache.o common.o printer.o + +MANIFEST = network-discovery.xml +SVCMETHOD = svc-network-discovery + +include ../../../Makefile.cmd +include ../../Makefile.hal + +ROOTMANIFESTDIR = $(ROOTSVCNETWORK) +$(ROOTMANIFEST) := FILEMODE = 444 +$(ROOTLIBSVCMETHOD)/$(SVCMETHOD):= FILEMODE = 555 + +ROOTCMDDIR = $(ROOTLIB_HAL) + +LDLIBS += -lc -ldbus-1 -lhal -lglib-2.0 -ldbus-glib-1 +LDLIBS += -lnsl -lsocket +LDLIBS += -L$(SFWLIBDIR) -R$(SFWLIBDIR) $(ZIGNORE) -lnetsnmp + +CPPFLAGS += $(HAL_DBUS_CPPFLAGS) $(HAL_GLIB_CPPFLAGS) $(HAL_CONFIG_CPPFLAGS) +CPPFLAGS += -I$(ROOT)/usr/include/hal -I../../hald -I../../utils +CPPFLAGS += -I$(SFWINCDIR) +C99MODE = $(C99_ENABLE) + +.KEEP_STATE: + +all: $(PROG) + +probe-snmp.o: ../../probing/network-printer/probe-snmp.c + $(COMPILE.c) -o $@ ../../probing/network-printer/probe-snmp.c + $(POST_PROCESS_O) + +logger.o: ../../hald/logger.c + $(COMPILE.c) -o $@ ../../hald/logger.c + $(POST_PROCESS_O) + +printer.o: ../../utils/printer.c + $(COMPILE.c) -o $@ ../../utils/printer.c + $(POST_PROCESS_O) + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +install: all $(ROOTCMD) $(ROOTMANIFEST) $(ROOTSVCMETHOD) + +check: $(CHKMANIFEST) + +clean: + $(RM) $(OBJS) $(PROG) + +FRC: + +include ../../../Makefile.targ diff --git a/usr/src/cmd/hal/addons/network-devices/addon-network-discovery.c b/usr/src/cmd/hal/addons/network-devices/addon-network-discovery.c new file mode 100644 index 0000000000..c685a494e9 --- /dev/null +++ b/usr/src/cmd/hal/addons/network-devices/addon-network-discovery.c @@ -0,0 +1,339 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <fcntl.h> +#include <sys/dkio.h> +#include <sys/stat.h> +#include <priv.h> +#include <glib.h> + +#include <dbus/dbus-glib-lowlevel.h> +#include <libhal.h> + +#include "../../hald/logger.h" + +#include "network-discovery.h" +#include "printer.h" + +#define DBUS_INTERFACE "org.freedesktop.Hal.Device.NetworkDiscovery" +#define NP(x) (x?x:"NULL") +#define STRDUP(x) (x?strdup(x):NULL) + +typedef struct { + LibHalContext *ctx; + gboolean enabled; + char *parent; + char *community; + char *network; +} nds_snmp_cbdata_t; + +static nds_snmp_cbdata_t *snmp_cb_data = NULL; + +static int +nds_snmp_scan(LibHalContext *ctx, char *parent, char *community, char *network) +{ + time_t start; + + HAL_DEBUG(("nds_snmp_scan(0x%8.8x, %s, %s, %s)", + ctx, NP(parent), NP(community), NP(network))); + HAL_DEBUG(("NetworkDiscovery snmp scan initated")); + + /* scan for devices */ + time(&start); + if (network == NULL) { + GList *elem, *list = broadcast_addresses(); + + for (elem = list; elem != NULL; elem = g_list_next(elem)) { + scan_for_devices_using_snmp(ctx, parent, community, + (char *)elem->data); + free(elem->data); + } + g_list_free(list); + } else + scan_for_devices_using_snmp(ctx, parent, community, network); + + /* remove devices that haven't been seen since before this scan */ + scan_for_stale_devices(ctx, start); + + HAL_DEBUG(("NetworkDiscovery snmp scan completed")); + + return (0); +} + +static gboolean +nds_snmp_scan_cb(gpointer data) +{ + nds_snmp_cbdata_t *args = data; + + if (args->enabled == FALSE) { + if (args->parent) free(args->parent); + if (args->community) free(args->community); + if (args->network) free(args->network); + free(args); + return (FALSE); + } + + nds_snmp_scan(args->ctx, args->parent, args->community, args->network); + + return (TRUE); +} + +static int +nds_EnablePrinterScanningViaSNMP(LibHalContext *ctx, char *parent, int interval, + char *community, char *network) +{ + HAL_DEBUG(("NetworkDiscovery.EnablePrinterScanningViaSNMP(0x%8.8x, %s, %d, %s, %s)", + ctx, NP(parent), interval, NP(community), NP(network))); + + /* are we already discoverying network devices ? */ + if (snmp_cb_data != NULL) { + snmp_cb_data->enabled = FALSE; /* cancel it */ + } + + /* setup for network device discovery */ + if ((snmp_cb_data = calloc(1, sizeof (*snmp_cb_data))) != NULL) { + snmp_cb_data->ctx = ctx; + snmp_cb_data->enabled = TRUE; + snmp_cb_data->parent = STRDUP(parent); + snmp_cb_data->community = STRDUP(community); + snmp_cb_data->network = STRDUP(network); + + /* prime the pump with an initial scan */ + nds_snmp_scan(ctx, parent, community, network); + + /* add a regular network scan */ + g_timeout_add(interval * 1000, nds_snmp_scan_cb, snmp_cb_data); + } + + return (0); +} + +static int +nds_DisablePrinterScanningViaSNMP(LibHalContext *ctx) +{ + HAL_DEBUG(("NetworkDiscovery.DisablePrinterScanningViaSNMP(0x%8.8x)", ctx)); + + if (snmp_cb_data != NULL) + snmp_cb_data->enabled = FALSE; + snmp_cb_data = NULL; + + return (0); +} + +static int +nds_ScanForPrintersViaSNMP(LibHalContext *ctx, char *parent, char *community, + char *network) +{ + time_t start, stop; + + HAL_DEBUG(("NetworkDiscovery.ScanForPrintersViaSNMP(0x%8.8x, %s, %s, %s)", + ctx, NP(parent), NP(community), NP(network))); + + return (nds_snmp_scan(ctx, parent, community, network)); +} + +static DBusHandlerResult +nds_filter_function(DBusConnection *connection, DBusMessage *message, + void *user_data) +{ + LibHalContext *ctx = user_data; + DBusMessage *reply; + DBusError error; + const char *member = dbus_message_get_member(message); + const char *path = dbus_message_get_path(message); + int rc = -1; + + dbus_error_init(&error); + + HAL_DEBUG(("DBus message: %s, %s ", member, path)); + + if (dbus_message_is_method_call(message, + DBUS_INTERFACE, "EnablePrinterScanningViaSNMP")) { + int interval = -1; + char *udi = getenv("UDI"); + char *community = "public"; + char *network = "0.0.0.0"; + + dbus_message_get_args(message, &error, + DBUS_TYPE_INT32, &interval, + DBUS_TYPE_STRING, &community, + DBUS_TYPE_STRING, &network, + DBUS_TYPE_INVALID); + + if (strcmp(network, "0.0.0.0") == 0) + network = NULL; + + rc = nds_EnablePrinterScanningViaSNMP(ctx, udi, interval, + community, network); + } else if (dbus_message_is_method_call(message, + DBUS_INTERFACE, "ScanForPrintersViaSNMP")) { + int interval = -1; + char *udi = getenv("UDI"); + char *community = "public"; + char *network = "0.0.0.0"; + + dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &community, + DBUS_TYPE_STRING, &network, + DBUS_TYPE_INVALID); + + if (strcmp(network, "0.0.0.0") == 0) + network = NULL; + + rc = nds_ScanForPrintersViaSNMP(ctx, udi, community, network); + } else if (dbus_message_is_method_call(message, + DBUS_INTERFACE, "DisablePrinterScanningViaSNMP")) { + rc = nds_DisablePrinterScanningViaSNMP(ctx); + } else + HAL_WARNING(("Unknown DBus message: %s, %s ", member, path)); + + if (dbus_error_is_set(&error)) + dbus_error_free(&error); + + if ((reply = dbus_message_new_method_return(message)) == NULL) { + HAL_WARNING(("Could not allocate memory for the DBus reply")); + return (FALSE); + } + + dbus_message_append_args(reply, DBUS_TYPE_INT32, &rc, + DBUS_TYPE_INVALID); + + if (!dbus_connection_send(connection, reply, NULL)) { + HAL_WARNING(("Could not sent reply")); + } + dbus_connection_flush(connection); + dbus_message_unref(reply); + + return (DBUS_HANDLER_RESULT_HANDLED); +} + +static int +nds_claim_interface(LibHalContext *ctx, char *udi, DBusError *error) +{ + DBusConnection *connection; + char *interface_xml = + "<method name=\"EnablePrinterScanningViaSNMP\">\n" + " <arg name=\"interval\" direction=\"in\" type=\"i\"/>\n" + " <arg name=\"community\" direction=\"in\" type=\"s\"/>\n" + " <arg name=\"network\" direction=\"in\" type=\"s\"/>\n" + " <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n" + "</method>\n" + "<method name=\"DisablePrinterScanningViaSNMP\">\n" + " <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n" + "</method>\n" + "<method name=\"ScanForPrintersViaSNMP\">\n" + " <arg name=\"community\" direction=\"in\" type=\"s\"/>\n" + " <arg name=\"network\" direction=\"in\" type=\"s\"/>\n" + " <arg name=\"return_code\" direction=\"out\" type=\"i\"/>\n" + "</method>\n"; + + HAL_DEBUG(("nds_claim_interface(0x%8.8x, %s, 0x%8.8x): %s", + ctx, udi, error, DBUS_INTERFACE)); + + if ((connection = libhal_ctx_get_dbus_connection(ctx)) == NULL) { + HAL_WARNING(("Could not get DBus connection")); + return (-1); + } + + if (libhal_device_claim_interface(ctx, udi, + DBUS_INTERFACE, interface_xml, error) == 0) { + HAL_WARNING(("Could not claim interface: %s", error->message)); + return (-1); + } + + dbus_connection_setup_with_g_main(connection, NULL); + dbus_connection_add_filter(connection, nds_filter_function, ctx, NULL); + dbus_connection_set_exit_on_disconnect(connection, 0); + + return (0); +} + +static void +drop_privileges() +{ + priv_set_t *pPrivSet = NULL; + priv_set_t *lPrivSet = NULL; + + /* + * Start with the 'basic' privilege set and then remove any + * of the 'basic' privileges that will not be needed. + */ + if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) { + return; + } + + /* Clear privileges we will not need from the 'basic' set */ + (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY); + (void) priv_delset(pPrivSet, PRIV_PROC_EXEC); + (void) priv_delset(pPrivSet, PRIV_PROC_FORK); + (void) priv_delset(pPrivSet, PRIV_PROC_INFO); + (void) priv_delset(pPrivSet, PRIV_PROC_SESSION); + + /* Set the permitted privilege set. */ + if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) { + return; + } + + /* Clear the limit set. */ + if ((lPrivSet = priv_allocset()) == NULL) { + return; + } + + priv_emptyset(lPrivSet); + + if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) { + return; + } + + priv_freeset(lPrivSet); +} + + +int +main(int argc, char **argv) +{ + LibHalContext *ctx = NULL; + DBusError error; + GMainLoop *loop = g_main_loop_new(NULL, FALSE); + char *udi; + + if ((udi = getenv("UDI")) == NULL) { + return (0); + } + + drop_privileges(); + + setup_logger(); + + dbus_error_init(&error); + + if ((ctx = libhal_ctx_init_direct(&error)) == NULL) { + return (0); + } + + if (!libhal_device_addon_is_ready(ctx, udi, &error)) { + return (0); + } + + if (nds_claim_interface(ctx, udi, &error) != 0) { + return (0); + } + + g_main_loop_run(loop); + + /* NOTREACHED */ +} diff --git a/usr/src/cmd/hal/addons/network-devices/cache.c b/usr/src/cmd/hal/addons/network-devices/cache.c new file mode 100644 index 0000000000..27849cf3bd --- /dev/null +++ b/usr/src/cmd/hal/addons/network-devices/cache.c @@ -0,0 +1,106 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +#include <libhal.h> +#include <logger.h> + +#include <glib.h> + +#include "network-discovery.h" + +/* + * The interfaces in this file comprise a means of keeping track of devices + * that we have already seen and those that have gone missing. This allows + * us to quickly determine if we need to probe the device and quickly search + * for devices that are no longer available. + */ + +typedef struct { + LibHalContext *ctx; + time_t timestamp; +} removal_args_t; + +static GHashTable *seen = NULL; + +static gboolean +device_remove_if_stale(gpointer key, gpointer value, gpointer user_data) +{ + gboolean result = FALSE; + removal_args_t *args = user_data; + char *name = key; + time_t *val = value; + + HAL_DEBUG(("test stale: %s (%d > %d)", name, args->timestamp, *val)); + if (args->timestamp > *val) { + DBusError error; + char **udi = NULL; + int num = 0; + + dbus_error_init(&error); + udi = libhal_manager_find_device_string_match(args->ctx, + "network_device.address", name, + &num, &error); + + if (udi != NULL) { + int i; + + for (i = 0; i < num; i++) { + libhal_remove_device(args->ctx, udi[i], &error); + HAL_DEBUG(("remove: %s (%s)", name, udi[i])); + } + libhal_free_string_array(udi); + result = TRUE; + } + if (dbus_error_is_set(&error)) + dbus_error_free(&error); + } + + return (result); +} + +void +scan_for_stale_devices(LibHalContext *ctx, time_t timestamp) +{ + if (seen != NULL) { + removal_args_t args[1]; + + args->ctx = ctx; + args->timestamp = timestamp; + + g_hash_table_foreach_remove(seen, device_remove_if_stale, args); + } +} + +gboolean +device_seen(char *name) +{ + gboolean result; + char *key; + time_t *val; + + if (seen == NULL) + seen = g_hash_table_new_full(g_str_hash, g_str_equal, + free, free); + + result = g_hash_table_lookup_extended(seen, name, + (gpointer)&key, (gpointer)&val); + + if ((result == FALSE) && ((val = calloc(1, sizeof (*val))) != NULL)) { + g_hash_table_insert(seen, strdup(name), val); + } + (void) time(val); + HAL_DEBUG(("seen: %s (%d)", name, *val)); + + return (result); +} diff --git a/usr/src/cmd/hal/addons/network-devices/common.c b/usr/src/cmd/hal/addons/network-devices/common.c new file mode 100644 index 0000000000..720671236f --- /dev/null +++ b/usr/src/cmd/hal/addons/network-devices/common.c @@ -0,0 +1,351 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <signal.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <sys/sockio.h> +#include <net/if.h> +#include <net/if_arp.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <libhal.h> +#include <logger.h> + +#include <glib.h> + +#include "network-discovery.h" +#define NP(x) (x?x:"NULL") + +extern int snmp_printer_info(char *hostname, char *community, + char **manufacturer, char **model, char **description, + char **serial_no, char ***command_set, char **uri); + +void +network_device_name_to_udi(char *udi, size_t size, ...) +{ + va_list ap; + char *element; + int i; + + udi[0] = '\0'; + va_start(ap, size); + while ((element = va_arg(ap, char *)) != NULL) { + if (element[0] != '/') + strlcat(udi, "/", size); + strlcat(udi, element, size); + } + va_end(ap); + + for (i = 0; udi[i] != NULL; i++) + if (udi[i] == '.') + udi[i] = '_'; +} + +static void nop(int sig) {} + +static int +test_socket_access(struct in6_addr *addr, int port) +{ + int sd, rc; + struct sockaddr_in6 sin6; + void (*hndlr)(int); + + memset(&sin6, 0, sizeof (sin6)); + sin6.sin6_family = AF_INET6; + memcpy(&sin6.sin6_addr, addr, sizeof (*addr)); + sin6.sin6_port = htons(port); + + sd = socket(AF_INET6, SOCK_STREAM, 0); + hndlr = signal(SIGALRM, nop); + alarm(1); + rc = connect(sd, (struct sockaddr *)&sin6, sizeof (sin6)); + alarm(0); + if (hndlr != NULL) + signal(SIGALRM, hndlr); + close(sd); + + return ((rc < 0) ? 1 : 0); +} + +int +is_listening(char *hostname, int port) +{ + char *uri = NULL, addr_string[INET6_ADDRSTRLEN]; + struct in6_addr ipv6addr[1]; + int errnum; + struct hostent *hp; + + hp = getipnodebyname(hostname, AF_INET6, + AI_ALL | AI_ADDRCONFIG | AI_V4MAPPED, &errnum); + if (hp != NULL) { + (void) memcpy(&ipv6addr, hp->h_addr_list[0], hp->h_length); + } else + return (-1); + + return (test_socket_access(ipv6addr, port)); +} + +static char * +addr_to_string(char *prefix, uchar_t *mac, int mac_len, char *buf, int buf_len) +{ + int i, n = 0; + + buf[0] = '\0'; + if (prefix != NULL) + n = sprintf(buf, prefix); + for (i = 0; ((i < (mac_len)) && (n < buf_len)); i++) + n += sprintf(buf + n, "%2.2X", *mac++); + + return (buf); +} + +static char * +pseudo_serialno_from_addr(char *name) +{ + int sd, rc, errnum; + char buf[128]; + struct hostent *hp; + struct xarpreq ar; + + if (name == NULL) + return (NULL); + + memset(&ar, 0, sizeof (ar)); + + hp = getipnodebyname(name, AF_INET6, AI_ADDRCONFIG, &errnum); + if (hp != NULL) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ar.xarp_pa; + + sin6->sin6_family = AF_INET6; + (void) memcpy(&sin6->sin6_addr, hp->h_addr_list[0], + hp->h_length); + } else { + struct sockaddr_in *sin = (struct sockaddr_in *)&ar.xarp_pa; + + sin->sin_family = AF_INET; + sin->sin_addr.s_addr = inet_addr(name); + } + + sd = socket(AF_INET, SOCK_DGRAM, 0); + + ar.xarp_ha.sdl_family = AF_LINK; + rc = ioctl(sd, SIOCGXARP, (caddr_t)&ar); + + close(sd); + + if (ar.xarp_flags & ATF_COM) { /* use the MAC address */ + uchar_t *ea = (uchar_t *)LLADDR(&ar.xarp_ha); + + addr_to_string("LLADDR-", ea, ar.xarp_ha.sdl_alen, + buf, sizeof (buf)); + + } else if (hp != NULL) { /* use the IPv6 address */ + addr_to_string("IPV6ADDR-", (uchar_t *)&hp->h_addr_list[0], + hp->h_length, buf, sizeof (buf)); + } else { /* use the IPv4 address */ + struct sockaddr_in *sin = (struct sockaddr_in *)&ar.xarp_pa; + + addr_to_string("IPV4ADDR-", (uchar_t *)&sin->sin_addr.s_addr, 4, + buf, sizeof (buf)); + } + + return (strdup(buf)); +} + +int +add_network_printer(LibHalContext *ctx, char *base, char *hostaddr, + char *device, char *community) +{ + DBusError error; + int rc = -1; + char udi[128]; + char *tmp_udi = NULL; + static char *parent = NULL; + char *manufacturer = NULL, *model = NULL, *description = NULL, + *uri = NULL, *sn, *serial; + + sn = serial = pseudo_serialno_from_addr(hostaddr); + + if (parent == NULL) + parent = getenv("UDI"); + + dbus_error_init(&error); + + network_device_name_to_udi(udi, sizeof (udi), base, serial, NULL); + + if (libhal_device_exists(ctx, udi, &error) == TRUE) + goto out; + + if ((tmp_udi = libhal_new_device(ctx, &error)) == NULL) + goto out; + + snmp_printer_info(hostaddr, community, &manufacturer, &model, + &description, &serial, NULL, &uri); + + libhal_device_set_property_string(ctx, tmp_udi, + "info.parent", parent, &error); + + libhal_device_set_property_string(ctx, tmp_udi, + "info.category", "printer", &error); + + libhal_device_property_strlist_append(ctx, tmp_udi, + "info.capabilities", "printer", &error); + libhal_device_property_strlist_append(ctx, tmp_udi, + "info.capabilities", "network_device", &error); + + libhal_device_set_property_string(ctx, tmp_udi, + "network_device.address", hostaddr, &error); + + if ((community != NULL) && (strcasecmp(community, "public") != 0)) + libhal_device_set_property_string(ctx, tmp_udi, + "network_device.snmp_community", community, &error); + + if ((uri != NULL) || (device != NULL)) + libhal_device_set_property_string(ctx, tmp_udi, + "printer.device", (uri ? uri : device), &error); + + if (serial != NULL) + libhal_device_set_property_string(ctx, tmp_udi, + "printer.serial", serial, &error); + + if (manufacturer != NULL) + libhal_device_set_property_string(ctx, tmp_udi, + "printer.vendor", manufacturer, &error); + + if (model != NULL) + libhal_device_set_property_string(ctx, tmp_udi, + "printer.product", model, &error); + + if (description != NULL) + libhal_device_set_property_string(ctx, tmp_udi, + "printer.description", description, &error); + + /* commit the changes to the new UDI */ + rc = libhal_device_commit_to_gdl(ctx, tmp_udi, udi, &error); + +out: + HAL_DEBUG(("result: %s (%s): %s, %s, %s, %s, %s", hostaddr, udi, + NP(manufacturer), NP(model), NP(description), NP(serial), + NP(uri))); + + if (tmp_udi != NULL) + free(tmp_udi); + if (manufacturer != NULL) + free(manufacturer); + if (model != NULL) + free(model); + if (description != NULL) + free(description); + if (uri != NULL) + free(uri); + if (sn != NULL) + free(sn); + + if (dbus_error_is_set(&error)) { + HAL_WARNING(("%s: %s", error.name, error.message)); + dbus_error_free(&error); + } + + HAL_DEBUG(("add: %s (%s)", hostaddr, udi)); + + return (rc); +} + +static int +number_of_interfaces(int s) +{ + int rc = -1; + struct lifnum n; + + memset(&n, 0 , sizeof (n)); + n.lifn_family = AF_UNSPEC; + if (ioctl(s, SIOCGLIFNUM, (char *)&n) == 0) + rc = n.lifn_count; + + return (rc); +} + +static char * +broadcast_address(int s, char *ifname) +{ + char *result = NULL; + struct lifreq r; + + memset(&r, 0, sizeof (r)); + strncpy((char *)&r.lifr_name, ifname, sizeof (r.lifr_name)); + if (ioctl(s, SIOCGLIFBRDADDR, (char *)&r) == 0) { + char buf[INET6_ADDRSTRLEN]; + + switch (r.lifr_broadaddr.ss_family) { + case AF_INET: { + struct sockaddr_in *s = + (struct sockaddr_in *)&r.lifr_broadaddr; + result = (char *)inet_ntop(AF_INET, &s->sin_addr, + buf, sizeof (buf)); + } + break; + case AF_INET6: { + struct sockaddr_in6 *s = + (struct sockaddr_in6 *)&r.lifr_broadaddr; + result = (char *)inet_ntop(AF_INET6, &s->sin6_addr, + buf, sizeof (buf)); + } + break; + } + + if (result != NULL) + result = strdup(result); + } + + return (result); +} + +GList * +broadcast_addresses() +{ + GList *result = NULL; + int s; + struct lifconf c; + int count; + + if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) + return (NULL); + + count = number_of_interfaces(s); + + memset(&c, 0, sizeof (c)); + c.lifc_family = AF_UNSPEC; + c.lifc_flags = IFF_BROADCAST; + c.lifc_buf = calloc(count, sizeof (struct lifreq)); + c.lifc_len = (count * sizeof (struct lifreq)); + + if (ioctl(s, SIOCGLIFCONF, (char *)&c) == 0) { + struct lifreq *r = c.lifc_req; + + for (count = c.lifc_len / sizeof (struct lifreq); + count > 0; count--, r++) { + char *address = broadcast_address(s, r->lifr_name); + + if (address != NULL) /* add it to the list */ + result = g_list_append(result, address); + } + } + free(c.lifc_buf); + close(s); + + return (result); +} diff --git a/usr/src/cmd/hal/addons/network-devices/network-discovery.h b/usr/src/cmd/hal/addons/network-devices/network-discovery.h new file mode 100644 index 0000000000..9619a5d9be --- /dev/null +++ b/usr/src/cmd/hal/addons/network-devices/network-discovery.h @@ -0,0 +1,28 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef NETWORK_DEVICE_COMMON_H +#define NETWORK_DEVICE_COMMON_H + +#include <libhal.h> + +extern void network_device_name_to_udi(char *udi, size_t size, ...); +extern int add_network_printer(LibHalContext *ctx, char *parent, char *hostaddr, + char *device, char *community); + +extern gboolean scan_for_devices_using_snmp(LibHalContext *ctx, char *parent, + char *community, char *network); +extern void scan_for_stale_devices(LibHalContext *ctx, time_t timestamp); +extern gboolean device_seen(char *name); + +extern int is_listening(char *hostname, int port); + +extern GList *broadcast_addresses(); + +#endif /* NETWORK_DEVICE_COMMON_H */ diff --git a/usr/src/cmd/hal/addons/network-devices/network-discovery.xml b/usr/src/cmd/hal/addons/network-devices/network-discovery.xml new file mode 100644 index 0000000000..24307664ef --- /dev/null +++ b/usr/src/cmd/hal/addons/network-devices/network-discovery.xml @@ -0,0 +1,111 @@ +<?xml version="1.0"?> +<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1"> +<!-- + Copyright 2007 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + Licensed under the Academic Free License version 2.1 + + ident "%Z%%M% %I% %E% SMI" + + NOTE: This service manifest is not editable; its contents will + be overwritten by package or patch operations, including + operating system upgrade. Make customizations in a different + file. + + Service manifest for HAL network attached device discovery. +--> + +<service_bundle type='manifest' name='SUNWhalr:device-discovery'> + +<service + name='network/device-discovery/printers' + type='service' + version='1'> + + <dependency name='usr' + type='service' + grouping='require_all' + restart_on='none'> + <service_fmri value='svc:/system/filesystem/local' /> + </dependency> + + <dependency name='network-service' + grouping='require_all' + restart_on='none' + type='service'> + <service_fmri value='svc:/network/service' /> + </dependency> + + <dependency name='dbus' + type='service' + grouping='require_all' + restart_on='none'> + <service_fmri value='svc:/system/dbus' /> + </dependency> + + <dependency name='hal' + type='service' + grouping='require_all' + restart_on='refresh'> + <service_fmri value='svc:/system/hal' /> + </dependency> + + <exec_method + type='method' + name='start' + exec='/lib/svc/method/svc-network-discovery %m %i' + timeout_seconds='30'> + </exec_method> + + <exec_method + type='method' + name='stop' + exec='/lib/svc/method/svc-network-discovery %m %i' + timeout_seconds='30'> + </exec_method> + + <exec_method + type='method' + name='refresh' + exec='/lib/svc/method/svc-network-discovery %m %i' + timeout_seconds='30'> + </exec_method> + + <property_group name='startd' type='framework'> + <propval name='duration' type='astring' value='transient' /> + </property_group> + + <instance + name='snmp' + enabled='false'> + + <method_context> + <method_credential user='root' group='root' /> + </method_context> + + <property_group name='general' type='framework'> + <!-- to start/stop the discovery service --> + <propval name='action_authorization' type='astring' + value='solaris.smf.manage.discovery.printers.snmp' /> + </property_group> + + <property_group name='config' type='framework'> + <!-- authorization to modify config properties --> + <propval name='value_authorization' type='astring' + value='solaris.smf.value.discovery.printers.snmp' /> + </property_group> + </instance> + + <stability value='Unstable' /> + + <template> + <common_name> + <loctext xml:lang='C'> + Hardware Abstraction Layer network attached device discovery + </loctext> + </common_name> + </template> +</service> + +</service_bundle> diff --git a/usr/src/cmd/hal/addons/network-devices/snmp.c b/usr/src/cmd/hal/addons/network-devices/snmp.c new file mode 100644 index 0000000000..2213ba5049 --- /dev/null +++ b/usr/src/cmd/hal/addons/network-devices/snmp.c @@ -0,0 +1,133 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include <glib.h> + +#include <libhal.h> +#include <logger.h> + +#undef PACKAGE_STRING +#undef PACKAGE_VERSION + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> + +#include "network-discovery.h" +#include "printer.h" + +#define NP(x) (x?x:"NULL") + +static GList *new_addrs = NULL; + +static void +add_snmp_device(LibHalContext *ctx, char *parent, char *name, char *community) +{ + /* most printers listen on the appsocket port (9100) */ + if (is_listening(name, 9100) == 0) { + char device[128]; + + snprintf(device, sizeof (device), "socket://%s:9100", name); + + add_network_printer(ctx, parent, name, device, community); + } + + /* + * This would be a good place to detect other types of devices or other + * device capabilities. scanners, removable media, storage, ... + */ +} + +static int +snmp_response_cb(int operation, struct snmp_session *sp, int reqid, + struct snmp_pdu *pdu, void *data) +{ + struct sockaddr_in *addr = pdu->transport_data; + char *name; + + name = inet_ntoa(addr->sin_addr); + + /* have we already seen this network device */ + if (device_seen(name) == FALSE) + new_addrs = g_list_append(new_addrs, strdup(name)); + + return (0); +} + +gboolean +scan_for_devices_using_snmp(LibHalContext *ctx, char *parent, char *community, + char *network) +{ + struct snmp_session session, *ss; + struct snmp_pdu *request = NULL, *response = NULL; + oid Oid[MAX_OID_LEN]; + unsigned int oid_len = MAX_OID_LEN; + GList *elem; + + HAL_DEBUG(("scan_for_devices_using_snmp(0x%8.8x, %s, %s, %s)", + ctx, NP(parent), NP(community), NP(network))); + + init_snmp("snmp-scan"); + init_mib(); + + /* initialize the SNMP session */ + snmp_sess_init(&session); + session.peername = network; + session.community = (uchar_t *)community; + session.community_len = strlen((const char *)session.community); + session.version = SNMP_VERSION_1; + + if ((ss = snmp_open(&session)) == NULL) + return (FALSE); + + /* initialize the request PDU */ + request = snmp_pdu_create(SNMP_MSG_GET); + + /* add the requested data (everyone should have a sysDescr.0) */ + if (!read_objid("SNMPv2-MIB::sysDescr.0", Oid, &oid_len)) + snmp_perror("sysDescr.0"); + snmp_add_null_var(request, Oid, oid_len); + + snmp_async_send(ss, request, snmp_response_cb, NULL); + + /* detect any new devices */ + while (1) { + int fds = 0, block = 0; + fd_set fdset; + struct timeval timeout; + + FD_ZERO(&fdset); + snmp_select_info(&fds, &fdset, &timeout, &block); + fds = select(fds, &fdset, NULL, NULL, block ? NULL : &timeout); + if (fds < 0) { + perror("select failed"); + continue; + } if (fds == 0) { + break; + } else { + snmp_read(&fdset); + } + } + + snmp_close(ss); + + /* add the newly detected devices */ + for (elem = new_addrs; elem != NULL; elem = g_list_next(elem)) { + add_snmp_device(ctx, parent, (char *)elem->data, community); + free(elem->data); + } + g_list_free(new_addrs); + new_addrs = NULL; + + return (TRUE); +} diff --git a/usr/src/cmd/hal/addons/network-devices/svc-network-discovery b/usr/src/cmd/hal/addons/network-devices/svc-network-discovery new file mode 100644 index 0000000000..eec0d13486 --- /dev/null +++ b/usr/src/cmd/hal/addons/network-devices/svc-network-discovery @@ -0,0 +1,117 @@ +#!/bin/sh +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. + +# +# ident "%Z%%M% %I% %E% SMI" + +. /lib/svc/share/smf_include.sh + +METHOD=${1} +INSTANCE=${2} + +DBUS_DESTINATION="org.freedesktop.Hal" +MESSAGE_PREFIX="org.freedesktop.Hal.Device.NetworkDiscovery" +OBJECT_PATH="/org/freedesktop/Hal/devices/network_attached" +SMF_PROPERTY_GROUP="config" +HAL_PROPERTY_GROUP="network_discovery" +SVCS=/usr/bin/svcs + +usage() { + echo "Usage: $0 { start | stop | refresh } { snmp }" + exit $SMF_EXIT_ERR_FATAL +} + +execute() { + echo "$*" + $* + + return $? +} + +start_snmp() { + interval=`/bin/svcprop -p config/interval ${SMF_FMRI} 2>/dev/null` + community=`/bin/svcprop -p config/community ${SMF_FMRI} 2>/dev/null` + network=`/bin/svcprop -p config/network ${SMF_FMRI} 2>/dev/null` + MESSAGE="${MESSAGE_PREFIX}.EnablePrinterScanningViaSNMP" + MESSAGE="${MESSAGE} int32:${interval:-60}" + MESSAGE="${MESSAGE} string:${community:-public}" + MESSAGE="${MESSAGE} string:${network:-0.0.0.0}" + + execute /usr/bin/dbus-send --system --print-reply \ + --dest=${DBUS_DESTINATION} --type=method_call ${OBJECT_PATH} \ + ${MESSAGE} + return $? +} + +stop_snmp() { + MESSAGE="${MESSAGE_PREFIX}.DisablePrinterScanningViaSNMP" + + execute /usr/bin/dbus-send --system --print-reply \ + --dest=${DBUS_DESTINATION} --type=method_call ${OBJECT_PATH} \ + ${MESSAGE} + return $? +} + +refresh_snmp() { + community=`/bin/svcprop -p config/community ${SMF_FMRI} 2>/dev/null` + network=`/bin/svcprop -p config/network ${SMF_FMRI} 2>/dev/null` + MESSAGE="${MESSAGE_PREFIX}.EnablePrinterScanningViaSNMP" + MESSAGE="${MESSAGE} string:${community:-public}" + MESSAGE="${MESSAGE} string:${network:-0.0.0.0}" + + execute /usr/bin/dbus-send --system --print-reply \ + --dest=${DBUS_DESTINATION} --type=method_call ${OBJECT_PATH} \ + ${MESSAGE} + return $? +} + +case "${METHOD}" in + 'start') + ;; + 'stop') + count=`$SVCS -o STATE hal 2>>/dev/null | grep -c "^online"` + if [ $count -eq 0 ] ; then + exit 0 # if HAL isn't running, there is nothing to do + fi + ;; + 'refresh') + ;; + *) + usage + ;; +esac + +case "${INSTANCE}" in + 'snmp') + ;; + *) + usage + ;; +esac + +${METHOD}_${INSTANCE} +exit_code=$? + +exit $exit_code diff --git a/usr/src/cmd/hal/fdi/Makefile b/usr/src/cmd/hal/fdi/Makefile index ba5565fe94..6724d578bf 100644 --- a/usr/src/cmd/hal/fdi/Makefile +++ b/usr/src/cmd/hal/fdi/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -44,13 +44,15 @@ FDIS = information/10freedesktop/10-camera-ptp.fdi \ information/10freedesktop/10-wireless-mice.fdi \ policy/10osvendor/10-keyboard-policy.fdi \ policy/10osvendor/10-laptop-panel-mgmt-policy.fdi \ + policy/10osvendor/10-network-attached.fdi \ policy/10osvendor/10-power-mgmt-policy.fdi \ policy/10osvendor/10-toshiba-buttons.fdi \ policy/10osvendor/20-storage-methods.fdi \ policy/10osvendor/20-zfs-methods.fdi \ preprobe/10osvendor/10-ide-drives.fdi \ preprobe/10osvendor/20-ignore-fixed-storage.fdi \ - preprobe/10osvendor/20-ignore-lofi.fdi + preprobe/10osvendor/20-ignore-lofi.fdi \ + preprobe/10osvendor/20-printers.fdi FDIDIR = $(ROOT_HAL_FDI) ROOTFDIS = $(FDIS:%=$(FDIDIR)/%) diff --git a/usr/src/cmd/hal/fdi/policy/10osvendor/10-network-attached.fdi b/usr/src/cmd/hal/fdi/policy/10osvendor/10-network-attached.fdi new file mode 100644 index 0000000000..85a5d37bb2 --- /dev/null +++ b/usr/src/cmd/hal/fdi/policy/10osvendor/10-network-attached.fdi @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright 2007 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + Licensed under the Academic Free License version 2.1 + + ident "%Z%%M% %I% %E% SMI" +--> + +<deviceinfo version="0.2"> + + <!-- + Create a place holder in the HAL device tree for the network attached + device discovery service to attach. + --> + <device> + <match key="system.kernel.name" string="SunOS"> + <spawn udi="/org/freedesktop/Hal/devices/network_attached"/> + </match> + </device> + + <!-- + Attach an instance of the network attached device discovery service to + the new HAL device tree node. + --> + <device> + <match key="info.udi" string="/org/freedesktop/Hal/devices/network_attached"> + + <append key="info.product" type="strlist">Network Attached Devices</append> + <append key="info.capabilities" type="strlist">network_device_discovery</append> + <append key="info.addons" type="strlist">hald-addon-network-discovery</append> + <!-- + The addon implements the 'org.freedesktop.Hal.Device.NetworkDiscovery' + interface. This interface controls the operation of the addon module. + --> + + </match> + </device> + +</deviceinfo> diff --git a/usr/src/cmd/hal/fdi/preprobe/10osvendor/20-printers.fdi b/usr/src/cmd/hal/fdi/preprobe/10osvendor/20-printers.fdi new file mode 100644 index 0000000000..7159c954cf --- /dev/null +++ b/usr/src/cmd/hal/fdi/preprobe/10osvendor/20-printers.fdi @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- + Copyright 2007 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + Licensed under the Academic Free License version 2.1 + + ident "%Z%%M% %I% %E% SMI" +--> + +<deviceinfo version="0.2"> + + <!-- probe network attached printers for information --> + <device> + <match key="network_device.address" exists="true"> + <match key="info.capabilities" contains="printer"> + <append key="info.callouts.add" type="strlist">hald-probe-network-printer</append> + </match> + </match> + </device> + + <!-- probe USB printers for information --> + <device> + <match key="info.solaris.driver" equals="usbprn"> + <append key="info.callouts.add" type="strlist">hald-probe-printer</append> + </match> + </device> + + <!-- probe ECPP parallel ports for printer information --> + <device> + <match key="info.solaris.driver" contains="ecpp"> + <append key="info.callouts.add" type="strlist">hald-probe-printer</append> + </match> + </device> + +</deviceinfo> + diff --git a/usr/src/cmd/hal/probing/Makefile b/usr/src/cmd/hal/probing/Makefile index 8108cc147f..00244dcbe4 100644 --- a/usr/src/cmd/hal/probing/Makefile +++ b/usr/src/cmd/hal/probing/Makefile @@ -25,7 +25,7 @@ # ident "%Z%%M% %I% %E% SMI" # -SUBDIRS = storage volume printer battery +SUBDIRS = storage volume printer network-printer battery all := TARGET= all install := TARGET= install diff --git a/usr/src/cmd/hal/probing/network-printer/Makefile b/usr/src/cmd/hal/probing/network-printer/Makefile new file mode 100644 index 0000000000..bdf1450a56 --- /dev/null +++ b/usr/src/cmd/hal/probing/network-printer/Makefile @@ -0,0 +1,68 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +PROG = hald-probe-network-printer +OBJS = probe-network-printer.o logger.o probe-snmp.o printer.o +SRCS = probe-network-printer.c + +include ../../../Makefile.cmd +include ../../Makefile.hal + +ROOTCMDDIR = $(ROOTLIB_HAL) + +LDLIBS += -lc -ldbus-1 -lhal +LDLIBS += -L$(SFWLIBDIR) -R$(SFWLIBDIR) $(ZIGNORE) -lnetsnmp + +CPPFLAGS += $(HAL_DBUS_CPPFLAGS) $(HAL_CONFIG_CPPFLAGS) +CPPFLAGS += -I$(ROOT)/usr/include/hal -I../../utils -I../../hald +CPPFLAGS += -I$(SFWINCDIR) +C99MODE = $(C99_ENABLE) + +.KEEP_STATE: + +all: $(PROG) + +logger.o: ../../hald/logger.c + $(COMPILE.c) -o $@ ../../hald/logger.c + $(POST_PROCESS_O) + +printer.o: ../../utils/printer.c + $(COMPILE.c) -o $@ ../../utils/printer.c + $(POST_PROCESS_O) + +$(PROG): $(OBJS) + $(LINK.c) -o $@ $(OBJS) $(LDLIBS) + $(POST_PROCESS) + +install: all $(ROOTCMD) + +clean: + $(RM) $(OBJS) + +FRC: + +include ../../../Makefile.targ diff --git a/usr/src/cmd/hal/probing/network-printer/probe-network-printer.c b/usr/src/cmd/hal/probing/network-printer/probe-network-printer.c new file mode 100644 index 0000000000..fc7296bc9b --- /dev/null +++ b/usr/src/cmd/hal/probing/network-printer/probe-network-printer.c @@ -0,0 +1,118 @@ +/*************************************************************************** + * + * probe-network-printer.c : Probe for snmp printer device information + * + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + * + **************************************************************************/ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <errno.h> +#include <string.h> +#include <strings.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <sys/prnio.h> +#include <fcntl.h> +#include <unistd.h> +#include <ctype.h> + +#include <libhal.h> +#include <logger.h> + +#include "printer.h" + +int +main(int argc, char *argv[]) +{ + int ret = 1; + char *udi; + char *printer_address, + *community; + DBusError error; + LibHalContext *ctx = NULL; + LibHalChangeSet *cs = NULL; + char *manufacturer = NULL, + *model = NULL, + *serial_number = NULL, + *description = NULL, + **command_set = NULL, + *device_uri = NULL; + extern int snmp_printer_info(char *hostname, char *community, + char **manufacturer, char **model, char **description, + char **serial_number, char ***command_set, + char **device_uri); + + dbus_error_init(&error); + + if ((udi = getenv("UDI")) == NULL) + goto out; + + printer_address = getenv("HAL_PROP_NETWORK_DEVICE_ADDRESS"); + if (printer_address == NULL) + goto out; + + community = getenv("HAL_PROP_NETWORK_DEVICE_SNMP_COMMUNITY"); + if (community == NULL) + community = "public"; + + setup_logger(); + + dbus_error_init(&error); + + if ((ctx = libhal_ctx_init_direct(&error)) == NULL) + goto out; + + if ((cs = libhal_device_new_changeset(udi)) == NULL) { + HAL_DEBUG(("Cannot allocate changeset")); + goto out; + } + + /* Probe the printer for characteristics via SNMP */ + ret = snmp_printer_info(printer_address, community, &manufacturer, + &model, &description, &serial_number, &command_set, + &device_uri); + if (ret < 0) { + HAL_DEBUG(("Cannot get snmp data for %s: %s", + printer_address, strerror(errno))); + goto out; + } + + /* Add printer characteristics to the HAL device tree */ + ret = add_printer_info(cs, udi, manufacturer, model, description, + serial_number, command_set, device_uri); + if (ret < 0) { + HAL_DEBUG(("Cannot add printer data for %s to %s: %s", + printer_address, udi, strerror(errno))); + goto out; + } + + libhal_device_commit_changeset(ctx, cs, &error); + + ret = 0; + +out: + if (cs != NULL) { + libhal_device_free_changeset(cs); + } + + if (ctx != NULL) { + if (dbus_error_is_set(&error)) { + dbus_error_free(&error); + } + libhal_ctx_shutdown(ctx, &error); + libhal_ctx_free(ctx); + } + + return (ret); +} diff --git a/usr/src/cmd/hal/probing/network-printer/probe-snmp.c b/usr/src/cmd/hal/probing/network-printer/probe-snmp.c new file mode 100644 index 0000000000..7645ff9977 --- /dev/null +++ b/usr/src/cmd/hal/probing/network-printer/probe-snmp.c @@ -0,0 +1,507 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <strings.h> + +#undef PACKAGE_STRING +#undef PACKAGE_VERSION + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-includes.h> + +#include "logger.h" +#include "printer.h" + +static int +hrDeviceDesc_to_info(char *string, char **manufacturer, char **model, + char **description) +{ + int rc = -1; + char *s; + + if (string == NULL) + return (-1); + + /* if it has : and ; in it, it's probably a 1284 device id */ + if ((strchr(string, ':') != NULL) && (strchr(string, ';') != NULL)) { + rc = ieee1284_devid_to_printer_info(string, manufacturer, model, + description, NULL, NULL, NULL); + } else { + rc = 0; + *description = strdup(string); + *manufacturer = strdup(string); + if ((s = strchr(*manufacturer, ' ')) != NULL) { + *s++ = NULL; + *model = strdup(s); + } + } + + return (rc); +} + +static struct snmp_pdu * +snmp_get_item(char *host, char *community, char *mib_item) +{ + int status; + struct snmp_session session, *ss; + struct snmp_pdu *request = NULL, *result = NULL; + oid Oid[MAX_OID_LEN]; + unsigned int oid_len = MAX_OID_LEN; + + /* initialize the SNMP session */ + snmp_sess_init(&session); + session.peername = host; + session.community = (uchar_t *)community; + session.community_len = strlen((const char *)session.community); + session.version = SNMP_VERSION_1; + session.retries = 0; + + if ((ss = snmp_open(&session)) == NULL) + return (NULL); + + /* add the requested data */ + if (!read_objid(mib_item, Oid, &oid_len)) + snmp_perror(mib_item); + + /* initialize the request PDU */ + request = snmp_pdu_create(SNMP_MSG_GET); + snmp_add_null_var(request, Oid, oid_len); + + status = snmp_synch_response(ss, request, &result); + + snmp_close(ss); + + return (result); +} + +static char * +snmp_get_string(char *host, char *community, char *mib_item) +{ + char *result = NULL; + struct snmp_pdu *response = NULL; + + response = snmp_get_item(host, community, mib_item); + + if ((response != NULL) && (response->errstat == SNMP_ERR_NOERROR)) { + struct variable_list *v = response->variables; + + if (v->type == ASN_OCTET_STR) { + result = calloc(1, v->val_len + 1); + memcpy(result, v->val.string, v->val_len); + } + } + + HAL_DEBUG(("snmp_get_string(%s, %s, %s): %s", host, community, mib_item, + (result?result:"NULL"))); + + if (response != NULL) + snmp_free_pdu(response); + + return (result); +} + +static int +snmp_brother_printer_info(char *hostname, char *community, char **manufacturer, + char **model, char **description, char **serial_no, + char ***command_set) +{ + int rc = -1; + char *tmp = NULL; + + /* + * Brother printers appear to store + * 1284 DevID SNMPv2-SMI::enterprises.2435.2.3.9.1.1.7.0 + * Serial Number SNMPv2-SMI::enterprises.2435.2.3.9.4.2.1.5.5.1.0 + */ + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2435.2.3.9.1.1.7.0"); + if (tmp != NULL) { + rc = ieee1284_devid_to_printer_info(tmp, manufacturer, model, + description, NULL, serial_no, command_set); + free(tmp); + + if (*serial_no == NULL) + *serial_no = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2435.2.3.9.4.2.1.5.5.1.0"); + } + + return (rc); +} + +static int +snmp_ricoh_printer_info(char *hostname, char *community, char **manufacturer, + char **model, char **description, char **serial_no, + char ***command_set) +{ + int rc = -1; + char *tmp = NULL; + + /* + * OKI printers appear to store + * 1284 DevID SNMPv2-SMI::enterprises.367.3.2.1.1.1.11.0 + * Serial Number SNMPv2-SMI::enterprises.367.3.2.1.2.1.4.0 + */ + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.367.3.2.1.1.1.11.0"); + if (tmp != NULL) { + rc = ieee1284_devid_to_printer_info(tmp, manufacturer, model, + description, NULL, serial_no, command_set); + free(tmp); + + if (*serial_no == NULL) + *serial_no = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.367.3.2.1.2.1.4.0"); + } + + return (rc); +} + +static int +snmp_lexmark_printer_info(char *hostname, char *community, char **manufacturer, + char **model, char **description, char **serial_no, + char ***command_set) +{ + int rc = -1; + char *tmp = NULL; + + /* + * Lexmark printers appear to store + * 1284 DevID SNMPv2-SMI::enterprises.641.2.1.2.1.3.1 + * Serial Number SNMPv2-SMI::enterprises.641.2.1.2.1.6.1 + */ + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.641.2.1.2.1.3.1"); + if (tmp != NULL) { + rc = ieee1284_devid_to_printer_info(tmp, manufacturer, model, + description, NULL, serial_no, command_set); + free(tmp); + + if (*serial_no == NULL) + *serial_no = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.641.2.1.2.1.6.1"); + } + + return (rc); +} + +static int +snmp_xerox_phaser_printer_info(char *hostname, char *community, + char **manufacturer, char **model, char **description, + char **serial_no, char ***command_set, char **uri) +{ + int rc = -1; + char *tmp = NULL; + + /* + * Xerox Phaser XXXX printers store their + * 1284 DevID SNMPv2-SMI::enterprises.253.8.51.1.2.1.20.1 + * Manufacturer: + * SNMPv2-SMI::enterprises.128.2.1.3.1.1.0 + * SNMPv2-SMI::enterprises.23.2.32.3.2.1.10.1.16 + * SNMPv2-SMI::enterprises.23.2.32.4.1.0 + * Model: + * SNMPv2-SMI::enterprises.128.2.1.3.1.2.0 + * SNMPv2-SMI::enterprises.23.2.32.3.2.1.10.1.17 + * SNMPv2-SMI::enterprises.23.2.32.4.2.0 + * Description SNMPv2-SMI::enterprises.253.8.53.3.2.1.2.1 + * Serial Number SNMPv2-SMI::enterprises.253.8.53.3.2.1.3.1 + * Uri SNMPv2-SMI::enterprises.128.2.1.3.6.23.1.5.1 + */ + + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.253.8.51.1.2.1.20.1"); + if (tmp != NULL) { + rc = ieee1284_devid_to_printer_info(tmp, manufacturer, model, + description, NULL, serial_no, command_set); + free(tmp); + } + + if (*manufacturer == NULL) + *manufacturer = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.128.2.1.3.1.1.0"); + if (*manufacturer == NULL) + *manufacturer = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.23.2.32.3.2.1.10.1.16"); + if (*manufacturer == NULL) + *manufacturer = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.23.2.32.4.1.0"); + + if (*model == NULL) + *model = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.128.2.1.3.1.2.0"); + if (*model == NULL) + *model = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.23.2.32.3.2.1.10.1.17"); + if (*model == NULL) + *model = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.23.2.32.4.2.0"); + + if (*serial_no == NULL) + *serial_no = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.253.8.53.3.2.1.3.1"); + + if ((*manufacturer != NULL) && (*model != NULL)) + rc = 0; + + return (rc); +} + +static int +snmp_qms_printer_info(char *hostname, char *community, char **manufacturer, + char **model, char **description, char **serial_no, + char ***command_set, char **uri) +{ + int rc = -1; + char *tmp = NULL; + + /* + * MINOLTA-QMS printers appear to store + * Prouct Name SNMPv2-SMI::enterprises.2590.1.1.2.1.5.7.14.2.1.1.16.1 + * Serial Number SNMPv2-SMI::enterprises.2590.1.1.1.5.5.1.1.3.2 + * URI SNMPv2-SMI::enterprises.2590.1.1.2.1.5.7.14.2.2.1.3.1.1 + * SNMPv2-SMI::enterprises.2590.1.1.2.1.5.7.14.2.2.1.3.1.2 + */ + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2590.1.1.2.1.5.7.14.2.1.1.16.1"); + if (tmp != NULL) { + rc = hrDeviceDesc_to_info(tmp, manufacturer, model, + description); + free(tmp); + + if (*serial_no == NULL) + *serial_no = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2590.1.1.1.5.5.1.1.3.2"); + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2590.1.1.2.1.5.7.14.2.2.1.3.1.2"); + if (tmp == NULL) + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2590.1.1.2.1.5.7.14.2.2.1.3.1.1"); + if (tmp != NULL) + *uri = tmp; + } + + return (rc); +} + +static int +snmp_oki_printer_info(char *hostname, char *community, char **manufacturer, + char **model, char **description, char **serial_no, + char ***command_set) +{ + int rc = -1; + char *tmp = NULL; + + /* + * OKI printers appear to store + * Prouct Name SNMPv2-SMI::enterprises.2001.1.2.683.1.3 + * Serial Number SNMPv2-SMI::enterprises.2001.1.2.683.1.5 + */ + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2001.1.2.683.1.3"); + if (tmp != NULL) { + rc = ieee1284_devid_to_printer_info(tmp, manufacturer, model, + description, NULL, serial_no, command_set); + free(tmp); + + if (*serial_no == NULL) + *serial_no = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2001.1.2.683.1.5"); + } + + return (rc); +} + +static int +snmp_hp_printer_info(char *hostname, char *community, char **manufacturer, + char **model, char **description, char **serial_no, + char ***command_set) +{ + int rc = -1; + char *tmp = NULL; + + /* + * HP printers appear to store + * 1284 DevID SNMPv2-SMI::enterprises.11.2.3.9.1.1.7.0 + * Serial Number SNMPv2-SMI::enterprises.2.3.9.4.2.2.5.1.1.17 + */ + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.11.2.3.9.1.1.7.0"); + if (tmp != NULL) { + rc = ieee1284_devid_to_printer_info(tmp, manufacturer, model, + description, NULL, serial_no, command_set); + free(tmp); + + if (*serial_no == NULL) + *serial_no = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2.3.9.4.2.2.5.1.1.17"); + } + + return (rc); +} + +static int +snmp_ppm_printer_info(char *hostname, char *community, char **manufacturer, + char **model, char **description, char **serial_no, + char ***command_set) +{ + int rc = -1; + char *tmp = NULL; + + /* + * The PWG portMon MIB stores + * 1284 DevID SNMPv2-SMI::enterprises.2699.1.2.1.1.1.3` + */ + tmp = snmp_get_string(hostname, community, + "SNMPv2-SMI::enterprises.2699.1.2.1.1.1.3"); + if (tmp != NULL) { + rc = ieee1284_devid_to_printer_info(tmp, manufacturer, model, + description, NULL, serial_no, command_set); + free(tmp); + } + + return (rc); +} + +static int +snmp_prt_printer_info(char *hostname, char *community, char **manufacturer, + char **model, char **description, char **serial_no, + char ***command_set) +{ + int rc = -1; + char *tmp = NULL; + + /* + * The Printer Printer MIB stores + * Vendor SNMPv2-SMI::mib-2.43.8.2.1.14.1.1 + * Model SNMPv2-SMI::mib-2.43.8.2.1.15.1.1 + * Serial SNMPv2-SMI::mib-2.43.8.2.1.17.1.1 + */ + + if (*manufacturer == NULL) + *manufacturer = snmp_get_string(hostname, community, + "SNMPv2-SMI::mib-2.43.8.2.1.14.1.1"); + if (*model == NULL) + *model = snmp_get_string(hostname, community, + "SNMPv2-SMI::mib-2.43.8.2.1.15.1.1"); + if (*serial_no == NULL) + *serial_no = snmp_get_string(hostname, community, + "SNMPv2-SMI::mib-2.43.8.2.1.17.1.1"); + + if (*manufacturer != NULL) + rc = 0; + + return (rc); +} + +static int +snmp_host_resource_printer_info(char *hostname, char *community, + char **manufacturer, char **model, char **description, + char **serial_no, char ***command_set) +{ + int rc = -1; + char *tmp = NULL; + + tmp = snmp_get_string(hostname, community, + "HOST-RESOURCES-MIB::hrDeviceDescr.1"); + if (tmp != NULL) { + rc = hrDeviceDesc_to_info(tmp, manufacturer, model, + description); + free(tmp); + } + + return (rc); +} + +int +snmp_printer_info(char *hostname, char *community, char **manufacturer, + char **model, char **description, char **serial_no, + char ***command_set, char **uri) +{ + char *tmp = NULL; + + init_snmp("network-printer-probe"); + init_mib(); + + if (snmp_brother_printer_info(hostname, community, manufacturer, model, + description, serial_no, command_set) == 0) { + return (0); + } else if (snmp_ricoh_printer_info(hostname, community, manufacturer, + model, description, serial_no, command_set) == 0) { + return (0); + } else if (snmp_lexmark_printer_info(hostname, community, manufacturer, + model, description, serial_no, command_set) == 0) { + return (0); + } else if (snmp_xerox_phaser_printer_info(hostname, community, + manufacturer, model, description, serial_no, + command_set, uri) == 0) { + return (0); + } else if (snmp_qms_printer_info(hostname, community, manufacturer, + model, description, serial_no, command_set, uri) == 0) { + return (0); + } else if (snmp_oki_printer_info(hostname, community, manufacturer, + model, description, serial_no, command_set) == 0) { + return (0); + } else if (snmp_hp_printer_info(hostname, community, manufacturer, + model, description, serial_no, command_set) == 0) { + return (0); + } else if (snmp_ppm_printer_info(hostname, community, manufacturer, + model, description, serial_no, command_set) == 0) { + return (0); + } else if (snmp_prt_printer_info(hostname, community, manufacturer, + model, description, serial_no, command_set) == 0) { + return (0); + } else if (snmp_host_resource_printer_info(hostname, community, + manufacturer, model, description, serial_no, + command_set) == 0) { + return (0); + } + + return (-1); +} + +#ifdef NOTDEF + +#define NP(x) (x?x:"") + +int +main(int ac, char *av[]) +{ + int i; + + for (i = 1; av[i] != NULL; i++) { + char *hostname = av[i], *manufacturer = NULL, *model = NULL, + *description = NULL, *serial_no = NULL, + **command_set = NULL, *uri = NULL; + int rc; + + rc = snmp_printer_info(hostname, &manufacturer, &model, + &description, &serial_no, &command_set, &uri); + printf("SNMP data for %s...(%d)\n", hostname, rc); + printf("\tvendor = %s\n", NP(manufacturer)); + printf("\tproduct = %s\n", NP(model)); + printf("\tdescription = %s\n", NP(description)); + printf("\tserial = %s\n", NP(serial_no)); + printf("\tdevice = %s\n", NP(uri)); + + if (command_set != NULL) { + int j; + + printf("\tcommand set = \n"); + for (j = 0; command_set[j] != NULL; j++) + printf("\t\t%s\n", command_set[j]); + } + } + + return (0); +} +#endif diff --git a/usr/src/cmd/hal/probing/printer/Makefile b/usr/src/cmd/hal/probing/printer/Makefile index f35624b09a..26903c5959 100644 --- a/usr/src/cmd/hal/probing/printer/Makefile +++ b/usr/src/cmd/hal/probing/printer/Makefile @@ -26,7 +26,7 @@ # PROG = hald-probe-printer -OBJS = probe-printer.o logger.o +OBJS = probe-printer.o logger.o printer.o SRCS = probe-printer.c include ../../../Makefile.cmd @@ -48,6 +48,10 @@ logger.o: ../../hald/logger.c $(COMPILE.c) -o $@ ../../hald/logger.c $(POST_PROCESS_O) +printer.o: ../../utils/printer.c + $(COMPILE.c) -o $@ ../../utils/printer.c + $(POST_PROCESS_O) + $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) diff --git a/usr/src/cmd/hal/probing/printer/probe-printer.c b/usr/src/cmd/hal/probing/printer/probe-printer.c index 484acb3f73..181008e10d 100644 --- a/usr/src/cmd/hal/probing/printer/probe-printer.c +++ b/usr/src/cmd/hal/probing/printer/probe-printer.c @@ -12,7 +12,7 @@ #pragma ident "%Z%%M% %I% %E% SMI" #ifdef HAVE_CONFIG_H -# include <config.h> +#include <config.h> #endif #include <errno.h> @@ -21,6 +21,9 @@ #include <ctype.h> #include <stdlib.h> #include <stdio.h> +#include <sys/param.h> +#include <sys/types.h> +#include <dirent.h> #include <sys/ioctl.h> #include <sys/prnio.h> #include <fcntl.h> @@ -30,155 +33,142 @@ #include <libhal.h> #include <logger.h> -#define NELEM(a) (sizeof (a) / sizeof (*(a))) - -static char * -strip_ws(char *s) -{ - if (s != NULL) { - char *p; - - /* skip the leading whitespace */ - for (; ((*s != NULL) && (isspace(*s) != 0)); s++) ; - - /* drop the trailing whitespace */ - for (p = s + strlen(s) - 1; ((p > s) && (isspace(*p) != 0)); - p--) ; - *(++p) = '\0'; - } - - return (s); -} +#include "printer.h" static int -get_prnio_data(int fd, LibHalChangeSet *cs) +prnio_printer_info(char *device_file, char **manufacturer, char **model, + char **description, char **serial_number, char ***command_set) { struct prn_1284_device_id id; char buf[BUFSIZ]; - char *s, *iter = NULL; + int fd = -1, rc = -1; memset(&id, 0, sizeof (id)); memset(&buf, 0, sizeof (buf)); id.id_data = buf; id.id_len = sizeof (buf); + if ((fd = open (device_file, O_RDONLY | O_NONBLOCK)) < 0) { + goto prnio_out; + } + if (ioctl(fd, PRNIOC_GET_1284_DEVID, &id) < 0) { - return (-1); + goto prnio_out; } - HAL_DEBUG (("IEEE-1284 DeviceId = %s", buf)); + HAL_DEBUG(("IEEE-1284 DeviceId = %s", buf)); - for (s = strtok_r(buf, ";\n", &iter); s != NULL; - s = strtok_r(NULL, ";\n", &iter)) { - char *t, *u, *iter2 = NULL; + rc = ieee1284_devid_to_printer_info(buf, manufacturer, model, + description, NULL, serial_number, command_set); - if ((t = strtok_r(s, ":\n", &iter2)) == NULL) { - continue; - } +prnio_out: + if (fd != -1) + close(fd); - if ((u = strtok_r(NULL, ":\n", &iter2)) == NULL) { - continue; - } + return (rc); +} - if ((strcasecmp(t, "MFG") == 0) || - (strcasecmp(t, "MANUFACTURER") == 0)) { - libhal_changeset_set_property_string (cs, - "printer.vendor", strip_ws(u)); - } else if ((strcasecmp(t, "MDL") == 0) || - (strcasecmp(t, "MODEL") == 0)) { - libhal_changeset_set_property_string (cs, - "printer.product", strip_ws(u)); - } else if ((strcasecmp(t, "SN") == 0) || - (strcasecmp(t, "SERN") == 0) || - (strcasecmp(t, "SERIALNUMBER") == 0)) { - libhal_changeset_set_property_string (cs, - "printer.serial", strip_ws(u)); - } else if ((strcasecmp(t, "DES") == 0) || - (strcasecmp(t, "DESCRIPTION") == 0)) { - libhal_changeset_set_property_string (cs, - "printer.description", strip_ws(u)); - } else if ((strcasecmp(t, "CMD") == 0) || - (strcasecmp(t, "COMMAND SET") == 0) || - (strcasecmp(t, "COMMANDSET") == 0)) { - char *v, *iter3 = NULL; - const char *cmds[32]; - int i = 0; - - memset(&cmds, 0, sizeof (cmds)); - for (v = strtok_r(u, ",\n", &iter3); - ((v != NULL) && (i < NELEM(cmds))); - v = strtok_r(NULL, ",\n", &iter3)) { - cmds[i++] = strip_ws(v); +/* + * It is assumed that all devices that support prnio(7i), also have a link + * in /dev/printers. + */ +static char * +prnio_device_name(void) +{ + char *result = NULL; + char *devfs_path; + DIR *dp; + + if (((devfs_path = getenv("HAL_PROP_SOLARIS_DEVFS_PATH")) != NULL) && + ((dp = opendir("/dev/printers")) != NULL)) { + struct dirent *ep; + + while ((ep = readdir(dp)) != NULL) { + char path[MAXPATHLEN], lpath[MAXPATHLEN]; + + snprintf(path, sizeof (path), "/dev/printers/%s", + ep->d_name); + memset(lpath, 0, sizeof (lpath)); + if ((readlink(path, lpath, sizeof (lpath)) > 0) && + (strstr(lpath, devfs_path) != NULL)) { + result = strdup(path); + break; } - - libhal_changeset_set_property_strlist(cs, - "printer.commandset", cmds); } + closedir(dp); } - return (0); + return (result); } -int -main (int argc, char *argv[]) +int +main(int argc, char *argv[]) { int ret = 1; - int fd = -1; char *udi; char *device_file; + char *manufacturer = NULL, + *model = NULL, + *serial_number = NULL, + *description = NULL, + **command_set = NULL; DBusError error; LibHalContext *ctx = NULL; LibHalChangeSet *cs = NULL; - if ((udi = getenv ("UDI")) == NULL) + if ((udi = getenv("UDI")) == NULL) goto out; - if ((device_file = getenv ("HAL_PROP_PRINTER_DEVICE")) == NULL) + if ((device_file = getenv("HAL_PROP_PRINTER_DEVICE")) == NULL) + device_file = prnio_device_name(); + + if (device_file == NULL) goto out; - setup_logger (); + setup_logger(); - dbus_error_init (&error); - if ((ctx = libhal_ctx_init_direct (&error)) == NULL) + dbus_error_init(&error); + if ((ctx = libhal_ctx_init_direct(&error)) == NULL) goto out; - if ((cs = libhal_device_new_changeset (udi)) == NULL) { - HAL_DEBUG (("Cannot allocate changeset")); + if ((cs = libhal_device_new_changeset(udi)) == NULL) { + HAL_DEBUG(("Cannot allocate changeset")); goto out; } - HAL_DEBUG (("Doing probe-printer for %s (udi=%s)", - device_file, udi)); - - if ((fd = open (device_file, O_RDONLY | O_NONBLOCK)) < 0) { - HAL_DEBUG (("Cannot open %s: %s", device_file, strerror (errno))); + /* Probe the printer for characteristics via prnio(7i) */ + ret = prnio_printer_info(device_file, &manufacturer, &model, + &description, &serial_number, &command_set); + if (ret < 0) { + HAL_DEBUG(("Cannot get prnio data for %s: %s", + device_file, strerror(errno))); goto out; } - if (get_prnio_data(fd, cs) < 0) { - HAL_DEBUG (("Cannot get prnio data %s: %s", device_file, strerror (errno))); + /* Add printer characteristics to the HAL device tree */ + ret = add_printer_info(cs, udi, manufacturer, model, description, + serial_number, command_set, device_file); + if (ret < 0) { + HAL_DEBUG(("Cannot add printer data for %s to %s: %s", + device_file, udi, strerror(errno))); goto out; } - libhal_device_commit_changeset (ctx, cs, &error); + libhal_device_commit_changeset(ctx, cs, &error); ret = 0; out: if (cs != NULL) { - libhal_device_free_changeset (cs); - } - - if (fd >= 0) { - close (fd); + libhal_device_free_changeset(cs); } if (ctx != NULL) { if (dbus_error_is_set(&error)) { - dbus_error_free (&error); + dbus_error_free(&error); } - libhal_ctx_shutdown (ctx, &error); - libhal_ctx_free (ctx); + libhal_ctx_shutdown(ctx, &error); + libhal_ctx_free(ctx); } - return ret; + return (ret); } diff --git a/usr/src/cmd/hal/utils/printer.c b/usr/src/cmd/hal/utils/printer.c new file mode 100644 index 0000000000..0299ea6bb1 --- /dev/null +++ b/usr/src/cmd/hal/utils/printer.c @@ -0,0 +1,148 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <strings.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <ctype.h> + +#include <libhal.h> +#include <logger.h> + +#include "printer.h" + +static char * +strip_ws(char *s) +{ + if (s != NULL) { + char *p; + + /* skip the leading whitespace */ + for (; ((*s != NULL) && (isspace(*s) != 0)); s++); + + /* drop the trailing whitespace */ + for (p = s + strlen(s) - 1; ((p > s) && (isspace(*p) != 0)); + p--); + *(++p) = '\0'; + } + + return (s); +} + +int +ieee1284_devid_to_printer_info(char *devid_string, char **manufacturer, + char **model, char **description, char **class, + char **serial_no, char ***command_set) +{ + char *iter = NULL; + char *s; + + if (devid_string == NULL) + return (-1); + + /* parse the 1284 device id string */ + for (s = (char *)strtok_r(devid_string, ";\n", &iter); s != NULL; + s = (char *)strtok_r(NULL, ";\n", &iter)) { + char *t, *u, *iter2 = NULL; + + if ((t = (char *)strtok_r(s, ":\n", &iter2)) == NULL) + continue; + + if ((u = (char *)strtok_r(NULL, ":\n", &iter2)) == NULL) + continue; + + if (((strcasecmp(t, "MFG") == 0) || + (strcasecmp(t, "MANUFACTURER") == 0)) && + (manufacturer != NULL)) + *manufacturer = strdup(strip_ws(u)); + else if (((strcasecmp(t, "MDL") == 0) || + (strcasecmp(t, "MODEL") == 0)) && + (model != NULL)) + *model = strdup(strip_ws(u)); + else if (((strcasecmp(t, "DES") == 0) || + (strcasecmp(t, "DESCRIPTION") == 0)) && + (description != NULL)) + *description = strdup(strip_ws(u)); + else if (((strcasecmp(t, "CLS") == 0) || + (strcasecmp(t, "CLASS") == 0)) && + (class != NULL)) + *class = strdup(strip_ws(u)); + else if (((strcasecmp(t, "SER") == 0) || + (strcasecmp(t, "SERNO") == 0)) && + (serial_no != NULL)) + *serial_no = strdup(strip_ws(u)); + else if (((strcasecmp(t, "CMD") == 0) || + (strcasecmp(t, "COMMAND SET") == 0)) && + (command_set != NULL)) { + /* this should be more dynamic, I got lazy */ + char *v, *iter3 = NULL; + char *cmds[32]; + int i = 0; + + memset(&cmds, 0, sizeof (cmds)); +#define NELEM(a) (sizeof (a) / sizeof (*(a))) + for (v = strtok_r(u, ",\n", &iter3); + ((v != NULL) && (i < NELEM(cmds))); + v = strtok_r(NULL, ",\n", &iter3)) { + cmds[i++] = strdup(strip_ws(v)); + } +#undef NELEM + *command_set = calloc(++i, sizeof (char *)); + for (i = 0; (cmds)[i] != NULL; i++) + (*command_set)[i] = cmds[i]; + } + } + + return (0); +} + + +int +add_printer_info(LibHalChangeSet *cs, char *udi, char *manufacturer, + char *model, char *description, char *serial_number, + char **command_set, char *device) +{ +#define NP(x) (x?x:"") + HAL_DEBUG(("udi: %s, snmp data: vendor=%s, product=%s, " + "description=%s, serial=%s, device=%s\n", + NP(udi), NP(manufacturer), NP(model), NP(description), + NP(serial_number), NP(device))); +#undef NP + + if (model != NULL) + libhal_changeset_set_property_string(cs, + "info.product", model); + if (manufacturer != NULL) + libhal_changeset_set_property_string(cs, + "printer.vendor", manufacturer); + if (model != NULL) + libhal_changeset_set_property_string(cs, + "printer.product", model); + if (serial_number != NULL) + libhal_changeset_set_property_string(cs, + "printer.serial", serial_number); + if (description != NULL) + libhal_changeset_set_property_string(cs, + "printer.description", description); + if (command_set != NULL) + libhal_changeset_set_property_strlist(cs, "printer.commandset", + (const char **)command_set); + if (device != NULL) + libhal_changeset_set_property_string(cs, + "printer.device", device); + + return (0); +} diff --git a/usr/src/cmd/hal/utils/printer.h b/usr/src/cmd/hal/utils/printer.h new file mode 100644 index 0000000000..4b5eca18c0 --- /dev/null +++ b/usr/src/cmd/hal/utils/printer.h @@ -0,0 +1,23 @@ +/* + * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifndef _PRINTER_H +#define _PRINTER_H + +#include <libhal.h> + +extern int ieee1284_devid_to_printer_info(char *devid_string, + char **manufacturer, char **model, char **description, + char **class, char **serial_no, char ***command_set); + +extern int add_printer_info(LibHalChangeSet *cs, char *udi, char *manufacturer, + char *model, char *serial_number, char *description, + char **command_set, char *device); + +#endif /* _PRINTER_H */ diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt index d862e0f547..afb8349e40 100644 --- a/usr/src/lib/libsecdb/auth_attr.txt +++ b/usr/src/lib/libsecdb/auth_attr.txt @@ -111,6 +111,7 @@ solaris.smf.manage.:::Manage All SMF Service States::help=SmfManageHeader.html solaris.smf.manage.autofs:::Manage Automount Service States::help=SmfAutofsStates.html solaris.smf.manage.bind:::Manage DNS Service States::help=BindStates.html solaris.smf.manage.cron:::Manage Cron Service States::help=SmfCronStates.html +solaris.smf.manage.discover.printers.snmp:::Manage Network Attached Device Discovery Service States::help=SmfNADDStates.html solaris.smf.manage.hal:::Manage HAL Service States::help=SmfHALStates.html solaris.smf.manage.idmap:::Manage Identity Mapping Service States::help=SmfIdmapStates.html solaris.smf.manage.inetd:::Manage inetd and inetd managed services States::help=SmfIntedStates.html @@ -130,6 +131,7 @@ solaris.smf.manage.tnctl:::Manage Refresh of Trusted Network Parameters::help=TN solaris.smf.manage.tnd:::Manage Trusted Network Daemon::help=TNDaemon.html solaris.smf.manage.wpa:::Manage WPA Service States::help=SmfWpaStates.html solaris.smf.value.:::Change Values of SMF Service Properties::help=SmfValueHeader.html +solaris.smf.value.discover.printers.snmp:::Manage Network Attached Device Discovery Service Properties::help=SmfValueNADD.html solaris.smf.value.idmap:::Change Values of SMF Identity Mapping Service Properties::help=SmfValueIdmap.html solaris.smf.value.inetd:::Change values of SMF Inetd configuration paramaters::help=SmfValueInted.html solaris.smf.value.ipsec:::Change Values of SMF IPsec Properties::help=SmfValueIPsec.html diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile index cf290e0900..1bdd12e0ce 100644 --- a/usr/src/lib/libsecdb/help/auths/Makefile +++ b/usr/src/lib/libsecdb/help/auths/Makefile @@ -78,6 +78,7 @@ HTMLENTS = \ SmfModifyHeader.html \ SmfModifyMethod.html \ SmfNscdStates.html \ + SmfNADDStates.html \ SmfNWAMStates.html \ SmfPowerStates.html \ SmfRoutingStates.html \ @@ -89,6 +90,7 @@ HTMLENTS = \ SmfValueIPsec.html \ SmfValueIscsitgt.html \ SmfValueMDNS.html \ + SmfValueNADD.html \ SmfValueNWAM.html \ SmfValueRouting.html \ SmfWpaStates.html \ diff --git a/usr/src/lib/libsecdb/help/auths/SmfNADDStates.html b/usr/src/lib/libsecdb/help/auths/SmfNADDStates.html new file mode 100644 index 0000000000..811d216635 --- /dev/null +++ b/usr/src/lib/libsecdb/help/auths/SmfNADDStates.html @@ -0,0 +1,40 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +Copyright 2007 Sun Microsystems, Inc. All rights reserved. +Use is subject to license terms. +--> +<!-- SCCS keyword +#ident "%Z%%M% %I% %E% SMI" +--> +<!-- + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> +--> +<BODY> +When Manage Network Device Discovery Service States is in the Authorizations +Include column, it grants the authorization to enable, disable, or restart +the Network Attached Device Discovery services. +<p> +If Manage Network DeviceDiscovery Service States is grayed, then you are not entitled +to Add or Remove this authorization. +<BR> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/auths/SmfValueNADD.html b/usr/src/lib/libsecdb/help/auths/SmfValueNADD.html new file mode 100644 index 0000000000..eb26f2671c --- /dev/null +++ b/usr/src/lib/libsecdb/help/auths/SmfValueNADD.html @@ -0,0 +1,40 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +Copyright 2007 Sun Microsystems, Inc. All rights reserved. +Use is subject to license terms. +--> +<!-- SCCS keyword +#ident "%Z%%M% %I% %E% SMI" +--> +<!-- + <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"> +--> +<BODY> +When Value Network Attached Device Discovery Properties is in the Authorizations +Include column, it grants the the authorization to change Network Attached +Device Discovery service property values. +<P> +If Value Network Attached Device Discovery Properties is grayed, then you are +not entitled to Add or Remove this authorization. +<BR> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt index cfc9890dcb..96107e01f4 100644 --- a/usr/src/lib/libsecdb/prof_attr.txt +++ b/usr/src/lib/libsecdb/prof_attr.txt @@ -36,7 +36,7 @@ Audit Control:::Configure BSM auditing:auths=solaris.audit.config,solaris.jobs.a Audit Review:::Review BSM auditing logs:auths=solaris.audit.read;help=RtAuditReview.html Contract Observer:::Reliably observe any/all contract events:help=RtContractObserver.html Device Management:::Control Access to Removable Media:auths=solaris.device.*;help=RtDeviceMngmnt.html -Printer Management:::Manage printers, daemons, spooling:auths=solaris.print.*,solaris.label.print;help=RtPrntAdmin.html +Printer Management:::Manage printers, daemons, spooling:auths=solaris.print.*,solaris.label.print,solaris.smf.manage.discovery.printers.*,solaris.smf.value.discovery.printers.*;help=RtPrntAdmin.html Cron Management:::Manage at and cron jobs:auths=solaris.jobs.*,solaris.smf.manage.cron;help=RtCronMngmnt.html Log Management:::Manage log files:help=RtLogMngmnt.html Basic Solaris User:::Automatically assigned rights:auths=solaris.profmgr.read,solaris.jobs.user,solaris.mail.mailq,solaris.device.mount.removable;profiles=All;help=RtDefault.html diff --git a/usr/src/pkgdefs/SUNW0on/prototype_com b/usr/src/pkgdefs/SUNW0on/prototype_com index eaea3bad10..87facb2c00 100644 --- a/usr/src/pkgdefs/SUNW0on/prototype_com +++ b/usr/src/pkgdefs/SUNW0on/prototype_com @@ -251,6 +251,7 @@ f none usr/lib/help/auths/locale/SmfModifyHeader.html 444 root bin f none usr/lib/help/auths/locale/SmfModifyMethod.html 444 root bin f none usr/lib/help/auths/locale/SmfIPsecStates.html 444 root bin f none usr/lib/help/auths/locale/SmfNscdStates.html 444 root bin +f none usr/lib/help/auths/locale/SmfNADDStates.html 444 root bin f none usr/lib/help/auths/locale/SmfNWAMStates.html 444 root bin f none usr/lib/help/auths/locale/SmfPowerStates.html 444 root bin f none usr/lib/help/auths/locale/SmfRoutingStates.html 444 root bin @@ -262,6 +263,7 @@ f none usr/lib/help/auths/locale/SmfValueInetd.html 444 root bin f none usr/lib/help/auths/locale/SmfValueIPsec.html 444 root bin f none usr/lib/help/auths/locale/SmfValueIscsitgt.html 444 root bin f none usr/lib/help/auths/locale/SmfValueMDNS.html 444 root bin +f none usr/lib/help/auths/locale/SmfValueNADD.html 444 root bin f none usr/lib/help/auths/locale/SmfValueNWAM.html 444 root bin f none usr/lib/help/auths/locale/SmfValueRouting.html 444 root bin f none usr/lib/help/auths/locale/SmfWpaStates.html 444 root bin diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com index 40ba8db3d7..4c0a9807a5 100644 --- a/usr/src/pkgdefs/SUNWcsu/prototype_com +++ b/usr/src/pkgdefs/SUNWcsu/prototype_com @@ -487,6 +487,7 @@ f none usr/lib/help/auths/locale/C/SmfModifyMethod.html 444 root bin f none usr/lib/help/auths/locale/C/SmfInetdStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfIPsecStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfNscdStates.html 444 root bin +f none usr/lib/help/auths/locale/C/SmfNADDStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfNWAMStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfPowerStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfRoutingStates.html 444 root bin @@ -498,6 +499,7 @@ f none usr/lib/help/auths/locale/C/SmfValueInetd.html 444 root bin f none usr/lib/help/auths/locale/C/SmfValueIPsec.html 444 root bin f none usr/lib/help/auths/locale/C/SmfValueIscsitgt.html 444 root bin f none usr/lib/help/auths/locale/C/SmfValueMDNS.html 444 root bin +f none usr/lib/help/auths/locale/C/SmfValueNADD.html 444 root bin f none usr/lib/help/auths/locale/C/SmfValueNWAM.html 444 root bin f none usr/lib/help/auths/locale/C/SmfValueRouting.html 444 root bin f none usr/lib/help/auths/locale/C/SmfWpaStates.html 444 root bin diff --git a/usr/src/pkgdefs/SUNWhal/prototype_com b/usr/src/pkgdefs/SUNWhal/prototype_com index c1261489d0..2cc544a272 100644 --- a/usr/src/pkgdefs/SUNWhal/prototype_com +++ b/usr/src/pkgdefs/SUNWhal/prototype_com @@ -48,8 +48,10 @@ d none usr/lib 755 root bin d none usr/lib/hal 755 root bin f none usr/lib/hal/hald 555 root bin f none usr/lib/hal/hald-addon-acpi 555 root bin +f none usr/lib/hal/hald-addon-network-discovery 555 root bin f none usr/lib/hal/hald-addon-storage 555 root bin f none usr/lib/hal/hald-probe-battery 555 root bin +f none usr/lib/hal/hald-probe-network-printer 555 root bin f none usr/lib/hal/hald-probe-printer 555 root bin f none usr/lib/hal/hald-probe-storage 555 root bin f none usr/lib/hal/hald-probe-volume 555 root bin diff --git a/usr/src/pkgdefs/SUNWhalr/prototype_com b/usr/src/pkgdefs/SUNWhalr/prototype_com index b42c35545a..9cbe319b4f 100644 --- a/usr/src/pkgdefs/SUNWhalr/prototype_com +++ b/usr/src/pkgdefs/SUNWhalr/prototype_com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -68,6 +68,7 @@ d none etc/hal/fdi/policy 755 root bin d none etc/hal/fdi/policy/10osvendor 755 root bin f none etc/hal/fdi/policy/10osvendor/10-keyboard-policy.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/10-laptop-panel-mgmt-policy.fdi 444 root bin +f none etc/hal/fdi/policy/10osvendor/10-network-attached.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/10-power-mgmt-policy.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/10-toshiba-buttons.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/20-storage-methods.fdi 444 root bin @@ -79,14 +80,18 @@ d none etc/hal/fdi/preprobe/10osvendor 755 root bin f none etc/hal/fdi/preprobe/10osvendor/10-ide-drives.fdi 444 root bin f none etc/hal/fdi/preprobe/10osvendor/20-ignore-fixed-storage.fdi 444 root bin f none etc/hal/fdi/preprobe/10osvendor/20-ignore-lofi.fdi 444 root bin +f none etc/hal/fdi/preprobe/10osvendor/20-printers.fdi 444 root bin d none etc/hal/fdi/preprobe/20thirdparty 755 root bin d none etc/hal/fdi/preprobe/30user 755 root bin d none lib 755 root bin d none lib/svc 0755 root bin d none lib/svc/method 0755 root bin f none lib/svc/method/svc-hal 555 root bin +f none lib/svc/method/svc-network-discovery 555 root bin d none var 755 root sys d none var/svc 755 root sys d none var/svc/manifest 755 root sys +d none var/svc/manifest/network 755 root sys +f manifest var/svc/manifest/network/network-discovery.xml 444 root sys d none var/svc/manifest/system 755 root sys f manifest var/svc/manifest/system/hal.xml 444 root sys diff --git a/usr/src/tools/scripts/check_rtime.pl b/usr/src/tools/scripts/check_rtime.pl index 057e8ddaf0..891904e530 100644 --- a/usr/src/tools/scripts/check_rtime.pl +++ b/usr/src/tools/scripts/check_rtime.pl @@ -215,6 +215,7 @@ $UnusedNoise = qr{ libmapmalloc\.so\.1;\ unused | unused\ dependency\ of\ .*libstdc\+\+\.so\.6 | unreferenced\ object=.*libstdc\+\+\.so\.6 | + unused\ dependency\ of\ .*libnetsnmp\.so\.5 | unused\ dependency\ of\ .*libnetsnmphelpers\.so\.5 | unused\ dependency\ of\ .*libnetsnmpmibs\.so\.5 | unused\ dependency\ of\ .*libnetsnmpagent\.so\.5 |