fix systemd unit install path
[external/acpid.git] / acpi_listen.c
1 /*
2  *  acpi_listen.c - ACPI client for acpid's UNIX socket
3  *
4  *  Portions Copyright (C) 2003 Sun Microsystems (thockin@sun.com)
5  *  Some parts (C) 2003 - Gismo / Luca Capello <luca.pca.it> http://luca.pca.it
6  *  Copyright (C) 2004 Tim Hockin (thockin@hockin.org)
7  *
8  *  This program is free software; you can redistribute it and/or modify
9  *  it under the terms of the GNU General Public License as published by
10  *  the Free Software Foundation; either version 2 of the License, or
11  *  (at your option) any later version.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to the Free Software
20  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <unistd.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <ctype.h>
33 #include <getopt.h>
34 #include <time.h>
35 #include <sys/poll.h>
36 #include <grp.h>
37 #include <signal.h>
38
39 #include "acpid.h"
40 #include "ud_socket.h"
41
42 static int handle_cmdline(int *argc, char ***argv);
43 static char *read_line(int fd);
44
45 const char *progname;
46 const char *socketfile = ACPID_SOCKETFILE;
47 static int max_events;
48
49 static void
50 time_expired(int signum __attribute__((unused)))
51 {
52         exit(EXIT_SUCCESS);
53 }
54
55 int
56 main(int argc, char **argv)
57 {
58         int sock_fd;
59         int ret;
60
61         /* handle an alarm */
62         signal(SIGALRM, time_expired);
63
64         /* learn who we really are */
65         progname = (const char *)strrchr(argv[0], '/');
66         progname = progname ? (progname + 1) : argv[0];
67
68         /* handle the commandline  */
69         handle_cmdline(&argc, &argv);
70
71         /* open the socket */
72         sock_fd = ud_connect(socketfile);
73         if (sock_fd < 0) {
74                 fprintf(stderr, "%s: can't open socket %s: %s\n",
75                         progname, socketfile, strerror(errno));
76                 exit(EXIT_FAILURE);
77         }
78         fcntl(sock_fd, F_SETFD, FD_CLOEXEC);
79
80         /* set stdout to be line buffered */
81         setvbuf(stdout, NULL, _IOLBF, 0);
82
83         /* main loop */
84         ret = 0;
85         while (1) {
86                 char *event;
87
88                 /* read and handle an event */
89                 event = read_line(sock_fd);
90                 if (event) {
91                         fprintf(stdout, "%s\n", event);
92                 } else if (errno == EPIPE) {
93                         fprintf(stderr, "connection closed\n");
94                         break;
95                 } else {
96                         static int nerrs;
97                         if (++nerrs >= ACPID_MAX_ERRS) {
98                                 fprintf(stderr, "too many errors - aborting\n");
99                                 ret = 1;
100                                 break;
101                         }
102                 }
103
104                 if (max_events > 0 && --max_events == 0) {
105                         break;
106                 }
107         }
108
109         return ret;
110 }
111
112 static struct option opts[] = {
113         {"count", 0, 0, 'c'},
114         {"socketfile", 1, 0, 's'},
115         {"time", 0, 0, 't'},
116         {"version", 0, 0, 'v'},
117         {"help", 0, 0, 'h'},
118         {NULL, 0, 0, 0},
119 };
120 static const char *opts_help[] = {
121         "Set the maximum number of events.",    /* count */
122         "Use the specified socket file.",       /* socketfile */
123         "Listen for the specified time (in seconds).",/* time */
124         "Print version information.",           /* version */
125         "Print this message.",                  /* help */
126 };
127
128 static void
129 usage(FILE *fp)
130 {
131         struct option *opt;
132         const char **hlp;
133         int max, size;
134
135         fprintf(fp, "Usage: %s [OPTIONS]\n", progname);
136         max = 0;
137         for (opt = opts; opt->name; opt++) {
138                 size = strlen(opt->name);
139                 if (size > max)
140                         max = size;
141         }
142         for (opt = opts, hlp = opts_help; opt->name; opt++, hlp++) {
143                 fprintf(fp, "  -%c, --%s", opt->val, opt->name);
144                 size = strlen(opt->name);
145                 for (; size < max; size++)
146                         fprintf(fp, " ");
147                 fprintf(fp, "  %s\n", *hlp);
148         }
149 }
150
151 /*
152  * Parse command line arguments
153  */
154 static int
155 handle_cmdline(int *argc, char ***argv)
156 {
157         for (;;) {
158                 int i;
159                 i = getopt_long(*argc, *argv, "c:s:t:vh", opts, NULL);
160                 if (i == -1) {
161                         break;
162                 }
163                 switch (i) {
164                 case 'c':
165                         if (!isdigit(optarg[0])) {
166                                 usage(stderr);
167                                 exit(EXIT_FAILURE);
168                         }
169                         max_events = atoi(optarg);
170                         break;
171                 case 's':
172                         socketfile = optarg;
173                         break;
174                 case 't':
175                         if (!isdigit(optarg[0])) {
176                                 usage(stderr);
177                                 exit(EXIT_FAILURE);
178                         }
179                         alarm(atoi(optarg));
180                         break;
181                 case 'v':
182                         printf(PACKAGE "-" VERSION "\n");
183                         exit(EXIT_SUCCESS);
184                 case 'h':
185                         usage(stdout);
186                         exit(EXIT_SUCCESS);
187                 default:
188                         usage(stderr);
189                         exit(EXIT_FAILURE);
190                         break;
191                 }
192         }
193
194         *argc -= optind;
195         *argv += optind;
196
197         return 0;
198 }
199
200 #define MAX_BUFLEN      1024
201 static char *
202 read_line(int fd)
203 {
204         static char *buf;
205         int buflen = 64;
206         int i = 0;
207         int r;
208         int searching = 1;
209
210         while (searching) {
211                 buf = realloc(buf, buflen);
212                 if (!buf) {
213                         fprintf(stderr, "ERR: malloc(%d): %s\n",
214                                 buflen, strerror(errno));
215                         return NULL;
216                 }
217                 memset(buf+i, 0, buflen-i);
218
219                 while (i < buflen) {
220                         r = read(fd, buf+i, 1);
221                         if (r < 0 && errno != EINTR) {
222                                 /* we should do something with the data */
223                                 fprintf(stderr, "ERR: read(): %s\n",
224                                         strerror(errno));
225                                 return NULL;
226                         } else if (r == 0) {
227                                 /* signal this in an almost standard way */
228                                 errno = EPIPE;
229                                 return NULL;
230                         } else if (r == 1) {
231                                 /* scan for a newline */
232                                 if (buf[i] == '\n') {
233                                         searching = 0;
234                                         buf[i] = '\0';
235                                         break;
236                                 }
237                                 i++;
238                         }
239                 }
240                 if (buflen >= MAX_BUFLEN) {
241                         break;
242                 }
243                 buflen *= 2;
244         }
245
246         return buf;
247 }