I need to create FSEvents watcher for a Folder in Mac. I'm comfortable with C++ and is there a way to get FSEvents notifications in C++ code, rather than Objective-C. Is there some example code to start with and any libraries i need to include ..?
I'm already on this page.
http://developer.apple.com/library/mac/#featuredarticles/FileSystemEvents/_index.html
But there seems to be only Objective C, can i have CPP version of it
Yes, it is possible in C. You should look for Kernel Queues.
Here's a small sample to watch the directory:
#include <errno.h> // for errno
#include <fcntl.h> // for O_RDONLY
#include <stdio.h> // for fprintf()
#include <stdlib.h> // for EXIT_SUCCESS
#include <string.h> // for strerror()
#include <sys/event.h> // for kqueue() etc.
#include <unistd.h> // for close()
int main (int argc, const char *argv[])
{
int kq = kqueue ();
// dir name is in argv[1], NO checks for errors here
int dirfd = open (argv[1], O_RDONLY);
struct kevent direvent;
EV_SET (&direvent, dirfd, EVFILT_VNODE, EV_ADD | EV_CLEAR | EV_ENABLE,
NOTE_WRITE, 0, (void *)dirname);
kevent(kq, &direvent, 1, NULL, 0, NULL);
// Register interest in SIGINT with the queue. The user data
// is NULL, which is how we'll differentiate between
// a directory-modification event and a SIGINT-received event.
struct kevent sigevent;
EV_SET (&sigevent, SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, NULL);
// kqueue event handling happens after the legacy API, so make
// sure it doesn eat the signal before the kqueue can see it.
signal (SIGINT, SIG_IGN);
// Register the signal event.
kevent(kq, &sigevent, 1, NULL, 0, NULL);
while (1) {
// camp on kevent() until something interesting happens
struct kevent change;
if (kevent(kq, NULL, 0, &change, 1, NULL) == -1) { exit(1); }
// The signal event has NULL in the user data. Check for that first.
if (change.udata == NULL) {
break;
} else {
// udata is non-null, so it's the name of the directory
printf ("%s\n", (char*)change.udata);
}
}
close (kq);
return 0;
}
The details can be found in ch. 16 (kqueues and FSEvents) of "Advanced Mac OSX Programming" by Mark Dalrymple. The additional info may be found in *BSD documentation for kqueues.
Or use this API from FSEvents (it's mostly C-based).
FSEventStreamRef FSEventStreamCreate (CFAllocatorRef allocator,
FSEventStreamCallback callback,
FSEventStreamContext *context,
CFArrayRef pathsToWatch,
FSEventStreamEventId sinceWhen,
CFTimeInterval latency,
FSEventStreamCreateFlags flags);
to create the FSEvents event stream with pure-C callback.
Then attach this event stream to your runloop using the
void FSEventStreamScheduleWithRunLoop (FSEventStreamRef streamRef,
CFRunLoopRef runLoop,
CFStringRef runLoopMode);
Yes, here you probably should use a line of Obj-C to get the RunLoop handle: get the CFRunLoop from an NSRunLoop by using -getCFRunLoop
CFRunLoop* loopRef = [[NSRunLoop currentRunLoop] getCFRunLoop];
or use the pure C call
CFRunLoop* loopRef = CFRunLoopGetCurrent();
Start the event stream with
Boolean FSEventStreamStart (FSEventStreamRef streamRef);
Stop the event stream with
void FSEventStreamStop (FSEventStreamRef streamRef);
And then unschedule it from the runloop with this:
void FSEventStreamUnscheduleFromRunLoop (FSEventStreamRef streamRef,
CFRunLoopRef runLoop,
CFStringRef runLoopMode);
Invalidate the stream (cleanup):
void FSEventStreamInvalidate (FSEventStreamRef streamRef);
Hope this will get you started.
Related
I would like to call a cleanup function after the user presses
the small "x" at the top right hand corner of the console window.
I have registered an atexit method but this doesn't get called in this case.
Solution needs to work on windows and linux.
You cannot use atexit here because, it is called when a process is terminated normally, whereas in your case the process is terminated by a signal.
On linux, SIGHUP (signal hang up) is sent to the process when its controlling terminal is closed, and you can use POSIX signal handling.
On windows, CTRL_CLOSE_EVENT event is delivered, and you can use SetConsoleCtrlHandler winapi to handle this.
So, to my knowledge, there's no platform independent way to handle this in c++. You should use platform dependent code to do this as shown in the following simple program. I tested it on windows with VS and on ubuntu with g++. Please note that error handling has been omitted and I/O is performed in signal handlers for simplicity.
The program registers a signal handler and an atexit function. Then it sleeps for 10 seconds. If you do not close the console within 10s, the process will terminate normally and the atexit handler will be called. If you close the window before 10s, it'll catch the signal. On linux, you won't see the signal handler getting called, but it does get called, you can check this by writing a file (or issuing a beep?), though I don't recommend it.
#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#ifdef WIN32
BOOL sig_handler(DWORD signum)
{
switch( signum )
{
case CTRL_CLOSE_EVENT:
printf( "Ctrl-Close event\n" );
return( TRUE );
default:
return FALSE;
}
}
#else
void sig_handler(int signum)
{
/* you won't see this printed, but it runs */
printf("Received signal %d\n", signum);
}
#endif
void exit_fn(void)
{
printf("%s\n", __FUNCTION__);
}
void setup_signal_handler()
{
#ifdef WIN32
SetConsoleCtrlHandler((PHANDLER_ROUTINE)sig_handler, TRUE);
#else
struct sigaction sa;
sa.sa_handler = &sig_handler;
sigfillset(&sa.sa_mask);
sigaction(SIGHUP, &sa, NULL);
#endif
}
int main(void)
{
printf("%s\n", __FUNCTION__);
/* setup signal handler */
setup_signal_handler();
/* setup function to be called at normal process termination */
atexit(exit_fn);
/* sleep for 10s */
#ifdef WIN32
Sleep(10000);
#else
sleep(10);
#endif
/* print message if process terminates normally */
printf("Normal process termination\n");
exit(EXIT_SUCCESS);
}
I test that on Linux and it seems that when the tracee is in a signal handler, the tracer can use ptrace() to attach to it, as usual. But since tracee is in a signal handler, some functions might not be OK to invoke because of the asyn-signal-safe problem. So, is there any methods to detect that situation after calling ptrace()?
This recent discussion may interest you.
The short answer is that you can tell whether inferior (tracee) is in a signal handler by unwinding its stack, and looking for rt_sigreturn entry.
That is the entry that GDB prints as <signal handler called>.
However, the question is: why do you care?
Presumably it is to prevent your debugger from calling into the tracee when your end user asks you to perform equivalent of (gdb) call malloc(10).
Note that:
GDB does not prevent end-user from doing so. If the process corrupts its heap or deadlocks as the result, it's the end user's problem, not GDB's.
It is impossible for the debugger to know what functions should be allowed or disallowed, and this determination depends on whether the signal is synchronous and where it originates. For example:
void handler(int signo)
{
while (1)
{
char *p = malloc(20); // perfectly safe (but only in this program)
free(p);
}
}
int main()
{
signal(SIGINT, handler);
kill(getpid(), SIGINT);
return 0; // control never reaches here
}
It turns out that determining whether or not you are currently in a signal handler is trivial with libunwind:
Assume that you have build libunwind properly:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <string.h>
/* assume that you have build libunwind properly */
#include "./libunwindout/include/libunwind.h"
/* Simple error handling functions */
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
void show_backtrace(void) {
unw_cursor_t cursor; unw_context_t uc;
unw_word_t ip, sp;
unw_getcontext(&uc);
unw_init_local(&cursor, &uc);
while(unw_step(&cursor) > 0) {
unw_get_reg(&cursor, UNW_REG_IP, &ip);
unw_get_reg(&cursor, UNW_REG_SP, &sp);
/* Upon unwinding to a signal handler, you get a "1" */
printf("Is in a signal handler [%d]\n",
unw_is_signal_frame(&cursor));
printf("ip = %lx, sp = %lx \n", (long)ip, (long)sp);
}
}
struct sigaction act;
/* Upon receiving a SIGQUIT, this signal handler will be invoked */
void sighandler(int signum, siginfo_t *info, void *ptr) {
printf("Received signal: %d\n", signum);
printf("signal originate from pid[%d]\n", info->si_pid);
printf("Inside a signal handler...\n");
show_backtrace();
while(1)
;
printf("[FATAL] quiting the signal handler\n");
}
int main(int argc, char *argv[]) {
{
printf("Pid of the current process: %d\n", getpid());
memset(&act, 0, sizeof(act));
act.sa_sigaction = sighandler;
act.sa_flags = SA_SIGINFO;
sigaction(SIGQUIT, &act, NULL);
while(1)
;
return 0;
}
So you should run this program, and then send it a SIGQUIT. Upon receiving a
SIGQUIT, the signal handler will be invoked and the show_backtrace() function
will be called, which will unwind the stack and eventually find the signal
handler frame, reporting 1.
More interesting, libunwind allows you to detect "remotely" with its
libunwind-ptrace module. By "remotely", it simply means that you can use
ptrace(2) to attach to a process and then you can use libunwind-ptrace to
detect the remote process is running in a signal handler.
For more info, please refer to libunwind's doc
Is there any way to send a signal to a process (in Linux), that results in a termination of the process after going through the "atexit-functions" (in this case: void shutdownEngines())? Using "pkill name" does not work.
#include <cstdlib>
void shutdownEngines() {/*is not executed by "pkill name"*/}
int main() {
atexit(shutdownEngines);
while(true)
doStuff();
}
Usage: I'm currently programming a robot. Every time I want to test it, I'll start the program and terminate it with "pkill name", but "shutdownEngines" isn't called and the robot keeps moving, falling off the table etc.
I know I could do "pkill name; ./shutdownEngines.sh", but this would be very bad style in my case (the numbers of the gpio pins connected to the engines are defined in a header file of the main program (the source code of the main program is not on the robot but on my computer). Making sure that there's always a "shutdownEngines.sh" program/script with the right pins on every robot would be very complicated.
Update
The following code works perfectly:
#include <iostream>
#include <csignal>
#include <cstdlib>
void signalHandler(__attribute__((unused)) const int signum) {
exit(EXIT_FAILURE);
}
void driverEpilog() {
std::cout << "shutting down engines...";
//drv255(0,0);
}
int main() {
signal(SIGTERM, signalHandler);
atexit(driverEpilog);
while(true)
system("sleep 1");
}
from the man page of atexit:
Functions registered using atexit() (and on_exit(3)) are not called
if a process terminates abnormally because of the delivery of a
signal.
atexit is called when your main routine returns or when you call exit, not on a signal.
When you call pkill you're sending a SIGTERM signal. Handle this signal with signal or sigaction instead (define handlers on SIGTERM, SIGINT, SIGFPE, ...) to stop the engines before exiting your program.
Example lifted from GNU C library documentation:
void
termination_handler (int signum)
{
struct temp_file *p;
for (p = temp_file_list; p; p = p->next)
unlink (p->name); // don't delete files, stop your engines instead :)
}
int
main (void)
{
…
struct sigaction new_action, old_action;
/* Set up the structure to specify the new action. */
new_action.sa_handler = termination_handler;
sigemptyset (&new_action.sa_mask);
new_action.sa_flags = 0;
sigaction (SIGINT, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction (SIGINT, &new_action, NULL);
sigaction (SIGHUP, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction (SIGHUP, &new_action, NULL);
sigaction (SIGTERM, NULL, &old_action);
if (old_action.sa_handler != SIG_IGN)
sigaction (SIGTERM, &new_action, NULL);
…
}
(of course, no handler can handle the SIGKILL "signal", which tells the OS to remove your process from the active process list, without further notice!)
I am use the code (actually copy from hereFSEvents C++ Example)as following, but it can only work for a path, can not work for a file.
I just want to monitor a specific file. How can I do that? thanks
#include <fcntl.h> // for O_RDONLY
#include <stdio.h> // for fprintf()
#include <stdlib.h> // for EXIT_SUCCESS
#include <string.h> // for strerror()
#include <sys/event.h> // for kqueue() etc.
#include <unistd.h> // for close()
int main (int argc, const char *argv[])
{
int kq = kqueue ();
// dir name is in argv[1], NO checks for errors here
int dirfd = open (argv[1], O_RDONLY);
struct kevent direvent;
EV_SET (&direvent, dirfd, EVFILT_VNODE, EV_ADD | EV_CLEAR | EV_ENABLE,
NOTE_WRITE, 0, (void *)argv[1]);
kevent(kq, &direvent, 1, NULL, 0, NULL);
// Register interest in SIGINT with the queue. The user data
// is NULL, which is how we'll differentiate between
// a directory-modification event and a SIGINT-received event.
struct kevent sigevent;
EV_SET (&sigevent, SIGINT, EVFILT_SIGNAL, EV_ADD | EV_ENABLE, 0, 0, NULL);
// kqueue event handling happens after the legacy API, so make
// sure it doesn eat the signal before the kqueue can see it.
signal (SIGINT, SIG_IGN);
// Register the signal event.
kevent(kq, &sigevent, 1, NULL, 0, NULL);
while (1) {
// camp on kevent() until something interesting happens
struct kevent change;
if (kevent(kq, NULL, 0, &change, 1, NULL) == -1) { exit(1); }
// The signal event has NULL in the user data. Check for that first.
if (change.udata == NULL) {
break;
} else {
// udata is non-null, so it's the name of the directory
printf ("%s\n", (char*)change.udata);
}
}
close (kq);
return 0;
}
What operations on the file are being performed that you're missing?
Note that many things that write files don't open the existing file and write to it; they unlink the existing file and replace it with a new one. Because of that, kqueue() won't report that the file that you have open has been written to. You can add NOTE_DELETE to the fflags to try to catch that.
I want to use ptrace to check what system calls a program spawned by my program makes. I started out from this tutorial as it was explained in an answer to my previous question. I modified the code by adapting it to the platform I'm using (SLES 11 64 bit), and put together the following test code that prints out every system call the spawned process makes:
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
run();
}
return 0;
}
It works pretty well: it prints the id of the system calls made by the program (actually it prints each one twice, once at entry and once for exit, but that doesn't matter now). However, my program needs to do other things to do other than checking the system calls, so I decided to move the checking to a separate thread (I'm more comfortable with C++ than C, so I did it the C++ way, but I don't think that matters). Of course in this thest program, I only start the thread and then join it.
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/reg.h>
#include <sys/syscall.h> /* For SYS_write etc */
#include <boost/thread.hpp>
pid_t child;
void run()
{
long orig_eax;
int status;
while(1) {
int pid = wait(&status);
if (pid == -1) {
perror("wait");
kill(child, SIGKILL);
return;
}
printf("Got event from %d.\n", pid);
if(WIFEXITED(status))
break;
orig_eax = ptrace(PTRACE_PEEKUSER,
pid, 8 * ORIG_RAX, NULL);
if (orig_eax == -1) {
perror("ptrace");
kill(child, SIGKILL);
return;
} else {
printf("Syscall %ld called.\n", orig_eax);
}
ptrace(PTRACE_SYSCALL,
pid, NULL, NULL);
}
}
int main(int /*argc*/, char* argv[])
{
child = fork();
if(child == 0) {
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
execl(argv[1], argv[1], NULL);
}
else {
printf("Child process id = %d.\n", child);
boost::thread t(run);
t.join();
}
return 0;
}
This time I get an error message:
Child process id = 24682.
Got event from 24682.
ptrace: No such process
Why is this? I tried searching for an answer but found nothing like this. I found that ptrace won't trace threads started by the child process, but that's another thing needs to be dealed with later. Is that even possible to check the child process from a different therad?
The other strange thing is that in my real application I do basically the same thing (but from a much more complicated context: classes, mutexes etc.), and I get a different kind of error. Instead of ptrace returning with an error, wait doesn't even return for system calls on the child process (and the child process doesn't even stop). On the other hand, wait works as expected when the child process exits.
As far as I can tell, ptrace allows just one tracer per process. This means that if you try to attach, which you can try and force it with PTRACE_ATTACH, you will receive an error, telling that ptrace was not able to attach to the specified process.
Thus, your error appears because your thread is not attached to the child process, and this way, when you try to ptrace it, it fails, sending a -ESRCH code.
Furthermore, you can have a look at this post here, it might answer some other questions you might have apart from this one.