From 5958d7c06f2795b9ec773eb750b8259460acf8cb Mon Sep 17 00:00:00 2001 From: Apple Date: Wed, 11 Apr 2001 13:07:37 +0000 Subject: [PATCH 1/1] configd-24.tar.gz --- Makefile | 46 + Makefile.postamble | 100 ++ Makefile.preamble | 137 ++ PB.project | 22 + SystemConfiguration.fproj/CustomInfo.plist | 5 + SystemConfiguration.fproj/Makefile | 73 + SystemConfiguration.fproj/Makefile.postamble | 119 ++ SystemConfiguration.fproj/Makefile.preamble | 159 +++ SystemConfiguration.fproj/PB.project | 120 ++ SystemConfiguration.fproj/SCD.c | 230 +++ SystemConfiguration.fproj/SCD.h | 631 +++++++++ SystemConfiguration.fproj/SCDAdd.c | 94 ++ SystemConfiguration.fproj/SCDAddSession.c | 94 ++ SystemConfiguration.fproj/SCDClose.c | 118 ++ SystemConfiguration.fproj/SCDConsoleUser.c | 172 +++ SystemConfiguration.fproj/SCDConsoleUser.h | 96 ++ SystemConfiguration.fproj/SCDGet.c | 120 ++ SystemConfiguration.fproj/SCDHandle.c | 102 ++ SystemConfiguration.fproj/SCDHostName.c | 86 ++ SystemConfiguration.fproj/SCDHostName.h | 69 + SystemConfiguration.fproj/SCDKeys.c | 119 ++ SystemConfiguration.fproj/SCDKeys.h | 63 + SystemConfiguration.fproj/SCDList.c | 132 ++ SystemConfiguration.fproj/SCDLock.c | 56 + SystemConfiguration.fproj/SCDNotifierAdd.c | 93 ++ SystemConfiguration.fproj/SCDNotifierCancel.c | 99 ++ .../SCDNotifierGetChanges.c | 110 ++ .../SCDNotifierInformViaCallback.c | 275 ++++ .../SCDNotifierInformViaFD.c | 111 ++ .../SCDNotifierInformViaMachPort.c | 109 ++ .../SCDNotifierInformViaSignal.c | 83 ++ SystemConfiguration.fproj/SCDNotifierList.c | 73 + SystemConfiguration.fproj/SCDNotifierRemove.c | 98 ++ SystemConfiguration.fproj/SCDNotifierWait.c | 151 ++ SystemConfiguration.fproj/SCDOpen.c | 152 ++ SystemConfiguration.fproj/SCDPrivate.c | 165 +++ SystemConfiguration.fproj/SCDPrivate.h | 130 ++ SystemConfiguration.fproj/SCDRemove.c | 75 + SystemConfiguration.fproj/SCDSet.c | 96 ++ SystemConfiguration.fproj/SCDSnapshot.c | 55 + SystemConfiguration.fproj/SCDTouch.c | 75 + SystemConfiguration.fproj/SCDUnlock.c | 60 + SystemConfiguration.fproj/SCNetwork.c | 1235 +++++++++++++++++ SystemConfiguration.fproj/SCNetwork.h | 164 +++ SystemConfiguration.fproj/SCP.c | 250 ++++ SystemConfiguration.fproj/SCP.h | 404 ++++++ SystemConfiguration.fproj/SCPAdd.c | 50 + SystemConfiguration.fproj/SCPApply.c | 89 ++ SystemConfiguration.fproj/SCPClose.c | 66 + SystemConfiguration.fproj/SCPCommit.c | 173 +++ SystemConfiguration.fproj/SCPGet.c | 51 + SystemConfiguration.fproj/SCPList.c | 70 + SystemConfiguration.fproj/SCPLock.c | 172 +++ SystemConfiguration.fproj/SCPOpen.c | 223 +++ SystemConfiguration.fproj/SCPPath.c | 428 ++++++ SystemConfiguration.fproj/SCPPath.h | 175 +++ SystemConfiguration.fproj/SCPPrivate.h | 101 ++ SystemConfiguration.fproj/SCPRemove.c | 50 + SystemConfiguration.fproj/SCPSet.c | 46 + SystemConfiguration.fproj/SCPUnlock.c | 63 + .../SystemConfiguration.h | 54 + SystemConfiguration.fproj/config.defs | 168 +++ SystemConfiguration.fproj/config_types.h | 50 + SystemConfiguration.fproj/genSCPreferences.c | 643 +++++++++ SystemConfiguration.fproj/h.template | 11 + SystemConfiguration.fproj/m.template | 18 + SystemConfiguration.fproj/ppp.c | 341 +++++ SystemConfiguration.fproj/ppp.h | 69 + SystemConfiguration.fproj/ppp_msg.h | 242 ++++ configd.tproj/Makefile | 60 + configd.tproj/Makefile.postamble | 101 ++ configd.tproj/Makefile.preamble | 141 ++ configd.tproj/PB.project | 75 + configd.tproj/_SCD.c | 532 +++++++ configd.tproj/_SCD.h | 202 +++ configd.tproj/_configadd.c | 161 +++ configd.tproj/_configadd_s.c | 173 +++ configd.tproj/_configclose.c | 203 +++ configd.tproj/_configget.c | 139 ++ configd.tproj/_configlist.c | 227 +++ configd.tproj/_configlock.c | 97 ++ configd.tproj/_configopen.c | 189 +++ configd.tproj/_configremove.c | 162 +++ configd.tproj/_configset.c | 246 ++++ configd.tproj/_configtouch.c | 139 ++ configd.tproj/_configunlock.c | 296 ++++ configd.tproj/_notifyadd.c | 212 +++ configd.tproj/_notifycancel.c | 102 ++ configd.tproj/_notifychanges.c | 109 ++ configd.tproj/_notifyremove.c | 168 +++ configd.tproj/_notifyviafd.c | 168 +++ configd.tproj/_notifyviaport.c | 100 ++ configd.tproj/_notifyviasignal.c | 158 +++ configd.tproj/_snapshot.c | 89 ++ configd.tproj/config.defs | 18 + configd.tproj/configd.h | 41 + configd.tproj/configd.m | 257 ++++ configd.tproj/configd_server.c | 315 +++++ configd.tproj/configd_server.h | 149 ++ configd.tproj/h.template | 11 + configd.tproj/m.template | 18 + configd.tproj/notify.c | 161 +++ configd.tproj/notify.h | 34 + configd.tproj/notify_server.c | 64 + configd.tproj/notify_server.h | 35 + configd.tproj/plugin_support.c | 568 ++++++++ configd.tproj/plugin_support.h | 35 + configd.tproj/session.c | 208 +++ configd.tproj/session.h | 61 + scselect.tproj/Makefile | 50 + scselect.tproj/Makefile.postamble | 100 ++ scselect.tproj/Makefile.preamble | 137 ++ scselect.tproj/PB.project | 30 + scselect.tproj/h.template | 11 + scselect.tproj/m.template | 18 + scselect.tproj/scselect.c | 258 ++++ scutil.tproj/Makefile | 54 + scutil.tproj/Makefile.postamble | 100 ++ scutil.tproj/Makefile.preamble | 137 ++ scutil.tproj/PB.project | 28 + scutil.tproj/cache.c | 162 +++ scutil.tproj/cache.h | 39 + scutil.tproj/commands.c | 242 ++++ scutil.tproj/commands.h | 48 + scutil.tproj/dictionary.c | 205 +++ scutil.tproj/dictionary.h | 37 + scutil.tproj/h.template | 11 + scutil.tproj/m.template | 18 + scutil.tproj/notify.c | 352 +++++ scutil.tproj/notify.h | 42 + scutil.tproj/scutil.c | 293 ++++ scutil.tproj/scutil.h | 47 + scutil.tproj/session.c | 92 ++ scutil.tproj/session.h | 37 + scutil.tproj/tests.c | 87 ++ scutil.tproj/tests.h | 39 + 136 files changed, 19277 insertions(+) create mode 100644 Makefile create mode 100644 Makefile.postamble create mode 100644 Makefile.preamble create mode 100644 PB.project create mode 100644 SystemConfiguration.fproj/CustomInfo.plist create mode 100644 SystemConfiguration.fproj/Makefile create mode 100644 SystemConfiguration.fproj/Makefile.postamble create mode 100644 SystemConfiguration.fproj/Makefile.preamble create mode 100644 SystemConfiguration.fproj/PB.project create mode 100644 SystemConfiguration.fproj/SCD.c create mode 100644 SystemConfiguration.fproj/SCD.h create mode 100644 SystemConfiguration.fproj/SCDAdd.c create mode 100644 SystemConfiguration.fproj/SCDAddSession.c create mode 100644 SystemConfiguration.fproj/SCDClose.c create mode 100644 SystemConfiguration.fproj/SCDConsoleUser.c create mode 100644 SystemConfiguration.fproj/SCDConsoleUser.h create mode 100644 SystemConfiguration.fproj/SCDGet.c create mode 100644 SystemConfiguration.fproj/SCDHandle.c create mode 100644 SystemConfiguration.fproj/SCDHostName.c create mode 100644 SystemConfiguration.fproj/SCDHostName.h create mode 100644 SystemConfiguration.fproj/SCDKeys.c create mode 100644 SystemConfiguration.fproj/SCDKeys.h create mode 100644 SystemConfiguration.fproj/SCDList.c create mode 100644 SystemConfiguration.fproj/SCDLock.c create mode 100644 SystemConfiguration.fproj/SCDNotifierAdd.c create mode 100644 SystemConfiguration.fproj/SCDNotifierCancel.c create mode 100644 SystemConfiguration.fproj/SCDNotifierGetChanges.c create mode 100644 SystemConfiguration.fproj/SCDNotifierInformViaCallback.c create mode 100644 SystemConfiguration.fproj/SCDNotifierInformViaFD.c create mode 100644 SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c create mode 100644 SystemConfiguration.fproj/SCDNotifierInformViaSignal.c create mode 100644 SystemConfiguration.fproj/SCDNotifierList.c create mode 100644 SystemConfiguration.fproj/SCDNotifierRemove.c create mode 100644 SystemConfiguration.fproj/SCDNotifierWait.c create mode 100644 SystemConfiguration.fproj/SCDOpen.c create mode 100644 SystemConfiguration.fproj/SCDPrivate.c create mode 100644 SystemConfiguration.fproj/SCDPrivate.h create mode 100644 SystemConfiguration.fproj/SCDRemove.c create mode 100644 SystemConfiguration.fproj/SCDSet.c create mode 100644 SystemConfiguration.fproj/SCDSnapshot.c create mode 100644 SystemConfiguration.fproj/SCDTouch.c create mode 100644 SystemConfiguration.fproj/SCDUnlock.c create mode 100644 SystemConfiguration.fproj/SCNetwork.c create mode 100644 SystemConfiguration.fproj/SCNetwork.h create mode 100644 SystemConfiguration.fproj/SCP.c create mode 100644 SystemConfiguration.fproj/SCP.h create mode 100644 SystemConfiguration.fproj/SCPAdd.c create mode 100644 SystemConfiguration.fproj/SCPApply.c create mode 100644 SystemConfiguration.fproj/SCPClose.c create mode 100644 SystemConfiguration.fproj/SCPCommit.c create mode 100644 SystemConfiguration.fproj/SCPGet.c create mode 100644 SystemConfiguration.fproj/SCPList.c create mode 100644 SystemConfiguration.fproj/SCPLock.c create mode 100644 SystemConfiguration.fproj/SCPOpen.c create mode 100644 SystemConfiguration.fproj/SCPPath.c create mode 100644 SystemConfiguration.fproj/SCPPath.h create mode 100644 SystemConfiguration.fproj/SCPPrivate.h create mode 100644 SystemConfiguration.fproj/SCPRemove.c create mode 100644 SystemConfiguration.fproj/SCPSet.c create mode 100644 SystemConfiguration.fproj/SCPUnlock.c create mode 100644 SystemConfiguration.fproj/SystemConfiguration.h create mode 100644 SystemConfiguration.fproj/config.defs create mode 100644 SystemConfiguration.fproj/config_types.h create mode 100644 SystemConfiguration.fproj/genSCPreferences.c create mode 100644 SystemConfiguration.fproj/h.template create mode 100644 SystemConfiguration.fproj/m.template create mode 100644 SystemConfiguration.fproj/ppp.c create mode 100644 SystemConfiguration.fproj/ppp.h create mode 100644 SystemConfiguration.fproj/ppp_msg.h create mode 100644 configd.tproj/Makefile create mode 100644 configd.tproj/Makefile.postamble create mode 100644 configd.tproj/Makefile.preamble create mode 100644 configd.tproj/PB.project create mode 100644 configd.tproj/_SCD.c create mode 100644 configd.tproj/_SCD.h create mode 100644 configd.tproj/_configadd.c create mode 100644 configd.tproj/_configadd_s.c create mode 100644 configd.tproj/_configclose.c create mode 100644 configd.tproj/_configget.c create mode 100644 configd.tproj/_configlist.c create mode 100644 configd.tproj/_configlock.c create mode 100644 configd.tproj/_configopen.c create mode 100644 configd.tproj/_configremove.c create mode 100644 configd.tproj/_configset.c create mode 100644 configd.tproj/_configtouch.c create mode 100644 configd.tproj/_configunlock.c create mode 100644 configd.tproj/_notifyadd.c create mode 100644 configd.tproj/_notifycancel.c create mode 100644 configd.tproj/_notifychanges.c create mode 100644 configd.tproj/_notifyremove.c create mode 100644 configd.tproj/_notifyviafd.c create mode 100644 configd.tproj/_notifyviaport.c create mode 100644 configd.tproj/_notifyviasignal.c create mode 100644 configd.tproj/_snapshot.c create mode 100644 configd.tproj/config.defs create mode 100644 configd.tproj/configd.h create mode 100644 configd.tproj/configd.m create mode 100644 configd.tproj/configd_server.c create mode 100644 configd.tproj/configd_server.h create mode 100644 configd.tproj/h.template create mode 100644 configd.tproj/m.template create mode 100644 configd.tproj/notify.c create mode 100644 configd.tproj/notify.h create mode 100644 configd.tproj/notify_server.c create mode 100644 configd.tproj/notify_server.h create mode 100644 configd.tproj/plugin_support.c create mode 100644 configd.tproj/plugin_support.h create mode 100644 configd.tproj/session.c create mode 100644 configd.tproj/session.h create mode 100644 scselect.tproj/Makefile create mode 100644 scselect.tproj/Makefile.postamble create mode 100644 scselect.tproj/Makefile.preamble create mode 100644 scselect.tproj/PB.project create mode 100644 scselect.tproj/h.template create mode 100644 scselect.tproj/m.template create mode 100644 scselect.tproj/scselect.c create mode 100644 scutil.tproj/Makefile create mode 100644 scutil.tproj/Makefile.postamble create mode 100644 scutil.tproj/Makefile.preamble create mode 100644 scutil.tproj/PB.project create mode 100644 scutil.tproj/cache.c create mode 100644 scutil.tproj/cache.h create mode 100644 scutil.tproj/commands.c create mode 100644 scutil.tproj/commands.h create mode 100644 scutil.tproj/dictionary.c create mode 100644 scutil.tproj/dictionary.h create mode 100644 scutil.tproj/h.template create mode 100644 scutil.tproj/m.template create mode 100644 scutil.tproj/notify.c create mode 100644 scutil.tproj/notify.h create mode 100644 scutil.tproj/scutil.c create mode 100644 scutil.tproj/scutil.h create mode 100644 scutil.tproj/session.c create mode 100644 scutil.tproj/session.h create mode 100644 scutil.tproj/tests.c create mode 100644 scutil.tproj/tests.h diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..61c7f5a --- /dev/null +++ b/Makefile @@ -0,0 +1,46 @@ +# +# 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 diff --git a/Makefile.postamble b/Makefile.postamble new file mode 100644 index 0000000..b3af842 --- /dev/null +++ b/Makefile.postamble @@ -0,0 +1,100 @@ +############################################################################### +# 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. +# diff --git a/Makefile.preamble b/Makefile.preamble new file mode 100644 index 0000000..974c0ac --- /dev/null +++ b/Makefile.preamble @@ -0,0 +1,137 @@ +############################################################################### +# 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: <> +# 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) diff --git a/PB.project b/PB.project new file mode 100644 index 0000000..3af9f55 --- /dev/null +++ b/PB.project @@ -0,0 +1,22 @@ +{ + 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"; +} diff --git a/SystemConfiguration.fproj/CustomInfo.plist b/SystemConfiguration.fproj/CustomInfo.plist new file mode 100644 index 0000000..89cf132 --- /dev/null +++ b/SystemConfiguration.fproj/CustomInfo.plist @@ -0,0 +1,5 @@ +{ + CFBundleName = "SystemConfiguration"; + CFBundleIdentifier = "com.apple.SystemConfiguration"; + CFBundleShortVersionString = "1.0.0"; +} diff --git a/SystemConfiguration.fproj/Makefile b/SystemConfiguration.fproj/Makefile new file mode 100644 index 0000000..20f1e2c --- /dev/null +++ b/SystemConfiguration.fproj/Makefile @@ -0,0 +1,73 @@ +# +# 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 diff --git a/SystemConfiguration.fproj/Makefile.postamble b/SystemConfiguration.fproj/Makefile.postamble new file mode 100644 index 0000000..888849f --- /dev/null +++ b/SystemConfiguration.fproj/Makefile.postamble @@ -0,0 +1,119 @@ +############################################################################### +# 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 diff --git a/SystemConfiguration.fproj/Makefile.preamble b/SystemConfiguration.fproj/Makefile.preamble new file mode 100644 index 0000000..cb94833 --- /dev/null +++ b/SystemConfiguration.fproj/Makefile.preamble @@ -0,0 +1,159 @@ +############################################################################### +# 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: <> +# 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 diff --git a/SystemConfiguration.fproj/PB.project b/SystemConfiguration.fproj/PB.project new file mode 100644 index 0000000..f132d48 --- /dev/null +++ b/SystemConfiguration.fproj/PB.project @@ -0,0 +1,120 @@ +{ + 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"; +} diff --git a/SystemConfiguration.fproj/SCD.c b/SystemConfiguration.fproj/SCD.c new file mode 100644 index 0000000..169af6b --- /dev/null +++ b/SystemConfiguration.fproj/SCD.c @@ -0,0 +1,230 @@ +/* + * 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 +#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 +#include +#include +#include +#include + + +/*! + @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 */ diff --git a/SystemConfiguration.fproj/SCDAdd.c b/SystemConfiguration.fproj/SCDAdd.c new file mode 100644 index 0000000..382249e --- /dev/null +++ b/SystemConfiguration.fproj/SCDAdd.c @@ -0,0 +1,94 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDAddSession.c b/SystemConfiguration.fproj/SCDAddSession.c new file mode 100644 index 0000000..b19ae0e --- /dev/null +++ b/SystemConfiguration.fproj/SCDAddSession.c @@ -0,0 +1,94 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDClose.c b/SystemConfiguration.fproj/SCDClose.c new file mode 100644 index 0000000..86aeb3c --- /dev/null +++ b/SystemConfiguration.fproj/SCDClose.c @@ -0,0 +1,118 @@ +/* + * 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 +#include +#include + +#include +#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; ireKeys)) > 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; iserver, (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; +} diff --git a/SystemConfiguration.fproj/SCDConsoleUser.c b/SystemConfiguration.fproj/SCDConsoleUser.c new file mode 100644 index 0000000..a607b93 --- /dev/null +++ b/SystemConfiguration.fproj/SCDConsoleUser.c @@ -0,0 +1,172 @@ +/* + * 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 + + +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; +} diff --git a/SystemConfiguration.fproj/SCDConsoleUser.h b/SystemConfiguration.fproj/SCDConsoleUser.h new file mode 100644 index 0000000..e164799 --- /dev/null +++ b/SystemConfiguration.fproj/SCDConsoleUser.h @@ -0,0 +1,96 @@ +/* + * 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 + +/*! + @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 */ diff --git a/SystemConfiguration.fproj/SCDGet.c b/SystemConfiguration.fproj/SCDGet.c new file mode 100644 index 0000000..d59a46a --- /dev/null +++ b/SystemConfiguration.fproj/SCDGet.c @@ -0,0 +1,120 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDHandle.c b/SystemConfiguration.fproj/SCDHandle.c new file mode 100644 index 0000000..5e4ab8e --- /dev/null +++ b/SystemConfiguration.fproj/SCDHandle.c @@ -0,0 +1,102 @@ +/* + * 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 +#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; +} diff --git a/SystemConfiguration.fproj/SCDHostName.c b/SystemConfiguration.fproj/SCDHostName.c new file mode 100644 index 0000000..c127f7f --- /dev/null +++ b/SystemConfiguration.fproj/SCDHostName.c @@ -0,0 +1,86 @@ +/* + * 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 + + +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; +} diff --git a/SystemConfiguration.fproj/SCDHostName.h b/SystemConfiguration.fproj/SCDHostName.h new file mode 100644 index 0000000..2ce1cad --- /dev/null +++ b/SystemConfiguration.fproj/SCDHostName.h @@ -0,0 +1,69 @@ +/* + * 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 + +/*! + @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 */ diff --git a/SystemConfiguration.fproj/SCDKeys.c b/SystemConfiguration.fproj/SCDKeys.c new file mode 100644 index 0000000..e2a51c7 --- /dev/null +++ b/SystemConfiguration.fproj/SCDKeys.c @@ -0,0 +1,119 @@ +/* + * 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 + +#include + +/* + * 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)); + } +} diff --git a/SystemConfiguration.fproj/SCDKeys.h b/SystemConfiguration.fproj/SCDKeys.h new file mode 100644 index 0000000..4c1f2b6 --- /dev/null +++ b/SystemConfiguration.fproj/SCDKeys.h @@ -0,0 +1,63 @@ +/* + * 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 +#include + +__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 */ diff --git a/SystemConfiguration.fproj/SCDList.c b/SystemConfiguration.fproj/SCDList.c new file mode 100644 index 0000000..1efabf3 --- /dev/null +++ b/SystemConfiguration.fproj/SCDList.c @@ -0,0 +1,132 @@ +/* + * 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 +#include + +#include +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDLock.c b/SystemConfiguration.fproj/SCDLock.c new file mode 100644 index 0000000..ff1a1d4 --- /dev/null +++ b/SystemConfiguration.fproj/SCDLock.c @@ -0,0 +1,56 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierAdd.c b/SystemConfiguration.fproj/SCDNotifierAdd.c new file mode 100644 index 0000000..689cb2e --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierAdd.c @@ -0,0 +1,93 @@ +/* + * 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 +#include + +#include +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierCancel.c b/SystemConfiguration.fproj/SCDNotifierCancel.c new file mode 100644 index 0000000..3ee6d14 --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierCancel.c @@ -0,0 +1,99 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierGetChanges.c b/SystemConfiguration.fproj/SCDNotifierGetChanges.c new file mode 100644 index 0000000..1fbf028 --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierGetChanges.c @@ -0,0 +1,110 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c b/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c new file mode 100644 index 0000000..481d5b1 --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c @@ -0,0 +1,275 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaFD.c b/SystemConfiguration.fproj/SCDNotifierInformViaFD.c new file mode 100644 index 0000000..48ba04f --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierInformViaFD.c @@ -0,0 +1,111 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c b/SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c new file mode 100644 index 0000000..848579f --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c @@ -0,0 +1,109 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaSignal.c b/SystemConfiguration.fproj/SCDNotifierInformViaSignal.c new file mode 100644 index 0000000..01e0c14 --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierInformViaSignal.c @@ -0,0 +1,83 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierList.c b/SystemConfiguration.fproj/SCDNotifierList.c new file mode 100644 index 0000000..e821232 --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierList.c @@ -0,0 +1,73 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierRemove.c b/SystemConfiguration.fproj/SCDNotifierRemove.c new file mode 100644 index 0000000..e062600 --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierRemove.c @@ -0,0 +1,98 @@ +/* + * 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 +#include + +#include +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDNotifierWait.c b/SystemConfiguration.fproj/SCDNotifierWait.c new file mode 100644 index 0000000..67cf1d9 --- /dev/null +++ b/SystemConfiguration.fproj/SCDNotifierWait.c @@ -0,0 +1,151 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDOpen.c b/SystemConfiguration.fproj/SCDOpen.c new file mode 100644 index 0000000..7e1f720 --- /dev/null +++ b/SystemConfiguration.fproj/SCDOpen.c @@ -0,0 +1,152 @@ +/* + * 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 +#include +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDPrivate.c b/SystemConfiguration.fproj/SCDPrivate.c new file mode 100644 index 0000000..86a6f03 --- /dev/null +++ b/SystemConfiguration.fproj/SCDPrivate.c @@ -0,0 +1,165 @@ +/* + * 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 +#include +#include +#include + +#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; +} diff --git a/SystemConfiguration.fproj/SCDPrivate.h b/SystemConfiguration.fproj/SCDPrivate.h new file mode 100644 index 0000000..3601d35 --- /dev/null +++ b/SystemConfiguration.fproj/SCDPrivate.h @@ -0,0 +1,130 @@ +/* + * 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 + +#include +#include +#include +#include +#include + + +/* 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 */ diff --git a/SystemConfiguration.fproj/SCDRemove.c b/SystemConfiguration.fproj/SCDRemove.c new file mode 100644 index 0000000..30cc8b1 --- /dev/null +++ b/SystemConfiguration.fproj/SCDRemove.c @@ -0,0 +1,75 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDSet.c b/SystemConfiguration.fproj/SCDSet.c new file mode 100644 index 0000000..1cb79ad --- /dev/null +++ b/SystemConfiguration.fproj/SCDSet.c @@ -0,0 +1,96 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDSnapshot.c b/SystemConfiguration.fproj/SCDSnapshot.c new file mode 100644 index 0000000..1339cda --- /dev/null +++ b/SystemConfiguration.fproj/SCDSnapshot.c @@ -0,0 +1,55 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDTouch.c b/SystemConfiguration.fproj/SCDTouch.c new file mode 100644 index 0000000..2e83c37 --- /dev/null +++ b/SystemConfiguration.fproj/SCDTouch.c @@ -0,0 +1,75 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCDUnlock.c b/SystemConfiguration.fproj/SCDUnlock.c new file mode 100644 index 0000000..c1540b9 --- /dev/null +++ b/SystemConfiguration.fproj/SCDUnlock.c @@ -0,0 +1,60 @@ +/* + * 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 +#include + +#include +#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; +} diff --git a/SystemConfiguration.fproj/SCNetwork.c b/SystemConfiguration.fproj/SCNetwork.c new file mode 100644 index 0000000..9c24f2e --- /dev/null +++ b/SystemConfiguration.fproj/SCNetwork.c @@ -0,0 +1,1235 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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; isa_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; isin_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; is_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; isin_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; +} diff --git a/SystemConfiguration.fproj/SCNetwork.h b/SystemConfiguration.fproj/SCNetwork.h new file mode 100644 index 0000000..2f22ca1 --- /dev/null +++ b/SystemConfiguration.fproj/SCNetwork.h @@ -0,0 +1,164 @@ +/* + * 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 +#include + +/*! + @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 */ diff --git a/SystemConfiguration.fproj/SCP.c b/SystemConfiguration.fproj/SCP.c new file mode 100644 index 0000000..15d39f3 --- /dev/null +++ b/SystemConfiguration.fproj/SCP.c @@ -0,0 +1,250 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include +#include +#include +#include +#include + + +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)"; +} diff --git a/SystemConfiguration.fproj/SCP.h b/SystemConfiguration.fproj/SCP.h new file mode 100644 index 0000000..3c210c4 --- /dev/null +++ b/SystemConfiguration.fproj/SCP.h @@ -0,0 +1,404 @@ +/* + * 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 +#include + +/*! + @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 */ diff --git a/SystemConfiguration.fproj/SCPAdd.c b/SystemConfiguration.fproj/SCPAdd.c new file mode 100644 index 0000000..eaba463 --- /dev/null +++ b/SystemConfiguration.fproj/SCPAdd.c @@ -0,0 +1,50 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SCPApply.c b/SystemConfiguration.fproj/SCPApply.c new file mode 100644 index 0000000..8c42762 --- /dev/null +++ b/SystemConfiguration.fproj/SCPApply.c @@ -0,0 +1,89 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SCPClose.c b/SystemConfiguration.fproj/SCPClose.c new file mode 100644 index 0000000..8ad50cf --- /dev/null +++ b/SystemConfiguration.fproj/SCPClose.c @@ -0,0 +1,66 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SCPCommit.c b/SystemConfiguration.fproj/SCPCommit.c new file mode 100644 index 0000000..7ea5a5e --- /dev/null +++ b/SystemConfiguration.fproj/SCPCommit.c @@ -0,0 +1,173 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SCPGet.c b/SystemConfiguration.fproj/SCPGet.c new file mode 100644 index 0000000..bd0a50a --- /dev/null +++ b/SystemConfiguration.fproj/SCPGet.c @@ -0,0 +1,51 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SCPList.c b/SystemConfiguration.fproj/SCPList.c new file mode 100644 index 0000000..3fb1a89 --- /dev/null +++ b/SystemConfiguration.fproj/SCPList.c @@ -0,0 +1,70 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SCPLock.c b/SystemConfiguration.fproj/SCPLock.c new file mode 100644 index 0000000..760de8d --- /dev/null +++ b/SystemConfiguration.fproj/SCPLock.c @@ -0,0 +1,172 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SCPOpen.c b/SystemConfiguration.fproj/SCPOpen.c new file mode 100644 index 0000000..dd3e772 --- /dev/null +++ b/SystemConfiguration.fproj/SCPOpen.c @@ -0,0 +1,223 @@ +/* + * 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 +#include +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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); +} diff --git a/SystemConfiguration.fproj/SCPPath.c b/SystemConfiguration.fproj/SCPPath.c new file mode 100644 index 0000000..aee9cf8 --- /dev/null +++ b/SystemConfiguration.fproj/SCPPath.c @@ -0,0 +1,428 @@ +/* + * 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 +#include +#include "SCPPrivate.h" +#include +#include + +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 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 +#include + +/*! + @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. + + + key1 + val1 + key2 + val2 + path1 + + key3 + val3 + key4 + val4 + + + + 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 */ diff --git a/SystemConfiguration.fproj/SCPPrivate.h b/SystemConfiguration.fproj/SCPPrivate.h new file mode 100644 index 0000000..707279c --- /dev/null +++ b/SystemConfiguration.fproj/SCPPrivate.h @@ -0,0 +1,101 @@ +/* + * 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 +#include + +#include +#include +#include + + +#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 */ diff --git a/SystemConfiguration.fproj/SCPRemove.c b/SystemConfiguration.fproj/SCPRemove.c new file mode 100644 index 0000000..a861973 --- /dev/null +++ b/SystemConfiguration.fproj/SCPRemove.c @@ -0,0 +1,50 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SCPSet.c b/SystemConfiguration.fproj/SCPSet.c new file mode 100644 index 0000000..6b875ae --- /dev/null +++ b/SystemConfiguration.fproj/SCPSet.c @@ -0,0 +1,46 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SCPUnlock.c b/SystemConfiguration.fproj/SCPUnlock.c new file mode 100644 index 0000000..4d808a8 --- /dev/null +++ b/SystemConfiguration.fproj/SCPUnlock.c @@ -0,0 +1,63 @@ +/* + * 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 +#include "SCPPrivate.h" + +#include + +#include +#include +#include + + +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; +} diff --git a/SystemConfiguration.fproj/SystemConfiguration.h b/SystemConfiguration.fproj/SystemConfiguration.h new file mode 100644 index 0000000..9d4ef22 --- /dev/null +++ b/SystemConfiguration.fproj/SystemConfiguration.h @@ -0,0 +1,54 @@ +/* + * 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 +#include + +/* preference access APIs */ +#include +#include +#include + +/* "console user" APIs */ +#include + +/* "computer/host name" APIs */ +#include + +/* "network reachability" APIs */ +#include + +#endif /* _SYSTEMCONFIGURATION_H */ diff --git a/SystemConfiguration.fproj/config.defs b/SystemConfiguration.fproj/config.defs new file mode 100644 index 0000000..7449dea --- /dev/null +++ b/SystemConfiguration.fproj/config.defs @@ -0,0 +1,168 @@ +/* + * 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 +#include + +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); diff --git a/SystemConfiguration.fproj/config_types.h b/SystemConfiguration.fproj/config_types.h new file mode 100644 index 0000000..2351837 --- /dev/null +++ b/SystemConfiguration.fproj/config_types.h @@ -0,0 +1,50 @@ +/* + * 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 */ diff --git a/SystemConfiguration.fproj/genSCPreferences.c b/SystemConfiguration.fproj/genSCPreferences.c new file mode 100644 index 0000000..78bc8e4 --- /dev/null +++ b/SystemConfiguration.fproj/genSCPreferences.c @@ -0,0 +1,643 @@ +/* + * 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 +#include +#include +#include + +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 \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); +} + diff --git a/SystemConfiguration.fproj/h.template b/SystemConfiguration.fproj/h.template new file mode 100644 index 0000000..f3c1b04 --- /dev/null +++ b/SystemConfiguration.fproj/h.template @@ -0,0 +1,11 @@ +$$ +/* $FILENAME$ created by $USERNAME$ on $DATE$ */ + +#import + +@interface $FILENAMESANSEXTENSION$ : NSObject +{ + +} + +@end diff --git a/SystemConfiguration.fproj/m.template b/SystemConfiguration.fproj/m.template new file mode 100644 index 0000000..1216fe5 --- /dev/null +++ b/SystemConfiguration.fproj/m.template @@ -0,0 +1,18 @@ +$$ 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 diff --git a/SystemConfiguration.fproj/ppp.c b/SystemConfiguration.fproj/ppp.c new file mode 100644 index 0000000..2af5760 --- /dev/null +++ b/SystemConfiguration.fproj/ppp.c @@ -0,0 +1,341 @@ +/* + * 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 +//#include +//#include +#include +#include +#include +#include +#include +#include +#include + + +#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 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; +} diff --git a/SystemConfiguration.fproj/ppp.h b/SystemConfiguration.fproj/ppp.h new file mode 100644 index 0000000..8375d1b --- /dev/null +++ b/SystemConfiguration.fproj/ppp.h @@ -0,0 +1,69 @@ +/* + * 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 +#include +#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 */ diff --git a/SystemConfiguration.fproj/ppp_msg.h b/SystemConfiguration.fproj/ppp_msg.h new file mode 100644 index 0000000..4a3c6da --- /dev/null +++ b/SystemConfiguration.fproj/ppp_msg.h @@ -0,0 +1,242 @@ +/* + * 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 + + +/* 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 */ + diff --git a/configd.tproj/Makefile b/configd.tproj/Makefile new file mode 100644 index 0000000..d9c7c6f --- /dev/null +++ b/configd.tproj/Makefile @@ -0,0 +1,60 @@ +# +# 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 diff --git a/configd.tproj/Makefile.postamble b/configd.tproj/Makefile.postamble new file mode 100644 index 0000000..ce9e54f --- /dev/null +++ b/configd.tproj/Makefile.postamble @@ -0,0 +1,101 @@ +############################################################################### +# 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. +# + diff --git a/configd.tproj/Makefile.preamble b/configd.tproj/Makefile.preamble new file mode 100644 index 0000000..b5e7557 --- /dev/null +++ b/configd.tproj/Makefile.preamble @@ -0,0 +1,141 @@ +############################################################################### +# 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: <> +# 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 + diff --git a/configd.tproj/PB.project b/configd.tproj/PB.project new file mode 100644 index 0000000..9174d1f --- /dev/null +++ b/configd.tproj/PB.project @@ -0,0 +1,75 @@ +{ + 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"; +} diff --git a/configd.tproj/_SCD.c b/configd.tproj/_SCD.c new file mode 100644 index 0000000..c89dd8c --- /dev/null +++ b/configd.tproj/_SCD.c @@ -0,0 +1,532 @@ +/* + * 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 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 + + +/* + * 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 */ diff --git a/configd.tproj/_configadd.c b/configd.tproj/_configadd.c new file mode 100644 index 0000000..76a9dfb --- /dev/null +++ b/configd.tproj/_configadd.c @@ -0,0 +1,161 @@ +/* + * 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; +} diff --git a/configd.tproj/_configadd_s.c b/configd.tproj/_configadd_s.c new file mode 100644 index 0000000..8e54070 --- /dev/null +++ b/configd.tproj/_configadd_s.c @@ -0,0 +1,173 @@ +/* + * 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; +} diff --git a/configd.tproj/_configclose.c b/configd.tproj/_configclose.c new file mode 100644 index 0000000..afba5bb --- /dev/null +++ b/configd.tproj/_configclose.c @@ -0,0 +1,203 @@ +/* + * 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 + +#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; ireKeys)) > 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; iserver); + 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; iserver); + 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; +} diff --git a/configd.tproj/_configget.c b/configd.tproj/_configget.c new file mode 100644 index 0000000..7b1e64d --- /dev/null +++ b/configd.tproj/_configget.c @@ -0,0 +1,139 @@ +/* + * 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; +} diff --git a/configd.tproj/_configlist.c b/configd.tproj/_configlist.c new file mode 100644 index 0000000..85286c3 --- /dev/null +++ b/configd.tproj/_configlist.c @@ -0,0 +1,227 @@ +/* + * 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; isession, 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; +} diff --git a/configd.tproj/_configlock.c b/configd.tproj/_configlock.c new file mode 100644 index 0000000..ec6b9b1 --- /dev/null +++ b/configd.tproj/_configlock.c @@ -0,0 +1,97 @@ +/* + * 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; +} diff --git a/configd.tproj/_configopen.c b/configd.tproj/_configopen.c new file mode 100644 index 0000000..62b1238 --- /dev/null +++ b/configd.tproj/_configopen.c @@ -0,0 +1,189 @@ +/* + * 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; +} diff --git a/configd.tproj/_configremove.c b/configd.tproj/_configremove.c new file mode 100644 index 0000000..77c5fa9 --- /dev/null +++ b/configd.tproj/_configremove.c @@ -0,0 +1,162 @@ +/* + * 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; +} + diff --git a/configd.tproj/_configset.c b/configd.tproj/_configset.c new file mode 100644 index 0000000..efa671c --- /dev/null +++ b/configd.tproj/_configset.c @@ -0,0 +1,246 @@ +/* + * 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; +} diff --git a/configd.tproj/_configtouch.c b/configd.tproj/_configtouch.c new file mode 100644 index 0000000..318e6db --- /dev/null +++ b/configd.tproj/_configtouch.c @@ -0,0 +1,139 @@ +/* + * 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; +} diff --git a/configd.tproj/_configunlock.c b/configd.tproj/_configunlock.c new file mode 100644 index 0000000..421eee6 --- /dev/null +++ b/configd.tproj/_configunlock.c @@ -0,0 +1,296 @@ +/* + * 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; +} diff --git a/configd.tproj/_notifyadd.c b/configd.tproj/_notifyadd.c new file mode 100644 index 0000000..5ca354a --- /dev/null +++ b/configd.tproj/_notifyadd.c @@ -0,0 +1,212 @@ +/* + * 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; +} diff --git a/configd.tproj/_notifycancel.c b/configd.tproj/_notifycancel.c new file mode 100644 index 0000000..5a77701 --- /dev/null +++ b/configd.tproj/_notifycancel.c @@ -0,0 +1,102 @@ +/* + * 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 + +#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; +} diff --git a/configd.tproj/_notifychanges.c b/configd.tproj/_notifychanges.c new file mode 100644 index 0000000..19ad363 --- /dev/null +++ b/configd.tproj/_notifychanges.c @@ -0,0 +1,109 @@ +/* + * 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; +} diff --git a/configd.tproj/_notifyremove.c b/configd.tproj/_notifyremove.c new file mode 100644 index 0000000..e16f2a2 --- /dev/null +++ b/configd.tproj/_notifyremove.c @@ -0,0 +1,168 @@ +/* + * 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; +} + diff --git a/configd.tproj/_notifyviafd.c b/configd.tproj/_notifyviafd.c new file mode 100644 index 0000000..7eedbfc --- /dev/null +++ b/configd.tproj/_notifyviafd.c @@ -0,0 +1,168 @@ +/* + * 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 +#include +#include +#include +#include + +#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; +} diff --git a/configd.tproj/_notifyviaport.c b/configd.tproj/_notifyviaport.c new file mode 100644 index 0000000..ac270ec --- /dev/null +++ b/configd.tproj/_notifyviaport.c @@ -0,0 +1,100 @@ +/* + * 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; +} diff --git a/configd.tproj/_notifyviasignal.c b/configd.tproj/_notifyviasignal.c new file mode 100644 index 0000000..fc10d1b --- /dev/null +++ b/configd.tproj/_notifyviasignal.c @@ -0,0 +1,158 @@ +/* + * 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; +} diff --git a/configd.tproj/_snapshot.c b/configd.tproj/_snapshot.c new file mode 100644 index 0000000..b21d96a --- /dev/null +++ b/configd.tproj/_snapshot.c @@ -0,0 +1,89 @@ +/* + * 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 +#include +#include + +#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; +} diff --git a/configd.tproj/config.defs b/configd.tproj/config.defs new file mode 100644 index 0000000..cc2513a --- /dev/null +++ b/configd.tproj/config.defs @@ -0,0 +1,18 @@ +/* + * 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 diff --git a/configd.tproj/configd.h b/configd.tproj/configd.h new file mode 100644 index 0000000..05ffe70 --- /dev/null +++ b/configd.tproj/configd.h @@ -0,0 +1,41 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include "config_types.h" +#include "SCDPrivate.h" +#include "_SCD.h" + + +__BEGIN_DECLS +__END_DECLS + +#endif /* !_S_CONFIGD_H */ diff --git a/configd.tproj/configd.m b/configd.tproj/configd.m new file mode 100644 index 0000000..dad2d5a --- /dev/null +++ b/configd.tproj/configd.m @@ -0,0 +1,257 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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. +} diff --git a/configd.tproj/configd_server.c b/configd.tproj/configd_server.c new file mode 100644 index 0000000..69a1911 --- /dev/null +++ b/configd.tproj/configd_server.c @@ -0,0 +1,315 @@ +/* + * 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 +#include + +#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(); + } +} diff --git a/configd.tproj/configd_server.h b/configd.tproj/configd_server.h new file mode 100644 index 0000000..bc5708c --- /dev/null +++ b/configd.tproj/configd_server.h @@ -0,0 +1,149 @@ +/* + * 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 +#include + +#include +#include + +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 */ diff --git a/configd.tproj/h.template b/configd.tproj/h.template new file mode 100644 index 0000000..f3c1b04 --- /dev/null +++ b/configd.tproj/h.template @@ -0,0 +1,11 @@ +$$ +/* $FILENAME$ created by $USERNAME$ on $DATE$ */ + +#import + +@interface $FILENAMESANSEXTENSION$ : NSObject +{ + +} + +@end diff --git a/configd.tproj/m.template b/configd.tproj/m.template new file mode 100644 index 0000000..1216fe5 --- /dev/null +++ b/configd.tproj/m.template @@ -0,0 +1,18 @@ +$$ 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 diff --git a/configd.tproj/notify.c b/configd.tproj/notify.c new file mode 100644 index 0000000..b87dd9e --- /dev/null +++ b/configd.tproj/notify.c @@ -0,0 +1,161 @@ +/* + * 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 + +#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; +} diff --git a/configd.tproj/notify.h b/configd.tproj/notify.h new file mode 100644 index 0000000..cd1f018 --- /dev/null +++ b/configd.tproj/notify.h @@ -0,0 +1,34 @@ +/* + * 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 + +__BEGIN_DECLS + +void pushNotifications __P(()); + +__END_DECLS + +#endif /* !_S_NOTIFY_H */ diff --git a/configd.tproj/notify_server.c b/configd.tproj/notify_server.c new file mode 100644 index 0000000..c043d43 --- /dev/null +++ b/configd.tproj/notify_server.c @@ -0,0 +1,64 @@ +/* + * 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; +} diff --git a/configd.tproj/notify_server.h b/configd.tproj/notify_server.h new file mode 100644 index 0000000..170d718 --- /dev/null +++ b/configd.tproj/notify_server.h @@ -0,0 +1,35 @@ +/* + * 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 +#include + +__BEGIN_DECLS + +boolean_t notify_server __P((mach_msg_header_t *request, mach_msg_header_t *reply)); + +__END_DECLS + +#endif /* !_S_NOTIFY_SERVER_H */ diff --git a/configd.tproj/plugin_support.c b/configd.tproj/plugin_support.c new file mode 100644 index 0000000..fd6e3c8 --- /dev/null +++ b/configd.tproj/plugin_support.c @@ -0,0 +1,568 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#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; +} diff --git a/configd.tproj/plugin_support.h b/configd.tproj/plugin_support.h new file mode 100644 index 0000000..072e3c1 --- /dev/null +++ b/configd.tproj/plugin_support.h @@ -0,0 +1,35 @@ +/* + * 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 + +__BEGIN_DECLS + +void plugin_init __P(()); +void plugin_exec __P((void *arg)); + +__END_DECLS + +#endif /* !_S_PLUGIN_SUPPORT_H */ diff --git a/configd.tproj/session.c b/configd.tproj/session.c new file mode 100644 index 0000000..88577cd --- /dev/null +++ b/configd.tproj/session.c @@ -0,0 +1,208 @@ +/* + * 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; ikey == 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; ikey = 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; ikey == 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; ikey == 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; ikey); + + if (thisSession->session != NULL) { + task_t task = ((SCDSessionPrivateRef)thisSession->session)->notifySignalTask; + + if (task != TASK_NULL) { + fprintf(stderr, "/%d", task); + } + } + } + fprintf(stderr, "\n"); +} + diff --git a/configd.tproj/session.h b/configd.tproj/session.h new file mode 100644 index 0000000..9d431de --- /dev/null +++ b/configd.tproj/session.h @@ -0,0 +1,61 @@ +/* + * 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 + +/* 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 */ diff --git a/scselect.tproj/Makefile b/scselect.tproj/Makefile new file mode 100644 index 0000000..64e8cfc --- /dev/null +++ b/scselect.tproj/Makefile @@ -0,0 +1,50 @@ +# +# 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 diff --git a/scselect.tproj/Makefile.postamble b/scselect.tproj/Makefile.postamble new file mode 100644 index 0000000..e6f3e09 --- /dev/null +++ b/scselect.tproj/Makefile.postamble @@ -0,0 +1,100 @@ +############################################################################### +# 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. +# diff --git a/scselect.tproj/Makefile.preamble b/scselect.tproj/Makefile.preamble new file mode 100644 index 0000000..13efa5f --- /dev/null +++ b/scselect.tproj/Makefile.preamble @@ -0,0 +1,137 @@ +############################################################################### +# 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: <> +# 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) diff --git a/scselect.tproj/PB.project b/scselect.tproj/PB.project new file mode 100644 index 0000000..5e4c7da --- /dev/null +++ b/scselect.tproj/PB.project @@ -0,0 +1,30 @@ +{ + 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"; +} diff --git a/scselect.tproj/h.template b/scselect.tproj/h.template new file mode 100644 index 0000000..f3c1b04 --- /dev/null +++ b/scselect.tproj/h.template @@ -0,0 +1,11 @@ +$$ +/* $FILENAME$ created by $USERNAME$ on $DATE$ */ + +#import + +@interface $FILENAMESANSEXTENSION$ : NSObject +{ + +} + +@end diff --git a/scselect.tproj/m.template b/scselect.tproj/m.template new file mode 100644 index 0000000..1216fe5 --- /dev/null +++ b/scselect.tproj/m.template @@ -0,0 +1,18 @@ +$$ 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 diff --git a/scselect.tproj/scselect.c b/scselect.tproj/scselect.c new file mode 100644 index 0000000..b889b4f --- /dev/null +++ b/scselect.tproj/scselect.c @@ -0,0 +1,258 @@ +/* + * 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 +#include + + +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= 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 0) ? " (* == current set)" : ""); + + for (i=0; i 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; +} diff --git a/scutil.tproj/Makefile b/scutil.tproj/Makefile new file mode 100644 index 0000000..c23c5f1 --- /dev/null +++ b/scutil.tproj/Makefile @@ -0,0 +1,54 @@ +# +# 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 diff --git a/scutil.tproj/Makefile.postamble b/scutil.tproj/Makefile.postamble new file mode 100644 index 0000000..b3af842 --- /dev/null +++ b/scutil.tproj/Makefile.postamble @@ -0,0 +1,100 @@ +############################################################################### +# 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. +# diff --git a/scutil.tproj/Makefile.preamble b/scutil.tproj/Makefile.preamble new file mode 100644 index 0000000..b9f5238 --- /dev/null +++ b/scutil.tproj/Makefile.preamble @@ -0,0 +1,137 @@ +############################################################################### +# 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: <> +# 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) diff --git a/scutil.tproj/PB.project b/scutil.tproj/PB.project new file mode 100644 index 0000000..c1ceca4 --- /dev/null +++ b/scutil.tproj/PB.project @@ -0,0 +1,28 @@ +{ + 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"; +} diff --git a/scutil.tproj/cache.c b/scutil.tproj/cache.c new file mode 100644 index 0000000..759959b --- /dev/null +++ b/scutil.tproj/cache.c @@ -0,0 +1,162 @@ +/* + * 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 + +#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 + +__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 */ diff --git a/scutil.tproj/commands.c b/scutil.tproj/commands.c new file mode 100644 index 0000000..501b23f --- /dev/null +++ b/scutil.tproj/commands.c @@ -0,0 +1,242 @@ +/* + * 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 +#include +#include + +#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 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 + +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 */ diff --git a/scutil.tproj/dictionary.c b/scutil.tproj/dictionary.c new file mode 100644 index 0000000..35371d4 --- /dev/null +++ b/scutil.tproj/dictionary.c @@ -0,0 +1,205 @@ +/* + * 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 +//#include + + +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; +} diff --git a/scutil.tproj/dictionary.h b/scutil.tproj/dictionary.h new file mode 100644 index 0000000..8ea9cfe --- /dev/null +++ b/scutil.tproj/dictionary.h @@ -0,0 +1,37 @@ +/* + * 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 + +__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 */ diff --git a/scutil.tproj/h.template b/scutil.tproj/h.template new file mode 100644 index 0000000..f3c1b04 --- /dev/null +++ b/scutil.tproj/h.template @@ -0,0 +1,11 @@ +$$ +/* $FILENAME$ created by $USERNAME$ on $DATE$ */ + +#import + +@interface $FILENAMESANSEXTENSION$ : NSObject +{ + +} + +@end diff --git a/scutil.tproj/m.template b/scutil.tproj/m.template new file mode 100644 index 0000000..1216fe5 --- /dev/null +++ b/scutil.tproj/m.template @@ -0,0 +1,18 @@ +$$ 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 diff --git a/scutil.tproj/notify.c b/scutil.tproj/notify.c new file mode 100644 index 0000000..b19df55 --- /dev/null +++ b/scutil.tproj/notify.c @@ -0,0 +1,352 @@ +/* + * 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 +#include +#include +#include + +#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 0) { + for (i=0; i 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) { + printf("Signal must be one of the following:"); + for (sig=1; sig + +__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 */ diff --git a/scutil.tproj/scutil.c b/scutil.tproj/scutil.c new file mode 100644 index 0000000..b46c128 --- /dev/null +++ b/scutil.tproj/scutil.c @@ -0,0 +1,293 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#ifdef DEBUG +#include +#include +#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. +} diff --git a/scutil.tproj/scutil.h b/scutil.tproj/scutil.h new file mode 100644 index 0000000..b1d13dd --- /dev/null +++ b/scutil.tproj/scutil.h @@ -0,0 +1,47 @@ +/* + * 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 + +#include + +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 */ diff --git a/scutil.tproj/session.c b/scutil.tproj/session.c new file mode 100644 index 0000000..7a8287e --- /dev/null +++ b/scutil.tproj/session.c @@ -0,0 +1,92 @@ +/* + * 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; +} diff --git a/scutil.tproj/session.h b/scutil.tproj/session.h new file mode 100644 index 0000000..8a3f8bb --- /dev/null +++ b/scutil.tproj/session.h @@ -0,0 +1,37 @@ +/* + * 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 + +__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 */ diff --git a/scutil.tproj/tests.c b/scutil.tproj/tests.c new file mode 100644 index 0000000..703ef5f --- /dev/null +++ b/scutil.tproj/tests.c @@ -0,0 +1,87 @@ +/* + * 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 + +__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 */ -- 2.47.2