dnsmasq: v2.67test16 patch Sept.25th/2013.
[tomato.git] / release / src / router / dnsmasq / src / helper.c
blobd6bcd63ba39175d651dd7320462408358f4d6ad6
1 /* dnsmasq is Copyright (c) 2000-2013 Simon Kelley
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; version 2 dated June, 1991, or
6 (at your option) version 3 dated 29 June, 2007.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include "dnsmasq.h"
19 #ifdef HAVE_SCRIPT
21 /* This file has code to fork a helper process which recieves data via a pipe
22 shared with the main process and which is responsible for calling a script when
23 DHCP leases change.
25 The helper process is forked before the main process drops root, so it retains root
26 privs to pass on to the script. For this reason it tries to be paranoid about
27 data received from the main process, in case that has been compromised. We don't
28 want the helper to give an attacker root. In particular, the script to be run is
29 not settable via the pipe, once the fork has taken place it is not alterable by the
30 main process.
33 static void my_setenv(const char *name, const char *value, int *error);
34 static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err);
36 #ifdef HAVE_LUASCRIPT
37 #define LUA_COMPAT_ALL
38 #include <lua.h>
39 #include <lualib.h>
40 #include <lauxlib.h>
42 #ifndef lua_open
43 #define lua_open() luaL_newstate()
44 #endif
46 lua_State *lua;
48 static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field);
49 #endif
52 struct script_data
54 int flags;
55 int action, hwaddr_len, hwaddr_type;
56 int clid_len, hostname_len, ed_len;
57 struct in_addr addr, giaddr;
58 unsigned int remaining_time;
59 #ifdef HAVE_BROKEN_RTC
60 unsigned int length;
61 #else
62 time_t expires;
63 #endif
64 #ifdef HAVE_DHCP6
65 struct in6_addr addr6;
66 int iaid, vendorclass_count;
67 #endif
68 unsigned char hwaddr[DHCP_CHADDR_MAX];
69 char interface[IF_NAMESIZE];
72 static struct script_data *buf = NULL;
73 static size_t bytes_in_buf = 0, buf_size = 0;
75 int create_helper(int event_fd, int err_fd, uid_t uid, gid_t gid, long max_fd)
77 pid_t pid;
78 int i, pipefd[2];
79 struct sigaction sigact;
81 /* create the pipe through which the main program sends us commands,
82 then fork our process. */
83 if (pipe(pipefd) == -1 || !fix_fd(pipefd[1]) || (pid = fork()) == -1)
85 send_event(err_fd, EVENT_PIPE_ERR, errno, NULL);
86 _exit(0);
89 if (pid != 0)
91 close(pipefd[0]); /* close reader side */
92 return pipefd[1];
95 /* ignore SIGTERM, so that we can clean up when the main process gets hit
96 and SIGALRM so that we can use sleep() */
97 sigact.sa_handler = SIG_IGN;
98 sigact.sa_flags = 0;
99 sigemptyset(&sigact.sa_mask);
100 sigaction(SIGTERM, &sigact, NULL);
101 sigaction(SIGALRM, &sigact, NULL);
103 if (!option_bool(OPT_DEBUG) && uid != 0)
105 gid_t dummy;
106 if (setgroups(0, &dummy) == -1 ||
107 setgid(gid) == -1 ||
108 setuid(uid) == -1)
110 if (option_bool(OPT_NO_FORK))
111 /* send error to daemon process if no-fork */
112 send_event(event_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
113 else
115 /* kill daemon */
116 send_event(event_fd, EVENT_DIE, 0, NULL);
117 /* return error */
118 send_event(err_fd, EVENT_USER_ERR, errno, daemon->scriptuser);
120 _exit(0);
124 /* close all the sockets etc, we don't need them here.
125 Don't close err_fd, in case the lua-init fails.
126 Note that we have to do this before lua init
127 so we don't close any lua fds. */
128 for (max_fd--; max_fd >= 0; max_fd--)
129 if (max_fd != STDOUT_FILENO && max_fd != STDERR_FILENO &&
130 max_fd != STDIN_FILENO && max_fd != pipefd[0] &&
131 max_fd != event_fd && max_fd != err_fd)
132 close(max_fd);
134 #ifdef HAVE_LUASCRIPT
135 if (daemon->luascript)
137 const char *lua_err = NULL;
138 lua = lua_open();
139 luaL_openlibs(lua);
141 /* get Lua to load our script file */
142 if (luaL_dofile(lua, daemon->luascript) != 0)
143 lua_err = lua_tostring(lua, -1);
144 else
146 lua_getglobal(lua, "lease");
147 if (lua_type(lua, -1) != LUA_TFUNCTION)
148 lua_err = _("lease() function missing in Lua script");
151 if (lua_err)
153 if (option_bool(OPT_NO_FORK) || option_bool(OPT_DEBUG))
154 /* send error to daemon process if no-fork */
155 send_event(event_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
156 else
158 /* kill daemon */
159 send_event(event_fd, EVENT_DIE, 0, NULL);
160 /* return error */
161 send_event(err_fd, EVENT_LUA_ERR, 0, (char *)lua_err);
163 _exit(0);
166 lua_pop(lua, 1); /* remove nil from stack */
167 lua_getglobal(lua, "init");
168 if (lua_type(lua, -1) == LUA_TFUNCTION)
169 lua_call(lua, 0, 0);
170 else
171 lua_pop(lua, 1); /* remove nil from stack */
173 #endif
175 /* All init done, close our copy of the error pipe, so that main process can return */
176 if (err_fd != -1)
177 close(err_fd);
179 /* loop here */
180 while(1)
182 struct script_data data;
183 char *p, *action_str, *hostname = NULL, *domain = NULL;
184 unsigned char *buf = (unsigned char *)daemon->namebuff;
185 unsigned char *end, *extradata, *alloc_buff = NULL;
186 int is6, err = 0;
188 free(alloc_buff);
190 /* we read zero bytes when pipe closed: this is our signal to exit */
191 if (!read_write(pipefd[0], (unsigned char *)&data, sizeof(data), 1))
193 #ifdef HAVE_LUASCRIPT
194 if (daemon->luascript)
196 lua_getglobal(lua, "shutdown");
197 if (lua_type(lua, -1) == LUA_TFUNCTION)
198 lua_call(lua, 0, 0);
200 #endif
201 _exit(0);
204 is6 = !!(data.flags & (LEASE_TA | LEASE_NA));
206 if (data.action == ACTION_DEL)
207 action_str = "del";
208 else if (data.action == ACTION_ADD)
209 action_str = "add";
210 else if (data.action == ACTION_OLD || data.action == ACTION_OLD_HOSTNAME)
211 action_str = "old";
212 else if (data.action == ACTION_TFTP)
214 action_str = "tftp";
215 is6 = (data.flags != AF_INET);
217 else
218 continue;
221 /* stringify MAC into dhcp_buff */
222 p = daemon->dhcp_buff;
223 if (data.hwaddr_type != ARPHRD_ETHER || data.hwaddr_len == 0)
224 p += sprintf(p, "%.2x-", data.hwaddr_type);
225 for (i = 0; (i < data.hwaddr_len) && (i < DHCP_CHADDR_MAX); i++)
227 p += sprintf(p, "%.2x", data.hwaddr[i]);
228 if (i != data.hwaddr_len - 1)
229 p += sprintf(p, ":");
232 /* supplied data may just exceed normal buffer (unlikely) */
233 if ((data.hostname_len + data.ed_len + data.clid_len) > MAXDNAME &&
234 !(alloc_buff = buf = malloc(data.hostname_len + data.ed_len + data.clid_len)))
235 continue;
237 if (!read_write(pipefd[0], buf,
238 data.hostname_len + data.ed_len + data.clid_len, 1))
239 continue;
241 /* CLID into packet */
242 for (p = daemon->packet, i = 0; i < data.clid_len; i++)
244 p += sprintf(p, "%.2x", buf[i]);
245 if (i != data.clid_len - 1)
246 p += sprintf(p, ":");
249 #ifdef HAVE_DHCP6
250 if (is6)
252 /* or IAID and server DUID for IPv6 */
253 sprintf(daemon->dhcp_buff3, "%s%u", data.flags & LEASE_TA ? "T" : "", data.iaid);
254 for (p = daemon->dhcp_packet.iov_base, i = 0; i < daemon->duid_len; i++)
256 p += sprintf(p, "%.2x", daemon->duid[i]);
257 if (i != daemon->duid_len - 1)
258 p += sprintf(p, ":");
262 #endif
264 buf += data.clid_len;
266 if (data.hostname_len != 0)
268 char *dot;
269 hostname = (char *)buf;
270 hostname[data.hostname_len - 1] = 0;
271 if (data.action != ACTION_TFTP)
273 if (!legal_hostname(hostname))
274 hostname = NULL;
275 else if ((dot = strchr(hostname, '.')))
277 domain = dot+1;
278 *dot = 0;
283 extradata = buf + data.hostname_len;
285 if (!is6)
286 inet_ntop(AF_INET, &data.addr, daemon->addrbuff, ADDRSTRLEN);
287 #ifdef HAVE_DHCP6
288 else
289 inet_ntop(AF_INET6, &data.addr6, daemon->addrbuff, ADDRSTRLEN);
290 #endif
292 /* file length */
293 if (data.action == ACTION_TFTP)
294 sprintf(is6 ? daemon->packet : daemon->dhcp_buff, "%u", data.iaid);
296 #ifdef HAVE_LUASCRIPT
297 if (daemon->luascript)
299 if (data.action == ACTION_TFTP)
301 lua_getglobal(lua, "tftp");
302 if (lua_type(lua, -1) != LUA_TFUNCTION)
303 lua_pop(lua, 1); /* tftp function optional */
304 else
306 lua_pushstring(lua, action_str); /* arg1 - action */
307 lua_newtable(lua); /* arg2 - data table */
308 lua_pushstring(lua, daemon->addrbuff);
309 lua_setfield(lua, -2, "destination_address");
310 lua_pushstring(lua, hostname);
311 lua_setfield(lua, -2, "file_name");
312 lua_pushstring(lua, is6 ? daemon->packet : daemon->dhcp_buff);
313 lua_setfield(lua, -2, "file_size");
314 lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
317 else
319 lua_getglobal(lua, "lease"); /* function to call */
320 lua_pushstring(lua, action_str); /* arg1 - action */
321 lua_newtable(lua); /* arg2 - data table */
323 if (is6)
325 lua_pushstring(lua, daemon->packet);
326 lua_setfield(lua, -2, "client_duid");
327 lua_pushstring(lua, daemon->dhcp_packet.iov_base);
328 lua_setfield(lua, -2, "server_duid");
329 lua_pushstring(lua, daemon->dhcp_buff3);
330 lua_setfield(lua, -2, "iaid");
333 if (!is6 && data.clid_len != 0)
335 lua_pushstring(lua, daemon->packet);
336 lua_setfield(lua, -2, "client_id");
339 if (strlen(data.interface) != 0)
341 lua_pushstring(lua, data.interface);
342 lua_setfield(lua, -2, "interface");
345 #ifdef HAVE_BROKEN_RTC
346 lua_pushnumber(lua, data.length);
347 lua_setfield(lua, -2, "lease_length");
348 #else
349 lua_pushnumber(lua, data.expires);
350 lua_setfield(lua, -2, "lease_expires");
351 #endif
353 if (hostname)
355 lua_pushstring(lua, hostname);
356 lua_setfield(lua, -2, "hostname");
359 if (domain)
361 lua_pushstring(lua, domain);
362 lua_setfield(lua, -2, "domain");
365 end = extradata + data.ed_len;
366 buf = extradata;
368 if (!is6)
369 buf = grab_extradata_lua(buf, end, "vendor_class");
370 #ifdef HAVE_DHCP6
371 else if (data.vendorclass_count != 0)
373 sprintf(daemon->dhcp_buff2, "vendor_class_id");
374 buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
375 for (i = 0; i < data.vendorclass_count - 1; i++)
377 sprintf(daemon->dhcp_buff2, "vendor_class%i", i);
378 buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
381 #endif
383 buf = grab_extradata_lua(buf, end, "supplied_hostname");
385 if (!is6)
387 buf = grab_extradata_lua(buf, end, "cpewan_oui");
388 buf = grab_extradata_lua(buf, end, "cpewan_serial");
389 buf = grab_extradata_lua(buf, end, "cpewan_class");
390 buf = grab_extradata_lua(buf, end, "circuit_id");
391 buf = grab_extradata_lua(buf, end, "subscriber_id");
392 buf = grab_extradata_lua(buf, end, "remote_id");
395 buf = grab_extradata_lua(buf, end, "tags");
397 if (is6)
398 buf = grab_extradata_lua(buf, end, "relay_address");
399 else if (data.giaddr.s_addr != 0)
401 lua_pushstring(lua, inet_ntoa(data.giaddr));
402 lua_setfield(lua, -2, "relay_address");
405 for (i = 0; buf; i++)
407 sprintf(daemon->dhcp_buff2, "user_class%i", i);
408 buf = grab_extradata_lua(buf, end, daemon->dhcp_buff2);
411 if (data.action != ACTION_DEL && data.remaining_time != 0)
413 lua_pushnumber(lua, data.remaining_time);
414 lua_setfield(lua, -2, "time_remaining");
417 if (data.action == ACTION_OLD_HOSTNAME && hostname)
419 lua_pushstring(lua, hostname);
420 lua_setfield(lua, -2, "old_hostname");
423 if (!is6 || data.hwaddr_len != 0)
425 lua_pushstring(lua, daemon->dhcp_buff);
426 lua_setfield(lua, -2, "mac_address");
429 lua_pushstring(lua, daemon->addrbuff);
430 lua_setfield(lua, -2, "ip_address");
432 lua_call(lua, 2, 0); /* pass 2 values, expect 0 */
435 #endif
437 /* no script, just lua */
438 if (!daemon->lease_change_command)
439 continue;
441 /* possible fork errors are all temporary resource problems */
442 while ((pid = fork()) == -1 && (errno == EAGAIN || errno == ENOMEM))
443 sleep(2);
445 if (pid == -1)
446 continue;
448 /* wait for child to complete */
449 if (pid != 0)
451 /* reap our children's children, if necessary */
452 while (1)
454 int status;
455 pid_t rc = wait(&status);
457 if (rc == pid)
459 /* On error send event back to main process for logging */
460 if (WIFSIGNALED(status))
461 send_event(event_fd, EVENT_KILLED, WTERMSIG(status), NULL);
462 else if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
463 send_event(event_fd, EVENT_EXITED, WEXITSTATUS(status), NULL);
464 break;
467 if (rc == -1 && errno != EINTR)
468 break;
471 continue;
474 if (data.action != ACTION_TFTP)
476 #ifdef HAVE_DHCP6
477 if (is6)
479 my_setenv("DNSMASQ_IAID", daemon->dhcp_buff3, &err);
480 my_setenv("DNSMASQ_SERVER_DUID", daemon->dhcp_packet.iov_base, &err);
481 if (data.hwaddr_len != 0)
482 my_setenv("DNSMASQ_MAC", daemon->dhcp_buff, &err);
484 #endif
486 if (!is6 && data.clid_len != 0)
487 my_setenv("DNSMASQ_CLIENT_ID", daemon->packet, &err);
489 if (strlen(data.interface) != 0)
490 my_setenv("DNSMASQ_INTERFACE", data.interface, &err);
492 #ifdef HAVE_BROKEN_RTC
493 sprintf(daemon->dhcp_buff2, "%u", data.length);
494 my_setenv("DNSMASQ_LEASE_LENGTH", daemon->dhcp_buff2, &err);
495 #else
496 sprintf(daemon->dhcp_buff2, "%lu", (unsigned long)data.expires);
497 my_setenv("DNSMASQ_LEASE_EXPIRES", daemon->dhcp_buff2, &err);
498 #endif
500 if (domain)
501 my_setenv("DNSMASQ_DOMAIN", domain, &err);
503 end = extradata + data.ed_len;
504 buf = extradata;
506 if (!is6)
507 buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS", &err);
508 #ifdef HAVE_DHCP6
509 else
511 if (data.vendorclass_count != 0)
513 buf = grab_extradata(buf, end, "DNSMASQ_VENDOR_CLASS_ID", &err);
514 for (i = 0; i < data.vendorclass_count - 1; i++)
516 sprintf(daemon->dhcp_buff2, "DNSMASQ_VENDOR_CLASS%i", i);
517 buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
521 #endif
523 buf = grab_extradata(buf, end, "DNSMASQ_SUPPLIED_HOSTNAME", &err);
525 if (!is6)
527 buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_OUI", &err);
528 buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_SERIAL", &err);
529 buf = grab_extradata(buf, end, "DNSMASQ_CPEWAN_CLASS", &err);
530 buf = grab_extradata(buf, end, "DNSMASQ_CIRCUIT_ID", &err);
531 buf = grab_extradata(buf, end, "DNSMASQ_SUBSCRIBER_ID", &err);
532 buf = grab_extradata(buf, end, "DNSMASQ_REMOTE_ID", &err);
535 buf = grab_extradata(buf, end, "DNSMASQ_TAGS", &err);
537 if (is6)
538 buf = grab_extradata(buf, end, "DNSMASQ_RELAY_ADDRESS", &err);
539 else if (data.giaddr.s_addr != 0)
540 my_setenv("DNSMASQ_RELAY_ADDRESS", inet_ntoa(data.giaddr), &err);
542 for (i = 0; buf; i++)
544 sprintf(daemon->dhcp_buff2, "DNSMASQ_USER_CLASS%i", i);
545 buf = grab_extradata(buf, end, daemon->dhcp_buff2, &err);
548 if (data.action != ACTION_DEL && data.remaining_time != 0)
550 sprintf(daemon->dhcp_buff2, "%u", data.remaining_time);
551 my_setenv("DNSMASQ_TIME_REMAINING", daemon->dhcp_buff2, &err);
554 if (data.action == ACTION_OLD_HOSTNAME && hostname)
556 my_setenv("DNSMASQ_OLD_HOSTNAME", hostname, &err);
557 hostname = NULL;
561 if (option_bool(OPT_LOG_OPTS))
562 my_setenv("DNSMASQ_LOG_DHCP", "1", &err);
564 /* we need to have the event_fd around if exec fails */
565 if ((i = fcntl(event_fd, F_GETFD)) != -1)
566 fcntl(event_fd, F_SETFD, i | FD_CLOEXEC);
567 close(pipefd[0]);
569 p = strrchr(daemon->lease_change_command, '/');
570 if (err == 0)
572 execl(daemon->lease_change_command,
573 p ? p+1 : daemon->lease_change_command,
574 action_str, is6 ? daemon->packet : daemon->dhcp_buff,
575 daemon->addrbuff, hostname, (char*)NULL);
576 err = errno;
578 /* failed, send event so the main process logs the problem */
579 send_event(event_fd, EVENT_EXEC_ERR, err, NULL);
580 _exit(0);
584 static void my_setenv(const char *name, const char *value, int *error)
586 if (*error == 0 && setenv(name, value, 1) != 0)
587 *error = errno;
590 static unsigned char *grab_extradata(unsigned char *buf, unsigned char *end, char *env, int *err)
592 unsigned char *next;
594 if (!buf || (buf == end))
595 return NULL;
597 for (next = buf; *next != 0; next++)
598 if (next == end)
599 return NULL;
601 if (next != buf)
603 char *p;
604 /* No "=" in value */
605 if ((p = strchr((char *)buf, '=')))
606 *p = 0;
607 my_setenv(env, (char *)buf, err);
610 return next + 1;
613 #ifdef HAVE_LUASCRIPT
614 static unsigned char *grab_extradata_lua(unsigned char *buf, unsigned char *end, char *field)
616 unsigned char *next;
618 if (!buf || (buf == end))
619 return NULL;
621 for (next = buf; *next != 0; next++)
622 if (next == end)
623 return NULL;
625 if (next != buf)
627 lua_pushstring(lua, (char *)buf);
628 lua_setfield(lua, -2, field);
631 return next + 1;
633 #endif
635 static void buff_alloc(size_t size)
637 if (size > buf_size)
639 struct script_data *new;
641 /* start with reasonable size, will almost never need extending. */
642 if (size < sizeof(struct script_data) + 200)
643 size = sizeof(struct script_data) + 200;
645 if (!(new = whine_malloc(size)))
646 return;
647 if (buf)
648 free(buf);
649 buf = new;
650 buf_size = size;
654 /* pack up lease data into a buffer */
655 void queue_script(int action, struct dhcp_lease *lease, char *hostname, time_t now)
657 unsigned char *p;
658 unsigned int hostname_len = 0, clid_len = 0, ed_len = 0;
659 int fd = daemon->dhcpfd;
660 #ifdef HAVE_DHCP6
661 if (!daemon->dhcp)
662 fd = daemon->dhcp6fd;
663 #endif
665 /* no script */
666 if (daemon->helperfd == -1)
667 return;
669 if (lease->extradata)
670 ed_len = lease->extradata_len;
671 if (lease->clid)
672 clid_len = lease->clid_len;
673 if (hostname)
674 hostname_len = strlen(hostname) + 1;
676 buff_alloc(sizeof(struct script_data) + clid_len + ed_len + hostname_len);
678 buf->action = action;
679 buf->flags = lease->flags;
680 #ifdef HAVE_DHCP6
681 buf->vendorclass_count = lease->vendorclass_count;
682 buf->addr6 = lease->addr6;
683 buf->iaid = lease->iaid;
684 #endif
685 buf->hwaddr_len = lease->hwaddr_len;
686 buf->hwaddr_type = lease->hwaddr_type;
687 buf->clid_len = clid_len;
688 buf->ed_len = ed_len;
689 buf->hostname_len = hostname_len;
690 buf->addr = lease->addr;
691 buf->giaddr = lease->giaddr;
692 memcpy(buf->hwaddr, lease->hwaddr, DHCP_CHADDR_MAX);
693 if (!indextoname(fd, lease->last_interface, buf->interface))
694 buf->interface[0] = 0;
696 #ifdef HAVE_BROKEN_RTC
697 buf->length = lease->length;
698 #else
699 buf->expires = lease->expires;
700 #endif
702 if (lease->expires != 0)
703 buf->remaining_time = (unsigned int)difftime(lease->expires, now);
704 else
705 buf->remaining_time = 0;
707 p = (unsigned char *)(buf+1);
708 if (clid_len != 0)
710 memcpy(p, lease->clid, clid_len);
711 p += clid_len;
713 if (hostname_len != 0)
715 memcpy(p, hostname, hostname_len);
716 p += hostname_len;
718 if (ed_len != 0)
720 memcpy(p, lease->extradata, ed_len);
721 p += ed_len;
723 bytes_in_buf = p - (unsigned char *)buf;
726 #ifdef HAVE_TFTP
727 /* This nastily re-uses DHCP-fields for TFTP stuff */
728 void queue_tftp(off_t file_len, char *filename, union mysockaddr *peer)
730 unsigned int filename_len;
732 /* no script */
733 if (daemon->helperfd == -1)
734 return;
736 filename_len = strlen(filename) + 1;
737 buff_alloc(sizeof(struct script_data) + filename_len);
738 memset(buf, 0, sizeof(struct script_data));
740 buf->action = ACTION_TFTP;
741 buf->hostname_len = filename_len;
742 buf->iaid = file_len;
744 if ((buf->flags = peer->sa.sa_family) == AF_INET)
745 buf->addr = peer->in.sin_addr;
746 #ifdef HAVE_IPV6
747 else
748 buf->addr6 = peer->in6.sin6_addr;
749 #endif
751 memcpy((unsigned char *)(buf+1), filename, filename_len);
753 bytes_in_buf = sizeof(struct script_data) + filename_len;
755 #endif
757 int helper_buf_empty(void)
759 return bytes_in_buf == 0;
762 void helper_write(void)
764 ssize_t rc;
766 if (bytes_in_buf == 0)
767 return;
769 if ((rc = write(daemon->helperfd, buf, bytes_in_buf)) != -1)
771 if (bytes_in_buf != (size_t)rc)
772 memmove(buf, buf + rc, bytes_in_buf - rc);
773 bytes_in_buf -= rc;
775 else
777 if (errno == EAGAIN || errno == EINTR)
778 return;
779 bytes_in_buf = 0;
783 #endif