/*
* Td.c
* T daemon. Saves resources by uniting all T windows under the same process.
*
* This file is part of T.
*
* T 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 3 of the License, or (at your option) any later
* version.
*
* T 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
* T. If not, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "T.h"
#define MSGBUF_MAXLEN 64
static int bind_socket();
static TMessage handle_message(TMessage msg);
static gboolean socket_g_io_watch(GIOChannel *source, GIOCondition condition, gpointer data);
static int
bind_socket()
{
struct sockaddr_un sock_addr;
memset(&sock_addr, 0, sizeof(sock_addr));
sock_addr.sun_family = AF_UNIX;
strncpy(sock_addr.sun_path, SOCKPATH, sizeof(sock_addr.sun_path) - 1);
/* Remove old socket */
if (!access(sock_addr.sun_path, F_OK) && unlink(sock_addr.sun_path) < 0)
err("Failed to remove socket file at " SOCKPATH, EXIT_FAILURE);
if (!access(CONFIG_SOCKDIR, F_OK) && rmdir(CONFIG_SOCKDIR) < 0)
err("Failed to remove socket directory at " CONFIG_SOCKDIR, EXIT_FAILURE);
/* Create a new directory */
if (mkdir(CONFIG_SOCKDIR, S_IRWXU) < 0)
err("Failed to create socket directory at " CONFIG_SOCKDIR, EXIT_FAILURE);
int sock_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sock_fd < 0)
err("Failed to create socket", EXIT_FAILURE);
if (bind(sock_fd, (struct sockaddr *) &sock_addr, sizeof(sock_addr)) < 0)
err("Failed to bind the socket to the file at " SOCKPATH, EXIT_FAILURE);
return sock_fd;
}
static TMessage
handle_message(TMessage msg)
{
switch (msg) {
case MSG_NEWWIN:
new_window();
return MSG_OK;
case MSG_EXIT:
if (num_open_windows() == 0) {
gtk_main_quit();
return MSG_OK;
}
return MSG_ERROR;
default:
return MSG_ERROR;
}
}
static gboolean
socket_g_io_watch(GIOChannel *source, GIOCondition condition, gpointer data)
{
int sock_fd = g_io_channel_unix_get_fd(source);
int client_fd = accept(sock_fd, NULL, NULL);
if (client_fd < 0) {
wrn("accept() failed");
return TRUE;
}
TMessage msg;
int len = recv(client_fd, &msg, sizeof(msg), 0);
if (len < 0) {
wrn("recv() failed");
goto socket_g_io_watch_cleanup;
}
msg = handle_message(msg);
write(client_fd, &msg, sizeof(msg));
socket_g_io_watch_cleanup:
close(client_fd);
return TRUE;
}
int
main(int argc, char *argv[])
{
int sock_fd;
gtk_init(&argc, &argv);
sock_fd = bind_socket();
if (listen(sock_fd, SOMAXCONN) < 0)
err("Failed to listen to socket", EXIT_SUCCESS);
/* poll the socket in the main loop */
GIOChannel *sock_chan = g_io_channel_unix_new(sock_fd);
g_io_add_watch(sock_chan, G_IO_IN, socket_g_io_watch, NULL);
gtk_main();
/* clean up */
close(sock_fd);
unlink(SOCKPATH);
return EXIT_SUCCESS;
}