--- /dev/null
+#
+# Generated by the Apple Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = configd
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Aggregate
+
+TOOLS = configd.tproj scselect.tproj scutil.tproj
+
+FRAMEWORK_SUBPROJECTS = SystemConfiguration.fproj
+
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = aggregate.make
+LIBS =
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
--- /dev/null
+###############################################################################
+# Makefile.postamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile, which is imported after all other makefiles, to
+# override attributes for a project's Makefile environment. This allows you
+# to take advantage of the environment set up by the other Makefiles.
+# You can also define custom rules at the end of this file.
+#
+###############################################################################
+#
+# These variables are exported by the standard makefiles and can be
+# used in any customizations you make. They are *outputs* of
+# the Makefiles and should be used, not set.
+#
+# PRODUCTS: products to install. All of these products will be placed in
+# the directory $(DSTROOT)$(INSTALLDIR)
+# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
+# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
+# OFILE_DIR: Directory into which .o object files are generated.
+# DERIVED_SRC_DIR: Directory used for all other derived files
+#
+# ALL_CFLAGS: flags to pass when compiling .c files
+# ALL_MFLAGS: flags to pass when compiling .m files
+# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
+# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
+# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
+# ALL_LDFLAGS: flags to pass when linking object files
+# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
+# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
+# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
+# ALL_YFLAGS: flags to pass when processing .y (yacc) files
+# ALL_LFLAGS: flags to pass when processing .l (lex) files
+#
+# NAME: name of application, bundle, subproject, palette, etc.
+# LANGUAGES: langages in which the project is written (default "English")
+# English_RESOURCES: localized resources (e.g. nib's, images) of project
+# GLOBAL_RESOURCES: non-localized resources of project
+#
+# SRCROOT: base directory in which to place the new source files
+# SRCPATH: relative path from SRCROOT to present subdirectory
+#
+# INSTALLDIR: Directory the product will be installed into by 'install' target
+# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+#
+# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
+#
+###############################################################################
+
+# Some compiler flags can be overridden here for certain build situations.
+#
+# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
+# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
+# to -g)
+# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
+# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
+# to -O)
+# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
+# to -pg -DPROFILE)
+# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
+# the include path (defaults to -I.)
+# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
+# passed to ld/libtool (defaults to nothing)
+
+
+# Library and Framework projects only:
+# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
+# against the framework will run against the correct version even if
+# the current version of the framework changes. You may override this
+# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
+# development cycle, but be sure to restore it before installing.
+
+
+# Ownership and permissions of files installed by 'install' target
+
+#INSTALL_AS_USER = root
+ # User/group ownership
+#INSTALL_AS_GROUP = wheel
+ # (probably want to set both of these)
+#INSTALL_PERMISSIONS =
+ # If set, 'install' chmod's executable to this
+
+
+# Options to strip. Note: -S strips debugging symbols (executables can be stripped
+# down further with -x or, if they load no bundles, with no options at all).
+
+#STRIPFLAGS = -S
+
+
+#########################################################################
+# Put rules to extend the behavior of the standard Makefiles here. Include them in
+# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
+#
+# You should avoid redefining things like "install" or "app", as they are
+# owned by the top-level Makefile API and no context has been set up for where
+# derived files should go.
+#
--- /dev/null
+###############################################################################
+# Makefile.preamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile for configuring the standard application makefiles
+# associated with ProjectBuilder. It is included before the main makefile.
+# In Makefile.preamble you set attributes for a project, so they are available
+# to the project's makefiles. In contrast, you typically write additional rules or
+# override built-in behavior in the Makefile.postamble.
+#
+# Each directory in a project tree (main project plus subprojects) should
+# have its own Makefile.preamble and Makefile.postamble.
+###############################################################################
+#
+# Before the main makefile is included for this project, you may set:
+#
+# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
+# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
+
+# Compiler/linker flags added to the defaults: The OTHER_* variables will be
+# inherited by all nested sub-projects, but the LOCAL_ versions of the same
+# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
+# Build Attributes inspector if at all possible. To override the default flags
+# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
+# variables below are *inputs* to the build process and distinct from the override
+# settings done (less often) in the Makefile.postamble.
+#
+# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
+# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
+# .cc, .cxx, .C, and .M files. There is no need to respecify the
+# flags in OTHER_MFLAGS, etc.
+# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
+# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
+# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
+# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
+# precompiling header files
+# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
+# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
+# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
+# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
+# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
+
+# These variables provide hooks enabling you to add behavior at almost every
+# stage of the make:
+#
+# BEFORE_PREBUILD: targets to build before installing headers for a subproject
+# AFTER_PREBUILD: targets to build after installing headers for a subproject
+# BEFORE_BUILD_RECURSION: targets to make before building subprojects
+# BEFORE_BUILD: targets to make before a build, but after subprojects
+# AFTER_BUILD: targets to make after a build
+#
+# BEFORE_INSTALL: targets to build before installing the product
+# AFTER_INSTALL: targets to build after installing the product
+# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
+# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
+#
+# BEFORE_INSTALLHDRS: targets to build before installing headers for a
+# subproject
+# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
+# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
+# AFTER_INSTALLSRC: targets to build after installing source for a subproject
+#
+# BEFORE_DEPEND: targets to build before building dependencies for a
+# subproject
+# AFTER_DEPEND: targets to build after building dependencies for a
+# subproject
+#
+# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
+# updated every time the project is built. If NO, the dependency
+# file is only built when the depend target is invoked.
+
+# Framework-related variables:
+# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the framework's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+
+# Library-related variables:
+# PUBLIC_HEADER_DIR: Determines where public exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically. For library projects you should
+# set this to something like /Developer/Headers/$(NAME). Do not set
+# this variable for framework projects unless you do not want the
+# header files included in the framework.
+# PRIVATE_HEADER_DIR: Determines where private exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically.
+# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
+# whether the libraries produced are statically linked when they
+# are used or if they are dynamically loadable. This defaults to
+# DYNAMIC.
+# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the library's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+#
+# INSTALL_AS_USER: owner of the intalled products (default root)
+# INSTALL_AS_GROUP: group of the installed products (default wheel)
+# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
+#
+# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
+# passed on the command line to recursive invocations of make. Note that
+# the values in OTHER_*FLAGS are inherited by subprojects automatically --
+# you do not have to (and shouldn't) add OTHER_*FLAGS to
+# OTHER_RECURSIVE_VARIABLES.
+
+# Additional headers to export beyond those in the PB.project:
+# OTHER_PUBLIC_HEADERS
+# OTHER_PROJECT_HEADERS
+# OTHER_PRIVATE_HEADERS
+
+# Additional files for the project's product: <<path relative to proj?>>
+# OTHER_RESOURCES: (non-localized) resources for this project
+# OTHER_OFILES: relocatables to be linked into this project
+# OTHER_LIBS: more libraries to link against
+# OTHER_PRODUCT_DEPENDS: other dependencies of this project
+# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
+# OTHER_GARBAGE: additional files to be removed by `make clean'
+
+# Set this to YES if you don't want a final libtool call for a library/framework.
+# BUILD_OFILES_LIST_ONLY
+
+# To include a version string, project source must exist in a directory named
+# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
+# OTHER_GENERATED_OFILES = $(VERS_OFILE)
+
+# This definition will suppress stripping of debug symbols when an executable
+# is installed. By default it is YES.
+# STRIP_ON_INSTALL = NO
+
+# Uncomment to suppress generation of a KeyValueCoding index when installing
+# frameworks (This index is used by WOB and IB to determine keys available
+# for an object). Set to YES by default.
+# PREINDEX_FRAMEWORK = NO
+
+# Change this definition to install projects somewhere other than the
+# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
+# and "" on other systems.
+DSTROOT = $(HOME)
--- /dev/null
+{
+ DYNAMIC_CODE_GEN = YES;
+ FILESTABLE = {
+ H_FILES = ();
+ OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble);
+ SUBPROJECTS = (SystemConfiguration.fproj, configd.tproj, scselect.tproj, scutil.tproj);
+ };
+ LANGUAGE = English;
+ MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
+ NEXTSTEP_BUILDTOOL = /bin/gnumake;
+ NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
+ NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
+ PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
+ PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
+ PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = configd;
+ PROJECTTYPE = Aggregate;
+ PROJECTVERSION = 2.8;
+ WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
+ WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
+ WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+}
--- /dev/null
+{
+ CFBundleName = "SystemConfiguration";
+ CFBundleIdentifier = "com.apple.SystemConfiguration";
+ CFBundleShortVersionString = "1.0.0";
+}
--- /dev/null
+#
+# Generated by the Apple Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = SystemConfiguration
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Framework
+
+HFILES = SystemConfiguration.h config_types.h SCD.h SCDKeys.h\
+ SCDPrivate.h SCP.h SCPPrivate.h SCPPath.h SCDConsoleUser.h\
+ SCDHostName.h SCNetwork.h ppp_msg.h ppp.h
+
+CFILES = SCD.c SCDKeys.c SCDPrivate.c SCDHandle.c SCDOpen.c\
+ SCDClose.c SCDLock.c SCDUnlock.c SCDList.c SCDAdd.c\
+ SCDAddSession.c SCDGet.c SCDSet.c SCDRemove.c SCDTouch.c\
+ SCDNotifierList.c SCDNotifierAdd.c SCDNotifierRemove.c\
+ SCDNotifierGetChanges.c SCDNotifierWait.c\
+ SCDNotifierInformViaCallback.c SCDNotifierInformViaMachPort.c\
+ SCDNotifierInformViaFD.c SCDNotifierInformViaSignal.c\
+ SCDNotifierCancel.c SCDSnapshot.c SCP.c SCPOpen.c SCPClose.c\
+ SCPLock.c SCPUnlock.c SCPList.c SCPGet.c SCPAdd.c SCPSet.c\
+ SCPRemove.c SCPCommit.c SCPApply.c SCPPath.c SCDConsoleUser.c\
+ SCDHostName.c SCNetwork.c ppp.c
+
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble m.template\
+ h.template config.defs genSCPreferences.c CustomInfo.plist
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CURRENTLY_ACTIVE_VERSION = YES
+DEPLOY_WITH_VERSION_NAME = A
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = framework.make
+NEXTSTEP_INSTALLDIR = $(SYSTEM_LIBRARY_DIR)/PrivateFrameworks
+WINDOWS_INSTALLDIR = /Library/Frameworks
+PDO_UNIX_INSTALLDIR = /Library/Frameworks
+LIBS =
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+FRAMEWORKS = -framework CoreFoundation
+PUBLIC_HEADERS = SystemConfiguration.h SCD.h SCDKeys.h SCP.h SCPPath.h\
+ SCDConsoleUser.h SCDHostName.h SCNetwork.h
+
+PROJECT_HEADERS = SystemConfiguration.h config_types.h SCD.h\
+ SCDPrivate.h SCP.h SCPPrivate.h SCPPath.h\
+ SCDConsoleUser.h SCDHostName.h SCNetwork.h
+
+
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
--- /dev/null
+###############################################################################
+# Makefile.postamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile, which is imported after all other makefiles, to
+# override attributes for a project's Makefile environment. This allows you
+# to take advantage of the environment set up by the other Makefiles.
+# You can also define custom rules at the end of this file.
+#
+###############################################################################
+#
+# These variables are exported by the standard makefiles and can be
+# used in any customizations you make. They are *outputs* of
+# the Makefiles and should be used, not set.
+#
+# PRODUCTS: products to install. All of these products will be placed in
+# the directory $(DSTROOT)$(INSTALLDIR)
+# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
+# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
+# OFILE_DIR: Directory into which .o object files are generated.
+# DERIVED_SRC_DIR: Directory used for all other derived files
+#
+# ALL_CFLAGS: flags to pass when compiling .c files
+# ALL_MFLAGS: flags to pass when compiling .m files
+# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
+# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
+# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
+# ALL_LDFLAGS: flags to pass when linking object files
+# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
+# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
+# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
+# ALL_YFLAGS: flags to pass when processing .y (yacc) files
+# ALL_LFLAGS: flags to pass when processing .l (lex) files
+#
+# NAME: name of application, bundle, subproject, palette, etc.
+# LANGUAGES: langages in which the project is written (default "English")
+# English_RESOURCES: localized resources (e.g. nib's, images) of project
+# GLOBAL_RESOURCES: non-localized resources of project
+#
+# SRCROOT: base directory in which to place the new source files
+# SRCPATH: relative path from SRCROOT to present subdirectory
+#
+# INSTALLDIR: Directory the product will be installed into by 'install' target
+# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+#
+# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
+#
+###############################################################################
+
+# Some compiler flags can be overridden here for certain build situations.
+#
+# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
+# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
+# to -g)
+# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
+# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
+# to -O)
+# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
+# to -pg -DPROFILE)
+# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
+# the include path (defaults to -I.)
+# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
+# passed to ld/libtool (defaults to nothing)
+
+
+# Library and Framework projects only:
+# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
+# against the framework will run against the correct version even if
+# the current version of the framework changes. You may override this
+# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
+# development cycle, but be sure to restore it before installing.
+
+
+# Ownership and permissions of files installed by 'install' target
+
+#INSTALL_AS_USER = root
+ # User/group ownership
+#INSTALL_AS_GROUP = wheel
+ # (probably want to set both of these)
+#INSTALL_PERMISSIONS =
+ # If set, 'install' chmod's executable to this
+
+
+# Options to strip. Note: -S strips debugging symbols (executables can be stripped
+# down further with -x or, if they load no bundles, with no options at all).
+
+#STRIPFLAGS = -S
+
+
+#########################################################################
+# Put rules to extend the behavior of the standard Makefiles here. Include them in
+# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
+#
+# You should avoid redefining things like "install" or "app", as they are
+# owned by the top-level Makefile API and no context has been set up for where
+# derived files should go.
+#
+
+#
+# Additional options to create generated headers, source
+#
+before_installhdrs: $(OFILE_DIR)
+
+$(OFILE_DIR)/genSCPreferences: genSCPreferences.o
+ $(CC) -o $@ $(ARCHITECTURE_FLAGS) $<
+
+SCPreferences.h: $(OFILE_DIR)/genSCPreferences
+ $(CD) $(SFILE_DIR) && $(OFILE_DIR)/genSCPreferences header > $@
+
+SCPreferences.c: $(OFILE_DIR)/genSCPreferences
+ $(CD) $(SFILE_DIR) && $(OFILE_DIR)/genSCPreferences cfile > $@
+
+genSCFiles:
+ cc -o /tmp/genSCFiles genSCPreferences.c -framework CoreFoundation
+ /tmp/genSCFiles header > /tmp/SCPreferences.h
+ /tmp/genSCFiles cfile > /tmp/SCPreferences.c
--- /dev/null
+###############################################################################
+# Makefile.preamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile for configuring the standard application makefiles
+# associated with ProjectBuilder. It is included before the main makefile.
+# In Makefile.preamble you set attributes for a project, so they are available
+# to the project's makefiles. In contrast, you typically write additional rules or
+# override built-in behavior in the Makefile.postamble.
+#
+# Each directory in a project tree (main project plus subprojects) should
+# have its own Makefile.preamble and Makefile.postamble.
+###############################################################################
+#
+# Before the main makefile is included for this project, you may set:
+#
+# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
+# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
+
+# Compiler/linker flags added to the defaults: The OTHER_* variables will be
+# inherited by all nested sub-projects, but the LOCAL_ versions of the same
+# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
+# Build Attributes inspector if at all possible. To override the default flags
+# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
+# variables below are *inputs* to the build process and distinct from the override
+# settings done (less often) in the Makefile.postamble.
+#
+# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
+# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
+# .cc, .cxx, .C, and .M files. There is no need to respecify the
+# flags in OTHER_MFLAGS, etc.
+# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
+# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
+# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
+# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
+# precompiling header files
+# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
+# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
+# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
+# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
+# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
+
+# These variables provide hooks enabling you to add behavior at almost every
+# stage of the make:
+#
+# BEFORE_PREBUILD: targets to build before installing headers for a subproject
+# AFTER_PREBUILD: targets to build after installing headers for a subproject
+# BEFORE_BUILD_RECURSION: targets to make before building subprojects
+# BEFORE_BUILD: targets to make before a build, but after subprojects
+# AFTER_BUILD: targets to make after a build
+#
+# BEFORE_INSTALL: targets to build before installing the product
+# AFTER_INSTALL: targets to build after installing the product
+# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
+# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
+#
+# BEFORE_INSTALLHDRS: targets to build before installing headers for a
+# subproject
+# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
+# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
+# AFTER_INSTALLSRC: targets to build after installing source for a subproject
+#
+# BEFORE_DEPEND: targets to build before building dependencies for a
+# subproject
+# AFTER_DEPEND: targets to build after building dependencies for a
+# subproject
+#
+# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
+# updated every time the project is built. If NO, the dependency
+# file is only built when the depend target is invoked.
+
+# Framework-related variables:
+# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the framework's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+
+# Library-related variables:
+# PUBLIC_HEADER_DIR: Determines where public exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically. For library projects you should
+# set this to something like /Developer/Headers/$(NAME). Do not set
+# this variable for framework projects unless you do not want the
+# header files included in the framework.
+# PRIVATE_HEADER_DIR: Determines where private exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically.
+# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
+# whether the libraries produced are statically linked when they
+# are used or if they are dynamically loadable. This defaults to
+# DYNAMIC.
+# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the library's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+#
+# INSTALL_AS_USER: owner of the intalled products (default root)
+# INSTALL_AS_GROUP: group of the installed products (default wheel)
+# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
+#
+# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
+# passed on the command line to recursive invocations of make. Note that
+# the values in OTHER_*FLAGS are inherited by subprojects automatically --
+# you do not have to (and shouldn't) add OTHER_*FLAGS to
+# OTHER_RECURSIVE_VARIABLES.
+
+# Additional headers to export beyond those in the PB.project:
+# OTHER_PUBLIC_HEADERS
+# OTHER_PROJECT_HEADERS
+# OTHER_PRIVATE_HEADERS
+
+# Additional files for the project's product: <<path relative to proj?>>
+# OTHER_RESOURCES: (non-localized) resources for this project
+# OTHER_OFILES: relocatables to be linked into this project
+# OTHER_LIBS: more libraries to link against
+# OTHER_PRODUCT_DEPENDS: other dependencies of this project
+# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
+# OTHER_GARBAGE: additional files to be removed by `make clean'
+
+# Set this to YES if you don't want a final libtool call for a library/framework.
+# BUILD_OFILES_LIST_ONLY
+
+# To include a version string, project source must exist in a directory named
+# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
+OTHER_GENERATED_OFILES = $(VERS_OFILE)
+
+# This definition will suppress stripping of debug symbols when an executable
+# is installed. By default it is YES.
+# STRIP_ON_INSTALL = NO
+
+# Uncomment to suppress generation of a KeyValueCoding index when installing
+# frameworks (This index is used by WOB and IB to determine keys available
+# for an object). Set to YES by default.
+# PREINDEX_FRAMEWORK = NO
+
+# Change this definition to install projects somewhere other than the
+# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
+# and "" on other systems.
+# DSTROOT = $(HOME)
+
+# Additional flags for MiG generated files
+OTHER_PROJECT_HEADERS += config.defs config.h
+OTHER_OFILES += configUser.o
+
+# Additional options to create generated headers, source
+BEFORE_INSTALLHDRS = before_installhdrs
+OTHER_SOURCEFILES += genSCPreferences.c
+OTHER_GENERATED_SRCFILES += SCPreferences.h SCPreferences.c
+OTHER_PUBLIC_HEADERS += SCPreferences.h
+OTHER_OFILES += SCPreferences.o
+
+# Specify framework initialization code
+OTHER_LDFLAGS += -Wl,-init,___Initialize
+
+# Additional build flags
+ifeq "$(PLATFORM_OS)" "macos"
+ APPLE_INTERNAL_DIR ?= /AppleInternal
+ APPLE_INTERNAL_DEVELOPER_DIR ?= /AppleInternal/Developer
+ OTHER_LDFLAGS += -seg_addr_table $(APPLE_INTERNAL_DEVELOPER_DIR)/seg_addr_table
+ SECTORDER_FLAGS = -sectorder __TEXT __text $(APPLE_INTERNAL_DIR)/OrderFiles/SystemConfiguration.order
+endif
--- /dev/null
+{
+ CURRENTLY_ACTIVE_VERSION = YES;
+ DEPLOY_WITH_VERSION_NAME = A;
+ DYNAMIC_CODE_GEN = YES;
+ FILESTABLE = {
+ FRAMEWORKS = (CoreFoundation.framework);
+ FRAMEWORKSEARCH = ();
+ H_FILES = (
+ SystemConfiguration.h,
+ config_types.h,
+ SCD.h,
+ SCDKeys.h,
+ SCDPrivate.h,
+ SCP.h,
+ SCPPrivate.h,
+ SCPPath.h,
+ SCDConsoleUser.h,
+ SCDHostName.h,
+ SCNetwork.h,
+ ppp_msg.h,
+ ppp.h
+ );
+ OTHER_LINKED = (
+ SCD.c,
+ SCDKeys.c,
+ SCDPrivate.c,
+ SCDHandle.c,
+ SCDOpen.c,
+ SCDClose.c,
+ SCDLock.c,
+ SCDUnlock.c,
+ SCDList.c,
+ SCDAdd.c,
+ SCDAddSession.c,
+ SCDGet.c,
+ SCDSet.c,
+ SCDRemove.c,
+ SCDTouch.c,
+ SCDNotifierList.c,
+ SCDNotifierAdd.c,
+ SCDNotifierRemove.c,
+ SCDNotifierGetChanges.c,
+ SCDNotifierWait.c,
+ SCDNotifierInformViaCallback.c,
+ SCDNotifierInformViaMachPort.c,
+ SCDNotifierInformViaFD.c,
+ SCDNotifierInformViaSignal.c,
+ SCDNotifierCancel.c,
+ SCDSnapshot.c,
+ SCP.c,
+ SCPOpen.c,
+ SCPClose.c,
+ SCPLock.c,
+ SCPUnlock.c,
+ SCPList.c,
+ SCPGet.c,
+ SCPAdd.c,
+ SCPSet.c,
+ SCPRemove.c,
+ SCPCommit.c,
+ SCPApply.c,
+ SCPPath.c,
+ SCDConsoleUser.c,
+ SCDHostName.c,
+ SCNetwork.c,
+ ppp.c
+ );
+ OTHER_SOURCES = (
+ Makefile.preamble,
+ Makefile,
+ Makefile.postamble,
+ m.template,
+ h.template,
+ config.defs,
+ genSCPreferences.c,
+ CustomInfo.plist
+ );
+ PRECOMPILED_HEADERS = ();
+ PROJECT_HEADERS = (
+ SystemConfiguration.h,
+ config_types.h,
+ SCD.h,
+ SCDPrivate.h,
+ SCP.h,
+ SCPPrivate.h,
+ SCPPath.h,
+ SCDConsoleUser.h,
+ SCDHostName.h,
+ SCNetwork.h
+ );
+ PUBLIC_HEADERS = (
+ SystemConfiguration.h,
+ SCD.h,
+ SCDKeys.h,
+ SCP.h,
+ SCPPath.h,
+ SCDConsoleUser.h,
+ SCDHostName.h,
+ SCNetwork.h
+ );
+ SUBPROJECTS = ();
+ };
+ LANGUAGE = English;
+ MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
+ NEXTSTEP_BUILDTOOL = /usr/bin/gnumake;
+ NEXTSTEP_INSTALLDIR = "$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks";
+ NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
+ NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
+ PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
+ PDO_UNIX_INSTALLDIR = /Library/Frameworks;
+ PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
+ PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = SystemConfiguration;
+ PROJECTTYPE = Framework;
+ PROJECTVERSION = 2.8;
+ WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
+ WINDOWS_INSTALLDIR = /Library/Frameworks;
+ WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
+ WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+static _SCDFlags globalFlags = {
+ FALSE /* debug */,
+ FALSE /* verbose */,
+ FALSE /* useSyslog */,
+ FALSE /* isLocked */,
+ TRUE /* useCFRunLoop */,
+};
+
+static boolean_t isSCDServer = FALSE;
+
+static const struct scd_errmsg {
+ SCDStatus status;
+ char *message;
+} scd_errmsgs[] = {
+ { SCD_OK, "Success!" },
+ { SCD_NOSESSION, "Configuration daemon session not active" },
+ { SCD_NOSERVER, "Configuration daemon not (no longer) available" },
+ { SCD_LOCKED, "Lock already held" },
+ { SCD_NEEDLOCK, "Lock required for this operation" },
+ { SCD_EACCESS, "Permission denied (must be root to obtain lock)" },
+ { SCD_NOKEY, "No such key" },
+ { SCD_EXISTS, "Data associated with key already defined" },
+ { SCD_STALE, "Write attempted on stale version of object" },
+ { SCD_INVALIDARGUMENT, "Invalid argument" },
+ { SCD_NOTIFIERACTIVE, "Notifier is currently active" },
+ { SCD_FAILED, "Failed!" }
+};
+#define nSCD_ERRMSGS (sizeof(scd_errmsgs)/sizeof(struct scd_errmsg))
+
+
+int
+SCDOptionGet(SCDSessionRef session, const int option)
+{
+ _SCDFlags *theFlags = &globalFlags;
+ int value = 0;
+
+ if (session != NULL) {
+ theFlags = &((SCDSessionPrivateRef)session)->flags;
+ }
+
+ switch (option) {
+
+ /* session dependent flags */
+
+ case kSCDOptionDebug :
+ value = theFlags->debug;
+ break;
+
+ case kSCDOptionVerbose :
+ value = theFlags->verbose;
+ break;
+
+ case kSCDOptionIsLocked :
+ value = theFlags->isLocked;
+ break;
+
+ case kSCDOptionUseSyslog :
+ value = theFlags->useSyslog;
+ break;
+
+ case kSCDOptionUseCFRunLoop :
+ value = theFlags->useCFRunLoop;
+ break;
+
+ /* session independent flags */
+
+ case kSCDOptionIsServer :
+ value = isSCDServer;
+ break;
+ }
+
+ return value;
+}
+
+
+void
+SCDOptionSet(SCDSessionRef session, int option, const int value)
+{
+ _SCDFlags *theFlags = &globalFlags;
+
+ if (session != NULL) {
+ theFlags = &((SCDSessionPrivateRef)session)->flags;
+ }
+
+ switch (option) {
+
+ /* session independent flags */
+
+ case kSCDOptionDebug :
+ theFlags->debug = value;
+ break;
+
+ case kSCDOptionVerbose :
+ theFlags->verbose = value;
+ break;
+
+ case kSCDOptionIsLocked :
+ theFlags->isLocked = value;
+ break;
+
+ case kSCDOptionUseSyslog :
+ theFlags->useSyslog = value;
+ break;
+
+ case kSCDOptionUseCFRunLoop :
+ theFlags->useCFRunLoop = value;
+ break;
+
+ /* session independent flags */
+
+ case kSCDOptionIsServer :
+ isSCDServer = value;
+ break;
+ }
+
+ return;
+}
+
+
+static void
+_SCDLog(SCDSessionRef session, int level, CFArrayRef lines)
+{
+ FILE *f = (LOG_PRI(level) > LOG_NOTICE) ? stderr : stdout;
+ CFDataRef line;
+ int i;
+
+ if ((LOG_PRI(level) == LOG_DEBUG) && !SCDOptionGet(session, kSCDOptionVerbose)) {
+ /* it's a debug message and we haven't requested verbose logging */
+ return;
+ }
+
+ pthread_mutex_lock(&lock);
+
+ for (i=0; i<CFArrayGetCount(lines); i++) {
+ line = CFStringCreateExternalRepresentation(NULL,
+ CFArrayGetValueAtIndex(lines, i),
+ kCFStringEncodingMacRoman,
+ '?');
+ if (line != NULL) {
+ if (SCDOptionGet(session, kSCDOptionUseSyslog)) {
+ syslog (level, "%.*s", (int)CFDataGetLength(line), CFDataGetBytePtr(line));
+ } else {
+ fprintf(f, "%.*s\n", (int)CFDataGetLength(line), CFDataGetBytePtr(line));
+ fflush (f);
+ }
+ CFRelease(line);
+ }
+ }
+
+ pthread_mutex_unlock(&lock);
+}
+
+
+void
+SCDSessionLog(SCDSessionRef session, int level, CFStringRef formatString, ...)
+{
+ va_list argList;
+ CFStringRef resultString;
+ CFArrayRef lines;
+
+ va_start(argList, formatString);
+ resultString = CFStringCreateWithFormatAndArguments(NULL, NULL, formatString, argList);
+ va_end(argList);
+
+ lines = CFStringCreateArrayBySeparatingStrings(NULL, resultString, CFSTR("\n"));
+ _SCDLog(session, level, lines);
+ CFRelease(lines);
+ CFRelease(resultString);
+}
+
+
+void
+SCDLog(int level, CFStringRef formatString, ...)
+{
+ va_list argList;
+ CFStringRef resultString;
+ CFArrayRef lines;
+
+ va_start(argList, formatString);
+ resultString = CFStringCreateWithFormatAndArguments(NULL, NULL, formatString, argList);
+ va_end(argList);
+
+ lines = CFStringCreateArrayBySeparatingStrings(NULL, resultString, CFSTR("\n"));
+ _SCDLog(NULL, level, lines);
+ CFRelease(lines);
+ CFRelease(resultString);
+}
+
+
+const char *
+SCDError(SCDStatus status)
+{
+ int i;
+
+ for (i = 0; i < nSCD_ERRMSGS; i++) {
+ if (scd_errmsgs[i].status == status) {
+ return scd_errmsgs[i].message;
+ }
+ }
+ return "(unknown error)";
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCD_H
+#define _SCD_H
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <CoreFoundation/CFRunLoop.h>
+#include <mach/message.h>
+#include <sys/cdefs.h>
+#include <sys/syslog.h>
+
+
+/*!
+ @header SCD.h
+ The SystemConfiguration framework provides access to the data used to configure a running system. The APIs provided by this framework communicate with the "configd" daemon.
+
+The "configd" daemon manages a "cache" reflecting the desired configuration settings as well as the current state of the system. The daemon provides a notification mechanism for user-level processes which need to be aware of changes made to the "cache" data. Lastly, the daemon loads a number of bundles(or plug-ins) which monitor low-level kernel events and, via a set of policy modules, keep this cached data up to date.
+
+The "configd" daemon also provides an address space/task/process which can be used by other CFRunLoop based functions which would otherwise require their own process/daemon for execution.
+
+ */
+
+
+/*!
+ @enum SCDStatus
+ @discussion Returned status codes.
+ @constant SCD_OK Success
+ @constant SCD_NOSESSION Configuration daemon session not active
+ @constant SCD_NOSERVER Configuration daemon not (no longer) available
+ @constant SCD_LOCKED Lock already held
+ @constant SCD_NEEDLOCK Lock required for this operation
+ @constant SCD_EACCESS Permission denied (must be root to obtain lock)
+ @constant SCD_NOKEY No such key
+ @constant SCD_EXISTS Data associated with key already defined
+ @constant SCD_STALE Write attempted on stale version of object
+ @constant SCD_INVALIDARGUMENT Invalid argument
+ @constant SCD_NOTIFIERACTIVE Notifier is currently active
+ @constant SCD_FAILED Generic error
+ */
+typedef enum {
+ SCD_OK = 0, /* Success */
+ SCD_NOSESSION = 1, /* Configuration daemon session not active */
+ SCD_NOSERVER = 2, /* Configuration daemon not (no longer) available */
+ SCD_LOCKED = 3, /* Lock already held */
+ SCD_NEEDLOCK = 4, /* Lock required for this operation */
+ SCD_EACCESS = 5, /* Permission denied (must be root to obtain lock) */
+ SCD_NOKEY = 6, /* No such key */
+ SCD_EXISTS = 7, /* Data associated with key already defined */
+ SCD_STALE = 8, /* Write attempted on stale version of object */
+ SCD_INVALIDARGUMENT = 9, /* Invalid argument */
+ SCD_NOTIFIERACTIVE = 10, /* Notifier is currently active */
+ SCD_FAILED = 9999 /* Generic error */
+} SCDStatus;
+
+
+/*!
+ @typedef SCDSessionRef
+ @discussion This is the type of a handle to an open "session" with the system
+ configuration daemon.
+ */
+typedef const struct __SCDSession * SCDSessionRef;
+
+/*!
+ @typedef SCDHandleRef
+ @discussion This is the type of a handle to data being retrieved from or to be
+ stored by the system configuration daemon.
+ */
+typedef const struct __SCDHandle * SCDHandleRef;
+
+
+/*!
+ @typedef SCDCallbackRoutine_t
+ @discussion Type of the callback function used by the SCDNotifierInformViaCallback()
+ function.
+ @param session The session handle.
+ @param callback_argument The user-defined argument to be passed to the callback
+ function.
+ */
+typedef boolean_t (*SCDCallbackRoutine_t) (SCDSessionRef session,
+ void *callback_argument);
+
+
+/*!
+ @enum SCDKeyOption
+ @discussion Used with the SCDList() and SCDNotifierAdd() functions to describe
+ the CFStringRef argument.
+ @constant kSCDRegexKey Specifies that the key consists of a regular expression.
+ */
+typedef enum {
+ kSCDRegexKey = 0100000, /* pattern string is a regular expression */
+} SCDKeyOption;
+
+
+/*!
+ @enum SCDOption
+ @discussion Options which determine the run-time processing of the system
+ configuration framework functions.
+ @constant kSCDOptionDebug Enable debugging
+ @constant kSCDOptionVerbose Enable verbose logging
+ @constant kSCDOptionUseSyslog Use syslog(3) for log messages
+ @constant kSCDOptionUseCFRunLoop Calling application is CFRunLoop() based
+ */
+typedef enum {
+ kSCDOptionDebug = 0, /* Enable debugging */
+ kSCDOptionVerbose = 1, /* Enable verbose logging */
+ kSCDOptionUseSyslog = 2, /* Use syslog(3) for log messages */
+ kSCDOptionUseCFRunLoop = 3, /* Calling application is CFRunLoop() based */
+} SCDOption;
+
+
+/*
+ * "configd" loadable bundle / plug-in options
+ */
+
+/*!
+ @typedef SCDBundleStartRoutine_t
+ @discussion Type of the start() initializatioin function which will be called
+ after all plug-ins have been loaded. This function should initialize any
+ variables, open any sessions with "configd", and register any needed
+ notifications.
+ @param bundlePath The path name associated with the plug-in / bundle.
+ @param bundleName The name of the plug-in / bundle.
+ */
+typedef void (*SCDBundleStartRoutine_t) (const char *bundlePath,
+ const char *bundleName);
+
+/*!
+ @typedef SCDBundlePrimeRoutine_t
+ @discussion Type of the prime() initializatioin function which will be
+ called after all plug-ins have executed their start() function but
+ before the main plug-in run loop is started. This function should
+ be used to initialize any configuration information and/or state
+ in the cache.
+ */
+typedef void (*SCDBundlePrimeRoutine_t) ();
+
+#define BUNDLE_DIRECTORY "/SystemConfiguration" /* [/System/Library]/... */
+#define BUNDLE_OLD_SUBDIR "/"
+#define BUNDLE_NEW_SUBDIR "/Contents/MacOS/"
+#define BUNDLE_DIR_EXTENSION ".bundle"
+#define BUNDLE_DEBUG_EXTENSION "_debug"
+#define BUNDLE_ENTRY_POINT "_start"
+#define BUNDLE_ENTRY_POINT2 "_prime"
+
+
+__BEGIN_DECLS
+
+/*!
+ @function SCDHandleInit
+ @discussion Creates a new handle used to access the cached configuration
+ dictionary data.
+ @result A new "cache" data handle.
+ */
+SCDHandleRef SCDHandleInit ();
+
+/*!
+ @function SCDHandleRelease
+ @discussion Releases the specified configuration data handle. The dictionary
+ (or other CFType) associated with this handle will also be released
+ unless a call was previously made to CFRetain().
+ @param handle The cache data handle to be released.
+ */
+void SCDHandleRelease (SCDHandleRef handle);
+
+/*!
+ @function SCDHandleGetInstance
+ @discussion Returns the instance number associated with the specified
+ configuration handle.
+ @param handle The cache data handle.
+ @result The instance number associated with the specified handle.
+ */
+int SCDHandleGetInstance (SCDHandleRef handle);
+
+/*!
+ @function SCDHandleGetData
+ @discussion Returns a reference to the data associated with the specified
+ configuration handle.
+ @param handle The cache data handle.
+ @result The CFType data associated with the specified handle.
+ */
+CFPropertyListRef SCDHandleGetData (SCDHandleRef handle);
+
+/*!
+ @function SCDHandleSetData
+ @discussion Returns a reference to the data associated with the specified
+ configuration handle.
+ @param handle The cache data handle.
+ @param data The CFType data to be associated with the handle.
+ */
+void SCDHandleSetData (SCDHandleRef handle,
+ CFPropertyListRef data);
+/*!
+ @function SCDOpen
+ @discussion Initiates a connection with the configuration daemon.
+ @param session A pointer to memory which will be filled with an SCDSessionRef
+ handle to be used for all subsequent requests to the server.
+ If a session cannot be established with the server, the contents of
+ memory pointed to by this parameter are undefined.
+ @param name Pass a string which describes the name of the calling process or
+ plug-in name of the caller.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDOpen (SCDSessionRef *session,
+ CFStringRef name);
+
+/*!
+ @function SCDClose
+ @discussion Closes the specified session to the configuration daemon. All
+ outstanding notification requests will be cancelled.
+ @param session Pass a pointer to an SCDSessionRef handle which should be closed.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDClose (SCDSessionRef *session);
+
+/*!
+ @function SCDLock
+ @discussion Locks access to the configuration "cache". All other clients
+ attempting to access the "cache" will block. All change notifications
+ will be deferred until the lock is released.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDLock (SCDSessionRef session);
+
+/*!
+ @function SCDUnlock
+ @discussion Unlocks access to the configuration "cache". Other clients will
+ be able to access the "cache". Any change notifications will be delivered.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDUnlock (SCDSessionRef session);
+
+/*!
+ @function SCDList
+ @discussion Returns an array of CFStringRefs representing the configuration "cache"
+ entries which match the specified pattern key.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param key The string which must prefix those keys in the configuration "cache"
+ (if regexOptions is zero) or a regex(3) regular expression string which
+ will be used to match configuration "cache" (if regexOptions is kSCDRegexKey).
+ @param regexOptions Pass a bitfield of type SCDKeyOption containing one or more
+ flags describing the pattern key.
+ @param subKeys Pass a pointer to a CFArrayRef which will be set to a new
+ array of CFStringRefs's matching the provided key.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDList (SCDSessionRef session,
+ CFStringRef key,
+ int regexOptions,
+ CFArrayRef *subKeys);
+
+/*!
+ @function SCDAdd
+ @discussion Creates a new entry in the configuration "cache" using the
+ specified key and data. An error is returned if the key is already
+ defined in the dictionary.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param key Pass a reference to the CFStringRef object to be created.
+ @param handle Pass a reference to the SCDHandle object containing the data
+ to be associated with the specified key.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDAdd (SCDSessionRef session,
+ CFStringRef key,
+ SCDHandleRef handle);
+
+/*!
+ @function SCDAddSession
+ @discussion Creates a new entry in the configuration "cache" using the
+ specified key and data. This entry will, unless updated by another
+ session, automatically be removed when the session is closed. An
+ error is returned if the key is already defined in the dictionary.
+
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param key Pass a reference to the CFStringRef object to be created.
+ @param handle Pass a reference to the SCDHandle object containing the data
+ to be associated with the specified key.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDAddSession (SCDSessionRef session,
+ CFStringRef key,
+ SCDHandleRef handle);
+
+/*!
+ @function SCDGet
+ @discussion Returns a handle to the configuration "cache" data that corresponds
+ to the specified key.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param key Pass a reference to the CFStringRef object to be returned.
+ @param handle Pass a pointer to a SCDHandleRef which will be set to a
+ new object containing the data associated with the specified key.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDGet (SCDSessionRef session,
+ CFStringRef key,
+ SCDHandleRef *handle);
+
+/*!
+ @function SCDSet
+ @discussion Updates the entry in the configuration "cache" that corresponds to
+ the specified key with the provided data. An error will be returned if
+ the data in the "cache" has been updated since the data handle was last
+ updated.
+ @param session Pass the SCDSessionRef handle which should be used to communicate
+ with the server.
+ @param key Pass a reference to the CFStringRef object to be updated.
+ @param handle Pass a reference to the SCDHandle object containing the data
+ to be associated with the specified key.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDSet (SCDSessionRef session,
+ CFStringRef key,
+ SCDHandleRef handle);
+
+/*!
+ @function SCDRemove
+ @discussion Removes the data from the configuration "cache" data which corresponds
+ to the specified key.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param key Pass a reference to the CFStringRef object to be removed.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDRemove (SCDSessionRef session,
+ CFStringRef key);
+
+/*!
+ @function SCDTouch
+ @discussion Updates the instance number for the data in the configuration "cache"
+ associated with the specified key. If the specified key does not exist
+ then a CFDate object will be associated with the key. If the associated
+ data is already a CFDate object then the value will be updated.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param key Pass a reference to the CFStringRef object to be updated.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDTouch (SCDSessionRef session,
+ CFStringRef key);
+
+/*
+ @function SCDSnapshot
+ @discussion Records the current state of configd's cache dictionary into the
+ /var/tmp/configd-cache file and configd's session dictionary into the
+ /var/tmp/configd-session file.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDSnapshot (SCDSessionRef session);
+
+/*!
+ @function SCDNotifierList
+ @discussion Returns an array of CFStringRefs representing the system configuration
+ data entries being monitored for changes.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param regexOptions Pass a bitfield of type SCDKeyOption which specifies whether
+ the specific configuration cache key patterns are to be returned or those
+ based on regex(3) pattern strings.
+ @param notifierKeys Pass a pointer to a CFArrayRef which will be set to a new
+ array of CFStringRef's being monitored.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierList (SCDSessionRef session,
+ int regexOptions,
+ CFArrayRef *notifierKeys);
+
+/*!
+ @function SCDNotifierAdd
+ @discussion Adds the specified key to the list of system configuration
+ data entries which are being monitored for changes.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param key Pass a reference to the CFStringRef object to be monitored.
+ @param regexOptions Pass a bitfield of type SCDKeyOption which specifies whether
+ the key is for a specific configuration cache key or if it consists
+ of a regex(3) pattern string.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierAdd (SCDSessionRef session,
+ CFStringRef key,
+ int regexOptions);
+
+/*!
+ @function SCDNotifierRemove
+ @discussion Removes the specified key from the list of system configuration
+ data entries which are being monitored for changes.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param key Pass a reference to the CFStringRef object which should not be monitored.
+ @param regexOptions Pass a bitfield of type SCDKeyOption which specifies whether
+ the key is for a specific configuration cache key or if it consists
+ of a regex(3) pattern string.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierRemove (SCDSessionRef session,
+ CFStringRef key,
+ int regexOptions);
+
+/*!
+ @function SCDNotifierGetChanges
+ @discussion Returns an array of CFStringRefs representing the monitored system
+ configuration data entries which have changed since this function
+ was last called.
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param notifierKeys Pass a pointer to a CFArrayRef which will be set to a new
+ array of CFStringRef's being monitored.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierGetChanges (SCDSessionRef session,
+ CFArrayRef *notifierKeys);
+
+/*!
+ @function SCDNotifierWait
+ @discussion Waits for a change to be made to a system configuration data
+ entry associated with the current sessions notifier keys.
+
+ Note: this function is not valid for "configd" plug-ins.
+
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierWait (SCDSessionRef session);
+
+/*!
+ @function SCDNotifierInformViaCallback
+ @discussion Requests that the specified function be called whenever a change
+ has been detected to one of the system configuration data entries
+ associated with the current sessions notifier keys.
+
+ The callback function will be called with two arguments, session and arg, which
+ correspond to the current session and the provided argument.
+ The function should return a boolean value indicating whether an
+ error occurred during execution of the callback.
+
+ Note: if the calling application is based on the CFRunLoop() then an additional
+ run loop source will be added for the notification.
+ Applications which are not based on the CFRunLoop() will have a separate thread
+ started to wait for changes.
+ In either case, the additional run loop source and/or thread will terminate if
+ the notification is cancelled or if the callback indicates that an error was
+ detected.
+
+ Note: this function is not valid for "configd" plug-ins.
+
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param func Pass a pointer to the callback applier function to call when a
+ monitored cache entry is changed. If this parameter is not a pointer to
+ a function of the correct prototype (SCDCallbackRoutine_t), the behavior
+ is undefined.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierInformViaCallback (SCDSessionRef session,
+ SCDCallbackRoutine_t func,
+ void *arg);
+
+/*!
+ @function SCDNotifierInformViaMachPort
+ @discussion Allocates a mach port which can be used to detect changes to
+ one of the system configuration data entries associated with the
+ current sessions notifier keys. When a change is detected, an
+ empty (no data) mach message with the specified identifier will
+ be delivered to the calling application via the allocated port.
+
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param msgid Pass a mach message ID to be included with any notifications.
+ @param port Pass a pointer to a mach port. Upon return, port will be filled
+ with the mach port which will be used for any notifications.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierInformViaMachPort (SCDSessionRef session,
+ mach_msg_id_t msgid,
+ mach_port_t *port);
+
+/*!
+ @function SCDNotifierInformViaFD
+ @discussion Allocates a file descriptor which can be used to detect changes
+ to one of the system configuration data entries associated with the
+ current sessions notifier keys. When a change is detected, the
+ specified identifier (4 bytes) will be delivered to the calling
+ application via the allocated file descriptor.
+
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param identifier Pass an (4 byte) integer identifer which be used for any
+ notifications.
+ @param fd Pass a pointer to a file descriptor. Upon return, fd will be filled
+ with the file descriptor which will be used for any notifications.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierInformViaFD (SCDSessionRef session,
+ int32_t identifier,
+ int *fd);
+
+/*!
+ @function SCDNotifierInformViaSignal
+ @discussion Requests that the specified BSD signal be sent to the process
+ with the indicated process id whenever a change has been detected
+ to one of the system configuration data entries associated with the
+ current sessions notifier keys.
+
+ Note: this function is not valid for "configd" plug-ins.
+
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @param pid Pass a UNIX proces ID which should be signalled for any notifications.
+ @param sig Pass a signal number to be used.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierInformViaSignal (SCDSessionRef session,
+ pid_t pid,
+ int sig);
+
+/*!
+ @function SCDNotifierCancel
+ @discussion Cancels all outstanding notification delivery request for this
+ session.
+
+ @param session Pass a SCDSessionRef handle which should be used for
+ communication with the server.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDNotifierCancel (SCDSessionRef session);
+
+/*!
+ @function SCDOptionGet
+ @discussion Returns the value associated with the specified option.
+ @param session Pass a SCDSessionRef handle of the option of interest (or
+ NULL for the global option setting).
+ @param option Pass the SCDOption of interest.
+ @result The current value of the specified option.
+ */
+int SCDOptionGet (SCDSessionRef session,
+ int option);
+
+/*!
+ @function SCDOptionSet
+ @discussion Sets the value associated with the specified option.
+ @param session Pass a SCDSessionRef handle for the option to be set (or
+ NULL for the global option settings).
+ @param option Pass the SCDOption to be updated.
+ @param value Pass the new value for the option.
+ @result The current value of the specified option.
+ */
+void SCDOptionSet (SCDSessionRef session,
+ int option,
+ int value);
+
+/*!
+ @function SCDSessionLog
+ @discussion Issues a log and/or debug message.
+ @param session Pass a SCDSessionRef handle for the current session..
+ @param level Pass a syslog(3) logging priority.
+
+ Note: LOG_DEBUG messages will not be issued if the verbose option has not been enabled.
+ @param formatString Pass the CF format string
+ @result The specified message will be logged.
+ */
+void SCDSessionLog (SCDSessionRef session,
+ int level,
+ CFStringRef formatString,
+ ...);
+
+/*!
+ @function SCDLog
+ @discussion Issues a log and/or debug message.
+ @param level Pass a syslog(3) logging priority.
+ @param formatString Pass the CF format string
+ @result The specified message will be logged.
+ */
+void SCDLog (int level,
+ CFStringRef formatString,
+ ...);
+
+const char * SCDError (SCDStatus status);
+
+__END_DECLS
+
+#endif /* _SCD_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDAdd(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlKey; /* serialized key */
+ xmlData_t myKeyRef;
+ CFIndex myKeyLen;
+ CFDataRef xmlData; /* serialized data */
+ xmlData_t myDataRef;
+ CFIndex myDataLen;
+ int newInstance;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDAdd:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" data = %@"), SCDHandleGetData(handle));
+
+ if (key == NULL) {
+ return SCD_INVALIDARGUMENT; /* no key specified */
+ }
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /* serialize the key and data */
+ xmlKey = CFPropertyListCreateXMLData(NULL, key);
+ myKeyRef = (xmlData_t)CFDataGetBytePtr(xmlKey);
+ myKeyLen = CFDataGetLength(xmlKey);
+
+ xmlData = CFPropertyListCreateXMLData(NULL, SCDHandleGetData(handle));
+ myDataRef = (xmlData_t)CFDataGetBytePtr(xmlData);
+ myDataLen = CFDataGetLength(xmlData);
+
+ /* send the key & data to the server */
+ status = configadd(sessionPrivate->server,
+ myKeyRef,
+ myKeyLen,
+ myDataRef,
+ myDataLen,
+ &newInstance,
+ (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlKey);
+ CFRelease(xmlData);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configadd(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ if (scd_status == SCD_OK) {
+ _SCDHandleSetInstance(handle, newInstance);
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR(" new instance = %d"), SCDHandleGetInstance(handle));
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDAddSession(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlKey; /* serialized key */
+ xmlData_t myKeyRef;
+ CFIndex myKeyLen;
+ CFDataRef xmlData; /* serialized data */
+ xmlData_t myDataRef;
+ CFIndex myDataLen;
+ int newInstance;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDAddSession:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" data = %@"), SCDHandleGetData(handle));
+
+ if (key == NULL) {
+ return SCD_INVALIDARGUMENT; /* no key specified */
+ }
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /* serialize the key and data */
+ xmlKey = CFPropertyListCreateXMLData(NULL, key);
+ myKeyRef = (xmlData_t)CFDataGetBytePtr(xmlKey);
+ myKeyLen = CFDataGetLength(xmlKey);
+
+ xmlData = CFPropertyListCreateXMLData(NULL, SCDHandleGetData(handle));
+ myDataRef = (xmlData_t)CFDataGetBytePtr(xmlData);
+ myDataLen = CFDataGetLength(xmlData);
+
+ /* send the key & data to the server */
+ status = configadd_s(sessionPrivate->server,
+ myKeyRef,
+ myKeyLen,
+ myDataRef,
+ myDataLen,
+ &newInstance,
+ (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlKey);
+ CFRelease(xmlData);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configadd_s(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ if (scd_status == SCD_OK) {
+ _SCDHandleSetInstance(handle, newInstance);
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR(" new instance = %d"), SCDHandleGetInstance(handle));
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDClose(SCDSessionRef *session)
+{
+ SCDSessionPrivateRef sessionPrivate;
+ int oldThreadState;
+ kern_return_t status;
+ SCDStatus scd_status;
+ CFIndex keyCnt;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDClose:"));
+
+ if ((session == NULL) || (*session == NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCDSessionPrivateRef)*session;
+
+ (void) pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, &oldThreadState);
+
+ scd_status = (sessionPrivate->server == MACH_PORT_NULL) ? SCD_NOSESSION : SCD_OK;
+
+ /* Remove notification keys */
+ if ((keyCnt = CFSetGetCount(sessionPrivate->keys)) > 0) {
+ void **watchedKeys;
+ CFArrayRef keysToRemove;
+ CFIndex i;
+
+ watchedKeys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
+ CFSetGetValues(sessionPrivate->keys, watchedKeys);
+ keysToRemove = CFArrayCreate(NULL, watchedKeys, keyCnt, &kCFTypeArrayCallBacks);
+ CFAllocatorDeallocate(NULL, watchedKeys);
+ for (i=0; i<keyCnt; i++) {
+ if (scd_status == SCD_OK) {
+ scd_status = SCDNotifierRemove(*session,
+ CFArrayGetValueAtIndex(keysToRemove, i),
+ 0);
+ }
+ }
+ CFRelease(keysToRemove);
+ }
+
+ /* Remove regex notification keys */
+ if ((keyCnt = CFSetGetCount(sessionPrivate->reKeys)) > 0) {
+ void **watchedKeys;
+ CFArrayRef keysToRemove;
+ CFIndex i;
+
+ watchedKeys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
+ CFSetGetValues(sessionPrivate->reKeys, watchedKeys);
+ keysToRemove = CFArrayCreate(NULL, watchedKeys, keyCnt, &kCFTypeArrayCallBacks);
+ CFAllocatorDeallocate(NULL, watchedKeys);
+ for (i=0; i<keyCnt; i++) {
+ if (scd_status == SCD_OK) {
+ scd_status = SCDNotifierRemove(*session,
+ CFArrayGetValueAtIndex(keysToRemove, i),
+ kSCDRegexKey);
+ }
+ }
+ CFRelease(keysToRemove);
+ }
+
+ /* Remove/cancel any outstanding notification requests. */
+ (void) SCDNotifierCancel(*session);
+
+ if (SCDOptionGet(*session, kSCDOptionIsLocked) && (scd_status == SCD_OK)) {
+ scd_status = SCDUnlock(*session); /* release the lock */
+ }
+
+ if (scd_status == SCD_OK) {
+ status = configclose(sessionPrivate->server, (int *)&scd_status);
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configclose(): %s"), mach_error_string(status));
+ scd_status = SCD_NOSERVER;
+ }
+
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ }
+
+ CFAllocatorDeallocate(NULL, sessionPrivate);
+ *session = NULL;
+
+ (void) pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &oldThreadState);
+ pthread_testcancel();
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SystemConfiguration.h>
+
+
+CFStringRef
+SCDKeyCreateConsoleUser()
+{
+ return SCDKeyCreate(CFSTR("%@/%@/%@"),
+ CFSTR("state:"), // FIXME!!! (should be kSCCacheDomainState)
+ kSCCompUsers,
+ kSCEntUsersConsoleUser);
+}
+
+
+SCDStatus
+SCDConsoleUserGet(char *user, int userlen, uid_t *uid, gid_t *gid)
+{
+ CFDictionaryRef dict;
+ SCDHandleRef handle = NULL;
+ CFStringRef key;
+ SCDSessionRef session = NULL;
+ SCDStatus status;
+
+ /* get current user */
+ status = SCDOpen(&session, CFSTR("SCDConsoleUserGet"));
+ if (status != SCD_OK) {
+ goto done;
+ }
+
+ key = SCDKeyCreateConsoleUser();
+ status = SCDGet(session, key, &handle);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ goto done;
+ }
+
+ dict = SCDHandleGetData(handle);
+
+ if (user && (userlen > 0)) {
+ CFStringRef consoleUser;
+
+ bzero(user, userlen);
+ if (CFDictionaryGetValueIfPresent(dict,
+ kSCPropUsersConsoleUserName,
+ (void **)&consoleUser)) {
+ CFIndex len;
+ CFRange range;
+
+ range = CFRangeMake(0, CFStringGetLength(consoleUser));
+ (void)CFStringGetBytes(consoleUser,
+ range,
+ kCFStringEncodingMacRoman,
+ 0,
+ FALSE,
+ user,
+ userlen,
+ &len);
+ }
+ }
+
+ if (uid) {
+ CFNumberRef num;
+ SInt32 val;
+
+ if (CFDictionaryGetValueIfPresent(dict,
+ kSCPropUsersConsoleUserUID,
+ (void **)&num)) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) {
+ *uid = (uid_t)val;
+ }
+ }
+ }
+
+ if (gid) {
+ CFNumberRef num;
+ SInt32 val;
+
+ if (CFDictionaryGetValueIfPresent(dict,
+ kSCPropUsersConsoleUserGID,
+ (void **)&num)) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val)) {
+ *gid = (gid_t)val;
+ }
+ }
+ }
+
+ done :
+
+ if (handle) SCDHandleRelease(handle);
+ if (session) (void) SCDClose(&session);
+ return status;
+}
+
+
+SCDStatus
+SCDConsoleUserSet(const char *user, uid_t uid, gid_t gid)
+{
+ CFStringRef consoleUser;
+ CFMutableDictionaryRef dict = NULL;
+ SCDHandleRef handle = NULL;
+ CFStringRef key = SCDKeyCreateConsoleUser();
+ CFNumberRef num;
+ SCDSessionRef session = NULL;
+ SCDStatus status;
+
+ status = SCDOpen(&session, CFSTR("SCDConsoleUserSet"));
+ if (status != SCD_OK) {
+ goto done;
+ }
+
+ if (user == NULL) {
+ (void)SCDRemove(session, key);
+ goto done;
+ }
+
+ dict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ consoleUser = CFStringCreateWithCString(NULL, user, kCFStringEncodingMacRoman);
+ CFDictionarySetValue(dict, kSCPropUsersConsoleUserName, consoleUser);
+ CFRelease(consoleUser);
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, (SInt32 *)&uid);
+ CFDictionarySetValue(dict, kSCPropUsersConsoleUserUID, num);
+ CFRelease(num);
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, (SInt32 *)&gid);
+ CFDictionarySetValue(dict, kSCPropUsersConsoleUserGID, num);
+ CFRelease(num);
+
+ handle = SCDHandleInit();
+ SCDHandleSetData(handle, dict);
+
+ status = SCDLock(session);
+ if (status != SCD_OK) {
+ goto done;
+ }
+ (void)SCDRemove(session, key);
+ (void)SCDAdd (session, key, handle);
+ status = SCDUnlock(session);
+
+ done :
+
+ if (dict) CFRelease(dict);
+ if (handle) SCDHandleRelease(handle);
+ if (key) CFRelease(key);
+ if (session) (void) SCDClose(&session);
+ return status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCDCONSOLEUSER_H
+#define _SCDCONSOLEUSER_H
+
+#include <sys/cdefs.h>
+
+/*!
+ @header SCDConsoleUser.h
+ The SystemConfiguration framework provides access to the data used
+ to configure a running system.
+
+ Specifically, the SCDConsoleUserXXX() API's allow an application
+ to determine (or set) the login/user currently using the
+ console.
+
+ The APIs provided by this framework communicate with the "configd"
+ daemon to obtain information regarding the systems current
+ configuration.
+ */
+
+
+__BEGIN_DECLS
+
+/*!
+ @function SCDKeyCreateConsoleUser
+ @discussion Creates a key which can be used by the SCDNotifierAdd()
+ function to receive notifications when the current "Console"
+ user changes.
+ @result A notification string for the current "Console" user.
+*/
+CFStringRef SCDKeyCreateConsoleUser ();
+
+/*!
+ @function SCDConsoleUserGet
+ @discussion Gets the name, user ID, and group ID of the currently
+ logged in user.
+ @param user A pointer to a character buffer of at least size
+ userlen. The returned name is null-terminated unless
+ in-sufficient space is provided.If NULL, this value
+ will not be returned.
+ @param userlen Pass an integer specifying the maximum size of the
+ user buffer.
+ @param uid A pointer to memory which will be filled with the user ID
+ of the current "Console" user. If NULL, this value will not
+ be returned.
+ @param gid A pointer to memory which will be filled with the group ID
+ of the current "Console" user. If NULL, this value will not be
+ returned.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDConsoleUserGet (char *user,
+ int userlen,
+ uid_t *uid,
+ gid_t *gid);
+
+/*!
+ @function SCDConsoleUserSet
+ @discussion Sets the name, user ID, and group ID of the currently
+ logged in user.
+ @param user A pointer to a character buffer containing the name of
+ the current "Console" user. If NULL, any current "Console"
+ user information will be reset.
+ @param uid The user ID of the current "Console" user.
+ @param gid The group ID of the current "Console" user.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDConsoleUserSet (const char *user,
+ uid_t uid,
+ gid_t gid);
+
+__END_DECLS
+
+#endif /* _SCDCONSOLEUSER_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDGet(SCDSessionRef session, CFStringRef key, SCDHandleRef *handle)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlKey; /* key (XML serialized) */
+ xmlData_t myKeyRef; /* key (serialized) */
+ CFIndex myKeyLen;
+ xmlDataOut_t xmlDataRef; /* data (serialized) */
+ CFIndex xmlDataLen;
+ CFDataRef xmlData; /* data (XML serialized) */
+ CFPropertyListRef data; /* data (un-serialized) */
+ int newInstance;
+ SCDStatus scd_status;
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDGet:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+
+ if (key == NULL) {
+ return SCD_INVALIDARGUMENT; /* no key specified */
+ }
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION;
+ }
+
+ /* serialize the key */
+ xmlKey = CFPropertyListCreateXMLData(NULL, key);
+ myKeyRef = (xmlData_t)CFDataGetBytePtr(xmlKey);
+ myKeyLen = CFDataGetLength(xmlKey);
+
+ /* send the key & fetch the associated data from the server */
+ status = configget(sessionPrivate->server,
+ myKeyRef,
+ myKeyLen,
+ &xmlDataRef,
+ (int *)&xmlDataLen,
+ &newInstance,
+ (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlKey);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configget(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ if (scd_status != SCD_OK) {
+ status = vm_deallocate(mach_task_self(), (vm_address_t)xmlDataRef, xmlDataLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ *handle = NULL;
+ return scd_status;
+ }
+
+ /* un-serialize the data, return a handle associated with the key */
+ *handle = SCDHandleInit();
+ xmlData = CFDataCreate(NULL, xmlDataRef, xmlDataLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)xmlDataRef, xmlDataLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ data = CFPropertyListCreateFromXMLData(NULL,
+ xmlData,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlData);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() data: %s"), xmlError);
+ SCDHandleRelease(*handle);
+ return SCD_FAILED;
+ }
+ SCDHandleSetData(*handle, data);
+ CFRelease(data);
+
+ _SCDHandleSetInstance(*handle, newInstance);
+
+ SCDLog(LOG_DEBUG, CFSTR(" data = %@"), SCDHandleGetData(*handle));
+ SCDLog(LOG_DEBUG, CFSTR(" instance = %d"), SCDHandleGetInstance(*handle));
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCD.h>
+#include "SCDPrivate.h"
+
+
+SCDHandleRef
+SCDHandleInit()
+{
+ SCDHandlePrivateRef privateHandle = CFAllocatorAllocate(NULL, sizeof(SCDHandlePrivate), 0);
+
+ /* set data */
+ privateHandle->data = NULL;
+
+ /* set instance */
+ privateHandle->instance = 0;
+
+ return (SCDHandleRef)privateHandle;
+}
+
+
+void
+SCDHandleRelease(SCDHandleRef handle)
+{
+ SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
+
+ if (privateHandle->data)
+ CFRelease(privateHandle->data);
+
+ CFAllocatorDeallocate(NULL, privateHandle);
+ return;
+}
+
+
+int
+SCDHandleGetInstance(SCDHandleRef handle)
+{
+ SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
+
+ return privateHandle->instance;
+}
+
+
+void
+_SCDHandleSetInstance(SCDHandleRef handle, int instance)
+{
+ SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
+
+ privateHandle->instance = instance;
+ return;
+}
+
+
+CFPropertyListRef
+SCDHandleGetData(SCDHandleRef handle)
+{
+ SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
+
+ if (privateHandle->data == NULL) {
+ return CFSTR("SCDHandleRef not initialized.");
+ }
+
+ return privateHandle->data;
+}
+
+
+void
+SCDHandleSetData(SCDHandleRef handle, CFPropertyListRef data)
+{
+ SCDHandlePrivateRef privateHandle = (SCDHandlePrivateRef)handle;
+
+ /* remove reference to data previously associated with handle */
+ if (privateHandle->data)
+ CFRelease(privateHandle->data);
+
+ /* associate new data with handle, keep a reference as needed */
+ privateHandle->data = data;
+ if (privateHandle->data)
+ CFRetain(privateHandle->data);
+
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SystemConfiguration.h>
+
+
+CFStringRef
+SCDKeyCreateHostName()
+{
+ return SCDKeyCreate(CFSTR("%@/%@"),
+ kSCCacheDomainSetup,
+ kSCCompSystem);
+}
+
+
+SCDStatus
+SCDHostNameGet(CFStringRef *name, CFStringEncoding *nameEncoding)
+{
+ CFDictionaryRef dict;
+ SCDHandleRef handle = NULL;
+ CFStringRef key;
+ SCDSessionRef session = NULL;
+ SCDStatus status;
+
+ if (name == NULL) {
+ return SCD_FAILED;
+ }
+
+ /* get current user */
+ status = SCDOpen(&session, CFSTR("SCDHostNameGet"));
+ if (status != SCD_OK) {
+ goto done;
+ }
+
+ key = SCDKeyCreateHostName();
+ status = SCDGet(session, key, &handle);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ goto done;
+ }
+
+ dict = SCDHandleGetData(handle);
+
+ *name = CFDictionaryGetValue(dict, kSCPropSystemComputerName);
+ if (*name == NULL) {
+ goto done;
+ }
+ CFRetain(*name);
+
+ if (nameEncoding) {
+ CFNumberRef num;
+
+ num = CFDictionaryGetValue(dict,
+ kSCPropSystemComputerNameEncoding);
+ if (num) {
+ CFNumberGetValue(num, kCFNumberIntType, nameEncoding);
+ } else {
+ *nameEncoding = CFStringGetSystemEncoding();
+ }
+ }
+
+ done :
+
+ if (handle) SCDHandleRelease(handle);
+ if (session) (void) SCDClose(&session);
+ return status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCDHOSTNAME_H
+#define _SCDHOSTNAME_H
+
+#include <sys/cdefs.h>
+
+/*!
+ @header SCDHostName.h
+ The SystemConfiguration framework provides access to the data used
+ to configure a running system.
+
+ Specifically, the SCDHostNameXXX() API's allow an application
+ to determine (or set) the login/user currently using the
+ console.
+
+ The APIs provided by this framework communicate with the "configd"
+ daemon to obtain information regarding the systems current
+ configuration.
+ */
+
+
+__BEGIN_DECLS
+
+/*!
+ @function SCDKeyCreateHostName
+ @discussion Creates a key which can be used by the SCDNotifierAdd()
+ function to receive notifications when the current
+ computer/host name changes.
+ @result A notification string for the current computer/host name".
+*/
+CFStringRef SCDKeyCreateHostName ();
+
+/*!
+ @function SCDHostNameGet
+ @discussion Gets the current computer/host name.
+ @param name A pointer to memory which will be filled with the current
+ computer/host name.
+ @param nameEncoding A pointer to memory which, if non-NULL, will be
+ filled with the encoding associated with the computer/host name.
+ @result A constant of type SCDStatus indicating the success (or failure) of
+ the call.
+ */
+SCDStatus SCDHostNameGet (CFStringRef *name,
+ CFStringEncoding *nameEncoding);
+
+__END_DECLS
+
+#endif /* _SCDHOSTNAME_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include <stdarg.h>
+
+/*
+ * SCDKeyCreate*
+ * - convenience routines that create a CFString key for an item in the cache
+ */
+
+/*
+ * Function: SCDKeyCreate
+ * Purpose:
+ * Creates a cache key using the given format.
+ */
+CFStringRef
+SCDKeyCreate(CFStringRef fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ return (CFStringCreateWithFormatAndArguments(NULL,
+ NULL,
+ fmt,
+ args));
+}
+
+CFStringRef
+SCDKeyCreateNetworkGlobalEntity(CFStringRef domain, CFStringRef entity)
+{
+ return (CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@/%@/%@/%@"),
+ domain,
+ kSCCompNetwork,
+ kSCCompGlobal,
+ entity));
+}
+
+CFStringRef
+SCDKeyCreateNetworkInterface(CFStringRef domain)
+{
+ return (CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@/%@/%@"),
+ domain,
+ kSCCompNetwork,
+ kSCCompInterface));
+}
+
+CFStringRef
+SCDKeyCreateNetworkInterfaceEntity(CFStringRef domain,
+ CFStringRef ifname,
+ CFStringRef entity)
+{
+ if (entity == NULL) {
+ return (CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@/%@/%@/%@"),
+ domain,
+ kSCCompNetwork,
+ kSCCompInterface,
+ ifname));
+ } else {
+ return (CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@/%@/%@/%@/%@"),
+ domain,
+ kSCCompNetwork,
+ kSCCompInterface,
+ ifname,
+ entity));
+ }
+}
+
+CFStringRef
+SCDKeyCreateNetworkServiceEntity(CFStringRef domain,
+ CFStringRef serviceID,
+ CFStringRef entity)
+{
+ if (entity == NULL) {
+ return (CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@/%@/%@/%@"),
+ domain,
+ kSCCompNetwork,
+ kSCCompService,
+ serviceID));
+ } else {
+ return (CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@/%@/%@/%@/%@"),
+ domain,
+ kSCCompNetwork,
+ kSCCompService,
+ serviceID,
+ entity));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * SCDKeys.h
+ */
+
+#ifndef _SCDKEYS_H
+#define _SCDKEYS_H
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+/*
+ * SCDKeyCreate*
+ * - convenience routines that create a CFString key for an item in the cache
+ */
+
+/*
+ * Function: SCDKeyCreate
+ * Purpose:
+ * Creates a cache key using the given format.
+ */
+CFStringRef SCDKeyCreate (CFStringRef fmt,
+ ...);
+
+CFStringRef SCDKeyCreateNetworkGlobalEntity (CFStringRef domain,
+ CFStringRef entity);
+
+CFStringRef SCDKeyCreateNetworkInterface (CFStringRef domain);
+
+CFStringRef SCDKeyCreateNetworkInterfaceEntity (CFStringRef domain,
+ CFStringRef ifname,
+ CFStringRef entity);
+
+CFStringRef SCDKeyCreateNetworkServiceEntity (CFStringRef domain,
+ CFStringRef serviceID,
+ CFStringRef entity);
+
+__END_DECLS
+
+#endif /* _SCDKEYS_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <regex.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+static CFComparisonResult
+sort_keys(const void *p1, const void *p2, void *context) {
+ CFStringRef key1 = (CFStringRef)p1;
+ CFStringRef key2 = (CFStringRef)p2;
+ return CFStringCompare(key1, key2, 0);
+}
+
+
+SCDStatus
+SCDList(SCDSessionRef session, CFStringRef key, int regexOptions, CFArrayRef *subKeys)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlKey; /* serialized key */
+ xmlData_t myKeyRef;
+ CFIndex myKeyLen;
+ CFDataRef xmlData; /* data (XML serialized) */
+ xmlDataOut_t xmlDataRef; /* serialized data */
+ int xmlDataLen;
+ SCDStatus scd_status;
+ CFArrayRef allKeys;
+ CFMutableArrayRef sortedKeys;
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDList:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" regexOptions = %0o"), regexOptions);
+
+ if (key == NULL) {
+ return SCD_INVALIDARGUMENT; /* no key specified */
+ }
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION;
+ }
+
+ /* serialize the key */
+ xmlKey = CFPropertyListCreateXMLData(NULL, key);
+ myKeyRef = (xmlData_t)CFDataGetBytePtr(xmlKey);
+ myKeyLen = CFDataGetLength(xmlKey);
+
+ /* send the key & fetch the associated data from the server */
+ status = configlist(sessionPrivate->server,
+ myKeyRef,
+ myKeyLen,
+ regexOptions,
+ &xmlDataRef,
+ &xmlDataLen,
+ (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlKey);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configlist(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ if (scd_status != SCD_OK) {
+ status = vm_deallocate(mach_task_self(), (vm_address_t)xmlDataRef, xmlDataLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ *subKeys = NULL;
+ return scd_status;
+ }
+
+ /* un-serialize the list of keys */
+ xmlData = CFDataCreate(NULL, xmlDataRef, xmlDataLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)xmlDataRef, xmlDataLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ allKeys = CFPropertyListCreateFromXMLData(NULL,
+ xmlData,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlData);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() list: %s"), xmlError);
+ return SCD_FAILED;
+ }
+
+ myKeyLen = CFArrayGetCount(allKeys);
+ sortedKeys = CFArrayCreateMutableCopy(NULL, myKeyLen, allKeys);
+ CFRelease(allKeys);
+ CFArraySortValues(sortedKeys,
+ CFRangeMake(0, myKeyLen),
+ sort_keys,
+ NULL);
+
+ *subKeys = sortedKeys;
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDLock(SCDSessionRef session)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDLock:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ /* get the lock from the server */
+ status = configlock(sessionPrivate->server, (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configlock(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <regex.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDNotifierAdd(SCDSessionRef session, CFStringRef key, int regexOptions)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlKey; /* serialized key */
+ xmlData_t myKeyRef;
+ CFIndex myKeyLen;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierAdd:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" regexOptions = %0o"), regexOptions);
+
+ if (key == NULL) {
+ return SCD_INVALIDARGUMENT; /* no key specified */
+ }
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /*
+ * add new key after checking if key has already been defined
+ */
+ if (regexOptions & kSCDRegexKey) {
+ if (CFSetContainsValue(sessionPrivate->reKeys, key))
+ return SCD_EXISTS; /* sorry, key already exists in notifier list */
+ CFSetAddValue(sessionPrivate->reKeys, key); /* add key to this sessions notifier list */
+ } else {
+ if (CFSetContainsValue(sessionPrivate->keys, key))
+ return SCD_EXISTS; /* sorry, key already exists in notifier list */
+ CFSetAddValue(sessionPrivate->keys, key); /* add key to this sessions notifier list */
+ }
+
+ /* serialize the key */
+ xmlKey = CFPropertyListCreateXMLData(NULL, key);
+ myKeyRef = (xmlData_t)CFDataGetBytePtr(xmlKey);
+ myKeyLen = CFDataGetLength(xmlKey);
+
+ /* send the key & data to the server */
+ status = notifyadd(sessionPrivate->server,
+ myKeyRef,
+ myKeyLen,
+ regexOptions,
+ (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlKey);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifyadd(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDNotifierCancel(SCDSessionRef session)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierCancel:"));
+
+ if (session == NULL) {
+ return SCD_NOSESSION; /* you can't do anything without a session */
+ }
+
+ if (sessionPrivate->notifyStatus == NotifierNotRegistered) {
+ /* nothing to do, no notifications have been registered */
+ return SCD_OK;
+ }
+
+ /* if SCDNotifierInformViaCallback() active, stop the background thread */
+ if (sessionPrivate->callbackFunction != NULL) {
+
+ if (SCDOptionGet(session, kSCDOptionUseCFRunLoop)) {
+ SCDLog(LOG_DEBUG, CFSTR(" cancel callback runloop source"));
+
+ /* XXX invalidating the port is not sufficient, remove the run loop source */
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
+ sessionPrivate->callbackRunLoopSource,
+ kCFRunLoopDefaultMode);
+ CFRelease(sessionPrivate->callbackRunLoopSource);
+
+ /* invalidate port */
+ CFMachPortInvalidate(sessionPrivate->callbackPort);
+ CFRelease(sessionPrivate->callbackPort);
+ } else {
+ int ts;
+
+ SCDLog(LOG_DEBUG, CFSTR(" cancel callback thread"));
+ ts = pthread_cancel(sessionPrivate->callbackHelper);
+ if (ts != 0) {
+ SCDLog(LOG_DEBUG, CFSTR(" pthread_cancel(): %s"), strerror(ts));
+ }
+ }
+
+ sessionPrivate->callbackFunction = NULL;
+ sessionPrivate->callbackArgument = NULL;
+ sessionPrivate->callbackPort = NULL;
+ sessionPrivate->callbackRunLoopSource = NULL; /* XXX */
+ sessionPrivate->callbackHelper = NULL;
+ }
+
+ if (sessionPrivate->server == MACH_PORT_NULL) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ status = notifycancel(sessionPrivate->server, (int *)&scd_status);
+
+ /* set notifier inactive */
+ sessionPrivate->notifyStatus = NotifierNotRegistered;
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifycancel(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+static CFComparisonResult
+sort_keys(const void *p1, const void *p2, void *context) {
+ CFStringRef key1 = (CFStringRef)p1;
+ CFStringRef key2 = (CFStringRef)p2;
+ return CFStringCompare(key1, key2, 0);
+}
+
+
+SCDStatus
+SCDNotifierGetChanges(SCDSessionRef session, CFArrayRef *notifierKeys)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlData; /* data (XML serialized) */
+ xmlDataOut_t xmlDataRef; /* serialized data */
+ int xmlDataLen;
+ SCDStatus scd_status;
+ CFArrayRef allKeys;
+ CFStringRef xmlError;
+ CFIndex keyCnt;
+ CFMutableArrayRef sortedKeys;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierGetChanges:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION;
+ }
+
+ /* send the key & fetch the associated data from the server */
+ status = notifychanges(sessionPrivate->server,
+ &xmlDataRef,
+ &xmlDataLen,
+ (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifychanges(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ if (scd_status != SCD_OK) {
+ status = vm_deallocate(mach_task_self(), (vm_address_t)xmlDataRef, xmlDataLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ *notifierKeys = NULL;
+ return scd_status;
+ }
+
+ /* un-serialize the list of keys which have changed */
+ xmlData = CFDataCreate(NULL, xmlDataRef, xmlDataLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)xmlDataRef, xmlDataLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ allKeys = CFPropertyListCreateFromXMLData(NULL,
+ xmlData,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlData);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() list: %s"), xmlError);
+ return SCD_FAILED;
+ }
+
+ keyCnt = CFArrayGetCount(allKeys);
+ sortedKeys = CFArrayCreateMutableCopy(NULL, keyCnt, allKeys);
+ CFRelease(allKeys);
+ CFArraySortValues(sortedKeys,
+ CFRangeMake(0, keyCnt),
+ sort_keys,
+ NULL);
+
+ *notifierKeys = sortedKeys;
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+static void
+informCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
+{
+ SCDSessionRef session = (SCDSessionRef)info;
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ mach_msg_empty_rcv_t *buf = msg;
+ mach_msg_id_t msgid = buf->header.msgh_id;
+ SCDCallbackRoutine_t cbFunc = sessionPrivate->callbackFunction;
+ void *cbArg = sessionPrivate->callbackArgument;
+
+ if (msgid == MACH_NOTIFY_NO_SENDERS) {
+ /* the server died, disable additional callbacks */
+ SCDLog(LOG_DEBUG, CFSTR(" notifier port closed, disabling notifier"));
+ } else if (cbFunc == NULL) {
+ /* there is no (longer) a callback function, disable additional callbacks */
+ SCDLog(LOG_DEBUG, CFSTR(" no callback function, disabling notifier"));
+ } else {
+ SCDLog(LOG_DEBUG, CFSTR(" executing notifiction function"));
+ if ((*cbFunc)(session, cbArg)) {
+ /*
+ * callback function returned success.
+ */
+ return;
+ } else {
+ SCDLog(LOG_DEBUG, CFSTR(" callback returned error, disabling notifier"));
+ }
+ }
+
+#ifdef DEBUG
+ if (port != sessionPrivate->callbackPort) {
+ SCDLog(LOG_DEBUG, CFSTR("informCallback, why is port != callbackPort?"));
+ }
+#endif /* DEBUG */
+
+ /* we have encountered some type of error, disable additional callbacks */
+
+ /* XXX invalidating the port is not sufficient, remove the run loop source */
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
+ sessionPrivate->callbackRunLoopSource,
+ kCFRunLoopDefaultMode);
+ CFRelease(sessionPrivate->callbackRunLoopSource);
+
+ /* invalidate port */
+ CFMachPortInvalidate(port);
+ CFRelease(port);
+
+ sessionPrivate->notifyStatus = NotifierNotRegistered;
+ sessionPrivate->callbackFunction = NULL;
+ sessionPrivate->callbackArgument = NULL;
+ sessionPrivate->callbackPort = NULL;
+ sessionPrivate->callbackRunLoopSource = NULL; /* XXX */
+
+ return;
+}
+
+
+static void
+cleanupMachPort(void *ptr)
+{
+ mach_port_t *port = (mach_port_t *)ptr;
+
+ SCDLog(LOG_DEBUG, CFSTR(" cleaning up notification port %d"), *port);
+ if (*port != MACH_PORT_NULL) {
+ (void) mach_port_destroy(mach_task_self(), *port);
+ free(port);
+ }
+
+ return;
+}
+
+
+static void *
+watcherThread(void *arg)
+{
+ SCDSessionRef session = (SCDSessionRef)arg;
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ SCDCallbackRoutine_t cbFunc = sessionPrivate->callbackFunction;
+ void *cbArg = sessionPrivate->callbackArgument;
+ mach_port_t *port = malloc(sizeof(mach_port_t));
+
+ *port = CFMachPortGetPort(sessionPrivate->callbackPort);
+ pthread_cleanup_push(cleanupMachPort, (void *)port);
+
+ while (TRUE) {
+ mach_msg_id_t msgid;
+
+ SCDLog(LOG_DEBUG, CFSTR("Callback thread waiting, port=%d, tid=0x%08x"),
+ *port, pthread_self());
+
+ msgid = _waitForMachMessage(*port);
+
+ if (msgid == MACH_NOTIFY_NO_SENDERS) {
+ /* the server closed the notifier port, disable additional callbacks */
+ SCDLog(LOG_DEBUG, CFSTR(" notifier port closed, disabling notifier"));
+ break;
+ }
+
+ if (msgid == -1) {
+ mach_port_type_t pt;
+
+ /* an error was detected, disable additional callbacks */
+ SCDLog(LOG_DEBUG, CFSTR(" server failure, disabling notifier"));
+
+ /* check if the server connection is not valid, close if necessary */
+ if ((mach_port_type(mach_task_self(), sessionPrivate->server, &pt) == KERN_SUCCESS) &&
+ (pt & MACH_PORT_TYPE_DEAD_NAME)) {
+ SCDLog(LOG_DEBUG, CFSTR(" server process died, destroying (dead) port"));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ }
+ break;
+ }
+
+ if (cbFunc == NULL) {
+ /* there is no (longer) a callback function, disable additional callbacks */
+ SCDLog(LOG_DEBUG, CFSTR(" no callback function, disabling notifier"));
+ break;
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR(" executing notifiction function"));
+
+ if (!(*cbFunc)(session, cbArg)) {
+ /*
+ * callback function returned an error, exit the thread
+ */
+ break;
+ }
+
+ }
+
+ /*
+ * pop the cleanup routine for the "port" mach port. We end up calling
+ * mach_port_destroy() in the process.
+ */
+ pthread_cleanup_pop(1);
+
+ pthread_exit (NULL);
+ return NULL;
+}
+
+
+SCDStatus
+SCDNotifierInformViaCallback(SCDSessionRef session, SCDCallbackRoutine_t func, void *arg)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ mach_port_t port;
+ mach_port_t oldNotify;
+ SCDStatus scd_status;
+ CFMachPortContext context = { 0, (void *)session, NULL, NULL, NULL };
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierInformViaCallback:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ if (sessionPrivate->notifyStatus != NotifierNotRegistered) {
+ /* sorry, you can only have one notification registered at once */
+ return SCD_NOTIFIERACTIVE;
+ }
+
+ if (func == NULL) {
+ /* sorry, you must specify a callback function */
+ return SCD_INVALIDARGUMENT;
+ }
+
+ /* Allocating port (for server response) */
+ sessionPrivate->callbackPort = CFMachPortCreate(NULL,
+ informCallback,
+ &context,
+ NULL);
+
+ /* Request a notification when/if the server dies */
+ port = CFMachPortGetPort(sessionPrivate->callbackPort);
+ status = mach_port_request_notification(mach_task_self(),
+ port,
+ MACH_NOTIFY_NO_SENDERS,
+ 1,
+ port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &oldNotify);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_request_notification(): %s"), mach_error_string(status));
+ CFMachPortInvalidate(sessionPrivate->callbackPort);
+ CFRelease(sessionPrivate->callbackPort);
+ return SCD_FAILED;
+ }
+
+#ifdef DEBUG
+ if (oldNotify != MACH_PORT_NULL) {
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierInformViaCallback(): why is oldNotify != MACH_PORT_NULL?"));
+ }
+#endif /* DEBUG */
+
+ /* Requesting notification via mach port */
+ status = notifyviaport(sessionPrivate->server,
+ port,
+ 0,
+ (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifyviaport(): %s"), mach_error_string(status));
+ CFMachPortInvalidate(sessionPrivate->callbackPort);
+ CFRelease(sessionPrivate->callbackPort);
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ if (scd_status != SCD_OK) {
+ return scd_status;
+ }
+
+ /* set notifier active */
+ sessionPrivate->notifyStatus = Using_NotifierInformViaCallback;
+ sessionPrivate->callbackFunction = func;
+ sessionPrivate->callbackArgument = arg;
+
+ if (SCDOptionGet(session, kSCDOptionUseCFRunLoop)) {
+ /* Creating/adding a run loop source for the port */
+ sessionPrivate->callbackRunLoopSource =
+ CFMachPortCreateRunLoopSource(NULL, sessionPrivate->callbackPort, 0);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(),
+ sessionPrivate->callbackRunLoopSource,
+ kCFRunLoopDefaultMode);
+ } else {
+ pthread_attr_t tattr;
+
+ SCDLog(LOG_DEBUG, CFSTR("Starting background thread to watch for notifications..."));
+ pthread_attr_init(&tattr);
+ pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
+ pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+ pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
+ pthread_create(&sessionPrivate->callbackHelper,
+ &tattr,
+ watcherThread,
+ (void *)session);
+ pthread_attr_destroy(&tattr);
+ SCDLog(LOG_DEBUG, CFSTR(" thread id=0x%08x"), sessionPrivate->callbackHelper);
+ }
+
+ return SCD_OK;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <paths.h>
+#include <unistd.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDNotifierInformViaFD(SCDSessionRef session,
+ int32_t identifier,
+ int *fd)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ SCDStatus scd_status;
+ struct sockaddr_un un;
+ int sock;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierInformViaFD:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ if (sessionPrivate->notifyStatus != NotifierNotRegistered) {
+ /* sorry, you can only have one notification registered at once */
+ return SCD_NOTIFIERACTIVE;
+ }
+
+ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ SCDLog(LOG_NOTICE, CFSTR("socket: %s"), strerror(errno));
+ return SCD_FAILED;
+ }
+
+ /* establish a UNIX domain socket for server->client notification */
+ bzero(&un, sizeof(un));
+ un.sun_family = AF_UNIX;
+ snprintf(un.sun_path,
+ sizeof(un.sun_path)-1,
+ "%s%s-%d",
+ _PATH_VARTMP,
+ "SCDNotifierInformViaFD",
+ sessionPrivate->server);
+
+ if (bind(sock, (struct sockaddr *)&un, sizeof(un)) == -1) {
+ SCDLog(LOG_NOTICE, CFSTR("bind: %s"), strerror(errno));
+ (void) close(sock);
+ return SCD_FAILED;
+ }
+
+ if (listen(sock, 0) == -1) {
+ SCDLog(LOG_NOTICE, CFSTR("listen: %s"), strerror(errno));
+ (void) close(sock);
+ return SCD_FAILED;
+ }
+
+ status = notifyviafd(sessionPrivate->server,
+ un.sun_path,
+ strlen(un.sun_path),
+ identifier,
+ (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifyviafd(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ *fd = accept(sock, 0, 0);
+ if (*fd == -1) {
+ SCDLog(LOG_NOTICE, CFSTR("accept: %s"), strerror(errno));
+ (void) close(sock);
+ return SCD_FAILED;
+ }
+ (void) close(sock);
+
+ /* set notifier active */
+ sessionPrivate->notifyStatus = Using_NotifierInformViaFD;
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDNotifierInformViaMachPort(SCDSessionRef session, mach_msg_id_t identifier, mach_port_t *port)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ mach_port_t oldNotify;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierInformViaMachPort:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ if (sessionPrivate->notifyStatus != NotifierNotRegistered) {
+ /* sorry, you can only have one notification registered at once */
+ return SCD_NOTIFIERACTIVE;
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR("Allocating port (for server response)"));
+ status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, port);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_allocate(): %s"), mach_error_string(status));
+ return SCD_FAILED;
+ }
+ SCDLog(LOG_DEBUG, CFSTR(" port = %d"), *port);
+
+ status = mach_port_insert_right(mach_task_self(),
+ *port,
+ *port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_insert_right(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), *port);
+ *port = MACH_PORT_NULL;
+ return SCD_FAILED;
+ }
+
+ /* Request a notification when/if the server dies */
+ status = mach_port_request_notification(mach_task_self(),
+ *port,
+ MACH_NOTIFY_NO_SENDERS,
+ 1,
+ *port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &oldNotify);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_request_notification(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), *port);
+ *port = MACH_PORT_NULL;
+ return SCD_FAILED;
+ }
+
+#ifdef DEBUG
+ if (oldNotify != MACH_PORT_NULL) {
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierInformViaMachPort(): why is oldNotify != MACH_PORT_NULL?"));
+ }
+#endif /* DEBUG */
+
+ status = notifyviaport(sessionPrivate->server,
+ *port,
+ identifier,
+ (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifyviaport(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), *port);
+ *port = MACH_PORT_NULL;
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ /* set notifier active */
+ sessionPrivate->notifyStatus = Using_NotifierInformViaMachPort;
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDNotifierInformViaSignal(SCDSessionRef session, pid_t pid, int sig)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+
+ kern_return_t status;
+ SCDStatus scd_status;
+ task_t task;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierInformViaSignal:"));
+ SCDLog(LOG_DEBUG, CFSTR(" pid = %d"), pid);
+ SCDLog(LOG_DEBUG, CFSTR(" sig = %d"), sig);
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ if (SCDOptionGet(NULL, kSCDOptionIsServer)) {
+ /* sorry, neither the server nor any plug-ins can "wait" */
+ return SCD_FAILED;
+ }
+
+ if (sessionPrivate->notifyStatus != NotifierNotRegistered) {
+ /* sorry, you can only have one notification registered at once */
+ return SCD_NOTIFIERACTIVE;
+ }
+
+ if ((sig <= 0) || (sig > NSIG)) {
+ /* sorry, you must specify a valid signal */
+ return SCD_INVALIDARGUMENT;
+ }
+
+ status = task_for_pid(mach_task_self(), pid, &task);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("task_for_pid(): %s"), mach_error_string(status));
+ return SCD_FAILED;
+ }
+
+ status = notifyviasignal(sessionPrivate->server, task, sig, (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifyviasignal(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ /* set notifier active */
+ sessionPrivate->notifyStatus = Using_NotifierInformViaSignal;
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+static CFComparisonResult
+sort_keys(const void *p1, const void *p2, void *context) {
+ CFStringRef key1 = (CFStringRef)p1;
+ CFStringRef key2 = (CFStringRef)p2;
+ return CFStringCompare(key1, key2, 0);
+}
+
+
+SCDStatus
+SCDNotifierList(SCDSessionRef session, int regexOptions, CFArrayRef *notifierKeys)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ CFIndex keyCnt;
+ void **keyRefs;
+ CFArrayRef keys;
+ CFMutableArrayRef sortedKeys;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierList:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION;
+ }
+
+ if (regexOptions & kSCDRegexKey) {
+ keyCnt = CFSetGetCount(sessionPrivate->reKeys);
+ keyRefs = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
+ CFSetGetValues(sessionPrivate->reKeys, keyRefs);
+ keys = CFArrayCreate(NULL, keyRefs, keyCnt, &kCFTypeArrayCallBacks);
+ CFAllocatorDeallocate(NULL, keyRefs);
+ } else {
+ keyCnt = CFSetGetCount(sessionPrivate->keys);
+ keyRefs = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
+ CFSetGetValues(sessionPrivate->keys, keyRefs);
+ keys = CFArrayCreate(NULL, keyRefs, keyCnt, &kCFTypeArrayCallBacks);
+ CFAllocatorDeallocate(NULL, keyRefs);
+ }
+
+ sortedKeys = CFArrayCreateMutableCopy(NULL, keyCnt, keys);
+ CFRelease(keys);
+ CFArraySortValues(sortedKeys, CFRangeMake(0, keyCnt), sort_keys, NULL);
+
+ *notifierKeys = sortedKeys;
+ return SCD_OK;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <regex.h>
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDNotifierRemove(SCDSessionRef session, CFStringRef key, int regexOptions)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlKey; /* serialized key */
+ xmlData_t myKeyRef;
+ CFIndex myKeyLen;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierRemove:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" regexOptions = %0o"), regexOptions);
+
+ if (key == NULL) {
+ return SCD_INVALIDARGUMENT; /* no key specified */
+ }
+
+ if (session == NULL) {
+ return SCD_NOSESSION; /* you can't do anything without a session */
+ }
+
+ /*
+ * remove key from this sessions notifier list after checking that
+ * it was previously defined.
+ */
+ if (regexOptions & kSCDRegexKey) {
+ if (!CFSetContainsValue(sessionPrivate->reKeys, key))
+ return SCD_NOKEY; /* sorry, key does not exist in notifier list */
+ CFSetRemoveValue(sessionPrivate->reKeys, key); /* remove key from this sessions notifier list */
+ } else {
+ if (!CFSetContainsValue(sessionPrivate->keys, key))
+ return SCD_NOKEY; /* sorry, key does not exist in notifier list */
+ CFSetRemoveValue(sessionPrivate->keys, key); /* remove key from this sessions notifier list */
+ }
+
+ if (sessionPrivate->server == MACH_PORT_NULL) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /* serialize the key */
+ xmlKey = CFPropertyListCreateXMLData(NULL, key);
+ myKeyRef = (xmlData_t)CFDataGetBytePtr(xmlKey);
+ myKeyLen = CFDataGetLength(xmlKey);
+
+ /* send the key to the server */
+ status = notifyremove(sessionPrivate->server,
+ myKeyRef,
+ myKeyLen,
+ regexOptions,
+ (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlKey);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifyremove(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDNotifierWait(SCDSessionRef session)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ mach_port_t port;
+ mach_port_t oldNotify;
+ SCDStatus scd_status;
+ mach_msg_id_t msgid;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierWait:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ if (SCDOptionGet(NULL, kSCDOptionIsServer)) {
+ /* sorry, neither the server nor any plug-ins can "wait" */
+ return SCD_FAILED;
+ }
+
+ if (sessionPrivate->notifyStatus != NotifierNotRegistered) {
+ /* sorry, you can only have one notification registered at once */
+ return SCD_NOTIFIERACTIVE;
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR("Allocating port (for server response)"));
+ status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_allocate(): %s"), mach_error_string(status));
+ return SCD_FAILED;
+ }
+ SCDLog(LOG_DEBUG, CFSTR(" port = %d"), port);
+
+ status = mach_port_insert_right(mach_task_self(),
+ port,
+ port,
+ MACH_MSG_TYPE_MAKE_SEND);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_insert_right(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), port);
+ return SCD_FAILED;
+ }
+
+ /* Request a notification when/if the server dies */
+ status = mach_port_request_notification(mach_task_self(),
+ port,
+ MACH_NOTIFY_NO_SENDERS,
+ 1,
+ port,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &oldNotify);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_request_notification(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), port);
+ return SCD_FAILED;
+ }
+
+#ifdef DEBUG
+ if (oldNotify != MACH_PORT_NULL) {
+ SCDLog(LOG_DEBUG, CFSTR("SCDNotifierWait(): why is oldNotify != MACH_PORT_NULL?"));
+ }
+#endif /* DEBUG */
+
+ SCDLog(LOG_DEBUG, CFSTR("Requesting notification via mach port %d"), port);
+ status = notifyviaport(sessionPrivate->server,
+ port,
+ 0,
+ (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifyviaport(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ if (scd_status != SCD_OK) {
+ return scd_status;
+ }
+
+ /* set notifier active */
+ sessionPrivate->notifyStatus = Using_NotifierWait;
+
+ SCDLog(LOG_DEBUG, CFSTR("Waiting..."));
+
+ msgid = _waitForMachMessage(port);
+
+ /* set notifier inactive */
+ sessionPrivate->notifyStatus = NotifierNotRegistered;
+
+ if (msgid == MACH_NOTIFY_NO_SENDERS) {
+ /* the server closed the notifier port */
+ SCDLog(LOG_DEBUG, CFSTR(" notifier port closed, destroying port %d"), port);
+ return SCD_NOSERVER;
+ }
+
+ if (msgid == -1) {
+ /* one of the mach routines returned an error */
+ SCDLog(LOG_DEBUG, CFSTR(" communication with server failed, destroying port %d"), port);
+ (void) mach_port_destroy(mach_task_self(), port);
+ return SCD_NOSERVER;
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR("Something changed, cancelling notification request"));
+ status = notifycancel(sessionPrivate->server,
+ (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("notifycancel(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ scd_status = SCD_NOSERVER;
+ }
+
+ (void) mach_port_destroy(mach_task_self(), port);
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#include <servers/bootstrap.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDSessionRef
+_SCDSessionCreatePrivate()
+{
+ SCDSessionRef newSession;
+ SCDSessionPrivateRef newPrivate;
+
+ /* allocate space */
+ newSession = (SCDSessionRef)CFAllocatorAllocate(NULL, sizeof(SCDSessionPrivate), 0);
+ newPrivate = (SCDSessionPrivateRef)newSession;
+
+ /* server side of the "configd" session */
+ newPrivate->server = MACH_PORT_NULL;
+
+ /* per-session flags */
+ SCDOptionSet(newSession, kSCDOptionDebug, SCDOptionGet(NULL, kSCDOptionDebug ));
+ SCDOptionSet(newSession, kSCDOptionVerbose, SCDOptionGet(NULL, kSCDOptionVerbose ));
+ SCDOptionSet(newSession, kSCDOptionIsLocked, FALSE);
+ SCDOptionSet(newSession, kSCDOptionUseSyslog, SCDOptionGet(NULL, kSCDOptionUseSyslog ));
+ SCDOptionSet(newSession, kSCDOptionUseCFRunLoop, SCDOptionGet(NULL, kSCDOptionUseCFRunLoop));
+
+ /* SCDKeys being watched */
+ newPrivate->keys = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+ newPrivate->reKeys = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+
+ /* No notifications pending */
+ newPrivate->notifyStatus = NotifierNotRegistered;
+
+ /* "client" information about active (notification) callback */
+ newPrivate->callbackFunction = NULL;
+ newPrivate->callbackArgument = NULL;
+ newPrivate->callbackPort = NULL;
+ newPrivate->callbackRunLoopSource = NULL; /* XXX */
+ newPrivate->callbackHelper = NULL;
+
+ /* "server" information associated with SCDNotifierInformViaMachPort(); */
+ newPrivate->notifyPort = MACH_PORT_NULL;
+ newPrivate->notifyPortIdentifier = 0;
+
+ /* "server" information associated with SCDNotifierInformViaFD(); */
+ newPrivate->notifyFile = -1;
+ newPrivate->notifyFileIdentifier = 0;
+
+ /* "server" information associated with SCDNotifierInformViaSignal(); */
+ newPrivate->notifySignal = 0;
+ newPrivate->notifySignalTask = TASK_NULL;
+
+ return newSession;
+}
+
+
+SCDStatus
+SCDOpen(SCDSessionRef *session, CFStringRef name)
+{
+ SCDSessionPrivateRef sessionPrivate;
+ kern_return_t status;
+ mach_port_t bootstrap_port;
+ mach_port_t server;
+ CFDataRef xmlName; /* serialized name */
+ xmlData_t myNameRef;
+ CFIndex myNameLen;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDOpen:"));
+ SCDLog(LOG_DEBUG, CFSTR(" name = %@"), name);
+
+ /*
+ * allocate and initialize a new session
+ */
+ sessionPrivate = (SCDSessionPrivateRef)_SCDSessionCreatePrivate();
+ *session = (SCDSessionRef)sessionPrivate;
+
+ status = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("task_get_bootstrap_port(): %s"), mach_error_string(status));
+ CFAllocatorDeallocate(NULL, sessionPrivate);
+ *session = NULL;
+ return SCD_NOSERVER;
+ }
+
+ status = bootstrap_look_up(bootstrap_port, SCD_SERVER, &server);
+ switch (status) {
+ case BOOTSTRAP_SUCCESS :
+ /* service currently registered, "a good thing" (tm) */
+ break;
+ case BOOTSTRAP_UNKNOWN_SERVICE :
+ /* service not currently registered, try again later */
+ CFAllocatorDeallocate(NULL, sessionPrivate);
+ *session = NULL;
+ return SCD_NOSERVER;
+ break;
+ default :
+#ifdef DEBUG
+ SCDLog(LOG_DEBUG, CFSTR("bootstrap_status: %s"), mach_error_string(status));
+#endif /* DEBUG */
+ CFAllocatorDeallocate(NULL, sessionPrivate);
+ *session = NULL;
+ return SCD_NOSERVER;
+ }
+
+ /* serialize the name */
+ xmlName = CFPropertyListCreateXMLData(NULL, name);
+ myNameRef = (xmlData_t)CFDataGetBytePtr(xmlName);
+ myNameLen = CFDataGetLength(xmlName);
+
+ /* open a new session with the server */
+ status = configopen(server, myNameRef, myNameLen, &sessionPrivate->server, (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlName);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configopen(): %s"), mach_error_string(status));
+ CFAllocatorDeallocate(NULL, sessionPrivate);
+ *session = NULL;
+ return SCD_NOSERVER;
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR(" server port = %d"), sessionPrivate->server);
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/notify.h>
+#include <mach/mach_error.h>
+#include <pthread.h>
+
+#include "SCDPrivate.h"
+
+
+__private_extern__ mach_msg_id_t
+_waitForMachMessage(mach_port_t port)
+{
+ kern_return_t status;
+ mach_msg_empty_rcv_t *buf;
+
+ mach_msg_size_t size = sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE;
+
+ status = vm_allocate(mach_task_self(), (vm_address_t *)&buf, size, TRUE);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_allocate(): %s"), mach_error_string(status));
+ return -1;
+ }
+
+ status = mach_msg(&buf->header, /* msg */
+ MACH_RCV_MSG, /* options */
+ 0, /* send_size */
+ size, /* rcv_size */
+ port, /* rcv_name */
+ MACH_MSG_TIMEOUT_NONE, /* timeout */
+ MACH_PORT_NULL); /* notify */
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_msg(): %s"), mach_error_string(status));
+ return -1;
+ }
+
+ return buf->header.msgh_id;
+}
+
+
+void
+_showMachPortStatus()
+{
+#ifdef DEBUG
+ /* print status of in-use mach ports */
+ if (SCDOptionGet(NULL, kSCDOptionDebug) && SCDOptionGet(NULL, kSCDOptionVerbose)) {
+ kern_return_t status;
+ mach_port_name_array_t ports;
+ mach_port_type_array_t types;
+ int pi, pn, tn;
+ CFMutableStringRef str;
+
+ SCDLog(LOG_DEBUG, CFSTR("----------"));
+
+ /* report on ALL mach ports associated with this task */
+ status = mach_port_names(mach_task_self(), &ports, &pn, &types, &tn);
+ if (status == MACH_MSG_SUCCESS) {
+ str = CFStringCreateMutable(NULL, 0);
+ for (pi=0; pi < pn; pi++) {
+ char rights[16], *rp = &rights[0];
+
+ if (types[pi] != MACH_PORT_TYPE_NONE) {
+ *rp++ = ' ';
+ *rp++ = '(';
+ if (types[pi] & MACH_PORT_TYPE_SEND)
+ *rp++ = 'S';
+ if (types[pi] & MACH_PORT_TYPE_RECEIVE)
+ *rp++ = 'R';
+ if (types[pi] & MACH_PORT_TYPE_SEND_ONCE)
+ *rp++ = 'O';
+ if (types[pi] & MACH_PORT_TYPE_PORT_SET)
+ *rp++ = 'P';
+ if (types[pi] & MACH_PORT_TYPE_DEAD_NAME)
+ *rp++ = 'D';
+ *rp++ = ')';
+ }
+ *rp = '\0';
+ CFStringAppendFormat(str, NULL, CFSTR(" %d%s"), ports[pi], rights);
+ }
+ SCDLog(LOG_DEBUG, CFSTR("Task ports (n=%d):%@"), pn, str);
+ CFRelease(str);
+ } else {
+ /* log (but ignore) errors */
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_names(): %s"), mach_error_string(status));
+ }
+ }
+#endif /* DEBUG */
+ return;
+}
+
+
+void
+_showMachPortReferences(mach_port_t port)
+{
+#ifdef DEBUG
+ kern_return_t status;
+ mach_port_urefs_t refs_send = 0;
+ mach_port_urefs_t refs_recv = 0;
+ mach_port_urefs_t refs_once = 0;
+ mach_port_urefs_t refs_pset = 0;
+ mach_port_urefs_t refs_dead = 0;
+
+ SCDLog(LOG_DEBUG, CFSTR("user references for mach port %d"), port);
+
+ status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs_send);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_SEND): %s"), mach_error_string(status));
+ return;
+ }
+
+ status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, &refs_recv);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_RECEIVE): %s"), mach_error_string(status));
+ return;
+ }
+
+ status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, &refs_once);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_SEND_ONCE): %s"), mach_error_string(status));
+ return;
+ }
+
+ status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, &refs_pset);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_PORT_SET): %s"), mach_error_string(status));
+ return;
+ }
+
+ status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, &refs_dead);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR(" mach_port_get_refs(MACH_PORT_RIGHT_DEAD_NAME): %s"), mach_error_string(status));
+ return;
+ }
+
+ SCDLog(LOG_DEBUG,
+ CFSTR(" send = %d, receive = %d, send once = %d, port set = %d, dead name = %d"),
+ refs_send,
+ refs_recv,
+ refs_once,
+ refs_pset,
+ refs_dead);
+
+#endif /* DEBUG */
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCDPRIVATE_H
+#define _SCDPRIVATE_H
+
+#include <SystemConfiguration/SCD.h>
+
+#include <sys/cdefs.h>
+#include <sys/types.h>
+#include <regex.h>
+#include <pthread.h>
+#include <CoreFoundation/CFMachPort.h>
+
+
+/* Define the per-session (and global) flags */
+typedef struct {
+ int debug;
+ int verbose;
+ boolean_t isLocked;
+ boolean_t useSyslog;
+ boolean_t useCFRunLoop;
+} _SCDFlags;
+
+
+/* Define the status of any registered notification. */
+typedef enum {
+ NotifierNotRegistered = 0,
+ Using_NotifierWait,
+ Using_NotifierInformViaCallback,
+ Using_NotifierInformViaMachPort,
+ Using_NotifierInformViaFD,
+ Using_NotifierInformViaSignal,
+} _SCDNotificationStatus;
+
+
+typedef struct {
+
+ /* server side of the "configd" session */
+ mach_port_t server;
+
+ /* per-session flags */
+ _SCDFlags flags;
+
+ /* SCDKeys being watched */
+ CFMutableSetRef keys;
+ CFMutableSetRef reKeys;
+
+ /* current status of notification requests */
+ _SCDNotificationStatus notifyStatus;
+
+ /* "client" information associated with SCDNotifierInformViaCallback() */
+ SCDCallbackRoutine_t callbackFunction;
+ void *callbackArgument;
+ CFMachPortRef callbackPort;
+ CFRunLoopSourceRef callbackRunLoopSource; /* XXX CFMachPortInvalidate() doesn't work */
+ pthread_t callbackHelper;
+
+ /* "server" information associated with SCDNotifierInformViaMachPort() */
+ mach_port_t notifyPort;
+ mach_msg_id_t notifyPortIdentifier;
+
+ /* "server" information associated with SCDNotifierInformViaFD() */
+ int notifyFile;
+ int notifyFileIdentifier;
+
+ /* "server" information associated with SCDNotifierInformViaSignal() */
+ int notifySignal;
+ task_t notifySignalTask;
+
+} SCDSessionPrivate, *SCDSessionPrivateRef;
+
+
+typedef struct {
+
+ /* configuration data associated with key */
+ CFPropertyListRef data;
+
+ /* instance value of last fetched data */
+ int instance;
+
+} SCDHandlePrivate, *SCDHandlePrivateRef;
+
+
+/* per-session options */
+typedef enum {
+ kSCDOptionIsLocked = 1024,
+} SCDServerSessionOptions;
+
+
+/* global options */
+typedef enum {
+ kSCDOptionIsServer = 2048,
+} SCDServerGlobalOptions;
+
+
+__BEGIN_DECLS
+
+SCDSessionRef _SCDSessionCreatePrivate ();
+
+void _SCDHandleSetInstance (SCDHandleRef handle,
+ int instance);
+
+mach_msg_id_t _waitForMachMessage (mach_port_t port);
+
+void _showMachPortStatus ();
+void _showMachPortReferences (mach_port_t port);
+
+__END_DECLS
+
+#endif /* !_SCDPRIVATE_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDRemove(SCDSessionRef session, CFStringRef key)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlKey; /* serialized key */
+ xmlData_t myKeyRef;
+ CFIndex myKeyLen;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDRemove:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+
+ if (key == NULL) {
+ return SCD_INVALIDARGUMENT; /* no key specified */
+ }
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /* serialize the key */
+ xmlKey = CFPropertyListCreateXMLData(NULL, key);
+ myKeyRef = (xmlData_t)CFDataGetBytePtr(xmlKey);
+ myKeyLen = CFDataGetLength(xmlKey);
+
+ /* send the key to the server */
+ status = configremove(sessionPrivate->server,
+ myKeyRef,
+ myKeyLen,
+ (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlKey);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configremove(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDSet(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlKey; /* serialized key */
+ xmlData_t myKeyRef;
+ CFIndex myKeyLen;
+ CFDataRef xmlData; /* serialized data */
+ xmlData_t myDataRef;
+ CFIndex myDataLen;
+ SCDStatus scd_status;
+ int newInstance;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDSet:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" data = %@"), SCDHandleGetData(handle));
+ SCDLog(LOG_DEBUG, CFSTR(" instance = %d"), SCDHandleGetInstance(handle));
+
+ if (key == NULL) {
+ return SCD_INVALIDARGUMENT; /* no key specified */
+ }
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /* serialize the key and data */
+ xmlKey = CFPropertyListCreateXMLData(NULL, key);
+ myKeyRef = (xmlData_t)CFDataGetBytePtr(xmlKey);
+ myKeyLen = CFDataGetLength(xmlKey);
+
+ xmlData = CFPropertyListCreateXMLData(NULL, SCDHandleGetData(handle));
+ myDataRef = (xmlData_t)CFDataGetBytePtr(xmlData);
+ myDataLen = CFDataGetLength(xmlData);
+
+ /* send the key & data to the server, get new instance id */
+ status = configset(sessionPrivate->server,
+ myKeyRef,
+ myKeyLen,
+ myDataRef,
+ myDataLen,
+ SCDHandleGetInstance(handle),
+ &newInstance,
+ (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlKey);
+ CFRelease(xmlData);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configset(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ if (scd_status == SCD_OK) {
+ _SCDHandleSetInstance(handle, newInstance);
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR(" new instance = %d"), SCDHandleGetInstance(handle));
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDSnapshot(SCDSessionRef session)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDSnapshot:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ status = snapshot(sessionPrivate->server, (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("snapshot(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDTouch(SCDSessionRef session, CFStringRef key)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ CFDataRef xmlKey; /* serialized key */
+ xmlData_t myKeyRef;
+ CFIndex myKeyLen;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDTouch:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+
+ if (key == NULL) {
+ return SCD_INVALIDARGUMENT; /* no key specified */
+ }
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /* serialize the key */
+ xmlKey = CFPropertyListCreateXMLData(NULL, key);
+ myKeyRef = (xmlData_t)CFDataGetBytePtr(xmlKey);
+ myKeyLen = CFDataGetLength(xmlKey);
+
+ /* send the key to the server */
+ status = configtouch(sessionPrivate->server,
+ myKeyRef,
+ myKeyLen,
+ (int *)&scd_status);
+
+ /* clean up */
+ CFRelease(xmlKey);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configtouch(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config.h" /* MiG generated file */
+#include "SCDPrivate.h"
+
+
+SCDStatus
+SCDUnlock(SCDSessionRef session)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ kern_return_t status;
+ SCDStatus scd_status;
+
+ SCDLog(LOG_DEBUG, CFSTR("SCDUnlock:"));
+
+ if (session == NULL) {
+ return SCD_NOSESSION; /* you can't do anything without closed session */
+ }
+
+ scd_status = (sessionPrivate->server == MACH_PORT_NULL) ? SCD_NOSESSION : SCD_OK;
+
+ if (scd_status == SCD_OK) {
+ /* (attempt to) release the servers lock */
+ status = configunlock(sessionPrivate->server, (int *)&scd_status);
+
+ if (status != KERN_SUCCESS) {
+ if (status != MACH_SEND_INVALID_DEST)
+ SCDLog(LOG_DEBUG, CFSTR("configunlock(): %s"), mach_error_string(status));
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->server);
+ sessionPrivate->server = MACH_PORT_NULL;
+ return SCD_NOSERVER;
+ }
+ }
+
+ return scd_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SystemConfiguration.h>
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <arpa/nameser.h>
+#include <netdb.h>
+#include <resolv.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include "ppp.h"
+
+
+static int
+inet_atonCF(CFStringRef cfStr, struct in_addr *addr)
+{
+ char cStr[sizeof("255.255.255.255")];
+
+ if (!CFStringGetCString(cfStr, cStr, sizeof(cStr), kCFStringEncodingMacRoman)) {
+ return 0;
+ }
+
+ return inet_aton(cStr, addr);
+}
+
+
+/*
+ * Function: parse_component
+ * Purpose:
+ * Given a string 'key' and a string prefix 'prefix',
+ * return the next component in the slash '/' separated
+ * key.
+ *
+ * Examples:
+ * 1. key = "a/b/c" prefix = "a/"
+ * returns "b"
+ * 2. key = "a/b/c" prefix = "a/b/"
+ * returns "c"
+ */
+static CFStringRef
+parse_component(CFStringRef key, CFStringRef prefix)
+{
+ CFMutableStringRef comp;
+ CFRange range;
+
+ if (CFStringHasPrefix(key, prefix) == FALSE) {
+ return NULL;
+ }
+ comp = CFStringCreateMutableCopy(NULL, 0, key);
+ CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix)));
+ range = CFStringFind(comp, CFSTR("/"), 0);
+ if (range.location == kCFNotFound) {
+ return comp;
+ }
+ range.length = CFStringGetLength(comp) - range.location;
+ CFStringDelete(comp, range);
+ return comp;
+}
+
+
+/*
+ * return a dictionary of configured services.
+ */
+static CFDictionaryRef
+getServices(SCDSessionRef session)
+{
+ CFArrayRef defined = NULL;
+ int i;
+ CFStringRef key;
+ CFStringRef prefix;
+ CFMutableDictionaryRef services;
+ SCDStatus status;
+
+ prefix = SCDKeyCreate(CFSTR("%@/%@/%@/"),
+ kSCCacheDomainSetup,
+ kSCCompNetwork,
+ kSCCompService);
+
+ services = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ key = SCDKeyCreateNetworkServiceEntity(kSCCacheDomainSetup,
+ kSCCompAnyRegex,
+ kSCEntNetIPv4);
+ status = SCDList(session, key, kSCDRegexKey, &defined);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ goto done;
+ }
+
+ for (i = 0; i < CFArrayGetCount(defined); i++) {
+ CFDictionaryRef if_dict;
+ SCDHandleRef if_handle = NULL;
+ CFDictionaryRef ip_dict;
+ SCDHandleRef ip_handle = NULL;
+ boolean_t isPPP = FALSE;
+ CFDictionaryRef ppp_dict;
+ SCDHandleRef ppp_handle = NULL;
+ CFMutableDictionaryRef sDict = NULL;
+ CFStringRef sid = NULL;
+
+ key = CFArrayGetValueAtIndex(defined, i);
+
+ /* get IPv4 dictionary for service */
+ status = SCDGet(session, key, &ip_handle);
+ if (status != SCD_OK) {
+ /* if service was removed behind our back */
+ goto nextService;
+ }
+ ip_dict = SCDHandleGetData(ip_handle);
+
+ sDict = CFDictionaryCreateMutableCopy(NULL, 0, ip_dict);
+
+ /* add keys from the service's Interface dictionary */
+ sid = parse_component(key, prefix);
+ if (sid == NULL) {
+ goto nextService;
+ }
+
+ key = SCDKeyCreateNetworkServiceEntity(kSCCacheDomainSetup,
+ sid,
+ kSCEntNetInterface);
+ status = SCDGet(session, key, &if_handle);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ goto nextService;
+ }
+ if_dict = SCDHandleGetData(if_handle);
+
+ /* check the interface "Type", "SubType", and "DeviceName" */
+ if (CFDictionaryGetValueIfPresent(if_dict,
+ kSCPropNetInterfaceType,
+ (void **)&key)) {
+ CFDictionaryAddValue(sDict, kSCPropNetInterfaceType, key);
+ isPPP = CFEqual(key, kSCValNetInterfaceTypePPP);
+ }
+ if (CFDictionaryGetValueIfPresent(if_dict,
+ kSCPropNetInterfaceSubType,
+ (void **)&key)) {
+ CFDictionaryAddValue(sDict, kSCPropNetInterfaceSubType, key);
+ }
+
+ if (isPPP) {
+ key = SCDKeyCreateNetworkServiceEntity(kSCCacheDomainSetup,
+ sid,
+ kSCEntNetPPP);
+ status = SCDGet(session, key, &ppp_handle);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ goto nextService;
+ }
+ ppp_dict = SCDHandleGetData(ppp_handle);
+
+ /* get Dial-on-Traffic flag */
+ if (CFDictionaryGetValueIfPresent(ppp_dict,
+ kSCPropNetPPPDialOnDemand,
+ (void **)&key)) {
+ CFDictionaryAddValue(sDict, kSCPropNetPPPDialOnDemand, key);
+ }
+ }
+
+ CFDictionaryAddValue(services, sid, sDict);
+
+ nextService:
+
+ if (sid) CFRelease(sid);
+ if (if_handle) SCDHandleRelease(if_handle);
+ if (ip_handle) SCDHandleRelease(ip_handle);
+ if (ppp_handle) SCDHandleRelease(ppp_handle);
+ if (sDict) CFRelease(sDict);
+ }
+
+ done:
+
+ if (defined) CFRelease(defined);
+ CFRelease(prefix);
+
+ return services;
+}
+
+
+/*
+ * return a dictionary of configured interfaces.
+ */
+static CFDictionaryRef
+getInterfaces(SCDSessionRef session)
+{
+ CFMutableArrayRef defined = NULL;
+ int i;
+ CFStringRef key;
+ CFMutableDictionaryRef interfaces;
+ CFStringRef prefix;
+ SCDStatus status;
+
+ prefix = SCDKeyCreate(CFSTR("%@/%@/%@/"),
+ kSCCacheDomainState,
+ kSCCompNetwork,
+ kSCCompInterface);
+
+ interfaces = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+
+ key = SCDKeyCreateNetworkInterfaceEntity(kSCCacheDomainState,
+ kSCCompAnyRegex,
+ kSCEntNetIPv4);
+ status = SCDList(session, key, kSCDRegexKey, &defined);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ goto done;
+ }
+
+ for (i=0; i<CFArrayGetCount(defined); i++) {
+ CFStringRef iid = NULL;
+ CFDictionaryRef ip_dict;
+ SCDHandleRef ip_handle = NULL;
+
+ key = CFArrayGetValueAtIndex(defined, i);
+
+ /* get IPv4 dictionary for service */
+ status = SCDGet(session, key, &ip_handle);
+ if (status != SCD_OK) {
+ /* if interface was removed behind our back */
+ goto nextIF;
+ }
+ ip_dict = SCDHandleGetData(ip_handle);
+
+ iid = parse_component(key, prefix);
+ if (iid == NULL) {
+ goto nextIF;
+ }
+
+ CFDictionaryAddValue(interfaces, iid, ip_dict);
+
+ nextIF :
+
+ if (iid) CFRelease(iid);
+ if (ip_handle) SCDHandleRelease(ip_handle);
+ }
+
+ done:
+
+ if (defined) CFRelease(defined);
+ CFRelease(prefix);
+ return interfaces;
+}
+
+
+/*
+ * return an array of interface names based on a specified service order.
+ */
+static CFArrayRef
+getInterfaceOrder(CFDictionaryRef interfaces,
+ CFArrayRef serviceOrder,
+ CFNumberRef pppOverridePrimary)
+{
+ CFIndex i;
+ CFIndex iCnt;
+ CFMutableArrayRef iKeys;
+ void **keys;
+ CFMutableArrayRef order = NULL;
+ CFArrayRef tKeys;
+
+ order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ iCnt = CFDictionaryGetCount(interfaces);
+ keys = CFAllocatorAllocate(NULL, iCnt * sizeof(CFStringRef), 0);
+ CFDictionaryGetKeysAndValues(interfaces, keys, NULL);
+ tKeys = CFArrayCreate(NULL, keys, iCnt, &kCFTypeArrayCallBacks);
+ CFAllocatorDeallocate(NULL, keys);
+ iKeys = CFArrayCreateMutableCopy(NULL, 0, tKeys);
+ CFRelease(tKeys);
+
+ for (i = 0; serviceOrder && i < CFArrayGetCount(serviceOrder); i++) {
+ CFIndex j;
+ CFStringRef oSID;
+
+ oSID = CFArrayGetValueAtIndex(serviceOrder, i);
+ for (j=0; j<CFArrayGetCount(iKeys); j++) {
+ CFDictionaryRef iDict;
+ CFStringRef iKey;
+ CFStringRef iSID;
+ CFArrayRef iSIDs;
+ CFIndex k;
+ boolean_t match = FALSE;
+
+ iKey = CFArrayGetValueAtIndex(iKeys, j);
+ iDict = CFDictionaryGetValue(interfaces, iKey);
+
+ iSIDs = CFDictionaryGetValue(iDict, kSCCachePropNetServiceIDs);
+ for (k = 0; iSIDs && k < CFArrayGetCount(iSIDs); k++) {
+ iSID = CFArrayGetValueAtIndex(iSIDs, k);
+ if (CFEqual(oSID, iSID)) {
+ match = TRUE;
+ break;
+ }
+ }
+
+ if (match) {
+ /* if order ServiceID is associated with this interface */
+ CFArrayAppendValue(order, iKey);
+ CFArrayRemoveValueAtIndex(iKeys, j);
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < CFArrayGetCount(iKeys); i++) {
+ CFStringRef iKey;
+
+ iKey = CFArrayGetValueAtIndex(iKeys, i);
+ CFArrayAppendValue(order, iKey);
+ }
+
+ CFRelease(iKeys);
+ return order;
+}
+
+
+static boolean_t
+getAddresses(CFDictionaryRef iDict,
+ CFIndex *nAddrs,
+ CFArrayRef *addrs,
+ CFArrayRef *masks,
+ CFArrayRef *dests)
+{
+ *addrs = CFDictionaryGetValue(iDict, kSCPropNetIPv4Addresses);
+ *masks = CFDictionaryGetValue(iDict, kSCPropNetIPv4SubnetMasks);
+ *dests = CFDictionaryGetValue(iDict, kSCPropNetIPv4DestAddresses);
+
+ if ((*addrs == NULL) ||
+ ((*nAddrs = CFArrayGetCount(*addrs)) == 0)) {
+ /* sorry, no addresses */
+ return FALSE;
+ }
+
+ if ((*masks && *dests) ||
+ (*masks == NULL) && (*dests == NULL)) {
+ /*
+ * sorry, we expect to have "SubnetMasks" or
+ * "DestAddresses" (not both) and if the count
+ * must match the number of "Addresses".
+ */
+ return FALSE;
+ }
+
+ if (*masks && (*nAddrs != CFArrayGetCount(*masks))) {
+ /* if we don't like the netmasks */
+ return FALSE;
+ }
+
+ if (*dests && (*nAddrs != CFArrayGetCount(*dests))) {
+ /* if we don't like the destaddresses */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static SCNStatus
+checkAddress(SCDSessionRef session,
+ const struct sockaddr *address,
+ const int addrlen,
+ CFDictionaryRef services,
+ CFDictionaryRef interfaces,
+ CFArrayRef interfaceOrder,
+ struct in_addr *defaultRoute,
+ int *flags,
+ const char **errorMessage)
+{
+ CFIndex i;
+ struct ifreq ifr;
+ CFIndex iCnt;
+ CFStringRef iKey = NULL;
+ CFStringRef iType = NULL;
+ void **keys;
+ int pppRef = -1;
+ SCNStatus scn_status = SCN_REACHABLE_UNKNOWN;
+ CFIndex sCnt;
+ CFMutableArrayRef sKeys = NULL;
+ CFStringRef sID = NULL;
+ CFArrayRef sIDs = NULL;
+ CFArrayRef sList = NULL;
+ int sock = -1;
+ CFStringRef sKey = NULL;
+ CFDictionaryRef sDict = NULL;
+ CFArrayRef tKeys;
+
+ if (flags != NULL) {
+ *flags = 0;
+ }
+
+ if (address == NULL) {
+ return SCN_REACHABLE_NO;
+ }
+
+ sCnt = CFDictionaryGetCount(services);
+ keys = CFAllocatorAllocate(NULL, sCnt * sizeof(CFStringRef), 0);
+ CFDictionaryGetKeysAndValues(services, keys, NULL);
+ tKeys = CFArrayCreate(NULL, keys, sCnt, &kCFTypeArrayCallBacks);
+ CFAllocatorDeallocate(NULL, keys);
+ sKeys = CFArrayCreateMutableCopy(NULL, 0, tKeys);
+ CFRelease(tKeys);
+
+ if (address->sa_family == AF_INET) {
+ struct sockaddr_in *sin = (struct sockaddr_in *)address;
+
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR("checkAddress(%s)"), inet_ntoa(sin->sin_addr));
+#endif /* DEBUG */
+ /*
+ * Check for loopback address
+ */
+ if (ntohl(sin->sin_addr.s_addr) == ntohl(INADDR_LOOPBACK)) {
+ /* if asking about the loopback address */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" isReachable via loopback"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_YES;
+ goto done;
+ }
+
+ /*
+ * Check if the address is on one of the subnets
+ * associated with our active IPv4 interfaces
+ */
+ iCnt = CFArrayGetCount(interfaceOrder);
+ for (i=0; i<iCnt; i++) {
+ CFArrayRef addrs;
+ CFArrayRef dests;
+ CFDictionaryRef iDict;
+ CFIndex j;
+ CFArrayRef masks;
+ CFIndex nAddrs = 0;
+
+ iKey = CFArrayGetValueAtIndex(interfaceOrder, i);
+ iDict = CFDictionaryGetValue(interfaces, iKey);
+
+ /* remove active services */
+ sIDs = CFDictionaryGetValue(iDict, kSCCachePropNetServiceIDs);
+ for (j = 0; sIDs && j < CFArrayGetCount(sIDs); j++) {
+ CFIndex k;
+ CFStringRef sID;
+
+ sID = CFArrayGetValueAtIndex(sIDs, j);
+ k = CFArrayGetFirstIndexOfValue(sKeys,
+ CFRangeMake(0, CFArrayGetCount(sKeys)),
+ sID);
+ if (k != -1) {
+ CFArrayRemoveValueAtIndex(sKeys, k);
+ }
+ }
+
+ if (!getAddresses(iDict, &nAddrs, &addrs, &masks, &dests)) {
+ /* if no addresses to check */
+ continue;
+ }
+
+ for (j=0; j<nAddrs; j++) {
+ struct in_addr ifAddr;
+
+ if (inet_atonCF(CFArrayGetValueAtIndex(addrs, j),
+ &ifAddr) == 0) {
+ /* if Addresses string is invalid */
+ break;
+ }
+
+ if (masks) {
+ struct in_addr ifMask;
+
+ if (inet_atonCF(CFArrayGetValueAtIndex(masks, j),
+ &ifMask) == 0) {
+ /* if SubnetMask string is invalid */
+ break;
+ }
+
+ if ((ntohl(ifAddr.s_addr) & ntohl(ifMask.s_addr)) ==
+ (ntohl(sin->sin_addr.s_addr) & ntohl(ifMask.s_addr))) {
+ /* the requested address is on this subnet */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" isReachable (my subnet)"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_YES;
+ goto checkInterface;
+ }
+ } else {
+ struct in_addr destAddr;
+
+ /* check remote address */
+ if (inet_atonCF(CFArrayGetValueAtIndex(dests, j),
+ &destAddr) == 0) {
+ /* if DestAddresses string is invalid */
+ break;
+ }
+
+ /* check local address */
+ if (ntohl(sin->sin_addr.s_addr) == ntohl(ifAddr.s_addr)) {
+ /* the address is our side of the link */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" isReachable (my local address)"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_YES;
+ goto checkInterface;
+ }
+
+ if (ntohl(sin->sin_addr.s_addr) == ntohl(destAddr.s_addr)) {
+ /* the address is the other side of the link */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" isReachable (my remote address)"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_YES;
+ goto checkInterface;
+ }
+ }
+ }
+ }
+
+ /*
+ * Check if the address is accessible via the "default" route.
+ */
+ for (i=0; i<iCnt; i++) {
+ CFArrayRef addrs;
+ CFArrayRef dests;
+ CFDictionaryRef iDict;
+ CFIndex j;
+ CFArrayRef masks;
+ CFIndex nAddrs = 0;
+
+ iKey = CFArrayGetValueAtIndex(interfaceOrder, i);
+ iDict = CFDictionaryGetValue(interfaces, iKey);
+
+ if (!getAddresses(iDict, &nAddrs, &addrs, &masks, &dests)) {
+ /* if no addresses to check */
+ continue;
+ }
+
+ for (j=0; defaultRoute && j<nAddrs; j++) {
+ if (masks) {
+ struct in_addr ifAddr;
+ struct in_addr ifMask;
+
+ if (inet_atonCF(CFArrayGetValueAtIndex(addrs, j),
+ &ifAddr) == 0) {
+ /* if Addresses string is invalid */
+ break;
+ }
+
+ if (inet_atonCF(CFArrayGetValueAtIndex(masks, j),
+ &ifMask) == 0) {
+ /* if SubnetMasks string is invalid */
+ break;
+ }
+
+ if ((ntohl(ifAddr.s_addr) & ntohl(ifMask.s_addr)) ==
+ (ntohl(defaultRoute->s_addr) & ntohl(ifMask.s_addr))) {
+ /* the requested address is on this subnet */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" isReachable via default route (my subnet)"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_YES;
+ goto checkInterface;
+ }
+ } else {
+ struct in_addr destAddr;
+
+ /* check remote address */
+ if (inet_atonCF(CFArrayGetValueAtIndex(dests, j),
+ &destAddr) == 0) {
+ /* if DestAddresses string is invalid */
+ break;
+ }
+
+ if (ntohl(destAddr.s_addr) == ntohl(defaultRoute->s_addr)) {
+ /* the address is the other side of the link */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" isReachable via default route (my remote address)"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_YES;
+ goto checkInterface;
+ }
+ }
+ }
+ }
+
+ /*
+ * Check the not active (but configured) IPv4 services
+ */
+ sCnt = CFArrayGetCount(sKeys);
+ for (i=0; i<sCnt; i++) {
+ CFArrayRef addrs;
+ CFStringRef configMethod = NULL;
+ CFArrayRef dests;
+ CFIndex j;
+ CFArrayRef masks;
+ CFIndex nAddrs = 0;
+
+ sKey = CFArrayGetValueAtIndex(sKeys, i);
+ sDict = CFDictionaryGetValue(services, sKey);
+
+ /*
+ * check configured network addresses
+ */
+ for (j=0; j<nAddrs; j++) {
+ struct in_addr ifAddr;
+
+ if (inet_atonCF(CFArrayGetValueAtIndex(addrs, j),
+ &ifAddr) == 0) {
+ /* if Addresses string is invalid */
+ break;
+ }
+
+ if (masks) {
+ struct in_addr ifMask;
+
+ /* check address/netmask */
+ if (inet_atonCF(CFArrayGetValueAtIndex(masks, j),
+ &ifMask) == 0) {
+ /* if SubnetMasks string is invalid */
+ break;
+ }
+
+ if ((ntohl(ifAddr.s_addr) & ntohl(ifMask.s_addr)) !=
+ (ntohl(sin->sin_addr.s_addr) & ntohl(ifMask.s_addr))) {
+ /* the requested address is on this subnet */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" is configured w/static info (my subnet)"));
+#endif /* DEBUG */
+ goto checkService;
+ }
+ } else {
+ struct in_addr destAddr;
+
+ /* check remote address */
+ if (inet_atonCF(CFArrayGetValueAtIndex(dests, j),
+ &destAddr) == 0) {
+ /* if DestAddresses string is invalid */
+ break;
+ }
+
+ /* check local address */
+ if (ntohl(sin->sin_addr.s_addr) == ntohl(ifAddr.s_addr)) {
+ /* the address is our side of the link */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" is configured w/static info (my local address)"));
+#endif /* DEBUG */
+ goto checkService;
+ }
+
+ if (ntohl(sin->sin_addr.s_addr) == ntohl(destAddr.s_addr)) {
+ /* the address is the other side of the link */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" is configured w/static info (my remote address)"));
+#endif /* DEBUG */
+ goto checkService;
+ }
+ }
+ }
+
+ /*
+ * check for dynamic (i.e. not manual) configuration
+ * method.
+ */
+ if (CFDictionaryGetValueIfPresent(sDict,
+ kSCPropNetIPv4ConfigMethod,
+ (void **)&configMethod) &&
+ !CFEqual(configMethod, kSCValNetIPv4ConfigMethodManual)) {
+ /* if only we were "connected" */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" is configured w/dynamic addressing"));
+#endif /* DEBUG */
+ goto checkService;
+ }
+ }
+
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" cannot be reached"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_NO;
+ goto done;
+
+ } else {
+ /*
+ * if no code for this address family (yet)
+ */
+ SCDSessionLog(session,
+ LOG_ERR,
+ CFSTR("checkAddress(): unexpected address family %d"),
+ address->sa_family);
+ if (errorMessage != NULL) {
+ *errorMessage = "unexpected address family";
+ }
+ goto done;
+ }
+
+ goto done;
+
+ checkInterface :
+
+ /*
+ * We have an interface which "claims" to be a valid path
+ * off of the system. Check to make sure that this isn't
+ * a dial-on-demand PPP link that isn't connected yet.
+ */
+ if (sIDs) {
+ CFNumberRef num;
+ CFDictionaryRef sDict;
+
+ /* attempt to get the interface type from the first service */
+ sID = CFArrayGetValueAtIndex(sIDs, 0);
+ sDict = CFDictionaryGetValue(services, sID);
+ if (sDict) {
+ iType = CFDictionaryGetValue(sDict, kSCPropNetInterfaceType);
+ }
+
+ if (!iType) {
+ /* if we don't know the interface type */
+ goto done;
+ }
+
+ if (!CFEqual(iType, kSCValNetInterfaceTypePPP)) {
+ /* if not a ppp interface */
+ goto done;
+ }
+
+ num = CFDictionaryGetValue(sDict, kSCPropNetPPPDialOnDemand);
+ if (num) {
+ int dialOnDemand;
+
+ CFNumberGetValue(num, kCFNumberIntType, &dialOnDemand);
+ if (flags && (dialOnDemand != 0)) {
+ *flags |= kSCNFlagsConnectionAutomatic;
+ }
+
+ }
+ } else if (!CFStringHasPrefix(iKey, CFSTR("ppp"))) {
+ /* if not a ppp interface */
+ goto done;
+ }
+
+ if (flags != NULL) {
+ *flags |= kSCNFlagsTransientConnection;
+ }
+
+ if (sID) {
+ u_int32_t pppLink;
+ struct ppp_status *pppLinkStatus;
+ int pppStatus;
+
+ /*
+ * The service ID is available, ask the PPP controller
+ * for the extended status.
+ */
+ pppStatus = PPPInit(&pppRef);
+ if (pppStatus != 0) {
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_DEBUG, CFSTR(" PPPInit() failed: status=%d"), pppStatus);
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_UNKNOWN;
+ if (errorMessage != NULL) {
+ *errorMessage = "PPPInit() failed";
+ }
+ goto done;
+ }
+
+ pppStatus = PPPGetLinkByServiceID(pppRef, sID, &pppLink);
+ if (pppStatus != 0) {
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_DEBUG, CFSTR(" PPPGetLinkByServiceID() failed: status=%d"), pppStatus);
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_UNKNOWN;
+ if (errorMessage != NULL) {
+ *errorMessage = "PPPGetLinkByServiceID() failed";
+ }
+ goto done;
+ }
+
+ pppStatus = PPPStatus(pppRef, pppLink, &pppLinkStatus);
+ if (pppStatus != 0) {
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_DEBUG, CFSTR(" PPPStatus() failed: status=%d"), pppStatus);
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_UNKNOWN;
+ if (errorMessage != NULL) {
+ *errorMessage = "PPPStatus() failed";
+ }
+ goto done;
+ }
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_DEBUG, CFSTR(" PPP link status = %d"), pppLinkStatus->status);
+#endif /* DEBUG */
+ switch (pppLinkStatus->status) {
+ case PPP_RUNNING :
+ /* if we're really UP and RUNNING */
+ break;
+ case PPP_IDLE :
+ /* if we're not connected at all */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" PPP link idle, dial-on-traffic to connect"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_CONNECTION_REQUIRED;
+ break;
+ default :
+ /* if we're in the process of [dis]connecting */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" PPP link, connection in progress"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_CONNECTION_REQUIRED;
+ break;
+ }
+ CFAllocatorDeallocate(NULL, pppLinkStatus);
+ } else {
+ /*
+ * The service ID is not available, check the interfaces
+ * UP and RUNNING flags.
+ */
+ bzero(&ifr, sizeof(ifr));
+ if (!CFStringGetCString(iKey,
+ (char *)&ifr.ifr_name,
+ sizeof(ifr.ifr_name),
+ kCFStringEncodingMacRoman)) {
+ scn_status = SCN_REACHABLE_UNKNOWN;
+ if (errorMessage != NULL) {
+ *errorMessage = "could not convert interface name to C string";
+ }
+ goto done;
+ }
+
+ sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if (sock == -1) {
+ scn_status = SCN_REACHABLE_UNKNOWN;
+ if (errorMessage != NULL) {
+ *errorMessage = strerror(errno);
+ }
+ goto done;
+ }
+
+ if (ioctl(sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ scn_status = SCN_REACHABLE_UNKNOWN;
+ if (errorMessage != NULL) {
+ *errorMessage = strerror(errno);
+ }
+ goto done;
+ }
+
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" flags for %s == 0x%hx"), ifr.ifr_name, ifr.ifr_flags);
+#endif /* DEBUG */
+ if ((ifr.ifr_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
+ if ((ifr.ifr_flags & IFF_UP) == IFF_UP) {
+ /* if we're "up" but not "running" */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" up & not running, dial-on-traffic to connect"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_CONNECTION_REQUIRED;
+ if (flags != NULL) {
+ *flags |= kSCNFlagsConnectionAutomatic;
+ }
+ } else {
+ /* if we're not "up" and "running" */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" not up & running, connection required"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_CONNECTION_REQUIRED;
+ }
+ goto done;
+ }
+ }
+
+ goto done;
+
+ checkService :
+
+ /*
+ * We have a service which "claims" to be a potential path
+ * off of the system. Check to make sure that this is a
+ * type of PPP link before claiming it's viable.
+ */
+ if (sDict &&
+ CFDictionaryGetValueIfPresent(sDict,
+ kSCPropNetInterfaceType,
+ (void **)&iType) &&
+ !CFEqual(iType, kSCValNetInterfaceTypePPP)) {
+ /* no path if this not a ppp interface */
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug))
+ SCDLog(LOG_INFO, CFSTR(" cannot be reached"));
+#endif /* DEBUG */
+ scn_status = SCN_REACHABLE_NO;
+ goto done;
+ }
+
+ scn_status = SCN_REACHABLE_CONNECTION_REQUIRED;
+ if (flags != NULL) {
+ *flags |= kSCNFlagsTransientConnection;
+ }
+
+ done :
+
+ if (sKeys) CFRelease(sKeys);
+ if (sList) CFRelease(sList);
+ if (pppRef != -1) (void) PPPDispose(pppRef);
+ if (sock != -1) (void)close(sock);
+
+ return scn_status;
+}
+
+
+static void
+_IsReachableInit(SCDSessionRef session,
+ CFDictionaryRef *services,
+ CFDictionaryRef *interfaces,
+ CFArrayRef *interfaceOrder,
+ struct in_addr **defaultRoute)
+{
+ CFStringRef addr;
+ CFDictionaryRef dict;
+ CFStringRef key;
+ SCDHandleRef handle;
+ CFNumberRef pppOverridePrimary = NULL;
+ CFArrayRef serviceOrder = NULL;
+ struct in_addr *route = NULL;
+ SCDStatus status;
+
+ /*
+ * get the ServiceOrder and PPPOverridePrimary keys
+ * from the global settings.
+ */
+ key = SCDKeyCreateNetworkGlobalEntity(kSCCacheDomainSetup, kSCEntNetIPv4);
+ status = SCDGet(session, key, &handle);
+ CFRelease(key);
+ switch (status) {
+ case SCD_OK :
+ /* if global settings are available */
+ dict = SCDHandleGetData(handle);
+
+ /* get service order */
+ if ((CFDictionaryGetValueIfPresent(dict,
+ kSCPropNetServiceOrder,
+ (void **)&serviceOrder) == TRUE)) {
+ CFRetain(serviceOrder);
+ }
+
+ /* get PPP overrides primary flag */
+ if ((CFDictionaryGetValueIfPresent(dict,
+ kSCPropNetPPPOverridePrimary,
+ (void **)&pppOverridePrimary) == TRUE)) {
+ CFRetain(pppOverridePrimary);
+ }
+
+ SCDHandleRelease(handle);
+ break;
+ case SCD_NOKEY :
+ /* if no global settings */
+ break;
+ default :
+ SCDLog(LOG_ERR, CFSTR("SCDGet() failed: %s"), SCDError(status));
+ /* XXX need to do something more with this FATAL error XXXX */
+ goto error;
+ }
+
+ /*
+ * Get default route
+ */
+ key = SCDKeyCreateNetworkGlobalEntity(kSCCacheDomainState,
+ kSCEntNetIPv4);
+ status = SCDGet(session, key, &handle);
+ CFRelease(key);
+ switch (status) {
+ case SCD_OK :
+ dict = SCDHandleGetData(handle);
+ addr = CFDictionaryGetValue(dict, kSCPropNetIPv4Router);
+ if (addr == NULL) {
+ /* if no default route */
+ break;
+ }
+
+ route = CFAllocatorAllocate(NULL, sizeof(struct in_addr), 0);
+ if (inet_atonCF(addr, route) == 0) {
+ /* if address string is invalid */
+ CFAllocatorDeallocate(NULL, route);
+ route = NULL;
+ break;
+ }
+ *defaultRoute = route;
+
+ break;
+ case SCD_NOKEY :
+ /* if no default route */
+ break;
+ default :
+ SCDSessionLog(session,
+ LOG_ERR,
+ CFSTR("SCDGet() failed: %s"),
+ SCDError(status));
+ goto error;
+ }
+ if (handle) {
+ SCDHandleRelease(handle);
+ handle = NULL;
+ }
+
+ /*
+ * get the configured services and interfaces
+ */
+ *services = getServices (session);
+ *interfaces = getInterfaces(session);
+ *interfaceOrder = getInterfaceOrder(*interfaces,
+ serviceOrder,
+ pppOverridePrimary);
+
+ error :
+
+ if (serviceOrder) CFRelease(serviceOrder);
+ if (pppOverridePrimary) CFRelease(pppOverridePrimary);
+
+#ifdef DEBUG
+ if (SCDOptionGet(session, kSCDOptionDebug)) {
+ SCDLog(LOG_NOTICE, CFSTR("interfaces = %@"), *interfaces);
+ SCDLog(LOG_NOTICE, CFSTR("services = %@"), *services);
+ SCDLog(LOG_NOTICE, CFSTR("interfaceOrder = %@"), *interfaceOrder);
+ SCDLog(LOG_NOTICE, CFSTR("defaultRoute = %s"), *defaultRoute?inet_ntoa(**defaultRoute):"None");
+ }
+#endif /* DEBUG */
+ return;
+
+}
+
+
+static void
+_IsReachableFree(CFDictionaryRef services,
+ CFDictionaryRef interfaces,
+ CFArrayRef interfaceOrder,
+ struct in_addr *defaultRoute)
+{
+ if (services) CFRelease(services);
+ if (interfaces) CFRelease(interfaces);
+ if (interfaceOrder) CFRelease(interfaceOrder);
+ if (defaultRoute) CFAllocatorDeallocate(NULL, defaultRoute);
+ return;
+}
+
+
+SCNStatus
+SCNIsReachableByAddress(const struct sockaddr *address,
+ const int addrlen,
+ int *flags,
+ const char **errorMessage)
+{
+ struct in_addr *defaultRoute = NULL;
+ CFDictionaryRef interfaces = NULL;
+ CFArrayRef interfaceOrder = NULL;
+ CFDictionaryRef services = NULL;
+ SCDSessionRef session = NULL;
+ SCDStatus scd_status;
+ SCNStatus scn_status;
+
+ scd_status = SCDOpen(&session, CFSTR("SCNIsReachableByAddress"));
+ if (scd_status != SCD_OK) {
+ if (errorMessage != NULL) {
+ *errorMessage = SCDError(scd_status);
+ }
+ return SCN_REACHABLE_UNKNOWN;
+ }
+
+ _IsReachableInit(session, &services, &interfaces, &interfaceOrder, &defaultRoute);
+ scn_status = checkAddress(session,
+ address,
+ addrlen,
+ services,
+ interfaces,
+ interfaceOrder,
+ defaultRoute,
+ flags,
+ errorMessage);
+ _IsReachableFree(services, interfaces, interfaceOrder, defaultRoute);
+
+ (void) SCDClose(&session);
+ return scn_status;
+}
+
+
+SCNStatus
+SCNIsReachableByName(const char *nodename,
+ int *flags,
+ const char **errorMessage)
+{
+ struct in_addr *defaultRoute = NULL;
+ int i;
+ CFDictionaryRef interfaces = NULL;
+ CFArrayRef interfaceOrder = NULL;
+ SCDStatus scd_status = SCD_OK;
+ SCNStatus ns_status = SCN_REACHABLE_YES;
+ struct addrinfo *res = NULL;
+ struct addrinfo *resP;
+ CFDictionaryRef services = NULL;
+ SCDSessionRef session = NULL;
+ SCNStatus scn_status = SCN_REACHABLE_YES;
+
+ scd_status = SCDOpen(&session, CFSTR("SCNIsReachableByName"));
+ if (scd_status != SCD_OK) {
+ scn_status = SCN_REACHABLE_UNKNOWN;
+ if (errorMessage != NULL) {
+ *errorMessage = SCDError(scd_status);
+ }
+ goto done;
+ }
+
+ _IsReachableInit(session, &services, &interfaces, &interfaceOrder, &defaultRoute);
+
+ /*
+ * since we don't know which name server will be consulted
+ * to resolve the specified nodename we need to check the
+ * availability of ALL name servers.
+ */
+ res_init();
+ for (i=0; i<_res.nscount; i++) {
+ ns_status = checkAddress(session,
+ (struct sockaddr *)&_res.nsaddr_list[i],
+ _res.nsaddr_list[i].sin_len,
+ services,
+ interfaces,
+ interfaceOrder,
+ defaultRoute,
+ flags,
+ errorMessage);
+ if (ns_status < scn_status) {
+ /* return the worst case result */
+ scn_status = ns_status;
+ if (ns_status == SCN_REACHABLE_UNKNOWN) {
+ /* not today */
+ break;
+ }
+ }
+ }
+
+ if (ns_status < SCN_REACHABLE_YES) {
+ goto done;
+ }
+
+ /*
+ * OK, all of the DNS name servers are available. Let's
+ * first assume that the requested host is NOT available,
+ * resolve the nodename, and check its address for
+ * accessibility. We return the best status available.
+ */
+ scn_status = SCN_REACHABLE_UNKNOWN;
+
+ /*
+ * resolve the nodename into an address
+ */
+ i = getaddrinfo(nodename, NULL, NULL, &res);
+ if (i != 0) {
+ SCDSessionLog(session,
+ LOG_ERR,
+ CFSTR("getaddrinfo() failed: %s"),
+ gai_strerror(i));
+ goto done;
+ }
+
+ for (resP=res; resP!=NULL; resP=resP->ai_next) {
+ ns_status = checkAddress(session,
+ resP->ai_addr,
+ resP->ai_addrlen,
+ services,
+ interfaces,
+ interfaceOrder,
+ defaultRoute,
+ flags,
+ errorMessage);
+ if (ns_status > scn_status) {
+ /* return the best case result */
+ scn_status = ns_status;
+ if (ns_status == SCN_REACHABLE_YES) {
+ /* we're in luck */
+ break;
+ }
+ }
+ }
+
+ done :
+
+ _IsReachableFree(services, interfaces, interfaceOrder, defaultRoute);
+ if (session) (void)SCDClose(&session);
+ if (res) freeaddrinfo(res);
+
+ return scn_status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCPNETWORK_H
+#define _SCPNETWORK_H
+
+#include <sys/cdefs.h>
+#include <sys/socket.h>
+
+/*!
+ @header SCPNetwork.h
+ The SystemConfiguration framework provides access to the data used
+ to configure a running system.
+
+ Specifically, the SCPNetworkXXX() API's allow an application
+ to determine the status of the systems current network
+ configuration.
+
+ The APIs provided by this framework communicate with the "configd"
+ daemon to obtain information regarding the systems current
+ configuration.
+ */
+
+/*!
+ @enum SCNStatus
+ @discussion Returned status codes from the SCNIsReachableByAddress()
+ and SCNIsReachableByName() functions.
+
+ The term "reachable" in these status codes reflects whether
+ a data packet, sent by an application into the network stack,
+ will be able to reach the destination host.
+
+ Please not that being "able" to reach the destination host
+ does not guarantee that the data packet "will" reach the
+ host.
+
+ @constant SCN_REACHABLE_UNKNOWN
+ A determination could not be made regarding the reachability
+ of the specified nodename/address.
+
+ @constant SCN_REACHABLE_NO
+ The specified nodename/address can not be reached using the
+ current network configuration.
+
+ @constant SCN_REACHABLE_CONNECTION_REQUIRED
+ The specified nodename/address can be reached using the
+ current network configuration but a connection must first
+ be established.
+
+ This status would be returned for a dialup connection which
+ was not currently active but could handle network traffic for
+ the target system.
+
+ @constant SCN_REACHABLE_YES
+ The specified nodename/address can be reached using the
+ current network configuration.
+ */
+typedef enum {
+ SCN_REACHABLE_UNKNOWN = -1,
+ SCN_REACHABLE_NO = 0,
+ SCN_REACHABLE_CONNECTION_REQUIRED = 1,
+ SCN_REACHABLE_YES = 2,
+} SCNStatus;
+
+
+/*!
+ @enum SCNConnectionFlags
+ @discussion Additional flags which reflect whether a network connection
+ to the specified nodename/address is reachable, requires a
+ connection, requires some user intervention in establishing
+ the connection, and whether the calling application must initiate
+ the connection using the SCNEstablishConnection() API.
+
+ @constant kSCNFlagsTransientConnection
+ This flag indicates that the specified nodename/address can
+ be reached via a transient (e.g. PPP) connection.
+
+ @constant kSCNFlagsConnectionAutomatic
+ The specified nodename/address can be reached using the
+ current network configuration but a connection must first
+ be established. Any traffic directed to the specified
+ name/address will initiate the connection.
+
+ @constant kSCNFlagsInterventionRequired
+ The specified nodename/address can be reached using the
+ current network configuration but a connection must first
+ be established. In addition, some form of user intervention
+ will be required to establish this connection (e.g. providing
+ a password, authentication token, etc.).
+ */
+typedef enum {
+ kSCNFlagsTransientConnection = 1<<0,
+ kSCNFlagsConnectionAutomatic = 1<<1,
+ kSCNFlagsInterventionRequired = 1<<2,
+} SCNConnectionFlags;
+
+
+__BEGIN_DECLS
+
+/*!
+ @function SCNIsReachableByAddress
+ @discussion Determines if the given network address is
+ reachable using the current network configuration.
+
+ Note: This API is not thread safe.
+ @param address Pass the network address of the desired host.
+ @param addrlen Pass the length, in bytes, of the address.
+ @param flags A pointer to memory which will be filled with a
+ set of SCNConnectionFlags related to the reachability
+ of the specified address. If NULL, no flags will be
+ returned.
+ @param status A pointer to memory which will be filled with the
+ error status associated with any error communicating with
+ the system configuration daemon.
+ @result A constant of type SCNStatus indicating the reachability
+ of the specified node address.
+ */
+SCNStatus SCNIsReachableByAddress (const struct sockaddr *address,
+ const int addrlen,
+ int *flags,
+ const char **errorMessage);
+
+/*!
+ @function SCNIsReachableByName
+ @discussion Determines if the given network host/node name is
+ reachable using the current network configuration.
+ @param nodename Pass a node name of the desired host. This name would
+ be the same as that passed to gethostbyname() or getaddrinfo().
+ @param flags A pointer to memory which will be filled with a
+ set of SCNConnectionFlags related to the reachability
+ of the specified address. If NULL, no flags will be
+ returned.
+ @param status A pointer to memory which will be filled with the
+ error status associated with any error communicating with
+ the system configuration daemon.
+ @result A constant of type SCNStatus indicating the reachability
+ of the specified node address.
+ */
+SCNStatus SCNIsReachableByName (const char *nodename,
+ int *flags,
+ const char **errorMessage);
+
+__END_DECLS
+
+#endif /* _SCPNETWORK_H */
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SystemConfiguration.h>
+#include "SCPPrivate.h"
+
+#include <fcntl.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+
+
+static const struct scp_errmsg {
+ SCPStatus status;
+ char *message;
+} scp_errmsgs[] = {
+ { SCP_OK, "Success!" },
+ { SCP_BUSY, "Configuration daemon busy" },
+ { SCP_NEEDLOCK, "Lock required for this operation" },
+ { SCP_EACCESS, "Permission denied (must be root to obtain lock)" },
+ { SCP_ENOENT, "Configuration file not found" },
+ { SCP_BADCF, "Configuration file corrupt" },
+ { SCP_NOKEY, "No such key" },
+ { SCP_NOLINK, "No such link" },
+ { SCP_EXISTS, "Key already defined" },
+ { SCP_STALE, "Write attempted on stale version of object" },
+ { SCP_INVALIDARGUMENT, "Invalid argument" },
+ { SCP_FAILED, "Failed!" }
+};
+#define nSCP_ERRMSGS (sizeof(scp_errmsgs)/sizeof(struct scp_errmsg))
+
+
+__private_extern__ CFDataRef
+_SCPSignatureFromStatbuf(const struct stat *statBuf)
+{
+ CFMutableDataRef signature;
+ SCPSignatureDataRef sig;
+
+ signature = CFDataCreateMutable(NULL, sizeof(SCPSignatureData));
+ CFDataSetLength(signature, sizeof(SCPSignatureData));
+ sig = (SCPSignatureDataRef)CFDataGetBytePtr(signature);
+ sig->st_dev = statBuf->st_dev;
+ sig->st_ino = statBuf->st_ino;
+ sig->st_mtimespec = statBuf->st_mtimespec;
+ sig->st_size = statBuf->st_size;
+ return signature;
+}
+
+
+__private_extern__ char *
+_SCPPrefsPath(CFStringRef prefsID, boolean_t perUser, CFStringRef user)
+{
+ CFStringRef path = NULL;
+ int pathLen;
+ char *pathStr;
+
+ if (perUser) {
+ if (prefsID == NULL) {
+ /* no user prefsID specified */
+ return NULL;
+ } else if (CFStringHasPrefix(prefsID, CFSTR("/"))) {
+ /* if absolute path */
+ path = CFRetain(prefsID);
+ } else {
+ /*
+ * relative (to the user's preferences) path
+ */
+ char login[MAXLOGNAME+1];
+ struct passwd *pwd;
+
+ bzero(&login, sizeof(login));
+ if (user == NULL) {
+ /* get current console user */
+ if (SCDConsoleUserGet(login,
+ MAXLOGNAME,
+ NULL,
+ NULL) != SCD_OK) {
+ /* if could not get console user */
+ return NULL;
+ }
+ } else {
+ /* use specified user */
+ (void)CFStringGetBytes(user,
+ CFRangeMake(0, CFStringGetLength(user)),
+ kCFStringEncodingMacRoman,
+ 0,
+ FALSE,
+ login,
+ MAXLOGNAME,
+ NULL);
+ }
+
+ /* get password entry for user */
+ pwd = getpwnam(login);
+ if (pwd == NULL) {
+ /* if no home directory */
+ return NULL;
+ }
+
+ /* create prefs ID */
+ path = CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%s/%@/%@"),
+ pwd->pw_dir,
+ PREFS_DEFAULT_USER_DIR,
+ prefsID);
+ }
+ } else {
+ if (prefsID == NULL) {
+ /* default preference ID */
+ path = CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@/%@"),
+ PREFS_DEFAULT_DIR,
+ PREFS_DEFAULT_CONFIG);
+ } else if (CFStringHasPrefix(prefsID, CFSTR("/"))) {
+ /* if absolute path */
+ path = CFRetain(prefsID);
+ } else {
+ /* relative path */
+ path = CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@/%@"),
+ PREFS_DEFAULT_DIR,
+ prefsID);
+ }
+ }
+
+ /*
+ * convert CFStringRef path to C-string path
+ */
+ pathLen = CFStringGetLength(path) + 1;
+ pathStr = CFAllocatorAllocate(NULL, pathLen, 0);
+ if (!CFStringGetCString(path,
+ pathStr,
+ pathLen,
+ kCFStringEncodingMacRoman)) {
+ SCDLog(LOG_DEBUG, CFSTR("could not convert path to C string"));
+ CFAllocatorDeallocate(NULL, pathStr);
+ pathStr = NULL;
+ }
+
+ CFRelease(path);
+ return pathStr;
+}
+
+
+SCPStatus
+SCPGetSignature(SCPSessionRef session, CFDataRef *signature)
+{
+ SCPSessionPrivateRef sessionPrivate;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ *signature = sessionPrivate->signature;
+ return SCP_OK;
+}
+
+
+__private_extern__ CFStringRef
+_SCPNotificationKey(CFStringRef prefsID,
+ boolean_t perUser,
+ CFStringRef user,
+ int keyType)
+{
+ CFStringRef key = NULL;
+ char *pathStr;
+ char *typeStr;
+
+ pathStr = _SCPPrefsPath(prefsID, perUser, user);
+ if (pathStr == NULL) {
+ return NULL;
+ }
+
+ /* create notification key */
+ switch (keyType) {
+ case kSCPKeyLock :
+ typeStr = "lock";
+ break;
+ case kSCPKeyCommit :
+ typeStr = "commit";
+ break;
+ case kSCPKeyApply :
+ typeStr = "apply";
+ break;
+ default :
+ typeStr = "?";
+ }
+
+ key = CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@%s:%s"),
+ kSCCacheDomainPrefs,
+ typeStr,
+ pathStr);
+
+ CFAllocatorDeallocate(NULL, pathStr);
+ return key;
+}
+
+
+CFStringRef
+SCPNotificationKeyCreate(CFStringRef prefsID, int keyType)
+{
+ return _SCPNotificationKey(prefsID, FALSE, NULL, keyType);
+}
+
+
+CFStringRef
+SCPUserNotificationKeyCreate(CFStringRef prefsID, CFStringRef user, int keyType)
+{
+ return _SCPNotificationKey(prefsID, TRUE, user, keyType);
+}
+
+
+const char *
+SCPError(SCPStatus status)
+{
+ int i;
+
+ for (i = 0; i < nSCP_ERRMSGS; i++) {
+ if (scp_errmsgs[i].status == status) {
+ return scp_errmsgs[i].message;
+ }
+ }
+ return "(unknown error)";
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCP_H
+#define _SCP_H
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/cdefs.h>
+
+/*!
+ @header SCP.h
+ The SystemConfiguration framework provides access to the data used
+ to configure a running system.
+
+ Specifically, the SCPxxx() API's allow an application to load and
+ store XML configuration data in a controlled manner
+ and provides the necessary notifications to other
+ applications which need to be aware of configuration
+ changes.
+
+ The APIs provided by this framework communicate with the "configd"
+ daemon for any tasks requiring synchronization and/or
+ notification.
+ */
+
+
+/*!
+ @enum SCPStatus
+ @discussion Returned status codes.
+ @constant SCP_OK Success
+ @constant SCP_NOSESSION Preference session not active
+ @constant SCP_BUSY Configuration daemon busy
+ @constant SCD_NEEDLOCK Lock required for this operation
+ @constant SCP_EACCESS Permission denied (must be root to obtain lock)
+ @constant SCP_ENOENT Configuration file not found
+ @constant SCP_BADCF Configuration file corrupt
+ @constant SCD_NOKEY No such key
+ @constant SCD_NOLINK No such link
+ @constant SCP_EXISTS Key already defined
+ @constant SCP_STALE Write attempted on stale version of object
+ @constant SCP_INVALIDARGUMENT Invalid argument
+ @constant SCP_FAILED Generic error
+ */
+typedef enum {
+ SCP_OK = 0, /* Success */
+ SCP_NOSESSION = 1024, /* Preference session not active */
+ SCP_BUSY = 1025, /* Preferences update currently in progress */
+ SCP_NEEDLOCK = 1026, /* Lock required for this operation */
+ SCP_EACCESS = 1027, /* Permission denied */
+ SCP_ENOENT = 1028, /* Configuration file not found */
+ SCP_BADCF = 1029, /* Configuration file corrupt */
+ SCP_NOKEY = 1030, /* No such key */
+ SCP_NOLINK = 1031, /* No such link */
+ SCP_EXISTS = 1032, /* No such key */
+ SCP_STALE = 1033, /* Write attempted on stale version of object */
+ SCP_INVALIDARGUMENT = 1034, /* Invalid argument */
+ SCP_FAILED = 9999 /* Generic error */
+} SCPStatus;
+
+
+/*!
+ @enum SCPOption
+ @discussion Used with the SCP[User]Open() and SCP[User]NotificationKeyCreate()
+ to describe the prefsID CFStringRef argument.
+ @constant kSCPOptionCreatePrefs Specifies that the preferences file should
+ be created if it does not exist.
+ */
+typedef enum {
+ kSCPOpenCreatePrefs = 1, /* create preferences file if not found */
+} SCPOption;
+
+
+/*!
+ @enum SCPKeyType
+ @discussion Used with the SCDList() and SCDNotifierAdd() functions to describe
+ the CFStringRef argument.
+ @constant kSCDKeyLock key used when exclusive access to the stored preferences
+ is obtained or released.
+ @constant kSCDKeyCommit key used when new preferences are committed to the store
+ @constant kSCDKeyApply key used when new preferences are to be applied to the
+ active system configuration.
+ */
+typedef enum {
+ kSCPKeyLock = 1,
+ kSCPKeyCommit = 2,
+ kSCPKeyApply = 3,
+} SCPKeyType;
+
+
+/*!
+ @typedef SCPSessionRef
+ @discussion This is the type of a handle to an open "session" for
+ accessing system configuration preferences.
+ */
+typedef void * SCPSessionRef;
+
+
+__BEGIN_DECLS
+
+/*!
+ @function SCPOpen
+ @discussion Initiates access to the per-system set of configuration
+ preferences.
+
+ This function will ensure that the current state of the prefsID is
+ retrieved (by reading the whole thing into memory, or at least,
+ open()'ing the file and keeping it open)
+ @param session A pointer to memory which will be filled with an
+ SCPSessionRef handle to be used for all subsequent requests.
+ If a session cannot be established, the contents of
+ memory pointed to by this parameter are undefined.
+ @param name Pass a string which describes the name of the calling
+ process.
+ @param prefsID Pass a string which identifies the name of the
+ group of preferences to be accessed/updated. A NULL value
+ specifies the default system configuration preferences.
+ @param options Pass a bitfield of type SCPOpenOption containing
+ one or more flags describing how the preferences should
+ be accessed.
+
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call.
+ */
+SCPStatus SCPOpen (SCPSessionRef *session,
+ CFStringRef name,
+ CFStringRef prefsID,
+ int options);
+
+/*!
+ @function SCPUserOpen
+ @discussion Initiates access to the per-user set of configuration
+ preferences.
+
+ This function will ensure that the current state of the prefsID is
+ retrieved (by reading the whole thing into memory, or at least,
+ open()'ing the file and keeping it open)
+ @param session A pointer to memory which will be filled with an
+ SCPSessionRef handle to be used for all subsequent requests.
+ If a session cannot be established, the contents of
+ memory pointed to by this parameter are undefined.
+ @param name Pass a string which describes the name of the calling
+ process.
+ @param prefsID Pass a string which identifies the name of the
+ group of preferences to be accessed/updated.
+ @param user Pass a string which identifies the user/login who's
+ preferences should be accessed. A NULL value specifies
+ the current console user.
+ @param options Pass a bitfield of type SCPOpenOption containing
+ one or more flags describing how the preferences should
+ be accessed.
+
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call.
+ */
+SCPStatus SCPUserOpen (SCPSessionRef *session,
+ CFStringRef name,
+ CFStringRef prefsID,
+ CFStringRef user,
+ int options);
+
+/*!
+ @function SCPClose
+ @discussion Terminates access to a set of configuration preferences.
+
+ This function frees/closes all allocated/opened resources. Any
+ uncommitted changes are NOT written.
+ @param session Pass a pointer to the SCPSessionRef handle which should
+ be closed.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call.
+ */
+SCPStatus SCPClose (SCPSessionRef *session);
+
+/*!
+ @function SCPLock
+ @discussion Locks access to the configuration preferences.
+
+ This function obtains exclusive access to the configuration
+ preferences associated with this prefsID. Clients attempting
+ to obtain exclusive access the preferences will either receive
+ an SCP_BUSY error or block waiting for the lock to be released.
+ @param session Pass an SCPSessionRef handle which should be used for
+ all API calls.
+ @param wait Pass a boolean flag indicating whether the calling process
+ should block waiting for another process to complete its update
+ operation and release its lock.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_BUSY, SCP_EACCESS, SCP_STALE.
+ */
+SCPStatus SCPLock (SCPSessionRef session,
+ boolean_t wait);
+
+/*!
+ @function SCPCommit
+ @discussion Commits changes made to the configuration preferences to
+ persitent storage.
+
+ This function commits the any changes to permanent storage. An
+ implicit call to SCPLock/SCPUnlock will be made if exclusive
+ access had not been established.
+ @param session Pass an SCPSessionRef handle which should be used for
+ all API calls.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_BUSY, SCP_EACCESS, SCP_STALE.
+ */
+SCPStatus SCPCommit (SCPSessionRef session);
+
+/*!
+ @function SCPApply
+ @discussion Requests that the currently stored configuration
+ preferences be applied to the active configuration.
+ @param session Pass an SCPSessionRef handle which should be used for
+ all API calls.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_EACCESS.
+ */
+SCPStatus SCPApply (SCPSessionRef session);
+
+/*!
+ @function SCPUnlock
+ @discussion Releases exclusive access to the configuration preferences.
+
+ This function releases the exclusive access "lock" fr this prefsID.
+ Other clients will be now be able to establish exclusive access to
+ the preferences.
+ @param session Pass an SCPSessionRef handle which should be used for
+ all API calls.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call.
+ */
+SCPStatus SCPUnlock (SCPSessionRef session);
+
+/*!
+ @function SCPGetSignature
+ @discussion Returns an sequence of bytes which can be used to determine
+ if the saved configuration preferences have changed.
+ @param session Pass an SCPSessionRef handle which should be used for
+ all API calls.
+ @param signature Pass a pointer to a CFDataRef which will be reflect
+ the signature of the configuration preferences at the time
+ of the call to SCPOpen().
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call.
+ */
+SCPStatus SCPGetSignature (SCPSessionRef session,
+ CFDataRef *signature);
+
+/*!
+ @function SCPList
+ @discussion Returns an array of currently defined preference keys.
+ @param session Pass an SCPSessionRef handle which should be used for
+ all API calls.
+ @param keys Pass a pointer to a CFArrayRef which will be set to a new
+ array of currently defined preference keys.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call.
+ */
+SCPStatus SCPList (SCPSessionRef session,
+ CFArrayRef *keys);
+
+/*!
+ @function SCPGet
+ @discussion Returns the data associated with a preference key.
+
+ This function retrieves data associated with a key for the prefsID.
+ You "could" read stale data and not know it, unless you first call
+ SCPLock().
+ @param session Pass an SCPSessionRef handle which should be used for
+ all API calls.
+ @param key Pass a reference to the preference key to be returned.
+ @param data Pass a pointer to a CFPropertyListRef which will be set to a
+ new object containing the data associated with the
+ configuration preference.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_NOKEY.
+ */
+SCPStatus SCPGet (SCPSessionRef session,
+ CFStringRef key,
+ CFPropertyListRef *data);
+
+/*!
+ @function SCPAdd
+ @discussion Adds data for a preference key.
+
+ This function associates new data with the specified key. In order
+ to commit these changes to permanent storage a call must be made to
+ SCDPCommit().
+ @param session Pass the SCPSessionRef handle which should be used to
+ communicate with the APIs.
+ @param key Pass a reference to the preference key to be updated.
+ @param data Pass a reference to the CFPropertyListRef object containing the
+ data to be associated with the configuration preference.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_EXISTS.
+ */
+SCPStatus SCPAdd (SCPSessionRef session,
+ CFStringRef key,
+ CFPropertyListRef data);
+
+/*!
+ @function SCPSet
+ @discussion Updates the data associated with a preference key.
+
+ This function creates (or updates) the data associated with the
+ specified key. In order to commit these changes to permanent
+ storage a call must be made to SCDPCommit().
+ @param session Pass the SCPSessionRef handle which should be used to
+ communicate with the APIs.
+ @param key Pass a reference to the preference key to be updated.
+ @param data Pass a reference to the CFPropertyListRef object containing the
+ data to be associated with the configuration preference.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK.
+ */
+SCPStatus SCPSet (SCPSessionRef session,
+ CFStringRef key,
+ CFPropertyListRef data);
+
+/*!
+ @function SCPRemove
+ @discussion Removes the data associated with a preference key.
+
+ This function removes the data associated with the specified
+ key. In order to commit these changes to permanent storage a
+ call must be made to SCDPCommit().
+ @param session Pass the SCPSessionRef handle which should be used to
+ communicate with the APIs.
+ @param key Pass a reference to the preference key to be removed.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_NOKEY.
+ */
+SCPStatus SCPRemove (SCPSessionRef session,
+ CFStringRef key);
+
+/*!
+ @function SCPNotificationKeyCreate
+ @discussion Creates a key which can be used by the SCDNotifierAdd()
+ function to receive notifications of changes to the saved
+ preferences.
+ @param prefsID Pass a string which identifies the name of the
+ preferences to be accessed/updated. A NULL value specifies
+ the default system configuration preferences.
+ @param keyType Pass a kSCPKeyType indicating the type a notification
+ key to be returned.
+ @result A notification string for the specified preference identifier.
+ */
+CFStringRef SCPNotificationKeyCreate (CFStringRef prefsID,
+ int keyType);
+
+/*!
+ @function SCPUserNotificationKeyCreate
+ @discussion Creates a key which can be used by the SCDNotifierAdd()
+ function to receive notifications of changes to the saved
+ preferences.
+ @param prefsID Pass a string which identifies the name of the
+ preferences to be accessed/updated. A NULL value specifies
+ the default system configuration preferences.
+ @param user Pass a string which identifies the user/login who's
+ preferences should be accessed. A NULL value specifies
+ the current console user.
+ @param keyType Pass a kSCPKeyType indicating the type a notification
+ key to be returned.
+ @result A notification string for the specified preference identifier.
+ */
+CFStringRef SCPUserNotificationKeyCreate (CFStringRef prefsID,
+ CFStringRef user,
+ int keyType);
+
+/*!
+ @function SCPError
+ @discussion
+ @param status
+ @result
+ */
+const char * SCPError (SCPStatus status);
+
+__END_DECLS
+
+#endif /* _SCP_H */
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+SCPStatus
+SCPAdd(SCPSessionRef session, CFStringRef key, CFPropertyListRef data)
+{
+ SCPSessionPrivateRef sessionPrivate;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ if (CFDictionaryContainsKey(sessionPrivate->prefs, key)) {
+ return SCP_EXISTS;
+ }
+
+ CFDictionaryAddValue(sessionPrivate->prefs, key, data);
+ sessionPrivate->changed = TRUE;
+ return SCP_OK;
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+SCPStatus
+SCPApply(SCPSessionRef session)
+{
+ SCPSessionPrivateRef sessionPrivate;
+ SCPStatus scp_status = SCP_OK;
+ SCDStatus scd_status;
+ boolean_t wasLocked;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ /*
+ * Determine if the we have exclusive access to the preferences
+ * and acquire the lock if necessary.
+ */
+ wasLocked = sessionPrivate->locked;
+ if (!wasLocked) {
+ scp_status = SCPLock(session, TRUE);
+ if (scp_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" SCPLock(): %s"), SCPError(scp_status));
+ return scp_status;
+ }
+ }
+
+ if (!sessionPrivate->isRoot) {
+ /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
+ goto notRoot;
+ }
+
+ /* if necessary, create the session "apply" key */
+ if (sessionPrivate->sessionKeyApply == NULL) {
+ sessionPrivate->sessionKeyApply = _SCPNotificationKey(sessionPrivate->prefsID,
+ sessionPrivate->perUser,
+ sessionPrivate->user,
+ kSCPKeyApply);
+ }
+
+ /* post notification */
+ scd_status = SCDLock(sessionPrivate->session);
+ if (scd_status == SCD_OK) {
+ (void) SCDTouch (sessionPrivate->session, sessionPrivate->sessionKeyApply);
+ (void) SCDRemove(sessionPrivate->session, sessionPrivate->sessionKeyApply);
+ (void) SCDUnlock(sessionPrivate->session);
+ } else {
+ SCDLog(LOG_DEBUG, CFSTR(" SCDLock(): %s"), SCDError(scd_status));
+ scp_status = SCP_FAILED;
+ }
+
+ notRoot:
+
+ if (!wasLocked)
+ (void) SCPUnlock(session);
+
+ return scp_status;
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+SCPStatus
+SCPClose(SCPSessionRef *session)
+{
+ SCPSessionPrivateRef sessionPrivate;
+
+ if ((session == NULL) || (*session == NULL)) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)*session;
+
+ /* release resources */
+ if (sessionPrivate->name) CFRelease(sessionPrivate->name);
+ if (sessionPrivate->prefsID) CFRelease(sessionPrivate->prefsID);
+ if (sessionPrivate->user) CFRelease(sessionPrivate->user);
+ if (sessionPrivate->path) CFAllocatorDeallocate(NULL, sessionPrivate->path);
+ if (sessionPrivate->signature) CFRelease(sessionPrivate->signature);
+ if (sessionPrivate->session) {
+ SCDStatus scd_status;
+
+ scd_status = SCDClose(&sessionPrivate->session);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDClose() failed: %s"), SCDError(scd_status));
+ }
+ }
+ if (sessionPrivate->sessionKeyLock) CFRelease(sessionPrivate->sessionKeyLock);
+ if (sessionPrivate->sessionKeyCommit) CFRelease(sessionPrivate->sessionKeyCommit);
+ if (sessionPrivate->sessionKeyApply) CFRelease(sessionPrivate->sessionKeyApply);
+ if (sessionPrivate->prefs) CFRelease(sessionPrivate->prefs);
+
+ /* release session */
+ CFAllocatorDeallocate(NULL, sessionPrivate);
+ *session = NULL;
+ return SCP_OK;
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+SCPStatus
+SCPCommit(SCPSessionRef session)
+{
+ SCPSessionPrivateRef sessionPrivate;
+ SCPStatus scp_status = SCP_OK;
+ SCDStatus scd_status;
+ boolean_t wasLocked;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ /*
+ * Determine if the we have exclusive access to the preferences
+ * and acquire the lock if necessary.
+ */
+ wasLocked = sessionPrivate->locked;
+ if (!wasLocked) {
+ scp_status = SCPLock(session, TRUE);
+ if (scp_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" SCPLock(): %s"), SCPError(scp_status));
+ return scp_status;
+ }
+ }
+
+ /*
+ * if necessary, apply changes
+ */
+ if (sessionPrivate->changed) {
+ struct stat statBuf;
+ int pathLen;
+ char *newPath;
+ int fd;
+ CFDataRef newPrefs;
+
+ if (stat(sessionPrivate->path, &statBuf) == -1) {
+ if (errno == ENOENT) {
+ bzero(&statBuf, sizeof(statBuf));
+ statBuf.st_mode = 0644;
+ statBuf.st_uid = geteuid();
+ statBuf.st_gid = getegid();
+ } else {
+ SCDLog(LOG_DEBUG, CFSTR("stat() failed: %s"), strerror(errno));
+ scp_status = SCP_FAILED;
+ goto done;
+ }
+ }
+
+ /* create the (new) preferences file */
+ pathLen = strlen(sessionPrivate->path) + sizeof("-new");
+ newPath = CFAllocatorAllocate(NULL, pathLen, 0);
+ snprintf(newPath, pathLen, "%s-new", sessionPrivate->path);
+
+ /* open the (new) preferences file */
+ reopen :
+ fd = open(newPath, O_WRONLY|O_CREAT, statBuf.st_mode);
+ if (fd == -1) {
+ if ((errno == ENOENT) &&
+ ((sessionPrivate->prefsID == NULL) || !CFStringHasPrefix(sessionPrivate->prefsID, CFSTR("/")))) {
+ char *ch;
+
+ ch = strrchr(newPath, '/');
+ if (ch != NULL) {
+ int status;
+
+ *ch = '\0';
+ status = mkdir(newPath, 0755);
+ *ch = '/';
+ if (status == 0) {
+ goto reopen;
+ }
+ }
+ }
+ SCDLog(LOG_DEBUG, CFSTR("SCPCommit open() failed: %s"), strerror(errno));
+ CFAllocatorDeallocate(NULL, newPath);
+ scp_status = SCP_FAILED;
+ goto done;
+ }
+
+ /* preserve permissions */
+ (void)fchown(fd, statBuf.st_uid, statBuf.st_gid);
+
+ /* write the new preferences */
+ newPrefs = CFPropertyListCreateXMLData(NULL, sessionPrivate->prefs);
+ (void) write(fd, CFDataGetBytePtr(newPrefs), CFDataGetLength(newPrefs));
+ (void) close(fd);
+ CFRelease(newPrefs);
+
+ /* rename new->old */
+ if (rename(newPath, sessionPrivate->path) == -1) {
+ SCDLog(LOG_DEBUG, CFSTR("rename() failed: %s"), strerror(errno));
+ CFAllocatorDeallocate(NULL, newPath);
+ scp_status = SCP_FAILED;
+ goto done;
+ }
+ CFAllocatorDeallocate(NULL, newPath);
+
+ /* update signature */
+ if (stat(sessionPrivate->path, &statBuf) == -1) {
+ SCDLog(LOG_DEBUG, CFSTR("stat() failed: %s"), strerror(errno));
+ scp_status = SCP_FAILED;
+ goto done;
+ }
+ CFRelease(sessionPrivate->signature);
+ sessionPrivate->signature = _SCPSignatureFromStatbuf(&statBuf);
+ }
+
+ if (!sessionPrivate->isRoot) {
+ /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
+ goto done;
+ }
+
+ /* if necessary, create the session "commit" key */
+ if (sessionPrivate->sessionKeyCommit == NULL) {
+ sessionPrivate->sessionKeyCommit = _SCPNotificationKey(sessionPrivate->prefsID,
+ sessionPrivate->perUser,
+ sessionPrivate->user,
+ kSCPKeyCommit);
+ }
+
+ /* post notification */
+ scd_status = SCDLock(sessionPrivate->session);
+ if (scd_status == SCD_OK) {
+ (void) SCDTouch (sessionPrivate->session, sessionPrivate->sessionKeyCommit);
+ (void) SCDRemove(sessionPrivate->session, sessionPrivate->sessionKeyCommit);
+ (void) SCDUnlock(sessionPrivate->session);
+ } else {
+ SCDLog(LOG_DEBUG, CFSTR(" SCDLock(): %s"), SCDError(scd_status));
+ scp_status = SCP_FAILED;
+ }
+
+ done :
+
+ if (!wasLocked)
+ (void) SCPUnlock(session);
+
+ sessionPrivate->changed = FALSE;
+
+ return scp_status;
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+SCPStatus
+SCPGet(SCPSessionRef session, CFStringRef key, CFPropertyListRef *data)
+{
+ SCPSessionPrivateRef sessionPrivate;
+ CFPropertyListRef val;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ val = CFDictionaryGetValue(sessionPrivate->prefs, key);
+ if (val == NULL) {
+ return SCP_NOKEY;
+ }
+
+ *data = val;
+ return SCP_OK;
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+static CFComparisonResult
+sort_keys(const void *p1, const void *p2, void *context) {
+ CFStringRef key1 = (CFStringRef)p1;
+ CFStringRef key2 = (CFStringRef)p2;
+ return CFStringCompare(key1, key2, 0);
+}
+
+
+SCPStatus
+SCPList(SCPSessionRef session, CFArrayRef *keys)
+{
+ SCPSessionPrivateRef sessionPrivate;
+ CFIndex prefsCnt;
+ void **prefsKeys;
+ CFArrayRef allKeys;
+ CFMutableArrayRef sortedKeys;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ prefsCnt = CFDictionaryGetCount(sessionPrivate->prefs);
+ prefsKeys = CFAllocatorAllocate(NULL, prefsCnt * sizeof(CFStringRef), 0);
+ CFDictionaryGetKeysAndValues(sessionPrivate->prefs, prefsKeys, NULL);
+ allKeys = CFArrayCreate(NULL, prefsKeys, prefsCnt, &kCFTypeArrayCallBacks);
+ CFAllocatorDeallocate(NULL, prefsKeys);
+
+ sortedKeys = CFArrayCreateMutableCopy(NULL, prefsCnt, allKeys);
+ CFRelease(allKeys);
+ CFArraySortValues(sortedKeys,
+ CFRangeMake(0, prefsCnt),
+ sort_keys,
+ NULL);
+
+ *keys = sortedKeys;
+ return SCP_OK;
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+SCPStatus
+SCPLock(SCPSessionRef session, boolean_t wait)
+{
+ SCPStatus scp_status;
+ SCDStatus scd_status;
+ SCPSessionPrivateRef sessionPrivate;
+ SCDHandleRef handle = NULL;
+ CFDateRef value;
+ CFArrayRef changes;
+ struct stat statBuf;
+ CFDataRef currentSignature;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ if (!sessionPrivate->isRoot) {
+ /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
+ goto notRoot;
+ }
+
+ if (sessionPrivate->session == NULL) {
+ /* open a session */
+ scd_status = SCDOpen(&sessionPrivate->session, sessionPrivate->name);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDOpen() failed: %s"), SCDError(scd_status));
+ return SCP_FAILED;
+ }
+ }
+
+ if (sessionPrivate->sessionKeyLock == NULL) {
+ /* create the session "lock" key */
+ sessionPrivate->sessionKeyLock = _SCPNotificationKey(sessionPrivate->prefsID,
+ sessionPrivate->perUser,
+ sessionPrivate->user,
+ kSCPKeyLock);
+ }
+
+ scd_status = SCDNotifierAdd(sessionPrivate->session,
+ sessionPrivate->sessionKeyLock,
+ 0);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDNotifierAdd() failed: %s"), SCDError(scd_status));
+ scp_status = SCP_FAILED;
+ goto error;
+ }
+
+ handle = SCDHandleInit();
+ value = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
+ SCDHandleSetData(handle, value);
+ CFRelease(value);
+
+ while (TRUE) {
+ /*
+ * Attempt to acquire the lock
+ */
+ scd_status = SCDAddSession(sessionPrivate->session,
+ sessionPrivate->sessionKeyLock,
+ handle);
+ switch (scd_status) {
+ case SCD_OK :
+ scp_status = SCP_OK;
+ goto done;
+ case SCD_EXISTS :
+ if (!wait) {
+ scp_status = SCP_BUSY;
+ goto error;
+ }
+ break;
+ default :
+ SCDLog(LOG_INFO, CFSTR("SCDAddSession() failed: %s"), SCDError(scd_status));
+ scp_status = SCP_FAILED;
+ goto error;
+ }
+
+ /*
+ * Wait for the lock to be released
+ */
+ scd_status = SCDNotifierWait(sessionPrivate->session);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDAddSession() failed: %s"), SCDError(scd_status));
+ scp_status = SCP_FAILED;
+ goto error;
+ }
+ }
+
+ done :
+
+ SCDHandleRelease(handle);
+ handle = NULL;
+
+ scd_status = SCDNotifierRemove(sessionPrivate->session,
+ sessionPrivate->sessionKeyLock,
+ 0);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDNotifierRemove() failed: %s"), SCDError(scd_status));
+ scp_status = SCP_FAILED;
+ goto error;
+ }
+
+ scd_status = SCDNotifierGetChanges(sessionPrivate->session, &changes);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDNotifierGetChanges() failed: %s"), SCDError(scd_status));
+ scp_status = SCP_FAILED;
+ goto error;
+ }
+ CFRelease(changes);
+
+ notRoot:
+
+ /*
+ * Check the signature
+ */
+ if (stat(sessionPrivate->path, &statBuf) == -1) {
+ if (errno == ENOENT) {
+ bzero(&statBuf, sizeof(statBuf));
+ } else {
+ SCDLog(LOG_DEBUG, CFSTR("stat() failed: %s"), strerror(errno));
+ scp_status = SCP_STALE;
+ goto error;
+ }
+ }
+
+ currentSignature = _SCPSignatureFromStatbuf(&statBuf);
+ if (!CFEqual(sessionPrivate->signature, currentSignature)) {
+ CFRelease(currentSignature);
+ scp_status = SCP_STALE;
+ goto error;
+ }
+ CFRelease(currentSignature);
+
+ sessionPrivate->locked = TRUE;
+ return SCD_OK;
+
+ error :
+
+ if (handle) SCDHandleRelease(handle);
+ return scp_status;
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include <SystemConfiguration/SCPPath.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+static SCPStatus
+_SCPOpen(SCPSessionRef *session,
+ CFStringRef name,
+ CFStringRef prefsID,
+ boolean_t perUser,
+ CFStringRef user,
+ int options)
+{
+ SCPStatus scp_status;
+ SCPSessionPrivateRef newSession;
+ int fd = -1;
+ struct stat statBuf;
+ CFMutableDataRef xmlData;
+ CFStringRef xmlError;
+
+ newSession = (SCPSessionPrivateRef)CFAllocatorAllocate(NULL, sizeof(SCPSessionPrivate), 0);
+ newSession->name = NULL;
+ newSession->prefsID = NULL;
+ newSession->perUser = perUser;
+ newSession->user = NULL;
+ newSession->path = NULL;
+ newSession->signature = NULL;
+ newSession->session = NULL;
+ newSession->sessionKeyLock = NULL;
+ newSession->sessionKeyCommit = NULL;
+ newSession->sessionKeyApply = NULL;
+ newSession->prefs = NULL;
+ newSession->changed = FALSE;
+ newSession->locked = FALSE;
+ newSession->isRoot = (geteuid() == 0);
+
+ /*
+ * convert prefsID to path
+ */
+ newSession->path = _SCPPrefsPath(prefsID, perUser, user);
+ if (newSession->path == NULL) {
+ scp_status = SCP_FAILED;
+ goto error;
+ }
+
+ /*
+ * open file
+ */
+ fd = open(newSession->path, O_RDONLY, 0644);
+ if (fd == -1) {
+ char *errmsg = strerror(errno);
+
+ switch (errno) {
+ case ENOENT :
+ if (options & kSCPOpenCreatePrefs) {
+ bzero(&statBuf, sizeof(statBuf));
+ goto create_1;
+ }
+ scp_status = SCP_ENOENT;
+ break;
+ case EACCES :
+ scp_status = SCP_EACCESS;
+ break;
+ default :
+ scp_status = SCP_FAILED;
+ }
+ SCDLog(LOG_DEBUG, CFSTR("open() failed: %s"), errmsg);
+ goto error;
+ }
+
+ /*
+ * check file, create signature
+ */
+ if (fstat(fd, &statBuf) == -1) {
+ SCDLog(LOG_DEBUG, CFSTR("fstat() failed: %s"), strerror(errno));
+ scp_status = SCP_FAILED;
+ goto error;
+ }
+
+ create_1 :
+
+ newSession->signature = _SCPSignatureFromStatbuf(&statBuf);
+
+ if (statBuf.st_size > 0) {
+ /*
+ * extract property list
+ */
+ xmlData = CFDataCreateMutable(NULL, statBuf.st_size);
+ CFDataSetLength(xmlData, statBuf.st_size);
+ if (read(fd, (void *)CFDataGetBytePtr(xmlData), statBuf.st_size) != statBuf.st_size) {
+ SCDLog(LOG_DEBUG, CFSTR("_SCPOpen read(): could not load preference data."));
+ CFRelease(xmlData);
+ xmlData = NULL;
+ if (options & kSCPOpenCreatePrefs) {
+ goto create_2;
+ }
+ scp_status = SCP_BADCF;
+ goto error;
+ }
+
+ /*
+ * load preferences
+ */
+ newSession->prefs = (CFMutableDictionaryRef)
+ CFPropertyListCreateFromXMLData(NULL,
+ xmlData,
+ kCFPropertyListMutableContainers,
+ &xmlError);
+ CFRelease(xmlData);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("_SCPOpen CFPropertyListCreateFromXMLData(): %s"), xmlError);
+ if (options & kSCPOpenCreatePrefs) {
+ goto create_2;
+ }
+ scp_status = SCP_BADCF;
+ goto error;
+ }
+
+ /*
+ * make sure that we've got a dictionary
+ */
+ if (CFGetTypeID(newSession->prefs) != CFDictionaryGetTypeID()) {
+ SCDLog(LOG_DEBUG, CFSTR("_SCPOpen CFGetTypeID(): not a dictionary."));
+ CFRelease(newSession->prefs);
+ newSession->prefs = NULL;
+ if (options & kSCPOpenCreatePrefs) {
+ goto create_2;
+ }
+ scp_status = SCP_BADCF;
+ goto error;
+ }
+ }
+
+ create_2 :
+
+ if (fd != -1) {
+ (void) close(fd);
+ fd = -1;
+ }
+
+ if (newSession->prefs == NULL) {
+ /*
+ * new file, create empty preferences
+ */
+ SCDLog(LOG_DEBUG, CFSTR("_SCPOpen(): creating new dictionary."));
+ newSession->prefs = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ newSession->changed = TRUE;
+ }
+
+ /*
+ * all OK
+ */
+ newSession->name = CFRetain(name);
+ if (prefsID) {
+ newSession->prefsID = CFRetain(prefsID);
+ }
+ newSession->perUser = perUser;
+ if (user) {
+ newSession->user = CFRetain(user);
+ }
+ *session = (SCPSessionRef)newSession;
+ return SCP_OK;
+
+ error :
+
+ if (fd != -1) {
+ (void)close(fd);
+ }
+ (void) SCPClose((SCPSessionRef *)&newSession);
+ return scp_status;
+}
+
+
+SCPStatus
+SCPOpen(SCPSessionRef *session,
+ CFStringRef name,
+ CFStringRef prefsID,
+ int options)
+{
+ return _SCPOpen(session, name, prefsID, FALSE, NULL, options);
+}
+
+
+SCPStatus
+SCPUserOpen(SCPSessionRef *session,
+ CFStringRef name,
+ CFStringRef prefsID,
+ CFStringRef user,
+ int options)
+{
+ return _SCPOpen(session, name, prefsID, TRUE, user, options);
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCD.h>
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+#include <SystemConfiguration/SCPreferences.h>
+#include <SystemConfiguration/SCPPath.h>
+
+static CFArrayRef
+normalizePath(CFStringRef path)
+{
+ CFArrayRef tmpElements;
+ CFMutableArrayRef elements;
+ CFIndex nElements;
+ CFIndex i;
+
+ if (!CFStringHasPrefix(path, CFSTR("/"))) {
+ /* if no root separator */
+ return NULL;
+ }
+
+ tmpElements = CFStringCreateArrayBySeparatingStrings(NULL, path, CFSTR("/"));
+ elements = CFArrayCreateMutableCopy(NULL, 0, tmpElements);
+ CFRelease(tmpElements);
+
+ /* remove empty path components */
+ nElements = CFArrayGetCount(elements);
+ for (i=nElements; i>0; i--) {
+ CFStringRef pathElement;
+
+ pathElement = CFArrayGetValueAtIndex(elements, i-1);
+ if (CFStringGetLength(pathElement) == 0) {
+ CFArrayRemoveValueAtIndex(elements, i-1);
+ nElements--;
+ }
+ }
+
+ if (nElements < 1) {
+ CFRelease(elements);
+ return NULL;
+ }
+
+ return elements;
+}
+
+
+static SCPStatus
+getPath(SCPSessionRef session, CFStringRef path, CFMutableDictionaryRef *entity)
+{
+ CFArrayRef elements;
+ CFIndex i;
+ CFIndex nElements;
+ SCPStatus status;
+ CFMutableDictionaryRef value = NULL;
+
+ if (session == NULL) {
+ return SCP_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ elements = normalizePath(path);
+ if (elements == NULL) {
+ return SCP_NOKEY;
+ }
+
+ /* get preferences key */
+ status = SCPGet(session,
+ CFArrayGetValueAtIndex(elements, 0),
+ (CFPropertyListRef *)&value);
+ if (status != SCP_OK) {
+ goto done;
+ }
+
+ if (CFGetTypeID(value) != CFDictionaryGetTypeID()) {
+ status = SCP_NOKEY;
+ goto done;
+ }
+
+ nElements = CFArrayGetCount(elements);
+ for (i=1; i<nElements; i++) {
+ CFStringRef element;
+
+ element = CFArrayGetValueAtIndex(elements, i);
+ value = (CFMutableDictionaryRef)CFDictionaryGetValue(value, element);
+ if (value == NULL) {
+ /* if (parent) path component does not exist */
+ status = SCP_NOKEY;
+ goto done;
+ }
+
+ if (CFGetTypeID(value) != CFDictionaryGetTypeID()) {
+ status = SCP_NOKEY;
+ goto done;
+ }
+
+ }
+
+ *entity = value;
+ status = SCP_OK;
+
+ done :
+
+ CFRelease(elements);
+ return status;
+}
+
+
+SCPStatus
+SCPPathCreateUniqueChild(SCPSessionRef session,
+ CFStringRef prefix,
+ CFStringRef *newPath)
+{
+ SCPStatus status;
+ CFMutableDictionaryRef value;
+ boolean_t newValue = FALSE;
+ CFIndex i;
+ CFStringRef path;
+ CFMutableDictionaryRef newDict;
+
+ if (session == NULL) {
+ return SCP_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ status = getPath(session, prefix, &value);
+ switch (status) {
+ case SCP_OK :
+ break;
+ case SCP_NOKEY :
+ value = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ newValue = TRUE;
+ break;
+ default :
+ return status;
+ }
+
+ if (CFGetTypeID(value) != CFDictionaryGetTypeID()) {
+ /* if specified path is not a dictionary */
+ status = SCP_NOKEY;
+ goto done;
+ }
+
+ if (CFDictionaryContainsKey(value, kSCResvLink)) {
+ /* the path is a link... */
+ status = SCP_FAILED;
+ goto done;
+ }
+
+ i = 0;
+ while (TRUE) {
+ CFStringRef pathComponent;
+ Boolean found;
+
+ pathComponent = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), i);
+ found = CFDictionaryContainsKey(value, pathComponent);
+ CFRelease(pathComponent);
+
+ if (!found) {
+ /* if we've identified the next unique key */
+ path = CFStringCreateWithFormat(NULL,
+ NULL,
+ CFSTR("%@/%i"),
+ prefix,
+ i);
+ break;
+ }
+ i++;
+ }
+
+ /* save the new dictionary */
+ newDict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ status = SCPPathSetValue(session, path, newDict);
+ CFRelease(newDict);
+ if (status != SCP_OK) {
+ CFRelease(path);
+ goto done;
+ }
+
+ *newPath = path;
+
+ done :
+
+ if (newValue) CFRelease(value);
+ return status;
+}
+
+
+SCPStatus
+SCPPathGetValue(SCPSessionRef session,
+ CFStringRef path,
+ CFDictionaryRef *value)
+{
+ SCPStatus status;
+ CFMutableDictionaryRef entity;
+ CFStringRef entityLink;
+
+ if (session == NULL) {
+ return SCP_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ status = getPath(session, path, &entity);
+ if (status != SCP_OK) {
+ return status;
+ }
+
+/* XXXX Add code here to chase multiple links XXXXX */
+
+ if ((CFGetTypeID(entity) == CFDictionaryGetTypeID()) &&
+ (CFDictionaryGetValueIfPresent(entity, kSCResvLink, (void **)&entityLink))) {
+ /* if this is a dictionary AND it is a link */
+ status = getPath(session, entityLink, &entity);
+ if (status != SCP_OK) {
+ /* if it was a bad link */
+ return status;
+ }
+ }
+
+ *value = entity;
+ return status;
+}
+
+
+SCPStatus
+SCPPathGetLink(SCPSessionRef session,
+ CFStringRef path,
+ CFStringRef *link)
+{
+ SCPStatus status;
+ CFMutableDictionaryRef entity;
+ CFStringRef entityLink;
+
+ if (session == NULL) {
+ return SCP_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ status = getPath(session, path, &entity);
+ if (status != SCP_OK) {
+ return status;
+ }
+
+ if ((CFGetTypeID(entity) == CFDictionaryGetTypeID()) &&
+ (CFDictionaryGetValueIfPresent(entity, kSCResvLink, (void **)&entityLink))) {
+ /* if this is a dictionary AND it is a link */
+ *link = entityLink;
+ return status;
+ }
+
+ return SCP_NOKEY;
+}
+
+
+SCPStatus
+SCPPathSetValue(SCPSessionRef session, CFStringRef path, CFDictionaryRef value)
+{
+ CFMutableDictionaryRef element;
+ CFArrayRef elements = NULL;
+ CFIndex i;
+ CFIndex nElements;
+ boolean_t newRoot = FALSE;
+ CFMutableDictionaryRef root = NULL;
+ SCPStatus status = SCP_NOKEY;
+
+ if (session == NULL) {
+ return SCP_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ elements = normalizePath(path);
+ if (elements == NULL) {
+ return SCP_NOKEY;
+ }
+
+ /* get preferences key */
+ status = SCPGet(session,
+ CFArrayGetValueAtIndex(elements, 0),
+ (CFPropertyListRef *)&root);
+ if (status != SCP_OK) {
+ root = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ newRoot = TRUE;
+ }
+
+ nElements = CFArrayGetCount(elements);
+ if (nElements == 1) {
+ /* if we are only updating the data associated with the preference key */
+ if (newRoot) {
+ CFRelease(root);
+ newRoot = FALSE;
+ }
+ root = (CFMutableDictionaryRef)value;
+ }
+
+ element = root;
+ for (i=1; i<nElements-1; i++) {
+ CFStringRef pathComponent;
+ CFMutableDictionaryRef tmpElement;
+
+ pathComponent = CFArrayGetValueAtIndex(elements, i);
+ tmpElement = (void *)CFDictionaryGetValue(element, pathComponent);
+ if (tmpElement == NULL) {
+ /* if (parent) path component does not exist */
+ tmpElement = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFDictionarySetValue(element, pathComponent, tmpElement);
+ CFRelease(tmpElement);
+ }
+ element = tmpElement;
+ }
+
+ if (nElements > 1) {
+ CFDictionarySetValue(element,
+ CFArrayGetValueAtIndex(elements, nElements-1),
+ value);
+ }
+ status = SCPSet(session, CFArrayGetValueAtIndex(elements, 0), root);
+
+ if (newRoot) CFRelease(root);
+ CFRelease(elements);
+ return status;
+}
+
+
+SCPStatus
+SCPPathSetLink(SCPSessionRef session, CFStringRef path, CFStringRef link)
+{
+ CFMutableDictionaryRef dict;
+ SCPStatus status;
+
+ if (session == NULL) {
+ return SCP_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ dict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ CFDictionaryAddValue(dict, kSCResvLink, link);
+ status = SCPPathSetValue(session, path, dict);
+ CFRelease(dict);
+
+ return status;
+}
+
+
+SCPStatus
+SCPPathRemove(SCPSessionRef session, CFStringRef path)
+{
+ CFMutableDictionaryRef element;
+ CFArrayRef elements = NULL;
+ CFIndex i;
+ CFIndex nElements;
+ CFMutableDictionaryRef root = NULL;
+ SCPStatus status = SCP_NOKEY;
+
+ if (session == NULL) {
+ return SCP_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ elements = normalizePath(path);
+ if (elements == NULL) {
+ return SCP_NOKEY;
+ }
+
+ /* get preferences key */
+ status = SCPGet(session,
+ CFArrayGetValueAtIndex(elements, 0),
+ (CFPropertyListRef *)&root);
+ if (status != SCP_OK) {
+ goto done;
+ }
+
+ nElements = CFArrayGetCount(elements);
+ if (nElements == 1) {
+ /* if we are removing the data associated with the preference key */
+ status = SCPRemove(session, CFArrayGetValueAtIndex(elements, 0));
+ goto done;
+ }
+
+ element = root;
+ for (i=1; i<nElements-1; i++) {
+ CFStringRef pathComponent;
+ CFMutableDictionaryRef tmpElement;
+
+ pathComponent = CFArrayGetValueAtIndex(elements, i);
+ tmpElement = (void *)CFDictionaryGetValue(element, pathComponent);
+ if (tmpElement == NULL) {
+ status = SCP_NOKEY;
+ goto done;
+ }
+ element = tmpElement;
+ }
+
+ CFDictionaryRemoveValue(element,
+ CFArrayGetValueAtIndex(elements, nElements-1));
+ status = SCPSet(session, CFArrayGetValueAtIndex(elements, 0), root);
+
+ done :
+
+ CFRelease(elements);
+ return status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCPPATH_H
+#define _SCPPATH_H
+
+#include <CoreFoundation/CoreFoundation.h>
+#include <sys/cdefs.h>
+
+/*!
+ @header SCPPath.h
+ The SystemConfiguration framework provides access to the data used
+ to configure a running system.
+
+ Specifically, the SCPPathXXX() API's allow an application to
+ load and store XML configuration data in a controlled
+ manner and provides the necessary notifications to other
+ applications which need to be aware of configuration
+ changes.
+
+ The SCPPathXXX() API's make certain assumptions about the layout
+ of the preferences data. These APIs view the data as a
+ collection of dictionaries of key/value pairs and an
+ associated path name. The root path ("/") identifies
+ the top-level dictionary. Additional path components
+ specify the keys for sub-dictionaries.
+
+ For example, the following dictionary can be access via
+ two paths. The root ("/") path would return a property
+ list with all keys and values. The path "/path1" would
+ only return the dictionary with the "key3" and "key4"
+ properties.
+
+ <dict>
+ <key>key1</key>
+ <string>val1</string>
+ <key>key2</key>
+ <string>val2</string>
+ <key>path1</key>
+ <dict>
+ <key>key3</key>
+ <string>val3</string>
+ <key>key4</key>
+ <string>val4</string>
+ </dict>
+ </dict>
+
+ The APIs provided by this framework communicate with the "configd"
+ daemon for any tasks requiring synchronization and/or
+ notification.
+ */
+
+
+__BEGIN_DECLS
+
+/*!
+ @function SCPPathCreateUniqueChild
+ @discussion Creates a new path component within the dictionary
+ hierarchy.
+ @param session Pass the SCPSessionRef handle which should be used to
+ communicate with the APIs.
+ @param prefix Pass a string which represents the parent path.
+ @param newPath A pointer to memory which will be filled with an
+ string representing the new child path.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_NOKEY.
+ */
+SCPStatus SCPPathCreateUniqueChild (SCPSessionRef session,
+ CFStringRef prefix,
+ CFStringRef *newPath);
+
+/*!
+ @function SCPPathGetValue
+ @discussion Returns the dictionary associated with the specified
+ path.
+ @param session Pass the SCPSessionRef handle which should be used to
+ communicate with the APIs.
+ @param path Pass a string whcih represents the path to be returned.
+ @param value A pointer to memory which will be filled with an
+ dictionary associated with the specified path.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_NOKEY.
+ */
+SCPStatus SCPPathGetValue (SCPSessionRef session,
+ CFStringRef path,
+ CFDictionaryRef *value);
+
+/*!
+ @function SCPPathGetLink
+ @discussion Returns the link (if one exists) associatd with the
+ specified path.
+ @param session Pass the SCPSessionRef handle which should be used to
+ communicate with the APIs.
+ @param path Pass a string whcih represents the path to be returned.
+ @param link A pointer to memory which will be filled with a
+ string reflecting the link found at the specified path.
+ If no link was present at the specified path a status
+ value of SCP_NOKEY will be returned.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_NOKEY.
+ */
+SCPStatus SCPPathGetLink (SCPSessionRef session,
+ CFStringRef path,
+ CFStringRef *link);
+
+/*!
+ @function SCPPathSetValue
+ @discussion Associates a dictionary with the specified path.
+ @param session Pass the SCPSessionRef handle which should be used to
+ communicate with the APIs.
+ @param path Pass a string whcih represents the path to be returned.
+ @param value Pass a dictionary which represents the data to be
+ stored at the specified path.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK.
+ */
+SCPStatus SCPPathSetValue (SCPSessionRef session,
+ CFStringRef path,
+ CFDictionaryRef value);
+
+/*!
+ @function SCPPathSetLink
+ @discussion Associates a link to a second dictionary at the
+ specified path.
+ @param session Pass the SCPSessionRef handle which should be used to
+ communicate with the APIs.
+ @param path Pass a string whcih represents the path to be returned.
+ @param value Pass a string which represents the path to be stored
+ at the specified path.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_NOKEY.
+ */
+SCPStatus SCPPathSetLink (SCPSessionRef session,
+ CFStringRef path,
+ CFStringRef link);
+
+/*!
+ @function SCPPathRemove
+ @discussion Removes the data associated with the specified path.
+ @param session Pass the SCPSessionRef handle which should be used to
+ communicate with the APIs.
+ @param path Pass a string whcih represents the path to be returned.
+ @result A constant of type SCPStatus indicating the success (or
+ failure) of the call. Possible return values include: SCP_OK,
+ SCP_NOKEY.
+ */
+SCPStatus SCPPathRemove (SCPSessionRef session,
+ CFStringRef path);
+
+__END_DECLS
+
+#endif /* _SCPPATH_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SCPPRIVATE_H
+#define _SCPPRIVATE_H
+
+#include <SystemConfiguration/SCP.h>
+#include <SystemConfiguration/SCD.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+
+#define PREFS_DEFAULT_DIR CFSTR("/var/db/SystemConfiguration")
+#define PREFS_DEFAULT_CONFIG CFSTR("preferences.xml")
+
+#define PREFS_DEFAULT_USER_DIR CFSTR("Library/Preferences")
+
+
+/* Define the per-preference-handle structure */
+typedef struct {
+ /* session name */
+ CFStringRef name;
+
+ /* preferences ID */
+ CFStringRef prefsID;
+
+ /* per-user preference info */
+ boolean_t perUser;
+ CFStringRef user;
+
+ /* configuration file path */
+ char *path;
+
+ /* configuration file signature */
+ CFDataRef signature;
+
+ /* configd session */
+ SCDSessionRef session;
+
+ /* configd session keys */
+ CFStringRef sessionKeyLock;
+ CFStringRef sessionKeyCommit;
+ CFStringRef sessionKeyApply;
+
+ /* preferences */
+ CFMutableDictionaryRef prefs;
+
+ /* flags */
+ boolean_t changed;
+ boolean_t locked;
+ boolean_t isRoot;
+
+} SCPSessionPrivate, *SCPSessionPrivateRef;
+
+
+/* Define signature data */
+typedef struct {
+ dev_t st_dev; /* inode's device */
+ ino_t st_ino; /* inode's number */
+ struct timespec st_mtimespec; /* time of last data modification */
+ off_t st_size; /* file size, in bytes */
+} SCPSignatureData, *SCPSignatureDataRef;
+
+
+__BEGIN_DECLS
+
+CFDataRef _SCPSignatureFromStatbuf (const struct stat *statBuf);
+
+char * _SCPPrefsPath (CFStringRef prefsID,
+ boolean_t perUser,
+ CFStringRef user);
+
+CFStringRef _SCPNotificationKey (CFStringRef prefsID,
+ boolean_t perUser,
+ CFStringRef user,
+ int keyType);
+
+__END_DECLS
+
+#endif /* _SCPPRIVATE_H */
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+SCPStatus
+SCPRemove(SCPSessionRef session, CFStringRef key)
+{
+ SCPSessionPrivateRef sessionPrivate;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ if (!CFDictionaryContainsKey(sessionPrivate->prefs, key)) {
+ return SCP_NOKEY;
+ }
+
+ CFDictionaryRemoveValue(sessionPrivate->prefs, key);
+ sessionPrivate->changed = TRUE;
+ return SCP_OK;
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+SCPStatus
+SCPSet(SCPSessionRef session, CFStringRef key, CFPropertyListRef data)
+{
+ SCPSessionPrivateRef sessionPrivate;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ CFDictionarySetValue(sessionPrivate->prefs, key, data);
+ sessionPrivate->changed = TRUE;
+ return SCP_OK;
+}
--- /dev/null
+/*
+ * Copyright(c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1(the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SCP.h>
+#include "SCPPrivate.h"
+
+#include <SystemConfiguration/SCD.h>
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/errno.h>
+
+
+SCPStatus
+SCPUnlock(SCPSessionRef session)
+{
+ SCPSessionPrivateRef sessionPrivate;
+ SCDStatus scd_status;
+
+ if (session == NULL) {
+ return SCP_FAILED; /* you can't do anything with a closed session */
+ }
+ sessionPrivate = (SCPSessionPrivateRef)session;
+
+ if (!sessionPrivate->locked) {
+ return SCP_NEEDLOCK; /* sorry, you don't have the lock */
+ }
+
+ if (!sessionPrivate->isRoot) {
+ /* CONFIGD REALLY NEEDS NON-ROOT WRITE ACCESS */
+ goto notRoot;
+ }
+
+ scd_status = SCDRemove(sessionPrivate->session, sessionPrivate->sessionKeyLock);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDRemove() failed: %s"), SCDError(scd_status));
+ return SCP_FAILED;
+ }
+
+ notRoot:
+
+ sessionPrivate->locked = FALSE;
+ return SCP_OK;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SYSTEMCONFIGURATION_H
+#define _SYSTEMCONFIGURATION_H
+
+/*!
+ @header SystemConfiguration.h
+ The SystemConfiguration framework provides access to the data used to configure a running system. The APIs provided by this framework communicate with the "configd" daemon.
+
+The "configd" daemon manages a "cache" reflecting the desired configuration settings as well as the current state of the system. The daemon provides a notification mechanism for user-level processes which need to be aware of changes made to the "cache" data. Lastly, the daemon loads a number of bundles(or plug-ins) which monitor low-level kernel events and, via a set of policy modules, keep this cached data up to date.
+
+The "configd" daemon also provides an address space/task/process which can be used by other CFRunLoop based functions which would otherwise require their own process/daemon for execution.
+
+ */
+
+/* cache access APIs */
+#include <SystemConfiguration/SCD.h>
+#include <SystemConfiguration/SCDKeys.h>
+
+/* preference access APIs */
+#include <SystemConfiguration/SCP.h>
+#include <SystemConfiguration/SCPPath.h>
+#include <SystemConfiguration/SCPreferences.h>
+
+/* "console user" APIs */
+#include <SystemConfiguration/SCDConsoleUser.h>
+
+/* "computer/host name" APIs */
+#include <SystemConfiguration/SCDHostName.h>
+
+/* "network reachability" APIs */
+#include <SystemConfiguration/SCNetwork.h>
+
+#endif /* _SYSTEMCONFIGURATION_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach/std_types.defs>
+#include <mach/mach_types.defs>
+
+subsystem config 20000;
+serverprefix _;
+
+import "config_types.h";
+
+/*
+ * serialized XML data (client->server)
+ */
+type xmlData = ^ array [] of MACH_MSG_TYPE_BYTE
+ ctype : xmlData_t;
+
+/*
+ * serialized XML data (server->client)
+ */
+type xmlDataOut = ^ array [] of MACH_MSG_TYPE_BYTE
+ ctype : xmlDataOut_t;
+
+/*
+ * additional types
+ */
+/*
+type task_move_send_t = MACH_MSG_TYPE_MOVE_SEND
+ ctype: mach_port_t;
+*/
+
+
+/*
+ * Connection management API's
+ */
+
+routine configopen ( server : mach_port_t;
+ name : xmlData;
+ out session : mach_port_move_send_t;
+ out status : int);
+
+routine configclose ( server : mach_port_t;
+ out status : int);
+
+routine configlock ( server : mach_port_t;
+ out status : int);
+
+routine configunlock ( server : mach_port_t;
+ out status : int);
+
+ skip; /* reserved for future use */
+ skip; /* reserved for future use */
+ skip; /* reserved for future use */
+ skip; /* reserved for future use */
+
+/*
+ * Cache access API's
+ */
+
+routine configlist ( server : mach_port_t;
+ xmlData : xmlData;
+ regexOptions : int;
+ out list : xmlDataOut, dealloc;
+ out status : int);
+
+routine configadd ( server : mach_port_t;
+ key : xmlData;
+ data : xmlData;
+ out newInstance : int;
+ out status : int);
+
+routine configget ( server : mach_port_t;
+ key : xmlData;
+ out data : xmlDataOut, dealloc;
+ out newInstance : int;
+ out status : int);
+
+routine configset ( server : mach_port_t;
+ key : xmlData;
+ data : xmlData;
+ instance : int;
+ out newInstance : int;
+ out status : int);
+
+routine configremove ( server : mach_port_t;
+ key : xmlData;
+ out status : int);
+
+routine configtouch ( server : mach_port_t;
+ key : xmlData;
+ out status : int);
+
+routine configadd_s ( server : mach_port_t;
+ key : xmlData;
+ data : xmlData;
+ out newInstance : int;
+ out status : int);
+
+ skip; /* reserved for future use */
+ skip; /* reserved for future use */
+ skip; /* reserved for future use */
+
+/*
+ * Notification API's
+ */
+
+routine notifyadd ( server : mach_port_t;
+ key : xmlData;
+ regexOptions : int;
+ out status : int);
+
+routine notifyremove ( server : mach_port_t;
+ key : xmlData;
+ regexOptions : int;
+ out status : int);
+
+routine notifychanges ( server : mach_port_t;
+ out list : xmlDataOut, dealloc;
+ out status : int);
+
+routine notifyviaport ( server : mach_port_t;
+ port : mach_port_move_send_t;
+ msgid : mach_msg_id_t;
+ out status : int);
+
+routine notifyviafd ( server : mach_port_t;
+ path : xmlData;
+ identifier : int;
+ out status : int);
+
+routine notifyviasignal ( server : mach_port_t;
+ task : task_t /*task_move_send_t*/;
+ sig : int;
+ out status : int);
+
+routine notifycancel ( server : mach_port_t;
+ out status : int);
+
+ skip; /* reserved for future use */
+ skip; /* reserved for future use */
+ skip; /* reserved for future use */
+ skip; /* reserved for future use */
+
+/*
+ * Miscellaneous API's
+ */
+
+routine snapshot ( server : mach_port_t;
+ out status : int);
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _CONFIG_TYPES_H
+#define _CONFIG_TYPES_H
+
+/*
+ * Keep IPC functions private to the framework
+ */
+#ifdef mig_external
+#undef mig_external
+#endif
+#define mig_external __private_extern__
+
+/*
+ * Mach server port name
+ */
+#define SCD_SERVER "System Configuration Server"
+
+/*
+ * Input arguments: serialized key's, list delimiters, ...
+ * (sent as out-of-line data in a message)
+ */
+typedef const char * xmlData_t;
+
+/* Output arguments: serialized data, lists, ...
+ * (sent as out-of-line data in a message)
+ */
+typedef char * xmlDataOut_t;
+
+#endif /* !_CONFIG_TYPES_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * genSCPreferences.c
+ * - generates System Configuration header/cfile
+ * - invoke with "header" to generate the header
+ * - invoke with "cfile" to generate the cfile
+ */
+
+/*
+ * Modification History
+ * 3 Nov 2000 Dieter Siegmund (dieter@apple)
+ * - created
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <mach/boolean.h>
+
+char copyright_string[] =
+"/*\n"
+" * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.\n"
+" *\n"
+" * @APPLE_LICENSE_HEADER_START@\n"
+" * \n"
+" * The contents of this file constitute Original Code as defined in and\n"
+" * are subject to the Apple Public Source License Version 1.1 (the\n"
+" * \"License\"). You may not use this file except in compliance with the\n"
+" * License. Please obtain a copy of the License at\n"
+" * http://www.apple.com/publicsource and read it before using this file.\n"
+" * \n"
+" * This Original Code and all software distributed under the License are\n"
+" * distributed on an \"AS IS\" basis, WITHOUT WARRANTY OF ANY KIND, EITHER\n"
+" * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,\n"
+" * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,\n"
+" * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the\n"
+" * License for the specific language governing rights and limitations\n"
+" * under the License.\n"
+" * \n"
+" * @APPLE_LICENSE_HEADER_END@\n"
+" */\n";
+
+
+#define REGULAR 0
+#define COMMENT 1
+#define END 2
+
+#define STRING_MACRO_NAME "STRING_DECL"
+
+#define KEY_PREFIX "kSC"
+
+#define CACHE "Cache"
+#define COMP "Comp"
+#define PREF "Pref"
+#define PROP "Prop"
+#define PATH "Path"
+#define NETENT "EntNet"
+#define NETPROP "PropNet"
+#define NETVAL "ValNet"
+#define SETUPENT "EntSetup"
+#define SETUPPROP "PropSetup"
+#define SYSTEMENT "EntSystem"
+#define SYSTEMPROP "PropSystem"
+#define RESV "Resv"
+#define USERSENT "EntUsers"
+#define USERSPROP "PropUsers"
+
+#define CFNUMBER "CFNumber"
+#define CFSTRING "CFString"
+#define CFNUMBER_BOOL "CFNumber (0 or 1)"
+#define CFARRAY_CFSTRING "CFArray[CFString]"
+
+#define ACTIVE "Active"
+#define ADDRESSES "Addresses"
+#define AIRPORT "AirPort"
+#define ALERT "Alert"
+#define ANYREGEX "AnyRegex"
+#define AUTOMATIC "Automatic"
+#define APPLETALK "AppleTalk"
+#define AUTH "Auth"
+#define BINDINGMETHODS "BindingMethods"
+#define BOOTP "BOOTP"
+#define BROADCAST "Broadcast"
+#define BROADCASTADDRESSES "BroadcastAddresses"
+#define BROADCASTSERVERTAG "BroadcastServerTag"
+#define COMM "Comm"
+#define COMPONENTSEPARATOR "ComponentSeparator"
+#define COMPUTERNAME "ComputerName"
+#define CONFIGMETHOD "ConfigMethod"
+#define CONSOLEUSER "ConsoleUser"
+#define CURRENTSET "CurrentSet"
+#define DEFAULTSERVERTAG "DefaultServerTag"
+#define DEFAULTZONE "DefaultZone"
+#define DESTADDRESSES "DestAddresses"
+#define DHCP "DHCP"
+#define DHCPCLIENTID "DHCPClientID"
+#define DEVICENAME "DeviceName"
+#define DIALMODE "DialMode"
+#define DNS "DNS"
+#define DOMAIN "Domain"
+#define DOMAINNAME "DomainName"
+#define DOMAINSEPARATOR "DomainSeparator"
+#define DUPLEX "Duplex"
+#define ENCODING "Encoding"
+#define ENCRYPTION "Encryption"
+#define ETHERNET "Ethernet"
+#define EXCEPTIONSLIST "ExceptionsList"
+#define FILE "File"
+#define FTPENABLE "FTPEnable"
+#define FTPPASSIVE "FTPPassive"
+#define FTPPORT "FTPPort"
+#define FTPPROXY "FTPProxy"
+#define GID "GID"
+#define GLOBAL "Global"
+#define GOPHERENABLE "GopherEnable"
+#define GOPHERPORT "GopherPort"
+#define GOPHERPROXY "GopherProxy"
+#define HARDWARE "Hardware"
+#define HTTPENABLE "HTTPEnable"
+#define HTTPPORT "HTTPPort"
+#define HTTPPROXY "HTTPProxy"
+#define INACTIVE "Inactive"
+#define INCLUDEPRIVATENETS "IncludePrivateNets"
+#define INFORM "INFORM"
+#define INTERFACE "Interface"
+#define INTERFACES "Interfaces"
+#define IPCP "IPCP"
+#define IPV4 "IPv4"
+#define IPV6 "IPv6"
+#define LASTUPDATED "LastUpdated"
+#define LCP "LCP"
+#define LINK "Link"
+#define MACADDRESS "MACAddress"
+#define MANUAL "Manual"
+#define MEDIA "Media"
+#define MODEM "Modem"
+#define NAME "Name"
+#define NETINFO "NetInfo"
+#define NETWORK "Network"
+#define NETWORKSERVICES "NetworkServices"
+#define NETWORKID "NetworkID"
+#define NIS "NIS"
+#define NODE "Node"
+#define NODEID "NodeID"
+#define PASSWORD "Password"
+#define PLUGIN "Plugin"
+#define PORTNAME "PortName"
+#define PPP "PPP"
+#define PPPOE "PPPoE"
+#define PPPSERIAL "PPPSerial"
+#define PPPOVERRIDEPRIMARY "PPPOverridePrimary"
+#define PREFS "Prefs"
+#define PRIMARYINTERFACE "PrimaryInterface"
+#define PROTOCOL "Protocol"
+#define PROXIES "Proxies"
+#define ROOTSEPARATOR "RootSeparator"
+#define ROUTER "Router"
+#define RTSPENABLE "RTSPEnable"
+#define RTSPPORT "RTSPPort"
+#define RTSPPROXY "RTSPProxy"
+#define SEARCHDOMAINS "SearchDomains"
+#define SEEDNETWORKRANGE "SeedNetworkRange"
+#define SEEDROUTER "SeedRouter"
+#define SEEDZONES "SeedZones"
+#define SERVICE "Service"
+#define SERVERADDRESSES "ServerAddresses"
+#define SERVERTAGS "ServerTags"
+#define SERVICEORDER "ServiceOrder"
+#define SERVICEIDS "ServiceIDs"
+#define SETS "Sets"
+#define SETUP "Setup"
+#define SPEED "Speed"
+#define STATE "State"
+#define SOCKSENABLE "SOCKSEnable"
+#define SOCKSPORT "SOCKSPort"
+#define SOCKSPROXY "SOCKSProxy"
+#define SUBNETMASKS "SubnetMasks"
+#define SUBTYPE "SubType"
+#define SYSTEM "System"
+#define TYPE "Type"
+#define UID "UID"
+#define USERS "Users"
+#define USERDEFINEDNAME "UserDefinedName"
+#define VERBOSELOGGING "VerboseLogging"
+
+struct {
+ int control;
+ unsigned char * prefix;
+ unsigned char * key;
+ unsigned char * value;
+ unsigned char * type;
+} names[] = {
+ { COMMENT, "/*\n * Reserved Keys\n */", NULL, NULL },
+ { REGULAR, RESV, LINK, "__LINK__", CFSTRING },
+ { REGULAR, RESV, INACTIVE, "__INACTIVE__", NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * Generic Keys\n */", NULL },
+ { REGULAR, PROP, MACADDRESS, NULL, CFSTRING },
+ { REGULAR, PROP, USERDEFINEDNAME, NULL, CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * Preference Keys\n */", NULL },
+ { REGULAR, PREF, CURRENTSET, NULL, NULL },
+ { REGULAR, PREF, HARDWARE, NULL, NULL },
+ { REGULAR, PREF, NETWORKSERVICES, NULL, NULL },
+ { REGULAR, PREF, SETS, NULL, NULL },
+ { REGULAR, PREF, SYSTEM, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * Component Keys\n */", NULL },
+ { REGULAR, COMP, NETWORK, NULL, NULL },
+ { REGULAR, COMP, SERVICE, NULL, NULL },
+ { REGULAR, COMP, GLOBAL, NULL, NULL },
+ { REGULAR, COMP, INTERFACE, NULL, NULL },
+ { REGULAR, COMP, SYSTEM, NULL, NULL },
+ { REGULAR, COMP, USERS, "users", NULL }, /* FIX ME! */
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * Regex key which matches any component\n */", NULL },
+ { REGULAR, COMP, ANYREGEX, "[^/]+", NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * Network Entity Keys\n */", NULL },
+ { REGULAR, NETENT, AIRPORT, NULL, NULL },
+ { REGULAR, NETENT, APPLETALK, NULL, NULL },
+ { REGULAR, NETENT, DNS, NULL, NULL },
+ { REGULAR, NETENT, ETHERNET, NULL, NULL },
+ { REGULAR, NETENT, INTERFACE, NULL, NULL },
+ { REGULAR, NETENT, IPV4, NULL, NULL },
+ { REGULAR, NETENT, IPV6, NULL, NULL },
+ { REGULAR, NETENT, LINK, NULL, NULL },
+ { REGULAR, NETENT, MODEM, NULL, NULL },
+ { REGULAR, NETENT, NETINFO, NULL, NULL },
+ { REGULAR, NETENT, NIS, NULL, NULL },
+ { REGULAR, NETENT, PPP, NULL, NULL },
+ { REGULAR, NETENT, PPPOE, NULL, NULL },
+ { REGULAR, NETENT, PROXIES, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " NETWORK " Properties\n */", NULL },
+ { REGULAR, NETPROP, SERVICEORDER, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETPROP, PPPOVERRIDEPRIMARY, NULL, CFNUMBER_BOOL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " AIRPORT " (Hardware) Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP AIRPORT, "PowerEnabled", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP AIRPORT, AUTH PASSWORD, NULL, CFSTRING },
+ { REGULAR, NETPROP AIRPORT, AUTH PASSWORD ENCRYPTION, NULL, CFSTRING },
+ { REGULAR, NETPROP AIRPORT, "PreferredNetwork", NULL, CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " APPLETALK " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP APPLETALK, COMPUTERNAME, NULL, CFSTRING },
+ { REGULAR, NETPROP APPLETALK, COMPUTERNAME ENCODING, NULL, CFNUMBER },
+ { REGULAR, NETPROP APPLETALK, CONFIGMETHOD, NULL, CFSTRING },
+ { REGULAR, NETPROP APPLETALK, DEFAULTZONE, NULL, CFSTRING },
+ { REGULAR, NETPROP APPLETALK, NETWORKID, NULL, CFNUMBER },
+ { REGULAR, NETPROP APPLETALK, NODEID, NULL, CFNUMBER },
+ { REGULAR, NETPROP APPLETALK, SEEDNETWORKRANGE, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETPROP APPLETALK, SEEDZONES, NULL, CFARRAY_CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+ { COMMENT, "/* " KEY_PREFIX NETPROP APPLETALK CONFIGMETHOD " values */", NULL, NULL, NULL },
+ { REGULAR, NETVAL APPLETALK CONFIGMETHOD, NODE, NULL, NULL },
+ { REGULAR, NETVAL APPLETALK CONFIGMETHOD, ROUTER, NULL, NULL },
+ { REGULAR, NETVAL APPLETALK CONFIGMETHOD, SEEDROUTER, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " DNS " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP DNS, DOMAINNAME, NULL, CFSTRING },
+ { REGULAR, NETPROP DNS, SEARCHDOMAINS, NULL, CFARRAY_CFSTRING},
+ { REGULAR, NETPROP DNS, SERVERADDRESSES, NULL, CFARRAY_CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " ETHERNET " (Hardware) Entity Keys\n */", NULL, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " INTERFACE " Entity Keys\n */", NULL },
+ { REGULAR, NETPROP INTERFACE, DEVICENAME, NULL, CFSTRING },
+ { REGULAR, NETPROP INTERFACE, HARDWARE, NULL, CFSTRING },
+ { REGULAR, NETPROP INTERFACE, TYPE, NULL, CFSTRING },
+ { REGULAR, NETPROP INTERFACE, SUBTYPE, NULL, CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+ { COMMENT, "/* " KEY_PREFIX NETPROP INTERFACE TYPE " values */", NULL, NULL, NULL },
+ { REGULAR, NETVAL INTERFACE TYPE, ETHERNET, NULL, NULL },
+ { REGULAR, NETVAL INTERFACE TYPE, PPP, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+ { COMMENT, "/* " KEY_PREFIX NETPROP SERVICE SUBTYPE " values (for " PPP ") */", NULL, NULL, NULL },
+ { REGULAR, NETVAL INTERFACE SUBTYPE, PPPOE, NULL, NULL },
+ { REGULAR, NETVAL INTERFACE SUBTYPE, PPPSERIAL, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " IPV4 " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP IPV4, ADDRESSES, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETPROP IPV4, CONFIGMETHOD, NULL, CFSTRING },
+ { REGULAR, NETPROP IPV4, DHCPCLIENTID, NULL, CFSTRING },
+ { REGULAR, NETPROP IPV4, ROUTER, NULL, CFSTRING },
+ { REGULAR, NETPROP IPV4, SUBNETMASKS, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETPROP IPV4, DESTADDRESSES, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETPROP IPV4, BROADCASTADDRESSES, NULL, CFARRAY_CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+ { COMMENT, "/* " KEY_PREFIX NETPROP IPV4 CONFIGMETHOD " values */", NULL, NULL, NULL },
+ { REGULAR, NETVAL IPV4 CONFIGMETHOD, BOOTP, NULL, NULL },
+ { REGULAR, NETVAL IPV4 CONFIGMETHOD, DHCP, NULL, NULL },
+ { REGULAR, NETVAL IPV4 CONFIGMETHOD, INFORM, NULL, NULL },
+ { REGULAR, NETVAL IPV4 CONFIGMETHOD, MANUAL, NULL, NULL },
+ { REGULAR, NETVAL IPV4 CONFIGMETHOD, PPP, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " IPV6 " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP IPV6, ADDRESSES, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETPROP IPV6, CONFIGMETHOD, NULL, CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " LINK " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP LINK, ACTIVE, NULL, CFNUMBER_BOOL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " MODEM " (Hardware) Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP MODEM, "ConnectionScript", NULL, CFSTRING },
+ { REGULAR, NETPROP MODEM, DIALMODE, NULL, CFSTRING },
+ { REGULAR, NETPROP MODEM, "PulseDial", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP MODEM, "Speaker", NULL, CFNUMBER_BOOL },
+ { COMMENT, "", NULL, NULL, NULL },
+ { COMMENT, "/* " KEY_PREFIX NETPROP MODEM DIALMODE " values */", NULL, NULL, NULL },
+ { REGULAR, NETVAL MODEM DIALMODE, "IgnoreDialTone", NULL, NULL },
+ { REGULAR, NETVAL MODEM DIALMODE, MANUAL, NULL, NULL },
+ { REGULAR, NETVAL MODEM DIALMODE, "WaitForDialTone", NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " NETINFO " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP NETINFO, BINDINGMETHODS, NULL, CFSTRING },
+ { REGULAR, NETPROP NETINFO, SERVERADDRESSES, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETPROP NETINFO, SERVERTAGS, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETPROP NETINFO, BROADCASTSERVERTAG, NULL, CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+ { COMMENT, "/* " KEY_PREFIX NETPROP NETINFO BINDINGMETHODS " values */", NULL, NULL, NULL },
+ { REGULAR, NETVAL NETINFO BINDINGMETHODS, BROADCAST, NULL, NULL },
+ { REGULAR, NETVAL NETINFO BINDINGMETHODS, DHCP, NULL, NULL },
+ { REGULAR, NETVAL NETINFO BINDINGMETHODS, MANUAL, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+ { COMMENT, "/* " KEY_PREFIX NETPROP NETINFO BROADCASTSERVERTAG " default value */", NULL, NULL, NULL },
+ { REGULAR, NETVAL NETINFO, DEFAULTSERVERTAG, "network", NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " NIS " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP NIS, DOMAINNAME, NULL, CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " PPP " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP PPP, "DialOnDemand", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, "DisconnectOnIdle", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, "DisconnectOnIdleTimer", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, "DisconnectOnLogout", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, "IdleReminderTimer", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, "IdleReminder", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, "Logfile", NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, VERBOSELOGGING, NULL, CFNUMBER_BOOL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/* " AUTH ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP PPP, AUTH NAME, NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, AUTH PASSWORD, NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, AUTH PASSWORD ENCRYPTION, NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, AUTH PROTOCOL, NULL, CFARRAY_CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+ { COMMENT, "/* " KEY_PREFIX NETPROP PPP AUTH PROTOCOL " values */", NULL, NULL, NULL },
+ { REGULAR, NETVAL PPP AUTH PROTOCOL, "CHAP", NULL, CFSTRING },
+ { REGULAR, NETVAL PPP AUTH PROTOCOL, "PAP", NULL, CFSTRING },
+
+ { COMMENT, "\n/* " COMM ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP PPP, COMM "AlternateRemoteAddress", NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, COMM "ConnectDelay", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, COMM "DisplayTerminalWindow", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, COMM "RedialCount", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, COMM "RedialEnabled", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, COMM "RedialInterval", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, COMM "RemoteAddress", NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, COMM "TerminalScript", NULL, CFSTRING },
+
+ { COMMENT, "\n/* " IPCP ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP PPP, IPCP "CompressionVJ", NULL, CFNUMBER_BOOL },
+
+ { COMMENT, "\n/* " LCP ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP PPP, LCP "EchoEnabled", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, LCP "EchoFailure", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, LCP "EchoInterval", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, LCP "CompressionACField", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, LCP "CompressionPField", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, LCP "MRU", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, LCP "MTU", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, LCP "ReceiveACCM", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, LCP "TransmitACCM", NULL, CFNUMBER },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " PPPOE " Entity Keys\n */", NULL, NULL, NULL },
+ { COMMENT, "/* RESERVED FOR FUTURE USE */", NULL, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " PPPSERIAL " Entity Keys\n */", NULL, NULL, NULL },
+ { COMMENT, "/* RESERVED FOR FUTURE USE */", NULL, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " PROXIES " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, NETPROP PROXIES, EXCEPTIONSLIST, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETPROP PROXIES, FTPENABLE, NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PROXIES, FTPPASSIVE, NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PROXIES, FTPPORT, NULL, CFNUMBER },
+ { REGULAR, NETPROP PROXIES, FTPPROXY, NULL, CFSTRING },
+ { REGULAR, NETPROP PROXIES, GOPHERENABLE, NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PROXIES, GOPHERPORT, NULL, CFNUMBER },
+ { REGULAR, NETPROP PROXIES, GOPHERPROXY, NULL, CFSTRING },
+ { REGULAR, NETPROP PROXIES, HTTPENABLE, NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PROXIES, HTTPPORT, NULL, CFNUMBER },
+ { REGULAR, NETPROP PROXIES, HTTPPROXY, NULL, CFSTRING },
+ { REGULAR, NETPROP PROXIES, RTSPENABLE, NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PROXIES, RTSPPORT, NULL, CFNUMBER },
+ { REGULAR, NETPROP PROXIES, RTSPPROXY, NULL, CFSTRING },
+ { REGULAR, NETPROP PROXIES, SOCKSENABLE, NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PROXIES, SOCKSPORT, NULL, CFNUMBER },
+ { REGULAR, NETPROP PROXIES, SOCKSPROXY, NULL, CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * Users Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, USERSENT, CONSOLEUSER, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n " CONSOLEUSER " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, USERSPROP CONSOLEUSER, NAME, "username", CFSTRING }, /* FIX ME! */
+ { REGULAR, USERSPROP CONSOLEUSER, UID, "uid", CFSTRING }, /* FIX ME! */
+ { REGULAR, USERSPROP CONSOLEUSER, GID, "gid", CFSTRING }, /* FIX ME! */
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * " SYSTEM " Entity Keys\n */", NULL, NULL, NULL },
+ { REGULAR, SYSTEMPROP, COMPUTERNAME, NULL, CFSTRING },
+ { REGULAR, SYSTEMPROP, COMPUTERNAME ENCODING, NULL, CFNUMBER },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/*\n * Configuration Cache Definitions\n */", NULL },
+ { COMMENT, "/* domain prefixes */", NULL },
+ { REGULAR, CACHE DOMAIN, FILE, "File:", NULL },
+ { REGULAR, CACHE DOMAIN, PLUGIN, "Plugin:", NULL },
+ { REGULAR, CACHE DOMAIN, SETUP, "Setup:", NULL },
+ { REGULAR, CACHE DOMAIN, STATE, "State:", NULL },
+ { REGULAR, CACHE DOMAIN, PREFS, "Prefs:", NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/* Setup: properties */", NULL },
+ { REGULAR, CACHE SETUPPROP, CURRENTSET, NULL, NULL },
+ { REGULAR, CACHE SETUPPROP, LASTUPDATED, NULL, NULL },
+ { COMMENT, "", NULL, NULL, NULL },
+
+ { COMMENT, "/* properties */", NULL },
+ { REGULAR, CACHE NETPROP, INTERFACES, NULL, CFARRAY_CFSTRING },
+ { REGULAR, CACHE NETPROP, PRIMARYINTERFACE, NULL, CFSTRING },
+ { REGULAR, CACHE NETPROP, SERVICEIDS, NULL, CFARRAY_CFSTRING },
+ { COMMENT, "", NULL, NULL, NULL },
+
+// XXX OBSOLETE XXX
+ { COMMENT, "/* OBSOLETE " NETPROP AIRPORT ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP AIRPORT, INCLUDEPRIVATENETS, NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP AIRPORT, "PreferredAirportNetwork", NULL, CFSTRING },
+
+ { COMMENT, "/* OBSOLETE " NETPROP ETHERNET ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP ETHERNET, SPEED, NULL, CFNUMBER },
+ { REGULAR, NETPROP ETHERNET, DUPLEX, NULL, CFSTRING },
+ { REGULAR, NETPROP ETHERNET, "WakeOnSignal", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP ETHERNET, "WakeOnTraffic", NULL, CFNUMBER_BOOL },
+ { COMMENT, "/* " KEY_PREFIX NETPROP ETHERNET DUPLEX " values */", NULL, NULL, NULL },
+ { REGULAR, NETVAL ETHERNET DUPLEX, AUTOMATIC, NULL, NULL },
+ { REGULAR, NETVAL ETHERNET DUPLEX, "FULL", NULL, NULL },
+ { REGULAR, NETVAL ETHERNET DUPLEX, "HALF", NULL, NULL },
+
+ { COMMENT, "/* OBSOLETE " NETPROP INTERFACE ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP INTERFACE, INTERFACE NAME, NULL, CFSTRING },
+ { REGULAR, NETPROP INTERFACE, MACADDRESS, NULL, CFSTRING },
+ { REGULAR, NETPROP INTERFACE, PORTNAME, NULL, CFSTRING },
+
+ { COMMENT, "/* OBSOLETE " NETPROP MODEM ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP MODEM, "IgnoreDialTone", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP MODEM, "InitString", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP MODEM, "Port", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP MODEM, PORTNAME, NULL, CFSTRING },
+ { REGULAR, NETPROP MODEM, "RedialCount", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP MODEM, "RedialEnabled", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP MODEM, "RedialTimeout", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP MODEM, "Script", NULL, CFSTRING },
+ { REGULAR, NETPROP MODEM, "SpeakerEnable", NULL, CFNUMBER },
+ { REGULAR, NETPROP MODEM, SPEED, NULL, CFNUMBER },
+ { REGULAR, NETPROP MODEM, "ToneDial", NULL, CFNUMBER },
+ { REGULAR, NETPROP MODEM, "WaitForTone", NULL, CFNUMBER },
+
+ { COMMENT, "/* OBSOLETE " NETPROP PPP ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP PPP, ALERT, NULL, CFARRAY_CFSTRING },
+ { REGULAR, NETVAL PPP ALERT, "Password", NULL, CFSTRING },
+ { REGULAR, NETVAL PPP ALERT, "Reminder", NULL, CFSTRING },
+ { REGULAR, NETVAL PPP ALERT, "Status", NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, "CompressionEnable", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, "DeviceEntity", NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, "HeaderCompression", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, "IdleDisconnect", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, "IdlePrompt", NULL, CFNUMBER_BOOL },
+ { REGULAR, NETPROP PPP, "IdleTimeout", NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, "PromptTimeout", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, "ReminderTimer", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, "SessionTimer", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, COMM "IdleTimer", NULL, CFNUMBER },
+ { REGULAR, NETPROP PPP, IPCP "LocalAddress", NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, IPCP "RemoteAddress", NULL, CFSTRING },
+ { REGULAR, NETPROP PPP, IPCP "UseServerDNS", NULL, CFNUMBER_BOOL },
+
+ { COMMENT, "/* OBSOLETE " NETPROP PPPOE ": */", NULL, NULL, NULL },
+ { REGULAR, NETPROP PPPOE, PORTNAME, NULL, CFSTRING },
+
+ { COMMENT, "", NULL, NULL, NULL },
+// XXX OBSOLETE XXX
+
+ { END, NULL, NULL, NULL, NULL },
+};
+
+enum {
+ gen_extern_e,
+ gen_init_e,
+ gen_header_e,
+};
+
+void
+dump_names(int type)
+{
+ int i;
+
+ for (i = 0; TRUE; i++) {
+ switch (names[i].control) {
+ case END: {
+ goto done;
+ break;
+ }
+ case COMMENT: {
+ if (type != gen_extern_e && type != gen_init_e) {
+ if (names[i].prefix)
+ printf("%s\n", names[i].prefix);
+ }
+ break;
+ }
+ case REGULAR: {
+ char buf[256];
+
+ switch (type) {
+ case gen_header_e:
+ snprintf(buf, sizeof(buf), KEY_PREFIX "%s%s;",
+ names[i].prefix, names[i].key);
+
+ if (names[i].type)
+ printf(STRING_MACRO_NAME " %-40s /* %s */\n",
+ buf, names[i].type);
+ else
+ printf(STRING_MACRO_NAME " %s\n", buf);
+ break;
+ case gen_extern_e:
+ snprintf(buf, sizeof(buf), KEY_PREFIX "%s%s",
+ names[i].prefix, names[i].key);
+
+ printf("volatile CFStringRef " KEY_PREFIX "%s%s = NULL;\n",
+ names[i].prefix, names[i].key);
+ break;
+ case gen_init_e:
+ snprintf(buf, sizeof(buf), KEY_PREFIX "%s%s",
+ names[i].prefix, names[i].key);
+ if (names[i].value)
+ printf(" *((void **)&%s) = (void *)CFSTR(\"%s\");\n",
+ buf, names[i].value);
+ else
+ printf(" *((void **)&%s) = (void *)CFSTR(\"%s\");\n",
+ buf, names[i].key);
+ break;
+ default:
+ break;
+ }
+ }
+ default: {
+ break;
+ }
+ }
+ }
+ done:
+ return;
+}
+
+int
+main(int argc, char * argv[])
+{
+ char * type = "";
+
+ if (argc >= 2)
+ type = argv[1];
+
+ if (strcmp(type, "header") == 0) {
+ printf("%s\n", copyright_string);
+ printf("/*\n * This file is automatically generated\n * DO NOT EDIT!\n */\n\n");
+ printf("#ifndef _SCPREFERENCES_H\n#define _SCPREFERENCES_H\n\n");
+ //printf("#ifndef " STRING_MACRO_NAME "\n");
+ printf("#ifndef __OBJC__\n");
+ printf("#define " STRING_MACRO_NAME "\t\textern const CFStringRef\n");
+ printf("#else\n");
+ printf("#define " STRING_MACRO_NAME "\t\textern NSString *\n");
+ printf("#endif\n");
+ //printf("#endif " STRING_MACRO_NAME "\n");
+ printf("\n");
+ dump_names(gen_header_e);
+ printf("#endif /* _SCPREFERENCES_H */\n");
+ }
+ else if (strcmp(type, "cfile") == 0) {
+ printf("/*\n * This file is automatically generated\n * DO NOT EDIT!\n */\n\n");
+ printf("\n#include <CoreFoundation/CFString.h>\n\n");
+ dump_names(gen_extern_e);
+ printf("\n\nvoid\n__private_extern__\n__Initialize(void)\n{\n");
+ dump_names(gen_init_e);
+ printf("}\n");
+ }
+ exit(0);
+ return (0);
+}
+
--- /dev/null
+$$
+/* $FILENAME$ created by $USERNAME$ on $DATE$ */
+
+#import <Foundation/Foundation.h>
+
+@interface $FILENAMESANSEXTENSION$ : NSObject
+{
+
+}
+
+@end
--- /dev/null
+$$ Lines starting with $$ are not inserted into newly created files
+$$ The following substitutions are made:
+$$
+$$ $FILENAME$ e.g. foo.m
+$$ $FILENAMESANSEXTENSION$ e.g. foo
+$$ $DIRECTORY$ e.g. /tmp/MyNewApp
+$$ $PROJECTNAME$ e.g. MyNewApp
+$$ $SUBPROJECTNAME$ e.g. TheGoodPart.subproj
+$$ $USERNAME$ e.g. mwagner
+$$ $DATE$ e.g. Jan-1-1994
+$$
+/* $FILENAME$ created by $USERNAME$ on $DATE$ */
+
+#import "$FILENAMESANSEXTENSION$.h"
+
+@implementation $FILENAMESANSEXTENSION$
+
+@end
--- /dev/null
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+//#include <stdlib.h>
+//#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include <SystemConfiguration/SystemConfiguration.h>
+
+
+#include "ppp_msg.h"
+#include "ppp.h"
+
+
+__private_extern__
+int
+PPPInit(int *ref)
+{
+ int sock;
+ int status;
+ struct sockaddr_un sun;
+
+ sock = socket(AF_LOCAL, SOCK_STREAM, 0);
+
+ bzero(&sun, sizeof(sun));
+ sun.sun_family = AF_LOCAL;
+ strncpy(sun.sun_path, PPP_PATH, sizeof(sun.sun_path));
+
+ status = connect(sock, (struct sockaddr *)&sun, sizeof(sun));
+ if (status < 0) {
+ return errno;
+ }
+
+ *ref = sock;
+ return 0;
+}
+
+
+__private_extern__
+int
+PPPDispose(int ref)
+{
+ if (close(ref) < 0) {
+ return errno;
+ }
+ return 0;
+}
+
+
+__private_extern__
+int
+PPPExec(int ref,
+ u_long link,
+ u_int32_t cmd,
+ void *request,
+ u_long requestLen,
+ void **reply,
+ u_long *replyLen)
+{
+ struct ppp_msg_hdr msg;
+ char *buf = NULL;
+ ssize_t n;
+
+ bzero(&msg, sizeof(msg));
+ msg.m_type = cmd;
+ msg.m_link = link;
+ msg.m_len = ((request != NULL) && (requestLen > 0)) ? requestLen : 0;
+
+ // send the command
+ n = write(ref, &msg, sizeof(msg));
+ if (n == -1) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec write() failed: %s"), strerror(errno));
+ return errno;
+ } else if (n != sizeof(msg)) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec write() failed: wrote=%d"), n);
+ return -1;
+ }
+
+ if ((request != NULL) && (requestLen > 0)) {
+ n = write(ref, request, requestLen);
+ if (n == -1) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec write() failed: %s"), strerror(errno));
+ return errno;
+ } else if (n != requestLen) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec write() failed: wrote=%d"), n);
+ return -1;
+ }
+ }
+
+ // always expect a reply
+ n = read(ref, &msg, sizeof(msg));
+ if (n == -1) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec read() failed: error=%s"), strerror(errno));
+ return errno;
+ } else if (n != sizeof(msg)) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec read() failed: insufficent data, read=%d"), n);
+ return -1;
+ }
+
+ if (msg.m_len) {
+ buf = CFAllocatorAllocate(NULL, msg.m_len, 0);
+ if (buf) {
+ // read reply
+ n = read(ref, buf, msg.m_len);
+ if (n == -1) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec read() failed: error=%s"), strerror(errno));
+ CFAllocatorDeallocate(NULL, buf);
+ return errno;
+ } else if (n != msg.m_len) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec read() failed: insufficent data, read=%d"), n);
+ CFAllocatorDeallocate(NULL, buf);
+ return -1;
+ }
+ }
+ }
+
+ if (reply && replyLen) {
+ *reply = buf;
+ *replyLen = msg.m_len;
+ } else if (buf) {
+ // if additional returned data is unwanted
+ CFAllocatorDeallocate(NULL, buf);
+ }
+
+ return msg.m_result;
+}
+
+
+__private_extern__
+int
+PPPGetNumberOfLinks(int ref, u_long *nLinks)
+{
+ void *replyBuf = NULL;
+ u_long replyBufLen = 0;
+ int status;
+
+ status = PPPExec(ref,
+ -1,
+ PPP_GETNBLINKS,
+ NULL,
+ 0,
+ &replyBuf,
+ &replyBufLen);
+ if (status != 0) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec() failed: status = %d"), status);
+ return status;
+ }
+
+ *nLinks = (replyBufLen == sizeof(u_long)) ? *(u_long *)replyBuf : 0;
+ if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
+
+ return status;
+}
+
+
+__private_extern__
+int
+PPPGetLinkByIndex(int ref, int index, u_int32_t *link)
+{
+ u_int32_t i = index;
+ void *replyBuf = NULL;
+ u_long replyBufLen = 0;
+ int status;
+
+ status = PPPExec(ref,
+ -1,
+ PPP_GETLINKBYINDEX,
+ (void *)&i,
+ sizeof(i),
+ &replyBuf,
+ &replyBufLen);
+ if (status != 0) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec() failed: status = %d"), status);
+ return status;
+ }
+
+ if (replyBuf && (replyBufLen == sizeof(u_int32_t))) {
+ *link = *(u_int32_t *)replyBuf;
+ } else {
+ status = -2; /* if not found */
+ }
+ if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
+
+ return status;
+}
+
+
+__private_extern__
+int
+PPPGetLinkByServiceID(int ref, CFStringRef serviceID, u_int32_t *link)
+{
+ int i;
+ u_long nLinks;
+ int status;
+ CFDataRef sID;
+
+ sID = CFStringCreateExternalRepresentation(NULL,
+ serviceID,
+ kCFStringEncodingMacRoman,
+ 0);
+
+ status = PPPGetNumberOfLinks(ref, &nLinks);
+ if (status != 0) {
+ SCDLog(LOG_ERR, CFSTR("PPPGetNumberOfLinks() failed: %d"), status);
+ goto done;
+ }
+
+ status = -2; /* assume no link */
+
+ for (i=0; i<nLinks; i++) {
+ u_int32_t iLink;
+ void *data = NULL;
+ u_long dataLen = 0;
+
+ status = PPPGetLinkByIndex(ref, i, &iLink);
+ if (status != 0) {
+ SCDLog(LOG_ERR, CFSTR("PPPGetLinkByIndex() failed: %d"), status);
+ goto done;
+ }
+
+ status = PPPGetOption(ref,
+ iLink,
+ PPP_OPT_SERVICEID,
+ &data,
+ &dataLen);
+ if (status != 0) {
+ SCDLog(LOG_ERR, CFSTR("PPPGetOption() failed: %d"), status);
+ goto done;
+ }
+
+ if ((dataLen != CFDataGetLength(sID)) ||
+ (strncmp(data, CFDataGetBytePtr(sID), dataLen) != 0)) {
+ /* if link not found */
+ status = -2;
+ }
+
+ CFAllocatorDeallocate(NULL, data);
+ if (status == 0) {
+ *link = iLink;
+ goto done;
+ }
+ }
+
+ done :
+
+ CFRelease(sID);
+ return status;
+}
+
+
+__private_extern__
+int
+PPPGetOption(int ref, u_long link, u_long option, void **data, u_long *dataLen)
+{
+ struct ppp_opt_hdr opt;
+ void *replyBuf = NULL;
+ u_long replyBufLen = 0;
+ int status;
+
+ bzero(&opt, sizeof(opt));
+ opt.o_type = option;
+
+ status = PPPExec(ref,
+ link,
+ PPP_GETOPTION,
+ (void *)&opt,
+ sizeof(opt),
+ &replyBuf,
+ &replyBufLen);
+ if (status != 0) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec() failed: status = %d"), status);
+ *data = NULL;
+ *dataLen = 0;
+ return status;
+ }
+
+ if (replyBuf && (replyBufLen > sizeof(struct ppp_opt_hdr))) {
+ *dataLen = replyBufLen - sizeof(struct ppp_opt_hdr);
+ *data = CFAllocatorAllocate(NULL, *dataLen, 0);
+ bcopy(((struct ppp_opt *)replyBuf)->o_data, *data, *dataLen);
+ }
+ if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
+
+ return status;
+}
+
+
+__private_extern__
+int
+PPPStatus(int ref, u_long link, struct ppp_status **stat)
+{
+ void *replyBuf = NULL;
+ u_long replyBufLen = 0;
+ int status;
+
+ status = PPPExec(ref,
+ link,
+ PPP_STATUS,
+ NULL,
+ 0,
+ &replyBuf,
+ &replyBufLen);
+ if (status != 0) {
+ SCDLog(LOG_ERR, CFSTR("PPPExec() failed: status = %d"), status);
+ return status;
+ }
+
+ if (replyBuf && (replyBufLen == sizeof(struct ppp_status))) {
+ *stat = (struct ppp_status *)replyBuf;
+ } else {
+ if (replyBuf) CFAllocatorDeallocate(NULL, replyBuf);
+ *stat = NULL;
+ status = -1;
+ }
+
+ return status;
+}
--- /dev/null
+/*
+ * Copyright (c) 2001 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _PPP_H
+#define _PPP_H
+
+
+#include <sys/cdefs.h>
+#include <CoreFoundation/CoreFoundation.h>
+#include "ppp_msg.h"
+
+
+__BEGIN_DECLS
+
+int PPPInit (int *ref);
+
+int PPPDispose (int ref);
+
+int PPPExec (int ref,
+ u_long link,
+ u_int32_t cmd,
+ void *request,
+ u_long requestLen,
+ void **reply,
+ u_long *replyLen);
+
+int PPPGetNumberOfLinks (int ref,
+ u_long *nLinks);
+
+int PPPGetLinkByIndex (int ref,
+ int index,
+ u_int32_t *link);
+
+int PPPGetLinkByServiceID (int ref,
+ CFStringRef serviceID,
+ u_int32_t *link);
+
+int PPPGetOption (int ref,
+ u_long link,
+ u_long option,
+ void **data,
+ u_long *dataLen);
+
+int PPPStatus (int ref,
+ u_long link,
+ struct ppp_status **stat);
+
+__END_DECLS
+
+#endif /* _PPP_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef _PPP_MSG_H
+#define _PPP_MSG_H
+
+#include <sys/types.h>
+
+
+/* local socket path */
+#define PPP_PATH "/var/run/pppconfd\0"
+
+
+/* PPP message paquets */
+struct ppp_msg_hdr {
+ u_int32_t m_type; // type of the message
+ u_int32_t m_result; // error code of notification message
+ u_int32_t m_cookie; // user param
+ u_int32_t m_link; // link for this message
+ u_int32_t m_len; // len of the following data
+};
+
+struct ppp_msg {
+ u_int32_t m_type; // type of the message
+ u_int32_t m_result; // error code of notification message
+ u_int32_t m_cookie; // user param, or error num for event
+ u_int32_t m_link; // link for this message
+ u_int32_t m_len; // len of the following data
+ u_char m_data[1]; // msg data sent or received
+};
+
+
+
+/* codes for ppp messages */
+enum {
+ /* API client commands */
+ PPP_VERSION = 1,
+ PPP_STATUS,
+ PPP_CONNECT,
+ PPP_DISCONNECT = 5,
+ PPP_GETOPTION,
+ PPP_SETOPTION,
+ PPP_ENABLE_EVENT,
+ PPP_DISABLE_EVENT,
+ PPP_EVENT,
+ PPP_GETNBLINKS,
+ PPP_GETLINKBYINDEX
+
+};
+
+// struct for an option
+struct ppp_opt_hdr {
+ u_int32_t o_type;
+};
+
+struct ppp_opt {
+ u_int32_t o_type;
+ u_char o_data[1];
+};
+
+
+/* codes for options management */
+enum {
+
+ PPP_OPT_DEV_NAME = 1, // string
+ PPP_OPT_DEV_SPEED, // 4 bytes
+ PPP_OPT_DEV_CONNECTSCRIPT, // string
+
+ PPP_OPT_COMM_IDLETIMER, // 4 bytes
+ PPP_OPT_COMM_REMOTEADDR, // string
+
+ PPP_OPT_AUTH_PROTO, // 4 bytes
+ PPP_OPT_AUTH_NAME, // string
+ PPP_OPT_AUTH_PASSWD, // string
+
+ PPP_OPT_LCP_HDRCOMP, // 4 bytes
+ PPP_OPT_LCP_MRU, // 4 bytes
+ PPP_OPT_LCP_MTU, // 4 bytes
+ PPP_OPT_LCP_RCACCM, // 4 bytes
+ PPP_OPT_LCP_TXACCM, // 4 bytes
+
+ PPP_OPT_IPCP_HDRCOMP, // 4 bytes
+ PPP_OPT_IPCP_LOCALADDR, // 4 bytes
+ PPP_OPT_IPCP_REMOTEADDR, // 4 bytes
+
+ PPP_OPT_LOGFILE, // string
+ PPP_OPT_RESERVED, // 4 bytes
+ PPP_OPT_REMINDERTIMER, // 4 bytes (not implemented)
+ PPP_OPT_ALERTENABLE, // 4 bytes (not implemented)
+
+ PPP_OPT_LCP_ECHO, // struct ppp_opt_echo
+
+ PPP_OPT_COMM_CONNECTDELAY, // 4 bytes
+ PPP_OPT_COMM_SESSIONTIMER, // 4 bytes
+ PPP_OPT_COMM_TERMINALMODE, // 4 bytes
+ PPP_OPT_COMM_TERMINALSCRIPT, // string. Additionnal connection script, once modem is connected
+ PPP_OPT_DEV_CAPS, // struct ppp_caps...
+
+ PPP_OPT_IPCP_USESERVERDNS, // 4 bytes
+ PPP_OPT_COMM_CONNECTSPEED, // 4 bytes, actual connection speed
+ PPP_OPT_SERVICEID // string, name of the associated service in the cache
+
+};
+
+// options values
+
+// PPP_LCP_OPT_HDRCOMP -- option ppp addr/ctrl compression
+enum {
+ PPP_LCP_HDRCOMP_NONE = 0,
+ PPP_LCP_HDRCOMP_ADDR = 1,
+ PPP_LCP_HDRCOMP_PROTO = 2
+};
+
+enum {
+ PPP_COMM_TERM_NONE = 0,
+ PPP_COMM_TERM_SCRIPT,
+ PPP_COMM_TERM_WINDOW
+};
+
+enum {
+ PPP_IPCP_HDRCOMP_NONE = 0,
+ PPP_IPCP_HDRCOMP_VJ
+};
+
+// PPP_LCP_OPT_RCACCM -- option receive control asynchronous character map
+enum {
+ PPP_LCP_ACCM_NONE = 0,
+ PPP_LCP_ACCM_XONXOFF = 0x000A0000,
+ PPP_LCP_ACCM_ALL = 0xFFFFFFFF
+};
+
+// PPP_OPT_AUTH
+enum {
+ PPP_AUTH_NONE = 0,
+ PPP_AUTH_PAPCHAP,
+ PPP_AUTH_PAP,
+ PPP_AUTH_CHAP
+};
+
+// state machine
+enum {
+ PPP_IDLE = 0,
+ PPP_INITIALIZE,
+ PPP_CONNECTLINK,
+ PPP_STATERESERVED,
+ PPP_ESTABLISH,
+ PPP_AUTHENTICATE,
+ PPP_CALLBACK,
+ PPP_NETWORK,
+ PPP_RUNNING,
+ PPP_TERMINATE,
+ PPP_DISCONNECTLINK
+};
+
+// events
+enum {
+ PPP_EVT_DISCONNECTED = 1,
+ PPP_EVT_CONNSCRIPT_STARTED,
+ PPP_EVT_CONNSCRIPT_FINISHED,
+ PPP_EVT_TERMSCRIPT_STARTED,
+ PPP_EVT_TERMSCRIPT_FINISHED,
+ PPP_EVT_LOWERLAYER_UP,
+ PPP_EVT_LOWERLAYER_DOWN,
+ PPP_EVT_LCP_UP,
+ PPP_EVT_LCP_DOWN,
+ PPP_EVT_IPCP_UP,
+ PPP_EVT_IPCP_DOWN,
+ PPP_EVT_AUTH_STARTED,
+ PPP_EVT_AUTH_FAILED,
+ PPP_EVT_AUTH_SUCCEDED
+};
+
+struct ppp_opt_echo { // 0 for the following value will cancel echo option
+ u_int16_t interval; // delay in seconds between echo requests
+ u_int16_t failure; // # of failure before declaring the link down
+};
+
+struct ppp_status {
+ // connection stats
+ u_int32_t status;
+ union {
+ struct connected {
+ u_int32_t timeElapsed;
+ u_int32_t timeRemaining;
+ // bytes stats
+ u_int32_t inBytes;
+ u_int32_t inPackets;
+ u_int32_t inErrors;
+ u_int32_t outBytes;
+ u_int32_t outPackets;
+ u_int32_t outErrors;
+ } run;
+ struct disconnected {
+ u_int32_t lastDiscCause;
+ } disc;
+ } s;
+};
+
+enum {
+ // from 0 to 255, we use bsd error codes from errno.h
+
+ // ppp speficic error codes
+ PPP_ERR_GEN_ERROR = 256,
+ PPP_ERR_CONNSCRIPTFAILED,
+ PPP_ERR_TERMSCRIPTFAILED,
+ PPP_ERR_LCPFAILED,
+ PPP_ERR_AUTHFAILED,
+ PPP_ERR_IDLETIMEOUT,
+ PPP_ERR_SESSIONTIMEOUT,
+ PPP_ERR_LOOPBACK,
+ PPP_ERR_PEERDEAD,
+ PPP_ERR_DISCSCRIPTFAILED,
+
+ // modem specific error codes
+ PPP_ERR_MOD_NOCARRIER = 512,
+ PPP_ERR_MOD_BUSY,
+ PPP_ERR_MOD_NODIALTONE,
+ PPP_ERR_MOD_ERROR
+};
+
+#endif /* _PPP_MSG_H */
+
--- /dev/null
+#
+# Generated by the Apple Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = configd
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = configd.h _SCD.h configd_server.h notify_server.h\
+ plugin_support.h session.h notify.h
+
+MFILES = configd.m
+
+CFILES = _SCD.c configd_server.c notify_server.c plugin_support.c\
+ session.c notify.c _configopen.c _configclose.c _configlock.c\
+ _configunlock.c _configlist.c _configadd.c _configadd_s.c\
+ _configget.c _configset.c _configremove.c _configtouch.c\
+ _notifyadd.c _notifyremove.c _notifychanges.c _notifyviaport.c\
+ _notifyviafd.c _notifyviasignal.c _notifycancel.c _snapshot.c
+
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble m.template\
+ h.template config.defs
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/sbin
+WINDOWS_INSTALLDIR = /Library/Executables
+PDO_UNIX_INSTALLDIR = /bin
+LIBS = -lobjc
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+FRAMEWORKS = -framework SystemConfiguration
+
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
--- /dev/null
+###############################################################################
+# Makefile.postamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile, which is imported after all other makefiles, to
+# override attributes for a project's Makefile environment. This allows you
+# to take advantage of the environment set up by the other Makefiles.
+# You can also define custom rules at the end of this file.
+#
+###############################################################################
+#
+# These variables are exported by the standard makefiles and can be
+# used in any customizations you make. They are *outputs* of
+# the Makefiles and should be used, not set.
+#
+# PRODUCTS: products to install. All of these products will be placed in
+# the directory $(DSTROOT)$(INSTALLDIR)
+# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
+# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
+# OFILE_DIR: Directory into which .o object files are generated.
+# DERIVED_SRC_DIR: Directory used for all other derived files
+#
+# ALL_CFLAGS: flags to pass when compiling .c files
+# ALL_MFLAGS: flags to pass when compiling .m files
+# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
+# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
+# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
+# ALL_LDFLAGS: flags to pass when linking object files
+# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
+# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
+# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
+# ALL_YFLAGS: flags to pass when processing .y (yacc) files
+# ALL_LFLAGS: flags to pass when processing .l (lex) files
+#
+# NAME: name of application, bundle, subproject, palette, etc.
+# LANGUAGES: langages in which the project is written (default "English")
+# English_RESOURCES: localized resources (e.g. nib's, images) of project
+# GLOBAL_RESOURCES: non-localized resources of project
+#
+# SRCROOT: base directory in which to place the new source files
+# SRCPATH: relative path from SRCROOT to present subdirectory
+#
+# INSTALLDIR: Directory the product will be installed into by 'install' target
+# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+#
+# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
+#
+###############################################################################
+
+# Some compiler flags can be overridden here for certain build situations.
+#
+# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
+# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
+# to -g)
+# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
+# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
+# to -O)
+# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
+# to -pg -DPROFILE)
+# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
+# the include path (defaults to -I.)
+# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
+# passed to ld/libtool (defaults to nothing)
+
+
+# Library and Framework projects only:
+# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
+# against the framework will run against the correct version even if
+# the current version of the framework changes. You may override this
+# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
+# development cycle, but be sure to restore it before installing.
+
+
+# Ownership and permissions of files installed by 'install' target
+
+#INSTALL_AS_USER = root
+ # User/group ownership
+#INSTALL_AS_GROUP = wheel
+ # (probably want to set both of these)
+#INSTALL_PERMISSIONS =
+ # If set, 'install' chmod's executable to this
+
+
+# Options to strip. Note: -S strips debugging symbols (executables can be stripped
+# down further with -x or, if they load no bundles, with no options at all).
+
+#STRIPFLAGS = -S
+
+
+#########################################################################
+# Put rules to extend the behavior of the standard Makefiles here. Include them in
+# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
+#
+# You should avoid redefining things like "install" or "app", as they are
+# owned by the top-level Makefile API and no context has been set up for where
+# derived files should go.
+#
+
--- /dev/null
+###############################################################################
+# Makefile.preamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile for configuring the standard application makefiles
+# associated with ProjectBuilder. It is included before the main makefile.
+# In Makefile.preamble you set attributes for a project, so they are available
+# to the project's makefiles. In contrast, you typically write additional rules or
+# override built-in behavior in the Makefile.postamble.
+#
+# Each directory in a project tree (main project plus subprojects) should
+# have its own Makefile.preamble and Makefile.postamble.
+###############################################################################
+#
+# Before the main makefile is included for this project, you may set:
+#
+# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
+# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
+
+# Compiler/linker flags added to the defaults: The OTHER_* variables will be
+# inherited by all nested sub-projects, but the LOCAL_ versions of the same
+# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
+# Build Attributes inspector if at all possible. To override the default flags
+# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
+# variables below are *inputs* to the build process and distinct from the override
+# settings done (less often) in the Makefile.postamble.
+#
+# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
+# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
+# .cc, .cxx, .C, and .M files. There is no need to respecify the
+# flags in OTHER_MFLAGS, etc.
+# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
+# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
+# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
+# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
+# precompiling header files
+# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
+# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
+# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
+# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
+# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
+
+# These variables provide hooks enabling you to add behavior at almost every
+# stage of the make:
+#
+# BEFORE_PREBUILD: targets to build before installing headers for a subproject
+# AFTER_PREBUILD: targets to build after installing headers for a subproject
+# BEFORE_BUILD_RECURSION: targets to make before building subprojects
+# BEFORE_BUILD: targets to make before a build, but after subprojects
+# AFTER_BUILD: targets to make after a build
+#
+# BEFORE_INSTALL: targets to build before installing the product
+# AFTER_INSTALL: targets to build after installing the product
+# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
+# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
+#
+# BEFORE_INSTALLHDRS: targets to build before installing headers for a
+# subproject
+# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
+# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
+# AFTER_INSTALLSRC: targets to build after installing source for a subproject
+#
+# BEFORE_DEPEND: targets to build before building dependencies for a
+# subproject
+# AFTER_DEPEND: targets to build after building dependencies for a
+# subproject
+#
+# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
+# updated every time the project is built. If NO, the dependency
+# file is only built when the depend target is invoked.
+
+# Framework-related variables:
+# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the framework's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+
+# Library-related variables:
+# PUBLIC_HEADER_DIR: Determines where public exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically. For library projects you should
+# set this to something like /Developer/Headers/$(NAME). Do not set
+# this variable for framework projects unless you do not want the
+# header files included in the framework.
+# PRIVATE_HEADER_DIR: Determines where private exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically.
+# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
+# whether the libraries produced are statically linked when they
+# are used or if they are dynamically loadable. This defaults to
+# DYNAMIC.
+# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the library's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+#
+# INSTALL_AS_USER: owner of the intalled products (default root)
+# INSTALL_AS_GROUP: group of the installed products (default wheel)
+# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
+#
+# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
+# passed on the command line to recursive invocations of make. Note that
+# the values in OTHER_*FLAGS are inherited by subprojects automatically --
+# you do not have to (and shouldn't) add OTHER_*FLAGS to
+# OTHER_RECURSIVE_VARIABLES.
+
+# Additional headers to export beyond those in the PB.project:
+# OTHER_PUBLIC_HEADERS
+# OTHER_PROJECT_HEADERS
+# OTHER_PRIVATE_HEADERS
+
+# Additional files for the project's product: <<path relative to proj?>>
+# OTHER_RESOURCES: (non-localized) resources for this project
+# OTHER_OFILES: relocatables to be linked into this project
+# OTHER_LIBS: more libraries to link against
+# OTHER_PRODUCT_DEPENDS: other dependencies of this project
+# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
+# OTHER_GARBAGE: additional files to be removed by `make clean'
+
+# Set this to YES if you don't want a final libtool call for a library/framework.
+# BUILD_OFILES_LIST_ONLY
+
+# To include a version string, project source must exist in a directory named
+# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
+OTHER_GENERATED_OFILES = $(VERS_OFILE)
+
+# This definition will suppress stripping of debug symbols when an executable
+# is installed. By default it is YES.
+# STRIP_ON_INSTALL = NO
+
+# Uncomment to suppress generation of a KeyValueCoding index when installing
+# frameworks (This index is used by WOB and IB to determine keys available
+# for an object). Set to YES by default.
+# PREINDEX_FRAMEWORK = NO
+
+# Change this definition to install projects somewhere other than the
+# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
+# and "" on other systems.
+# DSTROOT = $(HOME)
+
+# Additional flags (MiG generated files)
+OTHER_OFILES = configServer.o
+
--- /dev/null
+{
+ DYNAMIC_CODE_GEN = YES;
+ FILESTABLE = {
+ FRAMEWORKS = (SystemConfiguration.framework);
+ FRAMEWORKSEARCH = ();
+ HEADERSEARCH = ();
+ H_FILES = (
+ configd.h,
+ _SCD.h,
+ configd_server.h,
+ notify_server.h,
+ plugin_support.h,
+ session.h,
+ notify.h
+ );
+ OTHER_LIBS = (objc);
+ OTHER_LINKED = (
+ configd.m,
+ _SCD.c,
+ configd_server.c,
+ notify_server.c,
+ plugin_support.c,
+ session.c,
+ notify.c,
+ _configopen.c,
+ _configclose.c,
+ _configlock.c,
+ _configunlock.c,
+ _configlist.c,
+ _configadd.c,
+ _configadd_s.c,
+ _configget.c,
+ _configset.c,
+ _configremove.c,
+ _configtouch.c,
+ _notifyadd.c,
+ _notifyremove.c,
+ _notifychanges.c,
+ _notifyviaport.c,
+ _notifyviafd.c,
+ _notifyviasignal.c,
+ _notifycancel.c,
+ _snapshot.c
+ );
+ OTHER_SOURCES = (
+ Makefile.preamble,
+ Makefile,
+ Makefile.postamble,
+ m.template,
+ h.template,
+ config.defs
+ );
+ PRECOMPILED_HEADERS = ();
+ PROJECT_HEADERS = ();
+ PUBLIC_HEADERS = ();
+ SUBPROJECTS = ();
+ };
+ LANGUAGE = English;
+ MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
+ NEXTSTEP_BUILDTOOL = /usr/bin/gnumake;
+ NEXTSTEP_INSTALLDIR = /usr/sbin;
+ NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
+ NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
+ PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
+ PDO_UNIX_INSTALLDIR = /bin;
+ PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
+ PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = configd;
+ PROJECTTYPE = Tool;
+ PROJECTVERSION = 2.8;
+ WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
+ WINDOWS_INSTALLDIR = /Library/Executables;
+ WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
+ WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "configd.h"
+
+
+CFMutableDictionaryRef sessionData = NULL;
+
+CFMutableDictionaryRef cacheData = NULL;
+CFMutableDictionaryRef cacheData_s = NULL;
+
+CFMutableSetRef changedKeys = NULL;
+CFMutableSetRef changedKeys_s = NULL;
+
+CFMutableSetRef deferredRemovals = NULL;
+CFMutableSetRef deferredRemovals_s = NULL;
+
+CFMutableSetRef removedSessionKeys = NULL;
+CFMutableSetRef removedSessionKeys_s = NULL;
+
+CFMutableSetRef needsNotification = NULL;
+
+
+void
+_swapLockedCacheData()
+{
+ void *temp;
+
+ temp = cacheData;
+ cacheData = cacheData_s;
+ cacheData_s = temp;
+
+ temp = changedKeys;
+ changedKeys = changedKeys_s;
+ changedKeys_s = temp;
+
+ temp = deferredRemovals;
+ deferredRemovals = deferredRemovals_s;
+ deferredRemovals_s = temp;
+
+ temp = removedSessionKeys;
+ removedSessionKeys = removedSessionKeys_s;
+ removedSessionKeys_s = temp;
+
+ return;
+}
+
+
+void
+_addWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
+{
+ CFDictionaryRef dict;
+ CFMutableDictionaryRef newDict;
+ CFArrayRef watchers;
+ CFMutableArrayRef newWatchers;
+ CFArrayRef watcherRefs;
+ CFMutableArrayRef newWatcherRefs;
+ CFIndex i;
+ int refCnt;
+ CFNumberRef refNum;
+
+ /*
+ * Get the dictionary associated with this key out of the cache
+ */
+ dict = CFDictionaryGetValue(cacheData, watchedKey);
+ if (dict) {
+ newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+ } else {
+ newDict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ /*
+ * Get the set of watchers out of the keys dictionary
+ */
+ watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
+ watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
+ if (watchers) {
+ newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
+ newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
+ } else {
+ newWatchers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ newWatcherRefs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+
+ /*
+ * Add my session to the set of watchers
+ */
+ i = CFArrayGetFirstIndexOfValue(newWatchers,
+ CFRangeMake(0, CFArrayGetCount(newWatchers)),
+ sessionNum);
+ if (i == -1) {
+ /* if this is the first instance of this session watching this key */
+ CFArrayAppendValue(newWatchers, sessionNum);
+ refCnt = 1;
+ refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
+ CFArrayAppendValue(newWatcherRefs, refNum);
+ CFRelease(refNum);
+ } else {
+ /* if this is another instance of this session watching this key */
+ refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
+ CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
+ refCnt++;
+ refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
+ CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
+ CFRelease(refNum);
+ }
+
+ /*
+ * Update the keys dictionary
+ */
+ CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
+ CFRelease(newWatchers);
+ CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
+ CFRelease(newWatcherRefs);
+
+ /*
+ * Update the cache for this key
+ */
+ CFDictionarySetValue(cacheData, watchedKey, newDict);
+ CFRelease(newDict);
+
+ SCDLog(LOG_DEBUG, CFSTR(" _addWatcher: %@, %@"), sessionNum, watchedKey);
+
+ return;
+}
+
+
+/*
+ * _addRegexWatcherByKey()
+ *
+ * This is a CFDictionaryApplierFunction which will iterate over each key
+ * defined in the "cacheData" dictionary. The arguments are the dictionary
+ * key, it's associated cache dictionary, and a context structure which
+ * includes the following:
+ *
+ * 1. the session which has just added a regex notification request
+ * 2. the compiled regular expression associated with the above key.
+ *
+ * If a (real) dictionary key is found which matches the provided regular
+ * expression then we mark that key as being watched by the session.
+ */
+void
+_addRegexWatcherByKey(const void *key, void *val, void *context)
+{
+ CFStringRef cacheStr = key;
+ CFDictionaryRef info = val;
+ mach_port_t sessionID = ((addContextRef)context)->session->server;
+ regex_t *preg = ((addContextRef)context)->preg;
+ int cacheKeyLen;
+ char *cacheKey;
+ CFNumberRef sessionNum;
+ int reError;
+ char reErrBuf[256];
+ int reErrStrLen;
+
+ if (CFDictionaryContainsKey(info, kSCDData) == FALSE) {
+ /* if no data (yet) */
+ return;
+ }
+
+ /* convert cache key to C string */
+ cacheKeyLen = CFStringGetLength(cacheStr) + 1;
+ cacheKey = CFAllocatorAllocate(NULL, cacheKeyLen, 0);
+ if (!CFStringGetCString(cacheStr, cacheKey, cacheKeyLen, kCFStringEncodingMacRoman)) {
+ SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert cache key to C string"));
+ CFAllocatorDeallocate(NULL, cacheKey);
+ return;
+ }
+
+ /* compare cache key to new notification keys regular expression pattern */
+ reError = regexec(preg, cacheKey, 0, NULL, 0);
+ switch (reError) {
+ case 0 :
+ /* we've got a match */
+ sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionID);
+ _addWatcher(sessionNum, cacheStr);
+ CFRelease(sessionNum);
+ break;
+ case REG_NOMATCH :
+ /* no match */
+ break;
+ default :
+ reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
+ SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
+ break;
+ }
+ CFAllocatorDeallocate(NULL, cacheKey);
+}
+
+
+/*
+ * _addRegexWatchersBySession()
+ *
+ * This is a CFDictionaryApplierFunction which will iterate over each session
+ * defined in the "sessionData" dictionary. The arguments are the session
+ * key, it's associated session dictionary, , and the cache key being added.
+ *
+ * If an active session includes any regular expression keys which match the
+ * key being added to the "cacheData" dictionary then we mark this key as being
+ * watched by the session.
+ */
+void
+_addRegexWatchersBySession(const void *key, void *val, void *context)
+{
+ CFStringRef sessionKey = key;
+ CFDictionaryRef info = val;
+ CFStringRef addedKey = context;
+ CFIndex newKeyLen;
+ char *newKeyStr;
+ CFArrayRef rKeys;
+ CFArrayRef rData;
+ CFIndex i;
+
+ if (info == NULL) {
+ /* if no dictionary for this session */
+ return;
+ }
+
+ rKeys = CFDictionaryGetValue(info, kSCDRegexKeys);
+ if (rKeys == NULL) {
+ /* if no regex keys for this session */
+ return;
+ }
+ rData = CFDictionaryGetValue(info, kSCDRegexData);
+
+ /* convert new key to C string */
+ newKeyLen = CFStringGetLength(addedKey) + 1;
+ newKeyStr = CFAllocatorAllocate(NULL, newKeyLen, 0);
+ if (!CFStringGetCString(addedKey, newKeyStr, newKeyLen, kCFStringEncodingMacRoman)) {
+ SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert new key to C string"));
+ CFAllocatorDeallocate(NULL, newKeyStr);
+ return;
+ }
+
+ /* iterate over the regex keys looking for an pattern which matches the new key */
+ for (i=0; i<CFArrayGetCount(rKeys); i++) {
+ CFDataRef regexData = CFArrayGetValueAtIndex(rData, i);
+ regex_t *preg = (regex_t *)CFDataGetBytePtr(regexData);
+ int reError;
+ char reErrBuf[256];
+ int reErrStrLen;
+ SInt32 sessionInt;
+ CFNumberRef sessionNum;
+
+ /* check if this key matches the regular expression */
+ reError = regexec(preg, newKeyStr, 0, NULL, 0);
+ switch (reError) {
+ case 0 :
+ /* we've got a match, add a reference */
+ sessionInt = CFStringGetIntValue(sessionKey);
+ sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionInt);
+ _addWatcher(sessionNum, addedKey);
+ CFRelease(sessionNum);
+ break;
+ case REG_NOMATCH :
+ /* no match */
+ break;
+ default :
+ reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
+ SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
+ break;
+ }
+
+ }
+ CFAllocatorDeallocate(NULL, newKeyStr);
+
+ return;
+}
+
+
+void
+_removeWatcher(CFNumberRef sessionNum, CFStringRef watchedKey)
+{
+ CFDictionaryRef dict;
+ CFMutableDictionaryRef newDict;
+ CFArrayRef watchers;
+ CFMutableArrayRef newWatchers;
+ CFArrayRef watcherRefs;
+ CFMutableArrayRef newWatcherRefs;
+ CFIndex i;
+ int refCnt;
+ CFNumberRef refNum;
+
+ /*
+ * Get the dictionary associated with this key out of the cache
+ */
+ dict = CFDictionaryGetValue(cacheData, watchedKey);
+ if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDWatchers) == FALSE)) {
+ /* key doesn't exist (isn't this really fatal?) */
+ SCDLog(LOG_DEBUG, CFSTR("_removeWatcher: key not present in dictionary."));
+ return;
+ }
+ newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+
+ /*
+ * Get the set of watchers out of the keys dictionary and
+ * remove this session from the list.
+ */
+ watchers = CFDictionaryGetValue(newDict, kSCDWatchers);
+ newWatchers = CFArrayCreateMutableCopy(NULL, 0, watchers);
+
+ watcherRefs = CFDictionaryGetValue(newDict, kSCDWatcherRefs);
+ newWatcherRefs = CFArrayCreateMutableCopy(NULL, 0, watcherRefs);
+
+ /* locate the session reference */
+ i = CFArrayGetFirstIndexOfValue(newWatchers,
+ CFRangeMake(0, CFArrayGetCount(newWatchers)),
+ sessionNum);
+ if (i == -1) {
+ SCDLog(LOG_DEBUG, CFSTR("_removeWatcher: no reference for session %@"), sessionNum);
+ CFRelease(newDict);
+ CFRelease(newWatchers);
+ CFRelease(newWatcherRefs);
+ return;
+ }
+
+ /* remove one session reference */
+ refNum = CFArrayGetValueAtIndex(newWatcherRefs, i);
+ CFNumberGetValue(refNum, kCFNumberIntType, &refCnt);
+ if (--refCnt > 0) {
+ refNum = CFNumberCreate(NULL, kCFNumberIntType, &refCnt);
+ CFArraySetValueAtIndex(newWatcherRefs, i, refNum);
+ CFRelease(refNum);
+ } else {
+ /* if this was the last reference */
+ CFArrayRemoveValueAtIndex(newWatchers, i);
+ CFArrayRemoveValueAtIndex(newWatcherRefs, i);
+ }
+
+ if (CFArrayGetCount(newWatchers) > 0) {
+ /* if this key is still being "watched" */
+ CFDictionarySetValue(newDict, kSCDWatchers, newWatchers);
+ CFDictionarySetValue(newDict, kSCDWatcherRefs, newWatcherRefs);
+ } else {
+ /* no watchers left, remove the empty set */
+ CFDictionaryRemoveValue(newDict, kSCDWatchers);
+ CFDictionaryRemoveValue(newDict, kSCDWatcherRefs);
+ }
+ CFRelease(newWatchers);
+ CFRelease(newWatcherRefs);
+
+ if (CFDictionaryGetCount(newDict) > 0) {
+ /* if this key is still active */
+ CFDictionarySetValue(cacheData, watchedKey, newDict);
+ } else {
+ /* no information left, remove the empty dictionary */
+ CFDictionaryRemoveValue(cacheData, watchedKey);
+ }
+ CFRelease(newDict);
+
+ SCDLog(LOG_DEBUG, CFSTR(" _removeWatcher: %@, %@"), sessionNum, watchedKey);
+
+ return;
+}
+
+
+/*
+ * _removeRegexWatcherByKey()
+ *
+ * This is a CFDictionaryApplierFunction which will iterate over each key
+ * defined in the "cacheData" dictionary. The arguments are the dictionary
+ * key, it's associated cache dictionary, and a context structure which
+ * includes the following:
+ *
+ * 1. the session which has just removed a regex notification request
+ * 2. the compiled regular expression associated with the above key.
+ *
+ * If a key is found and it matches the provided regular expression then
+ * it will its "being watched" status will be cleared.
+ */
+void
+_removeRegexWatcherByKey(const void *key, void *val, void *context)
+{
+ CFStringRef cacheStr = key;
+ CFDictionaryRef info = val;
+ mach_port_t sessionID = ((removeContextRef)context)->session->server;
+ regex_t *preg = ((removeContextRef)context)->preg;
+ CFNumberRef sessionNum;
+ CFArrayRef watchers;
+ int cacheKeyLen;
+ char *cacheKey;
+ int reError;
+ char reErrBuf[256];
+ int reErrStrLen;
+
+ if ((info == NULL) || (CFDictionaryContainsKey(info, kSCDWatchers) == FALSE)) {
+ /* no dictionary or no watchers */
+ return;
+ }
+
+ sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionID);
+
+ watchers = CFDictionaryGetValue(info, kSCDWatchers);
+ if (CFArrayContainsValue(watchers,
+ CFRangeMake(0, CFArrayGetCount(watchers)),
+ sessionNum) == FALSE) {
+ /* this session is not watching this key */
+ CFRelease(sessionNum);
+ return;
+ }
+
+ /* convert key to C string */
+ cacheKeyLen = CFStringGetLength(cacheStr) + 1;
+ cacheKey = CFAllocatorAllocate(NULL, cacheKeyLen, 0);
+ if (!CFStringGetCString(cacheStr, cacheKey, cacheKeyLen, kCFStringEncodingMacRoman)) {
+ SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert key to C string"));
+ CFAllocatorDeallocate(NULL, cacheKey);
+ CFRelease(sessionNum);
+ return;
+ }
+
+ /* check if this key matches the regular expression */
+ reError = regexec(preg, cacheKey, 0, NULL, 0);
+ switch (reError) {
+ case 0 :
+ /* we've got a match */
+ _removeWatcher(sessionNum, cacheStr);
+ break;
+ case REG_NOMATCH :
+ /* no match */
+ break;
+ default :
+ reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
+ SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
+ break;
+ }
+ CFAllocatorDeallocate(NULL, cacheKey);
+ CFRelease(sessionNum);
+}
+
+
+/*
+ * _removeRegexWatchersBySession()
+ *
+ * This is a CFDictionaryApplierFunction which will iterate over each session
+ * defined in the "sessionData" dictionary. The arguments are the session
+ * key, it's associated session dictionary, and the cache key being removed.
+ *
+ * If an active session includes any regular expression keys which match the
+ * key being removed from the "cacheData" dictionary then we clear this keys
+ * reference of being watched.
+ */
+void
+_removeRegexWatchersBySession(const void *key, void *val, void *context)
+{
+ CFStringRef sessionKey = key;
+ CFDictionaryRef info = val;
+ CFStringRef removedKey = context;
+ CFIndex oldKeyLen;
+ char *oldKeyStr;
+ CFArrayRef rKeys;
+ CFArrayRef rData;
+ CFIndex i;
+
+ if (info == NULL) {
+ /* if no dictionary for this session */
+ return;
+ }
+
+ rKeys = CFDictionaryGetValue(info, kSCDRegexKeys);
+ if (rKeys == NULL) {
+ /* if no regex keys for this session */
+ return;
+ }
+ rData = CFDictionaryGetValue(info, kSCDRegexData);
+
+ /* convert new key to C string */
+ oldKeyLen = CFStringGetLength(removedKey) + 1;
+ oldKeyStr = CFAllocatorAllocate(NULL, oldKeyLen, 0);
+ if (!CFStringGetCString(removedKey, oldKeyStr, oldKeyLen, kCFStringEncodingMacRoman)) {
+ SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert old key to C string"));
+ CFAllocatorDeallocate(NULL, oldKeyStr);
+ return;
+ }
+
+ /* iterate over the regex keys looking for an pattern which matches the old key */
+ for (i=0; i<CFArrayGetCount(rKeys); i++) {
+ CFDataRef regexData = CFArrayGetValueAtIndex(rData, i);
+ regex_t *preg = (regex_t *)CFDataGetBytePtr(regexData);
+ int reError;
+ char reErrBuf[256];
+ int reErrStrLen;
+ SInt32 sessionInt;
+ CFNumberRef sessionNum;
+
+ /* check if this key matches the regular expression */
+ reError = regexec(preg, oldKeyStr, 0, NULL, 0);
+ switch (reError) {
+ case 0 :
+ /* we've got a match, remove a reference */
+ sessionInt = CFStringGetIntValue(sessionKey);
+ sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionInt);
+ _removeWatcher(sessionNum, removedKey);
+ CFRelease(sessionNum);
+ break;
+ case REG_NOMATCH :
+ /* no match */
+ break;
+ default :
+ reErrStrLen = regerror(reError, preg, reErrBuf, sizeof(reErrBuf));
+ SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
+ break;
+ }
+
+ }
+ CFAllocatorDeallocate(NULL, oldKeyStr);
+
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#ifndef _S_SCD_H
+#define _S_SCD_H
+
+#include <sys/cdefs.h>
+
+
+/*
+ * keys in the "cacheData" dictionary
+ */
+
+/*
+ * data associated with a key
+ */
+#define kSCDData CFSTR("data")
+/*
+ * instance value associated with a key
+ */
+#define kSCDInstance CFSTR("instance")
+/*
+ * client session ids watching a key and, since we can possibly have
+ * multiple regex keys which reference the key, a count of active
+ * references
+ */
+#define kSCDWatchers CFSTR("watchers")
+#define kSCDWatcherRefs CFSTR("watcherRefs")
+/*
+ * client session id for per-session keys.
+ */
+#define kSCDSession CFSTR("session")
+
+
+/*
+ * keys in the "sessionData" dictionary
+ */
+
+/*
+ * the name of the calling application / plug-in
+ */
+#define kSCDName CFSTR("name")
+/*
+ * keys which have changed since last call to SCDNotifierGetChanges()
+ */
+#define kSCDChangedKeys CFSTR("changedKeys")
+/*
+ * for notification keys which consist of a regular expression we keep
+ * both the pattern string and the compiled regular expression
+ */
+#define kSCDRegexKeys CFSTR("regexKeys")
+#define kSCDRegexData CFSTR("regexData")
+/*
+ * keys which are to be removed when the session is closed
+ */
+#define kSCDSessionKeys CFSTR("sessionKeys")
+
+
+extern CFMutableDictionaryRef cacheData;
+extern CFMutableDictionaryRef sessionData;
+extern CFMutableSetRef changedKeys;
+extern CFMutableSetRef deferredRemovals;
+extern CFMutableSetRef removedSessionKeys;
+extern CFMutableSetRef needsNotification;
+
+extern CFMutableDictionaryRef cacheData_s;
+extern CFMutableSetRef changedKeys_s;
+extern CFMutableSetRef deferredRemovals_s;
+extern CFMutableSetRef removedSessionKeys_s;
+
+/*
+ * "context" argument for CFDictionaryArrayApplier _addRegexWatcherByKey(),
+ * _addRegexWatcherBySession(), and _removeRegexWatcherByKey() functions.
+ */
+typedef struct {
+ SCDSessionPrivateRef session;
+ regex_t *preg;
+} addContext, *addContextRef;
+
+
+typedef struct {
+ SCDSessionPrivateRef session;
+ regex_t *preg;
+} removeContext, *removeContextRef;
+
+
+__BEGIN_DECLS
+
+SCDStatus _SCDOpen __P((SCDSessionRef *session,
+ CFStringRef name));
+
+SCDStatus _SCDClose __P((SCDSessionRef *session));
+
+SCDStatus _SCDLock __P((SCDSessionRef session));
+
+SCDStatus _SCDUnlock __P((SCDSessionRef session));
+
+SCDStatus _SCDList __P((SCDSessionRef session,
+ CFStringRef key,
+ int regexOptions,
+ CFArrayRef *subKeys));
+
+SCDStatus _SCDAdd __P((SCDSessionRef session,
+ CFStringRef key,
+ SCDHandleRef handle));
+
+SCDStatus _SCDAddSession __P((SCDSessionRef session,
+ CFStringRef key,
+ SCDHandleRef handle));
+
+SCDStatus _SCDGet __P((SCDSessionRef session,
+ CFStringRef key,
+ SCDHandleRef *handle));
+
+SCDStatus _SCDSet __P((SCDSessionRef session,
+ CFStringRef key,
+ SCDHandleRef handle));
+
+SCDStatus _SCDRemove __P((SCDSessionRef session,
+ CFStringRef key));
+
+SCDStatus _SCDTouch __P((SCDSessionRef session,
+ CFStringRef key));
+
+SCDStatus _SCDSnapshot __P((SCDSessionRef session));
+
+SCDStatus _SCDNotifierList __P((SCDSessionRef session,
+ int regexOptions,
+ CFArrayRef *notifierKeys));
+
+SCDStatus _SCDNotifierAdd __P((SCDSessionRef session,
+ CFStringRef key,
+ int regexOptions));
+
+SCDStatus _SCDNotifierRemove __P((SCDSessionRef session,
+ CFStringRef key,
+ int regexOptions));
+
+SCDStatus _SCDNotifierGetChanges __P((SCDSessionRef session,
+ CFArrayRef *notifierKeys));
+
+SCDStatus _SCDNotifierInformViaMachPort __P((SCDSessionRef session,
+ mach_msg_id_t msgid,
+ mach_port_t *port));
+
+SCDStatus _SCDNotifierInformViaFD __P((SCDSessionRef session,
+ int32_t identifier,
+ int *fd));
+
+SCDStatus _SCDNotifierInformViaSignal __P((SCDSessionRef session,
+ pid_t pid,
+ int sig));
+
+SCDStatus _SCDNotifierCancel __P((SCDSessionRef session));
+
+void _swapLockedCacheData __P(());
+
+void _addWatcher __P((CFNumberRef sessionNum,
+ CFStringRef watchedKey));
+
+void _addRegexWatcherByKey __P((const void *key,
+ void *val,
+ void *context));
+
+void _addRegexWatchersBySession __P((const void *key,
+ void *val,
+ void *context));
+
+void _removeWatcher __P((CFNumberRef sessionNum,
+ CFStringRef watchedKey));
+
+void _removeRegexWatcherByKey __P((const void *key,
+ void *val,
+ void *context));
+
+void _removeRegexWatchersBySession __P((const void *key,
+ void *val,
+ void *context));
+
+__END_DECLS
+
+#endif /* !_S_SCD_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDAdd(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ SCDStatus scd_status = SCD_OK;
+ boolean_t wasLocked;
+ SCDHandleRef tempHandle;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDAdd:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" data = %@"), SCDHandleGetData(handle));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /*
+ * 1. Determine if the cache lock is currently held
+ * and acquire the lock if necessary.
+ */
+ wasLocked = SCDOptionGet(NULL, kSCDOptionIsLocked);
+ if (!wasLocked) {
+ scd_status = _SCDLock(session);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" _SCDLock(): %s"), SCDError(scd_status));
+ return scd_status;
+ }
+ }
+
+ /*
+ * 2. Ensure that this is a new key.
+ */
+ scd_status = _SCDGet(session, key, &tempHandle);
+ switch (scd_status) {
+ case SCD_NOKEY :
+ /* cache key does not exist, proceed */
+ break;
+
+ case SCD_OK :
+ /* cache key exists, sorry */
+ SCDHandleRelease(tempHandle);
+ scd_status = SCD_EXISTS;
+ goto done;
+
+ default :
+ SCDLog(LOG_DEBUG, CFSTR(" _SCDGet(): %s"), SCDError(scd_status));
+ goto done;
+ }
+
+ /*
+ * 3. Save the new key.
+ */
+ scd_status = _SCDSet(session, key, handle);
+
+ /*
+ * 4. Release the lock if we acquired it as part of this request.
+ */
+ done:
+ if (!wasLocked)
+ _SCDUnlock(session);
+
+ return scd_status;
+}
+
+
+kern_return_t
+_configadd(mach_port_t server,
+ xmlData_t keyRef, /* raw XML bytes */
+ mach_msg_type_number_t keyLen,
+ xmlData_t dataRef, /* raw XML bytes */
+ mach_msg_type_number_t dataLen,
+ int *newInstance,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFDataRef xmlKey; /* key (XML serialized) */
+ CFStringRef key; /* key (un-serialized) */
+ CFDataRef xmlData; /* data (XML serialized) */
+ CFPropertyListRef data; /* data (un-serialized) */
+ SCDHandleRef handle;
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("Add key to configuration database."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the key */
+ xmlKey = CFDataCreate(NULL, keyRef, keyLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ key = CFPropertyListCreateFromXMLData(NULL,
+ xmlKey,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlKey);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ /* un-serialize the data */
+ xmlData = CFDataCreate(NULL, dataRef, dataLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ data = CFPropertyListCreateFromXMLData(NULL,
+ xmlData,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlData);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() data: %s"), xmlError);
+ CFRelease(key);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ handle = SCDHandleInit();
+ SCDHandleSetData(handle, data);
+ *scd_status = _SCDAdd(mySession->session, key, handle);
+ if (*scd_status == SCD_OK) {
+ *newInstance = SCDHandleGetInstance(handle);
+ }
+ SCDHandleRelease(handle);
+ CFRelease(key);
+ CFRelease(data);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDAddSession(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ SCDStatus scd_status = SCD_OK;
+ CFStringRef sessionKey;
+ CFDictionaryRef dict;
+ CFMutableDictionaryRef newDict;
+ CFArrayRef keys;
+ CFMutableArrayRef newKeys;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDAddSession:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" data = %@"), SCDHandleGetData(handle));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /*
+ * 1. Add the key
+ */
+ scd_status = _SCDAdd(session, key, handle);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" _SCDAdd(): %s"), SCDError(scd_status));
+ return scd_status;
+ }
+
+ /*
+ * 2. Create the session key
+ */
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
+
+ /*
+ * 3. Add this key to my list of per-session keys
+ */
+ dict = CFDictionaryGetValue(sessionData, sessionKey);
+ keys = CFDictionaryGetValue(dict, kSCDSessionKeys);
+ if ((keys == NULL) ||
+ (CFArrayGetFirstIndexOfValue(keys,
+ CFRangeMake(0, CFArrayGetCount(keys)),
+ key) == -1)) {
+ /*
+ * if no session keys defined "or" keys defined but not
+ * this one...
+ */
+ if (keys) {
+ /* this is a new session key */
+ newKeys = CFArrayCreateMutableCopy(NULL, 0, keys);
+ } else {
+ /* this is an additional session key */
+ newKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+ CFArrayAppendValue(newKeys, key);
+
+ /* update session dictionary */
+ newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+ CFDictionarySetValue(newDict, kSCDSessionKeys, newKeys);
+ CFRelease(newKeys);
+ CFDictionarySetValue(sessionData, sessionKey, newDict);
+ CFRelease(newDict);
+ }
+
+ /*
+ * 4. Mark the key as a "session" key and track the creator.
+ */
+ dict = CFDictionaryGetValue(cacheData, key);
+ newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+ CFDictionarySetValue(newDict, kSCDSession, sessionKey);
+ CFDictionarySetValue(cacheData, key, newDict);
+ CFRelease(newDict);
+
+ CFRelease(sessionKey);
+ return scd_status;
+}
+
+
+kern_return_t
+_configadd_s(mach_port_t server,
+ xmlData_t keyRef, /* raw XML bytes */
+ mach_msg_type_number_t keyLen,
+ xmlData_t dataRef, /* raw XML bytes */
+ mach_msg_type_number_t dataLen,
+ int *newInstance,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFDataRef xmlKey; /* key (XML serialized) */
+ CFStringRef key; /* key (un-serialized) */
+ CFDataRef xmlData; /* data (XML serialized) */
+ CFPropertyListRef data; /* data (un-serialized) */
+ SCDHandleRef handle;
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("Add (session) key to configuration database."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the key */
+ xmlKey = CFDataCreate(NULL, keyRef, keyLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ key = CFPropertyListCreateFromXMLData(NULL,
+ xmlKey,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlKey);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ /* un-serialize the data */
+ xmlData = CFDataCreate(NULL, dataRef, dataLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ data = CFPropertyListCreateFromXMLData(NULL,
+ xmlData,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlData);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() data: %s"), xmlError);
+ CFRelease(key);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ handle = SCDHandleInit();
+ SCDHandleSetData(handle, data);
+ *scd_status = _SCDAddSession(mySession->session, key, handle);
+ if (*scd_status == SCD_OK) {
+ *newInstance = SCDHandleGetInstance(handle);
+ }
+ SCDHandleRelease(handle);
+ CFRelease(key);
+ CFRelease(data);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <unistd.h>
+
+#include "configd.h"
+#include "session.h"
+
+static boolean_t
+isMySessionKey(CFStringRef sessionKey, CFStringRef key)
+{
+ CFDictionaryRef dict;
+ CFStringRef cacheSessionKey;
+
+ dict = CFDictionaryGetValue(cacheData, key);
+ if (!dict) {
+ /* if key no longer exists */
+ return FALSE;
+ }
+
+ cacheSessionKey = CFDictionaryGetValue(dict, kSCDSession);
+ if (!cacheSessionKey) {
+ /* if this is not a session key */
+ return FALSE;
+ }
+
+ if (!CFEqual(sessionKey, cacheSessionKey)) {
+ /* if this is not "my" session key */
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+SCDStatus
+_SCDClose(SCDSessionRef *session)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)*session;
+ CFIndex keyCnt;
+ CFStringRef sessionKey;
+ CFDictionaryRef dict;
+ CFArrayRef keys;
+ serverSessionRef mySession;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDClose:"));
+
+ if ((*session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION;
+ }
+
+ /* Remove notification keys */
+ if ((keyCnt = CFSetGetCount(sessionPrivate->keys)) > 0) {
+ void **watchedKeys;
+ CFArrayRef keysToRemove;
+ CFIndex i;
+
+ watchedKeys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
+ CFSetGetValues(sessionPrivate->keys, watchedKeys);
+ keysToRemove = CFArrayCreate(NULL, watchedKeys, keyCnt, &kCFTypeArrayCallBacks);
+ CFAllocatorDeallocate(NULL, watchedKeys);
+ for (i=0; i<keyCnt; i++) {
+ (void) _SCDNotifierRemove(*session,
+ CFArrayGetValueAtIndex(keysToRemove, i),
+ 0);
+ }
+ CFRelease(keysToRemove);
+ }
+
+ /* Remove regex notification keys */
+ if ((keyCnt = CFSetGetCount(sessionPrivate->reKeys)) > 0) {
+ void **watchedKeys;
+ CFArrayRef keysToRemove;
+ CFIndex i;
+
+ watchedKeys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
+ CFSetGetValues(sessionPrivate->reKeys, watchedKeys);
+ keysToRemove = CFArrayCreate(NULL, watchedKeys, keyCnt, &kCFTypeArrayCallBacks);
+ CFAllocatorDeallocate(NULL, watchedKeys);
+ for (i=0; i<keyCnt; i++) {
+ (void) _SCDNotifierRemove(*session,
+ CFArrayGetValueAtIndex(keysToRemove, i),
+ kSCDRegexKey);
+ }
+ CFRelease(keysToRemove);
+ }
+
+ /* Remove/cancel any outstanding notification requests. */
+ (void) _SCDNotifierCancel(*session);
+
+ /* Remove any session keys */
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
+ dict = CFDictionaryGetValue(sessionData, sessionKey);
+ keys = CFDictionaryGetValue(dict, kSCDSessionKeys);
+ if (keys && ((keyCnt = CFArrayGetCount(keys)) > 0)) {
+ boolean_t wasLocked;
+ CFIndex i;
+
+ /*
+ * if necessary, claim a lock to ensure that we inform
+ * any processes that a session key was removed.
+ */
+ wasLocked = SCDOptionGet(NULL, kSCDOptionIsLocked);
+ if (!wasLocked) {
+ (void) _SCDLock(*session);
+ }
+
+ /* remove keys from "locked" cache" */
+ for (i=0; i<keyCnt; i++) {
+ if (isMySessionKey(sessionKey, CFArrayGetValueAtIndex(keys, i)))
+ (void) _SCDRemove(*session, CFArrayGetValueAtIndex(keys, i));
+ }
+
+ if (wasLocked) {
+ /* remove keys from "unlocked" cache" */
+ _swapLockedCacheData();
+ for (i=0; i<keyCnt; i++) {
+ if (isMySessionKey(sessionKey, CFArrayGetValueAtIndex(keys, i)))
+ (void) _SCDRemove(*session, CFArrayGetValueAtIndex(keys, i));
+ }
+ _swapLockedCacheData();
+ }
+
+ /*
+ * Note: everyone who calls _SCDClose() ends up
+ * removing this sessions dictionary. As
+ * such, we don't need to worry about
+ * the session keys.
+ */
+ }
+ CFRelease(sessionKey);
+
+ /* release the lock */
+ if (SCDOptionGet(*session, kSCDOptionIsLocked)) {
+ (void) _SCDUnlock(*session);
+ }
+
+ /*
+ * Invalidate the server port (for this client) which will result
+ * in the removal of any associated run loop sources.
+ */
+ mySession = getSession(sessionPrivate->server);
+ if (mySession->serverRunLoopSource) {
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
+ mySession->serverRunLoopSource,
+ kCFRunLoopDefaultMode);
+ CFRelease(mySession->serverRunLoopSource);
+ }
+ CFMachPortInvalidate(mySession->serverPort);
+ CFRelease(mySession->serverPort);
+
+ CFRelease(sessionPrivate->keys);
+ CFRelease(sessionPrivate->reKeys);
+ CFAllocatorDeallocate(NULL, sessionPrivate);
+ *session = NULL;
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_configclose(mach_port_t server, int *scd_status)
+{
+ serverSessionRef mySession = getSession(server);
+
+ SCDLog(LOG_DEBUG, CFSTR("Close session."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /*
+ * Close the session.
+ */
+ *scd_status = _SCDClose(&mySession->session);
+ if (*scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" _SCDClose(): %s"), SCDError(*scd_status));
+ return KERN_SUCCESS;
+ }
+
+ /*
+ * Remove the session entry.
+ */
+ removeSession(server);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDGet(SCDSessionRef session, CFStringRef key, SCDHandleRef *handle)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ CFDictionaryRef dict;
+ CFNumberRef num;
+ int dictInstance;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDGet:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION;
+ }
+
+ dict = CFDictionaryGetValue(cacheData, key);
+ if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDData) == FALSE)) {
+ /* key doesn't exist (or data never defined) */
+ return SCD_NOKEY;
+ }
+
+ /* Create a new handle associated with the cached data */
+ *handle = SCDHandleInit();
+
+ /* Return the data associated with the key */
+ SCDHandleSetData(*handle, CFDictionaryGetValue(dict, kSCDData));
+
+ /* Return the instance number associated with the key */
+ num = CFDictionaryGetValue(dict, kSCDInstance);
+ (void) CFNumberGetValue(num, kCFNumberIntType, &dictInstance);
+ _SCDHandleSetInstance(*handle, dictInstance);
+
+ SCDLog(LOG_DEBUG, CFSTR(" data = %@"), SCDHandleGetData(*handle));
+ SCDLog(LOG_DEBUG, CFSTR(" instance = %d"), SCDHandleGetInstance(*handle));
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_configget(mach_port_t server,
+ xmlData_t keyRef, /* raw XML bytes */
+ mach_msg_type_number_t keyLen,
+ xmlDataOut_t *dataRef, /* raw XML bytes */
+ mach_msg_type_number_t *dataLen,
+ int *newInstance,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFDataRef xmlKey; /* key (XML serialized) */
+ CFStringRef key; /* key (un-serialized) */
+ CFDataRef xmlData; /* data (XML serialized) */
+ SCDHandleRef handle;
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("Get key from configuration database."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the key */
+ xmlKey = CFDataCreate(NULL, keyRef, keyLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ key = CFPropertyListCreateFromXMLData(NULL,
+ xmlKey,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlKey);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ *scd_status = _SCDGet(mySession->session, key, &handle);
+ CFRelease(key);
+ if (*scd_status != SCD_OK) {
+ *dataRef = NULL;
+ *dataLen = 0;
+ return KERN_SUCCESS;
+ }
+
+ /*
+ * serialize the data, copy it into an allocated buffer which will be
+ * released when it is returned as part of a Mach message.
+ */
+ xmlData = CFPropertyListCreateXMLData(NULL, SCDHandleGetData(handle));
+ *dataLen = CFDataGetLength(xmlData);
+ status = vm_allocate(mach_task_self(), (void *)dataRef, *dataLen, TRUE);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_allocate(): %s"), mach_error_string(status));
+ *scd_status = SCD_FAILED;
+ CFRelease(xmlData);
+ *dataRef = NULL;
+ *dataLen = 0;
+ return KERN_SUCCESS;
+ }
+
+ bcopy((char *)CFDataGetBytePtr(xmlData), *dataRef, *dataLen);
+ CFRelease(xmlData);
+
+ /*
+ * return the instance number associated with the returned data.
+ */
+ *newInstance = SCDHandleGetInstance(handle);
+
+ SCDHandleRelease(handle);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDList(SCDSessionRef session, CFStringRef key, int regexOptions, CFArrayRef *subKeys)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ CFIndex cacheCnt;
+ void **cacheKeys;
+ void **cacheValues;
+ CFMutableArrayRef keyArray;
+ int i;
+ CFStringRef cacheStr;
+ CFDictionaryRef cacheValue;
+ int regexStrLen;
+ char *regexStr = NULL;
+ regex_t preg;
+ int reError;
+ char reErrBuf[256];
+ int reErrStrLen;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDList:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" regexOptions = %0o"), regexOptions);
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION;
+ }
+
+ cacheCnt = CFDictionaryGetCount(cacheData);
+ keyArray = CFArrayCreateMutable(NULL, cacheCnt, &kCFTypeArrayCallBacks);
+
+ if (regexOptions & kSCDRegexKey) {
+ /*
+ * compile the provided regular expression using the
+ * provided regexOptions (passing only those flags
+ * which would make sense).
+ */
+ regexStrLen = CFStringGetLength(key) + 1;
+ regexStr = CFAllocatorAllocate(NULL, regexStrLen, 0);
+ if (!CFStringGetCString(key,
+ regexStr,
+ regexStrLen,
+ kCFStringEncodingMacRoman)) {
+ SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString() key: could not convert to regex string"));
+ CFAllocatorDeallocate(NULL, regexStr);
+ return SCD_FAILED;
+ }
+
+ reError = regcomp(&preg, regexStr, REG_EXTENDED);
+ if (reError != 0) {
+ reErrStrLen = regerror(reError, &preg, reErrBuf, sizeof(reErrBuf));
+ cacheStr = CFStringCreateWithCString(NULL, reErrBuf, kCFStringEncodingMacRoman);
+ CFArrayAppendValue(keyArray, cacheStr);
+ CFRelease(cacheStr);
+ *subKeys = CFArrayCreateCopy(NULL, keyArray);
+ CFRelease(keyArray);
+ CFAllocatorDeallocate(NULL, regexStr);
+ return SCD_FAILED;
+ }
+ }
+
+ cacheKeys = CFAllocatorAllocate(NULL, cacheCnt * sizeof(CFStringRef), 0);
+ cacheValues = CFAllocatorAllocate(NULL, cacheCnt * sizeof(CFStringRef), 0);
+ CFDictionaryGetKeysAndValues(cacheData, cacheKeys, cacheValues);
+ for (i=0; i<cacheCnt; i++) {
+ cacheStr = (CFStringRef)cacheKeys[i];
+ cacheValue = (CFDictionaryRef)cacheValues[i];
+ if (regexOptions & kSCDRegexKey) {
+ /*
+ * only return those keys which match the regular
+ * expression specified in the provided key.
+ */
+
+ int cacheKeyLen = CFStringGetLength(cacheStr) + 1;
+ char *cacheKey = CFAllocatorAllocate(NULL, cacheKeyLen, 0);
+
+ if (!CFStringGetCString(cacheStr,
+ cacheKey,
+ cacheKeyLen,
+ kCFStringEncodingMacRoman)) {
+ SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert cache key to C string"));
+ CFAllocatorDeallocate(NULL, cacheKey);
+ continue;
+ }
+
+ reError = regexec(&preg,
+ cacheKey,
+ 0,
+ NULL,
+ 0);
+ switch (reError) {
+ case 0 :
+ /* we've got a match */
+ if (CFDictionaryContainsKey(cacheValue, kSCDData))
+ CFArrayAppendValue(keyArray, cacheStr);
+ break;
+ case REG_NOMATCH :
+ /* no match */
+ break;
+ default :
+ reErrStrLen = regerror(reError,
+ &preg,
+ reErrBuf,
+ sizeof(reErrBuf));
+ SCDLog(LOG_DEBUG, CFSTR("regexec(): %s"), reErrBuf);
+ break;
+ }
+ CFAllocatorDeallocate(NULL, cacheKey);
+ } else {
+ /*
+ * only return those keys which are prefixed by the
+ * provided key string and have data.
+ */
+ if (((CFStringGetLength(key) == 0) || CFStringHasPrefix(cacheStr, key)) &&
+ CFDictionaryContainsKey(cacheValue, kSCDData)) {
+ CFArrayAppendValue(keyArray, cacheStr);
+ }
+ }
+ }
+ CFAllocatorDeallocate(NULL, cacheKeys);
+ CFAllocatorDeallocate(NULL, cacheValues);
+
+ if (regexOptions & kSCDRegexKey) {
+ regfree(&preg);
+ }
+
+ *subKeys = keyArray;
+
+ if (regexOptions & kSCDRegexKey) {
+ CFAllocatorDeallocate(NULL, regexStr);
+ }
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_configlist(mach_port_t server,
+ xmlData_t keyRef, /* raw XML bytes */
+ mach_msg_type_number_t keyLen,
+ int regexOptions,
+ xmlDataOut_t *listRef, /* raw XML bytes */
+ mach_msg_type_number_t *listLen,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFDataRef xmlKey; /* key (XML serialized) */
+ CFStringRef key; /* key (un-serialized) */
+ CFArrayRef subKeys; /* array of CFStringRef's */
+ CFDataRef xmlList; /* list (XML serialized) */
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("List keys in configuration database."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the key */
+ xmlKey = CFDataCreate(NULL, keyRef, keyLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ key = CFPropertyListCreateFromXMLData(NULL,
+ xmlKey,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlKey);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ *scd_status = _SCDList(mySession->session, key, regexOptions, &subKeys);
+ CFRelease(key);
+ if (*scd_status != SCD_OK) {
+ *listRef = NULL;
+ *listLen = 0;
+ return KERN_SUCCESS;
+ }
+
+ /*
+ * serialize the array, copy it into an allocated buffer which will be
+ * released when it is returned as part of a Mach message.
+ */
+ xmlList = CFPropertyListCreateXMLData(NULL, subKeys);
+ CFRelease(subKeys);
+ *listLen = CFDataGetLength(xmlList);
+ status = vm_allocate(mach_task_self(), (void *)listRef, *listLen, TRUE);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_allocate(): %s"), mach_error_string(status));
+ *scd_status = SCD_FAILED;
+ CFRelease(xmlList);
+ *listRef = NULL;
+ *listLen = 0;
+ return KERN_SUCCESS;
+ }
+ bcopy((char *)CFDataGetBytePtr(xmlList), *listRef, *listLen);
+ CFRelease(xmlList);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "configd_server.h"
+#include "session.h"
+
+
+SCDStatus
+_SCDLock(SCDSessionRef session)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ serverSessionRef mySession;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDLock:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ if (SCDOptionGet(NULL, kSCDOptionIsLocked)) {
+ return SCD_LOCKED; /* sorry, someone (you) already have the lock */
+ }
+
+ /* check credentials */
+ mySession = getSession(sessionPrivate->server);
+ if (mySession->callerEUID != 0) {
+#ifdef DEBUG
+ if (!SCDOptionGet(NULL, kSCDOptionDebug)) {
+#endif /* DEBUG */
+ return SCD_EACCESS;
+#ifdef DEBUG
+ } else {
+ SCDLog(LOG_DEBUG, CFSTR(" non-root access granted while debugging"));
+ }
+#endif /* DEBUG */
+ }
+
+ SCDOptionSet(NULL, kSCDOptionIsLocked, TRUE); /* global lock flag */
+ SCDOptionSet(session, kSCDOptionIsLocked, TRUE); /* per-session lock flag */
+
+ /*
+ * defer all (actually, most) changes until the call to _SCDUnlock()
+ */
+ if (cacheData_s) {
+ CFRelease(cacheData_s);
+ CFRelease(changedKeys_s);
+ CFRelease(deferredRemovals_s);
+ CFRelease(removedSessionKeys_s);
+ }
+ cacheData_s = CFDictionaryCreateMutableCopy(NULL, 0, cacheData);
+ changedKeys_s = CFSetCreateMutableCopy(NULL, 0, changedKeys);
+ deferredRemovals_s = CFSetCreateMutableCopy(NULL, 0, deferredRemovals);
+ removedSessionKeys_s = CFSetCreateMutableCopy(NULL, 0, removedSessionKeys);
+
+ /* Add a "locked" mode run loop source for this port */
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), mySession->serverRunLoopSource, CFSTR("locked"));
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_configlock(mach_port_t server, int *scd_status)
+{
+ serverSessionRef mySession = getSession(server);
+
+ SCDLog(LOG_DEBUG, CFSTR("Lock configuration database."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ *scd_status = _SCDLock(mySession->session);
+ if (*scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" SCDLock(): %s"), SCDError(*scd_status));
+ return KERN_SUCCESS;
+ }
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "configd_server.h"
+#include "session.h"
+
+SCDStatus
+_SCDOpen(SCDSessionRef *session, CFStringRef name)
+{
+ SCDSessionPrivateRef sessionPrivate;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDOpen:"));
+ SCDLog(LOG_DEBUG, CFSTR(" name = %@"), name);
+
+ /*
+ * allocate and initialize a new session
+ */
+ sessionPrivate = (SCDSessionPrivateRef)_SCDSessionCreatePrivate();
+ *session = (SCDSessionRef)sessionPrivate;
+
+ /*
+ * If necessary, initialize the cache and session data dictionaries
+ */
+ if (cacheData == NULL) {
+ cacheData = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ sessionData = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ changedKeys = CFSetCreateMutable(NULL,
+ 0,
+ &kCFTypeSetCallBacks);
+ deferredRemovals = CFSetCreateMutable(NULL,
+ 0,
+ &kCFTypeSetCallBacks);
+ removedSessionKeys = CFSetCreateMutable(NULL,
+ 0,
+ &kCFTypeSetCallBacks);
+ }
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_configopen(mach_port_t server,
+ xmlData_t nameRef, /* raw XML bytes */
+ mach_msg_type_number_t nameLen,
+ mach_port_t *newServer,
+ int *scd_status)
+{
+ kern_return_t status;
+ serverSessionRef mySession, newSession;
+ CFDataRef xmlName; /* name (XML serialized) */
+ CFStringRef name; /* name (un-serialized) */
+ CFStringRef xmlError;
+ mach_port_t oldNotify;
+ CFStringRef sessionKey;
+ CFDictionaryRef info;
+ CFMutableDictionaryRef newInfo;
+ CFMachPortRef mp;
+
+ SCDLog(LOG_DEBUG, CFSTR("Open new session."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the name */
+ xmlName = CFDataCreate(NULL, nameRef, nameLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)nameRef, nameLen);
+ if (status != KERN_SUCCESS) {
+ CFRelease(xmlName);
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ name = CFPropertyListCreateFromXMLData(NULL,
+ xmlName,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlName);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() name: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ mySession = getSession(server);
+ if (mySession->session) {
+ CFRelease(name);
+ SCDLog(LOG_DEBUG, CFSTR(" Sorry, this session is already open."));
+ *scd_status = SCD_FAILED; /* you can't re-open an "open" session */
+ return KERN_SUCCESS;
+ }
+
+ /* Create the server port for this session */
+ mp = CFMachPortCreate(NULL, configdCallback, NULL, NULL);
+
+ /* return the newly allocated port to be used for this session */
+ *newServer = CFMachPortGetPort(mp);
+
+ /*
+ * establish the new session
+ */
+ newSession = addSession(mp);
+
+ /* Create and add a run loop source for the port */
+ newSession->serverRunLoopSource = CFMachPortCreateRunLoopSource(NULL, mp, 0);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(),
+ newSession->serverRunLoopSource,
+ kCFRunLoopDefaultMode);
+
+ /*
+ * save the credentials associated with the caller.
+ */
+ newSession->callerEUID = mySession->callerEUID;
+ newSession->callerEGID = mySession->callerEGID;
+
+ *scd_status = _SCDOpen(&newSession->session, name);
+
+ /*
+ * Make the server port accessible to the framework routines.
+ */
+ ((SCDSessionPrivateRef)newSession->session)->server = *newServer;
+
+ /* Request a notification when/if the client dies */
+ status = mach_port_request_notification(mach_task_self(),
+ *newServer,
+ MACH_NOTIFY_NO_SENDERS,
+ 1,
+ *newServer,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &oldNotify);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_request_notification(): %s"), mach_error_string(status));
+ CFRelease(name);
+ cleanupSession(*newServer);
+ *newServer = MACH_PORT_NULL;
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+#ifdef DEBUG
+ if (oldNotify != MACH_PORT_NULL) {
+ SCDLog(LOG_DEBUG, CFSTR("_configopen(): why is oldNotify != MACH_PORT_NULL?"));
+ }
+#endif /* DEBUG */
+
+ /*
+ * Save the name of the calling application / plug-in with the session data.
+ */
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), *newServer);
+ info = CFDictionaryGetValue(sessionData, sessionKey);
+ if (info) {
+ newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
+ } else {
+ newInfo = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(newInfo, kSCDName, name);
+ CFRelease(name);
+ CFDictionarySetValue(sessionData, sessionKey, newInfo);
+ CFRelease(newInfo);
+ CFRelease(sessionKey);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDRemove(SCDSessionRef session, CFStringRef key)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ SCDStatus scd_status = SCD_OK;
+ boolean_t wasLocked;
+ CFDictionaryRef dict;
+ CFMutableDictionaryRef newDict;
+ CFStringRef sessionKey;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDRemove:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /*
+ * 1. Determine if the cache lock is currently held and acquire
+ * the lock if necessary.
+ */
+ wasLocked = SCDOptionGet(NULL, kSCDOptionIsLocked);
+ if (!wasLocked) {
+ scd_status = _SCDLock(session);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" _SCDLock(): %s"), SCDError(scd_status));
+ return scd_status;
+ }
+ }
+
+ /*
+ * 2. Ensure that this key exists.
+ */
+ dict = CFDictionaryGetValue(cacheData, key);
+ if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDData) == FALSE)) {
+ /* key doesn't exist (or data never defined) */
+ scd_status = SCD_NOKEY;
+ goto done;
+ }
+ newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict);
+
+ /*
+ * 3. Mark this key as "changed". Any "watchers" will be
+ * notified as soon as the lock is released.
+ */
+ CFSetAddValue(changedKeys, key);
+
+ /*
+ * 4. Add this key to a deferred cleanup list so that, after
+ * the change notifications are posted, any associated
+ * regex keys can be removed.
+ */
+ CFSetAddValue(deferredRemovals, key);
+
+ /*
+ * 5. Check if this is a session key and, if so, add it
+ * to the (session) removal list
+ */
+ sessionKey = CFDictionaryGetValue(newDict, kSCDSession);
+ if (sessionKey) {
+ CFStringRef removedKey;
+
+ /* We are no longer a session key! */
+ CFDictionaryRemoveValue(newDict, kSCDSession);
+
+ /* add this session key to the (session) removal list */
+ removedKey = CFStringCreateWithFormat(NULL, 0, CFSTR("%@:%@"), sessionKey, key);
+ CFSetAddValue(removedSessionKeys, removedKey);
+ CFRelease(removedKey);
+ }
+
+ /*
+ * 6. Remove data, remove instance, and update/remove
+ * the dictionary cache entry.
+ */
+ CFDictionaryRemoveValue(newDict, kSCDData);
+ CFDictionaryRemoveValue(newDict, kSCDInstance);
+ if (CFDictionaryGetCount(newDict) > 0) {
+ /* this key is still being "watched" */
+ CFDictionarySetValue(cacheData, key, newDict);
+ } else {
+ /* no information left, remove the empty dictionary */
+ CFDictionaryRemoveValue(cacheData, key);
+ }
+ CFRelease(newDict);
+
+ /*
+ * 7. Release the lock if we acquired it as part of this request.
+ */
+ done:
+ if (!wasLocked)
+ _SCDUnlock(session);
+
+ return scd_status;
+}
+
+
+kern_return_t
+_configremove(mach_port_t server,
+ xmlData_t keyRef, /* raw XML bytes */
+ mach_msg_type_number_t keyLen,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFDataRef xmlKey; /* key (XML serialized) */
+ CFStringRef key; /* key (un-serialized) */
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("Remove key from configuration database."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the key */
+ xmlKey = CFDataCreate(NULL, keyRef, keyLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ key = CFPropertyListCreateFromXMLData(NULL,
+ xmlKey,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlKey);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ *scd_status = _SCDRemove(mySession->session, key);
+ CFRelease(key);
+
+ return KERN_SUCCESS;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDSet(SCDSessionRef session, CFStringRef key, SCDHandleRef handle)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ SCDStatus scd_status = SCD_OK;
+ boolean_t wasLocked;
+ CFDictionaryRef dict;
+ CFMutableDictionaryRef newDict;
+ CFNumberRef num;
+ int dictInstance;
+ CFStringRef sessionKey;
+ CFStringRef cacheSessionKey;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDSet:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" data = %@"), SCDHandleGetData(handle));
+ SCDLog(LOG_DEBUG, CFSTR(" instance = %d"), SCDHandleGetInstance(handle));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /*
+ * 1. Determine if the cache lock is currently held
+ * and acquire the lock if necessary.
+ */
+ wasLocked = SCDOptionGet(NULL, kSCDOptionIsLocked);
+ if (!wasLocked) {
+ scd_status = _SCDLock(session);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" _SCDLock(): %s"), SCDError(scd_status));
+ return scd_status;
+ }
+ }
+
+ /*
+ * 2. Grab the current (or establish a new) dictionary for this key.
+ */
+
+ dict = CFDictionaryGetValue(cacheData, key);
+ if (dict) {
+ newDict = CFDictionaryCreateMutableCopy(NULL,
+ 0,
+ dict);
+ } else {
+ newDict = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ /*
+ * 3. Make sure that we're not updating the cache with potentially
+ * stale information.
+ */
+
+ if ((num = CFDictionaryGetValue(newDict, kSCDInstance)) == NULL) {
+ /* if first instance */
+ dictInstance = 0;
+ _SCDHandleSetInstance(handle, dictInstance);
+ } else {
+ (void) CFNumberGetValue(num, kCFNumberIntType, &dictInstance);
+ }
+ if (SCDHandleGetInstance(handle) != dictInstance) {
+ /* data may be based on old information */
+ CFRelease(newDict);
+ scd_status = SCD_STALE;
+ goto done;
+ }
+
+ /*
+ * 4. Update the dictionary entry (data & instance) to be saved to
+ * the cache.
+ */
+
+ CFDictionarySetValue(newDict, kSCDData, SCDHandleGetData(handle));
+
+ dictInstance++;
+ num = CFNumberCreate(NULL, kCFNumberIntType, &dictInstance);
+ CFDictionarySetValue(newDict, kSCDInstance, num);
+ CFRelease(num);
+ _SCDHandleSetInstance(handle, dictInstance);
+ SCDLog(LOG_DEBUG, CFSTR(" new instance = %d"), SCDHandleGetInstance(handle));
+
+ /*
+ * 5. Since we are updating this key we need to check and, if
+ * necessary, remove the indication that this key is on
+ * another session's remove-on-close list.
+ */
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
+ if (CFDictionaryGetValueIfPresent(newDict, kSCDSession, (void *)&cacheSessionKey) &&
+ !CFEqual(sessionKey, cacheSessionKey)) {
+ CFStringRef removedKey;
+
+ /* We are no longer a session key! */
+ CFDictionaryRemoveValue(newDict, kSCDSession);
+
+ /* add this session key to the (session) removal list */
+ removedKey = CFStringCreateWithFormat(NULL, 0, CFSTR("%@:%@"), cacheSessionKey, key);
+ CFSetAddValue(removedSessionKeys, removedKey);
+ CFRelease(removedKey);
+ }
+ CFRelease(sessionKey);
+
+ /*
+ * 6. Update the dictionary entry in the cache.
+ */
+
+ CFDictionarySetValue(cacheData, key, newDict);
+ CFRelease(newDict);
+
+ /*
+ * 7. For "new" entries to the cache, check the deferred cleanup
+ * list. If the key is flagged for removal, remove it from the
+ * list since any defined regex's for this key are still defined
+ * and valid. If the key is not flagged then iterate over the
+ * sessionData dictionary looking for regex keys which match the
+ * updated key. If a match is found then we mark those keys as
+ * being watched.
+ */
+
+ if (dictInstance == 1) {
+ if (CFSetContainsValue(deferredRemovals, key)) {
+ CFSetRemoveValue(deferredRemovals, key);
+ } else {
+ CFDictionaryApplyFunction(sessionData,
+ (CFDictionaryApplierFunction)_addRegexWatchersBySession,
+ (void *)key);
+ }
+ }
+
+ /*
+ * 8. Mark this key as "changed". Any "watchers" will be notified
+ * as soon as the lock is released.
+ */
+ CFSetAddValue(changedKeys, key);
+
+ /*
+ * 9. Release the lock if we acquired it as part of this request.
+ */
+ done:
+ if (!wasLocked)
+ _SCDUnlock(session);
+
+ return scd_status;
+}
+
+
+kern_return_t
+_configset(mach_port_t server,
+ xmlData_t keyRef, /* raw XML bytes */
+ mach_msg_type_number_t keyLen,
+ xmlData_t dataRef, /* raw XML bytes */
+ mach_msg_type_number_t dataLen,
+ int oldInstance,
+ int *newInstance,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFDataRef xmlKey; /* key (XML serialized) */
+ CFStringRef key; /* key (un-serialized) */
+ CFDataRef xmlData; /* data (XML serialized) */
+ CFPropertyListRef data; /* data (un-serialized) */
+ SCDHandleRef handle;
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("Set key to configuration database."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the key */
+ xmlKey = CFDataCreate(NULL, keyRef, keyLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ key = CFPropertyListCreateFromXMLData(NULL,
+ xmlKey,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlKey);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ /* un-serialize the data */
+ xmlData = CFDataCreate(NULL, dataRef, dataLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ data = CFPropertyListCreateFromXMLData(NULL,
+ xmlData,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlData);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() data: %s"), xmlError);
+ CFRelease(key);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ handle = SCDHandleInit();
+ SCDHandleSetData(handle, data);
+ _SCDHandleSetInstance(handle, oldInstance);
+ *scd_status = _SCDSet(mySession->session, key, handle);
+ if (*scd_status == SCD_OK) {
+ *newInstance = SCDHandleGetInstance(handle);
+ }
+ SCDHandleRelease(handle);
+ CFRelease(key);
+ CFRelease(data);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDTouch(SCDSessionRef session, CFStringRef key)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ SCDStatus scd_status;
+ boolean_t wasLocked;
+ SCDHandleRef handle;
+ CFPropertyListRef value;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDTouch:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /*
+ * 1. Determine if the cache lock is currently held by this session
+ * and acquire the lock if necessary.
+ */
+ wasLocked = SCDOptionGet(NULL, kSCDOptionIsLocked);
+ if (!wasLocked) {
+ scd_status = _SCDLock(session);
+ if (scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" _SCDLock(): %s"), SCDError(scd_status));
+ return scd_status;
+ }
+ }
+
+ /*
+ * 2. Grab the current (or establish a new) cache entry for this key.
+ */
+ scd_status = _SCDGet(session, key, &handle);
+ switch (scd_status) {
+ case SCD_NOKEY :
+ /* cache entry does not exist, create */
+ handle = SCDHandleInit();
+ value = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
+ SCDLog(LOG_DEBUG, CFSTR(" new time stamp = %@"), value);
+ SCDHandleSetData(handle, value);
+ CFRelease(value);
+ break;
+
+ case SCD_OK :
+ /* cache entry exists, update */
+ value = SCDHandleGetData(handle);
+ if (CFGetTypeID(value) == CFDateGetTypeID()) {
+ /* if value is a CFDate */
+ value = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent());
+ SCDLog(LOG_DEBUG, CFSTR(" new time stamp = %@"), value);
+ SCDHandleSetData(handle, value);
+ CFRelease(value);
+ } /* else, we'll just save the data (again) to bump the instance */
+ break;
+
+ default :
+ SCDLog(LOG_DEBUG, CFSTR(" _SCDGet(): %s"), SCDError(scd_status));
+ goto done;
+ }
+
+ scd_status = _SCDSet(session, key, handle);
+ SCDHandleRelease(handle);
+
+ done :
+
+ /*
+ * 8. Release the lock if we acquired it as part of this request.
+ */
+ if (!wasLocked)
+ _SCDUnlock(session);
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_configtouch(mach_port_t server,
+ xmlData_t keyRef, /* raw XML bytes */
+ mach_msg_type_number_t keyLen,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFDataRef xmlKey; /* key (XML serialized) */
+ CFStringRef key; /* key (un-serialized) */
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("Touch key in configuration database."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the key */
+ xmlKey = CFDataCreate(NULL, keyRef, keyLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ key = CFPropertyListCreateFromXMLData(NULL,
+ xmlKey,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlKey);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ *scd_status = _SCDTouch(mySession->session, key);
+ CFRelease(key);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include "configd.h"
+#include "configd_server.h"
+#include "session.h"
+
+
+static void
+_notifyWatchers()
+{
+ CFIndex keyCnt;
+ void **keys;
+
+ if ((keyCnt = CFSetGetCount(changedKeys)) == 0)
+ return; /* if nothing to do */
+
+ keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
+ CFSetGetValues(changedKeys, keys);
+ while (--keyCnt >= 0) {
+ CFDictionaryRef dict;
+ CFArrayRef sessionsWatchingKey;
+ CFIndex watcherCnt;
+ void **watchers;
+ CFDictionaryRef info;
+ CFMutableDictionaryRef newInfo;
+ CFArrayRef changes;
+ CFMutableArrayRef newChanges;
+
+ dict = CFDictionaryGetValue(cacheData, (CFStringRef)keys[keyCnt]);
+ if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDWatchers) == FALSE)) {
+ /* key doesn't exist or nobody cares if it changed */
+ continue;
+ }
+
+ /*
+ * Add this key to the list of changes for each of the
+ * sessions which is "watching".
+ */
+ sessionsWatchingKey = CFDictionaryGetValue(dict, kSCDWatchers);
+ watcherCnt = CFArrayGetCount(sessionsWatchingKey);
+ watchers = CFAllocatorAllocate(NULL, watcherCnt * sizeof(CFNumberRef), 0);
+ CFArrayGetValues(sessionsWatchingKey,
+ CFRangeMake(0, CFArrayGetCount(sessionsWatchingKey)),
+ watchers);
+ while (--watcherCnt >= 0) {
+ CFStringRef sessionKey;
+
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@"), watchers[watcherCnt]);
+ info = CFDictionaryGetValue(sessionData, sessionKey);
+ if (info) {
+ newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
+ } else {
+ newInfo = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ changes = CFDictionaryGetValue(newInfo, kSCDChangedKeys);
+ if (changes) {
+ newChanges = CFArrayCreateMutableCopy(NULL, 0, changes);
+ } else {
+ newChanges = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+
+ if (CFArrayContainsValue(newChanges,
+ CFRangeMake(0, CFArrayGetCount(newChanges)),
+ (CFStringRef)keys[keyCnt]) == FALSE) {
+ CFArrayAppendValue(newChanges, (CFStringRef)keys[keyCnt]);
+ }
+ CFDictionarySetValue(newInfo, kSCDChangedKeys, newChanges);
+ CFRelease(newChanges);
+ CFDictionarySetValue(sessionData, sessionKey, newInfo);
+ CFRelease(newInfo);
+ CFRelease(sessionKey);
+
+ /*
+ * flag this session as needing a kick
+ */
+ if (needsNotification == NULL)
+ needsNotification = CFSetCreateMutable(NULL,
+ 0,
+ &kCFTypeSetCallBacks);
+ CFSetAddValue(needsNotification, watchers[watcherCnt]);
+ }
+ CFAllocatorDeallocate(NULL, watchers);
+ }
+ CFAllocatorDeallocate(NULL, keys);
+
+ /*
+ * The list of changed keys have been updated for any sessions
+ * monitoring changes to the "cache". The next step, handled by
+ * the "configd" server, is to push out any needed notifications.
+ */
+ CFSetRemoveAllValues(changedKeys);
+
+}
+
+
+static void
+_processDeferredRemovals()
+{
+ CFIndex keyCnt;
+ void **keys;
+
+ if ((keyCnt = CFSetGetCount(deferredRemovals)) == 0)
+ return; /* if nothing to do */
+
+ keys = CFAllocatorAllocate(NULL, keyCnt * sizeof(CFStringRef), 0);
+ CFSetGetValues(deferredRemovals, keys);
+ while (--keyCnt >= 0) {
+ CFDictionaryApplyFunction(sessionData,
+ (CFDictionaryApplierFunction)_removeRegexWatchersBySession,
+ keys[keyCnt]);
+ }
+ CFAllocatorDeallocate(NULL, keys);
+
+ /*
+ * All regex keys associated with removed cache dictionary keys have
+ * been removed. Start the list fresh again.
+ */
+ CFSetRemoveAllValues(deferredRemovals);
+
+ return;
+}
+
+
+static void
+_cleanupRemovedSessionKeys(const void *value, void *context)
+{
+ CFStringRef removedKey = (CFStringRef)value;
+ CFRange dRange;
+ CFStringRef sessionKey;
+ CFStringRef key;
+ CFDictionaryRef sessionDict;
+ CFArrayRef sessionKeys;
+ CFIndex i;
+ CFMutableDictionaryRef newSessionDict;
+
+ dRange = CFStringFind(removedKey, CFSTR(":"), 0);
+ sessionKey = CFStringCreateWithSubstring(NULL,
+ removedKey,
+ CFRangeMake(0, dRange.location));
+ key = CFStringCreateWithSubstring(NULL,
+ removedKey,
+ CFRangeMake(dRange.location+dRange.length,
+ CFStringGetLength(removedKey)-dRange.location-dRange.length));
+
+ /*
+ * remove the key from the session key list
+ */
+ sessionDict = CFDictionaryGetValue(sessionData, sessionKey);
+ if (!sessionDict) {
+ /* if no session */
+ goto done;
+ }
+
+ sessionKeys = CFDictionaryGetValue(sessionDict, kSCDSessionKeys);
+ if (!sessionKeys) {
+ /* if no session keys */
+ goto done;
+ }
+
+ i = CFArrayGetFirstIndexOfValue(sessionKeys,
+ CFRangeMake(0, CFArrayGetCount(sessionKeys)),
+ key);
+ if (i == -1) {
+ /* if this session key has already been removed */
+ goto done;
+ }
+
+ newSessionDict = CFDictionaryCreateMutableCopy(NULL, 0, sessionDict);
+ if (CFArrayGetCount(sessionKeys) == 1) {
+ /* remove the last (session) key */
+ CFDictionaryRemoveValue(newSessionDict, kSCDSessionKeys);
+ } else {
+ CFMutableArrayRef newSessionKeys;
+
+ /* remove the (session) key */
+ newSessionKeys = CFArrayCreateMutableCopy(NULL, 0, sessionKeys);
+ CFArrayRemoveValueAtIndex(newSessionKeys, i);
+ CFDictionarySetValue(newSessionDict, kSCDSessionKeys, newSessionKeys);
+ CFRelease(newSessionKeys);
+ }
+ CFDictionarySetValue(sessionData, sessionKey, newSessionDict);
+ CFRelease(newSessionDict);
+
+ done:
+
+ CFRelease(sessionKey);
+ CFRelease(key);
+
+ return;
+}
+
+
+SCDStatus
+_SCDUnlock(SCDSessionRef session)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ serverSessionRef mySession;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDUnlock:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION;
+ }
+
+ if (!SCDOptionGet(NULL, kSCDOptionIsLocked) || !SCDOptionGet(session, kSCDOptionIsLocked)) {
+ return SCD_NEEDLOCK; /* sorry, you don't have the lock */
+ }
+
+ /*
+ * all of the changes can be committed to the (real) cache.
+ */
+ CFDictionaryRemoveAllValues(cacheData_s);
+ CFSetRemoveAllValues (changedKeys_s);
+ CFSetRemoveAllValues (deferredRemovals_s);
+ CFSetRemoveAllValues (removedSessionKeys_s);
+
+#ifdef DEBUG
+ SCDLog(LOG_DEBUG, CFSTR("keys I changed = %@"), changedKeys);
+ SCDLog(LOG_DEBUG, CFSTR("keys flagged for removal = %@"), deferredRemovals);
+ SCDLog(LOG_DEBUG, CFSTR("keys I'm watching = %@"), sessionPrivate->keys);
+ SCDLog(LOG_DEBUG, CFSTR("regex keys I'm watching = %@"), sessionPrivate->reKeys);
+#endif /* DEBUG */
+
+ /*
+ * push notifications to any session watching those keys which
+ * were recently changed.
+ */
+ _notifyWatchers();
+
+ /*
+ * process any deferred key deletions.
+ */
+ _processDeferredRemovals();
+
+ /*
+ * clean up any removed session keys
+ */
+ CFSetApplyFunction(removedSessionKeys, _cleanupRemovedSessionKeys, NULL);
+ CFSetRemoveAllValues(removedSessionKeys);
+
+#ifdef DEBUG
+ SCDLog(LOG_DEBUG, CFSTR("sessions to notify = %@"), needsNotification);
+#endif /* DEBUG */
+
+ /* Remove the "locked" run loop source for this port */
+ mySession = getSession(sessionPrivate->server);
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mySession->serverRunLoopSource, CFSTR("locked"));
+
+ SCDOptionSet(NULL, kSCDOptionIsLocked, FALSE); /* global lock flag */
+ SCDOptionSet(session, kSCDOptionIsLocked, FALSE); /* per-session lock flag */
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_configunlock(mach_port_t server, int *scd_status)
+{
+ serverSessionRef mySession = getSession(server);
+
+ SCDLog(LOG_DEBUG, CFSTR("Unlock configuration database."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ *scd_status = _SCDUnlock(mySession->session);
+ if (*scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" _SCDUnlock(): %s"), SCDError(*scd_status));
+ return KERN_SUCCESS;
+ }
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDNotifierAdd(SCDSessionRef session, CFStringRef key, int regexOptions)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDNotifierAdd:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" regexOptions = %0o"), regexOptions);
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /*
+ * add new key after checking if key has already been defined
+ */
+ if (regexOptions & kSCDRegexKey) {
+ if (CFSetContainsValue(sessionPrivate->reKeys, key))
+ return SCD_EXISTS; /* sorry, key already exists in notifier list */
+ CFSetAddValue(sessionPrivate->reKeys, key); /* add key to this sessions notifier list */
+ } else {
+ if (CFSetContainsValue(sessionPrivate->keys, key))
+ return SCD_EXISTS; /* sorry, key already exists in notifier list */
+ CFSetAddValue(sessionPrivate->keys, key); /* add key to this sessions notifier list */
+ }
+
+ if (regexOptions & kSCDRegexKey) {
+ CFStringRef sessionKey;
+ int regexStrLen;
+ char *regexStr;
+ CFMutableDataRef regexData;
+ int reError;
+ char reErrBuf[256];
+ int reErrStrLen;
+ addContext context;
+ CFDictionaryRef info;
+ CFMutableDictionaryRef newInfo;
+ CFArrayRef rKeys;
+ CFMutableArrayRef newRKeys;
+ CFArrayRef rData;
+ CFMutableArrayRef newRData;
+
+ /*
+ * We are adding a regex key. As such, we need to flag
+ * any keys currently in the cache.
+ */
+
+ /* 1. Extract a C String version of the key pattern string. */
+
+ regexStrLen = CFStringGetLength(key) + 1;
+ regexStr = CFAllocatorAllocate(NULL, regexStrLen, 0);
+ if (!CFStringGetCString(key,
+ regexStr,
+ regexStrLen,
+ kCFStringEncodingMacRoman)) {
+ SCDLog(LOG_DEBUG, CFSTR("CFStringGetCString: could not convert regex key to C string"));
+ CFAllocatorDeallocate(NULL, regexStr);
+ return SCD_FAILED;
+ }
+
+ /* 2. Compile the regular expression from the pattern string. */
+
+ regexData = CFDataCreateMutable(NULL, sizeof(regex_t));
+ CFDataSetLength(regexData, sizeof(regex_t));
+ reError = regcomp((regex_t *)CFDataGetBytePtr(regexData),
+ regexStr,
+ REG_EXTENDED);
+ CFAllocatorDeallocate(NULL, regexStr);
+ if (reError != 0) {
+ reErrStrLen = regerror(reError,
+ (regex_t *)CFDataGetBytePtr(regexData),
+ reErrBuf,
+ sizeof(reErrBuf));
+ SCDLog(LOG_DEBUG, CFSTR("regcomp() key: %s"), reErrBuf);
+ CFRelease(regexData);
+ return SCD_FAILED;
+ }
+
+ /*
+ * 3. Iterate over the current keys and add this session as a "watcher"
+ * for any key already defined in the cache.
+ */
+
+ context.session = sessionPrivate;
+ context.preg = (regex_t *)CFDataGetBytePtr(regexData);
+ CFDictionaryApplyFunction(cacheData,
+ (CFDictionaryApplierFunction)_addRegexWatcherByKey,
+ &context);
+
+ /*
+ * 4. We also need to save this key and the associated regex data
+ * for any subsequent additions.
+ */
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
+
+ info = CFDictionaryGetValue(sessionData, sessionKey);
+ if (info) {
+ newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
+ } else {
+ newInfo = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+
+ rKeys = CFDictionaryGetValue(newInfo, kSCDRegexKeys);
+ if ((rKeys == NULL) ||
+ (CFArrayContainsValue(rKeys,
+ CFRangeMake(0, CFArrayGetCount(rKeys)),
+ key) == FALSE)) {
+ rData = CFDictionaryGetValue(newInfo, kSCDRegexData);
+ if (rKeys) {
+ newRKeys = CFArrayCreateMutableCopy(NULL, 0, rKeys);
+ newRData = CFArrayCreateMutableCopy(NULL, 0, rData);
+ } else {
+ newRKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ newRData = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+
+ /* save the regex key */
+ CFArrayAppendValue(newRKeys, key);
+ CFDictionarySetValue(newInfo, kSCDRegexKeys, newRKeys);
+ CFRelease(newRKeys);
+ /* ...and the compiled expression */
+ CFArrayAppendValue(newRData, regexData);
+ CFDictionarySetValue(newInfo, kSCDRegexData, newRData);
+ CFRelease(newRData);
+ CFDictionarySetValue(sessionData, sessionKey, newInfo);
+ }
+ CFRelease(newInfo);
+ CFRelease(sessionKey);
+ } else {
+ CFNumberRef sessionNum;
+
+ /*
+ * We are watching a specific key. As such, update the
+ * cache to mark our interest in any changes.
+ */
+ sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionPrivate->server);
+ _addWatcher(sessionNum, key);
+ CFRelease(sessionNum);
+ }
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_notifyadd(mach_port_t server,
+ xmlData_t keyRef, /* raw XML bytes */
+ mach_msg_type_number_t keyLen,
+ int regexOptions,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFDataRef xmlKey; /* key (XML serialized) */
+ CFStringRef key; /* key (un-serialized) */
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("Add notification key for this session."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the key */
+ xmlKey = CFDataCreate(NULL, keyRef, keyLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ key = CFPropertyListCreateFromXMLData(NULL,
+ xmlKey,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlKey);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ *scd_status = _SCDNotifierAdd(mySession->session, key, regexOptions);
+ CFRelease(key);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <unistd.h>
+
+#include "configd.h"
+#include "session.h"
+
+
+SCDStatus
+_SCDNotifierCancel(SCDSessionRef session)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDNotifierCancel:"));
+
+ if (session == NULL) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ /*
+ * cleanup any mach port based notifications.
+ */
+ if (sessionPrivate->notifyPort != MACH_PORT_NULL) {
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->notifyPort);
+ sessionPrivate->notifyPort = MACH_PORT_NULL;
+ }
+
+ /*
+ * cleanup any file based notifications.
+ */
+ if (sessionPrivate->notifyFile >= 0) {
+ SCDLog(LOG_DEBUG, CFSTR(" closing (notification) fd %d"), sessionPrivate->notifyFile);
+ (void) close(sessionPrivate->notifyFile);
+ sessionPrivate->notifyFile = -1;
+ }
+
+ /*
+ * cleanup any signal notifications.
+ */
+ if (sessionPrivate->notifySignal > 0) {
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->notifySignalTask);
+ sessionPrivate->notifySignal = 0;
+ sessionPrivate->notifySignalTask = TASK_NULL;
+ }
+
+ /* remove this session from the to-be-notified list */
+ if (needsNotification) {
+ CFNumberRef num;
+
+ num = CFNumberCreate(NULL, kCFNumberIntType, &sessionPrivate->server);
+ CFSetRemoveValue(needsNotification, num);
+ CFRelease(num);
+
+ if (CFSetGetCount(needsNotification) == 0) {
+ CFRelease(needsNotification);
+ needsNotification = NULL;
+ }
+ }
+
+ /* set notifier inactive */
+ sessionPrivate->notifyStatus = NotifierNotRegistered;
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_notifycancel(mach_port_t server,
+ int *scd_status)
+{
+ serverSessionRef mySession = getSession(server);
+
+ SCDLog(LOG_DEBUG, CFSTR("Cancel requested notifications."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ *scd_status = _SCDNotifierCancel(mySession->session);
+ if (*scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" SCDNotifierCancel(): %s"), SCDError(*scd_status));
+ }
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDNotifierGetChanges(SCDSessionRef session, CFArrayRef *notifierKeys)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ CFStringRef sessionKey;
+ CFDictionaryRef info;
+ CFMutableDictionaryRef newInfo;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDNotifierGetChanges:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION;
+ }
+
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
+ info = CFDictionaryGetValue(sessionData, sessionKey);
+ if ((info == NULL) ||
+ (CFDictionaryContainsKey(info, kSCDChangedKeys) == FALSE)) {
+ CFRelease(sessionKey);
+ *notifierKeys = CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);;
+ return SCD_OK;
+ }
+ newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
+
+ *notifierKeys = CFDictionaryGetValue(newInfo, kSCDChangedKeys);
+ CFRetain(*notifierKeys);
+
+ CFDictionaryRemoveValue(newInfo, kSCDChangedKeys);
+ if (CFDictionaryGetCount(newInfo) > 0) {
+ CFDictionarySetValue(sessionData, sessionKey, newInfo);
+ } else {
+ CFDictionaryRemoveValue(sessionData, sessionKey);
+ }
+ CFRelease(newInfo);
+ CFRelease(sessionKey);
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_notifychanges(mach_port_t server,
+ xmlDataOut_t *listRef, /* raw XML bytes */
+ mach_msg_type_number_t *listLen,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFArrayRef notifierKeys; /* array of CFStringRef's */
+ CFDataRef xmlList; /* list (XML serialized) */
+
+ SCDLog(LOG_DEBUG, CFSTR("List notification keys which have changed."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ *scd_status = _SCDNotifierGetChanges(mySession->session, ¬ifierKeys);
+ if (*scd_status != SCD_OK) {
+ *listRef = NULL;
+ *listLen = 0;
+ return KERN_SUCCESS;
+ }
+
+ /*
+ * serialize the array, copy it into an allocated buffer which will be
+ * released when it is returned as part of a Mach message.
+ */
+ xmlList = CFPropertyListCreateXMLData(NULL, notifierKeys);
+ CFRelease(notifierKeys);
+ *listLen = CFDataGetLength(xmlList);
+ status = vm_allocate(mach_task_self(), (void *)listRef, *listLen, TRUE);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_allocate(): %s"), mach_error_string(status));
+ CFRelease(xmlList);
+ *listRef = NULL;
+ *listLen = 0;
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ bcopy((char *)CFDataGetBytePtr(xmlList), *listRef, *listLen);
+ CFRelease(xmlList);
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDNotifierRemove(SCDSessionRef session, CFStringRef key, int regexOptions)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDNotifierRemove:"));
+ SCDLog(LOG_DEBUG, CFSTR(" key = %@"), key);
+ SCDLog(LOG_DEBUG, CFSTR(" regexOptions = %0o"), regexOptions);
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you can't do anything with a closed session */
+ }
+
+ /*
+ * remove key from this sessions notifier list after checking that
+ * it was previously defined.
+ */
+ if (regexOptions & kSCDRegexKey) {
+ if (!CFSetContainsValue(sessionPrivate->reKeys, key))
+ return SCD_NOKEY; /* sorry, key does not exist in notifier list */
+ CFSetRemoveValue(sessionPrivate->reKeys, key); /* remove key from this sessions notifier list */
+ } else {
+ if (!CFSetContainsValue(sessionPrivate->keys, key))
+ return SCD_NOKEY; /* sorry, key does not exist in notifier list */
+ CFSetRemoveValue(sessionPrivate->keys, key); /* remove key from this sessions notifier list */
+ }
+
+ if (regexOptions & kSCDRegexKey) {
+ CFStringRef sessionKey;
+ CFDictionaryRef info;
+ CFMutableDictionaryRef newInfo;
+ CFArrayRef rKeys;
+ CFMutableArrayRef newRKeys;
+ CFArrayRef rData;
+ CFMutableArrayRef newRData;
+ CFIndex i;
+ CFDataRef regexData;
+ removeContext context;
+
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
+
+ info = CFDictionaryGetValue(sessionData, sessionKey);
+ newInfo = CFDictionaryCreateMutableCopy(NULL, 0, info);
+
+ rKeys = CFDictionaryGetValue(newInfo, kSCDRegexKeys);
+ newRKeys = CFArrayCreateMutableCopy(NULL, 0, rKeys);
+
+ rData = CFDictionaryGetValue(newInfo, kSCDRegexData);
+ newRData = CFArrayCreateMutableCopy(NULL, 0, rData);
+
+ i = CFArrayGetFirstIndexOfValue(newRKeys,
+ CFRangeMake(0, CFArrayGetCount(newRData)),
+ key);
+ regexData = CFArrayGetValueAtIndex(newRData, i);
+
+ context.session = sessionPrivate;
+ context.preg = (regex_t *)CFDataGetBytePtr(regexData);
+ CFDictionaryApplyFunction(cacheData,
+ (CFDictionaryApplierFunction)_removeRegexWatcherByKey,
+ &context);
+
+ /* remove the regex key */
+ CFArrayRemoveValueAtIndex(newRKeys, i);
+ if (CFArrayGetCount(newRKeys) > 0) {
+ CFDictionarySetValue(newInfo, kSCDRegexKeys, newRKeys);
+ } else {
+ CFDictionaryRemoveValue(newInfo, kSCDRegexKeys);
+ }
+ CFRelease(newRKeys);
+
+ /* ...and the compiled expression */
+ regfree((regex_t *)CFDataGetBytePtr(regexData));
+ CFArrayRemoveValueAtIndex(newRData, i);
+ if (CFArrayGetCount(newRData) > 0) {
+ CFDictionarySetValue(newInfo, kSCDRegexData, newRData);
+ } else {
+ CFDictionaryRemoveValue(newInfo, kSCDRegexData);
+ }
+ CFRelease(newRData);
+
+ /* save the updated session data */
+ CFDictionarySetValue(sessionData, sessionKey, newInfo);
+ CFRelease(newInfo);
+
+ CFRelease(sessionKey);
+ } else {
+ CFNumberRef sessionNum;
+
+ /*
+ * We are watching a specific key. As such, update the
+ * cache to mark our interest in any changes.
+ */
+
+ sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionPrivate->server);
+ _removeWatcher(sessionNum, key);
+ CFRelease(sessionNum);
+ }
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_notifyremove(mach_port_t server,
+ xmlData_t keyRef, /* raw XML bytes */
+ mach_msg_type_number_t keyLen,
+ int regexOptions,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ CFDataRef xmlKey; /* key (XML serialized) */
+ CFStringRef key; /* key (un-serialized) */
+ CFStringRef xmlError;
+
+ SCDLog(LOG_DEBUG, CFSTR("Remove notification key for this session."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+
+ /* un-serialize the key */
+ xmlKey = CFDataCreate(NULL, keyRef, keyLen);
+ status = vm_deallocate(mach_task_self(), (vm_address_t)keyRef, keyLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ key = CFPropertyListCreateFromXMLData(NULL,
+ xmlKey,
+ kCFPropertyListImmutable,
+ &xmlError);
+ CFRelease(xmlKey);
+ if (xmlError) {
+ SCDLog(LOG_DEBUG, CFSTR("CFPropertyListCreateFromXMLData() key: %s"), xmlError);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ *scd_status = _SCDNotifierRemove(mySession->session, key, regexOptions);
+ CFRelease(key);
+
+ return KERN_SUCCESS;
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "configd.h"
+#include "session.h"
+
+
+SCDStatus
+_SCDNotifierInformViaFD(SCDSessionRef session,
+ int32_t identifier,
+ int *fd)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ int sock;
+ CFStringRef sessionKey;
+ CFDictionaryRef info;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDNotifierInformViaFD:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ if (sessionPrivate->notifyStatus != NotifierNotRegistered) {
+ /* sorry, you can only have one notification registered at once */
+ return SCD_NOTIFIERACTIVE;
+ }
+
+ if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
+ SCDLog(LOG_NOTICE, CFSTR("socket: %s"), strerror(errno));
+ return SCD_FAILED;
+ }
+
+ *fd = sock;
+
+ /* push out a notification if any changes are pending */
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
+ info = CFDictionaryGetValue(sessionData, sessionKey);
+ CFRelease(sessionKey);
+ if (info && CFDictionaryContainsKey(info, kSCDChangedKeys)) {
+ CFNumberRef sessionNum;
+
+ if (needsNotification == NULL)
+ needsNotification = CFSetCreateMutable(NULL,
+ 0,
+ &kCFTypeSetCallBacks);
+
+ sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionPrivate->server);
+ CFSetAddValue(needsNotification, sessionNum);
+ CFRelease(sessionNum);
+ }
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_notifyviafd(mach_port_t server,
+ xmlData_t pathRef,
+ mach_msg_type_number_t pathLen,
+ int identifier,
+ int *scd_status
+)
+{
+ kern_return_t status;
+ serverSessionRef mySession = getSession(server);
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)mySession->session;
+ struct sockaddr_un un;
+ int sock;
+ int bufSiz = sizeof(sessionPrivate->notifyFileIdentifier);
+ int nbioYes = 1;
+
+ SCDLog(LOG_DEBUG, CFSTR("Send message via UNIX domain socket when a notification key changes."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+ SCDLog(LOG_DEBUG, CFSTR(" path = %s"), pathRef);
+
+ /*
+ * if socket currently open, close it!
+ */
+ /* validate the UNIX domain socket path */
+ if (pathLen > (sizeof(un.sun_path) - 1)) {
+ SCDLog(LOG_NOTICE, CFSTR("domain socket path length too long!"));
+ status = vm_deallocate(mach_task_self(), (vm_address_t)pathRef, pathLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ /* un-serialize the UNIX domain socket path */
+ un.sun_family = AF_UNIX;
+ bcopy(pathRef, un.sun_path, pathLen);
+ un.sun_path[pathLen] = '\0';
+ status = vm_deallocate(mach_task_self(), (vm_address_t)pathRef, pathLen);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("vm_deallocate(): %s"), mach_error_string(status));
+ /* non-fatal???, proceed */
+ }
+
+ /* do common sanity checks, get socket */
+ *scd_status = _SCDNotifierInformViaFD(mySession->session, identifier, &sock);
+
+ /* check status of _SCDNotifierInformViaFD() */
+ if (*scd_status != SCD_OK) {
+ return KERN_SUCCESS;
+ }
+
+ /* establish the connection, get ready for a read() */
+ if (connect(sock, (struct sockaddr *)&un, sizeof(un)) == -1) {
+ SCDLog(LOG_DEBUG, CFSTR("connect: %s"), strerror(errno));
+ (void) close(sock);
+ sessionPrivate->notifyStatus = NotifierNotRegistered;
+ sessionPrivate->notifyFile = -1;
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ SCDLog(LOG_NOTICE, CFSTR(" fd = %d"), sock);
+ (void) unlink(un.sun_path);
+
+ if (setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &bufSiz, sizeof(bufSiz)) < 0) {
+ SCDLog(LOG_DEBUG, CFSTR("setsockopt: %s"), strerror(errno));
+ (void) close(sock);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ if (ioctl(sock, FIONBIO, &nbioYes) == -1) {
+ SCDLog(LOG_DEBUG, CFSTR("ioctl(,FIONBIO,): %s"), strerror(errno));
+ (void) close(sock);
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+ /* set notifier active */
+ sessionPrivate->notifyStatus = Using_NotifierInformViaFD;
+ sessionPrivate->notifyFile = sock;
+ sessionPrivate->notifyFileIdentifier = identifier;
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+SCDStatus
+_SCDNotifierInformViaMachPort(SCDSessionRef session, mach_msg_id_t identifier, mach_port_t *port)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ CFStringRef sessionKey;
+ CFDictionaryRef info;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDNotifierInformViaMachPort:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ if (sessionPrivate->notifyStatus != NotifierNotRegistered) {
+ /* sorry, you can only have one notification registered at once */
+ return SCD_NOTIFIERACTIVE;
+ }
+
+ if (*port == MACH_PORT_NULL) {
+ /* sorry, you must specify a valid mach port */
+ return SCD_INVALIDARGUMENT;
+ }
+
+ /* push out a notification if any changes are pending */
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
+ info = CFDictionaryGetValue(sessionData, sessionKey);
+ CFRelease(sessionKey);
+ if (info && CFDictionaryContainsKey(info, kSCDChangedKeys)) {
+ CFNumberRef sessionNum;
+
+ if (needsNotification == NULL)
+ needsNotification = CFSetCreateMutable(NULL,
+ 0,
+ &kCFTypeSetCallBacks);
+
+ sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionPrivate->server);
+ CFSetAddValue(needsNotification, sessionNum);
+ CFRelease(sessionNum);
+ }
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_notifyviaport(mach_port_t server,
+ mach_port_t port,
+ mach_msg_id_t identifier,
+ int *scd_status
+)
+{
+ serverSessionRef mySession = getSession(server);
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)mySession->session;
+
+ SCDLog(LOG_DEBUG, CFSTR("Send mach message when a notification key changes."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+ SCDLog(LOG_DEBUG, CFSTR(" port = %d"), port);
+ SCDLog(LOG_DEBUG, CFSTR(" message id = %d"), identifier);
+
+ if (sessionPrivate->notifyPort != MACH_PORT_NULL) {
+ SCDLog(LOG_DEBUG, CFSTR(" destroying old callback mach port %d"), sessionPrivate->notifyPort);
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->notifyPort);
+ }
+
+ *scd_status = _SCDNotifierInformViaMachPort(mySession->session, identifier, &port);
+
+ if (*scd_status == SCD_OK) {
+ /* save notification port, requested identifier, and set notifier active */
+ sessionPrivate->notifyStatus = Using_NotifierInformViaMachPort;
+ sessionPrivate->notifyPort = port;
+ sessionPrivate->notifyPortIdentifier = identifier;
+ }
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "configd_server.h"
+#include "session.h"
+
+SCDStatus
+_SCDNotifierInformViaSignal(SCDSessionRef session, pid_t pid, int sig)
+{
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)session;
+ CFStringRef sessionKey;
+ CFDictionaryRef info;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDNotifierInformViaSignal:"));
+
+ if ((session == NULL) || (sessionPrivate->server == MACH_PORT_NULL)) {
+ return SCD_NOSESSION; /* you must have an open session to play */
+ }
+
+ if (sessionPrivate->notifyStatus != NotifierNotRegistered) {
+ /* sorry, you can only have one notification registered at once */
+ return SCD_NOTIFIERACTIVE;
+ }
+
+ if ((sig <= 0) || (sig > NSIG)) {
+ /* sorry, you must specify a valid signal */
+ return SCD_INVALIDARGUMENT;
+ }
+
+ /* push out a notification if any changes are pending */
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), sessionPrivate->server);
+ info = CFDictionaryGetValue(sessionData, sessionKey);
+ CFRelease(sessionKey);
+ if (info && CFDictionaryContainsKey(info, kSCDChangedKeys)) {
+ CFNumberRef sessionNum;
+
+ if (needsNotification == NULL)
+ needsNotification = CFSetCreateMutable(NULL,
+ 0,
+ &kCFTypeSetCallBacks);
+
+ sessionNum = CFNumberCreate(NULL, kCFNumberIntType, &sessionPrivate->server);
+ CFSetAddValue(needsNotification, sessionNum);
+ CFRelease(sessionNum);
+ }
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_notifyviasignal(mach_port_t server,
+ task_t task,
+ int sig,
+ int *scd_status)
+{
+ serverSessionRef mySession = getSession(server);
+ SCDSessionPrivateRef sessionPrivate = (SCDSessionPrivateRef)mySession->session;
+#if defined(DEBUG) || defined(NOTYET)
+ kern_return_t status;
+#endif
+#ifdef NOTYET
+ mach_port_t oldNotify;
+#endif /* NOTYET */
+
+ SCDLog(LOG_DEBUG, CFSTR("Send signal when a notification key changes."));
+ SCDLog(LOG_DEBUG, CFSTR(" server = %d"), server);
+ SCDLog(LOG_DEBUG, CFSTR(" task = %d"), task);
+ SCDLog(LOG_DEBUG, CFSTR(" signal = %d"), sig);
+
+ *scd_status = _SCDNotifierInformViaSignal(mySession->session, 0, sig); /* pid is N/A for server */
+ if (*scd_status != SCD_OK) {
+ if (task != TASK_NULL) {
+ (void) mach_port_destroy(mach_task_self(), task);
+ }
+ return KERN_SUCCESS;
+ }
+
+#ifdef DEBUG
+ { mach_port_type_t pt;
+
+ status = mach_port_type(mach_task_self(), task, &pt);
+ if (status == MACH_MSG_SUCCESS) {
+ char rights[8], *rp = &rights[0];
+
+ if (pt & MACH_PORT_TYPE_SEND)
+ *rp++ = 'S';
+ if (pt & MACH_PORT_TYPE_RECEIVE)
+ *rp++ = 'R';
+ if (pt & MACH_PORT_TYPE_SEND_ONCE)
+ *rp++ = 'O';
+ if (pt & MACH_PORT_TYPE_PORT_SET)
+ *rp++ = 'P';
+ if (pt & MACH_PORT_TYPE_DEAD_NAME)
+ *rp++ = 'D';
+ *rp = '\0';
+
+ SCDLog(LOG_DEBUG, CFSTR("Task %d, port rights = %s"), task, rights);
+ }
+ }
+#endif /* DEBUG */
+
+#ifdef NOTYET
+ /* Request a notification when/if the client dies */
+ status = mach_port_request_notification(mach_task_self(),
+ task,
+ MACH_NOTIFY_DEAD_NAME,
+ 1,
+ task,
+ MACH_MSG_TYPE_MAKE_SEND_ONCE,
+ &oldNotify);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_request_notification(): %s"), mach_error_string(status));
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+
+#ifdef DEBUG
+ if (oldNotify != MACH_PORT_NULL) {
+ SCDLog(LOG_DEBUG, CFSTR("_notifyviasignal(): why is oldNotify != MACH_PORT_NULL?"));
+ }
+#endif /* DEBUG */
+
+ SCDLog(LOG_DEBUG, CFSTR("Adding task notification port %d to the server's port set"), task);
+ status = mach_port_move_member(mach_task_self(), task, server_ports);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("mach_port_move_member(): %s"), mach_error_string(status));
+ *scd_status = SCD_FAILED;
+ return KERN_SUCCESS;
+ }
+#endif /* NOTYET */
+
+ sessionPrivate->notifyStatus = Using_NotifierInformViaSignal;
+ sessionPrivate->notifySignal = sig;
+ sessionPrivate->notifySignalTask = task;
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <fcntl.h>
+#include <paths.h>
+#include <unistd.h>
+
+#include "configd.h"
+#include "configd_server.h"
+#include "session.h"
+
+
+#define SNAPSHOT_PATH_CACHE _PATH_VARTMP "configd-cache.xml"
+#define SNAPSHOT_PATH_SESSION _PATH_VARTMP "configd-session.xml"
+
+
+SCDStatus
+_SCDSnapshot(SCDSessionRef session)
+{
+ int fd;
+ CFDataRef xmlData;
+
+ SCDLog(LOG_DEBUG, CFSTR("_SCDSnapshot:"));
+
+ /* Save a snapshot of the "cache" data */
+
+ (void) unlink(SNAPSHOT_PATH_CACHE);
+ fd = open(SNAPSHOT_PATH_CACHE, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd < 0) {
+ return SCD_FAILED;
+ }
+
+ xmlData = CFPropertyListCreateXMLData(NULL, cacheData);
+ (void) write(fd, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData));
+ (void) close(fd);
+ CFRelease(xmlData);
+
+ /* Save a snapshot of the "session" data */
+
+ (void) unlink(SNAPSHOT_PATH_SESSION);
+ fd = open(SNAPSHOT_PATH_SESSION, O_WRONLY|O_CREAT|O_TRUNC, 0644);
+ if (fd < 0) {
+ return SCD_FAILED;
+ }
+
+ /* Save a snapshot of the "session" data */
+
+ xmlData = CFPropertyListCreateXMLData(NULL, sessionData);
+ (void) write(fd, CFDataGetBytePtr(xmlData), CFDataGetLength(xmlData));
+ (void) close(fd);
+ CFRelease(xmlData);
+
+ return SCD_OK;
+}
+
+
+kern_return_t
+_snapshot(mach_port_t server, int *scd_status)
+{
+ serverSessionRef mySession = getSession(server);
+
+ SCDLog(LOG_DEBUG, CFSTR("Snapshot configuration database."));
+
+ *scd_status = _SCDSnapshot(mySession->session);
+ if (*scd_status != SCD_OK) {
+ SCDLog(LOG_DEBUG, CFSTR(" SCDUnlock(): %s"), SCDError(*scd_status));
+ }
+
+ return KERN_SUCCESS;
+}
--- /dev/null
+/*
+ * Import the real "config.defs" file from the framework.
+ *
+ * The ultimate goal is to have a single ".defs" file in
+ * the project which is used to generate a shared "config.h"
+ * header, the "configUser.c" file used by (and included in)
+ * the built framework, and the "configServer.c" file used
+ * by the server.
+ *
+ * To date, I have been unable to determine the needed flags
+ * and/or rules to add to the Makefile to ensure that any
+ * changes made to the real projects ".defs" file results in
+ * the[re-]generation of both framework and servers MiG files.
+ *
+ * As such... IF YOU CHANGE THE ".defs" FILE, MAKE CLEAN!
+ */
+
+#import "../SystemConfiguration.fproj/config.defs"
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _S_CONFIGD_H
+#define _S_CONFIGD_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/cdefs.h>
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+
+#include <SystemConfiguration/SCD.h>
+#include "config_types.h"
+#include "SCDPrivate.h"
+#include "_SCD.h"
+
+
+__BEGIN_DECLS
+__END_DECLS
+
+#endif /* !_S_CONFIGD_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+/*
+ * Modification History
+ * 24 March 2000 Allan Nathanson (ajn@apple.com)
+ * - created
+ */
+
+#include <stdio.h>
+#include <sysexits.h>
+#include <syslog.h>
+#include <unistd.h>
+#include <paths.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <objc/objc-runtime.h>
+
+#include "configd.h"
+#include "configd_server.h"
+#include "plugin_support.h"
+
+
+const char *signames[] = {
+ "" , "HUP" , "INT" , "QUIT", "ILL" , "TRAP", "ABRT", "EMT" ,
+ "FPE" , "KILL", "BUS" , "SEGV", "SYS" , "PIPE", "ALRM", "TERM",
+ "URG" , "STOP", "TSTP" , "CONT", "CHLD" , "TTIN", "TTOU", "IO" ,
+ "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "INFO", "USR1", "USR2"
+};
+
+
+void
+usage(const char *prog)
+{
+ SCDLog(LOG_INFO, CFSTR("%s: [-d] [-v] [-b] [-t plugin-bundle-path]"), prog);
+ SCDLog(LOG_INFO, CFSTR("options:"));
+ SCDLog(LOG_INFO, CFSTR("\t-d\tenable debugging"));
+ SCDLog(LOG_INFO, CFSTR("\t-v\tenable verbose logging"));
+ SCDLog(LOG_INFO, CFSTR("\t-b\tdisable loading of ALL plug-ins"));
+ SCDLog(LOG_INFO, CFSTR("\t-t\tload/test the specified plug-in"));
+ SCDLog(LOG_INFO, CFSTR("\t\t (Note: only the plug-in will be started)"), prog);
+ exit (EX_USAGE);
+}
+
+
+void
+catcher(int signum)
+{
+ /*
+ * log the signal
+ *
+ * Note: we can't use SCDLog() since the signal may be received while the
+ * logging thread lock is held.
+ */
+ if (SCDOptionGet(NULL, kSCDOptionUseSyslog)) {
+ syslog (LOG_INFO, "caught SIG%s" , signames[signum]);
+ } else {
+ fprintf(stderr, "caught SIG%s\n", signames[signum]);
+ fflush (stderr);
+ }
+
+ return;
+}
+
+static void
+parent_exit(int i)
+{
+ _exit (0);
+}
+
+static int
+fork_child()
+{
+ int child_pid;
+ int fd;
+
+ signal(SIGTERM, parent_exit);
+ child_pid = fork();
+ switch (child_pid) {
+ case -1: {
+ return -1;
+ }
+ case 0: {
+ /* child: becomes the daemon (see below) */
+ signal(SIGTERM, SIG_DFL);
+ break;
+ }
+ default: {
+ /* parent: wait for signal, then exit */
+ int status;
+
+ (void) wait4(child_pid, (int *)&status, 0, 0);
+ if (WIFEXITED(status)) {
+ fprintf(stderr,
+ "*** configd (daemon) failed to start, exit status=%d",
+ WEXITSTATUS(status));
+ } else {
+ fprintf(stderr,
+ "*** configd (daemon) failed to start, received signal=%d",
+ WTERMSIG(status));
+ }
+ fflush (stderr);
+ exit (EX_SOFTWARE);
+ }
+ }
+
+ if (setsid() == -1)
+ return -1;
+
+ (void)chdir("/");
+
+ if ((fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
+ (void)dup2(fd, STDIN_FILENO);
+ (void)dup2(fd, STDOUT_FILENO);
+ (void)dup2(fd, STDERR_FILENO);
+ if (fd > 2)
+ (void)close(fd);
+ }
+
+ return 0;
+}
+
+int
+main (int argc, const char *argv[])
+{
+ extern int optind;
+ int opt;
+ const char *prog = argv[0];
+ boolean_t loadBundles = TRUE;
+ const char *testBundle = NULL;
+ struct sigaction nact;
+
+ /* process any arguments */
+
+ while ((opt = getopt(argc, argv, "bdt:v")) != -1) {
+ switch(opt) {
+ case 'b':
+ loadBundles = FALSE;
+ break;
+ case 'd':
+ SCDOptionSet(NULL, kSCDOptionDebug, TRUE);
+ break;
+ case 't':
+ testBundle = optarg;
+ break;
+ case 'v':
+ SCDOptionSet(NULL, kSCDOptionVerbose, TRUE);
+ break;
+ case '?':
+ default :
+ usage(prog);
+ }
+ }
+ argc -= optind;
+ argv += optind;
+
+ /*
+ * display an error if configd is already running and we are
+ * not executing/testing a bundle.
+ */
+ if ((testBundle == NULL) && (server_active() == TRUE)) {
+ exit (EX_UNAVAILABLE);
+ }
+
+ /* get ready */
+
+ SCDOptionSet(NULL, kSCDOptionIsServer, TRUE); /* Use the config API's "server" code */
+ SCDOptionSet(NULL, kSCDOptionUseCFRunLoop, TRUE); /* Use the CFRunLoop */
+
+ /* check credentials */
+ if (getuid() != 0) {
+#ifdef DEBUG
+ if (!SCDOptionGet(NULL, kSCDOptionDebug)) {
+#endif /* DEBUG */
+ fprintf(stderr, "%s: permission denied.\n", prog);
+ exit (EX_NOPERM);
+#ifdef DEBUG
+ }
+#endif /* DEBUG */
+ }
+
+ if ((testBundle == NULL) && !SCDOptionGet(NULL, kSCDOptionDebug)) {
+ if (fork_child() == -1) {
+ fprintf(stderr, "configd: fork() failed, %s\n", strerror(errno));
+ exit (1);
+ }
+ /* now the child process, parent waits in fork_child */
+
+ /* log via syslog() facility */
+ openlog("configd", (LOG_NDELAY | LOG_PID), LOG_DAEMON);
+ SCDOptionSet(NULL, kSCDOptionUseSyslog, TRUE);
+ }
+
+ /* add signal handler to catch a SIGPIPE */
+
+ nact.sa_handler = catcher;
+ sigemptyset(&nact.sa_mask);
+ nact.sa_flags = SA_RESTART;
+
+ if (sigaction(SIGPIPE, &nact, NULL) == -1) {
+ SCDLog(LOG_ERR,
+ CFSTR("sigaction(SIGPIPE, ...) failed: %s"),
+ strerror(errno));
+ }
+
+ /* get set */
+
+ objc_setMultithreaded(YES);
+
+ if (testBundle == NULL) {
+ /* initialize primary (cache management) thread */
+ server_init();
+
+ /* load/initialize/start bundles into the secondary thread */
+ if (loadBundles) {
+ plugin_init();
+ } else {
+ if (!SCDOptionGet(NULL, kSCDOptionDebug)) {
+ /* synchronize with parent process */
+ kill(getppid(), SIGTERM);
+ }
+ }
+ }
+
+ /* go */
+
+ if (testBundle == NULL) {
+ /* start primary (cache management) thread */
+ server_loop();
+ } else {
+ /* load/initialize/start specified plug-in */
+ plugin_exec((void *)testBundle);
+ }
+
+ exit (EX_OK); // insure the process exit status is 0
+ return 0; // ...and make main fit the ANSI spec.
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <servers/bootstrap.h>
+#include <sysexits.h>
+
+#include "configd.h"
+#include "configd_server.h"
+#include "notify_server.h"
+#include "session.h"
+#include "notify.h"
+
+/* MiG generated externals and functions */
+extern struct rpc_subsystem _config_subsystem;
+extern boolean_t config_server(mach_msg_header_t *, mach_msg_header_t *);
+
+/* server state information */
+CFMachPortRef configd_port; /* configd server port (for new session requests) */
+
+
+boolean_t
+config_demux(mach_msg_header_t *request, mach_msg_header_t *reply)
+{
+ boolean_t processed = FALSE;
+
+ mach_msg_format_0_trailer_t *trailer;
+
+ /* Feed the request into the ("MiG" generated) server */
+ if (!processed &&
+ (request->msgh_id >= _config_subsystem.start && request->msgh_id < _config_subsystem.end)) {
+ serverSessionRef thisSession;
+
+ thisSession = getSession(request->msgh_local_port);
+ if (thisSession) {
+ /*
+ * Get the caller's credentials (eUID/eGID) from the message trailer.
+ */
+ trailer = (mach_msg_security_trailer_t *)((vm_offset_t)request +
+ round_msg(request->msgh_size));
+
+ if ((trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0) &&
+ (trailer->msgh_trailer_size >= MACH_MSG_TRAILER_FORMAT_0_SIZE)) {
+ thisSession->callerEUID = trailer->msgh_sender.val[0];
+ thisSession->callerEGID = trailer->msgh_sender.val[1];
+ SCDLog(LOG_DEBUG, CFSTR("caller has eUID = %d, eGID = %d"),
+ thisSession->callerEUID,
+ thisSession->callerEGID);
+ } else {
+ static boolean_t warned = FALSE;
+
+ if (!warned) {
+ SCDLog(LOG_WARNING, CFSTR("caller's credentials not available."));
+ warned = TRUE;
+ }
+ thisSession->callerEUID = 0;
+ thisSession->callerEGID = 0;
+ }
+ }
+
+ /*
+ * Process configd requests.
+ */
+ processed = config_server(request, reply);
+ }
+
+ if (!processed &&
+ (request->msgh_id >= MACH_NOTIFY_FIRST && request->msgh_id < MACH_NOTIFY_LAST)) {
+ processed = notify_server(request, reply);
+ }
+
+ if (!processed) {
+ SCDLog(LOG_WARNING, CFSTR("unknown message received"));
+ exit (EX_OSERR);
+ }
+
+ return processed;
+}
+
+
+void
+configdCallback(CFMachPortRef port, void *msg, CFIndex size, void *info)
+{
+ mig_reply_error_t *bufRequest = msg;
+ mig_reply_error_t *bufReply = CFAllocatorAllocate(NULL, _config_subsystem.maxsize, 0);
+ mach_msg_return_t mr;
+ int options;
+
+ /* we have a request message */
+ (void) config_demux(&bufRequest->Head, &bufReply->Head);
+
+ if (!(bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) && (bufReply->RetCode != KERN_SUCCESS)) {
+
+ if (bufReply->RetCode == MIG_NO_REPLY) {
+ /*
+ * This return code is a little tricky -- it appears that the
+ * demux routine found an error of some sort, but since that
+ * error would not normally get returned either to the local
+ * user or the remote one, we pretend it's ok.
+ */
+ CFAllocatorDeallocate(NULL, bufReply);
+ return;
+ }
+
+ /*
+ * destroy any out-of-line data in the request buffer but don't destroy
+ * the reply port right (since we need that to send an error message).
+ */
+ bufRequest->Head.msgh_remote_port = MACH_PORT_NULL;
+ mach_msg_destroy(&bufRequest->Head);
+ }
+
+ if (bufReply->Head.msgh_remote_port == MACH_PORT_NULL) {
+ /* no reply port, so destroy the reply */
+ if (bufReply->Head.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
+ mach_msg_destroy(&bufReply->Head);
+ }
+ CFAllocatorDeallocate(NULL, bufReply);
+ return;
+ }
+
+ /*
+ * send reply.
+ *
+ * We don't want to block indefinitely because the client
+ * isn't receiving messages from the reply port.
+ * If we have a send-once right for the reply port, then
+ * this isn't a concern because the send won't block.
+ * If we have a send right, we need to use MACH_SEND_TIMEOUT.
+ * To avoid falling off the kernel's fast RPC path unnecessarily,
+ * we only supply MACH_SEND_TIMEOUT when absolutely necessary.
+ */
+
+ options = MACH_SEND_MSG;
+ if (MACH_MSGH_BITS_REMOTE(bufReply->Head.msgh_bits) == MACH_MSG_TYPE_MOVE_SEND_ONCE) {
+ options |= MACH_SEND_TIMEOUT;
+ }
+ mr = mach_msg(&bufReply->Head, /* msg */
+ options, /* option */
+ bufReply->Head.msgh_size, /* send_size */
+ 0, /* rcv_size */
+ MACH_PORT_NULL, /* rcv_name */
+ MACH_MSG_TIMEOUT_NONE, /* timeout */
+ MACH_PORT_NULL); /* notify */
+
+
+ /* Has a message error occurred? */
+ switch (mr) {
+ case MACH_SEND_INVALID_DEST:
+ case MACH_SEND_TIMED_OUT:
+ /* the reply can't be delivered, so destroy it */
+ mach_msg_destroy(&bufReply->Head);
+ break;
+
+ default :
+ /* Includes success case. */
+ break;
+ }
+
+ CFAllocatorDeallocate(NULL, bufReply);
+}
+
+
+boolean_t
+server_active()
+{
+ kern_return_t status;
+ mach_port_t bootstrap_port;
+ boolean_t active;
+
+ /* Getting bootstrap server port */
+ status = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
+ if (status != KERN_SUCCESS) {
+ fprintf(stderr, "task_get_bootstrap_port(): %s\n",
+ mach_error_string(status));
+ exit (EX_UNAVAILABLE);
+ }
+
+ /* Check "configd" server status */
+ status = bootstrap_status(bootstrap_port, SCD_SERVER, &active);
+ switch (status) {
+ case BOOTSTRAP_SUCCESS :
+ if (active) {
+ fprintf(stderr, "configd: '%s' server already active\n",
+ SCD_SERVER);
+ return TRUE;
+ }
+ break;
+ case BOOTSTRAP_UNKNOWN_SERVICE :
+ break;
+ default :
+ fprintf(stderr, "bootstrap_status(): %s\n",
+ mach_error_string(status));
+ exit (EX_UNAVAILABLE);
+ }
+ return FALSE;
+}
+
+void
+server_init()
+{
+ kern_return_t status;
+ mach_port_t bootstrap_port;
+ boolean_t active;
+ CFRunLoopSourceRef rls;
+
+ /* Getting bootstrap server port */
+ status = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
+ if (status != KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("task_get_bootstrap_port(): %s"), mach_error_string(status));
+ exit (EX_UNAVAILABLE);
+ }
+
+ /* Check "configd" server status */
+ status = bootstrap_status(bootstrap_port, SCD_SERVER, &active);
+ switch (status) {
+ case BOOTSTRAP_SUCCESS :
+ if (active) {
+ SCDLog(LOG_DEBUG, CFSTR("\"%s\" is currently active, exiting."), SCD_SERVER);
+ exit (EX_UNAVAILABLE);
+ }
+ break;
+ case BOOTSTRAP_UNKNOWN_SERVICE :
+ /* service not currently registered, "a good thing" (tm) */
+ break;
+ default :
+ fprintf(stderr, "bootstrap_status(): %s\n", mach_error_string(status));
+ exit (EX_UNAVAILABLE);
+ }
+
+ /* Create the primary / new connection port */
+ configd_port = CFMachPortCreate(NULL, configdCallback, NULL, NULL);
+
+ /*
+ * Create and add a run loop source for the port and add this source
+ * to both the default run loop mode and the "locked" mode. These two
+ * modes will be used for normal (unlocked) communication with the
+ * server and when multiple (locked) updates are requested by a single
+ * session.
+ */
+ rls = CFMachPortCreateRunLoopSource(NULL, configd_port, 0);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, CFSTR("locked"));
+ CFRelease(rls);
+
+ /* Create a session for the primary / new connection port */
+ (void) addSession(configd_port);
+
+ SCDLog(LOG_DEBUG, CFSTR("Registering service \"%s\""), SCD_SERVER);
+ status = bootstrap_register(bootstrap_port, SCD_SERVER, CFMachPortGetPort(configd_port));
+ switch (status) {
+ case BOOTSTRAP_SUCCESS :
+ /* service not currently registered, "a good thing" (tm) */
+ break;
+ case BOOTSTRAP_NOT_PRIVILEGED :
+ SCDLog(LOG_ERR, CFSTR("bootstrap_register(): bootstrap not privileged"));
+ exit (EX_OSERR);
+ case BOOTSTRAP_SERVICE_ACTIVE :
+ SCDLog(LOG_ERR, CFSTR("bootstrap_register(): bootstrap service active"));
+ exit (EX_OSERR);
+ default :
+ SCDLog(LOG_ERR, CFSTR("bootstrap_register(): %s"), mach_error_string(status));
+ exit (EX_OSERR);
+ }
+
+ return;
+}
+
+
+void
+server_loop()
+{
+ CFStringRef rlMode;
+ int rlStatus;
+
+ while (TRUE) {
+ boolean_t isLocked = SCDOptionGet(NULL, kSCDOptionIsLocked);
+
+ /*
+ * if linked with a DEBUG version of the framework, display some
+ * debugging information
+ */
+ _showMachPortStatus();
+
+ /*
+ * process one run loop event
+ */
+ rlMode = isLocked ? CFSTR("locked") : kCFRunLoopDefaultMode;
+ rlStatus = CFRunLoopRunInMode(rlMode, 1.0e10, TRUE);
+
+ /*
+ * check for, and if necessary, push out change notifications
+ * to other processes.
+ */
+ pushNotifications();
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _S_CONFIGD_SERVER_H
+#define _S_CONFIGD_SERVER_H
+
+#include <sys/cdefs.h>
+#include <mach/mach.h>
+
+#include <CoreFoundation/CFRunLoop.h>
+#include <CoreFoundation/CFMachPort.h>
+
+extern CFMachPortRef configd_port; /* configd server port (for new session requests) */
+
+__BEGIN_DECLS
+
+void configdCallback __P((CFMachPortRef port,
+ void *msg,
+ CFIndex size,
+ void *info));
+
+boolean_t server_active __P(());
+void server_init __P(());
+
+void server_loop __P(());
+
+kern_return_t _snapshot __P((mach_port_t server, int *scd_status));
+
+kern_return_t _configopen __P((mach_port_t server,
+ xmlData_t name,
+ mach_msg_type_number_t nameCnt,
+ mach_port_t *newServer,
+ int *scd_status));
+
+kern_return_t _configclose __P((mach_port_t server, int *scd_status));
+
+kern_return_t _configlock __P((mach_port_t server, int *scd_status));
+
+kern_return_t _configunlock __P((mach_port_t server, int *scd_status));
+
+kern_return_t _configlist __P((mach_port_t server,
+ xmlData_t key,
+ mach_msg_type_number_t keyCnt,
+ int regexOptions,
+ xmlDataOut_t *list,
+ mach_msg_type_number_t *listCnt,
+ int *scd_status));
+
+kern_return_t _configadd __P((mach_port_t server,
+ xmlData_t key,
+ mach_msg_type_number_t keyCnt,
+ xmlData_t data,
+ mach_msg_type_number_t dataCnt,
+ int *newInstance,
+ int *scd_status));
+
+kern_return_t _configadd_s __P((mach_port_t server,
+ xmlData_t key,
+ mach_msg_type_number_t keyCnt,
+ xmlData_t data,
+ mach_msg_type_number_t dataCnt,
+ int *newInstance,
+ int *scd_status));
+
+kern_return_t _configget __P((mach_port_t server,
+ xmlData_t key,
+ mach_msg_type_number_t keyCnt,
+ xmlDataOut_t *data,
+ mach_msg_type_number_t *dataCnt,
+ int *newInstance,
+ int *scd_status));
+
+kern_return_t _configset __P((mach_port_t server,
+ xmlData_t key,
+ mach_msg_type_number_t keyCnt,
+ xmlData_t data,
+ mach_msg_type_number_t dataCnt,
+ int *newInstance,
+ int *scd_status));
+
+kern_return_t _configremove __P((mach_port_t server,
+ xmlData_t key,
+ mach_msg_type_number_t keyCnt,
+ int *scd_status));
+
+kern_return_t _configtouch __P((mach_port_t server,
+ xmlData_t key,
+ mach_msg_type_number_t keyCnt,
+ int *scd_status));
+
+kern_return_t _notifyadd __P((mach_port_t server,
+ xmlData_t key,
+ mach_msg_type_number_t keyCnt,
+ int regexOptions,
+ int *status));
+
+kern_return_t _notifyremove __P((mach_port_t server,
+ xmlData_t key,
+ mach_msg_type_number_t keyCnt,
+ int regexOptions,
+ int *status));
+
+kern_return_t _notifychanges __P((mach_port_t server,
+ xmlDataOut_t *list,
+ mach_msg_type_number_t *listCnt,
+ int *status));
+
+kern_return_t _notifyviaport __P((mach_port_t server,
+ mach_port_t port,
+ mach_msg_id_t msgid,
+ int *status));
+
+kern_return_t _notifyviafd __P((mach_port_t server,
+ xmlData_t path,
+ mach_msg_type_number_t pathCnt,
+ int identifier,
+ int *status));
+
+kern_return_t _notifyviasignal
+ __P((mach_port_t server,
+ task_t task,
+ int signal,
+ int *status));
+
+kern_return_t _notifycancel __P((mach_port_t server,
+ int *scd_status));
+
+__END_DECLS
+
+#endif /* !_S_CONFIGD_SERVER_H */
--- /dev/null
+$$
+/* $FILENAME$ created by $USERNAME$ on $DATE$ */
+
+#import <Foundation/Foundation.h>
+
+@interface $FILENAMESANSEXTENSION$ : NSObject
+{
+
+}
+
+@end
--- /dev/null
+$$ Lines starting with $$ are not inserted into newly created files
+$$ The following substitutions are made:
+$$
+$$ $FILENAME$ e.g. foo.m
+$$ $FILENAMESANSEXTENSION$ e.g. foo
+$$ $DIRECTORY$ e.g. /tmp/MyNewApp
+$$ $PROJECTNAME$ e.g. MyNewApp
+$$ $SUBPROJECTNAME$ e.g. TheGoodPart.subproj
+$$ $USERNAME$ e.g. mwagner
+$$ $DATE$ e.g. Jan-1-1994
+$$
+/* $FILENAME$ created by $USERNAME$ on $DATE$ */
+
+#import "$FILENAMESANSEXTENSION$.h"
+
+@implementation $FILENAMESANSEXTENSION$
+
+@end
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+
+#include <unistd.h>
+
+#include "configd.h"
+#include "configd_server.h"
+#include "session.h"
+
+
+void
+pushNotifications()
+{
+ void **sessionsToNotify;
+ CFIndex notifyCnt;
+ int server;
+ serverSessionRef theSession;
+ SCDSessionPrivateRef sessionPrivate;
+
+ if (needsNotification == NULL)
+ return; /* if no sessions need to be kicked */
+
+ notifyCnt = CFSetGetCount(needsNotification);
+ sessionsToNotify = malloc(notifyCnt * sizeof(CFNumberRef));
+ CFSetGetValues(needsNotification, sessionsToNotify);
+ while (--notifyCnt >= 0) {
+ (void) CFNumberGetValue(sessionsToNotify[notifyCnt],
+ kCFNumberIntType,
+ &server);
+ theSession = getSession(server);
+ sessionPrivate = (SCDSessionPrivateRef)theSession->session;
+
+ /*
+ * handle callbacks for "configd" plug-ins
+ */
+ if (sessionPrivate->callbackFunction != NULL) {
+ SCDLog(LOG_DEBUG, CFSTR("executing notifiction callback function (server=%d)."),
+ sessionPrivate->server);
+ (void) (*sessionPrivate->callbackFunction)(theSession->session,
+ sessionPrivate->callbackArgument);
+ }
+
+ /*
+ * deliver notifications to client sessions
+ */
+ if (sessionPrivate->notifyPort != MACH_PORT_NULL) {
+ mach_msg_empty_send_t msg;
+ mach_msg_option_t options;
+ kern_return_t status;
+ /*
+ * Post notification as mach message
+ */
+ SCDLog(LOG_DEBUG, CFSTR("sending mach message notification."));
+ SCDLog(LOG_DEBUG, CFSTR(" port = %d"), sessionPrivate->notifyPort);
+ SCDLog(LOG_DEBUG, CFSTR(" msgid = %d"), sessionPrivate->notifyPortIdentifier);
+ msg.header.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
+ msg.header.msgh_size = sizeof(msg);
+ msg.header.msgh_remote_port = sessionPrivate->notifyPort;
+ msg.header.msgh_local_port = MACH_PORT_NULL;
+ msg.header.msgh_id = sessionPrivate->notifyPortIdentifier;
+ options = MACH_SEND_TIMEOUT;
+ status = mach_msg(&msg.header, /* msg */
+ MACH_SEND_MSG|options, /* options */
+ msg.header.msgh_size, /* send_size */
+ 0, /* rcv_size */
+ MACH_PORT_NULL, /* rcv_name */
+ 0, /* timeout */
+ MACH_PORT_NULL); /* notify */
+ }
+
+ if (sessionPrivate->notifyFile >= 0) {
+ ssize_t written;
+
+ SCDLog(LOG_DEBUG, CFSTR("sending (UNIX domain) socket notification"));
+ SCDLog(LOG_DEBUG, CFSTR(" fd = %d"), sessionPrivate->notifyFile);
+ SCDLog(LOG_DEBUG, CFSTR(" msgid = %d"), sessionPrivate->notifyFileIdentifier);
+
+ written = write(sessionPrivate->notifyFile,
+ &sessionPrivate->notifyFileIdentifier,
+ sizeof(sessionPrivate->notifyFileIdentifier));
+ if (written == -1) {
+ if (errno == EWOULDBLOCK) {
+ SCDLog(LOG_DEBUG,
+ CFSTR("sorry, only one outstanding notification per session."));
+ } else {
+ SCDLog(LOG_DEBUG,
+ CFSTR("could not send notification, write() failed: %s"),
+ strerror(errno));
+ sessionPrivate->notifyFile = -1;
+ }
+ } else if (written != sizeof(sessionPrivate->notifyFileIdentifier)) {
+ SCDLog(LOG_DEBUG,
+ CFSTR("could not send notification, incomplete write()"));
+ sessionPrivate->notifyFile = -1;
+ }
+ }
+
+ if (sessionPrivate->notifySignal > 0) {
+ kern_return_t status;
+ pid_t pid;
+ /*
+ * Post notification as signal
+ */
+ status = pid_for_task(sessionPrivate->notifySignalTask, &pid);
+ if (status == KERN_SUCCESS) {
+ SCDLog(LOG_DEBUG, CFSTR("sending signal notification"));
+ SCDLog(LOG_DEBUG, CFSTR(" pid = %d"), pid);
+ SCDLog(LOG_DEBUG, CFSTR(" signal = %d"), sessionPrivate->notifySignal);
+ if (kill(pid, sessionPrivate->notifySignal) != 0) {
+ SCDLog(LOG_DEBUG, CFSTR("could not send signal: %s"), strerror(errno));
+ status = KERN_FAILURE;
+ }
+ } else {
+ mach_port_type_t pt;
+
+ if ((mach_port_type(mach_task_self(), sessionPrivate->notifySignalTask, &pt) == KERN_SUCCESS) &&
+ (pt & MACH_PORT_TYPE_DEAD_NAME)) {
+ SCDLog(LOG_DEBUG, CFSTR("could not send signal, process died"));
+ } else {
+ SCDLog(LOG_DEBUG, CFSTR("could not send signal: %s"), mach_error_string(status));
+ }
+ }
+
+ if (status != KERN_SUCCESS) {
+ /* don't bother with any more attempts */
+ (void) mach_port_destroy(mach_task_self(), sessionPrivate->notifySignalTask);
+ sessionPrivate->notifySignal = 0;
+ sessionPrivate->notifySignalTask = TASK_NULL;
+ }
+ }
+ }
+ free(sessionsToNotify);
+
+ /*
+ * this list of notifications have been posted, wait for some more.
+ */
+ CFRelease(needsNotification);
+ needsNotification = NULL;
+
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _S_NOTIFY_H
+#define _S_NOTIFY_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void pushNotifications __P(());
+
+__END_DECLS
+
+#endif /* !_S_NOTIFY_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "session.h"
+
+boolean_t
+notify_server(mach_msg_header_t *request, mach_msg_header_t *reply)
+{
+ mach_no_senders_notification_t *notify = (mach_no_senders_notification_t *)request;
+
+ if ((notify->not_header.msgh_id > MACH_NOTIFY_LAST) ||
+ (notify->not_header.msgh_id < MACH_NOTIFY_FIRST)) {
+ return FALSE; /* if this is not a notification message */
+ }
+
+ switch (notify->not_header.msgh_id) {
+ case MACH_NOTIFY_NO_SENDERS :
+ SCDLog(LOG_DEBUG, CFSTR("No more senders for port %d, closing."),
+ notify->not_header.msgh_local_port);
+ cleanupSession(notify->not_header.msgh_local_port);
+
+ (void) mach_port_destroy(mach_task_self(), notify->not_header.msgh_local_port);
+
+ notify->not_header.msgh_remote_port = MACH_PORT_NULL;
+ return TRUE;
+ case MACH_NOTIFY_DEAD_NAME :
+ SCDLog(LOG_DEBUG, CFSTR("Dead name for port %d, closing."),
+ notify->not_header.msgh_local_port);
+ cleanupSession(notify->not_header.msgh_local_port);
+
+ (void) mach_port_destroy(mach_task_self(), notify->not_header.msgh_local_port);
+
+ notify->not_header.msgh_remote_port = MACH_PORT_NULL;
+ return TRUE;
+ default :
+ break;
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR("HELP!, Received notification: port=%d, msgh_id=%d"),
+ notify->not_header.msgh_local_port,
+ notify->not_header.msgh_id);
+
+ return FALSE;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _S_NOTIFY_SERVER_H
+#define _S_NOTIFY_SERVER_H
+
+#include <sys/cdefs.h>
+#include <mach/mach.h>
+
+__BEGIN_DECLS
+
+boolean_t notify_server __P((mach_msg_header_t *request, mach_msg_header_t *reply));
+
+__END_DECLS
+
+#endif /* !_S_NOTIFY_SERVER_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <mach-o/dyld.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <NSSystemDirectories.h>
+
+#include "configd.h"
+
+
+/*
+ * Information maintained for each to-be-kicked registration.
+ */
+typedef struct {
+ /*
+ * bundle paths
+ */
+ char bundle[MAXNAMLEN + 1]; /* bundle name */
+ char path [MAXPATHLEN]; /* bundle path */
+
+ /*
+ * entry points for initialization code.
+ */
+ SCDBundleStartRoutine_t start; /* address of start() routine */
+ SCDBundlePrimeRoutine_t prime; /* address of prime() routine */
+
+} plugin, *pluginRef;
+
+CFMutableArrayRef plugins;
+
+
+/* exception handling functions */
+typedef kern_return_t (*cer_func_t) (mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t codeCnt);
+
+typedef kern_return_t (*cer_state_func_t) (mach_port_t exception_port,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt);
+
+typedef kern_return_t (*cer_identity_func_t) (mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt);
+
+static cer_func_t catch_exception_raise_func = NULL;
+static cer_state_func_t catch_exception_raise_state_func = NULL;
+static cer_identity_func_t catch_exception_raise_identity_func = NULL;
+
+kern_return_t
+catch_exception_raise(mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t codeCnt)
+{
+
+ if (catch_exception_raise_func == NULL) {
+ /* The user hasn't defined catch_exception_raise in their binary */
+ abort();
+ }
+ return (*catch_exception_raise_func)(exception_port,
+ thread,
+ task,
+ exception,
+ code,
+ codeCnt);
+}
+
+
+kern_return_t
+catch_exception_raise_state(mach_port_t exception_port,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt)
+{
+ if (catch_exception_raise_state_func == 0) {
+ /* The user hasn't defined catch_exception_raise_state in their binary */
+ abort();
+ }
+ return (*catch_exception_raise_state_func)(exception_port,
+ exception,
+ code,
+ codeCnt,
+ flavor,
+ old_state,
+ old_stateCnt,
+ new_state,
+ new_stateCnt);
+}
+
+
+kern_return_t
+catch_exception_raise_state_identity(mach_port_t exception_port,
+ mach_port_t thread,
+ mach_port_t task,
+ exception_type_t exception,
+ exception_data_t code,
+ mach_msg_type_number_t codeCnt,
+ int *flavor,
+ thread_state_t old_state,
+ mach_msg_type_number_t old_stateCnt,
+ thread_state_t new_state,
+ mach_msg_type_number_t *new_stateCnt)
+{
+ if (catch_exception_raise_identity_func == 0) {
+ /* The user hasn't defined catch_exception_raise_identify in their binary */
+ abort();
+ }
+ return (*catch_exception_raise_identity_func)(exception_port,
+ thread,
+ task,
+ exception,
+ code,
+ codeCnt,
+ flavor,
+ old_state,
+ old_stateCnt,
+ new_state,
+ new_stateCnt);
+}
+
+
+static boolean_t
+bundleLoad(pluginRef info)
+{
+ int len;
+ NSObjectFileImage image;
+ NSObjectFileImageReturnCode status;
+ NSModule module;
+ NSSymbol symbol;
+ unsigned long options;
+ char *bundleExe; /* full path of bundle executable */
+ struct stat sb;
+
+ /*
+ * allocate enough space for the bundle directory path, a "/" separator,
+ * the bundle name, and the (optional) "_debug" extension.
+ */
+
+ len = strlen(info->path); /* path */
+ len += sizeof(BUNDLE_NEW_SUBDIR) - 1; /* "/" or "/Contents/MacOS/" */
+ len += strlen(info->bundle); /* bundle name */
+ len += sizeof(BUNDLE_DEBUG_EXTENSION); /* "_debug" (and NUL) */
+ bundleExe = CFAllocatorAllocate(NULL, len, 0);
+
+ /* check for the (old layout) bundle executable path */
+ strcpy(bundleExe, info->path);
+ strcat(bundleExe, BUNDLE_OLD_SUBDIR);
+ strcat(bundleExe, info->bundle);
+ if (stat(bundleExe, &sb) == 0) {
+ goto load;
+ }
+
+ /* check for the "_debug" version */
+ strcat(bundleExe, BUNDLE_DEBUG_EXTENSION);
+ if (stat(bundleExe, &sb) == 0) {
+ goto load;
+ }
+
+ /* check for the (new layout) bundle executable path */
+ strcpy(bundleExe, info->path);
+ strcat(bundleExe, BUNDLE_NEW_SUBDIR);
+ strcat(bundleExe, info->bundle);
+ if (stat(bundleExe, &sb) == 0) {
+ goto load;
+ }
+
+ /* check for the "_debug" version */
+ strcat(bundleExe, BUNDLE_DEBUG_EXTENSION);
+ if (stat(bundleExe, &sb) == 0) {
+ goto load;
+ }
+
+ SCDLog(LOG_ERR,
+ CFSTR("bundleLoad() failed, no executable for %s in %s"),
+ info->bundle,
+ info->path);
+ CFAllocatorDeallocate(NULL, bundleExe);
+ return FALSE;
+
+ load :
+
+ /* load the bundle */
+ SCDLog(LOG_DEBUG, CFSTR("loading %s"), bundleExe);
+ status = NSCreateObjectFileImageFromFile(bundleExe, &image);
+ if (status != NSObjectFileImageSuccess) {
+ char *err;
+
+ switch (status) {
+ case NSObjectFileImageFailure :
+ err = "NSObjectFileImageFailure";
+ break;
+ case NSObjectFileImageInappropriateFile :
+ err = "NSObjectFileImageInappropriateFile";
+ break;
+ case NSObjectFileImageArch :
+ err = "NSObjectFileImageArch";
+ break;
+ case NSObjectFileImageFormat :
+ err = "NSObjectFileImageFormat";
+ break;
+ case NSObjectFileImageAccess :
+ err = "NSObjectFileImageAccess";
+ break;
+ default :
+ err = "Unknown";
+ break;
+ }
+ SCDLog(LOG_ERR, CFSTR("NSCreateObjectFileImageFromFile() failed"));
+ SCDLog(LOG_ERR, CFSTR(" executable path = %s"), bundleExe);
+ SCDLog(LOG_ERR, CFSTR(" error status = %s"), err);
+ CFAllocatorDeallocate(NULL, bundleExe);
+ return FALSE;
+ }
+
+ options = NSLINKMODULE_OPTION_BINDNOW;
+ options |= NSLINKMODULE_OPTION_PRIVATE;
+ options |= NSLINKMODULE_OPTION_RETURN_ON_ERROR;
+ module = NSLinkModule(image, bundleExe, options);
+
+ if (module == NULL) {
+ NSLinkEditErrors c;
+ int errorNumber;
+ const char *fileName;
+ const char *errorString;
+
+ SCDLog(LOG_ERR, CFSTR("NSLinkModule() failed"));
+ SCDLog(LOG_ERR, CFSTR(" executable path = %s"), bundleExe);
+
+ /* collect and report the details */
+ NSLinkEditError(&c, &errorNumber, &fileName, &errorString);
+ SCDLog(LOG_ERR, CFSTR(" NSLinkEditErrors = %d"), (int)c);
+ SCDLog(LOG_ERR, CFSTR(" errorNumber = %d"), errorNumber);
+ if((fileName != NULL) && (*fileName != '\0'))
+ SCDLog(LOG_ERR, CFSTR(" fileName = %s"), fileName);
+ if((errorString != NULL) && (*errorString != '\0'))
+ SCDLog(LOG_ERR, CFSTR(" errorString = %s"), errorString);
+
+ CFAllocatorDeallocate(NULL, bundleExe);
+ return FALSE;
+ }
+
+ CFAllocatorDeallocate(NULL, bundleExe);
+
+ /* identify the initialization functions */
+
+ symbol = NSLookupSymbolInModule(module, BUNDLE_ENTRY_POINT);
+ if (symbol) {
+ info->start = NSAddressOfSymbol(symbol);
+ }
+
+ symbol = NSLookupSymbolInModule(module, BUNDLE_ENTRY_POINT2);
+ if (symbol) {
+ info->prime = NSAddressOfSymbol(symbol);
+ }
+
+ if ((info->start == NULL) && (info->prime == NULL)) {
+ SCDLog(LOG_DEBUG, CFSTR(" no entry points"));
+ return FALSE;
+ }
+
+ /* identify any exception handling functions */
+
+ symbol = NSLookupSymbolInModule(module, "_catch_exception_raise");
+ if (symbol) {
+ catch_exception_raise_func = NSAddressOfSymbol(symbol);
+ }
+
+ symbol = NSLookupSymbolInModule(module, "_catch_exception_raise_state");
+ if (symbol) {
+ catch_exception_raise_state_func = NSAddressOfSymbol(symbol);
+ }
+
+ symbol = NSLookupSymbolInModule(module, "_catch_exception_raise_identity");
+ if (symbol) {
+ catch_exception_raise_identity_func = NSAddressOfSymbol(symbol);
+ }
+
+ return TRUE;
+}
+
+
+static void
+bundleStart(const void *value, void *context)
+{
+ CFDataRef data = (CFDataRef)value;
+ pluginRef info;
+
+ info = (pluginRef)CFDataGetBytePtr(data);
+ if (info->start) {
+ (*info->start)(info->bundle, info->path);
+ }
+}
+
+
+static void
+bundlePrime(const void *value, void *context)
+{
+ CFDataRef data = (CFDataRef)value;
+ pluginRef info;
+
+ info = (pluginRef)CFDataGetBytePtr(data);
+ if (info->prime) {
+ (*info->prime)(info->bundle, info->path);
+ }
+}
+
+
+static void
+loadOne(const char *bundleDir, const char *bundleName)
+{
+ CFMutableDataRef info;
+ pluginRef pluginInfo;
+ int len;
+
+ /* check if this directory entry is a valid bundle name */
+ len = strlen(bundleName);
+ if (len <= sizeof(BUNDLE_DIR_EXTENSION)) {
+ /* if entry name isn't long enough */
+ return;
+ }
+
+ len -= sizeof(BUNDLE_DIR_EXTENSION) - 1;
+ if (strcmp(&bundleName[len], BUNDLE_DIR_EXTENSION) != 0) {
+ /* if entry name doesn end with ".bundle" */
+ return;
+ }
+
+ info = CFDataCreateMutable(NULL, sizeof(plugin));
+ pluginInfo = (pluginRef)CFDataGetBytePtr(info);
+ pluginInfo->start = NULL;
+ pluginInfo->prime = NULL;
+
+ /* get (just) the bundle's name */
+ pluginInfo->bundle[0] = '\0';
+ (void) strncat(pluginInfo->bundle, bundleName, len);
+
+ /* get the bundle directory path */
+ (void) sprintf(pluginInfo->path, "%s/%s", bundleDir, bundleName);
+
+ /* load the bundle */
+ if (bundleLoad(pluginInfo)) {
+ SCDLog(LOG_INFO, CFSTR("%s loaded"), bundleName);
+ CFArrayAppendValue(plugins, info);
+ } else {
+ SCDLog(LOG_ERR, CFSTR("load of \"%s\" failed"), bundleName);
+ }
+ CFRelease(info);
+
+ return;
+}
+
+
+static void
+loadAll(const char *bundleDir)
+{
+ DIR *dirp;
+ struct dirent *dp;
+
+ dirp = opendir(bundleDir);
+ if (dirp == NULL) {
+ /* if no plugin directory */
+ return;
+ }
+
+ while ((dp = readdir(dirp)) != NULL) {
+ loadOne(bundleDir, dp->d_name);
+ }
+
+ closedir(dirp);
+ return;
+}
+
+
+void
+timerCallback(CFRunLoopTimerRef timer, void *info)
+{
+ SCDLog(LOG_INFO, CFSTR("the CFRunLoop is waiting for something to happen...."));
+ return;
+}
+
+
+void *
+plugin_exec(void *arg)
+{
+ NSSearchPathEnumerationState state;
+ char path[MAXPATHLEN];
+
+ /* keep track of loaded plugins */
+ plugins = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+
+ if (arg == NULL) {
+ /*
+ * identify and load all plugins
+ */
+ state = NSStartSearchPathEnumeration(NSLibraryDirectory,
+ NSLocalDomainMask|NSSystemDomainMask);
+ while ((state = NSGetNextSearchPathEnumeration(state, path))) {
+ /* load any available plugins */
+ strcat(path, BUNDLE_DIRECTORY);
+ SCDLog(LOG_DEBUG, CFSTR("searching for plugins in \"%s\""), path);
+ loadAll(path);
+ }
+
+ if (SCDOptionGet(NULL, kSCDOptionDebug)) {
+ SCDLog(LOG_DEBUG, CFSTR("searching for plugins in \".\""));
+ loadAll(".");
+ }
+ } else {
+ /*
+ * load the plugin specified on the command line
+ */
+ char *bn, *bd;
+
+ if ((bn = strrchr((char *)arg, '/')) != NULL) {
+ int len;
+
+ /* plug-in directory */
+ len = bn - (char *)arg;
+ if (len == 0)
+ len++; /* if plugin is in the root directory */
+
+ bd = CFAllocatorAllocate(NULL, len + 1, 0);
+ bd[0] = '\0';
+ (void) strncat(bd, (char *)arg, len);
+
+ /* plug-in name */
+ bn++; /* name starts just after trailing path separator */
+ } else {
+ /* plug-in (in current) directory */
+ bd = CFAllocatorAllocate(NULL, sizeof("."), 0);
+ (void) strcpy(bd, ".");
+
+ /* plug-in name */
+ bn = (char *)arg; /* no path separators */
+ }
+
+ loadOne(bd, bn);
+
+ CFAllocatorDeallocate(NULL, bd);
+
+ /* allocate a periodic event (to help show we're not blocking) */
+ if (CFArrayGetCount(plugins)) {
+ CFRunLoopTimerRef timer;
+
+ timer = CFRunLoopTimerCreate(NULL, /* allocator */
+ CFAbsoluteTimeGetCurrent() + 1.0, /* fireDate */
+ 60.0, /* interval */
+ 0, /* flags */
+ 0, /* order */
+ timerCallback, /* callout */
+ NULL); /* context */
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), timer, kCFRunLoopDefaultMode);
+ CFRelease(timer);
+ }
+ }
+
+ /*
+ * execute each plugins start() function which should initialize any
+ * variables, open any sessions with "configd", and register any needed
+ * notifications. Establishing initial information in the cache should
+ * be deferred until the prime() initialization function so that any
+ * plug-ins which want to receive a notification that the data has
+ * changed will have an opportunity to install a notification handler.
+ */
+ SCDLog(LOG_DEBUG, CFSTR("calling plugin start() functions"));
+ CFArrayApplyFunction(plugins,
+ CFRangeMake(0, CFArrayGetCount(plugins)),
+ bundleStart,
+ NULL);
+
+ /*
+ * execute each plugins prime() function which should initialize any
+ * configuration information and/or state in the cache.
+ */
+ SCDLog(LOG_DEBUG, CFSTR("calling plugin prime() functions"));
+ CFArrayApplyFunction(plugins,
+ CFRangeMake(0, CFArrayGetCount(plugins)),
+ bundlePrime,
+ NULL);
+
+ /*
+ * all plugins have been loaded and started.
+ */
+ CFRelease(plugins);
+
+ if (!SCDOptionGet(NULL, kSCDOptionDebug) && (arg == NULL)) {
+ /* synchronize with parent process */
+ kill(getppid(), SIGTERM);
+ }
+
+ /*
+ * The assumption is that each loaded plugin will establish CFMachPortRef,
+ * CFSocketRef, and CFRunLoopTimerRef input sources to handle any events
+ * and register these sources with this threads run loop. If the plugin
+ * needs to wait and/or block at any time it should do so only in its a
+ * private thread.
+ */
+ SCDLog(LOG_DEBUG, CFSTR("starting plugin CFRunLoop"));
+ CFRunLoopRun();
+ SCDLog(LOG_INFO, CFSTR("what, no more work for the \"configd\" plugins?"));
+ return NULL;
+}
+
+
+void
+plugin_init()
+{
+ pthread_attr_t tattr;
+ pthread_t tid;
+
+ SCDLog(LOG_DEBUG, CFSTR("Starting thread for plug-ins..."));
+ pthread_attr_init(&tattr);
+ pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM);
+ pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED);
+// pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack
+ pthread_create(&tid, &tattr, plugin_exec, NULL);
+ pthread_attr_destroy(&tattr);
+ SCDLog(LOG_DEBUG, CFSTR(" thread id=0x%08x"), tid);
+
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _S_PLUGIN_SUPPORT_H
+#define _S_PLUGIN_SUPPORT_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void plugin_init __P(());
+void plugin_exec __P((void *arg));
+
+__END_DECLS
+
+#endif /* !_S_PLUGIN_SUPPORT_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "configd.h"
+#include "configd_server.h"
+#include "session.h"
+
+/* information maintained for each active session */
+static serverSessionRef *sessions = NULL;
+static int nSessions = 0;
+
+
+serverSessionRef
+getSession(mach_port_t server)
+{
+ int i;
+
+ if (server == MACH_PORT_NULL) {
+ SCDLog(LOG_NOTICE, CFSTR("Excuse me, why is getSession() being called with an invalid port?"));
+ return NULL;
+ }
+
+ if (nSessions > 0) {
+ for (i=0; i<nSessions; i++) {
+ serverSessionRef thisSession = sessions[i];
+
+ if (thisSession == NULL) {
+ /* found an empty slot, skip it */
+ continue;
+ } else if (thisSession->key == server) {
+ return thisSession; /* we've seen this server before */
+ } else if ((thisSession->session != NULL) &&
+ (((SCDSessionPrivateRef)thisSession->session)->notifySignalTask == server)) {
+ return thisSession;
+ }
+ }
+ }
+
+ /* no sessions available */
+ return NULL;
+}
+
+
+serverSessionRef
+addSession(CFMachPortRef server)
+{
+ int i;
+ int n = -1;
+
+ if (nSessions <= 0) {
+ /* new session (actually, the first) found */
+ sessions = malloc(sizeof(serverSessionRef));
+ n = 0;
+ nSessions = 1;
+ } else {
+ for (i=0; i<nSessions; i++) {
+ if (sessions[i] == NULL) {
+ /* found an empty slot, use it */
+ n = i;
+ }
+ }
+ /* new session identified */
+ if (n < 0) {
+ /* no empty slots, add one to the list */
+ n = nSessions++;
+ sessions = realloc(sessions, ((nSessions) * sizeof(serverSessionRef)));
+ }
+ }
+
+ SCDLog(LOG_DEBUG, CFSTR("Allocating new session for port %d"), CFMachPortGetPort(server));
+ sessions[n] = malloc(sizeof(serverSession));
+ sessions[n]->key = CFMachPortGetPort(server);
+ sessions[n]->serverPort = server;
+ sessions[n]->serverRunLoopSource = NULL;
+ sessions[n]->session = NULL;
+ sessions[n]->callerEUID = 1; /* not "root" */
+ sessions[n]->callerEGID = 1; /* not "wheel" */
+
+ return sessions[n];
+}
+
+
+void
+removeSession(mach_port_t server)
+{
+ int i;
+ serverSessionRef thisSession;
+ CFStringRef sessionKey;
+
+ for (i=0; i<nSessions; i++) {
+ thisSession = sessions[i];
+
+ if (thisSession == NULL) {
+ /* found an empty slot, skip it */
+ continue;
+ } else if (thisSession->key == server) {
+ /*
+ * We don't need any remaining information in the
+ * sessionData dictionary, remove it.
+ */
+ sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), server);
+ CFDictionaryRemoveValue(sessionData, sessionKey);
+ CFRelease(sessionKey);
+
+ /*
+ * Lastly, get rid of the per-session structure.
+ */
+ free(thisSession);
+ sessions[i] = NULL;
+
+ return;
+ }
+ }
+
+ return;
+}
+
+
+void
+cleanupSession(mach_port_t server)
+{
+ int i;
+
+ for (i=0; i<nSessions; i++) {
+ serverSessionRef thisSession = sessions[i];
+
+ if ((thisSession != NULL) && (thisSession->key == server)) {
+ /*
+ * session entry still exists.
+ */
+
+ /*
+ * Ensure that any changes made while we held the "lock"
+ * are discarded.
+ */
+ if (SCDOptionGet(NULL, kSCDOptionIsLocked) &&
+ SCDOptionGet(thisSession->session, kSCDOptionIsLocked)) {
+ /*
+ * swap cache and associated data which, after
+ * being closed, will result in the restoration
+ * of the original pre-"locked" data.
+ */
+ _swapLockedCacheData();
+ }
+
+ /*
+ * Close any open connections including cancelling any outstanding
+ * notification requests and releasing any locks.
+ */
+ (void) _SCDClose(&thisSession->session);
+
+ /*
+ * Lastly, remove the session entry.
+ */
+ removeSession(server);
+
+ return;
+ }
+ }
+ return;
+}
+
+
+void
+listSessions()
+{
+ int i;
+
+ fprintf(stderr, "Current sessions:");
+ for (i=0; i<nSessions; i++) {
+ serverSessionRef thisSession = sessions[i];
+
+ if (thisSession == NULL) {
+ continue;
+ }
+
+ fprintf(stderr, " %d", thisSession->key);
+
+ if (thisSession->session != NULL) {
+ task_t task = ((SCDSessionPrivateRef)thisSession->session)->notifySignalTask;
+
+ if (task != TASK_NULL) {
+ fprintf(stderr, "/%d", task);
+ }
+ }
+ }
+ fprintf(stderr, "\n");
+}
+
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _S_SESSION_H
+#define _S_SESSION_H
+
+#include <sys/cdefs.h>
+
+/* Per client server state */
+typedef struct {
+
+ /* mach port used as the key to this session */
+ mach_port_t key;
+
+ /* mach port associated with this session */
+ CFMachPortRef serverPort;
+ CFRunLoopSourceRef serverRunLoopSource; /* XXX CFMachPortInvalidate() doesn't work */
+
+ /* data associated with this "open" session */
+ SCDSessionRef session;
+
+ /* credentials associated with this "open" session */
+ int callerEUID;
+ int callerEGID;
+
+} serverSession, *serverSessionRef;
+
+__BEGIN_DECLS
+
+serverSessionRef getSession __P((mach_port_t server));
+
+serverSessionRef addSession __P((CFMachPortRef server));
+
+void removeSession __P((mach_port_t server));
+
+void cleanupSession __P((mach_port_t server));
+
+void listSessions __P(());
+
+__END_DECLS
+
+#endif /* !_S_SESSION_H */
--- /dev/null
+#
+# Generated by the Apple Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = scselect
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+CFILES = scselect.c
+
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble m.template\
+ h.template
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/sbin
+WINDOWS_INSTALLDIR = /Library/Executables
+PDO_UNIX_INSTALLDIR = /bin
+LIBS =
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+FRAMEWORKS = -framework SystemConfiguration
+
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
--- /dev/null
+###############################################################################
+# Makefile.postamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile, which is imported after all other makefiles, to
+# override attributes for a project's Makefile environment. This allows you
+# to take advantage of the environment set up by the other Makefiles.
+# You can also define custom rules at the end of this file.
+#
+###############################################################################
+#
+# These variables are exported by the standard makefiles and can be
+# used in any customizations you make. They are *outputs* of
+# the Makefiles and should be used, not set.
+#
+# PRODUCTS: products to install. All of these products will be placed in
+# the directory $(DSTROOT)$(INSTALLDIR)
+# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
+# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
+# OFILE_DIR: Directory into which .o object files are generated.
+# DERIVED_SRC_DIR: Directory used for all other derived files
+#
+# ALL_CFLAGS: flags to pass when compiling .c files
+# ALL_MFLAGS: flags to pass when compiling .m files
+# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
+# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
+# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
+# ALL_LDFLAGS: flags to pass when linking object files
+# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
+# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
+# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
+# ALL_YFLAGS: flags to pass when processing .y (yacc) files
+# ALL_LFLAGS: flags to pass when processing .l (lex) files
+#
+# NAME: name of application, bundle, subproject, palette, etc.
+# LANGUAGES: langages in which the project is written (default "English")
+# English_RESOURCES: localized resources (e.g. nib's, images) of project
+# GLOBAL_RESOURCES: non-localized resources of project
+#
+# SRCROOT: base directory in which to place the new source files
+# SRCPATH: relative path from SRCROOT to present subdirectory
+#
+# INSTALLDIR: Directory the product will be installed into by 'install' target
+# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+#
+# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
+#
+###############################################################################
+
+# Some compiler flags can be overridden here for certain build situations.
+#
+# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
+# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
+# to -g)
+# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
+# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
+# to -O)
+# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
+# to -pg -DPROFILE)
+# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
+# the include path (defaults to -I.)
+# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
+# passed to ld/libtool (defaults to nothing)
+
+
+# Library and Framework projects only:
+# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
+# against the framework will run against the correct version even if
+# the current version of the framework changes. You may override this
+# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
+# development cycle, but be sure to restore it before installing.
+
+
+# Ownership and permissions of files installed by 'install' target
+
+#INSTALL_AS_USER = root
+ # User/group ownership
+#INSTALL_AS_GROUP = wheel
+ # (probably want to set both of these)
+INSTALL_PERMISSIONS = 4555
+ # If set, 'install' chmod's executable to this
+
+
+# Options to strip. Note: -S strips debugging symbols (executables can be stripped
+# down further with -x or, if they load no bundles, with no options at all).
+
+#STRIPFLAGS = -S
+
+
+#########################################################################
+# Put rules to extend the behavior of the standard Makefiles here. Include them in
+# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
+#
+# You should avoid redefining things like "install" or "app", as they are
+# owned by the top-level Makefile API and no context has been set up for where
+# derived files should go.
+#
--- /dev/null
+###############################################################################
+# Makefile.preamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile for configuring the standard application makefiles
+# associated with ProjectBuilder. It is included before the main makefile.
+# In Makefile.preamble you set attributes for a project, so they are available
+# to the project's makefiles. In contrast, you typically write additional rules or
+# override built-in behavior in the Makefile.postamble.
+#
+# Each directory in a project tree (main project plus subprojects) should
+# have its own Makefile.preamble and Makefile.postamble.
+###############################################################################
+#
+# Before the main makefile is included for this project, you may set:
+#
+# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
+# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
+
+# Compiler/linker flags added to the defaults: The OTHER_* variables will be
+# inherited by all nested sub-projects, but the LOCAL_ versions of the same
+# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
+# Build Attributes inspector if at all possible. To override the default flags
+# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
+# variables below are *inputs* to the build process and distinct from the override
+# settings done (less often) in the Makefile.postamble.
+#
+# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
+# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
+# .cc, .cxx, .C, and .M files. There is no need to respecify the
+# flags in OTHER_MFLAGS, etc.
+# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
+# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
+# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
+# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
+# precompiling header files
+# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
+# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
+# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
+# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
+# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
+
+# These variables provide hooks enabling you to add behavior at almost every
+# stage of the make:
+#
+# BEFORE_PREBUILD: targets to build before installing headers for a subproject
+# AFTER_PREBUILD: targets to build after installing headers for a subproject
+# BEFORE_BUILD_RECURSION: targets to make before building subprojects
+# BEFORE_BUILD: targets to make before a build, but after subprojects
+# AFTER_BUILD: targets to make after a build
+#
+# BEFORE_INSTALL: targets to build before installing the product
+# AFTER_INSTALL: targets to build after installing the product
+# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
+# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
+#
+# BEFORE_INSTALLHDRS: targets to build before installing headers for a
+# subproject
+# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
+# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
+# AFTER_INSTALLSRC: targets to build after installing source for a subproject
+#
+# BEFORE_DEPEND: targets to build before building dependencies for a
+# subproject
+# AFTER_DEPEND: targets to build after building dependencies for a
+# subproject
+#
+# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
+# updated every time the project is built. If NO, the dependency
+# file is only built when the depend target is invoked.
+
+# Framework-related variables:
+# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the framework's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+
+# Library-related variables:
+# PUBLIC_HEADER_DIR: Determines where public exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically. For library projects you should
+# set this to something like /Developer/Headers/$(NAME). Do not set
+# this variable for framework projects unless you do not want the
+# header files included in the framework.
+# PRIVATE_HEADER_DIR: Determines where private exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically.
+# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
+# whether the libraries produced are statically linked when they
+# are used or if they are dynamically loadable. This defaults to
+# DYNAMIC.
+# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the library's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+#
+# INSTALL_AS_USER: owner of the intalled products (default root)
+# INSTALL_AS_GROUP: group of the installed products (default wheel)
+# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
+#
+# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
+# passed on the command line to recursive invocations of make. Note that
+# the values in OTHER_*FLAGS are inherited by subprojects automatically --
+# you do not have to (and shouldn't) add OTHER_*FLAGS to
+# OTHER_RECURSIVE_VARIABLES.
+
+# Additional headers to export beyond those in the PB.project:
+# OTHER_PUBLIC_HEADERS
+# OTHER_PROJECT_HEADERS
+# OTHER_PRIVATE_HEADERS
+
+# Additional files for the project's product: <<path relative to proj?>>
+# OTHER_RESOURCES: (non-localized) resources for this project
+# OTHER_OFILES: relocatables to be linked into this project
+# OTHER_LIBS: more libraries to link against
+# OTHER_PRODUCT_DEPENDS: other dependencies of this project
+# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
+# OTHER_GARBAGE: additional files to be removed by `make clean'
+
+# Set this to YES if you don't want a final libtool call for a library/framework.
+# BUILD_OFILES_LIST_ONLY
+
+# To include a version string, project source must exist in a directory named
+# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
+OTHER_GENERATED_OFILES = $(VERS_OFILE)
+
+# This definition will suppress stripping of debug symbols when an executable
+# is installed. By default it is YES.
+# STRIP_ON_INSTALL = NO
+
+# Uncomment to suppress generation of a KeyValueCoding index when installing
+# frameworks (This index is used by WOB and IB to determine keys available
+# for an object). Set to YES by default.
+# PREINDEX_FRAMEWORK = NO
+
+# Change this definition to install projects somewhere other than the
+# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
+# and "" on other systems.
+DSTROOT = $(HOME)
--- /dev/null
+{
+ DYNAMIC_CODE_GEN = YES;
+ FILESTABLE = {
+ FRAMEWORKS = (SystemConfiguration.framework);
+ H_FILES = ();
+ OTHER_LINKED = (scselect.c);
+ OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, m.template, h.template);
+ PRECOMPILED_HEADERS = ();
+ PROJECT_HEADERS = ();
+ PUBLIC_HEADERS = ();
+ SUBPROJECTS = ();
+ };
+ LANGUAGE = English;
+ MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
+ NEXTSTEP_BUILDTOOL = /usr/bin/gnumake;
+ NEXTSTEP_INSTALLDIR = /usr/sbin;
+ NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
+ NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
+ PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
+ PDO_UNIX_INSTALLDIR = /bin;
+ PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
+ PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = scselect;
+ PROJECTTYPE = Tool;
+ PROJECTVERSION = 2.8;
+ WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
+ WINDOWS_INSTALLDIR = /Library/Executables;
+ WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
+ WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+}
--- /dev/null
+$$
+/* $FILENAME$ created by $USERNAME$ on $DATE$ */
+
+#import <Foundation/Foundation.h>
+
+@interface $FILENAMESANSEXTENSION$ : NSObject
+{
+
+}
+
+@end
--- /dev/null
+$$ Lines starting with $$ are not inserted into newly created files
+$$ The following substitutions are made:
+$$
+$$ $FILENAME$ e.g. foo.m
+$$ $FILENAMESANSEXTENSION$ e.g. foo
+$$ $DIRECTORY$ e.g. /tmp/MyNewApp
+$$ $PROJECTNAME$ e.g. MyNewApp
+$$ $SUBPROJECTNAME$ e.g. TheGoodPart.subproj
+$$ $USERNAME$ e.g. mwagner
+$$ $DATE$ e.g. Jan-1-1994
+$$
+/* $FILENAME$ created by $USERNAME$ on $DATE$ */
+
+#import "$FILENAMESANSEXTENSION$.h"
+
+@implementation $FILENAMESANSEXTENSION$
+
+@end
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <SystemConfiguration/SystemConfiguration.h>
+#include <unistd.h>
+
+
+boolean_t apply = TRUE;
+
+
+void
+usage(const char *command)
+{
+ SCDLog(LOG_ERR, CFSTR("usage: %s [-n] new-set-name"), command);
+ return;
+}
+
+
+int
+main(int argc, char **argv)
+{
+ const char *command = argv[0];
+ extern int optind;
+ int opt;
+ CFStringRef current = NULL;
+ int currentMatched = 0;
+ CFStringRef newSet = NULL; /* set key */
+ CFStringRef newSetUDN = NULL; /* user defined name */
+ CFStringRef prefix;
+ SCPStatus status;
+ SCPSessionRef session;
+ CFDictionaryRef sets;
+ CFIndex nSets;
+ void **setKeys;
+ void **setVals;
+ CFIndex i;
+
+ /* process any arguments */
+
+ SCDOptionSet(NULL, kSCDOptionUseSyslog, FALSE);
+
+ while ((opt = getopt(argc, argv, "dvn")) != -1)
+ switch(opt) {
+ case 'd':
+ SCDOptionSet(NULL, kSCDOptionDebug, TRUE);
+ break;
+ case 'v':
+ SCDOptionSet(NULL, kSCDOptionVerbose, TRUE);
+ break;
+ case 'n':
+ apply = FALSE;
+ break;
+ case '?':
+ default :
+ usage(command);
+ }
+ argc -= optind;
+ argv += optind;
+
+ prefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("/%@/"), kSCPrefSets);
+
+ newSet = (argc == 1)
+ ? CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman)
+ : CFSTR("");
+
+ status = SCPOpen(&session, CFSTR("Select Set Command"), NULL, 0);
+ if (status != SCP_OK) {
+ SCDLog(LOG_ERR,
+ CFSTR("SCPOpen() failed: %s"),
+ SCPError(status));
+ exit (1);
+ }
+
+ /* check if a full path to the new "set" was specified */
+ if ((CFStringGetLength(newSet) > 0) && CFStringHasPrefix(newSet, prefix)) {
+ CFRange range;
+ CFMutableStringRef str;
+
+ str = CFStringCreateMutableCopy(NULL, 0, newSet);
+ CFStringDelete(str, CFRangeMake(0, CFStringGetLength(prefix)));
+
+ range = CFStringFind(str, CFSTR("/"), 0);
+ if (range.location != kCFNotFound) {
+ SCDLog(LOG_ERR, CFSTR("Set \"%@\" not available."), newSet);
+ exit (1);
+ }
+
+ CFRelease(newSet);
+ newSet = str;
+ }
+
+ status = SCPGet(session, kSCPrefSets, (CFPropertyListRef *)&sets);
+ if (status != SCP_OK) {
+ SCDLog(LOG_ERR, CFSTR("SCDGet(...,%s,...) failed: %s"), SCPError(status));
+ exit (1);
+ }
+
+ status = SCPGet(session, kSCPrefCurrentSet, (CFPropertyListRef *)¤t);
+ switch (status) {
+ case SCP_OK :
+ if (CFStringHasPrefix(current, prefix)) {
+ CFMutableStringRef tmp;
+
+ tmp = CFStringCreateMutableCopy(NULL, 0, current);
+ CFStringDelete(tmp, CFRangeMake(0, CFStringGetLength(prefix)));
+ current = tmp;
+ } else {
+ currentMatched = -1; /* not prefixed */
+ }
+ break;
+ case SCP_NOKEY :
+ current = CFSTR("");
+ currentMatched = -2; /* not defined */
+ break;
+ default :
+ SCDLog(LOG_ERR, CFSTR("SCDGet(...,%s,...) failed: %s"), SCPError(status));
+ exit (1);
+ }
+
+ nSets = CFDictionaryGetCount(sets);
+ setKeys = CFAllocatorAllocate(NULL, nSets * sizeof(CFStringRef), 0);
+ setVals = CFAllocatorAllocate(NULL, nSets * sizeof(CFDictionaryRef), 0);
+ CFDictionaryGetKeysAndValues(sets, setKeys, setVals);
+
+ /* check for set with matching name */
+ for (i=0; i<nSets; i++) {
+ CFStringRef key = (CFStringRef) setKeys[i];
+ CFDictionaryRef dict = (CFDictionaryRef)setVals[i];
+
+ if ((currentMatched >= 0) && CFEqual(key, current)) {
+ currentMatched++;
+ }
+
+ if (CFEqual(newSet, key)) {
+ newSetUDN = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
+ if (newSetUDN) CFRetain(newSetUDN);
+ current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet);
+ goto found;
+ }
+ }
+
+ /* check for set with matching user-defined name */
+ for (i=0; i<nSets; i++) {
+ CFStringRef key = (CFStringRef) setKeys[i];
+ CFDictionaryRef dict = (CFDictionaryRef)setVals[i];
+
+ newSetUDN = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
+ if ((newSetUDN != NULL) && CFEqual(newSet, newSetUDN)) {
+ CFRelease(newSet);
+ newSet = CFRetain(key);
+ CFRetain(newSetUDN);
+ current = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@%@"), prefix, newSet);
+ goto found;
+ }
+ }
+
+ if (argc == 2) {
+ SCDLog(LOG_ERR, CFSTR("Set \"%@\" not available."), newSet);
+ } else {
+ usage(command);
+ }
+
+ SCDLog(LOG_ERR, CFSTR(""));
+ SCDLog(LOG_ERR,
+ CFSTR("Defined sets include:%s"),
+ (currentMatched > 0) ? " (* == current set)" : "");
+
+ for (i=0; i<nSets; i++) {
+ CFStringRef key = (CFStringRef) setKeys[i];
+ CFDictionaryRef dict = (CFDictionaryRef)setVals[i];
+ CFStringRef udn = CFDictionaryGetValue(dict, kSCPropUserDefinedName);
+
+ SCDLog(LOG_ERR,
+ CFSTR(" %s %@\t(%@)"),
+ ((currentMatched > 0) && CFEqual(key, current)) ? "*" : " ",
+ key,
+ udn ? udn : CFSTR(""));
+ }
+
+ switch (currentMatched) {
+ case -2 :
+ SCDLog(LOG_ERR, CFSTR(""));
+ SCDLog(LOG_ERR, CFSTR("CurrentSet not defined"));
+ break;
+ case -1 :
+ SCDLog(LOG_ERR, CFSTR(""));
+ SCDLog(LOG_ERR, CFSTR("CurrentSet \"%@\" may not be valid"), current);
+ break;
+ case 0 :
+ SCDLog(LOG_ERR, CFSTR(""));
+ SCDLog(LOG_ERR, CFSTR("CurrentSet \"%@\" not valid"), current);
+ break;
+ default :
+ break;
+ }
+
+ exit (1);
+
+ found :
+
+ status = SCPSet(session, kSCPrefCurrentSet, current);
+ if (status != SCP_OK) {
+ SCDLog(LOG_ERR,
+ CFSTR("SCDSet(...,%@,%@) failed: %s"),
+ kSCPrefCurrentSet,
+ current,
+ SCPError(status));
+ exit (1);
+ }
+
+ status = SCPCommit(session);
+ if (status != SCP_OK) {
+ SCDLog(LOG_ERR, CFSTR("SCPCommit() failed: %s"), SCPError(status));
+ exit (1);
+ }
+
+ if (apply) {
+ status = SCPApply(session);
+ if (status != SCP_OK) {
+ SCDLog(LOG_ERR, CFSTR("SCPApply() failed: %s"), SCPError(status));
+ exit (1);
+ }
+ }
+
+ status = SCPClose(&session);
+ if (status != SCP_OK) {
+ SCDLog(LOG_ERR, CFSTR("SCPClose() failed: %s"), SCPError(status));
+ exit (1);
+ }
+
+ SCDLog(LOG_NOTICE,
+ CFSTR("%@ updated to %@ (%@)"),
+ kSCPrefCurrentSet,
+ newSet,
+ newSetUDN ? newSetUDN : CFSTR(""));
+
+ exit (0);
+ return 0;
+}
--- /dev/null
+#
+# Generated by the Apple Project Builder.
+#
+# NOTE: Do NOT change this file -- Project Builder maintains it.
+#
+# Put all of your customizations in files called Makefile.preamble
+# and Makefile.postamble (both optional), and Makefile will include them.
+#
+
+NAME = scutil
+
+PROJECTVERSION = 2.8
+PROJECT_TYPE = Tool
+
+HFILES = scutil.h commands.h dictionary.h session.h cache.h notify.h\
+ tests.h
+
+CFILES = scutil.c commands.c dictionary.c session.c cache.c notify.c\
+ tests.c
+
+OTHERSRCS = Makefile.preamble Makefile Makefile.postamble m.template\
+ h.template
+
+
+MAKEFILEDIR = $(MAKEFILEPATH)/pb_makefiles
+CODE_GEN_STYLE = DYNAMIC
+MAKEFILE = tool.make
+NEXTSTEP_INSTALLDIR = /usr/sbin
+WINDOWS_INSTALLDIR = /Library/Executables
+PDO_UNIX_INSTALLDIR = /bin
+LIBS =
+DEBUG_LIBS = $(LIBS)
+PROF_LIBS = $(LIBS)
+
+
+FRAMEWORKS = -framework SystemConfiguration
+
+
+NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc
+WINDOWS_OBJCPLUS_COMPILER = $(DEVDIR)/gcc
+PDO_UNIX_OBJCPLUS_COMPILER = $(NEXTDEV_BIN)/gcc
+NEXTSTEP_JAVA_COMPILER = /usr/bin/javac
+WINDOWS_JAVA_COMPILER = $(JDKBINDIR)/javac.exe
+PDO_UNIX_JAVA_COMPILER = $(JDKBINDIR)/javac
+
+include $(MAKEFILEDIR)/platform.make
+
+-include Makefile.preamble
+
+include $(MAKEFILEDIR)/$(MAKEFILE)
+
+-include Makefile.postamble
+
+-include Makefile.dependencies
--- /dev/null
+###############################################################################
+# Makefile.postamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile, which is imported after all other makefiles, to
+# override attributes for a project's Makefile environment. This allows you
+# to take advantage of the environment set up by the other Makefiles.
+# You can also define custom rules at the end of this file.
+#
+###############################################################################
+#
+# These variables are exported by the standard makefiles and can be
+# used in any customizations you make. They are *outputs* of
+# the Makefiles and should be used, not set.
+#
+# PRODUCTS: products to install. All of these products will be placed in
+# the directory $(DSTROOT)$(INSTALLDIR)
+# GLOBAL_RESOURCE_DIR: The directory to which resources are copied.
+# LOCAL_RESOURCE_DIR: The directory to which localized resources are copied.
+# OFILE_DIR: Directory into which .o object files are generated.
+# DERIVED_SRC_DIR: Directory used for all other derived files
+#
+# ALL_CFLAGS: flags to pass when compiling .c files
+# ALL_MFLAGS: flags to pass when compiling .m files
+# ALL_CCFLAGS: flags to pass when compiling .cc, .cxx, and .C files
+# ALL_MMFLAGS: flags to pass when compiling .mm, .mxx, and .M files
+# ALL_PRECOMPFLAGS: flags to pass when precompiling .h files
+# ALL_LDFLAGS: flags to pass when linking object files
+# ALL_LIBTOOL_FLAGS: flags to pass when libtooling object files
+# ALL_PSWFLAGS: flags to pass when processing .psw and .pswm (pswrap) files
+# ALL_RPCFLAGS: flags to pass when processing .rpc (rpcgen) files
+# ALL_YFLAGS: flags to pass when processing .y (yacc) files
+# ALL_LFLAGS: flags to pass when processing .l (lex) files
+#
+# NAME: name of application, bundle, subproject, palette, etc.
+# LANGUAGES: langages in which the project is written (default "English")
+# English_RESOURCES: localized resources (e.g. nib's, images) of project
+# GLOBAL_RESOURCES: non-localized resources of project
+#
+# SRCROOT: base directory in which to place the new source files
+# SRCPATH: relative path from SRCROOT to present subdirectory
+#
+# INSTALLDIR: Directory the product will be installed into by 'install' target
+# PUBLIC_HDR_INSTALLDIR: where to install public headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+# PRIVATE_HDR_INSTALLDIR: where to install private headers. Don't forget
+# to prefix this with DSTROOT when you use it.
+#
+# EXECUTABLE_EXT: Executable extension for the platform (i.e. .exe on Windows)
+#
+###############################################################################
+
+# Some compiler flags can be overridden here for certain build situations.
+#
+# WARNING_CFLAGS: flag used to set warning level (defaults to -Wmost)
+# DEBUG_SYMBOLS_CFLAGS: debug-symbol flag passed to all builds (defaults
+# to -g)
+# DEBUG_BUILD_CFLAGS: flags passed during debug builds (defaults to -DDEBUG)
+# OPTIMIZE_BUILD_CFLAGS: flags passed during optimized builds (defaults
+# to -O)
+# PROFILE_BUILD_CFLAGS: flags passed during profile builds (defaults
+# to -pg -DPROFILE)
+# LOCAL_DIR_INCLUDE_DIRECTIVE: flag used to add current directory to
+# the include path (defaults to -I.)
+# DEBUG_BUILD_LDFLAGS, OPTIMIZE_BUILD_LDFLAGS, PROFILE_BUILD_LDFLAGS: flags
+# passed to ld/libtool (defaults to nothing)
+
+
+# Library and Framework projects only:
+# INSTALL_NAME_DIRECTIVE: This directive ensures that executables linked
+# against the framework will run against the correct version even if
+# the current version of the framework changes. You may override this
+# to "" as an alternative to using the DYLD_LIBRARY_PATH during your
+# development cycle, but be sure to restore it before installing.
+
+
+# Ownership and permissions of files installed by 'install' target
+
+#INSTALL_AS_USER = root
+ # User/group ownership
+#INSTALL_AS_GROUP = wheel
+ # (probably want to set both of these)
+#INSTALL_PERMISSIONS =
+ # If set, 'install' chmod's executable to this
+
+
+# Options to strip. Note: -S strips debugging symbols (executables can be stripped
+# down further with -x or, if they load no bundles, with no options at all).
+
+#STRIPFLAGS = -S
+
+
+#########################################################################
+# Put rules to extend the behavior of the standard Makefiles here. Include them in
+# the dependency tree via cvariables like AFTER_INSTALL in the Makefile.preamble.
+#
+# You should avoid redefining things like "install" or "app", as they are
+# owned by the top-level Makefile API and no context has been set up for where
+# derived files should go.
+#
--- /dev/null
+###############################################################################
+# Makefile.preamble
+# Copyright 1997, Apple Computer, Inc.
+#
+# Use this makefile for configuring the standard application makefiles
+# associated with ProjectBuilder. It is included before the main makefile.
+# In Makefile.preamble you set attributes for a project, so they are available
+# to the project's makefiles. In contrast, you typically write additional rules or
+# override built-in behavior in the Makefile.postamble.
+#
+# Each directory in a project tree (main project plus subprojects) should
+# have its own Makefile.preamble and Makefile.postamble.
+###############################################################################
+#
+# Before the main makefile is included for this project, you may set:
+#
+# MAKEFILEDIR: Directory in which to find $(MAKEFILE)
+# MAKEFILE: Top level mechanism Makefile (e.g., app.make, bundle.make)
+
+# Compiler/linker flags added to the defaults: The OTHER_* variables will be
+# inherited by all nested sub-projects, but the LOCAL_ versions of the same
+# variables will not. Put your -I, -D, -U, and -L flags in ProjectBuilder's
+# Build Attributes inspector if at all possible. To override the default flags
+# that get passed to ${CC} (e.g. change -O to -O2), see Makefile.postamble. The
+# variables below are *inputs* to the build process and distinct from the override
+# settings done (less often) in the Makefile.postamble.
+#
+# OTHER_CFLAGS, LOCAL_CFLAGS: additional flags to pass to the compiler
+# Note that $(OTHER_CFLAGS) and $(LOCAL_CFLAGS) are used for .h, ...c, .m,
+# .cc, .cxx, .C, and .M files. There is no need to respecify the
+# flags in OTHER_MFLAGS, etc.
+# OTHER_MFLAGS, LOCAL_MFLAGS: additional flags for .m files
+# OTHER_CCFLAGS, LOCAL_CCFLAGS: additional flags for .cc, .cxx, and ...C files
+# OTHER_MMFLAGS, LOCAL_MMFLAGS: additional flags for .mm and .M files
+# OTHER_PRECOMPFLAGS, LOCAL_PRECOMPFLAGS: additional flags used when
+# precompiling header files
+# OTHER_LDFLAGS, LOCAL_LDFLAGS: additional flags passed to ld and libtool
+# OTHER_PSWFLAGS, LOCAL_PSWFLAGS: additional flags passed to pswrap
+# OTHER_RPCFLAGS, LOCAL_RPCFLAGS: additional flags passed to rpcgen
+# OTHER_YFLAGS, LOCAL_YFLAGS: additional flags passed to yacc
+# OTHER_LFLAGS, LOCAL_LFLAGS: additional flags passed to lex
+
+# These variables provide hooks enabling you to add behavior at almost every
+# stage of the make:
+#
+# BEFORE_PREBUILD: targets to build before installing headers for a subproject
+# AFTER_PREBUILD: targets to build after installing headers for a subproject
+# BEFORE_BUILD_RECURSION: targets to make before building subprojects
+# BEFORE_BUILD: targets to make before a build, but after subprojects
+# AFTER_BUILD: targets to make after a build
+#
+# BEFORE_INSTALL: targets to build before installing the product
+# AFTER_INSTALL: targets to build after installing the product
+# BEFORE_POSTINSTALL: targets to build before postinstalling every subproject
+# AFTER_POSTINSTALL: targts to build after postinstalling every subproject
+#
+# BEFORE_INSTALLHDRS: targets to build before installing headers for a
+# subproject
+# AFTER_INSTALLHDRS: targets to build after installing headers for a subproject
+# BEFORE_INSTALLSRC: targets to build before installing source for a subproject
+# AFTER_INSTALLSRC: targets to build after installing source for a subproject
+#
+# BEFORE_DEPEND: targets to build before building dependencies for a
+# subproject
+# AFTER_DEPEND: targets to build after building dependencies for a
+# subproject
+#
+# AUTOMATIC_DEPENDENCY_INFO: if YES, then the dependency file is
+# updated every time the project is built. If NO, the dependency
+# file is only built when the depend target is invoked.
+
+# Framework-related variables:
+# FRAMEWORK_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the framework's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+
+# Library-related variables:
+# PUBLIC_HEADER_DIR: Determines where public exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically. For library projects you should
+# set this to something like /Developer/Headers/$(NAME). Do not set
+# this variable for framework projects unless you do not want the
+# header files included in the framework.
+# PRIVATE_HEADER_DIR: Determines where private exported header files
+# should be installed. Do not include $(DSTROOT) in this value --
+# it is prefixed automatically.
+# LIBRARY_STYLE: This may be either STATIC or DYNAMIC, and determines
+# whether the libraries produced are statically linked when they
+# are used or if they are dynamically loadable. This defaults to
+# DYNAMIC.
+# LIBRARY_DLL_INSTALLDIR: On Windows platforms, this variable indicates
+# where to put the library's DLL. This variable defaults to
+# $(INSTALLDIR)/../Executables
+#
+# INSTALL_AS_USER: owner of the intalled products (default root)
+# INSTALL_AS_GROUP: group of the installed products (default wheel)
+# INSTALL_PERMISSIONS: permissions of the installed product (default o+rX)
+#
+# OTHER_RECURSIVE_VARIABLES: The names of variables which you want to be
+# passed on the command line to recursive invocations of make. Note that
+# the values in OTHER_*FLAGS are inherited by subprojects automatically --
+# you do not have to (and shouldn't) add OTHER_*FLAGS to
+# OTHER_RECURSIVE_VARIABLES.
+
+# Additional headers to export beyond those in the PB.project:
+# OTHER_PUBLIC_HEADERS
+# OTHER_PROJECT_HEADERS
+# OTHER_PRIVATE_HEADERS
+
+# Additional files for the project's product: <<path relative to proj?>>
+# OTHER_RESOURCES: (non-localized) resources for this project
+# OTHER_OFILES: relocatables to be linked into this project
+# OTHER_LIBS: more libraries to link against
+# OTHER_PRODUCT_DEPENDS: other dependencies of this project
+# OTHER_SOURCEFILES: other source files maintained by .pre/postamble
+# OTHER_GARBAGE: additional files to be removed by `make clean'
+
+# Set this to YES if you don't want a final libtool call for a library/framework.
+# BUILD_OFILES_LIST_ONLY
+
+# To include a version string, project source must exist in a directory named
+# $(NAME).%d[.%d][.%d] and the following line must be uncommented.
+OTHER_GENERATED_OFILES = $(VERS_OFILE)
+
+# This definition will suppress stripping of debug symbols when an executable
+# is installed. By default it is YES.
+# STRIP_ON_INSTALL = NO
+
+# Uncomment to suppress generation of a KeyValueCoding index when installing
+# frameworks (This index is used by WOB and IB to determine keys available
+# for an object). Set to YES by default.
+# PREINDEX_FRAMEWORK = NO
+
+# Change this definition to install projects somewhere other than the
+# standard locations. NEXT_ROOT defaults to "C:/Apple" on Windows systems
+# and "" on other systems.
+# DSTROOT = $(HOME)
--- /dev/null
+{
+ DYNAMIC_CODE_GEN = YES;
+ FILESTABLE = {
+ FRAMEWORKS = (SystemConfiguration.framework);
+ FRAMEWORKSEARCH = ();
+ H_FILES = (scutil.h, commands.h, dictionary.h, session.h, cache.h, notify.h, tests.h);
+ OTHER_LINKED = (scutil.c, commands.c, dictionary.c, session.c, cache.c, notify.c, tests.c);
+ OTHER_SOURCES = (Makefile.preamble, Makefile, Makefile.postamble, m.template, h.template);
+ SUBPROJECTS = ();
+ };
+ LANGUAGE = English;
+ MAKEFILEDIR = "$(MAKEFILEPATH)/pb_makefiles";
+ NEXTSTEP_BUILDTOOL = /usr/bin/gnumake;
+ NEXTSTEP_INSTALLDIR = /usr/sbin;
+ NEXTSTEP_JAVA_COMPILER = /usr/bin/javac;
+ NEXTSTEP_OBJCPLUS_COMPILER = /usr/bin/cc;
+ PDO_UNIX_BUILDTOOL = $NEXT_ROOT/Developer/bin/make;
+ PDO_UNIX_INSTALLDIR = /bin;
+ PDO_UNIX_JAVA_COMPILER = "$(JDKBINDIR)/javac";
+ PDO_UNIX_OBJCPLUS_COMPILER = "$(NEXTDEV_BIN)/gcc";
+ PROJECTNAME = scutil;
+ PROJECTTYPE = Tool;
+ PROJECTVERSION = 2.8;
+ WINDOWS_BUILDTOOL = $NEXT_ROOT/Developer/Executables/make;
+ WINDOWS_INSTALLDIR = /Library/Executables;
+ WINDOWS_JAVA_COMPILER = "$(JDKBINDIR)/javac.exe";
+ WINDOWS_OBJCPLUS_COMPILER = "$(DEVDIR)/gcc";
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+
+#include "scutil.h"
+
+void
+do_list(int argc, char **argv)
+{
+ CFStringRef key;
+ int regexOptions = 0;
+ SCDStatus status;
+ CFArrayRef list;
+ CFIndex listCnt;
+ int i;
+
+ key = CFStringCreateWithCString(NULL,
+ (argc >= 1) ? argv[0] : "",
+ kCFStringEncodingMacRoman);
+
+ if (argc == 2)
+ regexOptions = kSCDRegexKey;
+
+ status = SCDList(session, key, regexOptions, &list);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDList: %s"), SCDError(status));
+ return;
+ }
+
+ listCnt = CFArrayGetCount(list);
+ if (listCnt > 0) {
+ for (i=0; i<listCnt; i++) {
+ SCDLog(LOG_NOTICE, CFSTR(" subKey [%d] = %@"), i, CFArrayGetValueAtIndex(list, i));
+ }
+ } else {
+ SCDLog(LOG_NOTICE, CFSTR(" no subKey's"));
+ }
+ CFRelease(list);
+
+ return;
+}
+
+
+void
+do_add(int argc, char **argv)
+{
+ CFStringRef key;
+ SCDStatus status;
+
+ key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+
+ if (argc < 2) {
+ status = SCDAdd(session, key, data);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDAdd: %s"), SCDError(status));
+ }
+ } else {
+ status = SCDAddSession(session, key, data);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDAddSession: %s"), SCDError(status));
+ }
+ }
+
+ CFRelease(key);
+ return;
+}
+
+
+void
+do_get(int argc, char **argv)
+{
+ SCDStatus status;
+ CFStringRef key;
+ SCDHandleRef newData = NULL;
+
+ key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+ status = SCDGet(session, key, &newData);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDGet: %s"), SCDError(status));
+ if (newData != NULL) {
+ SCDHandleRelease(newData); /* toss the handle from SCDGet() */
+ }
+ return;
+ }
+
+ if (data != NULL) {
+ SCDHandleRelease(data); /* we got a new handle from SCDGet() */
+ }
+ data = newData;
+
+ return;
+}
+
+
+void
+do_set(int argc, char **argv)
+{
+ SCDStatus status;
+ CFStringRef key;
+
+ key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+ status = SCDSet(session, key, data);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDSet: %s"), SCDError(status));
+ }
+ return;
+}
+
+
+void
+do_remove(int argc, char **argv)
+{
+ SCDStatus status;
+ CFStringRef key;
+
+ key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+ status = SCDRemove(session, key);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDRemove: %s"), SCDError(status));
+ }
+ return;
+}
+
+
+void
+do_touch(int argc, char **argv)
+{
+ SCDStatus status;
+ CFStringRef key;
+
+ key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+ status = SCDTouch(session, key);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDTouch: %s"), SCDError(status));
+ }
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _CACHE_H
+#define _CACHE_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void do_list __P((int argc, char **argv));
+void do_add __P((int argc, char **argv));
+void do_get __P((int argc, char **argv));
+void do_set __P((int argc, char **argv));
+void do_remove __P((int argc, char **argv));
+void do_touch __P((int argc, char **argv));
+
+__END_DECLS
+
+#endif /* !_CACHE_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/errno.h>
+
+#include "scutil.h"
+#include "commands.h"
+#include "dictionary.h"
+#include "session.h"
+#include "cache.h"
+#include "notify.h"
+#include "tests.h"
+
+#include "SCDPrivate.h"
+
+const cmdInfo commands[] = {
+ /* cmd minArgs maxArgs func */
+ /* usage */
+
+ { "help", 0, 0, do_help, 0,
+ " help : list available commands" },
+
+ { "f.read", 1, 1, do_readFile, 0,
+ " f.read file : process commands from file" },
+
+ /* local dictionary manipulation commands */
+
+ { "d.init", 0, 0, do_dictInit, 1,
+ " d.init : initialize (empty) dictionary" },
+
+ { "d.show", 0, 0, do_dictShow, 1,
+ " d.show : show dictionary contents" },
+
+ { "d.add", 2, 101, do_dictSetKey, 1,
+ " d.add key [*#?] val [v2 ...] : add information to dictionary\n"
+ " (*=array, #=number, ?=boolean)" },
+
+ { "d.remove", 1, 1, do_dictRemoveKey, 1,
+ " d.remove key : remove key from dictionary" },
+
+ /* data store manipulation commands */
+
+ { "open", 0, 0, do_open, 2,
+ " open : open a session with \"configd\"" },
+
+ { "close", 0, 0, do_close, 2,
+ " close : close current \"configd\" session" },
+
+ { "lock", 0, 0, do_lock, 3,
+ " lock : secures write access to data store" },
+
+ { "unlock", 0, 0, do_unlock, 3,
+ " unlock : secures write access to data store" },
+
+ { "list", 0, 2, do_list, 4,
+ " list [prefix] [regex] : list keys in data store" },
+
+ { "add", 1, 2, do_add, 4,
+ " add key [session] : add key in data store w/current dict" },
+
+ { "get", 1, 1, do_get, 4,
+ " get key : get dict from data store w/key" },
+
+ { "set", 1, 1, do_set, 4,
+ " set key : set key in data store w/current dict" },
+
+ { "remove", 1, 1, do_remove, 4,
+ " remove key : remove key from data store" },
+
+ { "touch", 1, 1, do_touch, 4,
+ " touch key : touch key in data store" },
+
+ { "n.list", 0, 1, do_notify_list, 5,
+ " n.list [regex] : list notification keys" },
+
+ { "n.add", 1, 2, do_notify_add, 5,
+ " n.add key [regex] : add notification key" },
+
+ { "n.remove", 1, 2, do_notify_remove, 5,
+ " n.remove key [regex] : remove notification key" },
+
+ { "n.changes", 0, 0, do_notify_changes, 5,
+ " n.changes : list changed keys" },
+
+ { "n.wait", 0, 0, do_notify_wait, 5,
+ " n.wait : wait for changes" },
+
+ { "n.watch", 0, 1, do_notify_callback, 5,
+ " n.watch [verbose] : watch for changes" },
+
+ { "n.signal", 1, 2, do_notify_signal, 5,
+ " n.signal sig [pid] : signal changes" },
+
+ { "n.file", 0, 1, do_notify_file, 5,
+ " n.file [identifier] : watch for changes via file" },
+
+ { "n.cancel", 0, 1, do_notify_cancel, 5,
+ " n.cancel : cancel notification requests" },
+
+ { "snapshot", 0, 0, do_snapshot, 9,
+ " snapshot : save snapshot of cache and session data" },
+
+#ifdef DEBUG
+ { "t.ocleak", 0, 1, test_openCloseLeak, 9,
+ " t.ocleak [#] : test for leaks (open/close)" },
+#endif /* DEBUG */
+};
+
+const int nCommands = (sizeof(commands)/sizeof(cmdInfo));
+
+
+void
+do_command(int argc, char **argv)
+{
+ int i;
+ char *cmd = argv[0];
+
+ for (i=0; i<nCommands; i++) {
+ if (strcasecmp(cmd, commands[i].cmd) == 0) {
+ --argc;
+ argv++;
+ if (argc < commands[i].minArgs) {
+ SCDLog(LOG_INFO, CFSTR("%s: too few arguments"), cmd);
+ return;
+ } else if (argc > commands[i].maxArgs) {
+ SCDLog(LOG_INFO, CFSTR("%s: too many arguments"), cmd);
+ return;
+ }
+ commands[i].func(argc, argv);
+ return;
+ }
+ }
+
+ SCDLog(LOG_INFO, CFSTR("%s: unknown, type \"help\" for command info"), cmd);
+ return;
+}
+
+
+void
+do_help(int argc, char **argv)
+{
+ int g = -1; /* current group */
+ int i;
+
+ SCDLog(LOG_NOTICE, CFSTR(""));
+ SCDLog(LOG_NOTICE, CFSTR("Available commands:"));
+ for (i=0; i<nCommands; i++) {
+ if (g != commands[i].group) {
+ SCDLog(LOG_NOTICE, CFSTR(""));
+ g = commands[i].group;
+ }
+ SCDLog(LOG_NOTICE, CFSTR("%s"), commands[i].usage);
+ }
+ SCDLog(LOG_NOTICE, CFSTR(""));
+
+ return;
+}
+
+
+void
+do_readFile(int argc, char **argv)
+{
+ FILE *fp = fopen(argv[0], "r");
+ boolean_t ok;
+
+ if (fp == NULL) {
+ SCDLog(LOG_INFO, CFSTR("f.read: could not open file (%s)."), strerror(errno));
+ return;
+ }
+
+ /* open file, increase nesting level */
+ SCDLog(LOG_DEBUG, CFSTR("f.read: reading file (%s)."), argv[0]);
+ nesting++;
+
+ if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
+ CFSocketRef in;
+ CFSocketContext context = { 0, fp, NULL, NULL, NULL };
+ CFRunLoopSourceRef rls;
+
+ /* create a "socket" reference with the file descriptor associated with stdin */
+ in = CFSocketCreateWithNative(NULL,
+ fileno(fp),
+ kCFSocketReadCallBack,
+ runLoopProcessInput,
+ &context);
+
+ /* Create and add a run loop source for the file descriptor */
+ rls = CFSocketCreateRunLoopSource(NULL, in, nesting);
+
+ /*
+ * Remove the current input file from the run loop sources. We
+ * will reactivate the current input file source when we are
+ * finished reading data from the new file.
+ */
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
+ (CFRunLoopSourceRef) CFArrayGetValueAtIndex(sources, 0),
+ kCFRunLoopDefaultMode);
+
+ /* keep track of this new source */
+ CFArrayInsertValueAtIndex(sources, 0, rls);
+
+ /* add this source to the run loop */
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+
+ CFRelease(rls);
+ CFRelease(in);
+ } else {
+ do {
+ /* debug information, diagnostics */
+ _showMachPortStatus();
+
+ /* process command */
+ ok = process_line(fp);
+ } while (ok);
+
+ /* decrement the nesting level */
+ nesting--;
+ }
+
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _COMMANDS_H
+#define _COMMANDS_H
+
+#include <sys/cdefs.h>
+
+typedef struct {
+ char *cmd;
+ int minArgs;
+ int maxArgs;
+ void (*func)();
+ int group;
+ char *usage;
+} cmdInfo;
+
+extern const cmdInfo commands[];
+extern const int nCommands;
+
+__BEGIN_DECLS
+
+void do_command __P((int argc, char **argv));
+void do_help __P((int argc, char **argv));
+void do_readFile __P((int argc, char **argv));
+
+__END_DECLS
+
+#endif /* !_COMMANDS_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "scutil.h"
+
+
+//#include <stdlib.h>
+//#include <limits.h>
+
+
+void
+do_dictInit(int argc, char **argv)
+{
+ CFMutableDictionaryRef dict;
+
+ if (data != NULL) {
+ SCDHandleRelease(data);
+ }
+
+ data = SCDHandleInit();
+ dict = CFDictionaryCreateMutable(NULL
+ ,0
+ ,&kCFTypeDictionaryKeyCallBacks
+ ,&kCFTypeDictionaryValueCallBacks
+ );
+ SCDHandleSetData(data, dict);
+ CFRelease(dict);
+
+ return;
+}
+
+
+void
+do_dictShow(int argc, char **argv)
+{
+ int instance;
+ CFPropertyListRef store;
+
+ if (data == NULL) {
+ SCDLog(LOG_INFO, CFSTR("d.show: dictionary must be initialized."));
+ return;
+ }
+
+ instance = SCDHandleGetInstance(data);
+ store = SCDHandleGetData(data);
+
+ SCDLog(LOG_NOTICE, CFSTR("dict (instance = %d) = \n\t%@"), instance, store);
+
+ return;
+}
+
+
+void
+do_dictSetKey(int argc, char **argv)
+{
+ CFPropertyListRef store;
+ CFStringRef key;
+ CFPropertyListRef value = NULL;
+ CFMutableArrayRef array = NULL;
+ boolean_t doArray = FALSE;
+ boolean_t doBoolean = FALSE;
+ boolean_t doNumeric = FALSE;
+
+ if (data == NULL) {
+ SCDLog(LOG_INFO, CFSTR("d.add: dictionary must be initialized."));
+ return;
+ }
+
+ store = SCDHandleGetData(data);
+ if (CFGetTypeID(store) != CFDictionaryGetTypeID()) {
+ SCDLog(LOG_INFO, CFSTR("d.add: data (fetched from configuration server) is not a dictionary"));
+ return;
+ }
+
+
+ key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+ argv++; argc--;
+
+ while (argc > 0) {
+ if (strcmp(argv[0], "*") == 0) {
+ /* if array requested */
+ doArray = TRUE;
+ } else if (strcmp(argv[0], "-") == 0) {
+ /* if string values requested */
+ } else if (strcmp(argv[0], "?") == 0) {
+ /* if boolean values requested */
+ doBoolean = TRUE;
+ } else if (strcmp(argv[0], "#") == 0) {
+ /* if numeric values requested */
+ doNumeric = TRUE;
+ } else {
+ /* it's not a special flag */
+ break;
+ }
+ argv++; argc--;
+ }
+
+ if (argc > 1) {
+ doArray = TRUE;
+ } else if (!doArray && (argc == 0)) {
+ SCDLog(LOG_INFO, CFSTR("d.add: no values"));
+ return;
+ }
+
+ if (doArray) {
+ array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ }
+
+ while (argc > 0) {
+ if (doBoolean) {
+ if ((strcasecmp(argv[0], "true") == 0) ||
+ (strcasecmp(argv[0], "t" ) == 0) ||
+ (strcasecmp(argv[0], "yes" ) == 0) ||
+ (strcasecmp(argv[0], "y" ) == 0) ||
+ (strcmp (argv[0], "1" ) == 0)) {
+ value = CFRetain(kCFBooleanTrue);
+ } else if ((strcasecmp(argv[0], "false") == 0) ||
+ (strcasecmp(argv[0], "f" ) == 0) ||
+ (strcasecmp(argv[0], "no" ) == 0) ||
+ (strcasecmp(argv[0], "n" ) == 0) ||
+ (strcmp (argv[0], "0" ) == 0)) {
+ value = CFRetain(kCFBooleanFalse);
+ } else {
+ SCDLog(LOG_INFO, CFSTR("d.add: invalid data"));
+ if (doArray) {
+ CFRelease(array);
+ }
+ return;
+ }
+ } else if (doNumeric) {
+ int intValue;
+
+ if (sscanf(argv[0], "%d", &intValue) == 1) {
+ value = CFNumberCreate(NULL, kCFNumberIntType, &intValue);
+ } else {
+ SCDLog(LOG_INFO, CFSTR("d.add: invalid data"));
+ if (doArray) {
+ CFRelease(array);
+ }
+ return;
+ }
+ } else {
+ value = (CFPropertyListRef)CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+ }
+
+ if (doArray) {
+ CFArrayAppendValue(array, value);
+ }
+
+ argv++; argc--;
+ }
+
+ if (doArray) {
+ value = array;
+ }
+
+ CFDictionarySetValue((CFMutableDictionaryRef)store, key, value);
+ CFRelease(value);
+ CFRelease(key);
+
+ return;
+}
+
+
+void
+do_dictRemoveKey(int argc, char **argv)
+{
+ CFPropertyListRef store;
+ CFStringRef key;
+
+ if (data == NULL) {
+ SCDLog(LOG_INFO, CFSTR("d.remove: dictionary must be initialized."));
+ return;
+ }
+
+ store = SCDHandleGetData(data);
+ if (CFGetTypeID(store) == CFDictionaryGetTypeID()) {
+ key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+ CFDictionaryRemoveValue((CFMutableDictionaryRef)store, key);
+ CFRelease(key);
+ } else {
+ SCDLog(LOG_INFO, CFSTR("d.add: data (fetched from configuration server) is not a dictionary"));
+ }
+
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _DICTIONARY_H
+#define _DICTIONARY_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void do_dictInit __P((int argc, char **argv));
+void do_dictShow __P((int argc, char **argv));
+void do_dictSetKey __P((int argc, char **argv));
+void do_dictRemoveKey __P((int argc, char **argv));
+
+__END_DECLS
+
+#endif /* !_DICTIONARY_H */
--- /dev/null
+$$
+/* $FILENAME$ created by $USERNAME$ on $DATE$ */
+
+#import <Foundation/Foundation.h>
+
+@interface $FILENAMESANSEXTENSION$ : NSObject
+{
+
+}
+
+@end
--- /dev/null
+$$ Lines starting with $$ are not inserted into newly created files
+$$ The following substitutions are made:
+$$
+$$ $FILENAME$ e.g. foo.m
+$$ $FILENAMESANSEXTENSION$ e.g. foo
+$$ $DIRECTORY$ e.g. /tmp/MyNewApp
+$$ $PROJECTNAME$ e.g. MyNewApp
+$$ $SUBPROJECTNAME$ e.g. TheGoodPart.subproj
+$$ $USERNAME$ e.g. mwagner
+$$ $DATE$ e.g. Jan-1-1994
+$$
+/* $FILENAME$ created by $USERNAME$ on $DATE$ */
+
+#import "$FILENAMESANSEXTENSION$.h"
+
+@implementation $FILENAMESANSEXTENSION$
+
+@end
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "scutil.h"
+
+static int osig;
+static struct sigaction *oact = NULL;
+
+void
+do_notify_list(int argc, char **argv)
+{
+ int regexOptions = 0;
+ SCDStatus status;
+ CFArrayRef list;
+ CFIndex listCnt;
+ int i;
+
+ if (argc == 1)
+ regexOptions = kSCDRegexKey;
+
+ status = SCDNotifierList(session, regexOptions, &list);
+ if (status != SCD_OK) {
+ printf("SCDNotifierList: %s\n", SCDError(status));
+ return;
+ }
+
+ listCnt = CFArrayGetCount(list);
+ if (listCnt > 0) {
+ for (i=0; i<listCnt; i++) {
+ SCDLog(LOG_NOTICE, CFSTR(" notifierKey [%d] = %@"), i, CFArrayGetValueAtIndex(list, i));
+ }
+ } else {
+ SCDLog(LOG_NOTICE, CFSTR(" no notifierKey's"));
+ }
+ CFRelease(list);
+
+ return;
+}
+
+
+void
+do_notify_add(int argc, char **argv)
+{
+ CFStringRef key;
+ int regexOptions = 0;
+ SCDStatus status;
+
+ key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+
+ if (argc == 2)
+ regexOptions = kSCDRegexKey;
+
+ status = SCDNotifierAdd(session, key, regexOptions);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ printf("SCDNotifierAdd: %s\n", SCDError(status));
+ }
+ return;
+}
+
+
+void
+do_notify_remove(int argc, char **argv)
+{
+ SCDStatus status;
+ CFStringRef key;
+ int regexOptions = 0;
+
+ key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman);
+
+ if (argc == 2)
+ regexOptions = kSCDRegexKey;
+
+ status = SCDNotifierRemove(session, key, regexOptions);
+ CFRelease(key);
+ if (status != SCD_OK) {
+ printf("SCDNotifierRemove: %s\n", SCDError(status));
+ }
+ return;
+}
+
+
+void
+do_notify_changes(int argc, char **argv)
+{
+ CFArrayRef list;
+ CFIndex listCnt;
+ SCDStatus status;
+ int i;
+
+ status = SCDNotifierGetChanges(session, &list);
+ if (status != SCD_OK) {
+ printf("SCDNotifierGetChanges: %s\n", SCDError(status));
+ return;
+ }
+
+ listCnt = CFArrayGetCount(list);
+ if (listCnt > 0) {
+ for (i=0; i<listCnt; i++) {
+ SCDLog(LOG_NOTICE, CFSTR(" changedKey [%d] = %@"), i, CFArrayGetValueAtIndex(list, i));
+ }
+ } else {
+ SCDLog(LOG_NOTICE, CFSTR(" no changedKey's"));
+ }
+ CFRelease(list);
+
+ return;
+}
+
+
+void
+do_notify_wait(int argc, char **argv)
+{
+ SCDStatus status;
+
+ status = SCDNotifierWait(session);
+ if (status != SCD_OK) {
+ printf("SCDNotifierWait: %s\n", SCDError(status));
+ return;
+ }
+
+ printf("OK, something changed!\n");
+ return;
+}
+
+
+static boolean_t
+notificationWatcher(SCDSessionRef session, void *arg)
+{
+ printf("notification callback (session address = %p)\n", session);
+ printf(" arg = %s\n", (char *)arg);
+ return TRUE;
+}
+
+
+static boolean_t
+notificationWatcherVerbose(SCDSessionRef session, void *arg)
+{
+ printf("notification callback (session address = %p)\n", session);
+ printf(" arg = %s\n", (char *)arg);
+ do_notify_changes(0, NULL); /* report the keys which changed */
+ return TRUE;
+}
+
+
+void
+do_notify_callback(int argc, char **argv)
+{
+ SCDStatus status;
+ SCDCallbackRoutine_t func = notificationWatcher;
+
+ if ((argc == 1) && (strcmp(argv[0], "verbose") == 0)) {
+ func = notificationWatcherVerbose;
+ }
+
+ status = SCDNotifierInformViaCallback(session,
+ func,
+ "Changed detected by callback handler!");
+ if (status != SCD_OK) {
+ printf("SCDNotifierInformViaCallback: %s\n", SCDError(status));
+ return;
+ }
+
+ return;
+}
+
+
+void
+do_notify_file(int argc, char **argv)
+{
+ int32_t reqID = 0;
+ SCDStatus status;
+ int fd;
+ union {
+ char data[4];
+ int32_t gotID;
+ } buf;
+ char *bufPtr;
+ int needed;
+
+ if (argc == 1) {
+ if ((sscanf(argv[0], "%d", &reqID) != 1)) {
+ printf("invalid identifier\n");
+ return;
+ }
+ }
+
+ status = SCDNotifierInformViaFD(session, reqID, &fd);
+ if (status != SCD_OK) {
+ printf("SCDNotifierInformViaFD: %s\n", SCDError(status));
+ return;
+ }
+
+ bzero(buf.data, sizeof(buf.data));
+ bufPtr = &buf.data[0];
+ needed = sizeof(buf.gotID);
+ while (needed > 0) {
+ int got;
+
+ got = read(fd, bufPtr, needed);
+ if (got == -1) {
+ /* if error detected */
+ printf("read() failed: %s\n", strerror(errno));
+ break;
+ }
+
+ if (got == 0) {
+ /* if end of file detected */
+ printf("read(): detected end of file\n");
+ break;
+ }
+
+ printf("Received %d bytes\n", got);
+ bufPtr += got;
+ needed -= got;
+ }
+
+ if (needed != sizeof(buf.gotID)) {
+ printf(" Received notification, identifier = %d\n", buf.gotID);
+ }
+
+ /* this utility only allows processes one notification per "n.file" request */
+ (void)SCDNotifierCancel(session);
+
+ (void) close(fd); /* close my side of the file descriptor */
+
+ return;
+}
+
+
+static char *signames[] = {
+ "" , "HUP" , "INT" , "QUIT", "ILL" , "TRAP", "ABRT", "EMT" ,
+ "FPE" , "KILL", "BUS" , "SEGV", "SYS" , "PIPE", "ALRM", "TERM",
+ "URG" , "STOP", "TSTP" , "CONT", "CHLD" , "TTIN", "TTOU", "IO" ,
+ "XCPU", "XFSZ", "VTALRM", "PROF", "WINCH", "INFO", "USR1",
+ "USR2"
+};
+
+
+static void
+signalCatcher(int signum)
+{
+ static int n = 0;
+
+ printf("Received SIG%s (#%d)\n", signames[signum], n++);
+ return;
+}
+
+
+void
+do_notify_signal(int argc, char **argv)
+{
+ int sig;
+ pid_t pid;
+ struct sigaction nact;
+ int ret;
+ SCDStatus status;
+
+ if (isdigit(*argv[0])) {
+ if ((sscanf(argv[0], "%d", &sig) != 1) || (sig <= 0) || (sig >= NSIG)) {
+ printf("signal must be in the range of 1 .. %d\n", NSIG-1);
+ return;
+ }
+ } else {
+ for (sig=1; sig<NSIG; sig++) {
+ if (strcasecmp(argv[0], signames[sig]) == 0)
+ break;
+ }
+ if (sig >= NSIG) {
+ printf("Signal must be one of the following:");
+ for (sig=1; sig<NSIG; sig++) {
+ if ((sig % 10) == 1)
+ printf("\n ");
+ printf(" %-6s", signames[sig]);
+ }
+ printf("\n");
+ return;
+ }
+
+ }
+
+ if ((argc != 2) || (sscanf(argv[1], "%d", &pid) != 1)) {
+ pid = getpid();
+ }
+
+ if (oact != NULL) {
+ ret = sigaction(osig, oact, NULL); /* restore original signal handler */
+ } else {
+ oact = malloc(sizeof(struct sigaction));
+ }
+
+ nact.sa_handler = signalCatcher;
+ sigemptyset(&nact.sa_mask);
+ nact.sa_flags = SA_RESTART;
+ ret = sigaction(sig, &nact, oact);
+ osig = sig;
+ printf("signal handler started\n");
+
+ status = SCDNotifierInformViaSignal(session, pid, sig);
+ if (status != SCD_OK) {
+ printf("SCDNotifierInformViaSignal: %s\n", SCDError(status));
+ return;
+ }
+
+ return;
+}
+
+
+void
+do_notify_cancel(int argc, char **argv)
+{
+ SCDStatus status;
+ int ret;
+
+ status = SCDNotifierCancel(session);
+ if (status != SCD_OK) {
+ printf("SCDNotifierCancel: %s\n", SCDError(status));
+ return;
+ }
+
+ if (oact != NULL) {
+ ret = sigaction(osig, oact, NULL); /* restore original signal handler */
+ free(oact);
+ oact = NULL;
+ }
+
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _NOTIFY_H
+#define _NOTIFY_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void do_notify_list __P((int argc, char **argv));
+void do_notify_add __P((int argc, char **argv));
+void do_notify_remove __P((int argc, char **argv));
+void do_notify_changes __P((int argc, char **argv));
+void do_notify_wait __P((int argc, char **argv));
+void do_notify_callback __P((int argc, char **argv));
+void do_notify_signal __P((int argc, char **argv));
+void do_notify_file __P((int argc, char **argv));
+void do_notify_cancel __P((int argc, char **argv));
+
+__END_DECLS
+
+#endif /* !_NOTIFY_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sysexits.h>
+
+#ifdef DEBUG
+#include <mach/mach.h>
+#include <mach/mach_error.h>
+#endif /* DEBUG */
+
+#include "scutil.h"
+#include "SCDPrivate.h"
+#include "commands.h"
+#include "dictionary.h"
+
+#define LINE_LENGTH 256
+
+SCDSessionRef session = NULL;
+SCDHandleRef data = NULL;
+int nesting = 0;
+CFMutableArrayRef sources = NULL;
+
+
+static char *
+getLine(char *buf, int len, FILE *fp)
+{
+ int x;
+
+ if (fgets(buf, len, fp) == NULL)
+ return NULL;
+
+ x = strlen(buf);
+ if (buf[x-1] == '\n') {
+ /* the entire line fit in the buffer, remove the newline */
+ buf[x-1] = '\0';
+ } else {
+ /* eat the remainder of the line */
+ do {
+ x = fgetc(fp);
+ } while ((x != '\n') && (x != EOF));
+ }
+
+ return buf;
+}
+
+
+char *
+getString(char **line)
+{
+ char *s, *e, c, *string;
+ int i, isQuoted = 0, escaped = 0;
+
+ if (*line == NULL) return NULL;
+ if (**line == '\0') return NULL;
+
+ /* Skip leading white space */
+ while (isspace(**line)) *line += 1;
+
+ /* Grab the next string */
+ s = *line;
+ if (*s == '\0') {
+ return NULL; /* no string available */
+ } else if (*s == '"') {
+ isQuoted = 1; /* it's a quoted string */
+ s++;
+ }
+
+ for (e = s; (c = *e) != '\0'; e++) {
+ if (isQuoted && (c == '"'))
+ break; /* end of quoted string */
+ if (c == '\\') {
+ e++;
+ if (*e == '\0')
+ break; /* if premature end-of-string */
+ if ((*e == '"') || isspace(*e))
+ escaped++; /* if escaped quote or white space */
+ }
+ if (!isQuoted && isspace(c))
+ break; /* end of non-quoted string */
+ }
+
+ string = malloc(e - s - escaped + 1);
+
+ for (i = 0; s < e; s++) {
+ string[i] = *s;
+ if (!((s[0] == '\\') && ((s[1] == '"') || isspace(s[1])))) i++;
+ }
+ string[i] = '\0';
+
+ if (isQuoted)
+ e++; /* move past end of quoted string */
+
+ *line = e;
+ return string;
+}
+
+
+boolean_t
+process_line(FILE *fp)
+{
+ char line[LINE_LENGTH], *s, *arg, **argv = NULL;
+ int i, argc;
+
+ /* if end-of-file, exit */
+ if (getLine(line, sizeof(line), fp) == NULL)
+ return FALSE;
+
+ if ((nesting > 0) && SCDOptionGet(NULL, kSCDOptionVerbose)) {
+ SCDLog(LOG_NOTICE, CFSTR("%d> %s"), nesting, line);
+ }
+
+ /* if requested, exit */
+ if (strcasecmp(line, "exit") == 0) return FALSE;
+ if (strcasecmp(line, "quit") == 0) return FALSE;
+ if (strcasecmp(line, "q" ) == 0) return FALSE;
+
+ /* break up the input line */
+ s = line;
+ argc = 0;
+ while ((arg = getString(&s)) != NULL) {
+ if (argc == 0)
+ argv = (char **)malloc(2 * sizeof(char *));
+ else
+ argv = (char **)realloc(argv, ((argc + 2) * sizeof(char *)));
+ argv[argc++] = arg;
+ }
+
+ /* process the command */
+ if (argc > 0) {
+ argv[argc] = NULL; /* just in case... */
+
+ if (*argv[0] != '#')
+ do_command(argc, argv);
+
+ for (i = 0; i < argc; i++)
+ free(argv[i]);
+ free(argv);
+ }
+
+ return TRUE;
+}
+
+
+void
+runLoopProcessInput(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
+{
+ FILE *fp = info;
+
+ if (process_line(fp) == FALSE) {
+ /* we don't want any more input from this stream, stop listening */
+ CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
+ (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, 0),
+ kCFRunLoopDefaultMode);
+
+ /* we no longer need the fd (socket) */
+ CFSocketInvalidate(s);
+
+ /* we no longer need to track this source */
+ CFArrayRemoveValueAtIndex(sources, 0);
+
+ if (CFArrayGetCount(sources) > 0) {
+ /* add the previous input source to the run loop */
+ CFRunLoopAddSource(CFRunLoopGetCurrent(),
+ (CFRunLoopSourceRef)CFArrayGetValueAtIndex(sources, 0),
+ kCFRunLoopDefaultMode);
+ } else {
+ /* no more input sources, we're done! */
+ exit (EX_OK);
+ }
+
+ /* decrement the nesting level */
+ nesting--;
+ }
+
+ if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
+ /* debug information, diagnostics */
+ _showMachPortStatus();
+
+ /* if necessary, re-issue prompt */
+ if ((CFArrayGetCount(sources) == 1) && isatty(STDIN_FILENO)) {
+ printf("> ");
+ fflush(stdout);
+ }
+ }
+
+ return;
+}
+
+
+int
+main(int argc, const char *argv[])
+{
+ extern int optind;
+ int opt;
+ boolean_t ok;
+
+ /* process any arguments */
+
+ SCDOptionSet(NULL, kSCDOptionUseCFRunLoop, FALSE);
+
+ while ((opt = getopt(argc, argv, "dvr")) != -1)
+ switch(opt) {
+ case 'd':
+ SCDOptionSet(NULL, kSCDOptionDebug, TRUE);
+ break;
+ case 'v':
+ SCDOptionSet(NULL, kSCDOptionVerbose, TRUE);
+ break;
+ case 'r':
+ SCDOptionSet(NULL, kSCDOptionUseCFRunLoop, TRUE);
+ break;
+ case '?':
+ default :
+ do_help(0, NULL);
+ }
+ argc -= optind;
+ argv += optind;
+
+ /* start with an empty dictionary */
+ do_dictInit(0, NULL);
+
+ if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
+ CFSocketRef in;
+ CFSocketContext context = { 0, stdin, NULL, NULL, NULL };
+ CFRunLoopSourceRef rls;
+
+ /* create a "socket" reference with the file descriptor associated with stdin */
+ in = CFSocketCreateWithNative(NULL,
+ STDIN_FILENO,
+ kCFSocketReadCallBack,
+ runLoopProcessInput,
+ &context);
+
+ /* Create a run loop source for the (stdin) file descriptor */
+ rls = CFSocketCreateRunLoopSource(NULL, in, nesting);
+
+ /* keep track of input file sources */
+ sources = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ CFArrayAppendValue(sources, rls);
+
+ /* add this source to the run loop */
+ CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
+
+ CFRelease(rls);
+ CFRelease(in);
+ }
+
+ do {
+ /* debug information, diagnostics */
+ _showMachPortStatus();
+
+ /* issue prompt */
+ if (isatty(STDIN_FILENO)) {
+ printf("> ");
+ fflush(stdout);
+ }
+
+ if (SCDOptionGet(NULL, kSCDOptionUseCFRunLoop)) {
+ CFRunLoopRun(); /* process input, process events */
+ ok = FALSE; /* if the RunLoop exited */
+ } else {
+ /* process command */
+ ok = process_line(stdin);
+ }
+ } while (ok);
+
+ exit (EX_OK); // insure the process exit status is 0
+ return 0; // ...and make main fit the ANSI spec.
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SC_H
+#define _SC_H
+
+#include <sys/cdefs.h>
+
+#include <SystemConfiguration/SCD.h>
+
+extern SCDSessionRef session;
+extern SCDHandleRef data;
+extern int nesting;
+extern CFMutableArrayRef sources;
+
+__BEGIN_DECLS
+
+boolean_t process_line __P((FILE *fp));
+
+void runLoopProcessInput __P((CFSocketRef s,
+ CFSocketCallBackType type,
+ CFDataRef address,
+ const void *data,
+ void *info));
+
+__END_DECLS
+
+#endif /* !_SC_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "scutil.h"
+
+void
+do_open(int argc, char **argv)
+{
+ SCDStatus status;
+
+ if (session != NULL) {
+ status = SCDClose(&session);
+ switch (status) {
+ case SCD_OK :
+ case SCD_NOSESSION :
+ /*
+ * if the "close" was successful or if we had an open
+ * session but can no talk to the server
+ */
+ break;
+ default :
+ SCDLog(LOG_INFO, CFSTR("SCDClose: %s"), SCDError(status));
+ return;
+ }
+ }
+
+ status = SCDOpen(&session, CFSTR("sc"));
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDOpen: %s"), SCDError(status));
+ return;
+ }
+
+ return;
+}
+
+
+void
+do_close(int argc, char **argv)
+{
+ SCDStatus status;
+
+ status = SCDClose(&session);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDClose: %s"), SCDError(status));
+ }
+ return;
+}
+
+
+void
+do_lock(int argc, char **argv)
+{
+ SCDStatus status;
+
+ status = SCDLock(session);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDLock: %s"), SCDError(status));
+ }
+ return;
+}
+
+
+void
+do_unlock(int argc, char **argv)
+{
+ SCDStatus status;
+
+ status = SCDUnlock(session);
+ if (status != SCD_OK) {
+ SCDLog(LOG_INFO, CFSTR("SCDUnlock: %s"), SCDError(status));
+ }
+ return;
+}
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _SESSION_H
+#define _SESSION_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void do_open __P((int argc, char **argv));
+void do_close __P((int argc, char **argv));
+void do_lock __P((int argc, char **argv));
+void do_unlock __P((int argc, char **argv));
+
+__END_DECLS
+
+#endif /* !_SESSION_H */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#include "scutil.h"
+#include "SCDPrivate.h"
+
+void
+do_snapshot(int argc, char **argv)
+{
+ SCDStatus status;
+
+ status = SCDSnapshot(session);
+ if (status != SCD_OK) {
+ printf("SCDSnapshot: %s\n", SCDError(status));
+ }
+ return;
+}
+
+
+#ifdef DEBUG
+
+void
+test_openCloseLeak(int argc, char **argv)
+{
+ SCDStatus status;
+ int i, loopCnt;
+ SCDSessionRef *sessions;
+
+ if ((argc == 0) || (sscanf(argv[0], "%d", &loopCnt) != 1)) {
+ loopCnt = 100;
+ }
+
+ sessions = malloc(loopCnt * sizeof(SCDSessionRef));
+
+ /* open, close, open, close, open, close, ... */
+ for (i=0; i<loopCnt; i++) {
+ status = SCDOpen(&sessions[i], CFSTR("sc"));
+ if (status != SCD_OK) {
+ printf("SCDOpen: %s\n", SCDError(status));
+ break;
+ }
+
+ status = SCDClose(&sessions[i]);
+ if (status != SCD_OK) {
+ printf("SCDClose: %s\n", SCDError(status));
+ break;
+ }
+ }
+
+ /* open, open, open, close, close, close, ... */
+ for (i=0; i<loopCnt; i++) {
+ status = SCDOpen(&sessions[i], CFSTR("sc"));
+ if (status != SCD_OK) {
+ printf("SCDOpen: %s\n", SCDError(status));
+ break;
+ }
+ }
+ for (i=0; i<loopCnt; i++) {
+ status = SCDClose(&sessions[i]);
+ if (status != SCD_OK) {
+ printf("SCDClose: %s\n", SCDError(status));
+ break;
+ }
+ }
+
+ return;
+}
+#endif /* DEBUG */
--- /dev/null
+/*
+ * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ *
+ * @APPLE_LICENSE_HEADER_START@
+ *
+ * The contents of this file constitute Original Code as defined in and
+ * are subject to the Apple Public Source License Version 1.1 (the
+ * "License"). You may not use this file except in compliance with the
+ * License. Please obtain a copy of the License at
+ * http://www.apple.com/publicsource and read it before using this file.
+ *
+ * This Original Code and all software distributed under the License are
+ * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
+ * License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * @APPLE_LICENSE_HEADER_END@
+ */
+
+#ifndef _TESTS_H
+#define _TESTS_H
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+void do_snapshot __P((int argc, char **argv));
+
+#ifdef DEBUG
+void test_setServer __P((int argc, char **argv));
+void test_openCloseLeak __P((int argc, char **argv));
+#endif /* DEBUG */
+
+__END_DECLS
+
+#endif /* !_TESTS_H */