/* notice.c -- Request file change notifiction messages. Copyright (C) 2002 Wolfgang J"ahrling 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 */ /* Compile with mig -DSERVERPREFIX=S_ -n -server fs_notify.c /include/hurd/fs_notify.defs gcc -Wall -g -o notice notice.c fs_notify.c -lports -lthreads */ #define _GNU_SOURCE 1 #include #include #include #include #include #include #include #include #include static struct port_bucket *bucket; static struct port_class *class; struct notice_handle { struct port_info pi; int changes; /* Changes which won't be ignored. See below. */ char name[1]; /* Actually it will be larger. */ }; /* The CHANGES field above is a set of those flags. See for details. */ #define NOTICE_NULL (1 << FILE_CHANGED_NULL) #define NOTICE_WRITE (1 << FILE_CHANGED_WRITE) #define NOTICE_EXTEND (1 << FILE_CHANGED_EXTEND) #define NOTICE_TRUNCATE (1 << FILE_CHANGED_TRUNCATE) #define NOTICE_META (1 << FILE_CHANGED_META) #define NOTICE_ALL (NOTICE_NULL | NOTICE_WRITE | NOTICE_EXTEND \ | NOTICE_TRUNCATE | NOTICE_META) static struct notice_handle * notice_port_to_handle (mach_port_t port) { return ports_lookup_port (bucket, port, class); } const char *argp_program_version = "notice 0.1"; static struct argp_option options[] = { {"null", 'n', 0, 0, "Regard startup message of the following files"}, {"no-null", 'N', 0, 0, "Ignore startup message of the following files"}, {"write", 'w', 0, 0, "Regard file writes on the following files"}, {"no-write", 'W', 0, 0, "Ignore file writes on the following files"}, {"extend", 'e', 0, 0, "Regard extensions of the following files"}, {"no-extend", 'E', 0, 0, "Ignore extensions of the following files"}, {"trunc", 't', 0, 0, "Regard truncation of thefollowing files"}, {"no-trunc", 'T', 0, 0, "Ignore truncation of the following files"}, {"meta", 'm', 0, 0, "Regard changes of meta information"}, {"no-meta", 'M', 0, 0, "Ignore changes of meta information"}, {0} }; static const char *args_doc = "FILE..."; static const char *doc = "Request file change notification messages."; static error_t parse_opt (int key, char *arg, struct argp_state *state) { static int changes = NOTICE_ALL; switch (key) { case 'n': changes |= NOTICE_NULL; break; case 'N': changes &= ~NOTICE_NULL; break; case 'w': changes |= NOTICE_WRITE; break; case 'W': changes &= ~NOTICE_WRITE; break; case 'e': changes |= NOTICE_EXTEND; break; case 'E': changes &= ~NOTICE_EXTEND; break; case 't': changes |= NOTICE_TRUNCATE; break; case 'T': changes &= ~NOTICE_TRUNCATE; break; case 'm': changes |= NOTICE_META; break; case 'M': changes &= ~NOTICE_META; break; case ARGP_KEY_ARG: { file_t file; mach_port_t notify_port; struct notice_handle *notice; error_t err; /* Create the notification port. */ err = mach_port_allocate (mach_task_self (), MACH_PORT_RIGHT_RECEIVE, ¬ify_port); if (err) error (1, err, "Could not allocate port"); /* Open the file. */ file = file_name_lookup (arg, 0, 0); if (file == MACH_PORT_NULL) error (1, errno, "Could not open %s", arg); /* Request notification messages. */ err = file_notice_changes (file, notify_port, MACH_MSG_TYPE_MAKE_SEND); if (err) error (1, err, "Noticing changes not possible for %s", arg); /* Put notification port in bucket. */ err = ports_import_port (class, bucket, notify_port, sizeof (struct notice_handle) + strlen (arg), ¬ice); if (err) error (1, err, "Could not import port"); /* Record the file name and the changes we are interested in. */ strcpy (notice->name, arg); notice->changes = changes; break; } default: return ARGP_ERR_UNKNOWN; } return 0; } static int notice_demuxer (mach_msg_header_t *, mach_msg_header_t *); int main (int argc, char **argv) { bucket = ports_create_bucket (); class = ports_create_class (NULL, NULL); /* Process arguments. */ { struct argp argp = {options, parse_opt, args_doc, doc}; argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, 0); } /* Be a server. */ ports_manage_port_operations_one_thread (bucket, notice_demuxer, 0); return 0; } error_t S_file_changed (mach_port_t port, file_changed_type_t change, off_t start, off_t end) { struct notice_handle *notice = notice_port_to_handle (port); if ((1 << change) & notice->changes) printf ("%s\n", notice->name); return 0; } error_t S_dir_changed (mach_port_t port, dir_changed_type_t change, string_t name) { return EOPNOTSUPP; } static int notice_demuxer (mach_msg_header_t *inp, mach_msg_header_t *outp) { extern int fs_notify_server (mach_msg_header_t *inp, mach_msg_header_t *outp); return (fs_notify_server (inp, outp) || ports_interrupt_server (inp, outp) || ports_notify_server (inp, outp)); }