void setup_notifyd()
    {
#if FISH_NOTIFYD_AVAILABLE
        // per notify(3), the user.uid.%d style is only accessible to processes with that uid
        char local_name[256];
        snprintf(local_name, sizeof local_name, "user.uid.%d.%ls.uvars",  getuid(), program_name ? program_name : L"fish");
        name.assign(local_name);
        
        uint32_t status = notify_register_file_descriptor(name.c_str(), &this->notify_fd, 0, &this->token);
        if (status != NOTIFY_STATUS_OK)
        {
            fprintf(stderr, "Warning: notify_register_file_descriptor() failed with status %u. Universal variable notifications may not be received.", status);
        }
        if (this->notify_fd >= 0)
        {
            // Mark us for non-blocking reads, with CLO_EXEC
            int flags = fcntl(this->notify_fd, F_GETFL, 0);
            fcntl(this->notify_fd, F_SETFL, flags | O_NONBLOCK | FD_CLOEXEC);
        }
#endif
    }
Exemple #2
0
static int ListenUsingFileDescriptor(size_t noteCount, const char **noteNames)
    // Implements the "listenFD" command.  Register for the noteCount 
    // notifications whose names are in the noteNames array.  Then read 
    // the notification file descriptor, printing information about any 
    // notifications that arrive.
{
    int         retVal;
    uint32_t    noteErr;
    size_t      noteIndex;
    int         noteTokens[noteCount];
    int         fd = -1;
    
    // Register.  The first time around this loop fd == -1 and so we don't 
    // specify NOTIFY_REUSE.  notify_register_file_descriptor then allocates 
    // a file descriptor and returns it in fd.  For subsequent iterations 
    // we /do/ specify NOTIFY_REUSE and notify_register_file_descriptor just 
    // reuses the existing fd.
    
    noteErr = NOTIFY_STATUS_OK;
    for (noteIndex = 0; noteIndex < noteCount; noteIndex++) {
        noteErr = notify_register_file_descriptor(
            noteNames[noteIndex], 
            &fd, 
            (fd == -1) ? 0 : NOTIFY_REUSE, 
            &noteTokens[noteIndex]
        );
        if (noteErr != NOTIFY_STATUS_OK) {
            break;
        }
    }
    if (noteErr != NOTIFY_STATUS_OK) {
        PrintNotifyError("registration failed", noteNames[noteIndex], noteErr);
        retVal = EXIT_FAILURE;
    } else {
    
        // Listen for and print any incoming notifications.
        
        fprintf(stdout, "Listening using a file descriptor:\n");
        fflush(stdout);
        do {
            ssize_t bytesRead;
            int     token;
            
            bytesRead = read(fd, &token, sizeof(token));
            if (bytesRead == 0) {
                fprintf(stderr, "end of file on notify file descriptor\n");
                retVal = EXIT_FAILURE;
                break;
            } else if (bytesRead < 0) {
                fprintf(stderr, "read failed: %s (%d)\n", strerror(errno), errno);
                retVal = EXIT_FAILURE;
                break;
            } else {
                // I'm just not up for handling partial reads at this point.
                
                assert(bytesRead == sizeof(token));
                
                // Have to swap to native endianness <rdar://problem/5352778>.
                
                token = ntohl(token);
                
                // Find the string associated with this token and print it.
                
                PrintToken(token, noteCount, noteTokens, noteNames);
            } 
        } while (true);
    }
    
    return retVal;
}
Exemple #3
0
int runDaemonRun(void) {
	// Register for all the notifications
	int fd;
	int quitToken = 0;
	if (notify_register_file_descriptor(quitNotification, &fd, 0, &quitToken) != NOTIFY_STATUS_OK) {
		return 0x10;
	}
	int startToken = 0;
	if (notify_register_file_descriptor(startNotification, &fd, NOTIFY_REUSE, &startToken) != NOTIFY_STATUS_OK) {
		return 0x11;
	}
	int stopToken = 0;
	if (notify_register_file_descriptor(stopNotification, &fd, NOTIFY_REUSE, &stopToken) != NOTIFY_STATUS_OK) {
		return 0x12;
	}
	int debugToken = 0;
	if (notify_register_file_descriptor(debugNotification, &fd, NOTIFY_REUSE, &debugToken) != NOTIFY_STATUS_OK) {
		return 0x14;
	}

	print_message(0, "Started as %d(%d):%d(%d)\n", getuid(), geteuid(), getgid(), getegid());

	fd_set readfds;
	FD_ZERO(&readfds);
	FD_SET(fd, &readfds);

	pid_t ngircdPid = 0;
	int ps;
	char debug = 1;

	char shouldContinue = 1;
	while (shouldContinue) {
		int status = select(fd + 1, &readfds, NULL, NULL, NULL);
		if (status <= 0 || !FD_ISSET(fd, &readfds)) {
			continue;
		}

		int t;
		status = read(fd, &t, sizeof(int));
		if (status < 0) {
			continue;
		}
		t = ntohl(t); // notify_register_file_descriptor docs: "The value is sent in network byte order."

		// Value in file descriptor matches token for quit notification
		if (t == quitToken) {
			if (debug) print_message(0, "Quitting\n");
			shouldContinue = 0;
		}

		// Value in file descriptor matches token for start notification
		if (t == startToken) {
			if (debug) print_message(0, "Starting\n");
			// Start ngircd as non-daemon, using custom config file
			const char *args[] = {"ngircd", "-n", "-f", "/Library/Application Support/IRCyslog/ircyslog.conf", NULL};
			if (!ngircdPid) {
				ps = posix_spawn(&ngircdPid, "/usr/sbin/ngircd", NULL, NULL, (char *const *)args, NULL);
				if (!ps) {
					if (debug) print_message(0, "Started ngircd with pid:%d\n", ngircdPid);
				}
			}

			// Start the IRC bot
			// ...

		}

		// Value in file descriptor matches token for stop notification
		// or the quit notification was posted
		if (t == stopToken || !shouldContinue) {
			if (debug) print_message(0, "stopping");

			// Stop the IRC bot
			// ...

			if (!ps) { // If the server is running, kill it
				if (debug) print_message(0, "Calling kill with (%d, %d)\n", ngircdPid, SIGTERM);
				int k = kill(ngircdPid, SIGTERM);
				if (debug) print_message(0, "kill'd with exit status %d\n", k);

				// Wait for the server to finish and purge from the process list
				int st;
				if (debug) print_message(0, "Calling waitpid with (%d,%d)\n", ngircdPid, 0);
				int w = waitpid(ngircdPid, &st, 0);
				if (debug) print_message(0, "waitpid'd with exit status %d, stat_loc %d\n", w, st);
			}
		}

		// Value in file descriptor matches token for debug notification
		if (t == debugToken) {
			debug = !debug;
			print_message(0, "debug is %s\n", debug ? "ON" : "OFF");
		}
	}

	// Cancel notification watching
	print_message(0, "Cancelling notifications\n");
	notify_cancel(quitToken);
	notify_cancel(startToken);
	notify_cancel(stopToken);
	notify_cancel(debugToken);

	return 0;
}