1 /******************************************************************************
2 (c) 2000-2008 Christine Caulfield christine.caulfield@googlemail.com
3 (c) 2003 Dmitri Popov
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 ******************************************************************************/
15
16 // LAT Control Program (latcp)
17
18
19 #include <sys/types.h>
20 #include <sys/uio.h>
21 #include <sys/socket.h>
22 #include <sys/un.h>
23 #include <sys/ioctl.h>
24 #include <sys/wait.h>
25 #include <sys/stat.h>
26 #include <sys/time.h>
27 #include <sys/utsname.h>
28 #include <stdio.h>
29 #include <errno.h>
30 #include <unistd.h>
31 #include <signal.h>
32 #include <string.h>
33 #include <fcntl.h>
34 #include <syslog.h>
35 #include <ctype.h>
36 #include <regex.h>
37 #include <stdlib.h>
38 // #include <utmp.h>
39 #include <pwd.h>
40 #include <signal.h>
41 #include <limits.h>
42 #include <assert.h>
43
44 #include <list>
45 #include <queue>
46 #include <map>
47 #include <string>
48 #include <algorithm>
49 #include <iterator>
50 #include <string>
51 #include <sstream>
52 #include <iostream>
53
54 #include "lat.h"
55 #include "latcp.h"
56 #include "utils.h"
57 #include "dn_endian.h"
58
59 static int latcp_socket;
60
61 static void make_upper(char *str);
62
63 int read_reply(int fd, int &cmd, unsigned char *&cmdbuf, int &len);
64 bool send_msg(int fd, int cmd, char *buf, int len);
65 bool open_socket(bool);
66
67 // Command processing routines
68 void display(int argc, char *argv[]);
69 void add_service(int argc, char *argv[]);
70 void del_service(int argc, char *argv[]);
71 void set_multicast(int);
72 void set_retransmit(int);
73 void set_keepalive(int);
74 void set_responder(int onoff);
75 void shutdown();
76 void purge_services();
77 void start_latd(int argc, char *argv[]);
78 void set_rating(int argc, char *argv[]);
79 void set_ident(int argc, char *argv[]);
80 void set_server_groups(int argc, char *argv[]);
81 void set_user_groups(int argc, char *argv[]);
82 void set_node (char *);
83
84
85 // Misc utility routines
86 static void make_bitmap(char *bitmap, char *cmdline);
87
88
usage(char * cmd)89 int usage(char *cmd)
90 {
91 printf ("Usage: latcp {option}\n");
92 printf (" where option is one of the following:\n");
93 printf (" -s [<latd args>]\n");
94 printf (" -h\n");
95 printf (" -A -a service [-i description] [-r rating] [-s] [-C command] [-u user] [-m max conn]\n");
96 printf (" -A -p tty -V learned_service [-R rem_port] [-H rem_node] [-Q] [-8]\n");
97 printf (" -D {-a service | -p tty}\n");
98 printf (" -C service command}\n");
99 printf (" -i description -a service\n");
100 printf (" -g list\n");
101 printf (" -G list\n");
102 printf (" -u list\n");
103 printf (" -U list\n");
104 printf (" -j\n");
105 printf (" -J\n");
106 printf (" -Y\n");
107 printf (" -x rating [-s] -a service\n");
108 printf (" -n node\n");
109 printf (" -r retransmit limit\n");
110 printf (" -m multicast timer (100ths/sec)\n");
111 printf (" -k keepalive timer (seconds)\n");
112 printf (" -d [ [-l [-v] [-n] ] ]\n");
113 printf (" -z \n");
114
115 return 2;
116 }
117
main(int argc,char * argv[])118 int main(int argc, char *argv[])
119 {
120
121 // Parse the command.
122 // because the args vary so much for each command I just check argv[1]
123 // for the command switch and the command processors call getopt themselves
124
125 if (argc == 1)
126 {
127 exit(usage(argv[0]));
128 }
129
130 if (argv[1][0] != '-')
131 {
132 exit(usage(argv[0]));
133 }
134
135 switch (argv[1][1])
136 {
137 case 'A':
138 add_service(argc-1, &argv[1]);
139 break;
140 case 'D':
141 del_service(argc-1, &argv[1]);
142 break;
143 case 'j':
144 set_responder(1);
145 break;
146 case 'J':
147 set_responder(0);
148 break;
149 case 'Y':
150 purge_services();
151 break;
152 case 'n':
153 set_node(argv[2]);
154 break;
155 case 'm':
156 if (argv[2])
157 set_multicast(atoi(argv[2]));
158 else
159 exit(usage(argv[0]));
160 break;
161 case 'r':
162 if (argv[2])
163 set_retransmit(atoi(argv[2]));
164 else
165 exit(usage(argv[0]));
166 break;
167 case 'k':
168 if (argv[2])
169 set_keepalive(atoi(argv[2]));
170 else
171 exit(usage(argv[0]));
172 break;
173 case 'd':
174 display(argc-1, &argv[1]);
175 break;
176 case 'h':
177 shutdown();
178 break;
179 case 's':
180 start_latd(argc, argv);
181 break;
182 case 'x':
183 set_rating(argc, argv);
184 break;
185 case 'i':
186 set_ident(argc, argv);
187 break;
188 case 'z':
189 printf("counters not yet done\n");
190 break;
191 case 'U':
192 set_user_groups(argc, argv);
193 break;
194 case 'u':
195 set_user_groups(argc, argv);
196 break;
197 case 'g':
198 set_server_groups(argc, argv);
199 break;
200 case 'G':
201 set_server_groups(argc, argv);
202 break;
203 default:
204 exit(usage(argv[0]));
205 break;
206 }
207 }
208
209
210 // Display latd characteristics or learned services
display(int argc,char * argv[])211 void display(int argc, char *argv[])
212 {
213 char verboseflag[1] = {'\0'};
214 signed char opt;
215 bool show_services = false;
216 bool show_nodes = false;
217
218 if (!open_socket(false)) return;
219
220 while ((opt=getopt(argc,argv,"lvn")) != EOF)
221 {
222 switch(opt)
223 {
224 case 'l':
225 show_services=true;
226 break;
227
228 case 'v':
229 verboseflag[0] = 1;
230 break;
231
232 case 'n':
233 show_nodes = true;
234 break;
235
236 default:
237 fprintf(stderr, "only -v, -n or -l valid with -d flag\n");
238 exit(2);
239 }
240 }
241
242 if (show_nodes)
243 {
244 send_msg(latcp_socket, LATCP_SHOWNODES, verboseflag, 1);
245 unsigned char *result;
246 int len;
247 int cmd;
248 if (!read_reply(latcp_socket, cmd, result, len))
249 {
250 std::cout << result;
251
252 delete[] result;
253 }
254 return;
255 }
256
257 if (show_services)
258 {
259 send_msg(latcp_socket, LATCP_SHOWSERVICE, verboseflag, 1);
260 }
261 else
262 {
263 send_msg(latcp_socket, LATCP_SHOWCHAR, verboseflag, 1);
264 }
265
266 unsigned char *result = NULL;
267 int len;
268 int cmd;
269
270 if (!read_reply(latcp_socket, cmd, result, len))
271 {
272 std::cout << result;
273
274 delete[] result;
275 }
276 }
277
278
279 // Change the rating of a service
set_rating(int argc,char * argv[])280 void set_rating(int argc, char *argv[])
281 {
282 int new_rating = 0;
283 bool static_rating = false;
284 char service[256];
285 signed char opt;
286
287 if (!open_socket(false)) return;
288
289 while ((opt=getopt(argc,argv,"x:sa:")) != EOF)
290 {
291 switch(opt)
292 {
293 case 'x':
294 new_rating = atoi(optarg);
295 break;
296
297 case 's':
298 static_rating = true;
299 break;
300
301 case 'a':
302 strcpy(service, optarg);
303 make_upper(service);
304 break;
305
306 default:
307 fprintf(stderr, "only valid with -a and -x flags\n");
308 exit(2);
309 }
310 }
311
312 if (!new_rating)
313 {
314 fprintf(stderr, "Invalid rating\n");
315 exit(2);
316 }
317
318 make_upper(service);
319
320 char message[520];
321 int ptr = 2;
322 message[0] = (int)static_rating;
323 message[1] = new_rating;
324 add_string((unsigned char*)message, &ptr, (unsigned char*)service);
325 send_msg(latcp_socket, LATCP_SETRATING, message, ptr);
326
327 // Wait for ACK or error
328 unsigned char *result = NULL;
329 int len;
330 int cmd;
331
332 exit (read_reply(latcp_socket, cmd, result, len));
333
334 }
335
336
337 // Change the ident of a service
set_ident(int argc,char * argv[])338 void set_ident(int argc, char *argv[])
339 {
340 char service[256];
341 char ident[256];
342 signed char opt;
343
344 if (!open_socket(false)) return;
345
346 while ((opt=getopt(argc,argv,"i:a:")) != EOF)
347 {
348 switch(opt)
349 {
350 case 'a':
351 strcpy(service, optarg);
352 make_upper(service);
353 break;
354 case 'i':
355 strcpy(ident, optarg);
356 break;
357
358 default:
359 fprintf(stderr, "must have both -i and -a flags\n");
360 exit(2);
361 }
362 }
363
364 make_upper(service);
365
366 char message[1024];
367 int ptr = 0;
368 add_string((unsigned char*)message, &ptr, (unsigned char*)service);
369 add_string((unsigned char*)message, &ptr, (unsigned char*)ident);
370 send_msg(latcp_socket, LATCP_SETIDENT, message, ptr);
371
372 // Wait for ACK or error
373 unsigned char *result = NULL;
374 int len;
375 int cmd;
376 exit(read_reply(latcp_socket, cmd, result, len));
377 }
378
379
set_server_groups(int argc,char * argv[])380 void set_server_groups(int argc, char *argv[])
381 {
382 signed char opt;
383 int cmd;
384 char groups[256];
385
386 while ((opt=getopt(argc,argv,"G:g:")) != EOF)
387 {
388 switch(opt)
389 {
390 case 'G':
391 cmd = LATCP_SETSERVERGROUPS;
392 strcpy(groups, optarg);
393 break;
394
395 case 'g':
396 cmd = LATCP_UNSETSERVERGROUPS;
397 strcpy(groups, optarg);
398 break;
399
400 default:
401 fprintf(stderr, "Just G or g please\n");
402 exit(2);
403 }
404 }
405
406 if (!open_socket(false)) return;
407
408 char bitmap[32]; // 256 bits
409 make_bitmap(bitmap, groups);
410
411 send_msg(latcp_socket, cmd, bitmap, 32);
412
413 // Wait for ACK or error
414 unsigned char *result = NULL;
415 int len;
416 exit(read_reply(latcp_socket, cmd, result, len));
417
418 }
419
set_user_groups(int argc,char * argv[])420 void set_user_groups(int argc, char *argv[])
421 {
422 signed char opt;
423 int cmd;
424 char groups[256];
425
426 while ((opt=getopt(argc,argv,"u:U:")) != EOF)
427 {
428 switch(opt)
429 {
430 case 'U':
431 cmd = LATCP_SETUSERGROUPS;
432 strcpy(groups, optarg);
433 break;
434
435 case 'u':
436 cmd = LATCP_UNSETUSERGROUPS;
437 strcpy(groups, optarg);
438 break;
439
440 default:
441 fprintf(stderr, "Just U or u please\n");
442 exit(2);
443 }
444 }
445
446 if (!open_socket(false)) return;
447
448 char bitmap[32]; // 256 bits
449 make_bitmap(bitmap, groups);
450
451 send_msg(latcp_socket, cmd, bitmap, 32);
452
453 // Wait for ACK or error
454 unsigned char *result = NULL;
455 int len;
456 exit(read_reply(latcp_socket, cmd, result, len));
457
458 }
459
460 // Enable/Disable the service responder
set_responder(int onoff)461 void set_responder(int onoff)
462 {
463 if (!open_socket(false)) return;
464
465 char flag[1];
466 flag[0] = onoff;
467 send_msg(latcp_socket, LATCP_SETRESPONDER, flag, 1);
468 }
469
470 // Shutdown latd
shutdown()471 void shutdown()
472 {
473 if (!open_socket(false)) return;
474
475 char dummy[1];
476 send_msg(latcp_socket, LATCP_SHUTDOWN, dummy, 0);
477 }
478
479 // Purge learned services
purge_services()480 void purge_services()
481 {
482 if (!open_socket(false)) return;
483
484 char dummy[1];
485 send_msg(latcp_socket, LATCP_PURGE, dummy, 0);
486 }
487
set_multicast(int newtime)488 void set_multicast(int newtime)
489 {
490 if (newtime < 10 || newtime > 180)
491 {
492 fprintf(stderr, "invalid multicast time\n");
493 return;
494 }
495 if (!open_socket(false)) return;
496
497 send_msg(latcp_socket, LATCP_SETMULTICAST, (char *)&newtime, sizeof(int));
498 }
499
set_retransmit(int newlim)500 void set_retransmit(int newlim)
501 {
502 if (newlim < 4 || newlim > 120)
503 {
504 fprintf(stderr, "invalid retransmit limit\n");
505 return;
506 }
507 if (!open_socket(false)) return;
508
509 send_msg(latcp_socket, LATCP_SETRETRANS, (char *)&newlim, sizeof(int));
510 }
511
set_keepalive(int newtime)512 void set_keepalive(int newtime)
513 {
514 if (newtime < 10 || newtime > 180)
515 {
516 fprintf(stderr, "invalid keepalive timer\n");
517 return;
518 }
519 if (!open_socket(false)) return;
520
521 send_msg(latcp_socket, LATCP_SETKEEPALIVE, (char *)&newtime, sizeof(int));
522 }
523
set_node(char * name)524 void set_node(char *name)
525 {
526 if (!open_socket(false)) return;
527
528 make_upper(name);
529
530 char message[520];
531 int ptr = 0;
532 add_string((unsigned char*)message, &ptr, (unsigned char*)name);
533
534 send_msg(latcp_socket, LATCP_SETNODENAME, message, ptr);
535 return;
536 }
537
add_service(int argc,char * argv[])538 void add_service(int argc, char *argv[])
539 {
540 char name[255] = {'\0'};
541 char ident[255] = {'\0'};
542 char remport[255] = {'\0'};
543 char localport[255] = {'\0'};
544 char remnode[255] = {'\0'};
545 char remservice[255] = {'\0'};
546 char password[255] = {'\0'};
547 char command[1024] = {'\0'};
548 signed char opt;
549 bool got_service=false;
550 bool got_port=false;
551 bool static_rating=false;
552 int rating = 0;
553 int queued = 0;
554 int clean = 0;
555 int max_connections = 0;
556 uid_t target_uid = 0;
557 gid_t target_gid = 0;
558 struct passwd *target_user;
559
560 opterr = 0;
561 while ((opt=getopt(argc,argv,"a:i:p:H:R:V:r:w:sQ8C:m:u:")) != EOF)
562 {
563 switch(opt)
564 {
565 case 'a':
566 got_service=true;
567 strcpy(name, optarg);
568 make_upper(name);
569 break;
570
571 case 'i':
572 got_service=true;
573 strcpy(ident, optarg);
574 break;
575
576 case 'w':
577 strcpy(password, optarg);
578 break;
579
580 case 'p':
581 got_port=true;
582 strcpy(localport, optarg);
583 if (strncmp(localport, LAT_DIRECTORY, strlen(LAT_DIRECTORY)) != 0)
584 {
585 fprintf(stderr, "Local port name must start " LAT_DIRECTORY "\n");
586 return;
587 }
588 break;
589
590 case 'H':
591 got_port=true;
592 strcpy(remnode, optarg);
593 make_upper(remnode);
594 break;
595
596 case 'R':
597 got_port=true;
598 strcpy(remport, optarg);
599 make_upper(remport);
600 break;
601
602 case 'V':
603 got_port=true;
604 strcpy(remservice, optarg);
605 make_upper(remservice);
606 break;
607
608 case 'Q':
609 got_port=true;
610 queued = 1;
611 break;
612
613 case 's':
614 static_rating = true;
615 break;
616
617 case '8':
618 clean = true;
619 break;
620
621 case 'C':
622 strcpy(command, optarg);
623 break;
624
625 case 'u':
626 target_user = getpwnam(optarg);
627 if (target_user == NULL)
628 {
629 fprintf(stderr, "Unknown username '%s'\n", optarg);
630 exit(99);
631 }
632 target_uid = target_user->pw_uid;
633 target_gid = target_user->pw_gid;
634 break;
635
636 case 'm':
637 max_connections = atoi(optarg);
638 break;
639
640 case 'r':
641 rating = atoi(optarg);
642 break;
643
644 default:
645 fprintf(stderr, "No more service switches defined yet\n");
646 exit(2);
647 }
648 }
649
650 if (!open_socket(false)) return;
651
652 // Variables for ACK message
653 unsigned char *result = NULL;
654 int len;
655 int cmd;
656
657 if (got_service)
658 {
659 if (name[0] == '\0')
660 {
661 fprintf(stderr, "No name for new service\n");
662 exit(2);
663 }
664
665 char message[520];
666 int ptr = 2;
667 message[0] = (int)static_rating;
668 message[1] = rating;
669 add_string((unsigned char*)message, &ptr, (unsigned char*)name);
670 add_string((unsigned char*)message, &ptr, (unsigned char*)ident);
671 message[ptr++] = max_connections;
672 memcpy(message+ptr, &target_uid, sizeof(uid_t)); ptr += sizeof(uid_t);
673 memcpy(message+ptr, &target_gid, sizeof(uid_t)); ptr += sizeof(gid_t);
674 add_string((unsigned char*)message, &ptr, (unsigned char*)command);
675
676 send_msg(latcp_socket, LATCP_ADDSERVICE, message, ptr);
677
678 // Wait for ACK or error
679 exit(read_reply(latcp_socket, cmd, result, len));
680 }
681
682 if (got_port)
683 {
684 char message[520];
685 int ptr = 0;
686 add_string((unsigned char*)message, &ptr, (unsigned char*)remservice);
687 add_string((unsigned char*)message, &ptr, (unsigned char*)remport);
688 add_string((unsigned char*)message, &ptr, (unsigned char*)localport);
689 add_string((unsigned char*)message, &ptr, (unsigned char*)remnode);
690 message[ptr++] = queued;
691 message[ptr++] = clean;
692 add_string((unsigned char*)message, &ptr, (unsigned char*)password);
693 send_msg(latcp_socket, LATCP_ADDPORT, message, ptr);
694
695 // Wait for ACK or error
696 exit(read_reply(latcp_socket, cmd, result, len));
697 }
698
699 fprintf(stderr, "Sorry, did you want me to do something??\n");
700 }
701
del_service(int argc,char * argv[])702 void del_service(int argc, char *argv[])
703 {
704 char name[255] = {'\0'};
705 signed char opt;
706 bool got_service = false;
707 bool got_port = false;
708 opterr = 0;
709
710 while ((opt=getopt(argc,argv,"a:p:")) != EOF)
711 {
712 switch(opt)
713 {
714 case 'a':
715 got_service = true;
716 strcpy(name, optarg);
717 make_upper(name);
718 break;
719
720 case 'p':
721 got_port = true;
722 strcpy(name, optarg);
723 break;
724
725 default:
726 fprintf(stderr, "No more service switches defined yet\n");
727 exit(2);
728 }
729 }
730
731 if ((got_port && got_service) ||
732 (!got_port && !got_service))
733 {
734 fprintf(stderr, "Either -a or -p can be specified but not both\n");
735 return;
736 }
737
738
739 if (!open_socket(false)) return;
740
741 char message[520];
742 int ptr = 0;
743 add_string((unsigned char*)message, &ptr, (unsigned char*)name);
744 if (got_service)
745 send_msg(latcp_socket, LATCP_REMSERVICE, message, ptr);
746 else
747 send_msg(latcp_socket, LATCP_REMPORT, message, ptr);
748
749 unsigned char *result = NULL;
750 int len;
751 int cmd;
752 exit(read_reply(latcp_socket, cmd, result, len));
753 }
754
755 // Start latd & run startup script.
start_latd(int argc,char * argv[])756 void start_latd(int argc, char *argv[])
757 {
758 if (getuid() != 0)
759 {
760 fprintf(stderr, "You must be root to start latd\n");
761 return;
762 }
763
764 // If we can connect to LATD than it's already running
765 if (open_socket(true))
766 {
767 fprintf(stderr, "LAT is already running\n");
768 return;
769 }
770
771 // Look for latd in well-known places
772 struct stat st;
773 char *latd_bin = NULL;
774 char *latd_path = NULL;
775
776 // Look for latd in the same place as latcp
777 char *name = (char *)malloc(strlen(argv[0])+1);
778 char *path = (char *)malloc(strlen(argv[0])+1);
779 strcpy(name, argv[0]);
780
781 char *slash = rindex(name, '/');
782 if (slash)
783 {
784 *slash='\0';
785 strcpy(path, name);
786 strcat(name, "/latd");
787 if (!stat(name, &st))
788 {
789 latd_bin = name;
790 latd_path = path;
791 }
792 }
793 // Otherwise look in some well-known places
794 else if (!stat("/usr/sbin/latd", &st))
795 {
796 latd_bin = (char *)"/usr/sbin/latd";
797 latd_path = (char *)"/usr/sbin";
798 }
799 else if (!stat("/usr/local/sbin/latd", &st))
800 {
801 latd_bin = (char *)"/usr/local/sbin/latd";
802 latd_path = (char *)"/usr/local/sbin";
803 }
804
805 // Did we find it?
806 if (latd_bin)
807 {
808 char *newargv[argc+1];
809 char *newenv[4];
810 int i;
811 char latcp_bin[PATH_MAX];
812 char latcp_env[PATH_MAX+7];
813
814 // This is VERY Linux specific and needs /proc mounted.
815 // we get the full path of the current executable by doing a readlink.
816 // /proc/<pid>/exe
817
818 #ifdef __linux__
819 char latcp_proc[PATH_MAX];
820
821 sprintf(latcp_proc, "/proc/%d/exe", getpid());
822 if ( (i=readlink(latcp_proc, latcp_bin, sizeof(latcp_bin))) == -1)
823 {
824 fprintf(stderr, "readlink in /proc failed. Make sure the the proc filesystem is mounted on /proc\n");
825 exit(2);
826 }
827 #endif
828 sprintf(latcp_env, "LATCP=%s", latcp_bin);
829
830 newargv[0] = latd_bin;
831 newargv[1] = NULL;
832 newenv[0] = (char *)"PATH=/bin:/usr/bin:/sbin:/usr/sbin";
833 newenv[1] = (char*)"LATCP_STARTED=true"; // Tell latd it was started by us.
834 newenv[2] = latcp_env;
835 newenv[3] = NULL;
836
837 switch(fork())
838 {
839 case 1: //Error
840 perror("fork failed");
841 return;
842 case 0: // Child
843 // Start latd with our args (after the "-s")
844 for (i=2; i<argc; i++)
845 newargv[i-1] = argv[i];
846 newargv[i-1] = NULL;
847
848 execve(latd_bin, newargv, newenv);
849 perror("exec of latd failed");
850 break;
851
852 default: //Parent
853 {
854 // Wait for latd to start up
855 int count = 0;
856 while (!open_socket(true) && count < 10)
857 {
858 sleep(1);
859 count++;
860 }
861 if (count >= 10)
862 {
863 fprintf(stderr, "latd did not start\n");
864 exit(2);
865 }
866
867
868 // Run startup script if there is one.
869 if (!stat("/etc/latd.conf", &st))
870 {
871 pid_t shell_pid;
872 switch ( (shell_pid=fork()) )
873 {
874 case 0: // Child
875 newargv[0] = (char *)"/bin/sh";
876 newargv[1] = (char *)"/etc/latd.conf";
877 newargv[2] = NULL;
878 execve("/bin/sh", newargv, newenv);
879 perror("exec of /bin/sh failed");
880 exit(0);
881
882 case -1:
883 perror("Fork failed");
884 exit(0);
885
886 default: // Parent. Wait for child to finish
887 waitpid(shell_pid, NULL, 0);
888 }
889 }
890 // OK, latd has started and we have run the startup script.
891 // Now "unlock" latd. ie tell it we have finished initialisation
892 char dummy[1];
893 send_msg(latcp_socket, LATCP_UNLOCK, dummy, 0);
894 }
895 break;
896 }
897 }
898 else
899 {
900 fprintf(stderr, "cannot find latd\n");
901 return;
902 }
903 }
904
905
send_msg(int fd,int cmd,char * buf,int len)906 bool send_msg(int fd, int cmd, char *buf, int len)
907 {
908 unsigned char outhead[3];
909
910 outhead[0] = cmd;
911 outhead[1] = len/256;
912 outhead[2] = len%256;
913 if (write(fd, outhead, 3) != 3) return false;
914 if (write(fd, buf, len) != len) return false;
915
916 return true;
917 }
918
919
920 // Return 0 for success and -1 for failure
read_reply(int fd,int & cmd,unsigned char * & cmdbuf,int & len)921 int read_reply(int fd, int &cmd, unsigned char *&cmdbuf, int &len)
922 {
923 unsigned char head[3];
924
925 // Get the message header (cmd & length)
926 if (read(fd, head, sizeof(head)) != 3)
927 return -1; // Bad header
928
929 len = head[1] * 256 + head[2];
930 cmd = head[0];
931 cmdbuf = new unsigned char[len];
932 if (cmdbuf == NULL)
933 return -1;
934
935 // Read the message buffer
936 if (read(fd, cmdbuf, len) != len)
937 {
938 return -1; // Bad message
939 }
940
941 if (cmd == LATCP_ERRORMSG)
942 {
943 fprintf(stderr, "%s\n", cmdbuf);
944 return -1;
945 }
946
947 return 0;
948 }
949
open_socket(bool quiet)950 bool open_socket(bool quiet)
951 {
952 struct sockaddr_un sockaddr;
953
954 latcp_socket = socket(PF_UNIX, SOCK_STREAM, 0);
955 if (latcp_socket == -1)
956 {
957 if (!quiet) perror("Can't create socket");
958 return false; /* arggh ! */
959 }
960
961 strcpy(sockaddr.sun_path, LATCP_SOCKNAME);
962 sockaddr.sun_family = AF_UNIX;
963 if (connect(latcp_socket, (struct sockaddr *)&sockaddr, sizeof(sockaddr)))
964 {
965 if (!quiet) perror("Can't connect to latd");
966 close(latcp_socket);
967 return false;
968 }
969
970 unsigned char *result = NULL;
971 int len;
972 int cmd;
973
974 // Send our version
975 send_msg(latcp_socket, LATCP_VERSION, (char*)VERSION, strlen(VERSION)+1);
976
977 if (!read_reply(latcp_socket, cmd, result, len)) // Read version number back
978 delete[] result;
979
980 return true;
981 }
982
make_upper(char * str)983 static void make_upper(char *str)
984 {
985 unsigned int i;
986
987 for (i=0; i<strlen(str); i++)
988 {
989 str[i] = toupper(str[i]);
990 }
991 }
992
set_in_bitmap(char * bits,int entry)993 static inline void set_in_bitmap(char *bits, int entry)
994 {
995
996 if (entry < 256)
997 {
998 unsigned int intnum;
999 unsigned int bitnum;
1000
1001 intnum = entry / 8;
1002 bitnum = entry % 8;
1003 bits[intnum] |= 1<<bitnum;
1004 }
1005 }
1006
make_bitmap(char * bitmap,char * cmdline)1007 static void make_bitmap(char *bitmap, char *cmdline)
1008 {
1009 int firstnum;
1010 int secondnum;
1011 int i;
1012 bool finished = false;
1013 char delimchar;
1014 char* delimiter;
1015
1016 memset(bitmap, 0, 32);
1017 delimiter = strpbrk(cmdline, ",-");
1018
1019 do
1020 {
1021 if (delimiter == NULL)
1022 {
1023 delimchar = ',';
1024 }
1025 else
1026 {
1027 delimchar = delimiter[0];
1028 delimiter[0] = '\0';
1029 }
1030 firstnum = atoi(cmdline);
1031 if (delimiter != NULL) delimiter[0] = delimchar;
1032
1033 /* Found a comma -- mark the number preceding it as read */
1034 if ((delimchar == ',') || (delimiter == NULL))
1035 {
1036 set_in_bitmap(bitmap, firstnum);
1037 }
1038
1039 /* Found a hyphen -- mark the range as read */
1040 if (delimchar == '-')
1041 {
1042 cmdline = delimiter+1;
1043 delimiter = strpbrk(cmdline, ",");
1044
1045 if (delimiter != NULL)
1046 {
1047 delimchar = delimiter[0];
1048 delimiter[0] = '\0';
1049 }
1050 secondnum = atoi(cmdline);
1051 if (delimiter != NULL) delimiter[0] = delimchar;
1052
1053 for (i=firstnum; i<=secondnum; i++)
1054 {
1055 set_in_bitmap(bitmap, i);
1056 }
1057 }
1058 if (delimiter == NULL) finished = true;
1059
1060 cmdline = delimiter+1;
1061 if (delimiter != NULL) delimiter = strpbrk(cmdline, ",-");
1062 } while (!finished);
1063 }
1064