From eb6009a5ee97ae82f7576ed1c8ac4b18518d6131 Mon Sep 17 00:00:00 2001 From: "Nicholas J. Kain" Date: Fri, 12 Nov 2010 18:44:49 -0500 Subject: [PATCH] Make write() and sendto() properly handle short writes and errors in ndhc. Make ndhc write a pidfile. Clean up defines.h and split out ifchd and ndhc specifics. --- ifchd/{defines.h => ifchd-defines.h} | 12 ++++++---- ifchd/ifchd.c | 4 ++-- ifchd/linux.c | 4 ++-- ndhc/dhcpc.c | 17 +++++++++++-- ndhc/ndhc-defines.h | 11 +++++++++ ndhc/packet.c | 36 +++++++++++++++++++++++----- ndhc/script.c | 28 ++++++++++++---------- 7 files changed, 82 insertions(+), 30 deletions(-) rename ifchd/{defines.h => ifchd-defines.h} (63%) create mode 100644 ndhc/ndhc-defines.h diff --git a/ifchd/defines.h b/ifchd/ifchd-defines.h similarity index 63% rename from ifchd/defines.h rename to ifchd/ifchd-defines.h index 143651a..5c66ab0 100644 --- a/ifchd/defines.h +++ b/ifchd/ifchd-defines.h @@ -1,12 +1,14 @@ -#define MAX_PATH_LENGTH 1024 +#ifndef IFCHD_DEFINES_H_ +#define IFCHD_DEFINES_H_ + +#include "defines.h" + #define PID_FILE_DEFAULT "/var/run/ifchd.pid" #define IFCHD_VERSION "0.8" - #define COMM_SOCKET_PATH "ifchange" #define MAX_BUF 1024 -#define MAXLINE 1024 - #define SOCK_QUEUE 2 #define CONN_TIMEOUT 60 -#define LINUX 1 + +#endif /* IFCHD_DEFINES_H_ */ diff --git a/ifchd/ifchd.c b/ifchd/ifchd.c index 8e9b79d..4029a53 100644 --- a/ifchd/ifchd.c +++ b/ifchd/ifchd.c @@ -1,5 +1,5 @@ /* ifchd.c - interface change daemon - * Time-stamp: <2010-11-12 17:22:34 njk> + * Time-stamp: <2010-11-12 18:40:54 njk> * * (C) 2004-2010 Nicholas J. Kain * @@ -39,7 +39,7 @@ #define _GNU_SOURCE #include -#include "defines.h" +#include "ifchd-defines.h" #include "malloc.h" #include "log.h" #include "chroot.h" diff --git a/ifchd/linux.c b/ifchd/linux.c index 7ee7589..59f3045 100644 --- a/ifchd/linux.c +++ b/ifchd/linux.c @@ -1,5 +1,5 @@ /* linux.c - ifchd Linux-specific functions - * Time-stamp: <2010-11-12 14:29:32 njk> + * Time-stamp: <2010-11-12 18:41:15 njk> * * (C) 2004-2010 Nicholas J. Kain * @@ -37,7 +37,7 @@ #include -#include "defines.h" +#include "ifchd-defines.h" #include "log.h" #include "strlist.h" #include "ifproto.h" diff --git a/ndhc/dhcpc.c b/ndhc/dhcpc.c index c90af1c..54786ac 100644 --- a/ndhc/dhcpc.c +++ b/ndhc/dhcpc.c @@ -39,6 +39,7 @@ #include #include +#include "ndhc-defines.h" #include "dhcpd.h" #include "dhcpc.h" #include "options.h" @@ -50,6 +51,7 @@ #include "chroot.h" #include "cap.h" #include "strl.h" +#include "pidfile.h" #include "malloc.h" #define VERSION "1.0" @@ -456,7 +458,8 @@ static int do_work(void) int main(int argc, char **argv) { - char chroot_dir[255]; + char pidfile[MAX_PATH_LENGTH] = ""; + char chroot_dir[MAX_PATH_LENGTH] = PID_FILE_DEFAULT; int c, len; struct passwd *pwd; uid_t uid = 0; @@ -465,6 +468,7 @@ int main(int argc, char **argv) {"clientid", required_argument, 0, 'c'}, {"foreground", no_argument, 0, 'f'}, {"background", no_argument, 0, 'b'}, + {"pidfile", required_argument, 0, 'p'}, {"hostname", required_argument, 0, 'H'}, {"hostname", required_argument, 0, 'h'}, {"interface", required_argument, 0, 'i'}, @@ -481,7 +485,7 @@ int main(int argc, char **argv) /* get options */ while (1) { int option_index = 0; - c = getopt_long(argc, argv, "c:fbH:h:i:np:qr:u:C:v", arg_options, + c = getopt_long(argc, argv, "c:fbp:H:h:i:np:qr:u:C:v", arg_options, &option_index); if (c == -1) break; @@ -502,6 +506,9 @@ int main(int argc, char **argv) case 'b': client_config.background_if_no_lease = 1; break; + case 'p': + strlcpy(pidfile, optarg, MAX_PATH_LENGTH); + break; case 'h': case 'H': len = strlen(optarg) > 255 ? 255 : strlen(optarg); @@ -549,6 +556,12 @@ int main(int argc, char **argv) log_line("ndhc client " VERSION " started."); + if (file_exists(pidfile, "w") == -1) { + log_line("FATAL - cannot open pidfile for write!"); + exit(EXIT_FAILURE); + } + write_pid(pidfile); + if (read_interface(client_config.interface, &client_config.ifindex, NULL, client_config.arp) < 0) exit(EXIT_FAILURE); diff --git a/ndhc/ndhc-defines.h b/ndhc/ndhc-defines.h new file mode 100644 index 0000000..f585e0e --- /dev/null +++ b/ndhc/ndhc-defines.h @@ -0,0 +1,11 @@ +#ifndef NDHC_DEFINES_H_ +#define NDHC_DEFINES_H_ + +#include "defines.h" + +#define PID_FILE_DEFAULT "/var/run/ndhc.pid" +#define NDHC_VERSION "1.0" +#define MAX_BUF 1024 + +#endif /* NDHC_DEFINES_H_ */ + diff --git a/ndhc/packet.c b/ndhc/packet.c index 5ad1a49..486cdcb 100644 --- a/ndhc/packet.c +++ b/ndhc/packet.c @@ -149,11 +149,21 @@ int raw_packet(struct dhcpMessage *payload, uint32_t source_ip, packet.ip.ttl = IPDEFTTL; packet.ip.check = checksum(&(packet.ip), sizeof(packet.ip)); - result = sendto(fd, &packet, sizeof(struct udp_dhcp_packet), 0, - (struct sockaddr *)&dest, sizeof dest); - if (result <= 0) { - log_error("write on socket failed: %s", - strerror(errno)); + int remain = sizeof(struct udp_dhcp_packet); + int sent = 0; + while (1) { + result = sendto(fd, &packet + sent, remain, 0, + (struct sockaddr *)&dest, sizeof dest); + if (result == -1) { + if (errno == EINTR) + continue; + log_error("raw_packet: sendto failed: %s", strerror(errno)); + break; + } + remain =- result; + sent += result; + if (remain == 0) + break; } out_fd: close(fd); @@ -190,7 +200,21 @@ int kernel_packet(struct dhcpMessage *payload, uint32_t source_ip, if (connect(fd, (struct sockaddr *)&client, sizeof(struct sockaddr)) == -1) goto out_fd; - result = write(fd, payload, sizeof(struct dhcpMessage)); + int remain = sizeof(struct dhcpMessage); + int sent = 0; + while (1) { + result = write(fd, payload + sent, remain); + if (result == -1) { + if (errno == EINTR) + continue; + log_error("kernel_packet: write failed: %s", strerror(errno)); + break; + } + remain =- result; + sent += result; + if (remain == 0) + break; + } out_fd: close(fd); out: diff --git a/ndhc/script.c b/ndhc/script.c index 2c1e0fd..1a08237 100644 --- a/ndhc/script.c +++ b/ndhc/script.c @@ -144,21 +144,23 @@ static int open_ifch(void) { return sockfd; } -static void sockwrite(int fd, const void *buf, size_t count) +static void sockwrite(int fd, const char *buf, size_t count) { int ret; - - sockwrite_again: - ret = write(fd, buf, count); - if (ret == -1) { - if (errno == EAGAIN) - goto sockwrite_again; - log_error("error while writing to unix socket!"); - exit(EXIT_FAILURE); - } - if (ret < 0) ret = 0; - if ((unsigned int)ret < strlen(buf)) { - log_error("incomplete write!"); + int remain = count; + int sent = 0; + while (1) { + ret = write(fd, buf + sent, remain); + if (ret == -1) { + if (errno == EINTR) + continue; + log_error("sockwrite: write failed: %s", strerror(errno)); + break; + } + remain =- ret; + sent += ret; + if (remain == 0) + break; } log_line("writing: %s", (char *)buf); }