fix systemd unit install path
[external/acpid.git] / proc.c
1 /*
2  *  proc.c - ACPI daemon proc filesystem interface
3  *
4  *  Portions Copyright (C) 2000 Andrew Henroid
5  *  Portions Copyright (C) 2001 Sun Microsystems
6  *  Portions 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 <unistd.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <errno.h>
29
30 #include "acpid.h"
31 #include "log.h"
32 #include "event.h"
33 #include "connection_list.h"
34
35 const char *eventfile = ACPID_EVENTFILE;
36
37 static char *read_line(int fd);
38
39 static void
40 process_proc(int fd)
41 {
42         char *event;
43
44         /* read an event */
45         event = read_line(fd);
46
47         /* if we're locked, don't process the event */
48         if (locked()) {
49                 if (logevents  &&  event != NULL) {
50                         acpid_log(LOG_INFO,
51                                 "lockfile present, not processing "
52                                 "event \"%s\"", event);
53                 }
54                 return;
55         }
56
57         /* handle the event */
58         if (event) {
59                 if (logevents) {
60                         acpid_log(LOG_INFO,
61                                   "procfs received event \"%s\"", event);
62                 }
63                 acpid_handle_event(event);
64                 if (logevents) {
65                         acpid_log(LOG_INFO,
66                                 "procfs completed event \"%s\"", event);
67                 }
68         } else if (errno == EPIPE) {
69                 acpid_log(LOG_WARNING,
70                         "events file connection closed");
71                 exit(EXIT_FAILURE);
72         } else {
73                 static int nerrs;
74                 if (++nerrs >= ACPID_MAX_ERRS) {
75                         acpid_log(LOG_ERR,
76                                 "too many errors reading "
77                                 "events file - aborting");
78                         exit(EXIT_FAILURE);
79                 }
80         }
81 }
82
83 int
84 open_proc()
85 {
86         int fd;
87         struct connection c;
88         
89         fd = open(eventfile, O_RDONLY);
90         if (fd < 0) {
91                 if (errno == ENOENT) {
92                         acpid_log(LOG_DEBUG, "Deprecated %s was not found.  "
93                                 "Trying netlink and the input layer...", eventfile);
94                 } else {
95                         acpid_log(LOG_ERR, "can't open %s: %s (%d)", eventfile, 
96                                 strerror(errno), errno);
97                 }
98                 return -1;
99                 
100         }
101
102     /* Make sure scripts we exec() (in event.c) don't get our file 
103        descriptors. */
104     fcntl(fd, F_SETFD, FD_CLOEXEC);
105
106         acpid_log(LOG_DEBUG, "proc fs opened successfully");
107
108         /* add a connection to the list */
109         c.fd = fd;
110         c.process = process_proc;
111         c.pathname = NULL;
112         c.kybd = 0;
113         add_connection(&c);
114
115         return 0;
116 }
117
118 /*
119  * This depends on fixes in linux ACPI after 2.4.8
120  */
121 #define BUFLEN 1024
122 static char *
123 read_line(int fd)
124 {
125         static char buf[BUFLEN];
126         int i = 0;
127         int r;
128         int searching = 1;
129
130         while (searching) {
131                 memset(buf+i, 0, BUFLEN-i);
132
133                 /* only go to BUFLEN-1 so there will always be a 0 at the end */
134                 while (i < BUFLEN-1) {
135                         r = read(fd, buf+i, 1);
136                         if (r < 0 && errno != EINTR) {
137                                 /* we should do something with the data */
138                                 acpid_log(LOG_ERR, "read(): %s",
139                                         strerror(errno));
140                                 return NULL;
141                         } else if (r == 0) {
142                                 /* signal this in an almost standard way */
143                                 errno = EPIPE;
144                                 return NULL;
145                         } else if (r == 1) {
146                                 /* scan for a newline */
147                                 if (buf[i] == '\n') {
148                                         searching = 0;
149                                         buf[i] = '\0';
150                                         break;
151                                 }
152                                 i++;
153                         }
154                 }
155                 if (i >= BUFLEN - 1)
156                         break;
157         }
158
159         return buf;
160 }
161
162 #if 0
163 /* This version leaks memory.  The above version is simpler and leak-free. */
164 /* Downside is that the above version always uses 1k of RAM. */
165 /*
166  * This depends on fixes in linux ACPI after 2.4.8
167  */
168 #define MAX_BUFLEN      1024
169 static char *
170 read_line(int fd)
171 {
172         static char *buf;
173         int buflen = 64;
174         int i = 0;
175         int r;
176         int searching = 1;
177
178         while (searching) {
179                 /* ??? This memory is leaked since it is never freed */
180                 buf = realloc(buf, buflen);
181                 if (!buf) {
182                         acpid_log(LOG_ERR, "malloc(%d): %s",
183                                 buflen, strerror(errno));
184                         return NULL;
185                 }
186                 memset(buf+i, 0, buflen-i);
187
188                 while (i < buflen) {
189                         r = read(fd, buf+i, 1);
190                         if (r < 0 && errno != EINTR) {
191                                 /* we should do something with the data */
192                                 acpid_log(LOG_ERR, "read(): %s",
193                                         strerror(errno));
194                                 return NULL;
195                         } else if (r == 0) {
196                                 /* signal this in an almost standard way */
197                                 errno = EPIPE;
198                                 return NULL;
199                         } else if (r == 1) {
200                                 /* scan for a newline */
201                                 if (buf[i] == '\n') {
202                                         searching = 0;
203                                         buf[i] = '\0';
204                                         break;
205                                 }
206                                 i++;
207                         }
208                 }
209                 if (buflen >= MAX_BUFLEN) {
210                         break;
211                 } 
212                 buflen *= 2;
213         }
214
215         return buf;
216 }
217 #endif