/* * sympathy.c: * * Copyright (c) 2008 James McKenzie , * All rights reserved. * */ static char rcsid[] = "$Id$"; /* * $Log$ * Revision 1.22 2008/02/28 01:47:44 james * *** empty log message *** * * Revision 1.21 2008/02/27 16:01:24 james * *** empty log message *** * * Revision 1.20 2008/02/27 10:00:34 james * *** empty log message *** * * Revision 1.19 2008/02/27 09:47:05 james * *** empty log message *** * * Revision 1.18 2008/02/27 09:42:53 james * *** empty log message *** * * Revision 1.17 2008/02/27 09:42:21 james * *** empty log message *** * * Revision 1.16 2008/02/27 01:31:38 james * *** empty log message *** * * Revision 1.15 2008/02/27 01:31:14 james * *** empty log message *** * * Revision 1.14 2008/02/24 00:43:55 james * *** empty log message *** * * Revision 1.13 2008/02/24 00:42:53 james * *** empty log message *** * * Revision 1.12 2008/02/23 11:48:52 james * *** empty log message *** * * Revision 1.11 2008/02/20 20:16:07 james * *** empty log message *** * * Revision 1.10 2008/02/20 19:44:37 james * @@ * * Revision 1.9 2008/02/20 18:49:11 staffcvs * *** empty log message *** * * Revision 1.8 2008/02/20 18:33:37 james * *** empty log message *** * * Revision 1.7 2008/02/20 18:31:44 james * *** empty log message *** * * Revision 1.6 2008/02/20 17:18:33 james * *** empty log message *** * * Revision 1.5 2008/02/20 15:50:14 james * *** empty log message *** * * Revision 1.4 2008/02/20 02:11:35 james * *** empty log message *** * * Revision 1.3 2008/02/14 02:46:44 james * *** empty log message *** * * Revision 1.2 2008/02/14 00:57:58 james * *** empty log message *** * * Revision 1.1 2008/02/05 14:25:49 james * *** empty log message *** * */ #include #include #include #include #include #include #include #include #include #include #include #include "mainloop.h" extern void usage (void); static char hostname[1024]; int safe_atoi (char *a) { char *end; int ret; if (!a) return -1; ret = (int) strtol (a, &end, 0); if (end == a) return -1; return ret; } char * fatal_moan (char *fmt, ...) { va_list ap; va_start (ap, fmt); vfprintf (stderr, fmt, ap); va_end (ap); putc ('\n', stderr); exit (1); } /*make the path in fmt from home (hence the name) */ char * mome (char *fmt, ...) { int n; int homelen; char *buf, *home; va_list ap; int size; home = getenv ("HOME"); if (!home) return NULL; homelen = strlen (home) + 1; size = 1024 + homelen; buf = malloc (size); if (!buf) fatal_moan ("malloc failed"); strcpy (buf, home); strcat (buf, "/"); while (1) { va_start (ap, fmt); n = vsnprintf (buf + homelen, size - homelen, fmt, ap); va_end (ap); if (n > -1 && n < (size - homelen)) return buf; if (n > -1) /* glibc 2.1 */ size = homelen + n + 1; else /* glibc 2.0 */ size *= 2; /* twice the old size */ buf = realloc (buf, size); if (!buf) fatal_moan ("malloc failed"); } } int list_sockets (void) { struct dirent *ent; struct stat buf; char *sn = NULL; Socket *s; char *sockdir = mome ("/.sympathy/"); DIR *dir = opendir (sockdir); int hostname_len = strlen (hostname); if (!dir) fatal_moan ("can't examine %s for sockets", sockdir); rewinddir (dir); while ((ent = readdir (dir))) { sn = mome (".sympathy/%s", ent->d_name); if (stat (sn, &buf) || (!S_ISSOCK (buf.st_mode))) { free (sn); continue; } s = socket_connect (sn); if (s) { printf ("\t%s (Active)\n", ent->d_name); socket_free (s); } else { if (strncmp (ent->d_name, hostname, hostname_len)) { printf ("\t%s (Unknown - not this host)\n", ent->d_name); } else { printf ("\t%s (Dead, wiped)\n", ent->d_name); unlink (sn); } } free (sn); } closedir (dir); return 0; } void get_hostname (void) { struct utsname name; if (uname (&name)) { strcpy (hostname, "unknown."); return; } strcpy (hostname, name.nodename); strcat (hostname, "."); } int main (int argc, char *argv[]) { int c; extern char *optarg; extern int optind, opterr, optopt; CRT_Pos size = { VT102_COLS_80, VT102_ROWS }; int oflags[128]; char *oargs[128]; Socket *server_socket = NULL, *client_socket = NULL; ANSI *ansi = NULL; TTY *tty = NULL; Log *log = NULL; int history = 200; get_hostname (); memset (oflags, 0, sizeof (oflags)); memset (oargs, 0, sizeof (oargs)); while ((c = getopt (argc, argv, "vw:utscr:lKHd:pb:fL:Fk:n:")) != EOF) { switch (c) { case ':': case 'h': case '?': usage (); default: if ((c > 64) && (c < 91)) { oflags[c]++; oargs[c] = optarg; } else if ((c > 96) && (c < 123)) { oflags[c]++; oargs[c] = optarg; } else { fprintf (stderr, "unknown option %c\n", c); usage (); } } } /*Compatability for screen's ls */ if (oflags['l']) oflags['s'] = 0; { int sum = 0; sum += oflags['t']; sum += (oflags['s'] || oflags['c']) ? 1 : 0; sum += oflags['r']; sum += oflags['l']; sum += oflags['v']; if (!sum) { /*If no mode is specified behave like screen */ oflags['s']++; oflags['c']++; sum++; } if (sum != 1) fatal_moan ("specifiy exactly one of ( -c and or -s ), -t, -r, -l and -v"); } if (oflags['v']) { fprintf (stderr, "Version: %s\n", libsympathy_version ()); fprintf (stderr, "Version: %s\n", rcsid); return 0; } if (oflags['l']) return list_sockets (); if (oflags['r'] && oflags['k']) fatal_moan ("-k is incompatible with -r"); if (oflags['n']) { history = safe_atoi (oargs['n']); if (history < 0) fatal_moan ("cannot parse -n %s as an integer", oargs['n']); if (!history) fatal_moan ("agrument to -n must be greater than zero"); } /*Fold -r into -c */ if (oflags['r']) { char *id = oargs['r']; if (id < 0) fatal_moan ("cannot parse -r %s as an integer", oargs['r']); oflags['k']++; if (safe_atoi(id)>0) { oargs['k'] = mome ("/.sympathy/%s%d", hostname, safe_atoi(id)); } else { oargs['k'] = mome ("/.sympathy/%s", id); } oflags['r'] = 0; oflags['c']++; } if (oflags['p'] && oflags['d']) fatal_moan ("-p incompatible with -d"); /*implement server and client by opening the server socket to prevent */ /*a race condition, and then forking and munging the cmd line options */ /*in the parent and child so that the child is the server and the */ /*parent becomes its client */ if (oflags['c'] && oflags['s'] && oflags['F']) fatal_moan ("-F is incompatible with -c -s"); if (oflags['s'] && !oflags['k']) { char *path; path = mome ("/.sympathy"); mkdir (path, 0700); free (path); oargs['k'] = mome ("/.sympathy/%s%d", hostname, getpid ()); oflags['k']++; } if (oflags['s']) { server_socket = socket_listen (oargs['k']); if (!server_socket) fatal_moan ("failed to create socket %s for listening", oargs['k']); } if (oflags['s'] && oflags['c']) { switch (fork ()) { case 0: /*child becomes the server */ oflags['c'] = 0; oflags['H'] = 0; break; case -1: fatal_moan ("fork failed"); default: oflags['s'] = 0; oflags['K'] = 0; oflags['d'] = 0; oflags['p'] = 0; oflags['b'] = 0; oflags['f'] = 0; oflags['L'] = 0; oflags['n'] = 0; oflags['w'] = 0; if (server_socket) { socket_free_parent (server_socket); server_socket = NULL; } } } if (oflags['c'] && !oflags['k']) fatal_moan ("-c requires a socket to be specified with -s or -k"); if ((oflags['p'] || oflags['d'] || oflags['K'] || oflags['b'] || oflags['f'] || oflags['L']) && oflags['c']) fatal_moan ("-c or -r are incompatible with -p, -d, -K, -b, -f or -L"); if (oflags['t'] || oflags['s']) { if (!oflags['p'] && !oflags['d']) oflags['p']++; } if (oflags['w']) { char buf[128], *ptr; strcpy (buf, oargs['w']); ptr = index (buf, 'x'); if (ptr) { *ptr = 0; ptr++; size.y = safe_atoi (ptr); } size.x = safe_atoi (buf); if ((size.x > VT102_MAX_COLS) || (size.x < 1)) fatal_moan ("-w requires a width between 1 and %d\n", VT102_MAX_COLS); if ((size.y > VT102_ROWS) || (size.y < 1)) fatal_moan ("-w requires a height between 1 and %d\n", VT102_MAX_COLS); } if (oflags['s'] && !oflags['F']) { daemon (1, 0); /*incase socket is relative path, unlink then will fail */ } if (oflags['s'] || oflags['t']) { if (oflags['L']) { log = file_log_new (oargs['L']); if (!log) fatal_moan ("unable to access log file %s", oargs['L']); } if (oflags['p']) { tty = ptty_open (NULL, NULL, &size); if (!tty) fatal_moan ("unable to open a ptty"); } else { /*HACK-- check that console=device does not occur in */ /*/proc/cmdline*/ if (!oargs['d']) fatal_moan("no argument to -d"); { char kernel_cmdline[4096]={0}; char search_string[1024]="console="; char *ptr=oargs['d']; int fd; if (!strncmp("/dev/",ptr,5)) ptr+=5; strcat(search_string,ptr); fd=open("/proc/cmdline",O_RDONLY); read(fd,kernel_cmdline,sizeof(kernel_cmdline)); close(fd); kernel_cmdline[sizeof(kernel_cmdline)-1]=0; if (strstr(kernel_cmdline,search_string)) fatal_moan("/proc/cmdline contains %s",search_string); } tty = serial_open (oargs['d'], oflags['K'] ? SERIAL_LOCK_ACTIVE : SERIAL_LOCK_PASSIVE); if (!tty) fatal_moan ("unable to open serial port %s", oargs['d']); } if (oflags['b']) { int baud = safe_atoi (oargs['b']); if (baud < 0) fatal_moan ("Unable to parse baudrate %s", oargs['b']); tty_set_baud (tty, baud); } tty_set_flow (tty, oflags['f'] ? 1 : 0); } if (oflags['c']) { client_socket = socket_connect (oargs['k']); if (!client_socket) fatal_moan ("failed to connect to socket %s", oargs['k']); } if (oflags['c'] || oflags['t']) { if (oflags['H']) { ansi = ansi_new_html (stdout); } else { terminal_register_handlers (); ansi = ansi_new_from_terminal (terminal_open (0, 1), oflags['u'] ? 0 : 1); ansi->reset (ansi, NULL); } } mainloop (tty, server_socket, client_socket, ansi, log, history, &size); if (ansi) { ansi->close (ansi); terminal_atexit (); } if (tty) tty->close (tty); if (log) log->close (log); if (server_socket) socket_free (server_socket); if (client_socket) socket_free (client_socket); if (!oflags['H']) printf ("you have now exited sympathy\n"); return 0; }