From 61bbf21f075441982f18160da83c6c1c5218b791 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Tue, 13 Feb 2007 20:55:17 +0000 Subject: r21322: No feedback means consent :-) It does not matter if I screw up 3.0.25 or 3.0.26 with this, so do it rather sooner than later. Add the notify support that already exists in 3_0 to 3_0_25. If you want to see this patch dissected into digestable parts, look at 3_0, revisions at about 20800 and following. Volker --- source/Makefile.in | 9 +- source/configure.in | 56 +-- source/include/event.h | 12 +- source/include/includes.h | 1 + source/include/messages.h | 4 + source/include/nt_status.h | 5 + source/include/smb.h | 108 ++++-- source/include/vfs.h | 12 +- source/include/vfs_macros.h | 3 + source/lib/debug.c | 8 +- source/lib/dmallocmsg.c | 14 +- source/lib/events.c | 223 +++++++++-- source/lib/messages.c | 245 ++++++++++-- source/lib/tallocmsg.c | 5 +- source/lib/util.c | 13 + source/lib/util_tdb.c | 98 +++++ source/librpc/gen_ndr/ndr_notify.c | 242 ++++++++++++ source/librpc/gen_ndr/ndr_notify.h | 20 + source/librpc/gen_ndr/notify.h | 33 ++ source/libsmb/clidgram.c | 5 +- source/nmbd/nmbd.c | 18 +- source/nmbd/nmbd_elections.c | 2 +- source/nmbd/nmbd_winsserver.c | 2 +- source/nsswitch/winbindd.c | 33 +- source/nsswitch/winbindd_cm.c | 35 +- source/nsswitch/winbindd_cred_cache.c | 16 +- source/nsswitch/winbindd_dual.c | 41 +- source/param/loadparm.c | 20 +- source/printing/nt_printing.c | 5 +- source/printing/printing.c | 6 +- source/rpc_server/srv_spoolss_nt.c | 11 +- source/rpc_server/srv_srvsvc_nt.c | 2 +- source/smbd/blocking.c | 18 +- source/smbd/close.c | 5 - source/smbd/conn.c | 3 +- source/smbd/dosmode.c | 10 +- source/smbd/files.c | 5 + source/smbd/notify.c | 522 ++++++++++++++++++-------- source/smbd/notify_fam.c | 464 ----------------------- source/smbd/notify_hash.c | 261 ------------- source/smbd/notify_inotify.c | 425 +++++++++++++++++++++ source/smbd/notify_internal.c | 686 ++++++++++++++++++++++++++++++++++ source/smbd/notify_kernel.c | 247 ------------ source/smbd/nttrans.c | 78 +++- source/smbd/open.c | 50 ++- source/smbd/oplock.c | 35 +- source/smbd/process.c | 90 ++--- source/smbd/reply.c | 75 +++- source/smbd/server.c | 55 ++- source/smbd/service.c | 35 +- source/smbd/trans2.c | 14 +- source/smbd/vfs.c | 32 +- source/torture/msgtest.c | 17 +- source/torture/vfstest.c | 21 ++ source/utils/net_ads.c | 2 +- source/utils/smbcontrol.c | 28 +- 56 files changed, 2941 insertions(+), 1544 deletions(-) create mode 100644 source/librpc/gen_ndr/ndr_notify.c create mode 100644 source/librpc/gen_ndr/ndr_notify.h create mode 100644 source/librpc/gen_ndr/notify.h delete mode 100644 source/smbd/notify_fam.c delete mode 100644 source/smbd/notify_hash.c create mode 100644 source/smbd/notify_inotify.c create mode 100644 source/smbd/notify_internal.c delete mode 100644 source/smbd/notify_kernel.c diff --git a/source/Makefile.in b/source/Makefile.in index 13719571409..833af9647f7 100644 --- a/source/Makefile.in +++ b/source/Makefile.in @@ -215,7 +215,7 @@ LIBNDR_OBJ = librpc/ndr/ndr_basic.o librpc/ndr/ndr.o librpc/ndr/ndr_misc.o \ librpc/ndr/ndr_sec_helper.o librpc/ndr/ndr_string.o librpc/ndr/sid.o \ rpc_client/ndr.o -LIBNDR_GEN_OBJ = librpc/gen_ndr/ndr_wkssvc.o +LIBNDR_GEN_OBJ = librpc/gen_ndr/ndr_wkssvc.o librpc/gen_ndr/ndr_notify.o RPC_PARSE_OBJ0 = rpc_parse/parse_prs.o rpc_parse/parse_misc.o @@ -398,7 +398,7 @@ PROFILES_OBJ = utils/profiles.o \ OPLOCK_OBJ = smbd/oplock.o smbd/oplock_irix.o smbd/oplock_linux.o -NOTIFY_OBJ = smbd/notify.o smbd/notify_hash.o smbd/notify_kernel.o smbd/notify_fam.o +NOTIFY_OBJ = smbd/notify.o smbd/notify_inotify.o smbd/notify_internal.o VFS_DEFAULT_OBJ = modules/vfs_default.o VFS_AUDIT_OBJ = modules/vfs_audit.o @@ -425,6 +425,7 @@ VFS_CACHEPRIME_OBJ = modules/vfs_cacheprime.o VFS_PREALLOC_OBJ = modules/vfs_prealloc.o VFS_COMMIT_OBJ = modules/vfs_commit.o VFS_GPFS_OBJ = modules/vfs_gpfs.o modules/gpfs.o modules/nfs4_acls.o +VFS_NOTIFY_FAM_OBJ = modules/vfs_notify_fam.o PLAINTEXT_AUTH_OBJ = auth/pampass.o auth/pass_check.o @@ -1533,6 +1534,10 @@ bin/gpfs.@SHLIBEXT@: $(VFS_GPFS_OBJ) @$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_GPFS_OBJ) \ @SONAMEFLAG@`basename $@` +bin/notify_fam.@SHLIBEXT@: $(VFS_NOTIFY_FAM_OBJ) + @echo "Building plugin $@" + @$(SHLD) $(LDSHFLAGS) -o $@ $(VFS_NOTIFY_FAM_OBJ) \ + @SONAMEFLAG@`basename $@` ######################################################### ## IdMap NSS plugins diff --git a/source/configure.in b/source/configure.in index db64eaa105e..30f4bbfb535 100644 --- a/source/configure.in +++ b/source/configure.in @@ -2509,6 +2509,19 @@ if test x"$samba_cv_HAVE_KERNEL_CHANGE_NOTIFY" = x"yes"; then AC_DEFINE(HAVE_KERNEL_CHANGE_NOTIFY,1,[Whether kernel notifies changes]) fi +AC_CACHE_CHECK([for inotify support],samba_cv_HAVE_INOTIFY,[ +AC_CHECK_HEADERS(linux/inotify.h asm/unistd.h) +AC_CHECK_FUNC(inotify_init) +AC_HAVE_DECL(__NR_inotify_init, [#include ]) +], +samba_cv_HAVE_INOTIFY=yes, +samba_cv_HAVE_INOTIFY=no, +samba_cv_HAVE_INOTIFY=cross) + +if test x"$ac_cv_func_inotify_init" = x"yes" -a x"$ac_cv_header_linux_inotify_h" = x"yes"; then + AC_DEFINE(HAVE_INOTIFY,1,[Whether kernel has inotify support]) +fi + ################################################# # Check if FAM notifications are available. For FAM info, see # http://oss.sgi.com/projects/fam/ @@ -2517,32 +2530,31 @@ AC_ARG_ENABLE(fam, [ --enable-fam Turn on FAM support (default=auto)]) if test x$enable_fam != xno; then -AC_CHECK_HEADERS(fam.h, [samba_cv_HAVE_FAM_H=yes], [samba_cv_HAVE_FAM_H=no]) -if test x"$samba_cv_HAVE_FAM_H" = x"yes"; then + AC_CHECK_HEADERS(fam.h, [samba_cv_HAVE_FAM_H=yes], [samba_cv_HAVE_FAM_H=no]) + if test x"$samba_cv_HAVE_FAM_H" = x"yes"; then # On IRIX, libfam requires libC, but other FAM implementations # might not need it. - AC_CHECK_LIB(fam, FAMOpen2, - [samba_cv_HAVE_LIBFAM=yes; samba_fam_libs="-lfam"], - [samba_cv_HAVE_LIBFAM=no]) - - if test x"$samba_cv_HAVE_LIBFAM" = x"no" ; then - samba_fam_xtra=-lC - AC_CHECK_LIB_EXT(fam, samba_fam_xtra, FAMOpen2, - [samba_cv_HAVE_LIBFAM=yes; samba_fam_libs="-lfam -lC"], - [samba_cv_HAVE_LIBFAM=no]) - unset samba_fam_xtra + AC_CHECK_LIB(fam, FAMOpen2, + [samba_cv_HAVE_LIBFAM=yes; samba_fam_libs="-lfam"], + [samba_cv_HAVE_LIBFAM=no]) + + if test x"$samba_cv_HAVE_LIBFAM" = x"no" ; then + samba_fam_xtra=-lC + AC_CHECK_LIB_EXT(fam, samba_fam_xtra, FAMOpen2, + [samba_cv_HAVE_LIBFAM=yes; samba_fam_libs="-lfam -lC"], + [samba_cv_HAVE_LIBFAM=no]) + unset samba_fam_xtra + fi fi -fi -if test x"$samba_cv_HAVE_LIBFAM" = x"yes" ; then - AC_DEFINE(HAVE_FAM_CHANGE_NOTIFY, 1, - [Whether FAM file notifications are available]) - AC_TRY_COMPILE([#include ], - [FAMCodes code = FAMChanged;], - AC_DEFINE(HAVE_FAM_H_FAMCODES_TYPEDEF, 1, - [Whether fam.h contains a typedef for enum FAMCodes]), - []) -fi + if test x"$samba_cv_HAVE_LIBFAM" = x"yes" ; then + default_shared_modules="$default_shared_modules vfs_notify_fam" + AC_TRY_COMPILE([#include ], + [FAMCodes code = FAMChanged;], + AC_DEFINE(HAVE_FAM_H_FAMCODES_TYPEDEF, 1, + [Whether fam.h contains a typedef for enum FAMCodes]), + []) + fi if test x$enable_fam = xyes && test x"$samba_cv_HAVE_LIBFAM" != xyes ; then AC_MSG_ERROR(FAM support requested but FAM library not available ) diff --git a/source/include/event.h b/source/include/event.h index fdb990678db..ce687eca6d6 100644 --- a/source/include/event.h +++ b/source/include/event.h @@ -19,13 +19,7 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -struct timed_event { - struct timed_event *next, *prev; - struct timeval when; - const char *event_name; - void (*handler)(struct timed_event *te, - const struct timeval *now, - void *private_data); - void *private_data; -}; +/* bits for file descriptor event flags */ +#define EVENT_FD_READ 1 +#define EVENT_FD_WRITE 2 diff --git a/source/include/includes.h b/source/include/includes.h index 7a6064d8264..34b9c36c8ac 100644 --- a/source/include/includes.h +++ b/source/include/includes.h @@ -684,6 +684,7 @@ typedef int BOOL; #include "rpc_shutdown.h" #include "rpc_perfcount.h" #include "rpc_perfcount_defs.h" +#include "librpc/gen_ndr/notify.h" #include "nt_printing.h" #include "idmap.h" #include "client.h" diff --git a/source/include/messages.h b/source/include/messages.h index ead5fb08c29..7cd0e023487 100644 --- a/source/include/messages.h +++ b/source/include/messages.h @@ -73,6 +73,10 @@ #define MSG_SMB_BLOCKING_LOCK_CANCEL 3013 #define MSG_SMB_NOTIFY 3014 #define MSG_SMB_STAT_CACHE_DELETE 3015 +/* + * Samba4 compatibility + */ +#define MSG_PVFS_NOTIFY 3016 /* winbind messages */ #define MSG_WINBIND_FINISHED 4001 diff --git a/source/include/nt_status.h b/source/include/nt_status.h index 968657ca44f..471ac47927a 100644 --- a/source/include/nt_status.h +++ b/source/include/nt_status.h @@ -66,6 +66,11 @@ typedef uint32 WERROR; }\ } while (0) +#define NT_STATUS_NOT_OK_RETURN(x) do { \ + if (!NT_STATUS_IS_OK(x)) {\ + return x;\ + }\ +} while (0) /* The top byte in an NTSTATUS code is used as a type field. * Windows only uses value 0xC0 as an indicator for an NT error diff --git a/source/include/smb.h b/source/include/smb.h index 9b914f6c7f9..8fa7dee5494 100644 --- a/source/include/smb.h +++ b/source/include/smb.h @@ -426,6 +426,9 @@ struct fd_handle { unsigned long file_id; }; +struct messaging_context; +struct event_context; +struct fd_event; struct timed_event; struct idle_event; struct share_mode_entry; @@ -439,6 +442,45 @@ struct vfs_fsp_data { */ }; +/* the basic packet size, assuming no words or bytes */ +#define smb_size 39 + +struct notify_change { + uint32_t action; + const char *name; +}; + +struct notify_mid_map; +struct notify_entry; +struct notify_event; +struct notify_change_request; +struct sys_notify_backend; +struct sys_notify_context { + struct event_context *ev; + struct connection_struct *conn; + void *private_data; /* For use by the system backend */ +}; + +struct notify_change_buf { + /* + * If no requests are pending, changes are queued here. Simple array, + * we only append. + */ + + /* + * num_changes == -1 means that we have got a catch-all change, when + * asked we just return NT_STATUS_OK without specific changes. + */ + int num_changes; + struct notify_change *changes; + + /* + * If no changes are around requests are queued here. Using a linked + * list, because we have to append at the end and delete from the top. + */ + struct notify_change_request *requests; +}; + typedef struct files_struct { struct files_struct *next, *prev; int fnum; @@ -483,6 +525,8 @@ typedef struct files_struct { struct vfs_fsp_data *vfs_extension; FAKE_FILE_HANDLE *fake_file_handle; + + struct notify_change_buf *notify; } files_struct; #include "ntquotas.h" @@ -627,6 +671,7 @@ typedef struct connection_struct { name_compare_entry *aio_write_behind_list; /* Per-share list of files to use aio write behind on. */ struct dfree_cached_info *dfree_info; struct trans_state *pending_trans; + struct notify_context *notify_ctx; } connection_struct; struct current_user { @@ -896,9 +941,6 @@ struct bitmap { unsigned int n; }; -/* the basic packet size, assuming no words or bytes */ -#define smb_size 39 - /* offsets into message for common items */ #define smb_com 8 #define smb_rcls 9 @@ -1259,22 +1301,19 @@ struct bitmap { #define FILE_SHARE_DELETE 4 /* FileAttributesField */ -#define FILE_ATTRIBUTE_READONLY 0x0001 -#define FILE_ATTRIBUTE_HIDDEN 0x0002 -#define FILE_ATTRIBUTE_SYSTEM 0x0004 -#define FILE_ATTRIBUTE_VOLUME 0x0008 -#define FILE_ATTRIBUTE_DIRECTORY 0x0010 -#define FILE_ATTRIBUTE_ARCHIVE 0x0020 -#define FILE_ATTRIBUTE_DEVICE 0x0040 -#define FILE_ATTRIBUTE_NORMAL 0x0080 -#define FILE_ATTRIBUTE_TEMPORARY 0x0100 -#define FILE_ATTRIBUTE_SPARSE 0x0200 -#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400 -#define FILE_ATTRIBUTE_COMPRESSED 0x0800 -#define FILE_ATTRIBUTE_OFFLINE 0x1000 -#define FILE_ATTRIBUTE_NONINDEXED 0x2000 -#define FILE_ATTRIBUTE_ENCRYPTED 0x4000 - +#define FILE_ATTRIBUTE_READONLY 0x001L +#define FILE_ATTRIBUTE_HIDDEN 0x002L +#define FILE_ATTRIBUTE_SYSTEM 0x004L +#define FILE_ATTRIBUTE_DIRECTORY 0x010L +#define FILE_ATTRIBUTE_ARCHIVE 0x020L +#define FILE_ATTRIBUTE_NORMAL 0x080L +#define FILE_ATTRIBUTE_TEMPORARY 0x100L +#define FILE_ATTRIBUTE_SPARSE 0x200L +#define FILE_ATTRIBUTE_REPARSE_POINT 0x400L +#define FILE_ATTRIBUTE_COMPRESSED 0x800L +#define FILE_ATTRIBUTE_OFFLINE 0x1000L +#define FILE_ATTRIBUTE_NONINDEXED 0x2000L +#define FILE_ATTRIBUTE_ENCRYPTED 0x4000L #define SAMBA_ATTRIBUTES_MASK 0x7F /* Flags - combined with attributes. */ @@ -1352,7 +1391,7 @@ struct bitmap { #define FILE_READ_ONLY_VOLUME 0x00080000 /* ChangeNotify flags. */ -#define FILE_NOTIFY_CHANGE_FILE 0x001 +#define FILE_NOTIFY_CHANGE_FILE_NAME 0x001 #define FILE_NOTIFY_CHANGE_DIR_NAME 0x002 #define FILE_NOTIFY_CHANGE_ATTRIBUTES 0x004 #define FILE_NOTIFY_CHANGE_SIZE 0x008 @@ -1361,7 +1400,23 @@ struct bitmap { #define FILE_NOTIFY_CHANGE_CREATION 0x040 #define FILE_NOTIFY_CHANGE_EA 0x080 #define FILE_NOTIFY_CHANGE_SECURITY 0x100 -#define FILE_NOTIFY_CHANGE_FILE_NAME 0x200 +#define FILE_NOTIFY_CHANGE_STREAM_NAME 0x00000200 +#define FILE_NOTIFY_CHANGE_STREAM_SIZE 0x00000400 +#define FILE_NOTIFY_CHANGE_STREAM_WRITE 0x00000800 + +#define FILE_NOTIFY_CHANGE_NAME \ + (FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_DIR_NAME) + +/* change notify action results */ +#define NOTIFY_ACTION_ADDED 1 +#define NOTIFY_ACTION_REMOVED 2 +#define NOTIFY_ACTION_MODIFIED 3 +#define NOTIFY_ACTION_OLD_NAME 4 +#define NOTIFY_ACTION_NEW_NAME 5 +#define NOTIFY_ACTION_ADDED_STREAM 6 +#define NOTIFY_ACTION_REMOVED_STREAM 7 +#define NOTIFY_ACTION_MODIFIED_STREAM 8 + /* where to find the base of the SMB packet proper */ #define smb_base(buf) (((char *)(buf))+4) @@ -1638,17 +1693,6 @@ struct kernel_oplocks { int notification_fd; }; - -/* this structure defines the functions for doing change notify in - various implementations */ -struct cnotify_fns { - void * (*register_notify)(connection_struct *conn, char *path, uint32 flags); - BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t); - void (*remove_notify)(void *data); - int select_time; - int notification_fd; -}; - #include "smb_macros.h" #define MAX_NETBIOSNAME_LEN 16 diff --git a/source/include/vfs.h b/source/include/vfs.h index fe4886567ff..de92c739d59 100644 --- a/source/include/vfs.h +++ b/source/include/vfs.h @@ -65,7 +65,8 @@ /* Changed to version 17 as we removed redundant connection_struct parameters. --jpeach */ /* Changed to version 18 to add fsp parameter to the open call -- jpeach Also include kernel_flock call - jmcd */ -#define SMB_VFS_INTERFACE_VERSION 18 +/* Changed to version 19, kernel change notify has been merged */ +#define SMB_VFS_INTERFACE_VERSION 19 /* to bug old modules which are trying to compile with the old functions */ @@ -152,6 +153,7 @@ typedef enum _vfs_op_type { SMB_VFS_OP_LINK, SMB_VFS_OP_MKNOD, SMB_VFS_OP_REALPATH, + SMB_VFS_OP_NOTIFY_WATCH, /* NT ACL operations. */ @@ -275,6 +277,13 @@ struct vfs_ops { int (*link)(struct vfs_handle_struct *handle, const char *oldpath, const char *newpath); int (*mknod)(struct vfs_handle_struct *handle, const char *path, mode_t mode, SMB_DEV_T dev); char *(*realpath)(struct vfs_handle_struct *handle, const char *path, char *resolved_path); + NTSTATUS (*notify_watch)(struct vfs_handle_struct *handle, + struct sys_notify_context *ctx, + struct notify_entry *e, + void (*callback)(struct sys_notify_context *ctx, + void *private_data, + struct notify_event *ev), + void *private_data, void *handle_p); /* NT ACL operations. */ @@ -390,6 +399,7 @@ struct vfs_ops { struct vfs_handle_struct *link; struct vfs_handle_struct *mknod; struct vfs_handle_struct *realpath; + struct vfs_handle_struct *notify_watch; /* NT ACL operations. */ diff --git a/source/include/vfs_macros.h b/source/include/vfs_macros.h index 119b616e72e..5a189ff07ff 100644 --- a/source/include/vfs_macros.h +++ b/source/include/vfs_macros.h @@ -77,6 +77,7 @@ #define SMB_VFS_LINK(conn, oldpath, newpath) ((conn)->vfs.ops.link((conn)->vfs.handles.link, (oldpath), (newpath))) #define SMB_VFS_MKNOD(conn, path, mode, dev) ((conn)->vfs.ops.mknod((conn)->vfs.handles.mknod, (path), (mode), (dev))) #define SMB_VFS_REALPATH(conn, path, resolved_path) ((conn)->vfs.ops.realpath((conn)->vfs.handles.realpath, (path), (resolved_path))) +#define SMB_VFS_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs.ops.notify_watch((conn)->vfs.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p))) /* NT ACL operations. */ #define SMB_VFS_FGET_NT_ACL(fsp, fd, security_info, ppdesc) ((fsp)->conn->vfs.ops.fget_nt_acl((fsp)->conn->vfs.handles.fget_nt_acl, (fsp), (fd), (security_info), (ppdesc))) @@ -190,6 +191,7 @@ #define SMB_VFS_OPAQUE_LINK(conn, oldpath, newpath) ((conn)->vfs_opaque.ops.link((conn)->vfs_opaque.handles.link, (oldpath), (newpath))) #define SMB_VFS_OPAQUE_MKNOD(conn, path, mode, dev) ((conn)->vfs_opaque.ops.mknod((conn)->vfs_opaque.handles.mknod, (path), (mode), (dev))) #define SMB_VFS_OPAQUE_REALPATH(conn, path, resolved_path) ((conn)->vfs_opaque.ops.realpath((conn)->vfs_opaque.handles.realpath, (path), (resolved_path))) +#define SMB_VFS_OPAQUE_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_opaque.ops.notify_watch((conn)->vfs_opaque.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p))) /* NT ACL operations. */ #define SMB_VFS_OPAQUE_FGET_NT_ACL(fsp, fd, security_info, ppdesc) ((fsp)->conn->vfs_opaque.ops.fget_nt_acl((fsp)->conn->vfs_opaque.handles.fget_nt_acl, (fsp), (fd), (security_info), (ppdesc))) @@ -304,6 +306,7 @@ #define SMB_VFS_NEXT_LINK(handle, oldpath, newpath) ((handle)->vfs_next.ops.link((handle)->vfs_next.handles.link, (oldpath), (newpath))) #define SMB_VFS_NEXT_MKNOD(handle, path, mode, dev) ((handle)->vfs_next.ops.mknod((handle)->vfs_next.handles.mknod, (path), (mode), (dev))) #define SMB_VFS_NEXT_REALPATH(handle, path, resolved_path) ((handle)->vfs_next.ops.realpath((handle)->vfs_next.handles.realpath, (path), (resolved_path))) +#define SMB_VFS_NEXT_NOTIFY_WATCH(conn, ctx, e, callback, private_data, handle_p) ((conn)->vfs_next.ops.notify_watch((conn)->vfs_next.handles.notify_watch, (ctx), (e), (callback), (private_data), (handle_p))) /* NT ACL operations. */ #define SMB_VFS_NEXT_FGET_NT_ACL(handle, fsp, fd, security_info, ppdesc) ((handle)->vfs_next.ops.fget_nt_acl((handle)->vfs_next.handles.fget_nt_acl, (fsp), (fd), (security_info), (ppdesc))) diff --git a/source/lib/debug.c b/source/lib/debug.c index 00f6b0e72ff..5f141661106 100644 --- a/source/lib/debug.c +++ b/source/lib/debug.c @@ -472,7 +472,7 @@ BOOL debug_parse_levels(const char *params_str) ****************************************************************************/ static void debug_message(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { const char *params_str = (const char *)buf; @@ -509,7 +509,7 @@ void debug_message_send(pid_t pid, const char *params_str) ****************************************************************************/ static void debuglevel_message(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { char *message = debug_list_class_names_and_levels(); @@ -539,8 +539,8 @@ void debug_init(void) initialised = True; - message_register(MSG_DEBUG, debug_message); - message_register(MSG_REQ_DEBUGLEVEL, debuglevel_message); + message_register(MSG_DEBUG, debug_message, NULL); + message_register(MSG_REQ_DEBUGLEVEL, debuglevel_message, NULL); for(p = default_classname_table; *p; p++) { debug_add_class(*p); diff --git a/source/lib/dmallocmsg.c b/source/lib/dmallocmsg.c index 1b2308ecba6..fed7bf59c52 100644 --- a/source/lib/dmallocmsg.c +++ b/source/lib/dmallocmsg.c @@ -35,8 +35,10 @@ static unsigned long our_dm_mark = 0; * Respond to a POOL_USAGE message by sending back string form of memory * usage stats. **/ -static void msg_req_dmalloc_mark(int UNUSED(msg_type), struct process_id UNUSED(src_pid), - void *UNUSED(buf), size_t UNUSED(len)) +static void msg_req_dmalloc_mark(int UNUSED(msg_type), + struct process_id UNUSED(src_pid), + void *UNUSED(buf), size_t UNUSED(len), + void *private_data) { #ifdef ENABLE_DMALLOC our_dm_mark = dmalloc_mark(); @@ -50,7 +52,8 @@ static void msg_req_dmalloc_mark(int UNUSED(msg_type), struct process_id UNUSED( static void msg_req_dmalloc_log_changed(int UNUSED(msg_type), struct process_id UNUSED(src_pid), - void *UNUSED(buf), size_t UNUSED(len)) + void *UNUSED(buf), size_t UNUSED(len), + void *private_data) { #ifdef ENABLE_DMALLOC dmalloc_log_changed(our_dm_mark, True, True, True); @@ -66,7 +69,8 @@ static void msg_req_dmalloc_log_changed(int UNUSED(msg_type), **/ void register_dmalloc_msgs(void) { - message_register(MSG_REQ_DMALLOC_MARK, msg_req_dmalloc_mark); - message_register(MSG_REQ_DMALLOC_LOG_CHANGED, msg_req_dmalloc_log_changed); + message_register(MSG_REQ_DMALLOC_MARK, msg_req_dmalloc_mark, NULL); + message_register(MSG_REQ_DMALLOC_LOG_CHANGED, + msg_req_dmalloc_log_changed, NULL); DEBUG(2, ("Registered MSG_REQ_DMALLOC_MARK and LOG_CHANGED\n")); } diff --git a/source/lib/events.c b/source/lib/events.c index 0e00dcbb034..a00db77b6be 100644 --- a/source/lib/events.c +++ b/source/lib/events.c @@ -21,27 +21,65 @@ #include "includes.h" -static struct timed_event *timed_events; +struct timed_event { + struct timed_event *next, *prev; + struct event_context *event_ctx; + struct timeval when; + const char *event_name; + void (*handler)(struct event_context *event_ctx, + struct timed_event *te, + const struct timeval *now, + void *private_data); + void *private_data; +}; + +struct fd_event { + struct fd_event *prev, *next; + struct event_context *event_ctx; + int fd; + uint16_t flags; /* see EVENT_FD_* flags */ + void (*handler)(struct event_context *event_ctx, + struct fd_event *event, + uint16 flags, + void *private_data); + void *private_data; +}; + +#define EVENT_FD_WRITEABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_WRITE) +#define EVENT_FD_READABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) | EVENT_FD_READ) + +#define EVENT_FD_NOT_WRITEABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_WRITE) +#define EVENT_FD_NOT_READABLE(fde) \ + event_set_fd_flags(fde, event_get_fd_flags(fde) & ~EVENT_FD_READ) + +struct event_context { + struct timed_event *timed_events; + struct fd_event *fd_events; +}; static int timed_event_destructor(struct timed_event *te) { DEBUG(10, ("Destroying timed event %lx \"%s\"\n", (unsigned long)te, te->event_name)); - DLIST_REMOVE(timed_events, te); + DLIST_REMOVE(te->event_ctx->timed_events, te); return 0; } /**************************************************************************** - Add te by time. + Add te by time. ****************************************************************************/ static void add_event_by_time(struct timed_event *te) { + struct event_context *ctx = te->event_ctx; struct timed_event *last_te, *cur_te; /* Keep the list ordered by time. We must preserve this. */ last_te = NULL; - for (cur_te = timed_events; cur_te; cur_te = cur_te->next) { + for (cur_te = ctx->timed_events; cur_te; cur_te = cur_te->next) { /* if the new event comes before the current one break */ if (!timeval_is_zero(&cur_te->when) && timeval_compare(&te->when, &cur_te->when) < 0) { @@ -50,7 +88,7 @@ static void add_event_by_time(struct timed_event *te) last_te = cur_te; } - DLIST_ADD_AFTER(timed_events, te, last_te); + DLIST_ADD_AFTER(ctx->timed_events, te, last_te); } /**************************************************************************** @@ -59,10 +97,12 @@ static void add_event_by_time(struct timed_event *te) handed to it. ****************************************************************************/ -struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx, +struct timed_event *event_add_timed(struct event_context *event_ctx, + TALLOC_CTX *mem_ctx, struct timeval when, const char *event_name, - void (*handler)(struct timed_event *te, + void (*handler)(struct event_context *event_ctx, + struct timed_event *te, const struct timeval *now, void *private_data), void *private_data) @@ -75,6 +115,7 @@ struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx, return NULL; } + te->event_ctx = event_ctx; te->when = when; te->event_name = event_name; te->handler = handler; @@ -89,38 +130,166 @@ struct timed_event *add_timed_event(TALLOC_CTX *mem_ctx, return te; } -void run_events(void) +static int fd_event_destructor(struct fd_event *fde) { + struct event_context *event_ctx = fde->event_ctx; + + DLIST_REMOVE(event_ctx->fd_events, fde); + return 0; +} + +struct fd_event *event_add_fd(struct event_context *event_ctx, + TALLOC_CTX *mem_ctx, + int fd, uint16_t flags, + void (*handler)(struct event_context *event_ctx, + struct fd_event *event, + uint16 flags, + void *private_data), + void *private_data) +{ + struct fd_event *fde; + + if (!(fde = TALLOC_P(mem_ctx, struct fd_event))) { + return NULL; + } + + fde->event_ctx = event_ctx; + fde->fd = fd; + fde->flags = flags; + fde->handler = handler; + fde->private_data = private_data; + + DLIST_ADD(event_ctx->fd_events, fde); + + talloc_set_destructor(fde, fd_event_destructor); + return fde; +} + +void event_fd_set_writeable(struct fd_event *fde) +{ + fde->flags |= EVENT_FD_WRITE; +} + +void event_fd_set_not_writeable(struct fd_event *fde) +{ + fde->flags &= ~EVENT_FD_WRITE; +} + +void event_fd_set_readable(struct fd_event *fde) +{ + fde->flags |= EVENT_FD_READ; +} + +void event_fd_set_not_readable(struct fd_event *fde) +{ + fde->flags &= ~EVENT_FD_READ; +} + +void event_add_to_select_args(struct event_context *event_ctx, + const struct timeval *now, + fd_set *read_fds, fd_set *write_fds, + struct timeval *timeout, int *maxfd) +{ + struct fd_event *fde; + struct timeval diff; + + for (fde = event_ctx->fd_events; fde; fde = fde->next) { + if (fde->flags & EVENT_FD_READ) { + FD_SET(fde->fd, read_fds); + } + if (fde->flags & EVENT_FD_WRITE) { + FD_SET(fde->fd, write_fds); + } + + if ((fde->flags & (EVENT_FD_READ|EVENT_FD_WRITE)) + && (fde->fd > *maxfd)) { + *maxfd = fde->fd; + } + } + + if (event_ctx->timed_events == NULL) { + return; + } + + diff = timeval_until(now, &event_ctx->timed_events->when); + *timeout = timeval_min(timeout, &diff); +} + +BOOL run_events(struct event_context *event_ctx, + int selrtn, fd_set *read_fds, fd_set *write_fds) +{ + BOOL fired = False; + struct fd_event *fde, *next; + /* Run all events that are pending, not just one (as we did previously. */ - while (timed_events) { + while (event_ctx->timed_events) { struct timeval now; GetTimeOfDay(&now); - if (timeval_compare(&now, &timed_events->when) < 0) { + if (timeval_compare( + &now, &event_ctx->timed_events->when) < 0) { /* Nothing to do yet */ DEBUG(11, ("run_events: Nothing to do\n")); - return; + break; } - DEBUG(10, ("Running event \"%s\" %lx\n", timed_events->event_name, - (unsigned long)timed_events)); + DEBUG(10, ("Running event \"%s\" %lx\n", + event_ctx->timed_events->event_name, + (unsigned long)event_ctx->timed_events)); + + event_ctx->timed_events->handler( + event_ctx, + event_ctx->timed_events, &now, + event_ctx->timed_events->private_data); + + fired = True; + } + + if (fired) { + /* + * We might have changed the socket status during the timed + * events, return to run select again. + */ + return True; + } + + if (selrtn == 0) { + /* + * No fd ready + */ + return fired; + } - timed_events->handler(timed_events, &now, timed_events->private_data); + for (fde = event_ctx->fd_events; fde; fde = next) { + uint16 flags = 0; + + next = fde->next; + if (FD_ISSET(fde->fd, read_fds)) flags |= EVENT_FD_READ; + if (FD_ISSET(fde->fd, write_fds)) flags |= EVENT_FD_WRITE; + + if (flags) { + fde->handler(event_ctx, fde, flags, fde->private_data); + fired = True; + } } + + return fired; } -struct timeval *get_timed_events_timeout(struct timeval *to_ret) + +struct timeval *get_timed_events_timeout(struct event_context *event_ctx, + struct timeval *to_ret) { struct timeval now; - if (timed_events == NULL) { + if (event_ctx->timed_events == NULL) { return NULL; } now = timeval_current(); - *to_ret = timeval_until(&now, &timed_events->when); + *to_ret = timeval_until(&now, &event_ctx->timed_events->when); DEBUG(10, ("timed_events_timeout: %d/%d\n", (int)to_ret->tv_sec, (int)to_ret->tv_usec)); @@ -128,33 +297,35 @@ struct timeval *get_timed_events_timeout(struct timeval *to_ret) return to_ret; } -/**************************************************************************** - Move a function within the list. Keep the list sorted by time. -****************************************************************************/ +struct event_context *event_context_init(TALLOC_CTX *mem_ctx) +{ + return TALLOC_ZERO_P(NULL, struct event_context); +} -int set_event_dispatch_time(const char *event_name, struct timeval when) +int set_event_dispatch_time(struct event_context *event_ctx, + const char *event_name, struct timeval when) { struct timed_event *te; - for (te = timed_events; te; te = te->next) { + for (te = event_ctx->timed_events; te; te = te->next) { if (strcmp(event_name, te->event_name) == 0) { - DLIST_REMOVE(timed_events, te); + DLIST_REMOVE(event_ctx->timed_events, te); te->when = when; add_event_by_time(te); return 1; } } - return 0; } /* Returns 1 if event was found and cancelled, 0 otherwise. */ -int cancel_named_event(const char *event_name) +int cancel_named_event(struct event_context *event_ctx, + const char *event_name) { struct timed_event *te; - for (te = timed_events; te; te = te->next) { + for (te = event_ctx->timed_events; te; te = te->next) { if (strcmp(event_name, te->event_name) == 0) { TALLOC_FREE(te); return 1; diff --git a/source/lib/messages.c b/source/lib/messages.c index de17a03afc1..e0bf86a46ce 100644 --- a/source/lib/messages.c +++ b/source/lib/messages.c @@ -66,7 +66,9 @@ struct message_rec { static struct dispatch_fns { struct dispatch_fns *next, *prev; int msg_type; - void (*fn)(int msg_type, struct process_id pid, void *buf, size_t len); + void (*fn)(int msg_type, struct process_id pid, void *buf, size_t len, + void *private_data); + void *private_data; } *dispatch_fns; /**************************************************************************** @@ -102,7 +104,7 @@ static void sig_usr1(void) ****************************************************************************/ static void ping_message(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { const char *msg = buf ? (const char *)buf : "none"; @@ -133,7 +135,7 @@ BOOL message_init(void) CatchSignal(SIGUSR1, SIGNAL_CAST sig_usr1); - message_register(MSG_PING, ping_message); + message_register(MSG_PING, ping_message, NULL); /* Register some debugging related messages */ @@ -164,7 +166,7 @@ static TDB_DATA message_key_pid(struct process_id pid) then delete its record in the database. ****************************************************************************/ -static BOOL message_notify(struct process_id procid) +static NTSTATUS message_notify(struct process_id procid) { pid_t pid = procid.pid; int ret; @@ -189,25 +191,40 @@ static BOOL message_notify(struct process_id procid) if (ret == -1) { if (errno == ESRCH) { - DEBUG(2,("pid %d doesn't exist - deleting messages record\n", (int)pid)); + DEBUG(2,("pid %d doesn't exist - deleting messages record\n", + (int)pid)); tdb_delete(tdb, message_key_pid(procid)); - } else { - DEBUG(2,("message to process %d failed - %s\n", (int)pid, strerror(errno))); + + /* + * INVALID_HANDLE is the closest I can think of -- vl + */ + return NT_STATUS_INVALID_HANDLE; } - return False; + + DEBUG(2,("message to process %d failed - %s\n", (int)pid, + strerror(errno))); + + /* + * No call to map_nt_error_from_unix -- don't want to link in + * errormap.o into lots of utils. + */ + + if (errno == EINVAL) return NT_STATUS_INVALID_PARAMETER; + if (errno == EPERM) return NT_STATUS_ACCESS_DENIED; + return NT_STATUS_UNSUCCESSFUL; } - return True; + return NT_STATUS_OK; } /**************************************************************************** Send a message to a particular pid. ****************************************************************************/ -static BOOL message_send_pid_internal(struct process_id pid, int msg_type, - const void *buf, size_t len, - BOOL duplicates_allowed, - unsigned int timeout) +static NTSTATUS message_send_pid_internal(struct process_id pid, int msg_type, + const void *buf, size_t len, + BOOL duplicates_allowed, + unsigned int timeout) { TDB_DATA kbuf; TDB_DATA dbuf; @@ -237,8 +254,9 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type, kbuf = message_key_pid(pid); dbuf.dptr = (char *)SMB_MALLOC(len + sizeof(rec)); - if (!dbuf.dptr) - return False; + if (!dbuf.dptr) { + return NT_STATUS_NO_MEMORY; + } memcpy(dbuf.dptr, &rec, sizeof(rec)); if (len > 0 && buf) @@ -253,13 +271,15 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type, /* lock the record for the destination */ if (timeout) { if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { - DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout)); - return False; + DEBUG(0,("message_send_pid_internal: failed to get " + "chainlock with timeout %ul.\n", timeout)); + return NT_STATUS_IO_TIMEOUT; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { - DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n")); - return False; + DEBUG(0,("message_send_pid_internal: failed to get " + "chainlock.\n")); + return NT_STATUS_LOCK_NOT_GRANTED; } } tdb_append(tdb, kbuf, dbuf); @@ -273,13 +293,15 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type, /* lock the record for the destination */ if (timeout) { if (tdb_chainlock_with_timeout(tdb, kbuf, timeout) == -1) { - DEBUG(0,("message_send_pid_internal: failed to get chainlock with timeout %ul.\n", timeout)); - return False; + DEBUG(0,("message_send_pid_internal: failed to get chainlock " + "with timeout %ul.\n", timeout)); + return NT_STATUS_IO_TIMEOUT; } } else { if (tdb_chainlock(tdb, kbuf) == -1) { - DEBUG(0,("message_send_pid_internal: failed to get chainlock.\n")); - return False; + DEBUG(0,("message_send_pid_internal: failed to get " + "chainlock.\n")); + return NT_STATUS_LOCK_NOT_GRANTED; } } @@ -308,10 +330,11 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type, if (!memcmp(ptr, &rec, sizeof(rec))) { if (!len || (len && !memcmp( ptr + sizeof(rec), buf, len))) { tdb_chainunlock(tdb, kbuf); - DEBUG(10,("message_send_pid_internal: discarding duplicate message.\n")); + DEBUG(10,("message_send_pid_internal: discarding " + "duplicate message.\n")); SAFE_FREE(dbuf.dptr); SAFE_FREE(old_dbuf.dptr); - return True; + return NT_STATUS_OK; } } memcpy(&prec, ptr, sizeof(prec)); @@ -334,19 +357,23 @@ static BOOL message_send_pid_internal(struct process_id pid, int msg_type, Send a message to a particular pid - no timeout. ****************************************************************************/ -BOOL message_send_pid(struct process_id pid, int msg_type, const void *buf, size_t len, BOOL duplicates_allowed) +NTSTATUS message_send_pid(struct process_id pid, int msg_type, const void *buf, + size_t len, BOOL duplicates_allowed) { - return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, 0); + return message_send_pid_internal(pid, msg_type, buf, len, + duplicates_allowed, 0); } /**************************************************************************** Send a message to a particular pid, with timeout in seconds. ****************************************************************************/ -BOOL message_send_pid_with_timeout(struct process_id pid, int msg_type, const void *buf, size_t len, - BOOL duplicates_allowed, unsigned int timeout) +NTSTATUS message_send_pid_with_timeout(struct process_id pid, int msg_type, + const void *buf, size_t len, + BOOL duplicates_allowed, unsigned int timeout) { - return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, timeout); + return message_send_pid_internal(pid, msg_type, buf, len, duplicates_allowed, + timeout); } /**************************************************************************** @@ -493,7 +520,9 @@ void message_dispatch(void) for (dfn = dispatch_fns; dfn; dfn = dfn->next) { if (dfn->msg_type == msg_type) { DEBUG(10,("message_dispatch: processing message of type %d.\n", msg_type)); - dfn->fn(msg_type, src, len ? (void *)buf : NULL, len); + dfn->fn(msg_type, src, + len ? (void *)buf : NULL, len, + dfn->private_data); n_handled++; break; } @@ -516,7 +545,9 @@ void message_dispatch(void) void message_register(int msg_type, void (*fn)(int msg_type, struct process_id pid, - void *buf, size_t len)) + void *buf, size_t len, + void *private_data), + void *private_data) { struct dispatch_fns *dfn; @@ -535,6 +566,7 @@ void message_register(int msg_type, dfn->msg_type = msg_type; dfn->fn = fn; + dfn->private_data = private_data; DLIST_ADD(dispatch_fns, dfn); } @@ -579,6 +611,7 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void { struct connections_data crec; struct msg_all *msg_all = (struct msg_all *)state; + NTSTATUS status; if (dbuf.dsize != sizeof(crec)) return 0; @@ -596,18 +629,17 @@ static int traverse_fn(TDB_CONTEXT *the_tdb, TDB_DATA kbuf, TDB_DATA dbuf, void /* If the msg send fails because the pid was not found (i.e. smbd died), * the msg has already been deleted from the messages.tdb.*/ - if (!message_send_pid(crec.pid, msg_all->msg_type, - msg_all->buf, msg_all->len, - msg_all->duplicates)) { + status = message_send_pid(crec.pid, msg_all->msg_type, + msg_all->buf, msg_all->len, + msg_all->duplicates); + + if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { /* If the pid was not found delete the entry from connections.tdb */ - if (errno == ESRCH) { - DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n", - procid_str_static(&crec.pid), - crec.cnum, crec.name)); - tdb_delete(the_tdb, kbuf); - } + DEBUG(2,("pid %s doesn't exist - deleting connections %d [%s]\n", + procid_str_static(&crec.pid), crec.cnum, crec.name)); + tdb_delete(the_tdb, kbuf); } msg_all->n_sent++; return 0; @@ -671,4 +703,135 @@ void message_unblock(void) { BlockSignals(False, SIGUSR1); } + +/* + * Samba4 API wrapper around the Samba3 implementation. Yes, I know, we could + * import the whole Samba4 thing, but I want notify.c from Samba4 in first. + */ + +struct messaging_callback { + struct messaging_callback *prev, *next; + uint32 msg_type; + void (*fn)(struct messaging_context *msg, void *private_data, + uint32_t msg_type, + struct server_id server_id, DATA_BLOB *data); + void *private_data; +}; + +struct messaging_context { + struct server_id id; + struct messaging_callback *callbacks; +}; + +static int messaging_context_destructor(struct messaging_context *ctx) +{ + struct messaging_callback *cb; + + for (cb = ctx->callbacks; cb; cb = cb->next) { + /* + * We unconditionally remove all instances of our callback + * from the tdb basis. + */ + message_deregister(cb->msg_type); + } + return 0; +} + +struct messaging_context *messaging_init(TALLOC_CTX *mem_ctx, + struct server_id server_id, + struct event_context *ev) +{ + struct messaging_context *ctx; + + if (!(ctx = TALLOC_ZERO_P(mem_ctx, struct messaging_context))) { + return NULL; + } + + ctx->id = server_id; + talloc_set_destructor(ctx, messaging_context_destructor); + return ctx; +} + +static void messaging_callback(int msg_type, struct process_id pid, + void *buf, size_t len, void *private_data) +{ + struct messaging_context *ctx = talloc_get_type_abort( + private_data, struct messaging_context); + struct messaging_callback *cb, *next; + + for (cb = ctx->callbacks; cb; cb = next) { + /* + * Allow a callback to remove itself + */ + next = cb->next; + + if (msg_type == cb->msg_type) { + DATA_BLOB blob; + struct server_id id; + + blob.data = (uint8 *)buf; + blob.length = len; + id.id = pid; + + cb->fn(ctx, cb->private_data, msg_type, id, &blob); + } + } +} + +/* + * Register a dispatch function for a particular message type. Allow multiple + * registrants +*/ +NTSTATUS messaging_register(struct messaging_context *ctx, void *private_data, + uint32_t msg_type, + void (*fn)(struct messaging_context *msg, + void *private_data, + uint32_t msg_type, + struct server_id server_id, + DATA_BLOB *data)) +{ + struct messaging_callback *cb; + + if (!(cb = talloc(ctx, struct messaging_callback))) { + return NT_STATUS_NO_MEMORY; + } + + cb->msg_type = msg_type; + cb->fn = fn; + cb->private_data = private_data; + + DLIST_ADD(ctx->callbacks, cb); + message_register(msg_type, messaging_callback, ctx); + return NT_STATUS_OK; +} + +/* + De-register the function for a particular message type. +*/ +void messaging_deregister(struct messaging_context *ctx, uint32_t msg_type, + void *private_data) +{ + struct messaging_callback *cb, *next; + + for (cb = ctx->callbacks; cb; cb = next) { + next = cb->next; + if ((cb->msg_type == msg_type) + && (cb->private_data == private_data)) { + DLIST_REMOVE(ctx->callbacks, cb); + TALLOC_FREE(cb); + } + } +} + +/* + Send a message to a particular server +*/ +NTSTATUS messaging_send(struct messaging_context *msg, + struct server_id server, + uint32_t msg_type, DATA_BLOB *data) +{ + return message_send_pid_internal(server.id, msg_type, data->data, + data->length, True, 0); +} + /** @} **/ diff --git a/source/lib/tallocmsg.c b/source/lib/tallocmsg.c index e4e9bac94d6..0f493538f3c 100644 --- a/source/lib/tallocmsg.c +++ b/source/lib/tallocmsg.c @@ -66,7 +66,8 @@ static void msg_pool_usage_helper(const void *ptr, int depth, int max_depth, int * usage stats. **/ void msg_pool_usage(int msg_type, struct process_id src_pid, - void *UNUSED(buf), size_t UNUSED(len)) + void *UNUSED(buf), size_t UNUSED(len), + void *private_data) { struct msg_pool_usage_state state; @@ -100,6 +101,6 @@ void msg_pool_usage(int msg_type, struct process_id src_pid, **/ void register_msg_pool_usage(void) { - message_register(MSG_REQ_POOL_USAGE, msg_pool_usage); + message_register(MSG_REQ_POOL_USAGE, msg_pool_usage, NULL); DEBUG(2, ("Registered MSG_REQ_POOL_USAGE\n")); } diff --git a/source/lib/util.c b/source/lib/util.c index 0f54ba74414..7d41a14292c 100644 --- a/source/lib/util.c +++ b/source/lib/util.c @@ -3013,11 +3013,24 @@ struct process_id procid_self(void) return pid_to_procid(sys_getpid()); } +struct server_id server_id_self(void) +{ + struct server_id id; + id.id = procid_self(); + return id; +} + BOOL procid_equal(const struct process_id *p1, const struct process_id *p2) { return (p1->pid == p2->pid); } +BOOL cluster_id_equal(const struct server_id *id1, + const struct server_id *id2) +{ + return procid_equal(&id1->id, &id2->id); +} + BOOL procid_is_me(const struct process_id *pid) { return (pid->pid == sys_getpid()); diff --git a/source/lib/util_tdb.c b/source/lib/util_tdb.c index e847c79369e..9136e2d6c1e 100644 --- a/source/lib/util_tdb.c +++ b/source/lib/util_tdb.c @@ -838,3 +838,101 @@ int tdb_trans_delete(struct tdb_context *tdb, TDB_DATA key) return res; } + +/* + Log tdb messages via DEBUG(). +*/ +static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, + const char *format, ...) PRINTF_ATTRIBUTE(3,4); + +static void tdb_wrap_log(TDB_CONTEXT *tdb, enum tdb_debug_level level, + const char *format, ...) +{ + va_list ap; + char *ptr = NULL; + int debuglevel = 0; + + va_start(ap, format); + vasprintf(&ptr, format, ap); + va_end(ap); + + switch (level) { + case TDB_DEBUG_FATAL: + debug_level = 0; + break; + case TDB_DEBUG_ERROR: + debuglevel = 1; + break; + case TDB_DEBUG_WARNING: + debuglevel = 2; + break; + case TDB_DEBUG_TRACE: + debuglevel = 5; + break; + default: + debuglevel = 0; + } + + if (ptr != NULL) { + const char *name = tdb_name(tdb); + DEBUG(debuglevel, ("tdb(%s): %s", name ? name : "unnamed", ptr)); + free(ptr); + } +} + +static struct tdb_wrap *tdb_list; + +/* destroy the last connection to a tdb */ +static int tdb_wrap_destructor(struct tdb_wrap *w) +{ + tdb_close(w->tdb); + DLIST_REMOVE(tdb_list, w); + return 0; +} + +/* + wrapped connection to a tdb database + to close just talloc_free() the tdb_wrap pointer + */ +struct tdb_wrap *tdb_wrap_open(TALLOC_CTX *mem_ctx, + const char *name, int hash_size, int tdb_flags, + int open_flags, mode_t mode) +{ + struct tdb_wrap *w; + struct tdb_logging_context log_ctx; + log_ctx.log_fn = tdb_wrap_log; + + for (w=tdb_list;w;w=w->next) { + if (strcmp(name, w->name) == 0) { + /* + * Yes, talloc_reference is exactly what we want + * here. Otherwise we would have to implement our own + * reference counting. + */ + return talloc_reference(mem_ctx, w); + } + } + + w = talloc(mem_ctx, struct tdb_wrap); + if (w == NULL) { + return NULL; + } + + if (!(w->name = talloc_strdup(w, name))) { + talloc_free(w); + return NULL; + } + + w->tdb = tdb_open_ex(name, hash_size, tdb_flags, + open_flags, mode, &log_ctx, NULL); + if (w->tdb == NULL) { + talloc_free(w); + return NULL; + } + + talloc_set_destructor(w, tdb_wrap_destructor); + + DLIST_ADD(tdb_list, w); + + return w; +} diff --git a/source/librpc/gen_ndr/ndr_notify.c b/source/librpc/gen_ndr/ndr_notify.c new file mode 100644 index 00000000000..c3873550bb0 --- /dev/null +++ b/source/librpc/gen_ndr/ndr_notify.c @@ -0,0 +1,242 @@ +/* parser auto-generated by pidl */ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_notify.h" + +_PUBLIC_ NTSTATUS ndr_push_notify_entry(struct ndr_push *ndr, int ndr_flags, const struct notify_entry *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 8)); + NDR_CHECK(ndr_push_server_id(ndr, NDR_SCALARS, &r->server)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->filter)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->subdir_filter)); + { + uint32_t _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->path)); + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->path_len)); + NDR_CHECK(ndr_push_pointer(ndr, NDR_SCALARS, r->private_data)); + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_push_server_id(ndr, NDR_BUFFERS, &r->server)); + } + return NT_STATUS_OK; +} + +_PUBLIC_ NTSTATUS ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_flags, struct notify_entry *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 8)); + NDR_CHECK(ndr_pull_server_id(ndr, NDR_SCALARS, &r->server)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->filter)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->subdir_filter)); + { + uint32_t _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->path)); + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->path_len)); + NDR_CHECK(ndr_pull_pointer(ndr, NDR_SCALARS, &r->private_data)); + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_pull_server_id(ndr, NDR_BUFFERS, &r->server)); + } + return NT_STATUS_OK; +} + +_PUBLIC_ void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, const struct notify_entry *r) +{ + ndr_print_struct(ndr, name, "notify_entry"); + ndr->depth++; + ndr_print_server_id(ndr, "server", &r->server); + ndr_print_uint32(ndr, "filter", r->filter); + ndr_print_uint32(ndr, "subdir_filter", r->subdir_filter); + ndr_print_string(ndr, "path", r->path); + ndr_print_uint32(ndr, "path_len", r->path_len); + ndr_print_pointer(ndr, "private_data", r->private_data); + ndr->depth--; +} + +NTSTATUS ndr_push_notify_depth(struct ndr_push *ndr, int ndr_flags, const struct notify_depth *r) +{ + uint32_t cntr_entries_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 8)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_mask)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->max_mask_subdir)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_entries)); + for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) { + NDR_CHECK(ndr_push_notify_entry(ndr, NDR_SCALARS, &r->entries[cntr_entries_0])); + } + } + if (ndr_flags & NDR_BUFFERS) { + for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) { + NDR_CHECK(ndr_push_notify_entry(ndr, NDR_BUFFERS, &r->entries[cntr_entries_0])); + } + } + return NT_STATUS_OK; +} + +NTSTATUS ndr_pull_notify_depth(struct ndr_pull *ndr, int ndr_flags, struct notify_depth *r) +{ + uint32_t cntr_entries_0; + TALLOC_CTX *_mem_save_entries_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 8)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_mask)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->max_mask_subdir)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_entries)); + NDR_PULL_ALLOC_N(ndr, r->entries, r->num_entries); + _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0); + for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) { + NDR_CHECK(ndr_pull_notify_entry(ndr, NDR_SCALARS, &r->entries[cntr_entries_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0); + } + if (ndr_flags & NDR_BUFFERS) { + _mem_save_entries_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->entries, 0); + for (cntr_entries_0 = 0; cntr_entries_0 < r->num_entries; cntr_entries_0++) { + NDR_CHECK(ndr_pull_notify_entry(ndr, NDR_BUFFERS, &r->entries[cntr_entries_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_entries_0, 0); + } + return NT_STATUS_OK; +} + +_PUBLIC_ void ndr_print_notify_depth(struct ndr_print *ndr, const char *name, const struct notify_depth *r) +{ + uint32_t cntr_entries_0; + ndr_print_struct(ndr, name, "notify_depth"); + ndr->depth++; + ndr_print_uint32(ndr, "max_mask", r->max_mask); + ndr_print_uint32(ndr, "max_mask_subdir", r->max_mask_subdir); + ndr_print_uint32(ndr, "num_entries", r->num_entries); + ndr->print(ndr, "%s: ARRAY(%d)", "entries", r->num_entries); + ndr->depth++; + for (cntr_entries_0=0;cntr_entries_0num_entries;cntr_entries_0++) { + char *idx_0=NULL; + asprintf(&idx_0, "[%d]", cntr_entries_0); + if (idx_0) { + ndr_print_notify_entry(ndr, "entries", &r->entries[cntr_entries_0]); + free(idx_0); + } + } + ndr->depth--; + ndr->depth--; +} + +_PUBLIC_ NTSTATUS ndr_push_notify_array(struct ndr_push *ndr, int ndr_flags, const struct notify_array *r) +{ + uint32_t cntr_depth_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 8)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->num_depths)); + for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) { + NDR_CHECK(ndr_push_notify_depth(ndr, NDR_SCALARS, &r->depth[cntr_depth_0])); + } + } + if (ndr_flags & NDR_BUFFERS) { + for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) { + NDR_CHECK(ndr_push_notify_depth(ndr, NDR_BUFFERS, &r->depth[cntr_depth_0])); + } + } + return NT_STATUS_OK; +} + +_PUBLIC_ NTSTATUS ndr_pull_notify_array(struct ndr_pull *ndr, int ndr_flags, struct notify_array *r) +{ + uint32_t cntr_depth_0; + TALLOC_CTX *_mem_save_depth_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 8)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_depths)); + NDR_PULL_ALLOC_N(ndr, r->depth, r->num_depths); + _mem_save_depth_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->depth, 0); + for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) { + NDR_CHECK(ndr_pull_notify_depth(ndr, NDR_SCALARS, &r->depth[cntr_depth_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_depth_0, 0); + } + if (ndr_flags & NDR_BUFFERS) { + _mem_save_depth_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->depth, 0); + for (cntr_depth_0 = 0; cntr_depth_0 < r->num_depths; cntr_depth_0++) { + NDR_CHECK(ndr_pull_notify_depth(ndr, NDR_BUFFERS, &r->depth[cntr_depth_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_depth_0, 0); + } + return NT_STATUS_OK; +} + +_PUBLIC_ void ndr_print_notify_array(struct ndr_print *ndr, const char *name, const struct notify_array *r) +{ + uint32_t cntr_depth_0; + ndr_print_struct(ndr, name, "notify_array"); + ndr->depth++; + ndr_print_uint32(ndr, "num_depths", r->num_depths); + ndr->print(ndr, "%s: ARRAY(%d)", "depth", r->num_depths); + ndr->depth++; + for (cntr_depth_0=0;cntr_depth_0num_depths;cntr_depth_0++) { + char *idx_0=NULL; + asprintf(&idx_0, "[%d]", cntr_depth_0); + if (idx_0) { + ndr_print_notify_depth(ndr, "depth", &r->depth[cntr_depth_0]); + free(idx_0); + } + } + ndr->depth--; + ndr->depth--; +} + +_PUBLIC_ NTSTATUS ndr_push_notify_event(struct ndr_push *ndr, int ndr_flags, const struct notify_event *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_push_align(ndr, 8)); + NDR_CHECK(ndr_push_uint32(ndr, NDR_SCALARS, r->action)); + { + uint32_t _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_push_string(ndr, NDR_SCALARS, r->path)); + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_push_pointer(ndr, NDR_SCALARS, r->private_data)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NT_STATUS_OK; +} + +_PUBLIC_ NTSTATUS ndr_pull_notify_event(struct ndr_pull *ndr, int ndr_flags, struct notify_event *r) +{ + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 8)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->action)); + { + uint32_t _flags_save_string = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM); + NDR_CHECK(ndr_pull_string(ndr, NDR_SCALARS, &r->path)); + ndr->flags = _flags_save_string; + } + NDR_CHECK(ndr_pull_pointer(ndr, NDR_SCALARS, &r->private_data)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NT_STATUS_OK; +} + +_PUBLIC_ void ndr_print_notify_event(struct ndr_print *ndr, const char *name, const struct notify_event *r) +{ + ndr_print_struct(ndr, name, "notify_event"); + ndr->depth++; + ndr_print_uint32(ndr, "action", r->action); + ndr_print_string(ndr, "path", r->path); + ndr_print_pointer(ndr, "private_data", r->private_data); + ndr->depth--; +} + diff --git a/source/librpc/gen_ndr/ndr_notify.h b/source/librpc/gen_ndr/ndr_notify.h new file mode 100644 index 00000000000..793ffa51ca7 --- /dev/null +++ b/source/librpc/gen_ndr/ndr_notify.h @@ -0,0 +1,20 @@ +/* header auto-generated by pidl */ + +#include "librpc/gen_ndr/notify.h" + +#ifndef _HEADER_NDR_notify +#define _HEADER_NDR_notify + +#include "librpc/ndr/libndr.h" +#define DCERPC_NOTIFY_CALL_COUNT (0) +NTSTATUS ndr_push_notify_entry(struct ndr_push *ndr, int ndr_flags, const struct notify_entry *r); +NTSTATUS ndr_pull_notify_entry(struct ndr_pull *ndr, int ndr_flags, struct notify_entry *r); +void ndr_print_notify_entry(struct ndr_print *ndr, const char *name, const struct notify_entry *r); +void ndr_print_notify_depth(struct ndr_print *ndr, const char *name, const struct notify_depth *r); +NTSTATUS ndr_push_notify_array(struct ndr_push *ndr, int ndr_flags, const struct notify_array *r); +NTSTATUS ndr_pull_notify_array(struct ndr_pull *ndr, int ndr_flags, struct notify_array *r); +void ndr_print_notify_array(struct ndr_print *ndr, const char *name, const struct notify_array *r); +NTSTATUS ndr_push_notify_event(struct ndr_push *ndr, int ndr_flags, const struct notify_event *r); +NTSTATUS ndr_pull_notify_event(struct ndr_pull *ndr, int ndr_flags, struct notify_event *r); +void ndr_print_notify_event(struct ndr_print *ndr, const char *name, const struct notify_event *r); +#endif /* _HEADER_NDR_notify */ diff --git a/source/librpc/gen_ndr/notify.h b/source/librpc/gen_ndr/notify.h new file mode 100644 index 00000000000..f85b9b1bac8 --- /dev/null +++ b/source/librpc/gen_ndr/notify.h @@ -0,0 +1,33 @@ +/* header auto-generated by pidl */ + +#ifndef _HEADER_notify +#define _HEADER_notify + +struct notify_entry { + struct server_id server; + uint32_t filter; + uint32_t subdir_filter; + const char * path;/* [flag(LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM)] */ + uint32_t path_len; + void* private_data; +}/* [public] */; + +struct notify_depth { + uint32_t max_mask; + uint32_t max_mask_subdir; + uint32_t num_entries; + struct notify_entry *entries; +}; + +struct notify_array { + uint32_t num_depths; + struct notify_depth *depth; +}/* [public] */; + +struct notify_event { + uint32_t action; + const char * path;/* [flag(LIBNDR_FLAG_STR_UTF8|LIBNDR_FLAG_STR_NULLTERM)] */ + void* private_data; +}/* [public] */; + +#endif /* _HEADER_notify */ diff --git a/source/libsmb/clidgram.c b/source/libsmb/clidgram.c index dfb613238f6..a983f485ab4 100644 --- a/source/libsmb/clidgram.c +++ b/source/libsmb/clidgram.c @@ -101,8 +101,9 @@ BOOL cli_send_mailslot(BOOL unique, const char *mailslot, DEBUGADD(4,("to %s IP %s\n", nmb_namestr(&dgram->dest_name), inet_ntoa(dest_ip))); - return message_send_pid(pid_to_procid(nmbd_pid), MSG_SEND_PACKET, &p, sizeof(p), - False); + return NT_STATUS_IS_OK(message_send_pid(pid_to_procid(nmbd_pid), + MSG_SEND_PACKET, &p, sizeof(p), + False)); } /* diff --git a/source/nmbd/nmbd.c b/source/nmbd/nmbd.c index 4a05fde28c9..46f209872b0 100644 --- a/source/nmbd/nmbd.c +++ b/source/nmbd/nmbd.c @@ -77,7 +77,7 @@ static void terminate(void) **************************************************************************** */ static void nmbd_terminate(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { terminate(); } @@ -272,7 +272,7 @@ static BOOL reload_nmbd_services(BOOL test) **************************************************************************** */ static void msg_reload_nmbd_services(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { write_browse_list( 0, True ); dump_all_namelists(); @@ -289,7 +289,7 @@ static void msg_reload_nmbd_services(int msg_type, struct process_id src, } static void msg_nmbd_send_packet(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { struct packet_struct *p = (struct packet_struct *)buf; struct subnet_record *subrec; @@ -558,7 +558,7 @@ static void process(void) if(reload_after_sighup) { DEBUG( 0, ( "Got SIGHUP dumping debug info.\n" ) ); msg_reload_nmbd_services(MSG_SMB_CONF_UPDATED, - pid_to_procid(0), (void*) &no_subnets, 0); + pid_to_procid(0), (void*) &no_subnets, 0, NULL); if(no_subnets) return; reload_after_sighup = 0; @@ -745,14 +745,14 @@ static BOOL open_sockets(BOOL isdaemon, int port) pidfile_create("nmbd"); message_init(); - message_register(MSG_FORCE_ELECTION, nmbd_message_election); + message_register(MSG_FORCE_ELECTION, nmbd_message_election, NULL); #if 0 /* Until winsrepl is done. */ - message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry); + message_register(MSG_WINS_NEW_ENTRY, nmbd_wins_new_entry, NULL); #endif - message_register(MSG_SHUTDOWN, nmbd_terminate); - message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services); - message_register(MSG_SEND_PACKET, msg_nmbd_send_packet); + message_register(MSG_SHUTDOWN, nmbd_terminate, NULL); + message_register(MSG_SMB_CONF_UPDATED, msg_reload_nmbd_services, NULL); + message_register(MSG_SEND_PACKET, msg_nmbd_send_packet, NULL); TimeInit(); diff --git a/source/nmbd/nmbd_elections.c b/source/nmbd/nmbd_elections.c index 50e13729361..3aadd70b83c 100644 --- a/source/nmbd/nmbd_elections.c +++ b/source/nmbd/nmbd_elections.c @@ -379,7 +379,7 @@ yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name )); ***************************************************************************/ void nmbd_message_election(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { struct subnet_record *subrec; diff --git a/source/nmbd/nmbd_winsserver.c b/source/nmbd/nmbd_winsserver.c index 320415503b3..6ea102c3913 100644 --- a/source/nmbd/nmbd_winsserver.c +++ b/source/nmbd/nmbd_winsserver.c @@ -2371,7 +2371,7 @@ void wins_write_database(time_t t, BOOL background) ***************************************************************************/ void nmbd_wins_new_entry(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { WINS_RECORD *record; struct name_record *namerec = NULL; diff --git a/source/nsswitch/winbindd.c b/source/nsswitch/winbindd.c index 1df1a1d27b8..341fa00c923 100644 --- a/source/nsswitch/winbindd.c +++ b/source/nsswitch/winbindd.c @@ -34,6 +34,16 @@ static BOOL interactive = False; extern BOOL override_logfile; +struct event_context *winbind_event_context(void) +{ + static struct event_context *ctx; + + if (!ctx && !(ctx = event_context_init(NULL))) { + smb_panic("Could not init winbind event context\n"); + } + return ctx; +} + /* Reload configuration */ static BOOL reload_services_file(void) @@ -164,7 +174,8 @@ static void sigchld_handler(int signum) } /* React on 'smbcontrol winbindd reload-config' in the same way as on SIGHUP*/ -static void msg_reload_services(int msg_type, struct process_id src, void *buf, size_t len) +static void msg_reload_services(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { /* Flush various caches */ flush_caches(); @@ -172,7 +183,8 @@ static void msg_reload_services(int msg_type, struct process_id src, void *buf, } /* React on 'smbcontrol winbindd shutdown' in the same way as on SIGTERM*/ -static void msg_shutdown(int msg_type, struct process_id src, void *buf, size_t len) +static void msg_shutdown(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { do_sigterm = True; } @@ -718,7 +730,7 @@ static void process_loop(void) message_dispatch(); - run_events(); + run_events(winbind_event_context(), 0, NULL, NULL); /* refresh the trusted domain cache */ @@ -750,7 +762,7 @@ static void process_loop(void) timeout.tv_usec = 0; /* Check for any event timeouts. */ - if (get_timed_events_timeout(&ev_timeout)) { + if (get_timed_events_timeout(winbind_event_context(), &ev_timeout)) { timeout = timeval_min(&timeout, &ev_timeout); } @@ -869,7 +881,7 @@ static void process_loop(void) DEBUG(3, ("got SIGHUP\n")); - msg_reload_services(MSG_SMB_CONF_UPDATED, pid_to_procid(0), NULL, 0); + msg_reload_services(MSG_SMB_CONF_UPDATED, pid_to_procid(0), NULL, 0, NULL); do_sighup = False; } @@ -1053,13 +1065,14 @@ int main(int argc, char **argv, char **envp) /* React on 'smbcontrol winbindd reload-config' in the same way as to SIGHUP signal */ - message_register(MSG_SMB_CONF_UPDATED, msg_reload_services); - message_register(MSG_SHUTDOWN, msg_shutdown); + message_register(MSG_SMB_CONF_UPDATED, msg_reload_services, NULL); + message_register(MSG_SHUTDOWN, msg_shutdown, NULL); /* Handle online/offline messages. */ - message_register(MSG_WINBIND_OFFLINE,winbind_msg_offline); - message_register(MSG_WINBIND_ONLINE,winbind_msg_online); - message_register(MSG_WINBIND_ONLINESTATUS,winbind_msg_onlinestatus); + message_register(MSG_WINBIND_OFFLINE, winbind_msg_offline, NULL); + message_register(MSG_WINBIND_ONLINE, winbind_msg_online, NULL); + message_register(MSG_WINBIND_ONLINESTATUS, winbind_msg_onlinestatus, + NULL); poptFreeContext(pc); diff --git a/source/nsswitch/winbindd_cm.c b/source/nsswitch/winbindd_cm.c index f39d3ff06ae..e1434ef32bb 100644 --- a/source/nsswitch/winbindd_cm.c +++ b/source/nsswitch/winbindd_cm.c @@ -82,7 +82,8 @@ static BOOL get_dcs(TALLOC_CTX *mem_ctx, const struct winbindd_domain *domain, Child failed to find DC's. Reschedule check. ****************************************************************/ -static void msg_failed_to_go_online(int msg_type, struct process_id src, void *buf, size_t len) +static void msg_failed_to_go_online(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { struct winbindd_domain *domain; const char *domainname = (const char *)buf; @@ -117,7 +118,8 @@ static void msg_failed_to_go_online(int msg_type, struct process_id src, void *b Actually cause a reconnect from a message. ****************************************************************/ -static void msg_try_to_go_online(int msg_type, struct process_id src, void *buf, size_t len) +static void msg_try_to_go_online(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { struct winbindd_domain *domain; const char *domainname = (const char *)buf; @@ -182,8 +184,10 @@ static BOOL fork_child_dc_connect(struct winbindd_domain *domain) if (child_pid != 0) { /* Parent */ - message_register(MSG_WINBIND_TRY_TO_GO_ONLINE,msg_try_to_go_online); - message_register(MSG_WINBIND_FAILED_TO_GO_ONLINE,msg_failed_to_go_online); + message_register(MSG_WINBIND_TRY_TO_GO_ONLINE, + msg_try_to_go_online, NULL); + message_register(MSG_WINBIND_FAILED_TO_GO_ONLINE, + msg_failed_to_go_online, NULL); message_unblock(); return True; } @@ -234,7 +238,8 @@ static BOOL fork_child_dc_connect(struct winbindd_domain *domain) Handler triggered if we're offline to try and detect a DC. ****************************************************************/ -static void check_domain_online_handler(struct timed_event *te, +static void check_domain_online_handler(struct event_context *ctx, + struct timed_event *te, const struct timeval *now, void *private_data) { @@ -330,7 +335,8 @@ void set_domain_offline(struct winbindd_domain *domain) calc_new_online_timeout_check(domain); - domain->check_online_event = add_timed_event( NULL, + domain->check_online_event = event_add_timed(winbind_event_context(), + NULL, timeval_current_ofs(domain->check_online_timeout,0), "check_domain_online_handler", check_domain_online_handler, @@ -370,7 +376,8 @@ static void set_domain_online(struct winbindd_domain *domain) /* If we are waiting to get a krb5 ticket, trigger immediately. */ GetTimeOfDay(&now); - set_event_dispatch_time("krb5_ticket_gain_handler", now); + set_event_dispatch_time(winbind_event_context(), + "krb5_ticket_gain_handler", now); /* Ok, we're out of any startup mode now... */ domain->startup = False; @@ -435,11 +442,12 @@ void set_domain_online_request(struct winbindd_domain *domain) DEBUG(10,("set_domain_online_request: domain %s was globally offline.\n", domain->name )); - domain->check_online_event = add_timed_event( NULL, - timeval_current_ofs(5, 0), - "check_domain_online_handler", - check_domain_online_handler, - domain); + domain->check_online_event = event_add_timed(winbind_event_context(), + NULL, + timeval_current_ofs(5, 0), + "check_domain_online_handler", + check_domain_online_handler, + domain); /* The above *has* to succeed for winbindd to work. */ if (!domain->check_online_event) { @@ -454,7 +462,8 @@ void set_domain_online_request(struct winbindd_domain *domain) domain->startup = True; tev.tv_sec += 5; - set_event_dispatch_time("check_domain_online_handler", tev); + + set_event_dispatch_time(winbind_event_context(), "check_domain_online_handler", tev); } /**************************************************************** diff --git a/source/nsswitch/winbindd_cred_cache.c b/source/nsswitch/winbindd_cred_cache.c index 6f629ad15c2..50d39dd670b 100644 --- a/source/nsswitch/winbindd_cred_cache.c +++ b/source/nsswitch/winbindd_cred_cache.c @@ -66,7 +66,8 @@ static int ccache_entry_count(void) Do the work of refreshing the ticket. ****************************************************************/ -static void krb5_ticket_refresh_handler(struct timed_event *te, +static void krb5_ticket_refresh_handler(struct event_context *event_ctx, + struct timed_event *te, const struct timeval *now, void *private_data) { @@ -145,7 +146,7 @@ static void krb5_ticket_refresh_handler(struct timed_event *te, done: - entry->event = add_timed_event(entry, + entry->event = event_add_timed(winbind_event_context(), entry, timeval_set(new_start, 0), "krb5_ticket_refresh_handler", krb5_ticket_refresh_handler, @@ -158,7 +159,8 @@ done: Do the work of regaining a ticket when coming from offline auth. ****************************************************************/ -static void krb5_ticket_gain_handler(struct timed_event *te, +static void krb5_ticket_gain_handler(struct event_context *event_ctx, + struct timed_event *te, const struct timeval *now, void *private_data) { @@ -220,7 +222,7 @@ static void krb5_ticket_gain_handler(struct timed_event *te, retry_later: - entry->event = add_timed_event(entry, + entry->event = event_add_timed(winbind_event_context(), entry, timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0), "krb5_ticket_gain_handler", krb5_ticket_gain_handler, @@ -236,7 +238,7 @@ static void krb5_ticket_gain_handler(struct timed_event *te, t = timeval_set(new_start, 0); #endif /* TESTING */ - entry->event = add_timed_event(entry, + entry->event = event_add_timed(winbind_event_context(), entry, t, "krb5_ticket_refresh_handler", krb5_ticket_refresh_handler, @@ -349,13 +351,13 @@ NTSTATUS add_ccache_to_list(const char *princ_name, if (lp_winbind_refresh_tickets() && renew_until > 0) { if (postponed_request) { - entry->event = add_timed_event(entry, + entry->event = event_add_timed(winbind_event_context(), entry, timeval_current_ofs(MAX(30, lp_winbind_cache_time()), 0), "krb5_ticket_gain_handler", krb5_ticket_gain_handler, entry); } else { - entry->event = add_timed_event(entry, + entry->event = event_add_timed(winbind_event_context(), entry, timeval_set((ticket_end - 1), 0), "krb5_ticket_refresh_handler", krb5_ticket_refresh_handler, diff --git a/source/nsswitch/winbindd_dual.c b/source/nsswitch/winbindd_dual.c index 4a652e47dac..edb4fa504b1 100644 --- a/source/nsswitch/winbindd_dual.c +++ b/source/nsswitch/winbindd_dual.c @@ -476,7 +476,8 @@ void winbindd_flush_negative_conn_cache(struct winbindd_domain *domain) /* Set our domains as offline and forward the offline message to our children. */ -void winbind_msg_offline(int msg_type, struct process_id src, void *buf, size_t len) +void winbind_msg_offline(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { struct winbindd_child *child; struct winbindd_domain *domain; @@ -527,7 +528,8 @@ void winbind_msg_offline(int msg_type, struct process_id src, void *buf, size_t /* Set our domains as online and forward the online message to our children. */ -void winbind_msg_online(int msg_type, struct process_id src, void *buf, size_t len) +void winbind_msg_online(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { struct winbindd_child *child; struct winbindd_domain *domain; @@ -579,7 +581,8 @@ void winbind_msg_online(int msg_type, struct process_id src, void *buf, size_t l } /* Forward the online/offline messages to our children. */ -void winbind_msg_onlinestatus(int msg_type, struct process_id src, void *buf, size_t len) +void winbind_msg_onlinestatus(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { struct winbindd_child *child; @@ -598,7 +601,8 @@ void winbind_msg_onlinestatus(int msg_type, struct process_id src, void *buf, si } -static void account_lockout_policy_handler(struct timed_event *te, +static void account_lockout_policy_handler(struct event_context *ctx, + struct timed_event *te, const struct timeval *now, void *private_data) { @@ -631,7 +635,7 @@ static void account_lockout_policy_handler(struct timed_event *te, nt_errstr(result))); } - child->lockout_policy_event = add_timed_event(NULL, + child->lockout_policy_event = event_add_timed(winbind_event_context(), NULL, timeval_current_ofs(3600, 0), "account_lockout_policy_handler", account_lockout_policy_handler, @@ -640,7 +644,8 @@ static void account_lockout_policy_handler(struct timed_event *te, /* Deal with a request to go offline. */ -static void child_msg_offline(int msg_type, struct process_id src, void *buf, size_t len) +static void child_msg_offline(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { struct winbindd_domain *domain; const char *domainname = (const char *)buf; @@ -677,7 +682,8 @@ static void child_msg_offline(int msg_type, struct process_id src, void *buf, si /* Deal with a request to go online. */ -static void child_msg_online(int msg_type, struct process_id src, void *buf, size_t len) +static void child_msg_online(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { struct winbindd_domain *domain; const char *domainname = (const char *)buf; @@ -738,7 +744,8 @@ static const char *collect_onlinestatus(TALLOC_CTX *mem_ctx) return buf; } -static void child_msg_onlinestatus(int msg_type, struct process_id src, void *buf, size_t len) +static void child_msg_onlinestatus(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { TALLOC_CTX *mem_ctx; const char *message; @@ -842,9 +849,10 @@ static BOOL fork_domain_child(struct winbindd_child *child) message_unblock(); /* Handle online/offline messages. */ - message_register(MSG_WINBIND_OFFLINE,child_msg_offline); - message_register(MSG_WINBIND_ONLINE,child_msg_online); - message_register(MSG_WINBIND_ONLINESTATUS,child_msg_onlinestatus); + message_register(MSG_WINBIND_OFFLINE, child_msg_offline, NULL); + message_register(MSG_WINBIND_ONLINE, child_msg_online, NULL); + message_register(MSG_WINBIND_ONLINESTATUS, child_msg_onlinestatus, + NULL); if ( child->domain ) { child->domain->startup = True; @@ -865,7 +873,8 @@ static BOOL fork_domain_child(struct winbindd_child *child) /* Ensure we're not handling an event inherited from our parent. */ - cancel_named_event("krb5_ticket_refresh_handler"); + cancel_named_event(winbind_event_context(), + "krb5_ticket_refresh_handler"); /* We might be in the idmap child...*/ if (child->domain && !(child->domain->internal) && @@ -873,8 +882,8 @@ static BOOL fork_domain_child(struct winbindd_child *child) set_domain_online_request(child->domain); - child->lockout_policy_event = add_timed_event( - NULL, timeval_zero(), + child->lockout_policy_event = event_add_timed( + winbind_event_context(), NULL, timeval_zero(), "account_lockout_policy_handler", account_lockout_policy_handler, child); @@ -892,7 +901,7 @@ static BOOL fork_domain_child(struct winbindd_child *child) lp_TALLOC_FREE(); main_loop_TALLOC_FREE(); - run_events(); + run_events(winbind_event_context(), 0, NULL, NULL); GetTimeOfDay(&now); @@ -904,7 +913,7 @@ static BOOL fork_domain_child(struct winbindd_child *child) child->domain->startup = False; } - tp = get_timed_events_timeout(&t); + tp = get_timed_events_timeout(winbind_event_context(), &t); if (tp) { DEBUG(11,("select will use timeout of %u.%u seconds\n", (unsigned int)tp->tv_sec, (unsigned int)tp->tv_usec )); diff --git a/source/param/loadparm.c b/source/param/loadparm.c index 469976325c0..976810ee153 100644 --- a/source/param/loadparm.c +++ b/source/param/loadparm.c @@ -299,8 +299,6 @@ typedef struct { BOOL bHostnameLookups; BOOL bUnixExtensions; BOOL bDisableNetbios; - BOOL bKernelChangeNotify; - BOOL bFamChangeNotify; BOOL bUseKerberosKeytab; BOOL bDeferSharingViolations; BOOL bEnablePrivileges; @@ -451,11 +449,12 @@ typedef struct { BOOL bAclCheckPermissions; BOOL bAclMapFullControl; BOOL bAclGroupControl; + BOOL bChangeNotify; + BOOL bKernelChangeNotify; int iallocation_roundup_size; int iAioReadSize; int iAioWriteSize; int iMap_readonly; - int ichange_notify_timeout; param_opt_struct *param_opt; char dummy[3]; /* for alignment */ @@ -590,11 +589,12 @@ static service sDefault = { True, /* bAclCheckPermissions */ True, /* bAclMapFullControl */ False, /* bAclGroupControl */ + True, /* bChangeNotify */ + True, /* bKernelChangeNotify */ SMB_ROUNDUP_ALLOCATION_SIZE, /* iallocation_roundup_size */ 0, /* iAioReadSize */ 0, /* iAioWriteSize */ MAP_READONLY_YES, /* iMap_readonly */ - 60, /* ichange_notify_timeout = 1 minute default. */ NULL, /* Parametric options */ @@ -1005,12 +1005,11 @@ static struct parm_struct parm_table[] = { {N_("Tuning Options"), P_SEP, P_SEPARATOR}, {"block size", P_INTEGER, P_LOCAL, &sDefault.iBlock_size, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE | FLAG_GLOBAL}, - {"change notify timeout", P_INTEGER, P_LOCAL, &sDefault.ichange_notify_timeout, NULL, NULL, FLAG_ADVANCED}, {"deadtime", P_INTEGER, P_GLOBAL, &Globals.deadtime, NULL, NULL, FLAG_ADVANCED}, {"getwd cache", P_BOOL, P_GLOBAL, &use_getwd_cache, NULL, NULL, FLAG_ADVANCED}, {"keepalive", P_INTEGER, P_GLOBAL, &keepalive, NULL, NULL, FLAG_ADVANCED}, - {"kernel change notify", P_BOOL, P_GLOBAL, &Globals.bKernelChangeNotify, NULL, NULL, FLAG_ADVANCED}, - {"fam change notify", P_BOOL, P_GLOBAL, &Globals.bFamChangeNotify, NULL, NULL, FLAG_ADVANCED}, + {"change notify", P_BOOL, P_LOCAL, &sDefault.bChangeNotify, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE }, + {"kernel change notify", P_BOOL, P_LOCAL, &sDefault.bKernelChangeNotify, NULL, NULL, FLAG_ADVANCED | FLAG_SHARE }, {"lpq cache time", P_INTEGER, P_GLOBAL, &Globals.lpqcachetime, NULL, NULL, FLAG_ADVANCED}, {"max smbd processes", P_INTEGER, P_GLOBAL, &Globals.iMaxSmbdProcesses, NULL, NULL, FLAG_ADVANCED}, @@ -1522,8 +1521,6 @@ static void init_globals(BOOL first_time_only) Globals.max_wins_ttl = 60 * 60 * 24 * 6; /* 6 days default. */ Globals.min_wins_ttl = 60 * 60 * 6; /* 6 hours default. */ Globals.machine_password_timeout = 60 * 60 * 24 * 7; /* 7 days default. */ - Globals.bKernelChangeNotify = True; /* On if we have it. */ - Globals.bFamChangeNotify = True; /* On if we have it. */ Globals.lm_announce = 2; /* = Auto: send only if LM clients found */ Globals.lm_interval = 60; Globals.announce_as = ANNOUNCE_AS_NT_SERVER; @@ -1934,8 +1931,8 @@ FN_GLOBAL_BOOL(lp_unix_extensions, &Globals.bUnixExtensions) FN_GLOBAL_BOOL(lp_use_spnego, &Globals.bUseSpnego) FN_GLOBAL_BOOL(lp_client_use_spnego, &Globals.bClientUseSpnego) FN_GLOBAL_BOOL(lp_hostname_lookups, &Globals.bHostnameLookups) -FN_GLOBAL_BOOL(lp_kernel_change_notify, &Globals.bKernelChangeNotify) -FN_GLOBAL_BOOL(lp_fam_change_notify, &Globals.bFamChangeNotify) +FN_LOCAL_PARM_BOOL(lp_change_notify, bChangeNotify) +FN_LOCAL_PARM_BOOL(lp_kernel_change_notify, bKernelChangeNotify) FN_GLOBAL_BOOL(lp_use_kerberos_keytab, &Globals.bUseKerberosKeytab) FN_GLOBAL_BOOL(lp_defer_sharing_violations, &Globals.bDeferSharingViolations) FN_GLOBAL_BOOL(lp_enable_privileges, &Globals.bEnablePrivileges) @@ -2097,7 +2094,6 @@ FN_LOCAL_INTEGER(lp_allocation_roundup_size, iallocation_roundup_size) FN_LOCAL_INTEGER(lp_aio_read_size, iAioReadSize) FN_LOCAL_INTEGER(lp_aio_write_size, iAioWriteSize) FN_LOCAL_INTEGER(lp_map_readonly, iMap_readonly) -FN_LOCAL_INTEGER(lp_change_notify_timeout, ichange_notify_timeout) FN_LOCAL_CHAR(lp_magicchar, magic_char) FN_GLOBAL_INTEGER(lp_winbind_cache_time, &Globals.winbind_cache_time) FN_GLOBAL_LIST(lp_winbind_nss_info, &Globals.szWinbindNssInfo) diff --git a/source/printing/nt_printing.c b/source/printing/nt_printing.c index 4a6b2e0a6de..5b5f82d1f48 100644 --- a/source/printing/nt_printing.c +++ b/source/printing/nt_printing.c @@ -629,14 +629,15 @@ BOOL nt_printing_init(void) * drivers are installed */ - message_register( MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer ); + message_register(MSG_PRINTER_DRVUPGRADE, do_drv_upgrade_printer, NULL); /* * register callback to handle updating printer data * when a driver is initialized */ - message_register( MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata ); + message_register(MSG_PRINTERDATA_INIT_RESET, reset_all_printerdata, + NULL); /* of course, none of the message callbacks matter if you don't tell messages.c that you interested in receiving PRINT_GENERAL diff --git a/source/printing/printing.c b/source/printing/printing.c index 2f1d123a200..588641358f3 100644 --- a/source/printing/printing.c +++ b/source/printing/printing.c @@ -1352,7 +1352,8 @@ static void print_queue_update_with_lock( const char *sharename, this is the receive function of the background lpq updater ****************************************************************************/ static void print_queue_receive(int msg_type, struct process_id src, - void *buf, size_t msglen) + void *buf, size_t msglen, + void *private_data) { fstring sharename; pstring lpqcommand, lprmcommand; @@ -1403,7 +1404,8 @@ void start_background_queue(void) exit(1); } - message_register(MSG_PRINTER_UPDATE, print_queue_receive); + message_register(MSG_PRINTER_UPDATE, print_queue_receive, + NULL); DEBUG(5,("start_background_queue: background LPQ thread waiting for messages\n")); while (1) { diff --git a/source/rpc_server/srv_spoolss_nt.c b/source/rpc_server/srv_spoolss_nt.c index 2a997722a0e..f5a2298fe97 100644 --- a/source/rpc_server/srv_spoolss_nt.c +++ b/source/rpc_server/srv_spoolss_nt.c @@ -1099,7 +1099,8 @@ static BOOL notify2_unpack_msg( SPOOLSS_NOTIFY_MSG *msg, struct timeval *tv, voi ********************************************************************/ static void receive_notify2_message_list(int msg_type, struct process_id src, - void *msg, size_t len) + void *msg, size_t len, + void *private_data) { size_t msg_count, i; char *buf = (char *)msg; @@ -1211,7 +1212,8 @@ static BOOL srv_spoolss_drv_upgrade_printer(char* drivername) over all printers, upgrading ones as necessary **********************************************************************/ -void do_drv_upgrade_printer(int msg_type, struct process_id src, void *buf, size_t len) +void do_drv_upgrade_printer(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { fstring drivername; int snum; @@ -1309,7 +1311,7 @@ static BOOL srv_spoolss_reset_printerdata(char* drivername) **********************************************************************/ void reset_all_printerdata(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { fstring drivername; int snum; @@ -2598,7 +2600,8 @@ static BOOL srv_spoolss_replyopenprinter(int snum, const char *printer, if ( !spoolss_connect_to_client( ¬ify_cli_pipe, client_ip, unix_printer )) return False; - message_register(MSG_PRINTER_NOTIFY2, receive_notify2_message_list); + message_register(MSG_PRINTER_NOTIFY2, + receive_notify2_message_list, NULL); /* Tell the connections db we're now interested in printer * notify messages. */ register_message_flags( True, FLAG_MSG_PRINT_NOTIFY ); diff --git a/source/rpc_server/srv_srvsvc_nt.c b/source/rpc_server/srv_srvsvc_nt.c index b7e63fcce13..17247b65938 100644 --- a/source/rpc_server/srv_srvsvc_nt.c +++ b/source/rpc_server/srv_srvsvc_nt.c @@ -1190,7 +1190,7 @@ WERROR _srv_net_sess_del(pipes_struct *p, SRV_Q_NET_SESS_DEL *q_u, SRV_R_NET_SES become_root(); } - if (message_send_pid(pid_to_procid(session_list[snum].pid), MSG_SHUTDOWN, NULL, 0, False)) + if (NT_STATUS_IS_OK(message_send_pid(pid_to_procid(session_list[snum].pid), MSG_SHUTDOWN, NULL, 0, False))) r_u->status = WERR_OK; if (not_root) diff --git a/source/smbd/blocking.c b/source/smbd/blocking.c index e0478fa762f..70b2d30aaba 100644 --- a/source/smbd/blocking.c +++ b/source/smbd/blocking.c @@ -71,7 +71,8 @@ static BOOL in_chained_smb(void) } static void received_unlock_msg(int msg_type, struct process_id src, - void *buf, size_t len); + void *buf, size_t len, + void *private_data); /**************************************************************************** Function to push a blocking lock request onto the lock queue. @@ -154,7 +155,8 @@ BOOL push_blocking_lock_request( struct byte_range_lock *br_lck, /* Ensure we'll receive messages when this is unlocked. */ if (!set_lock_msg) { - message_register(MSG_SMB_UNLOCK, received_unlock_msg); + message_register(MSG_SMB_UNLOCK, received_unlock_msg, + NULL); set_lock_msg = True; } @@ -581,7 +583,8 @@ BOOL blocking_lock_was_deferred(int mid) *****************************************************************************/ static void received_unlock_msg(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, + void *private_data) { DEBUG(10,("received_unlock_msg\n")); process_blocking_lock_queue(); @@ -775,8 +778,10 @@ void process_blocking_lock_queue(void) #define MSG_BLOCKING_LOCK_CANCEL_SIZE (sizeof(blocking_lock_record *) + sizeof(NTSTATUS)) -static void process_blocking_lock_cancel_message(int msg_type, struct process_id src, - void *buf, size_t len) +static void process_blocking_lock_cancel_message(int msg_type, + struct process_id src, + void *buf, size_t len, + void *private_data) { NTSTATUS err; const char *msg = (const char *)buf; @@ -822,7 +827,8 @@ BOOL blocking_lock_cancel(files_struct *fsp, if (!initialized) { /* Register our message. */ message_register(MSG_SMB_BLOCKING_LOCK_CANCEL, - process_blocking_lock_cancel_message); + process_blocking_lock_cancel_message, + NULL); initialized = True; } diff --git a/source/smbd/close.c b/source/smbd/close.c index ea0d807041c..b826cd622af 100644 --- a/source/smbd/close.c +++ b/source/smbd/close.c @@ -301,8 +301,6 @@ static NTSTATUS close_remove_share_mode(files_struct *fsp, /* unbecome user. */ pop_sec_ctx(); - process_pending_change_notify_queue((time_t)0); - TALLOC_FREE(lck); return status; } @@ -496,10 +494,7 @@ static NTSTATUS close_directory(files_struct *fsp, enum file_close_type close_ty if(NT_STATUS_IS_OK(status)) { remove_pending_change_notify_requests_by_fid(fsp, NT_STATUS_DELETE_PENDING); - remove_pending_change_notify_requests_by_filename(fsp, NT_STATUS_DELETE_PENDING); - } - process_pending_change_notify_queue((time_t)0); } else { TALLOC_FREE(lck); remove_pending_change_notify_requests_by_fid( diff --git a/source/smbd/conn.c b/source/smbd/conn.c index 083e8339c80..44888b777f2 100644 --- a/source/smbd/conn.c +++ b/source/smbd/conn.c @@ -311,7 +311,8 @@ the message contains just a share name and all instances of that share are unmounted the special sharename '*' forces unmount of all shares ****************************************************************************/ -void msg_force_tdis(int msg_type, struct process_id pid, void *buf, size_t len) +void msg_force_tdis(int msg_type, struct process_id pid, void *buf, size_t len, + void *private_data) { connection_struct *conn, *next; fstring sharename; diff --git a/source/smbd/dosmode.c b/source/smbd/dosmode.c index ff4291c08c8..ad79bbacddf 100644 --- a/source/smbd/dosmode.c +++ b/source/smbd/dosmode.c @@ -491,8 +491,11 @@ int file_set_dosmode(connection_struct *conn, const char *fname, unixmode |= (st->st_mode & (S_IWUSR|S_IWGRP|S_IWOTH)); } - if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) + if ((ret = SMB_VFS_CHMOD(conn,fname,unixmode)) == 0) { + notify_fname(conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); return 0; + } if((errno != EPERM) && (errno != EACCES)) return -1; @@ -521,6 +524,8 @@ int file_set_dosmode(connection_struct *conn, const char *fname, ret = SMB_VFS_FCHMOD(fsp, fsp->fh->fd, unixmode); unbecome_root(); close_file_fchmod(fsp); + notify_fname(conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_ATTRIBUTES, fname); } return( ret ); @@ -593,6 +598,9 @@ BOOL set_filetime(connection_struct *conn, const char *fname, time_t mtime) DEBUG(4,("set_filetime(%s) failed: %s\n",fname,strerror(errno))); return False; } + + notify_fname(conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_LAST_WRITE, fname); return(True); } diff --git a/source/smbd/files.c b/source/smbd/files.c index 7069818dee4..66ef37bb0fa 100644 --- a/source/smbd/files.c +++ b/source/smbd/files.c @@ -439,6 +439,11 @@ void file_free(files_struct *fsp) fsp->fh->ref_count--; } + if (fsp->notify) { + notify_remove(fsp->conn->notify_ctx, fsp); + TALLOC_FREE(fsp->notify); + } + bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET); files_used--; diff --git a/source/smbd/notify.c b/source/smbd/notify.c index 4ec53567dd4..cf60720bc74 100644 --- a/source/smbd/notify.c +++ b/source/smbd/notify.c @@ -3,6 +3,7 @@ change notify handling Copyright (C) Andrew Tridgell 2000 Copyright (C) Jeremy Allison 1994-1998 + Copyright (C) Volker Lendecke 2007 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -21,36 +22,95 @@ #include "includes.h" -static struct cnotify_fns *cnotify; +struct notify_change_request { + struct notify_change_request *prev, *next; + struct files_struct *fsp; /* backpointer for cancel by mid */ + char request_buf[smb_size]; + uint32 filter; + uint32 max_param_count; + uint32 current_bufsize; + struct notify_mid_map *mid_map; + void *backend_data; +}; -/**************************************************************************** - This is the structure to queue to implement NT change - notify. It consists of smb_size bytes stored from the - transact command (to keep the mid, tid etc around). - Plus the fid to examine and notify private data. -*****************************************************************************/ +static void notify_fsp(files_struct *fsp, uint32 action, const char *name); -struct change_notify { - struct change_notify *next, *prev; - files_struct *fsp; - connection_struct *conn; - uint32 flags; - char request_buf[smb_size]; - void *change_data; +static struct notify_mid_map *notify_changes_by_mid; + +/* + * For NTCancel, we need to find the notify_change_request indexed by + * mid. Separate list here. + */ + +struct notify_mid_map { + struct notify_mid_map *prev, *next; + struct notify_change_request *req; + uint16 mid; }; -static struct change_notify *change_notify_list; +static BOOL notify_marshall_changes(int num_changes, + struct notify_change *changes, + prs_struct *ps) +{ + int i; + UNISTR uni_name; + + for (i=0; iname, strlen(c->name)+1, + &uni_name.buffer, True); + if ((namelen == -1) || (uni_name.buffer == NULL)) { + goto fail; + } + + namelen -= 2; /* Dump NULL termination */ + + /* + * Offset to next entry, only if there is one + */ + + u32_tmp = (i == num_changes-1) ? 0 : namelen + 12; + if (!prs_uint32("offset", ps, 1, &u32_tmp)) goto fail; + + u32_tmp = c->action; + if (!prs_uint32("action", ps, 1, &u32_tmp)) goto fail; + + u32_tmp = namelen; + if (!prs_uint32("namelen", ps, 1, &u32_tmp)) goto fail; + + if (!prs_unistr("name", ps, 1, &uni_name)) goto fail; + + /* + * Not NULL terminated, decrease by the 2 UCS2 \0 chars + */ + prs_set_offset(ps, prs_offset(ps)-2); + + SAFE_FREE(uni_name.buffer); + } + + return True; + + fail: + SAFE_FREE(uni_name.buffer); + return False; +} /**************************************************************************** Setup the common parts of the return packet and send it. *****************************************************************************/ -static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code) +static void change_notify_reply_packet(const char *request_buf, + NTSTATUS error_code) { char outbuf[smb_size+38]; memset(outbuf, '\0', sizeof(outbuf)); - construct_reply_common(inbuf, outbuf); + construct_reply_common(request_buf, outbuf); ERROR_NT(error_code); @@ -62,193 +122,363 @@ static void change_notify_reply_packet(char *inbuf, NTSTATUS error_code) show_msg(outbuf); if (!send_smb(smbd_server_fd(),outbuf)) - exit_server_cleanly("change_notify_reply_packet: send_smb failed."); + exit_server_cleanly("change_notify_reply_packet: send_smb " + "failed."); } -/**************************************************************************** - Remove an entry from the list and free it, also closing any - directory handle if necessary. -*****************************************************************************/ +void change_notify_reply(const char *request_buf, uint32 max_param_count, + struct notify_change_buf *notify_buf) +{ + char *outbuf = NULL; + prs_struct ps; + size_t buflen = smb_size+38+max_param_count; + + if (notify_buf->num_changes == -1) { + change_notify_reply_packet(request_buf, NT_STATUS_OK); + return; + } + + if (!prs_init(&ps, 0, NULL, False) + || !notify_marshall_changes(notify_buf->num_changes, + notify_buf->changes, &ps)) { + change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY); + goto done; + } -static void change_notify_remove(struct change_notify *cnbp) + if (prs_offset(&ps) > max_param_count) { + /* + * We exceed what the client is willing to accept. Send + * nothing. + */ + change_notify_reply_packet(request_buf, NT_STATUS_OK); + goto done; + } + + if (!(outbuf = SMB_MALLOC_ARRAY(char, buflen))) { + change_notify_reply_packet(request_buf, NT_STATUS_NO_MEMORY); + goto done; + } + + construct_reply_common(request_buf, outbuf); + + if (send_nt_replies(outbuf, buflen, NT_STATUS_OK, prs_data_p(&ps), + prs_offset(&ps), NULL, 0) == -1) { + exit_server("change_notify_reply_packet: send_smb failed."); + } + + done: + SAFE_FREE(outbuf); + prs_mem_free(&ps); + + TALLOC_FREE(notify_buf->changes); + notify_buf->num_changes = 0; +} + +static void notify_callback(void *private_data, const struct notify_event *e) { - cnotify->remove_notify(cnbp->change_data); - DLIST_REMOVE(change_notify_list, cnbp); - ZERO_STRUCTP(cnbp); - SAFE_FREE(cnbp); + files_struct *fsp = (files_struct *)private_data; + DEBUG(10, ("notify_callback called for %s\n", fsp->fsp_name)); + notify_fsp(fsp, e->action, e->path); } -/**************************************************************************** - Delete entries by fnum from the change notify pending queue. -*****************************************************************************/ +NTSTATUS change_notify_create(struct files_struct *fsp, uint32 filter, + BOOL recursive) +{ + char *fullpath; + struct notify_entry e; + NTSTATUS status; + + SMB_ASSERT(fsp->notify == NULL); + + if (!(fsp->notify = TALLOC_ZERO_P(NULL, struct notify_change_buf))) { + DEBUG(0, ("talloc failed\n")); + return NT_STATUS_NO_MEMORY; + } + + if (asprintf(&fullpath, "%s/%s", fsp->conn->connectpath, + fsp->fsp_name) == -1) { + DEBUG(0, ("asprintf failed\n")); + return NT_STATUS_NO_MEMORY; + } + + e.path = fullpath; + e.filter = filter; + e.subdir_filter = 0; + if (recursive) { + e.subdir_filter = filter; + } -void remove_pending_change_notify_requests_by_fid(files_struct *fsp, NTSTATUS status) + status = notify_add(fsp->conn->notify_ctx, &e, notify_callback, fsp); + SAFE_FREE(fullpath); + + return status; +} + +NTSTATUS change_notify_add_request(const char *inbuf, uint32 max_param_count, + uint32 filter, BOOL recursive, + struct files_struct *fsp) { - struct change_notify *cnbp, *next; + struct notify_change_request *request = NULL; + struct notify_mid_map *map = NULL; + + if (!(request = SMB_MALLOC_P(struct notify_change_request)) + || !(map = SMB_MALLOC_P(struct notify_mid_map))) { + SAFE_FREE(request); + return NT_STATUS_NO_MEMORY; + } + + request->mid_map = map; + map->req = request; + + memcpy(request->request_buf, inbuf, sizeof(request->request_buf)); + request->max_param_count = max_param_count; + request->current_bufsize = 0; + request->filter = filter; + request->fsp = fsp; + request->backend_data = NULL; + + DLIST_ADD_END(fsp->notify->requests, request, + struct notify_change_request *); + + map->mid = SVAL(inbuf, smb_mid); + DLIST_ADD(notify_changes_by_mid, map); + + /* Push the MID of this packet on the signing queue. */ + srv_defer_sign_response(SVAL(inbuf,smb_mid)); - for (cnbp=change_notify_list; cnbp; cnbp=next) { - next=cnbp->next; - if (cnbp->fsp->fnum == fsp->fnum) { - change_notify_reply_packet(cnbp->request_buf,status); - change_notify_remove(cnbp); + return NT_STATUS_OK; +} + +static void change_notify_remove_request(struct notify_change_request *remove_req) +{ + files_struct *fsp; + struct notify_change_request *req; + + /* + * Paranoia checks, the fsp referenced must must have the request in + * its list of pending requests + */ + + fsp = remove_req->fsp; + SMB_ASSERT(fsp->notify != NULL); + + for (req = fsp->notify->requests; req; req = req->next) { + if (req == remove_req) { + break; } } + + if (req == NULL) { + smb_panic("notify_req not found in fsp's requests\n"); + } + + DLIST_REMOVE(fsp->notify->requests, req); + DLIST_REMOVE(notify_changes_by_mid, req->mid_map); + SAFE_FREE(req->mid_map); + TALLOC_FREE(req->backend_data); + SAFE_FREE(req); } /**************************************************************************** Delete entries by mid from the change notify pending queue. Always send reply. *****************************************************************************/ -void remove_pending_change_notify_requests_by_mid(int mid) +void remove_pending_change_notify_requests_by_mid(uint16 mid) { - struct change_notify *cnbp, *next; + struct notify_mid_map *map; - for (cnbp=change_notify_list; cnbp; cnbp=next) { - next=cnbp->next; - if(SVAL(cnbp->request_buf,smb_mid) == mid) { - change_notify_reply_packet(cnbp->request_buf,NT_STATUS_CANCELLED); - change_notify_remove(cnbp); + for (map = notify_changes_by_mid; map; map = map->next) { + if (map->mid == mid) { + break; } } + + if (map == NULL) { + return; + } + + change_notify_reply_packet(map->req->request_buf, NT_STATUS_CANCELLED); + change_notify_remove_request(map->req); } /**************************************************************************** - Delete entries by filename and cnum from the change notify pending queue. - Always send reply. + Delete entries by fnum from the change notify pending queue. *****************************************************************************/ -void remove_pending_change_notify_requests_by_filename(files_struct *fsp, NTSTATUS status) +void remove_pending_change_notify_requests_by_fid(files_struct *fsp, + NTSTATUS status) { - struct change_notify *cnbp, *next; + if (fsp->notify == NULL) { + return; + } - for (cnbp=change_notify_list; cnbp; cnbp=next) { - next=cnbp->next; - /* - * We know it refers to the same directory if the connection number and - * the filename are identical. - */ - if((cnbp->fsp->conn == fsp->conn) && strequal(cnbp->fsp->fsp_name,fsp->fsp_name)) { - change_notify_reply_packet(cnbp->request_buf,status); - change_notify_remove(cnbp); - } + while (fsp->notify->requests != NULL) { + change_notify_reply_packet( + fsp->notify->requests->request_buf, status); + change_notify_remove_request(fsp->notify->requests); } } -/**************************************************************************** - Set the current change notify timeout to the lowest value across all service - values. -****************************************************************************/ - -void set_change_notify_timeout(int val) +void notify_fname(connection_struct *conn, uint32 action, uint32 filter, + const char *path) { - if (val > 0) { - cnotify->select_time = MIN(cnotify->select_time, val); + char *fullpath; + + if (asprintf(&fullpath, "%s/%s", conn->connectpath, path) == -1) { + DEBUG(0, ("asprintf failed\n")); + return; } -} -/**************************************************************************** - Longest time to sleep for before doing a change notify scan. -****************************************************************************/ + notify_trigger(conn->notify_ctx, action, filter, fullpath); + SAFE_FREE(fullpath); +} -int change_notify_timeout(void) +static void notify_fsp(files_struct *fsp, uint32 action, const char *name) { - return cnotify->select_time; -} + struct notify_change *change, *changes; + char *name2; -/**************************************************************************** - Process the change notify queue. Note that this is only called as root. - Returns True if there are still outstanding change notify requests on the - queue. -*****************************************************************************/ + if (fsp->notify == NULL) { + /* + * Nobody is waiting, don't queue + */ + return; + } -BOOL process_pending_change_notify_queue(time_t t) -{ - struct change_notify *cnbp, *next; - uint16 vuid; + if (!(name2 = talloc_strdup(fsp->notify, name))) { + DEBUG(0, ("talloc_strdup failed\n")); + return; + } - for (cnbp=change_notify_list; cnbp; cnbp=next) { - next=cnbp->next; + string_replace(name2, '/', '\\'); - vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : SVAL(cnbp->request_buf,smb_uid); + /* + * Someone has triggered a notify previously, queue the change for + * later. + */ - if (cnotify->check_notify(cnbp->conn, vuid, cnbp->fsp->fsp_name, cnbp->flags, cnbp->change_data, t)) { - DEBUG(10,("process_pending_change_notify_queue: dir %s changed !\n", cnbp->fsp->fsp_name )); - change_notify_reply_packet(cnbp->request_buf,STATUS_NOTIFY_ENUM_DIR); - change_notify_remove(cnbp); - } + if ((fsp->notify->num_changes > 1000) || (name == NULL)) { + /* + * The real number depends on the client buf, just provide a + * guard against a DoS here. + */ + TALLOC_FREE(fsp->notify->changes); + TALLOC_FREE(name2); + fsp->notify->num_changes = -1; + return; } - return (change_notify_list != NULL); -} + if (fsp->notify->num_changes == -1) { + return; + } -/**************************************************************************** - Now queue an entry on the notify change list. - We only need to save smb_size bytes from this incoming packet - as we will always by returning a 'read the directory yourself' - error. -****************************************************************************/ + if (!(changes = TALLOC_REALLOC_ARRAY( + fsp->notify, fsp->notify->changes, + struct notify_change, fsp->notify->num_changes+1))) { + DEBUG(0, ("talloc_realloc failed\n")); + TALLOC_FREE(name2); + return; + } -BOOL change_notify_set(char *inbuf, files_struct *fsp, connection_struct *conn, uint32 flags) -{ - struct change_notify *cnbp; + fsp->notify->changes = changes; - if((cnbp = SMB_MALLOC_P(struct change_notify)) == NULL) { - DEBUG(0,("change_notify_set: malloc fail !\n" )); - return -1; - } + change = &(fsp->notify->changes[fsp->notify->num_changes]); - ZERO_STRUCTP(cnbp); + change->name = talloc_move(changes, &name2); + change->action = action; + fsp->notify->num_changes += 1; - memcpy(cnbp->request_buf, inbuf, smb_size); - cnbp->fsp = fsp; - cnbp->conn = conn; - cnbp->flags = flags; - cnbp->change_data = cnotify->register_notify(conn, fsp->fsp_name, flags); - - if (!cnbp->change_data) { - SAFE_FREE(cnbp); - return False; + if (fsp->notify->requests == NULL) { + /* + * Nobody is waiting, so don't send anything. The ot + */ + return; + } + + if (action == NOTIFY_ACTION_OLD_NAME) { + /* + * We have to send the two rename events in one reply. So hold + * the first part back. + */ + return; } - DLIST_ADD(change_notify_list, cnbp); + /* + * Someone is waiting for the change, trigger the reply immediately. + * + * TODO: do we have to walk the lists of requests pending? + */ - /* Push the MID of this packet on the signing queue. */ - srv_defer_sign_response(SVAL(inbuf,smb_mid)); + change_notify_reply(fsp->notify->requests->request_buf, + fsp->notify->requests->max_param_count, + fsp->notify); - return True; + change_notify_remove_request(fsp->notify->requests); } -int change_notify_fd(void) +char *notify_filter_string(TALLOC_CTX *mem_ctx, uint32 filter) { - if (cnotify) { - return cnotify->notification_fd; - } - - return -1; + char *result = NULL; + + result = talloc_strdup(mem_ctx, ""); + + if (filter & FILE_NOTIFY_CHANGE_FILE_NAME) + result = talloc_asprintf_append(result, "FILE_NAME|"); + if (filter & FILE_NOTIFY_CHANGE_DIR_NAME) + result = talloc_asprintf_append(result, "DIR_NAME|"); + if (filter & FILE_NOTIFY_CHANGE_ATTRIBUTES) + result = talloc_asprintf_append(result, "ATTRIBUTES|"); + if (filter & FILE_NOTIFY_CHANGE_SIZE) + result = talloc_asprintf_append(result, "SIZE|"); + if (filter & FILE_NOTIFY_CHANGE_LAST_WRITE) + result = talloc_asprintf_append(result, "LAST_WRITE|"); + if (filter & FILE_NOTIFY_CHANGE_LAST_ACCESS) + result = talloc_asprintf_append(result, "LAST_ACCESS|"); + if (filter & FILE_NOTIFY_CHANGE_CREATION) + result = talloc_asprintf_append(result, "CREATION|"); + if (filter & FILE_NOTIFY_CHANGE_EA) + result = talloc_asprintf_append(result, "EA|"); + if (filter & FILE_NOTIFY_CHANGE_SECURITY) + result = talloc_asprintf_append(result, "SECURITY|"); + if (filter & FILE_NOTIFY_CHANGE_STREAM_NAME) + result = talloc_asprintf_append(result, "STREAM_NAME|"); + if (filter & FILE_NOTIFY_CHANGE_STREAM_SIZE) + result = talloc_asprintf_append(result, "STREAM_SIZE|"); + if (filter & FILE_NOTIFY_CHANGE_STREAM_WRITE) + result = talloc_asprintf_append(result, "STREAM_WRITE|"); + + if (result == NULL) return NULL; + if (*result == '\0') return result; + + result[strlen(result)-1] = '\0'; + return result; } -/**************************************************************************** - Initialise the change notify subsystem. -****************************************************************************/ - -BOOL init_change_notify(void) +struct sys_notify_context *sys_notify_context_create(connection_struct *conn, + TALLOC_CTX *mem_ctx, + struct event_context *ev) { - cnotify = NULL; - -#if HAVE_KERNEL_CHANGE_NOTIFY - if (cnotify == NULL && lp_kernel_change_notify()) - cnotify = kernel_notify_init(); -#endif -#if HAVE_FAM_CHANGE_NOTIFY - if (cnotify == NULL && lp_fam_change_notify()) - cnotify = fam_notify_init(); -#endif - if (!cnotify) cnotify = hash_notify_init(); - - if (!cnotify) { - DEBUG(0,("Failed to init change notify system\n")); - return False; + struct sys_notify_context *ctx; + + if (!(ctx = TALLOC_P(mem_ctx, struct sys_notify_context))) { + DEBUG(0, ("talloc failed\n")); + return NULL; } - return True; + ctx->ev = ev; + ctx->conn = conn; + ctx->private_data = NULL; + return ctx; } + +NTSTATUS sys_notify_watch(struct sys_notify_context *ctx, + struct notify_entry *e, + void (*callback)(struct sys_notify_context *ctx, + void *private_data, + struct notify_event *ev), + void *private_data, void *handle) +{ + return SMB_VFS_NOTIFY_WATCH(ctx->conn, ctx, e, callback, private_data, + handle); +} + diff --git a/source/smbd/notify_fam.c b/source/smbd/notify_fam.c deleted file mode 100644 index bfef4ac871e..00000000000 --- a/source/smbd/notify_fam.c +++ /dev/null @@ -1,464 +0,0 @@ -/* - * FAM file notification support. - * - * Copyright (c) James Peach 2005 - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - -#include "includes.h" - -#ifdef HAVE_FAM_CHANGE_NOTIFY - -#include - -#if !defined(HAVE_FAM_H_FAMCODES_TYPEDEF) -/* Gamin provides this typedef which means we can't use 'enum FAMCodes' as per - * every other FAM implementation. Phooey. - */ -typedef enum FAMCodes FAMCodes; -#endif - -/* NOTE: There are multiple versions of FAM floating around the net, each with - * slight differences from the original SGI FAM implementation. In this file, - * we rely only on the SGI features and do not assume any extensions. For - * example, we do not look at FAMErrno, because it is not set by the original - * implementation. - * - * Random FAM links: - * http://oss.sgi.com/projects/fam/ - * http://savannah.nongnu.org/projects/fam/ - * http://sourceforge.net/projects/bsdfam/ - */ - -struct fam_req_info -{ - FAMRequest req; - int generation; - FAMCodes code; - enum - { - /* We are waiting for an event. */ - FAM_REQ_MONITORING, - /* An event has been receive, but we haven't been able to send it back - * to the client yet. It is stashed in the code member. - */ - FAM_REQ_FIRED - } state; -}; - -/* Don't initialise this until the first register request. We want a single - * FAM connection for each worker smbd. If we allow the master (parent) smbd to - * open a FAM connection, multiple processes talking on the same socket will - * undoubtedly create havoc. - */ -static FAMConnection global_fc; -static int global_fc_generation; - -#define FAM_TRACE 8 -#define FAM_TRACE_LOW 10 - -#define FAM_EVENT_DRAIN ((uint32_t)(-1)) - -static void * fam_register_notify(connection_struct * conn, - char * path, - uint32 flags); - -static BOOL fam_check_notify(connection_struct * conn, - uint16_t vuid, - char * path, - uint32_t flags, - void * data, - time_t when); - -static void fam_remove_notify(void * data); - -static struct cnotify_fns global_fam_notify = -{ - fam_register_notify, - fam_check_notify, - fam_remove_notify, - -1, - -1 -}; - -/* Turn a FAM event code into a string. Don't rely on specific code values, - * because that might not work across all flavours of FAM. - */ -static const char * -fam_event_str(FAMCodes code) -{ - static const struct { FAMCodes code; const char * name; } evstr[] = - { - { FAMChanged, "FAMChanged"}, - { FAMDeleted, "FAMDeleted"}, - { FAMStartExecuting, "FAMStartExecuting"}, - { FAMStopExecuting, "FAMStopExecuting"}, - { FAMCreated, "FAMCreated"}, - { FAMMoved, "FAMMoved"}, - { FAMAcknowledge, "FAMAcknowledge"}, - { FAMExists, "FAMExists"}, - { FAMEndExist, "FAMEndExist"} - }; - - int i; - - for (i = 0; i < ARRAY_SIZE(evstr); ++i) { - if (code == evstr[i].code) - return(evstr[i].name); - } - - return(""); -} - -static BOOL -fam_check_reconnect(void) -{ - if (FAMCONNECTION_GETFD(&global_fc) < 0) { - fstring name; - - global_fc_generation++; - snprintf(name, sizeof(name), "smbd (%lu)", (unsigned long)sys_getpid()); - - if (FAMOpen2(&global_fc, name) < 0) { - DEBUG(0, ("failed to connect to FAM service\n")); - return(False); - } - } - - global_fam_notify.notification_fd = FAMCONNECTION_GETFD(&global_fc); - return(True); -} - -static BOOL -fam_monitor_path(connection_struct * conn, - struct fam_req_info * info, - const char * path, - uint32 flags) -{ - SMB_STRUCT_STAT st; - pstring fullpath; - - DEBUG(FAM_TRACE, ("requesting FAM notifications for '%s'\n", path)); - - /* FAM needs an absolute pathname. */ - - /* It would be better to use reduce_name() here, but reduce_name does not - * actually return the reduced result. How utterly un-useful. - */ - pstrcpy(fullpath, path); - if (!canonicalize_path(conn, fullpath)) { - DEBUG(0, ("failed to canonicalize path '%s'\n", path)); - return(False); - } - - if (*fullpath != '/') { - DEBUG(0, ("canonicalized path '%s' into `%s`\n", path, fullpath)); - DEBUGADD(0, ("but expected an absolute path\n")); - return(False); - } - - if (SMB_VFS_STAT(conn, path, &st) < 0) { - DEBUG(0, ("stat of '%s' failed: %s\n", path, strerror(errno))); - return(False); - } - /* Start monitoring this file or directory. We hand the state structure to - * both the caller and the FAM library so we can match up the caller's - * status requests with FAM notifications. - */ - if (S_ISDIR(st.st_mode)) { - FAMMonitorDirectory(&global_fc, fullpath, &(info->req), info); - } else { - FAMMonitorFile(&global_fc, fullpath, &(info->req), info); - } - - /* Grr. On IRIX, neither of the monitor functions return a status. */ - - /* We will stay in initialising state until we see the FAMendExist message - * for this file. - */ - info->state = FAM_REQ_MONITORING; - info->generation = global_fc_generation; - return(True); -} - -static BOOL -fam_handle_event(const FAMCodes code, uint32 flags) -{ -#define F_CHANGE_MASK (FILE_NOTIFY_CHANGE_FILE | \ - FILE_NOTIFY_CHANGE_ATTRIBUTES | \ - FILE_NOTIFY_CHANGE_SIZE | \ - FILE_NOTIFY_CHANGE_LAST_WRITE | \ - FILE_NOTIFY_CHANGE_LAST_ACCESS | \ - FILE_NOTIFY_CHANGE_CREATION | \ - FILE_NOTIFY_CHANGE_EA | \ - FILE_NOTIFY_CHANGE_SECURITY) - -#define F_DELETE_MASK (FILE_NOTIFY_CHANGE_FILE_NAME | \ - FILE_NOTIFY_CHANGE_DIR_NAME) - -#define F_CREATE_MASK (FILE_NOTIFY_CHANGE_FILE_NAME | \ - FILE_NOTIFY_CHANGE_DIR_NAME) - - switch (code) { - case FAMChanged: - if (flags & F_CHANGE_MASK) - return(True); - break; - case FAMDeleted: - if (flags & F_DELETE_MASK) - return(True); - break; - case FAMCreated: - if (flags & F_CREATE_MASK) - return(True); - break; - default: - /* Ignore anything else. */ - break; - } - - return(False); - -#undef F_CHANGE_MASK -#undef F_DELETE_MASK -#undef F_CREATE_MASK -} - -static BOOL -fam_pump_events(struct fam_req_info * info, uint32_t flags) -{ - FAMEvent ev; - - for (;;) { - - /* If we are draining the event queue we must keep going until we find - * the correct FAMAcknowledge event or the connection drops. Otherwise - * we should stop when there are no more events pending. - */ - if (flags != FAM_EVENT_DRAIN && !FAMPending(&global_fc)) { - break; - } - - if (FAMNextEvent(&global_fc, &ev) < 0) { - DEBUG(0, ("failed to fetch pending FAM event\n")); - DEBUGADD(0, ("resetting FAM connection\n")); - FAMClose(&global_fc); - FAMCONNECTION_GETFD(&global_fc) = -1; - return(False); - } - - DEBUG(FAM_TRACE_LOW, ("FAM event %s on '%s' for request %d\n", - fam_event_str(ev.code), ev.filename, ev.fr.reqnum)); - - switch (ev.code) { - case FAMAcknowledge: - /* FAM generates an ACK event when we cancel a monitor. We need - * this to know when it is safe to free out request state - * structure. - */ - if (info->generation == global_fc_generation && - info->req.reqnum == ev.fr.reqnum && - flags == FAM_EVENT_DRAIN) { - return(True); - } - - case FAMEndExist: - case FAMExists: - /* Ignore these. FAM sends these enumeration events when we - * start monitoring. If we are monitoring a directory, we will - * get a FAMExists event for each directory entry. - */ - - /* TODO: we might be able to use these to implement recursive - * monitoring of entire subtrees. - */ - case FAMMoved: - /* These events never happen. A move or rename shows up as a - * create/delete pair. - */ - case FAMStartExecuting: - case FAMStopExecuting: - /* We might get these, but we just don't care. */ - break; - - case FAMChanged: - case FAMDeleted: - case FAMCreated: - if (info->generation != global_fc_generation) { - /* Ignore this; the req number can't be matched. */ - break; - } - - if (info->req.reqnum == ev.fr.reqnum) { - /* This is the event the caller was interested in. */ - DEBUG(FAM_TRACE, ("handling FAM %s event on '%s'\n", - fam_event_str(ev.code), ev.filename)); - /* Ignore events if we are draining this request. */ - if (flags != FAM_EVENT_DRAIN) { - return(fam_handle_event(ev.code, flags)); - } - break; - } else { - /* Caller doesn't want this event. Stash the result so we - * can come back to it. Unfortunately, FAM doesn't - * guarantee to give us back evinfo. - */ - struct fam_req_info * evinfo = - (struct fam_req_info *)ev.userdata; - - if (evinfo) { - DEBUG(FAM_TRACE, ("storing FAM %s event for winter\n", - fam_event_str(ev.code))); - evinfo->state = FAM_REQ_FIRED; - evinfo->code = ev.code; - } else { - DEBUG(2, ("received FAM %s notification for %s, " - "but userdata was unexpectedly NULL\n", - fam_event_str(ev.code), ev.filename)); - } - break; - } - - default: - DEBUG(0, ("ignoring unknown FAM event code %d for `%s`\n", - ev.code, ev.filename)); - } - } - - /* No more notifications pending. */ - return(False); -} - -static BOOL -fam_test_connection(void) -{ - FAMConnection fc; - - /* On IRIX FAMOpen2 leaks 960 bytes in 48 blocks. It's a deliberate leak - * in the library and there's nothing we can do about it here. - */ - if (FAMOpen2(&fc, "smbd probe") < 0) - return(False); - - FAMClose(&fc); - return(True); -} - -/* ------------------------------------------------------------------------- */ - -static void * -fam_register_notify(connection_struct * conn, - char * path, - uint32 flags) -{ - struct fam_req_info * info; - - if (!fam_check_reconnect()) { - return(False); - } - - if ((info = SMB_MALLOC_P(struct fam_req_info)) == NULL) { - DEBUG(0, ("malloc of %u bytes failed\n", (unsigned int)sizeof(struct fam_req_info))); - return(NULL); - } - - if (fam_monitor_path(conn, info, path, flags)) { - return(info); - } else { - SAFE_FREE(info); - return(NULL); - } -} - -static BOOL -fam_check_notify(connection_struct * conn, - uint16_t vuid, - char * path, - uint32_t flags, - void * data, - time_t when) -{ - struct fam_req_info * info; - - info = (struct fam_req_info *)data; - SMB_ASSERT(info != NULL); - - DEBUG(10, ("checking FAM events for `%s`\n", path)); - - if (info->state == FAM_REQ_FIRED) { - DEBUG(FAM_TRACE, ("handling previously fired FAM %s event\n", - fam_event_str(info->code))); - info->state = FAM_REQ_MONITORING; - return(fam_handle_event(info->code, flags)); - } - - if (!fam_check_reconnect()) { - return(False); - } - - if (info->generation != global_fc_generation) { - DEBUG(FAM_TRACE, ("reapplying stale FAM monitor to %s\n", path)); - fam_monitor_path(conn, info, path, flags); - return(False); - } - - return(fam_pump_events(info, flags)); -} - -static void -fam_remove_notify(void * data) -{ - struct fam_req_info * info; - - if ((info = (struct fam_req_info *)data) == NULL) - return; - - /* No need to reconnect. If the FAM connection is gone, there's no need to - * cancel and we can safely let FAMCancelMonitor fail. If it we - * reconnected, then the generation check will stop us cancelling the wrong - * request. - */ - - if ((FAMCONNECTION_GETFD(&global_fc) != -1) - && (info->generation == global_fc_generation)) { - DEBUG(FAM_TRACE, ("removing FAM notification for request %d\n", - info->req.reqnum)); - FAMCancelMonitor(&global_fc, &(info->req)); - - /* Soak up all events until the FAMAcknowledge. We can't free - * our request state until we are sure there are no more events in - * flight. - */ - fam_pump_events(info, FAM_EVENT_DRAIN); - } - - SAFE_FREE(info); -} - -struct cnotify_fns * fam_notify_init(void) -{ - FAMCONNECTION_GETFD(&global_fc) = -1; - - if (!fam_test_connection()) { - DEBUG(0, ("FAM file change notifications not available\n")); - return(NULL); - } - - DEBUG(FAM_TRACE, ("enabling FAM change notifications\n")); - return &global_fam_notify; -} - -#endif /* HAVE_FAM_CHANGE_NOTIFY */ diff --git a/source/smbd/notify_hash.c b/source/smbd/notify_hash.c deleted file mode 100644 index 0787a3eec5e..00000000000 --- a/source/smbd/notify_hash.c +++ /dev/null @@ -1,261 +0,0 @@ -/* - Unix SMB/CIFS implementation. - change notify handling - hash based implementation - Copyright (C) Jeremy Allison 1994-1998 - Copyright (C) Andrew Tridgell 2000 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -struct change_data { - time_t last_check_time; /* time we last checked this entry */ - struct timespec modify_time; /* Info from the directory we're monitoring. */ - struct timespec status_time; /* Info from the directory we're monitoring. */ - time_t total_time; /* Total time of all directory entries - don't care if it wraps. */ - unsigned int num_entries; /* Zero or the number of files in the directory. */ - unsigned int mode_sum; - unsigned char name_hash[16]; -}; - - -/* Compare struct timespec. */ -#define TIMESTAMP_NEQ(x, y) (((x).tv_sec != (y).tv_sec) || ((x).tv_nsec != (y).tv_nsec)) - -/**************************************************************************** - Create the hash we will use to determine if the contents changed. -*****************************************************************************/ - -static BOOL notify_hash(connection_struct *conn, char *path, uint32 flags, - struct change_data *data, struct change_data *old_data) -{ - SMB_STRUCT_STAT st; - pstring full_name; - char *p; - const char *fname; - size_t remaining_len; - size_t fullname_len; - struct smb_Dir *dp; - long offset; - - ZERO_STRUCTP(data); - - if(SMB_VFS_STAT(conn,path, &st) == -1) - return False; - - data->modify_time = get_mtimespec(&st); - data->status_time = get_ctimespec(&st); - - if (old_data) { - /* - * Shortcut to avoid directory scan if the time - * has changed - we always must return true then. - */ - if (TIMESTAMP_NEQ(old_data->modify_time, data->modify_time) || - TIMESTAMP_NEQ(old_data->status_time, data->status_time) ) { - return True; - } - } - - if (S_ISDIR(st.st_mode) && - (flags & ~(FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME)) == 0) - { - /* This is the case of a client wanting to know only when - * the contents of a directory changes. Since any file - * creation, rename or deletion will update the directory - * timestamps, we don't need to create a hash. - */ - return True; - } - - if (lp_change_notify_timeout(SNUM(conn)) <= 0) { - /* It change notify timeout has been disabled, never scan the directory. */ - return True; - } - - /* - * If we are to watch for changes that are only stored - * in inodes of files, not in the directory inode, we must - * scan the directory and produce a unique identifier with - * which we can determine if anything changed. We use the - * modify and change times from all the files in the - * directory, added together (ignoring wrapping if it's - * larger than the max time_t value). - */ - - dp = OpenDir(conn, path, NULL, 0); - if (dp == NULL) - return False; - - data->num_entries = 0; - - pstrcpy(full_name, path); - pstrcat(full_name, "/"); - - fullname_len = strlen(full_name); - remaining_len = sizeof(full_name) - fullname_len - 1; - p = &full_name[fullname_len]; - - offset = 0; - while ((fname = ReadDirName(dp, &offset))) { - SET_STAT_INVALID(st); - if(strequal(fname, ".") || strequal(fname, "..")) - continue; - - if (!is_visible_file(conn, path, fname, &st, True)) - continue; - - data->num_entries++; - safe_strcpy(p, fname, remaining_len); - - /* - * Do the stat - but ignore errors. - */ - if (!VALID_STAT(st)) { - SMB_VFS_STAT(conn,full_name, &st); - } - - /* - * Always sum the times. - */ - - data->total_time += (st.st_mtime + st.st_ctime); - - /* - * If requested hash the names. - */ - - if (flags & (FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME|FILE_NOTIFY_CHANGE_FILE)) { - int i; - unsigned char tmp_hash[16]; - mdfour(tmp_hash, (const unsigned char *)fname, strlen(fname)); - for (i=0;i<16;i++) - data->name_hash[i] ^= tmp_hash[i]; - } - - /* - * If requested sum the mode_t's. - */ - - if (flags & (FILE_NOTIFY_CHANGE_ATTRIBUTES|FILE_NOTIFY_CHANGE_SECURITY)) - data->mode_sum += st.st_mode; - } - - CloseDir(dp); - - return True; -} - -/**************************************************************************** - Register a change notify request. -*****************************************************************************/ - -static void *hash_register_notify(connection_struct *conn, char *path, uint32 flags) -{ - struct change_data data; - - if (!notify_hash(conn, path, flags, &data, NULL)) - return NULL; - - data.last_check_time = time(NULL); - - return (void *)memdup(&data, sizeof(data)); -} - -/**************************************************************************** - Check if a change notify should be issued. - A time of zero means instantaneous check - don't modify the last check time. -*****************************************************************************/ - -static BOOL hash_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t) -{ - struct change_data *data = (struct change_data *)datap; - struct change_data data2; - int cnto = lp_change_notify_timeout(SNUM(conn)); - - if (t && cnto <= 0) { - /* Change notify turned off on this share. - * Only scan when (t==0) - we think something changed. */ - return False; - } - - if (t && t < data->last_check_time + cnto) { - return False; - } - - if (!change_to_user(conn,vuid)) - return True; - if (!set_current_service(conn,FLAG_CASELESS_PATHNAMES,True)) { - change_to_root_user(); - return True; - } - - if (!notify_hash(conn, path, flags, &data2, data) || - TIMESTAMP_NEQ(data2.modify_time, data->modify_time) || - TIMESTAMP_NEQ(data2.status_time, data->status_time) || - data2.total_time != data->total_time || - data2.num_entries != data->num_entries || - data2.mode_sum != data->mode_sum || - memcmp(data2.name_hash, data->name_hash, sizeof(data2.name_hash))) { - change_to_root_user(); - return True; - } - - if (t) { - data->last_check_time = t; - } - - change_to_root_user(); - - return False; -} - -/**************************************************************************** - Remove a change notify data structure. -*****************************************************************************/ - -static void hash_remove_notify(void *datap) -{ - free(datap); -} - -/**************************************************************************** - Setup hash based change notify. -****************************************************************************/ - -struct cnotify_fns *hash_notify_init(void) -{ - static struct cnotify_fns cnotify; - - cnotify.register_notify = hash_register_notify; - cnotify.check_notify = hash_check_notify; - cnotify.remove_notify = hash_remove_notify; - cnotify.select_time = 60; /* Start with 1 minute default. */ - cnotify.notification_fd = -1; - - return &cnotify; -} - -/* - change_notify_reply_packet(cnbp->request_buf,ERRSRV,ERRaccess); - change_notify_reply_packet(cnbp->request_buf,0,NT_STATUS_NOTIFY_ENUM_DIR); - - chain_size = 0; - file_chain_reset(); - - uint16 vuid = (lp_security() == SEC_SHARE) ? UID_FIELD_INVALID : - SVAL(cnbp->request_buf,smb_uid); -*/ diff --git a/source/smbd/notify_inotify.c b/source/smbd/notify_inotify.c new file mode 100644 index 00000000000..5fb414de4cc --- /dev/null +++ b/source/smbd/notify_inotify.c @@ -0,0 +1,425 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + notify implementation using inotify +*/ + +#include "includes.h" + +#ifdef HAVE_INOTIFY + +#include +#include + +#ifndef HAVE_INOTIFY_INIT +/* + glibc doesn't define these functions yet (as of March 2006) +*/ +static int inotify_init(void) +{ + return syscall(__NR_inotify_init); +} + +static int inotify_add_watch(int fd, const char *path, __u32 mask) +{ + return syscall(__NR_inotify_add_watch, fd, path, mask); +} + +static int inotify_rm_watch(int fd, int wd) +{ + return syscall(__NR_inotify_rm_watch, fd, wd); +} +#endif + + +/* older glibc headers don't have these defines either */ +#ifndef IN_ONLYDIR +#define IN_ONLYDIR 0x01000000 +#endif +#ifndef IN_MASK_ADD +#define IN_MASK_ADD 0x20000000 +#endif + +struct inotify_private { + struct sys_notify_context *ctx; + int fd; + struct inotify_watch_context *watches; +}; + +struct inotify_watch_context { + struct inotify_watch_context *next, *prev; + struct inotify_private *in; + int wd; + void (*callback)(struct sys_notify_context *ctx, + void *private_data, + struct notify_event *ev); + void *private_data; + uint32_t mask; /* the inotify mask */ + uint32_t filter; /* the windows completion filter */ + const char *path; +}; + + +/* + destroy the inotify private context +*/ +static int inotify_destructor(struct inotify_private *in) +{ + close(in->fd); + return 0; +} + + +/* + see if a particular event from inotify really does match a requested + notify event in SMB +*/ +static BOOL filter_match(struct inotify_watch_context *w, + struct inotify_event *e) +{ + DEBUG(10, ("filter_match: e->mask=%x, w->mask=%x, w->filter=%x\n", + e->mask, w->mask, w->filter)); + + if ((e->mask & w->mask) == 0) { + /* this happens because inotify_add_watch() coalesces watches on the same + path, oring their masks together */ + return False; + } + + /* SMB separates the filters for files and directories */ + if (e->mask & IN_ISDIR) { + if ((w->filter & FILE_NOTIFY_CHANGE_DIR_NAME) == 0) { + return False; + } + } else { + if ((e->mask & IN_ATTRIB) && + (w->filter & (FILE_NOTIFY_CHANGE_ATTRIBUTES| + FILE_NOTIFY_CHANGE_LAST_WRITE| + FILE_NOTIFY_CHANGE_LAST_ACCESS| + FILE_NOTIFY_CHANGE_EA| + FILE_NOTIFY_CHANGE_SECURITY))) { + return True; + } + if ((e->mask & IN_MODIFY) && + (w->filter & FILE_NOTIFY_CHANGE_ATTRIBUTES)) { + return True; + } + if ((w->filter & FILE_NOTIFY_CHANGE_FILE_NAME) == 0) { + return False; + } + } + + return True; +} + + + +/* + dispatch one inotify event + + the cookies are used to correctly handle renames +*/ +static void inotify_dispatch(struct inotify_private *in, + struct inotify_event *e, + uint32_t prev_cookie, + struct inotify_event *e2) +{ + struct inotify_watch_context *w, *next; + struct notify_event ne; + + DEBUG(10, ("inotify_dispatch called with mask=%x, name=[%s]\n", + e->mask, e->len ? e->name : "")); + + /* ignore extraneous events, such as unmount and IN_IGNORED events */ + if ((e->mask & (IN_ATTRIB|IN_MODIFY|IN_CREATE|IN_DELETE| + IN_MOVED_FROM|IN_MOVED_TO)) == 0) { + return; + } + + /* map the inotify mask to a action. This gets complicated for + renames */ + if (e->mask & IN_CREATE) { + ne.action = NOTIFY_ACTION_ADDED; + } else if (e->mask & IN_DELETE) { + ne.action = NOTIFY_ACTION_REMOVED; + } else if (e->mask & IN_MOVED_FROM) { + if (e2 != NULL && e2->cookie == e->cookie) { + ne.action = NOTIFY_ACTION_OLD_NAME; + } else { + ne.action = NOTIFY_ACTION_REMOVED; + } + } else if (e->mask & IN_MOVED_TO) { + if (e->cookie == prev_cookie) { + ne.action = NOTIFY_ACTION_NEW_NAME; + } else { + ne.action = NOTIFY_ACTION_ADDED; + } + } else { + ne.action = NOTIFY_ACTION_MODIFIED; + } + ne.path = e->name; + + DEBUG(10, ("inotify_dispatch: ne.action = %d, ne.path = %s\n", + ne.action, ne.path)); + + /* find any watches that have this watch descriptor */ + for (w=in->watches;w;w=next) { + next = w->next; + if (w->wd == e->wd && filter_match(w, e)) { + w->callback(in->ctx, w->private_data, &ne); + } + } + + /* SMB expects a file rename to generate three events, two for + the rename and the other for a modify of the + destination. Strange! */ + if (ne.action != NOTIFY_ACTION_NEW_NAME || + (e->mask & IN_ISDIR) != 0) { + return; + } + + ne.action = NOTIFY_ACTION_MODIFIED; + e->mask = IN_ATTRIB; + + for (w=in->watches;w;w=next) { + next = w->next; + if (w->wd == e->wd && filter_match(w, e) && + !(w->filter & FILE_NOTIFY_CHANGE_CREATION)) { + w->callback(in->ctx, w->private_data, &ne); + } + } +} + +/* + called when the kernel has some events for us +*/ +static void inotify_handler(struct event_context *ev, struct fd_event *fde, + uint16_t flags, void *private_data) +{ + struct inotify_private *in = talloc_get_type(private_data, + struct inotify_private); + int bufsize = 0; + struct inotify_event *e0, *e; + uint32_t prev_cookie=0; + + /* + we must use FIONREAD as we cannot predict the length of the + filenames, and thus can't know how much to allocate + otherwise + */ + if (ioctl(in->fd, FIONREAD, &bufsize) != 0 || + bufsize == 0) { + DEBUG(0,("No data on inotify fd?!\n")); + return; + } + + e0 = e = (struct inotify_event *)talloc_size(in, bufsize); + if (e == NULL) return; + + if (read(in->fd, e0, bufsize) != bufsize) { + DEBUG(0,("Failed to read all inotify data\n")); + talloc_free(e0); + return; + } + + /* we can get more than one event in the buffer */ + while (bufsize >= sizeof(*e)) { + struct inotify_event *e2 = NULL; + bufsize -= e->len + sizeof(*e); + if (bufsize >= sizeof(*e)) { + e2 = (struct inotify_event *)(e->len + sizeof(*e) + (char *)e); + } + inotify_dispatch(in, e, prev_cookie, e2); + prev_cookie = e->cookie; + e = e2; + } + + talloc_free(e0); +} + +/* + setup the inotify handle - called the first time a watch is added on + this context +*/ +static NTSTATUS inotify_setup(struct sys_notify_context *ctx) +{ + struct inotify_private *in; + + if (!lp_parm_bool(-1, "notify", "inotify", True)) { + return NT_STATUS_INVALID_SYSTEM_SERVICE; + } + + in = talloc(ctx, struct inotify_private); + NT_STATUS_HAVE_NO_MEMORY(in); + in->fd = inotify_init(); + if (in->fd == -1) { + DEBUG(0,("Failed to init inotify - %s\n", strerror(errno))); + talloc_free(in); + return map_nt_error_from_unix(errno); + } + in->ctx = ctx; + in->watches = NULL; + + ctx->private_data = in; + talloc_set_destructor(in, inotify_destructor); + + /* add a event waiting for the inotify fd to be readable */ + event_add_fd(ctx->ev, in, in->fd, EVENT_FD_READ, inotify_handler, in); + + return NT_STATUS_OK; +} + + +/* + map from a change notify mask to a inotify mask. Remove any bits + which we can handle +*/ +static const struct { + uint32_t notify_mask; + uint32_t inotify_mask; +} inotify_mapping[] = { + {FILE_NOTIFY_CHANGE_FILE_NAME, IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO}, + {FILE_NOTIFY_CHANGE_DIR_NAME, IN_CREATE|IN_DELETE|IN_MOVED_FROM|IN_MOVED_TO}, + {FILE_NOTIFY_CHANGE_ATTRIBUTES, IN_ATTRIB|IN_MOVED_TO|IN_MOVED_FROM|IN_MODIFY}, + {FILE_NOTIFY_CHANGE_LAST_WRITE, IN_ATTRIB}, + {FILE_NOTIFY_CHANGE_LAST_ACCESS, IN_ATTRIB}, + {FILE_NOTIFY_CHANGE_EA, IN_ATTRIB}, + {FILE_NOTIFY_CHANGE_SECURITY, IN_ATTRIB} +}; + +static uint32_t inotify_map(struct notify_entry *e) +{ + int i; + uint32_t out=0; + for (i=0;ifilter) { + out |= inotify_mapping[i].inotify_mask; + e->filter &= ~inotify_mapping[i].notify_mask; + } + } + return out; +} + +/* + destroy a watch +*/ +static int watch_destructor(struct inotify_watch_context *w) +{ + struct inotify_private *in = w->in; + int wd = w->wd; + DLIST_REMOVE(w->in->watches, w); + + /* only rm the watch if its the last one with this wd */ + for (w=in->watches;w;w=w->next) { + if (w->wd == wd) break; + } + if (w == NULL) { + DEBUG(10, ("Deleting inotify watch %d\n", wd)); + if (inotify_rm_watch(in->fd, wd) == -1) { + DEBUG(1, ("inotify_rm_watch returned %s\n", + strerror(errno))); + } + + } + return 0; +} + + +/* + add a watch. The watch is removed when the caller calls + talloc_free() on *handle +*/ +NTSTATUS inotify_watch(struct sys_notify_context *ctx, + struct notify_entry *e, + void (*callback)(struct sys_notify_context *ctx, + void *private_data, + struct notify_event *ev), + void *private_data, + void *handle_p) +{ + struct inotify_private *in; + int wd; + uint32_t mask; + struct inotify_watch_context *w; + uint32_t filter = e->filter; + void **handle = (void **)handle_p; + + /* maybe setup the inotify fd */ + if (ctx->private_data == NULL) { + NTSTATUS status; + status = inotify_setup(ctx); + NT_STATUS_NOT_OK_RETURN(status); + } + + in = talloc_get_type(ctx->private_data, struct inotify_private); + + mask = inotify_map(e); + if (mask == 0) { + /* this filter can't be handled by inotify */ + return NT_STATUS_INVALID_PARAMETER; + } + + /* using IN_MASK_ADD allows us to cope with inotify() returning the same + watch descriptor for muliple watches on the same path */ + mask |= (IN_MASK_ADD | IN_ONLYDIR); + + /* get a new watch descriptor for this path */ + wd = inotify_add_watch(in->fd, e->path, mask); + if (wd == -1) { + e->filter = filter; + DEBUG(1, ("inotify_add_watch returned %s\n", strerror(errno))); + return map_nt_error_from_unix(errno); + } + + DEBUG(10, ("inotify_add_watch for %s mask %x returned wd %d\n", + e->path, mask, wd)); + + w = talloc(in, struct inotify_watch_context); + if (w == NULL) { + inotify_rm_watch(in->fd, wd); + e->filter = filter; + return NT_STATUS_NO_MEMORY; + } + + w->in = in; + w->wd = wd; + w->callback = callback; + w->private_data = private_data; + w->mask = mask; + w->filter = filter; + w->path = talloc_strdup(w, e->path); + if (w->path == NULL) { + inotify_rm_watch(in->fd, wd); + e->filter = filter; + return NT_STATUS_NO_MEMORY; + } + + (*handle) = w; + + DLIST_ADD(in->watches, w); + + /* the caller frees the handle to stop watching */ + talloc_set_destructor(w, watch_destructor); + + return NT_STATUS_OK; +} + +#endif diff --git a/source/smbd/notify_internal.c b/source/smbd/notify_internal.c new file mode 100644 index 00000000000..72b96049350 --- /dev/null +++ b/source/smbd/notify_internal.c @@ -0,0 +1,686 @@ +/* + Unix SMB/CIFS implementation. + + Copyright (C) Andrew Tridgell 2006 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +/* + this is the change notify database. It implements mechanisms for + storing current change notify waiters in a tdb, and checking if a + given event matches any of the stored notify waiiters. +*/ + +#include "includes.h" +#include "librpc/gen_ndr/ndr_notify.h" + +struct notify_context { + struct tdb_wrap *w; + struct server_id server; + struct messaging_context *messaging_ctx; + struct notify_list *list; + struct notify_array *array; + int seqnum; + struct sys_notify_context *sys_notify_ctx; +}; + + +struct notify_list { + struct notify_list *next, *prev; + void *private_data; + void (*callback)(void *, const struct notify_event *); + void *sys_notify_handle; + int depth; +}; + +#define NOTIFY_KEY "notify array" + +#define NOTIFY_ENABLE "notify:enable" +#define NOTIFY_ENABLE_DEFAULT True + +static NTSTATUS notify_remove_all(struct notify_context *notify, + const struct server_id *server); +static void notify_handler(struct messaging_context *msg_ctx, void *private_data, + uint32_t msg_type, struct server_id server_id, DATA_BLOB *data); + +/* + destroy the notify context +*/ +static int notify_destructor(struct notify_context *notify) +{ + messaging_deregister(notify->messaging_ctx, MSG_PVFS_NOTIFY, notify); + + if (notify->list != NULL) { + notify_remove_all(notify, ¬ify->server); + } + + return 0; +} + +/* + Open up the notify.tdb database. You should close it down using + talloc_free(). We need the messaging_ctx to allow for notifications + via internal messages +*/ +struct notify_context *notify_init(TALLOC_CTX *mem_ctx, struct server_id server, + struct messaging_context *messaging_ctx, + struct event_context *ev, + connection_struct *conn) +{ + struct notify_context *notify; + + if (!lp_change_notify(conn->params)) { + return NULL; + } + + notify = talloc(mem_ctx, struct notify_context); + if (notify == NULL) { + return NULL; + } + + notify->w = tdb_wrap_open(notify, lock_path("notify.tdb"), + 0, TDB_SEQNUM|TDB_CLEAR_IF_FIRST, + O_RDWR|O_CREAT, 0644); + if (notify->w == NULL) { + talloc_free(notify); + return NULL; + } + + notify->server = server; + notify->messaging_ctx = messaging_ctx; + notify->list = NULL; + notify->array = NULL; + notify->seqnum = tdb_get_seqnum(notify->w->tdb); + + talloc_set_destructor(notify, notify_destructor); + + /* register with the messaging subsystem for the notify + message type */ + messaging_register(notify->messaging_ctx, notify, + MSG_PVFS_NOTIFY, notify_handler); + + notify->sys_notify_ctx = sys_notify_context_create(conn, notify, ev); + + return notify; +} + + +/* + lock the notify db +*/ +static NTSTATUS notify_lock(struct notify_context *notify) +{ + if (tdb_lock_bystring(notify->w->tdb, NOTIFY_KEY) != 0) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + return NT_STATUS_OK; +} + +/* + unlock the notify db +*/ +static void notify_unlock(struct notify_context *notify) +{ + tdb_unlock_bystring(notify->w->tdb, NOTIFY_KEY); +} + +/* + load the notify array +*/ +static NTSTATUS notify_load(struct notify_context *notify) +{ + TDB_DATA dbuf; + DATA_BLOB blob; + NTSTATUS status; + int seqnum; + + seqnum = tdb_get_seqnum(notify->w->tdb); + + if (seqnum == notify->seqnum && notify->array != NULL) { + return NT_STATUS_OK; + } + + notify->seqnum = seqnum; + + talloc_free(notify->array); + notify->array = talloc_zero(notify, struct notify_array); + NT_STATUS_HAVE_NO_MEMORY(notify->array); + + dbuf = tdb_fetch_bystring(notify->w->tdb, NOTIFY_KEY); + if (dbuf.dptr == NULL) { + return NT_STATUS_OK; + } + + blob.data = (uint8 *)dbuf.dptr; + blob.length = dbuf.dsize; + + status = ndr_pull_struct_blob(&blob, notify->array, notify->array, + (ndr_pull_flags_fn_t)ndr_pull_notify_array); + + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("notify_load:\n")); + NDR_PRINT_DEBUG(notify_array, notify->array); + } + + free(dbuf.dptr); + + return status; +} + +/* + compare notify entries for sorting +*/ +static int notify_compare(const void *p1, const void *p2) +{ + const struct notify_entry *e1 = (const struct notify_entry *)p1; + const struct notify_entry *e2 = (const struct notify_entry *)p2; + return strcmp(e1->path, e2->path); +} + +/* + save the notify array +*/ +static NTSTATUS notify_save(struct notify_context *notify) +{ + TDB_DATA dbuf; + DATA_BLOB blob; + NTSTATUS status; + int ret; + TALLOC_CTX *tmp_ctx; + + /* if possible, remove some depth arrays */ + while (notify->array->num_depths > 0 && + notify->array->depth[notify->array->num_depths-1].num_entries == 0) { + notify->array->num_depths--; + } + + /* we might just be able to delete the record */ + if (notify->array->num_depths == 0) { + ret = tdb_delete_bystring(notify->w->tdb, NOTIFY_KEY); + if (ret != 0) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + return NT_STATUS_OK; + } + + tmp_ctx = talloc_new(notify); + NT_STATUS_HAVE_NO_MEMORY(tmp_ctx); + + status = ndr_push_struct_blob(&blob, tmp_ctx, notify->array, + (ndr_push_flags_fn_t)ndr_push_notify_array); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return status; + } + + if (DEBUGLEVEL >= 10) { + DEBUG(10, ("notify_save:\n")); + NDR_PRINT_DEBUG(notify_array, notify->array); + } + + dbuf.dptr = (char *)blob.data; + dbuf.dsize = blob.length; + + ret = tdb_store_bystring(notify->w->tdb, NOTIFY_KEY, dbuf, TDB_REPLACE); + talloc_free(tmp_ctx); + if (ret != 0) { + return NT_STATUS_INTERNAL_DB_CORRUPTION; + } + + return NT_STATUS_OK; +} + + +/* + handle incoming notify messages +*/ +static void notify_handler(struct messaging_context *msg_ctx, void *private_data, + uint32_t msg_type, struct server_id server_id, DATA_BLOB *data) +{ + struct notify_context *notify = talloc_get_type(private_data, struct notify_context); + NTSTATUS status; + struct notify_event ev; + TALLOC_CTX *tmp_ctx = talloc_new(notify); + struct notify_list *listel; + + if (tmp_ctx == NULL) { + return; + } + + status = ndr_pull_struct_blob(data, tmp_ctx, &ev, + (ndr_pull_flags_fn_t)ndr_pull_notify_event); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return; + } + + for (listel=notify->list;listel;listel=listel->next) { + if (listel->private_data == ev.private_data) { + listel->callback(listel->private_data, &ev); + break; + } + } + + talloc_free(tmp_ctx); +} + +/* + callback from sys_notify telling us about changes from the OS +*/ +static void sys_notify_callback(struct sys_notify_context *ctx, + void *ptr, struct notify_event *ev) +{ + struct notify_list *listel = talloc_get_type(ptr, struct notify_list); + ev->private_data = listel; + DEBUG(10, ("sys_notify_callback called with action=%d, for %s\n", + ev->action, ev->path)); + listel->callback(listel->private_data, ev); +} + +/* + add an entry to the notify array +*/ +static NTSTATUS notify_add_array(struct notify_context *notify, struct notify_entry *e, + void *private_data, int depth) +{ + int i; + struct notify_depth *d; + struct notify_entry *ee; + + /* possibly expand the depths array */ + if (depth >= notify->array->num_depths) { + d = talloc_realloc(notify->array, notify->array->depth, + struct notify_depth, depth+1); + NT_STATUS_HAVE_NO_MEMORY(d); + for (i=notify->array->num_depths;i<=depth;i++) { + ZERO_STRUCT(d[i]); + } + notify->array->depth = d; + notify->array->num_depths = depth+1; + } + d = ¬ify->array->depth[depth]; + + /* expand the entries array */ + ee = talloc_realloc(notify->array->depth, d->entries, struct notify_entry, + d->num_entries+1); + NT_STATUS_HAVE_NO_MEMORY(ee); + d->entries = ee; + + d->entries[d->num_entries] = *e; + d->entries[d->num_entries].private_data = private_data; + d->entries[d->num_entries].server = notify->server; + d->entries[d->num_entries].path_len = strlen(e->path); + d->num_entries++; + + d->max_mask |= e->filter; + d->max_mask_subdir |= e->subdir_filter; + + if (d->num_entries > 1) { + qsort(d->entries, d->num_entries, sizeof(d->entries[0]), notify_compare); + } + + /* recalculate the maximum masks */ + d->max_mask = 0; + d->max_mask_subdir = 0; + + for (i=0;inum_entries;i++) { + d->max_mask |= d->entries[i].filter; + d->max_mask_subdir |= d->entries[i].subdir_filter; + } + + return notify_save(notify); +} + +/* + add a notify watch. This is called when a notify is first setup on a open + directory handle. +*/ +NTSTATUS notify_add(struct notify_context *notify, struct notify_entry *e0, + void (*callback)(void *, const struct notify_event *), + void *private_data) +{ + struct notify_entry e = *e0; + NTSTATUS status; + char *tmp_path = NULL; + struct notify_list *listel; + size_t len; + int depth; + + /* see if change notify is enabled at all */ + if (notify == NULL) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + status = notify_lock(notify); + NT_STATUS_NOT_OK_RETURN(status); + + status = notify_load(notify); + if (!NT_STATUS_IS_OK(status)) { + goto done; + } + + /* cope with /. on the end of the path */ + len = strlen(e.path); + if (len > 1 && e.path[len-1] == '.' && e.path[len-2] == '/') { + tmp_path = talloc_strndup(notify, e.path, len-2); + if (tmp_path == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + e.path = tmp_path; + } + + depth = count_chars(e.path, '/'); + + listel = talloc_zero(notify, struct notify_list); + if (listel == NULL) { + status = NT_STATUS_NO_MEMORY; + goto done; + } + + listel->private_data = private_data; + listel->callback = callback; + listel->depth = depth; + DLIST_ADD(notify->list, listel); + + /* ignore failures from sys_notify */ + if (notify->sys_notify_ctx != NULL) { + /* + this call will modify e.filter and e.subdir_filter + to remove bits handled by the backend + */ + status = sys_notify_watch(notify->sys_notify_ctx, &e, + sys_notify_callback, listel, + &listel->sys_notify_handle); + if (NT_STATUS_IS_OK(status)) { + talloc_steal(listel, listel->sys_notify_handle); + } + } + + /* if the system notify handler couldn't handle some of the + filter bits, or couldn't handle a request for recursion + then we need to install it in the array used for the + intra-samba notify handling */ + if (e.filter != 0 || e.subdir_filter != 0) { + status = notify_add_array(notify, &e, private_data, depth); + } + +done: + notify_unlock(notify); + talloc_free(tmp_path); + + return status; +} + +/* + remove a notify watch. Called when the directory handle is closed +*/ +NTSTATUS notify_remove(struct notify_context *notify, void *private_data) +{ + NTSTATUS status; + struct notify_list *listel; + int i, depth; + struct notify_depth *d; + + /* see if change notify is enabled at all */ + if (notify == NULL) { + return NT_STATUS_NOT_IMPLEMENTED; + } + + for (listel=notify->list;listel;listel=listel->next) { + if (listel->private_data == private_data) { + DLIST_REMOVE(notify->list, listel); + break; + } + } + if (listel == NULL) { + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + depth = listel->depth; + + talloc_free(listel); + + status = notify_lock(notify); + NT_STATUS_NOT_OK_RETURN(status); + + status = notify_load(notify); + if (!NT_STATUS_IS_OK(status)) { + notify_unlock(notify); + return status; + } + + if (depth >= notify->array->num_depths) { + notify_unlock(notify); + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* we only have to search at the depth of this element */ + d = ¬ify->array->depth[depth]; + + for (i=0;inum_entries;i++) { + if (private_data == d->entries[i].private_data && + cluster_id_equal(¬ify->server, &d->entries[i].server)) { + break; + } + } + if (i == d->num_entries) { + notify_unlock(notify); + return NT_STATUS_OBJECT_NAME_NOT_FOUND; + } + + if (i < d->num_entries-1) { + memmove(&d->entries[i], &d->entries[i+1], + sizeof(d->entries[i])*(d->num_entries-(i+1))); + } + d->num_entries--; + + status = notify_save(notify); + + notify_unlock(notify); + + return status; +} + +/* + remove all notify watches for a messaging server +*/ +static NTSTATUS notify_remove_all(struct notify_context *notify, + const struct server_id *server) +{ + NTSTATUS status; + int i, depth, del_count=0; + + status = notify_lock(notify); + NT_STATUS_NOT_OK_RETURN(status); + + status = notify_load(notify); + if (!NT_STATUS_IS_OK(status)) { + notify_unlock(notify); + return status; + } + + /* we have to search for all entries across all depths, looking for matches + for the server id */ + for (depth=0;deptharray->num_depths;depth++) { + struct notify_depth *d = ¬ify->array->depth[depth]; + for (i=0;inum_entries;i++) { + if (cluster_id_equal(server, &d->entries[i].server)) { + if (i < d->num_entries-1) { + memmove(&d->entries[i], &d->entries[i+1], + sizeof(d->entries[i])*(d->num_entries-(i+1))); + } + i--; + d->num_entries--; + del_count++; + } + } + } + + if (del_count > 0) { + status = notify_save(notify); + } + + notify_unlock(notify); + + return status; +} + + +/* + send a notify message to another messaging server +*/ +static NTSTATUS notify_send(struct notify_context *notify, struct notify_entry *e, + const char *path, uint32_t action) +{ + struct notify_event ev; + DATA_BLOB data; + NTSTATUS status; + TALLOC_CTX *tmp_ctx; + + ev.action = action; + ev.path = path; + ev.private_data = e->private_data; + + tmp_ctx = talloc_new(notify); + + status = ndr_push_struct_blob(&data, tmp_ctx, &ev, + (ndr_push_flags_fn_t)ndr_push_notify_event); + if (!NT_STATUS_IS_OK(status)) { + talloc_free(tmp_ctx); + return status; + } + + status = messaging_send(notify->messaging_ctx, e->server, + MSG_PVFS_NOTIFY, &data); + talloc_free(tmp_ctx); + return status; +} + + +/* + trigger a notify message for anyone waiting on a matching event + + This function is called a lot, and needs to be very fast. The unusual data structure + and traversal is designed to be fast in the average case, even for large numbers of + notifies +*/ +void notify_trigger(struct notify_context *notify, + uint32_t action, uint32_t filter, const char *path) +{ + NTSTATUS status; + int depth; + const char *p, *next_p; + + DEBUG(10, ("notify_trigger called action=0x%x, filter=0x%x, " + "path=%s\n", (unsigned)action, (unsigned)filter, path)); + + /* see if change notify is enabled at all */ + if (notify == NULL) { + return; + } + + again: + status = notify_load(notify); + if (!NT_STATUS_IS_OK(status)) { + return; + } + + /* loop along the given path, working with each directory depth separately */ + for (depth=0,p=path; + p && depth < notify->array->num_depths; + p=next_p,depth++) { + int p_len = p - path; + int min_i, max_i, i; + struct notify_depth *d = ¬ify->array->depth[depth]; + next_p = strchr(p+1, '/'); + + /* see if there are any entries at this depth */ + if (d->num_entries == 0) continue; + + /* try to skip based on the maximum mask. If next_p is + NULL then we know it will be a 'this directory' + match, otherwise it must be a subdir match */ + if (next_p != NULL) { + if (0 == (filter & d->max_mask_subdir)) { + continue; + } + } else { + if (0 == (filter & d->max_mask)) { + continue; + } + } + + /* we know there is an entry here worth looking + for. Use a bisection search to find the first entry + with a matching path */ + min_i = 0; + max_i = d->num_entries-1; + + while (min_i < max_i) { + struct notify_entry *e; + int cmp; + i = (min_i+max_i)/2; + e = &d->entries[i]; + cmp = strncmp(path, e->path, p_len); + if (cmp == 0) { + if (p_len == e->path_len) { + max_i = i; + } else { + max_i = i-1; + } + } else if (cmp < 0) { + max_i = i-1; + } else { + min_i = i+1; + } + } + + if (min_i != max_i) { + /* none match */ + continue; + } + + /* we now know that the entries start at min_i */ + for (i=min_i;inum_entries;i++) { + struct notify_entry *e = &d->entries[i]; + if (p_len != e->path_len || + strncmp(path, e->path, p_len) != 0) break; + if (next_p != NULL) { + if (0 == (filter & e->subdir_filter)) { + continue; + } + } else { + if (0 == (filter & e->filter)) { + continue; + } + } + status = notify_send(notify, e, path + e->path_len + 1, + action); + + if (NT_STATUS_EQUAL( + status, NT_STATUS_INVALID_HANDLE)) { + struct server_id server = e->server; + + DEBUG(10, ("Deleting notify entries for " + "process %s because it's gone\n", + procid_str_static(&e->server.id))); + notify_remove_all(notify, &server); + goto again; + } + } + } +} diff --git a/source/smbd/notify_kernel.c b/source/smbd/notify_kernel.c deleted file mode 100644 index 0c20effc3d1..00000000000 --- a/source/smbd/notify_kernel.c +++ /dev/null @@ -1,247 +0,0 @@ -/* - Unix SMB/Netbios implementation. - Version 3.0 - change notify handling - linux kernel based implementation - Copyright (C) Andrew Tridgell 2000 - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -*/ - -#include "includes.h" - -#if HAVE_KERNEL_CHANGE_NOTIFY - -#define FD_PENDING_SIZE 20 -static SIG_ATOMIC_T fd_pending_array[FD_PENDING_SIZE]; -static SIG_ATOMIC_T signals_received; - -#ifndef DN_ACCESS -#define DN_ACCESS 0x00000001 /* File accessed in directory */ -#define DN_MODIFY 0x00000002 /* File modified in directory */ -#define DN_CREATE 0x00000004 /* File created in directory */ -#define DN_DELETE 0x00000008 /* File removed from directory */ -#define DN_RENAME 0x00000010 /* File renamed in directory */ -#define DN_ATTRIB 0x00000020 /* File changed attribute */ -#define DN_MULTISHOT 0x80000000 /* Don't remove notifier */ -#endif - - -#ifndef RT_SIGNAL_NOTIFY -#define RT_SIGNAL_NOTIFY (SIGRTMIN+2) -#endif - -#ifndef F_SETSIG -#define F_SETSIG 10 -#endif - -#ifndef F_NOTIFY -#define F_NOTIFY 1026 -#endif - -/**************************************************************************** - This is the structure to keep the information needed to - determine if a directory has changed. -*****************************************************************************/ - -struct change_data { - int directory_handle; -}; - -/**************************************************************************** - The signal handler for change notify. - The Linux kernel has a bug in that we should be able to block any - further delivery of RT signals until the kernel_check_notify() function - unblocks them, but it seems that any signal mask we're setting here is - being overwritten on exit from this handler. I should create a standalone - test case for the kernel hackers. JRA. -*****************************************************************************/ - -static void signal_handler(int sig, siginfo_t *info, void *unused) -{ - if (signals_received < FD_PENDING_SIZE - 1) { - fd_pending_array[signals_received] = (SIG_ATOMIC_T)info->si_fd; - signals_received++; - } /* Else signal is lost. */ - sys_select_signal(RT_SIGNAL_NOTIFY); -} - -/**************************************************************************** - Check if a change notify should be issued. - time non-zero means timeout check (used for hash). Ignore this (async method - where time is zero will be used instead). -*****************************************************************************/ - -static BOOL kernel_check_notify(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *datap, time_t t) -{ - struct change_data *data = (struct change_data *)datap; - int i; - BOOL ret = False; - - if (t) - return False; - - BlockSignals(True, RT_SIGNAL_NOTIFY); - for (i = 0; i < signals_received; i++) { - if (data->directory_handle == (int)fd_pending_array[i]) { - DEBUG(3,("kernel_check_notify: kernel change notify on %s fd[%d]=%d (signals_received=%d)\n", - path, i, (int)fd_pending_array[i], (int)signals_received )); - - close((int)fd_pending_array[i]); - fd_pending_array[i] = (SIG_ATOMIC_T)-1; - if (signals_received - i - 1) { - memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1], - sizeof(SIG_ATOMIC_T)*(signals_received-i-1)); - } - data->directory_handle = -1; - signals_received--; - ret = True; - break; - } - } - BlockSignals(False, RT_SIGNAL_NOTIFY); - return ret; -} - -/**************************************************************************** - Remove a change notify data structure. -*****************************************************************************/ - -static void kernel_remove_notify(void *datap) -{ - struct change_data *data = (struct change_data *)datap; - int fd = data->directory_handle; - if (fd != -1) { - int i; - BlockSignals(True, RT_SIGNAL_NOTIFY); - for (i = 0; i < signals_received; i++) { - if (fd == (int)fd_pending_array[i]) { - fd_pending_array[i] = (SIG_ATOMIC_T)-1; - if (signals_received - i - 1) { - memmove((void *)&fd_pending_array[i], (void *)&fd_pending_array[i+1], - sizeof(SIG_ATOMIC_T)*(signals_received-i-1)); - } - data->directory_handle = -1; - signals_received--; - break; - } - } - close(fd); - BlockSignals(False, RT_SIGNAL_NOTIFY); - } - SAFE_FREE(data); - DEBUG(3,("kernel_remove_notify: fd=%d\n", fd)); -} - -/**************************************************************************** - Register a change notify request. -*****************************************************************************/ - -static void *kernel_register_notify(connection_struct *conn, char *path, uint32 flags) -{ - struct change_data data; - int fd; - unsigned long kernel_flags; - - fd = sys_open(path,O_RDONLY, 0); - - if (fd == -1) { - DEBUG(3,("Failed to open directory %s for change notify\n", path)); - return NULL; - } - - if (sys_fcntl_long(fd, F_SETSIG, RT_SIGNAL_NOTIFY) == -1) { - DEBUG(3,("Failed to set signal handler for change notify\n")); - return NULL; - } - - kernel_flags = DN_CREATE|DN_DELETE|DN_RENAME; /* creation/deletion changes everything! */ - if (flags & FILE_NOTIFY_CHANGE_FILE) kernel_flags |= DN_MODIFY; - if (flags & FILE_NOTIFY_CHANGE_DIR_NAME) kernel_flags |= DN_RENAME|DN_DELETE; - if (flags & FILE_NOTIFY_CHANGE_ATTRIBUTES) kernel_flags |= DN_ATTRIB; - if (flags & FILE_NOTIFY_CHANGE_SIZE) kernel_flags |= DN_MODIFY; - if (flags & FILE_NOTIFY_CHANGE_LAST_WRITE) kernel_flags |= DN_MODIFY; - if (flags & FILE_NOTIFY_CHANGE_LAST_ACCESS) kernel_flags |= DN_ACCESS; - if (flags & FILE_NOTIFY_CHANGE_CREATION) kernel_flags |= DN_CREATE; - if (flags & FILE_NOTIFY_CHANGE_SECURITY) kernel_flags |= DN_ATTRIB; - if (flags & FILE_NOTIFY_CHANGE_EA) kernel_flags |= DN_ATTRIB; - if (flags & FILE_NOTIFY_CHANGE_FILE_NAME) kernel_flags |= DN_RENAME|DN_DELETE; - - if (sys_fcntl_long(fd, F_NOTIFY, kernel_flags) == -1) { - DEBUG(3,("Failed to set async flag for change notify\n")); - return NULL; - } - - data.directory_handle = fd; - - DEBUG(3,("kernel change notify on %s (ntflags=0x%x flags=0x%x) fd=%d\n", - path, (int)flags, (int)kernel_flags, fd)); - - return (void *)memdup(&data, sizeof(data)); -} - -/**************************************************************************** - See if the kernel supports change notify. -****************************************************************************/ - -static BOOL kernel_notify_available(void) -{ - int fd, ret; - fd = open("/tmp", O_RDONLY); - if (fd == -1) - return False; /* uggh! */ - ret = sys_fcntl_long(fd, F_NOTIFY, 0); - close(fd); - return ret == 0; -} - -/**************************************************************************** - Setup kernel based change notify. -****************************************************************************/ - -struct cnotify_fns *kernel_notify_init(void) -{ - static struct cnotify_fns cnotify; - struct sigaction act; - - ZERO_STRUCT(act); - - act.sa_sigaction = signal_handler; - act.sa_flags = SA_SIGINFO; - sigemptyset( &act.sa_mask ); - if (sigaction(RT_SIGNAL_NOTIFY, &act, NULL) != 0) { - DEBUG(0,("Failed to setup RT_SIGNAL_NOTIFY handler\n")); - return NULL; - } - - if (!kernel_notify_available()) - return NULL; - - cnotify.register_notify = kernel_register_notify; - cnotify.check_notify = kernel_check_notify; - cnotify.remove_notify = kernel_remove_notify; - cnotify.select_time = -1; - cnotify.notification_fd = -1; - - /* the signal can start off blocked due to a bug in bash */ - BlockSignals(False, RT_SIGNAL_NOTIFY); - - return &cnotify; -} - -#else - void notify_kernel_dummy(void); - - void notify_kernel_dummy(void) {} -#endif /* HAVE_KERNEL_CHANGE_NOTIFY */ diff --git a/source/smbd/nttrans.c b/source/smbd/nttrans.c index 2eddffb7f16..08f19e7bdb6 100644 --- a/source/smbd/nttrans.c +++ b/source/smbd/nttrans.c @@ -1782,11 +1782,6 @@ int reply_ntrename(connection_struct *conn, return ERROR_NT(status); } - /* - * Win2k needs a changenotify request response before it will - * update after a rename.. - */ - process_pending_change_notify_queue((time_t)0); outsize = set_message(outbuf,0,0,False); END_PROFILE(SMBntrename); @@ -1810,14 +1805,17 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, { uint16 *setup = *ppsetup; files_struct *fsp; - uint32 flags; + uint32 filter; + NTSTATUS status; + BOOL recursive; if(setup_count < 6) { return ERROR_DOS(ERRDOS,ERRbadfunc); } fsp = file_fsp((char *)setup,4); - flags = IVAL(setup, 0); + filter = IVAL(setup, 0); + recursive = (SVAL(setup, 6) != 0) ? True : False; DEBUG(3,("call_nt_transact_notify_change\n")); @@ -1825,16 +1823,65 @@ static int call_nt_transact_notify_change(connection_struct *conn, char *inbuf, return ERROR_DOS(ERRDOS,ERRbadfid); } + { + char *filter_string; + + if (!(filter_string = notify_filter_string(NULL, filter))) { + return ERROR_NT(NT_STATUS_NO_MEMORY); + } + + DEBUG(3,("call_nt_transact_notify_change: notify change " + "called on %s, filter = %s, recursive = %d\n", + fsp->fsp_name, filter_string, recursive)); + + TALLOC_FREE(filter_string); + } + if((!fsp->is_directory) || (conn != fsp->conn)) { - return ERROR_DOS(ERRDOS,ERRbadfid); + return ERROR_NT(NT_STATUS_INVALID_PARAMETER); } - if (!change_notify_set(inbuf, fsp, conn, flags)) { - return(UNIXERROR(ERRDOS,ERRbadfid)); + if (fsp->notify == NULL) { + + status = change_notify_create(fsp, filter, recursive); + + if (!NT_STATUS_IS_OK(status)) { + DEBUG(10, ("change_notify_create returned %s\n", + nt_errstr(status))); + return ERROR_NT(status); + } } - DEBUG(3,("call_nt_transact_notify_change: notify change called on directory \ -name = %s\n", fsp->fsp_name )); + if (fsp->notify->num_changes != 0) { + + /* + * We've got changes pending, respond immediately + */ + + /* + * TODO: write a torture test to check the filtering behaviour + * here. + */ + + change_notify_reply(inbuf, max_param_count, + fsp->notify); + + /* + * change_notify_reply() above has independently sent its + * results + */ + return -1; + } + + /* + * No changes pending, queue the request + */ + + status = change_notify_add_request(inbuf, max_param_count, filter, + recursive, fsp); + if (!NT_STATUS_IS_OK(status)) { + return ERROR_NT(status); + } return -1; } @@ -1886,13 +1933,6 @@ static int call_nt_transact_rename(connection_struct *conn, char *inbuf, char *o DEBUG(3,("nt transact rename from = %s, to = %s succeeded.\n", fsp->fsp_name, new_name)); - /* - * Win2k needs a changenotify request response before it will - * update after a rename.. - */ - - process_pending_change_notify_queue((time_t)0); - return -1; } diff --git a/source/smbd/open.c b/source/smbd/open.c index 05023729474..89474874cc5 100644 --- a/source/smbd/open.c +++ b/source/smbd/open.c @@ -197,7 +197,8 @@ static void change_dir_owner_to_parent(connection_struct *conn, static NTSTATUS open_file(files_struct *fsp, connection_struct *conn, const char *parent_dir, - const char *fname, + const char *name, + const char *path, SMB_STRUCT_STAT *psbuf, int flags, mode_t unx_mode, @@ -226,7 +227,7 @@ static NTSTATUS open_file(files_struct *fsp, if (!CAN_WRITE(conn)) { /* It's a read-only share - fail if we wanted to write. */ if(accmode != O_RDONLY) { - DEBUG(3,("Permission denied opening %s\n",fname)); + DEBUG(3,("Permission denied opening %s\n", path)); return NT_STATUS_ACCESS_DENIED; } else if(flags & O_CREAT) { /* We don't want to write - but we must make sure that @@ -252,7 +253,7 @@ static NTSTATUS open_file(files_struct *fsp, if ((accmode == O_RDONLY) && ((flags & O_TRUNC) == O_TRUNC)) { DEBUG(10,("open_file: truncate requested on read-only open " - "for file %s\n",fname )); + "for file %s\n", path)); local_flags = (flags & ~O_ACCMODE)|O_RDWR; } @@ -281,15 +282,15 @@ static NTSTATUS open_file(files_struct *fsp, /* Don't create files with Microsoft wildcard characters. */ if ((local_flags & O_CREAT) && !file_existed && - ms_has_wild(fname)) { + ms_has_wild(path)) { return NT_STATUS_OBJECT_NAME_INVALID; } /* Actually do the open */ - if (!fd_open(conn, fname, fsp, local_flags, unx_mode)) { + if (!fd_open(conn, path, fsp, local_flags, unx_mode)) { DEBUG(3,("Error opening file %s (%s) (local_flags=%d) " "(flags=%d)\n", - fname,strerror(errno),local_flags,flags)); + path,strerror(errno),local_flags,flags)); return map_nt_error_from_unix(errno); } @@ -297,7 +298,7 @@ static NTSTATUS open_file(files_struct *fsp, /* Inherit the ACL if required */ if (lp_inherit_perms(SNUM(conn))) { - inherit_access_acl(conn, parent_dir, fname, + inherit_access_acl(conn, parent_dir, path, unx_mode); } @@ -306,6 +307,9 @@ static NTSTATUS open_file(files_struct *fsp, change_file_owner_to_parent(conn, parent_dir, fsp); } + + notify_fname(conn, NOTIFY_ACTION_ADDED, + FILE_NOTIFY_CHANGE_FILE_NAME, path); } } else { @@ -316,13 +320,13 @@ static NTSTATUS open_file(files_struct *fsp, int ret; if (fsp->fh->fd == -1) { - ret = SMB_VFS_STAT(conn, fname, psbuf); + ret = SMB_VFS_STAT(conn, path, psbuf); } else { ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,psbuf); /* If we have an fd, this stat should succeed. */ if (ret == -1) { DEBUG(0,("Error doing fstat on open file %s " - "(%s)\n", fname,strerror(errno) )); + "(%s)\n", path,strerror(errno) )); } } @@ -365,11 +369,11 @@ static NTSTATUS open_file(files_struct *fsp, fsp->is_directory = False; fsp->is_stat = False; if (conn->aio_write_behind_list && - is_in_path(fname, conn->aio_write_behind_list, conn->case_sensitive)) { + is_in_path(path, conn->aio_write_behind_list, conn->case_sensitive)) { fsp->aio_write_behind = True; } - string_set(&fsp->fsp_name,fname); + string_set(&fsp->fsp_name, path); fsp->wcp = NULL; /* Write cache pointer. */ DEBUG(2,("%s opened file %s read=%s write=%s (numopen=%d)\n", @@ -646,7 +650,7 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck, BOOL valid_entry = False; BOOL delay_it = False; BOOL have_level2 = False; - BOOL ret; + NTSTATUS status; char msg[MSG_SMB_SHARE_MODE_ENTRY_SIZE]; if (oplock_request & INTERNAL_OPEN_ONLY) { @@ -734,10 +738,11 @@ static BOOL delay_for_oplocks(struct share_mode_lock *lck, SSVAL(msg,6,exclusive->op_type | FORCE_OPLOCK_BREAK_TO_NONE); } - ret = message_send_pid(exclusive->pid, MSG_SMB_BREAK_REQUEST, - msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True); - if (!ret) { - DEBUG(3, ("Could not send oplock break message\n")); + status = message_send_pid(exclusive->pid, MSG_SMB_BREAK_REQUEST, + msg, MSG_SMB_SHARE_MODE_ENTRY_SIZE, True); + if (!NT_STATUS_IS_OK(status)) { + DEBUG(3, ("Could not send oplock break message: %s\n", + nt_errstr(status))); } return True; @@ -1594,8 +1599,9 @@ NTSTATUS open_file_ntcreate(connection_struct *conn, * open_file strips any O_TRUNC flags itself. */ - fsp_open = open_file(fsp, conn, parent_dir, fname, psbuf, flags|flags2, - unx_mode, access_mask, open_access_mask); + fsp_open = open_file(fsp, conn, parent_dir, newname, fname, psbuf, + flags|flags2, unx_mode, access_mask, + open_access_mask); if (!NT_STATUS_IS_OK(fsp_open)) { if (lck != NULL) { @@ -1860,7 +1866,7 @@ NTSTATUS open_file_fchmod(connection_struct *conn, const char *fname, /* note! we must use a non-zero desired access or we don't get a real file descriptor. Oh what a twisted web we weave. */ - status = open_file(fsp, conn, NULL, fname, psbuf, O_WRONLY, 0, + status = open_file(fsp, conn, NULL, NULL, fname, psbuf, O_WRONLY, 0, FILE_WRITE_DATA, FILE_WRITE_DATA); /* @@ -1963,6 +1969,9 @@ static NTSTATUS mkdir_internal(connection_struct *conn, change_dir_owner_to_parent(conn, parent_dir, name, psbuf); } + notify_fname(conn, NOTIFY_ACTION_ADDED, FILE_NOTIFY_CHANGE_DIR_NAME, + name); + return NT_STATUS_OK; } @@ -2240,7 +2249,8 @@ NTSTATUS open_file_stat(connection_struct *conn, const char *fname, smbd process. ****************************************************************************/ -void msg_file_was_renamed(int msg_type, struct process_id src, void *buf, size_t len) +void msg_file_was_renamed(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { files_struct *fsp; char *frm = (char *)buf; diff --git a/source/smbd/oplock.c b/source/smbd/oplock.c index 526b7ced9ec..423d6b3a999 100644 --- a/source/smbd/oplock.c +++ b/source/smbd/oplock.c @@ -342,7 +342,8 @@ static files_struct *initial_break_processing(SMB_DEV_T dev, SMB_INO_T inode, un return fsp; } -static void oplock_timeout_handler(struct timed_event *te, +static void oplock_timeout_handler(struct event_context *ctx, + struct timed_event *te, const struct timeval *now, void *private_data) { @@ -372,7 +373,7 @@ static void add_oplock_timeout_handler(files_struct *fsp) } fsp->oplock_timeout = - add_timed_event(NULL, + event_add_timed(smbd_event_context(), NULL, timeval_current_ofs(OPLOCK_BREAK_TIMEOUT, 0), "oplock_timeout_handler", oplock_timeout_handler, fsp); @@ -391,7 +392,8 @@ static void add_oplock_timeout_handler(files_struct *fsp) *******************************************************************/ static void process_oplock_async_level2_break_message(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, + void *private_data) { struct share_mode_entry msg; files_struct *fsp; @@ -477,7 +479,8 @@ static void process_oplock_async_level2_break_message(int msg_type, struct proce *******************************************************************/ static void process_oplock_break_message(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, + void *private_data) { struct share_mode_entry msg; files_struct *fsp; @@ -585,7 +588,8 @@ static void process_oplock_break_message(int msg_type, struct process_id src, *******************************************************************/ static void process_kernel_oplock_break(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, + void *private_data) { SMB_DEV_T dev; SMB_INO_T inode; @@ -676,7 +680,8 @@ void reply_to_oplock_break_requests(files_struct *fsp) } static void process_oplock_break_response(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, + void *private_data) { struct share_mode_entry msg; @@ -703,7 +708,8 @@ static void process_oplock_break_response(int msg_type, struct process_id src, } static void process_open_retry_message(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, + void *private_data) { struct share_mode_entry msg; @@ -859,15 +865,20 @@ BOOL init_oplocks(void) DEBUG(3,("init_oplocks: initializing messages.\n")); message_register(MSG_SMB_BREAK_REQUEST, - process_oplock_break_message); + process_oplock_break_message, + NULL); message_register(MSG_SMB_ASYNC_LEVEL2_BREAK, - process_oplock_async_level2_break_message); + process_oplock_async_level2_break_message, + NULL); message_register(MSG_SMB_BREAK_RESPONSE, - process_oplock_break_response); + process_oplock_break_response, + NULL); message_register(MSG_SMB_KERNEL_BREAK, - process_kernel_oplock_break); + process_kernel_oplock_break, + NULL); message_register(MSG_SMB_OPEN_RETRY, - process_open_retry_message); + process_open_retry_message, + NULL); if (lp_kernel_oplocks()) { #if HAVE_KERNEL_OPLOCKS_IRIX diff --git a/source/smbd/process.c b/source/smbd/process.c index ffc731e42b3..5830af8f435 100644 --- a/source/smbd/process.c +++ b/source/smbd/process.c @@ -225,7 +225,8 @@ struct idle_event { void *private_data; }; -static void idle_event_handler(struct timed_event *te, +static void idle_event_handler(struct event_context *ctx, + struct timed_event *te, const struct timeval *now, void *private_data) { @@ -240,7 +241,8 @@ static void idle_event_handler(struct timed_event *te, return; } - event->te = add_timed_event(event, timeval_sum(now, &event->interval), + event->te = event_add_timed(smbd_event_context(), event, + timeval_sum(now, &event->interval), "idle_event_handler", idle_event_handler, event); @@ -267,11 +269,12 @@ struct idle_event *add_idle_event(TALLOC_CTX *mem_ctx, result->handler = handler; result->private_data = private_data; - result->te = add_timed_event(result, timeval_sum(&now, &interval), + result->te = event_add_timed(smbd_event_context(), result, + timeval_sum(&now, &interval), "idle_event_handler", idle_event_handler, result); if (result->te == NULL) { - DEBUG(0, ("add_timed_event failed\n")); + DEBUG(0, ("event_add_timed failed\n")); TALLOC_FREE(result); return NULL; } @@ -301,9 +304,6 @@ static void async_processing(fd_set *pfds) exit_server_cleanly("termination signal"); } - /* check for async change notify events */ - process_pending_change_notify_queue(0); - /* check for sighup processing */ if (reload_after_sighup) { change_to_root_user(); @@ -350,7 +350,7 @@ The timeout is in milliseconds static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) { - fd_set fds; + fd_set r_fds, w_fds; int selrtn; struct timeval to; int maxfd = 0; @@ -414,10 +414,11 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) } /* - * Setup the select read fd set. + * Setup the select fd sets. */ - FD_ZERO(&fds); + FD_ZERO(&r_fds); + FD_ZERO(&w_fds); /* * Ensure we process oplock break messages by preference. @@ -428,9 +429,9 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) * This is hideously complex - *MUST* be simplified for 3.0 ! JRA. */ - if (oplock_message_waiting(&fds)) { + if (oplock_message_waiting(&r_fds)) { DEBUG(10,("receive_message_or_smb: oplock_message is waiting.\n")); - async_processing(&fds); + async_processing(&r_fds); /* * After async processing we must go and do the select again, as * the state of the flag in fds for the server file descriptor is @@ -445,15 +446,17 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) */ { - struct timeval tmp; - struct timeval *tp = get_timed_events_timeout(&tmp); - - if (tp) { - to = timeval_min(&to, tp); - if (timeval_is_zero(&to)) { - /* Process a timed event now... */ - run_events(); - } + struct timeval now; + GetTimeOfDay(&now); + + event_add_to_select_args(smbd_event_context(), &now, + &r_fds, &w_fds, &to, &maxfd); + } + + if (timeval_is_zero(&to)) { + /* Process a timed event now... */ + if (run_events(smbd_event_context(), 0, NULL, NULL)) { + goto again; } } @@ -461,23 +464,26 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) int sav; START_PROFILE(smbd_idle); - maxfd = select_on_fd(smbd_server_fd(), maxfd, &fds); - maxfd = select_on_fd(change_notify_fd(), maxfd, &fds); - maxfd = select_on_fd(oplock_notify_fd(), maxfd, &fds); + maxfd = select_on_fd(smbd_server_fd(), maxfd, &r_fds); + maxfd = select_on_fd(oplock_notify_fd(), maxfd, &r_fds); - selrtn = sys_select(maxfd+1,&fds,NULL,NULL,&to); + selrtn = sys_select(maxfd+1,&r_fds,&w_fds,NULL,&to); sav = errno; END_PROFILE(smbd_idle); errno = sav; } + if (run_events(smbd_event_context(), selrtn, &r_fds, &w_fds)) { + goto again; + } + /* if we get EINTR then maybe we have received an oplock signal - treat this as select returning 1. This is ugly, but is the best we can do until the oplock code knows more about signals */ if (selrtn == -1 && errno == EINTR) { - async_processing(&fds); + async_processing(&r_fds); /* * After async processing we must go and do the select again, as * the state of the flag in fds for the server file descriptor is @@ -505,8 +511,8 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) * sending us an oplock break message. JRA. */ - if (oplock_message_waiting(&fds)) { - async_processing(&fds); + if (oplock_message_waiting(&r_fds)) { + async_processing(&r_fds); /* * After async processing we must go and do the select again, as * the state of the flag in fds for the server file descriptor is @@ -515,19 +521,6 @@ static BOOL receive_message_or_smb(char *buffer, int buffer_len, int timeout) goto again; } - if ((change_notify_fd() >= 0) && FD_ISSET(change_notify_fd(), &fds)) { - - process_pending_change_notify_queue((time_t)0); - - /* - * Same comment as for oplock processing applies here. We - * might have done I/O on the client socket. - */ - - goto again; - } - - return receive_smb(smbd_server_fd(), buffer, 0); } @@ -1240,16 +1233,9 @@ int chain_reply(char *inbuf,char *outbuf,int size,int bufsize) static int setup_select_timeout(void) { int select_timeout; - int t; select_timeout = blocking_locks_timeout_ms(SMBD_SELECT_TIMEOUT*1000); - t = change_notify_timeout(); - DEBUG(10, ("change_notify_timeout: %d\n", t)); - if (t != -1) { - select_timeout = MIN(select_timeout, t*1000); - } - if (print_notify_messages_pending()) { select_timeout = MIN(select_timeout, 1000); } @@ -1447,12 +1433,6 @@ machine %s in domain %s.\n", global_myname(), lp_workgroup())); update_monitored_printq_cache(); - /* - * Check to see if we have any change notifies - * outstanding on the queue. - */ - process_pending_change_notify_queue(t); - /* * Now we are root, check if the log files need pruning. * Force a log file check. @@ -1603,7 +1583,7 @@ void smbd_process(void) num_smbs = 0; /* Reset smb counter. */ } - run_events(); + run_events(smbd_event_context(), 0, NULL, NULL); #if defined(DEVELOPER) clobber_region(SAFE_STRING_FUNCTION_NAME, SAFE_STRING_LINE, InBuffer, total_buffer_size); diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 315b338b0ba..c48bebb0c6c 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -1865,6 +1865,9 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, if (SMB_VFS_UNLINK(conn,directory) == 0) { count++; + notify_fname(conn, NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_FILE_NAME, + directory); } } else { struct smb_Dir *dir_hnd = NULL; @@ -1921,9 +1924,15 @@ NTSTATUS unlink_internals(connection_struct *conn, uint32 dirtype, if (!NT_STATUS_IS_OK(status)) { continue; } - if (SMB_VFS_UNLINK(conn,fname) == 0) + if (SMB_VFS_UNLINK(conn,fname) == 0) { count++; - DEBUG(3,("unlink_internals: succesful unlink [%s]\n",fname)); + DEBUG(3,("unlink_internals: succesful unlink " + "[%s]\n",fname)); + notify_fname(conn, NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_FILE_NAME, + fname); + } + } CloseDir(dir_hnd); } @@ -1972,12 +1981,6 @@ int reply_unlink(connection_struct *conn, char *inbuf,char *outbuf, int dum_size return ERROR_NT(status); } - /* - * Win2k needs a changenotify request response before it will - * update after a rename.. - */ - process_pending_change_notify_queue((time_t)0); - outsize = set_message(outbuf,0,0,False); END_PROFILE(SMBunlink); @@ -3702,6 +3705,9 @@ NTSTATUS rmdir_internals(connection_struct *conn, const char *directory) ret = SMB_VFS_RMDIR(conn,directory); if (ret == 0) { + notify_fname(conn, NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_DIR_NAME, + directory); return NT_STATUS_OK; } @@ -3779,6 +3785,10 @@ NTSTATUS rmdir_internals(connection_struct *conn, const char *directory) return map_nt_error_from_unix(errno); } + notify_fname(conn, NOTIFY_ACTION_REMOVED, + FILE_NOTIFY_CHANGE_DIR_NAME, + directory); + return NT_STATUS_OK; } @@ -4095,6 +4105,48 @@ NTSTATUS rename_internals_fsp(connection_struct *conn, files_struct *fsp, pstrin return status; } +/* + * Do the notify calls from a rename + */ + +static void notify_rename(connection_struct *conn, BOOL is_dir, + const char *oldpath, const char *newpath) +{ + char *olddir, *newdir; + const char *oldname, *newname; + uint32 mask; + + mask = is_dir ? FILE_NOTIFY_CHANGE_DIR_NAME + : FILE_NOTIFY_CHANGE_FILE_NAME; + + if (!parent_dirname_talloc(NULL, oldpath, &olddir, &oldname) + || !parent_dirname_talloc(NULL, newpath, &newdir, &newname)) { + TALLOC_FREE(olddir); + return; + } + + if (strcmp(olddir, newdir) == 0) { + notify_fname(conn, NOTIFY_ACTION_OLD_NAME, mask, oldpath); + notify_fname(conn, NOTIFY_ACTION_NEW_NAME, mask, newpath); + } + else { + notify_fname(conn, NOTIFY_ACTION_REMOVED, mask, oldpath); + notify_fname(conn, NOTIFY_ACTION_ADDED, mask, newpath); + } + TALLOC_FREE(olddir); + TALLOC_FREE(newdir); + + /* this is a strange one. w2k3 gives an additional event for + CHANGE_ATTRIBUTES and CHANGE_CREATION on the new file when renaming + files, but not directories */ + if (!is_dir) { + notify_fname(conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_ATTRIBUTES + |FILE_NOTIFY_CHANGE_CREATION, + newpath); + } +} + /**************************************************************************** The guts of the rename command, split out so it may be called by the NT SMB code. @@ -4301,6 +4353,8 @@ NTSTATUS rename_internals(connection_struct *conn, pstring name, rename_open_files(conn, lck, sbuf1.st_dev, sbuf1.st_ino, newname); TALLOC_FREE(lck); + notify_rename(conn, S_ISDIR(sbuf1.st_mode), + directory, newname); return NT_STATUS_OK; } @@ -4499,11 +4553,6 @@ int reply_mv(connection_struct *conn, char *inbuf,char *outbuf, int dum_size, return ERROR_NT(status); } - /* - * Win2k needs a changenotify request response before it will - * update after a rename.. - */ - process_pending_change_notify_queue((time_t)0); outsize = set_message(outbuf,0,0,False); END_PROFILE(SMBmv); diff --git a/source/smbd/server.c b/source/smbd/server.c index 38767ab402e..ab32d656d38 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -61,12 +61,33 @@ static void smbd_set_server_fd(int fd) client_setfd(fd); } +struct event_context *smbd_event_context(void) +{ + static struct event_context *ctx; + + if (!ctx && !(ctx = event_context_init(NULL))) { + smb_panic("Could not init smbd event context\n"); + } + return ctx; +} + +struct messaging_context *smbd_messaging_context(void) +{ + static struct messaging_context *ctx; + + if (!ctx && !(ctx = messaging_init(NULL, server_id_self(), + smbd_event_context()))) { + smb_panic("Could not init smbd messaging context\n"); + } + return ctx; +} + /******************************************************************* What to do when smb.conf is updated. ********************************************************************/ static void smb_conf_updated(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { DEBUG(10,("smb_conf_updated: Got message saying smb.conf was updated. Reloading.\n")); reload_services(False); @@ -78,7 +99,7 @@ static void smb_conf_updated(int msg_type, struct process_id src, ********************************************************************/ static void smb_stat_cache_delete(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { const char *name = (const char *)buf; DEBUG(10,("smb_stat_cache_delete: delete name %s\n", name)); @@ -129,7 +150,8 @@ static void killkids(void) ****************************************************************************/ static void msg_sam_sync(int UNUSED(msg_type), struct process_id UNUSED(pid), - void *UNUSED(buf), size_t UNUSED(len)) + void *UNUSED(buf), size_t UNUSED(len), + void *private_data) { DEBUG(10, ("** sam sync message received, ignoring\n")); } @@ -140,7 +162,7 @@ static void msg_sam_sync(int UNUSED(msg_type), struct process_id UNUSED(pid), ****************************************************************************/ static void msg_sam_repl(int msg_type, struct process_id pid, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { uint32 low_serial; @@ -174,7 +196,7 @@ static BOOL open_sockets_inetd(void) } static void msg_exit_server(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { DEBUG(3, ("got a SHUTDOWN message\n")); exit_server_cleanly(NULL); @@ -182,7 +204,7 @@ static void msg_exit_server(int msg_type, struct process_id src, #ifdef DEVELOPER static void msg_inject_fault(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { int sig; @@ -419,15 +441,16 @@ static BOOL open_sockets_smbd(BOOL is_daemon, BOOL interactive, const char *smb_ /* Listen to messages */ - message_register(MSG_SMB_SAM_SYNC, msg_sam_sync); - message_register(MSG_SMB_SAM_REPL, msg_sam_repl); - message_register(MSG_SHUTDOWN, msg_exit_server); - message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed); - message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated); - message_register(MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete); + message_register(MSG_SMB_SAM_SYNC, msg_sam_sync, NULL); + message_register(MSG_SMB_SAM_REPL, msg_sam_repl, NULL); + message_register(MSG_SHUTDOWN, msg_exit_server, NULL); + message_register(MSG_SMB_FILE_RENAME, msg_file_was_renamed, NULL); + message_register(MSG_SMB_CONF_UPDATED, smb_conf_updated, NULL); + message_register(MSG_SMB_STAT_CACHE_DELETE, smb_stat_cache_delete, + NULL); #ifdef DEVELOPER - message_register(MSG_SMB_INJECT_FAULT, msg_inject_fault); + message_register(MSG_SMB_INJECT_FAULT, msg_inject_fault, NULL); #endif /* now accept incoming connections - forking a new process @@ -1078,15 +1101,11 @@ extern void build_options(BOOL screen); if (!init_oplocks()) exit(1); - /* Setup change notify */ - if (!init_change_notify()) - exit(1); - /* Setup aio signal handler. */ initialize_async_io_handler(); /* register our message handlers */ - message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis); + message_register(MSG_SMB_FORCE_TDIS, msg_force_tdis, NULL); smbd_process(); diff --git a/source/smbd/service.c b/source/smbd/service.c index 025fd38ff79..18db2f8aba2 100644 --- a/source/smbd/service.c +++ b/source/smbd/service.c @@ -22,6 +22,31 @@ extern userdom_struct current_user_info; +static BOOL canonicalize_path(connection_struct *conn, pstring path) +{ +#ifdef REALPATH_TAKES_NULL + char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL); + if (!resolved_name) { + return False; + } + pstrcpy(path, resolved_name); + SAFE_FREE(resolved_name); + return True; +#else +#ifdef PATH_MAX + char resolved_name_buf[PATH_MAX+1]; +#else + pstring resolved_name_buf; +#endif + char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf); + if (!resolved_name) { + return False; + } + pstrcpy(path, resolved_name); + return True; +#endif /* REALPATH_TAKES_NULL */ +} + /**************************************************************************** Ensure when setting connectpath it is a canonicalized (no ./ // or ../) absolute path stating in / and not ending in /. @@ -827,6 +852,13 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, set_conn_connectpath(conn,s); } + if ((!conn->printer) && (!conn->ipc)) { + conn->notify_ctx = notify_init(conn->mem_ctx, server_id_self(), + smbd_messaging_context(), + smbd_event_context(), + conn); + } + /* ROOT Activities: */ /* check number of connections */ if (!claim_connection(conn, @@ -980,9 +1012,6 @@ static connection_struct *make_connection_snum(int snum, user_struct *vuser, dbgtext( "(pid %d)\n", (int)sys_getpid() ); } - /* Setup the minimum value for a change notify wait time (seconds). */ - set_change_notify_timeout(lp_change_notify_timeout(snum)); - /* we've finished with the user stuff - go back to root */ change_to_root_user(); return(conn); diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index 8bdd10b643d..b91cdeef702 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -3800,6 +3800,11 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, const SMB_STRUCT_STAT *psbuf, struct utimbuf tvs) { + uint32 action = + FILE_NOTIFY_CHANGE_LAST_ACCESS + |FILE_NOTIFY_CHANGE_LAST_WRITE; + + if (!VALID_STAT(*psbuf)) { return NT_STATUS_OBJECT_NAME_NOT_FOUND; } @@ -3807,10 +3812,12 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, /* get some defaults (no modifications) if any info is zero or -1. */ if (null_mtime(tvs.actime)) { tvs.actime = psbuf->st_atime; + action &= ~FILE_NOTIFY_CHANGE_LAST_ACCESS; } if (null_mtime(tvs.modtime)) { tvs.modtime = psbuf->st_mtime; + action &= ~FILE_NOTIFY_CHANGE_LAST_WRITE; } DEBUG(6,("smb_set_file_time: actime: %s " , ctime(&tvs.actime))); @@ -3847,6 +3854,9 @@ static NTSTATUS smb_set_file_time(connection_struct *conn, if(file_utime(conn, fname, &tvs)!=0) { return map_nt_error_from_unix(errno); } + if (action != 0) { + notify_fname(conn, NOTIFY_ACTION_MODIFIED, action, fname); + } return NT_STATUS_OK; } @@ -4248,10 +4258,6 @@ static NTSTATUS smb_file_rename_information(connection_struct *conn, status = rename_internals(conn, fname, base_name, 0, overwrite, False); } - if (NT_STATUS_IS_OK(status)) { - process_pending_change_notify_queue((time_t)0); - } - return status; } diff --git a/source/smbd/vfs.c b/source/smbd/vfs.c index 643c48cd27c..82ea602187c 100644 --- a/source/smbd/vfs.c +++ b/source/smbd/vfs.c @@ -514,8 +514,13 @@ int vfs_set_filelen(files_struct *fsp, SMB_OFF_T len) release_level_2_oplocks_on_change(fsp); DEBUG(10,("vfs_set_filelen: ftruncate %s to len %.0f\n", fsp->fsp_name, (double)len)); flush_write_cache(fsp, SIZECHANGE_FLUSH); - if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) + if ((ret = SMB_VFS_FTRUNCATE(fsp, fsp->fh->fd, len)) != -1) { set_filelen_write_cache(fsp, len); + notify_fname(fsp->conn, NOTIFY_ACTION_MODIFIED, + FILE_NOTIFY_CHANGE_SIZE + | FILE_NOTIFY_CHANGE_ATTRIBUTES, + fsp->fsp_name); + } return ret; } @@ -792,31 +797,6 @@ char *vfs_GetWd(connection_struct *conn, char *path) return (path); } -BOOL canonicalize_path(connection_struct *conn, pstring path) -{ -#ifdef REALPATH_TAKES_NULL - char *resolved_name = SMB_VFS_REALPATH(conn,path,NULL); - if (!resolved_name) { - return False; - } - pstrcpy(path, resolved_name); - SAFE_FREE(resolved_name); - return True; -#else -#ifdef PATH_MAX - char resolved_name_buf[PATH_MAX+1]; -#else - pstring resolved_name_buf; -#endif - char *resolved_name = SMB_VFS_REALPATH(conn,path,resolved_name_buf); - if (!resolved_name) { - return False; - } - pstrcpy(path, resolved_name); - return True; -#endif /* REALPATH_TAKES_NULL */ -} - /******************************************************************* Reduce a file name, removing .. elements and checking that it is below dir in the heirachy. This uses realpath. diff --git a/source/torture/msgtest.c b/source/torture/msgtest.c index d913c4903f3..5a066bc599e 100644 --- a/source/torture/msgtest.c +++ b/source/torture/msgtest.c @@ -29,7 +29,8 @@ static int pong_count; /**************************************************************************** a useful function for testing the message system ****************************************************************************/ -static void pong_message(int msg_type, struct process_id src, void *buf, size_t len) +static void pong_message(int msg_type, struct process_id src, + void *buf, size_t len, void *private_data) { pong_count++; } @@ -57,7 +58,7 @@ static void pong_message(int msg_type, struct process_id src, void *buf, size_t pid = atoi(argv[1]); n = atoi(argv[2]); - message_register(MSG_PONG, pong_message); + message_register(MSG_PONG, pong_message, NULL); for (i=0;i pong_count + 20) { message_dispatch(); diff --git a/source/torture/vfstest.c b/source/torture/vfstest.c index fa0545988e9..872c7a74c32 100644 --- a/source/torture/vfstest.c +++ b/source/torture/vfstest.c @@ -479,6 +479,27 @@ BOOL reload_services(BOOL test) return (ret); } +struct event_context *smbd_event_context(void) +{ + static struct event_context *ctx; + + if (!ctx && !(ctx = event_context_init(NULL))) { + smb_panic("Could not init smbd event context\n"); + } + return ctx; +} + +struct messaging_context *smbd_messaging_context(void) +{ + static struct messaging_context *ctx; + + if (!ctx && !(ctx = messaging_init(NULL, server_id_self(), + smbd_event_context()))) { + smb_panic("Could not init smbd messaging context\n"); + } + return ctx; +} + /* Main function */ int main(int argc, char *argv[]) diff --git a/source/utils/net_ads.c b/source/utils/net_ads.c index eb3f9da1ca7..02a0b68932c 100644 --- a/source/utils/net_ads.c +++ b/source/utils/net_ads.c @@ -1802,7 +1802,7 @@ static int net_ads_printer_info(int argc, const char **argv) } void do_drv_upgrade_printer(int msg_type, struct process_id src, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { return; } diff --git a/source/utils/smbcontrol.c b/source/utils/smbcontrol.c index 9ca304c62bd..ec1e101e061 100644 --- a/source/utils/smbcontrol.c +++ b/source/utils/smbcontrol.c @@ -59,7 +59,8 @@ static BOOL send_message(struct process_id pid, int msg_type, return False; if (procid_to_pid(&pid) != 0) - return message_send_pid(pid, msg_type, buf, len, duplicates); + return NT_STATUS_IS_OK(message_send_pid(pid, msg_type, buf, len, + duplicates)); tdb = tdb_open_log(lock_path("connections.tdb"), 0, TDB_DEFAULT, O_RDWR, 0); @@ -98,7 +99,8 @@ static void wait_replies(BOOL multiple_replies) /* Message handler callback that displays the PID and a string on stdout */ -static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf, size_t len) +static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf, + size_t len, void *private_data) { printf("PID %u: %.*s", (unsigned int)procid_to_pid(&pid), (int)len, (const char *)buf); @@ -108,7 +110,7 @@ static void print_pid_string_cb(int msg_type, struct process_id pid, void *buf, /* Message handler callback that displays a string on stdout */ static void print_string_cb(int msg_type, struct process_id pid, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { printf("%.*s", (int)len, (const char *)buf); num_replies++; @@ -371,7 +373,8 @@ static BOOL do_election(const struct process_id pid, /* Ping a samba daemon process */ -static void pong_cb(int msg_type, struct process_id pid, void *buf, size_t len) +static void pong_cb(int msg_type, struct process_id pid, void *buf, + size_t len, void *private_data) { char *src_string = procid_str(NULL, &pid); printf("PONG from pid %s\n", src_string); @@ -391,7 +394,7 @@ static BOOL do_ping(const struct process_id pid, const int argc, const char **ar if (!send_message(pid, MSG_PING, NULL, 0, False)) return False; - message_register(MSG_PONG, pong_cb); + message_register(MSG_PONG, pong_cb, NULL); wait_replies(procid_to_pid(&pid) == 0); @@ -436,7 +439,8 @@ static BOOL do_profile(const struct process_id pid, /* Return the profiling level */ -static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size_t len) +static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, + size_t len, void *private_data) { int level; const char *s; @@ -473,7 +477,7 @@ static void profilelevel_cb(int msg_type, struct process_id pid, void *buf, size } static void profilelevel_rqst(int msg_type, struct process_id pid, - void *buf, size_t len) + void *buf, size_t len, void *private_data) { int v = 0; @@ -495,8 +499,8 @@ static BOOL do_profilelevel(const struct process_id pid, if (!send_message(pid, MSG_REQ_PROFILELEVEL, NULL, 0, False)) return False; - message_register(MSG_PROFILELEVEL, profilelevel_cb); - message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst); + message_register(MSG_PROFILELEVEL, profilelevel_cb, NULL); + message_register(MSG_REQ_PROFILELEVEL, profilelevel_rqst, NULL); wait_replies(procid_to_pid(&pid) == 0); @@ -525,7 +529,7 @@ static BOOL do_debuglevel(const struct process_id pid, if (!send_message(pid, MSG_REQ_DEBUGLEVEL, NULL, 0, False)) return False; - message_register(MSG_DEBUGLEVEL, print_pid_string_cb); + message_register(MSG_DEBUGLEVEL, print_pid_string_cb, NULL); wait_replies(procid_to_pid(&pid) == 0); @@ -732,7 +736,7 @@ static BOOL do_poolusage(const struct process_id pid, return False; } - message_register(MSG_POOL_USAGE, print_string_cb); + message_register(MSG_POOL_USAGE, print_string_cb, NULL); /* Send a message and register our interest in a reply */ @@ -923,7 +927,7 @@ static BOOL do_winbind_onlinestatus(const struct process_id pid, return False; } - message_register(MSG_WINBIND_ONLINESTATUS, print_pid_string_cb); + message_register(MSG_WINBIND_ONLINESTATUS, print_pid_string_cb, NULL); if (!send_message(pid, MSG_WINBIND_ONLINESTATUS, &myid, sizeof(myid), False)) return False; -- cgit