int lxc_netdev_delete_by_index(int ifindex) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct link_req *link_req; int err; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; link_req->ifinfomsg.ifi_index = ifindex; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; nlmsg->nlmsghdr.nlmsg_type = RTM_DELLINK; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
static int ip_addr_add(int family, int ifindex, void *addr, void *bcast, void *acast, int prefix) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct ip_req *ip_req; int addrlen; int err; addrlen = family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr); err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; ip_req = (struct ip_req *)nlmsg; ip_req->nlmsg.nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); ip_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; ip_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWADDR; ip_req->ifa.ifa_prefixlen = prefix; ip_req->ifa.ifa_index = ifindex; ip_req->ifa.ifa_family = family; ip_req->ifa.ifa_scope = 0; err = -EINVAL; if (nla_put_buffer(nlmsg, IFA_LOCAL, addr, addrlen)) goto out; if (nla_put_buffer(nlmsg, IFA_ADDRESS, addr, addrlen)) goto out; if (nla_put_buffer(nlmsg, IFA_BROADCAST, bcast, addrlen)) goto out; /* TODO : multicast, anycast with ipv6 */ err = -EPROTONOSUPPORT; if (family == AF_INET6 && (memcmp(bcast, &in6addr_any, sizeof(in6addr_any)) || memcmp(acast, &in6addr_any, sizeof(in6addr_any)))) goto out; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
extern int genetlink_open(struct genl_handler *handler, const char *family) { int ret; handler->family = genetlink_resolve_family(family); if (handler->family < 0) return handler->family; ret = netlink_open(&handler->nlh, NETLINK_GENERIC); return ret; }
static int ip_gateway_add(int family, int ifindex, void *gw) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct rt_req *rt_req; int addrlen; int err; addrlen = family == AF_INET ? sizeof(struct in_addr) : sizeof(struct in6_addr); err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; rt_req = (struct rt_req *)nlmsg; rt_req->nlmsg.nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); rt_req->nlmsg.nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL; rt_req->nlmsg.nlmsghdr.nlmsg_type = RTM_NEWROUTE; rt_req->rt.rtm_family = family; rt_req->rt.rtm_table = RT_TABLE_MAIN; rt_req->rt.rtm_scope = RT_SCOPE_UNIVERSE; rt_req->rt.rtm_protocol = RTPROT_BOOT; rt_req->rt.rtm_type = RTN_UNICAST; /* "default" destination */ rt_req->rt.rtm_dst_len = 0; err = -EINVAL; if (nla_put_buffer(nlmsg, RTA_GATEWAY, gw, addrlen)) goto out; /* Adding the interface index enables the use of link-local * addresses for the gateway */ if (nla_put_u32(nlmsg, RTA_OIF, ifindex)) goto out; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
int lxc_device_rename(const char *oldname, const char *newname) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct link_req *link_req; int index, len, err = -1; if (netlink_open(&nlh, NETLINK_ROUTE)) return -1; len = strlen(oldname); if (len == 1 || len > IFNAMSIZ) goto out; len = strlen(newname); if (len == 1 || len > IFNAMSIZ) goto out; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; index = if_nametoindex(oldname); if (!index) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; link_req->ifinfomsg.ifi_index = index; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_ACK|NLM_F_REQUEST; nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; if (nla_put_string(nlmsg, IFLA_IFNAME, newname)) goto out; if (netlink_transaction(&nlh, nlmsg, answer)) goto out; err = 0; out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
static int netdev_set_flag(const char *name, int flag) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct link_req *link_req; int index, len, err; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -EINVAL; len = strlen(name); if (len == 1 || len >= IFNAMSIZ) goto out; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; err = -EINVAL; index = if_nametoindex(name); if (!index) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; link_req->ifinfomsg.ifi_index = index; link_req->ifinfomsg.ifi_change |= IFF_UP; link_req->ifinfomsg.ifi_flags |= flag; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(nlmsg); nlmsg_free(answer); return err; }
int lxc_netdev_move_by_index(int ifindex, pid_t pid, const char* ifname) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL; struct ifinfomsg *ifi; int err; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; nlmsg->nlmsghdr->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; nlmsg->nlmsghdr->nlmsg_type = RTM_NEWLINK; ifi = nlmsg_reserve(nlmsg, sizeof(struct ifinfomsg)); if (!ifi) goto out; ifi->ifi_family = AF_UNSPEC; ifi->ifi_index = ifindex; if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid)) goto out; if (ifname != NULL) { if (nla_put_string(nlmsg, IFLA_IFNAME, ifname)) goto out; } err = netlink_transaction(&nlh, nlmsg, nlmsg); out: netlink_close(&nlh); nlmsg_free(nlmsg); return err; }
int lxc_netdev_move(char *ifname, pid_t pid) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL; struct link_req *link_req; int err, index; index = if_nametoindex(ifname); if (!ifname) return -EINVAL; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; link_req->ifinfomsg.ifi_index = index; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; if (nla_put_u32(nlmsg, IFLA_NET_NS_PID, pid)) goto out; err = netlink_transaction(&nlh, nlmsg, nlmsg); out: netlink_close(&nlh); nlmsg_free(nlmsg); return err; }
extern int rtnetlink_open(struct rtnl_handler *handler) { return netlink_open(&handler->nlh, NETLINK_ROUTE); }
static int genetlink_resolve_family(const char *family) { struct nl_handler handler; struct nlattr *attr; struct genlmsg *request, *reply; struct genlmsghdr *genlmsghdr; int len, ret; request = genlmsg_alloc(GENLMSG_GOOD_SIZE); if (!request) return -ENOMEM; reply = genlmsg_alloc(GENLMSG_GOOD_SIZE); if (!reply) { genlmsg_free(request); return -ENOMEM; } request->nlmsghdr.nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN); request->nlmsghdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; request->nlmsghdr.nlmsg_type = GENL_ID_CTRL; genlmsghdr = NLMSG_DATA(&request->nlmsghdr); genlmsghdr->cmd = CTRL_CMD_GETFAMILY; ret = netlink_open(&handler, NETLINK_GENERIC); if (ret) goto out; ret = nla_put_string((struct nlmsg *)&request->nlmsghdr, CTRL_ATTR_FAMILY_NAME, family); if (ret) goto out_close; ret = netlink_transaction(&handler, (struct nlmsg *)&request->nlmsghdr, (struct nlmsg *)&reply->nlmsghdr); if (ret < 0) goto out_close; genlmsghdr = NLMSG_DATA(&reply->nlmsghdr); len = reply->nlmsghdr.nlmsg_len; ret = -ENOMSG; if (reply->nlmsghdr.nlmsg_type != GENL_ID_CTRL) goto out_close; if (genlmsghdr->cmd != CTRL_CMD_NEWFAMILY) goto out_close; ret = -EMSGSIZE; len -= NLMSG_LENGTH(GENL_HDRLEN); if (len < 0) goto out_close; attr = (struct nlattr *)GENLMSG_DATA(reply); attr = (struct nlattr *)((char *)attr + NLA_ALIGN(attr->nla_len)); ret = -ENOMSG; if (attr->nla_type != CTRL_ATTR_FAMILY_ID) goto out_close; ret = *(__u16 *) NLA_DATA(attr); out_close: netlink_close(&handler); out: genlmsg_free(request); genlmsg_free(reply); return ret; }
int scim_port_wake(scim_root_t _root) { int index; int netlink; int result = -1; char name[IFNAMSIZ]; scim_lane_t lane; scim_port_data_t port; if((netlink = netlink_open()) < 0) { fprintf(stderr, "%s: netlink_open: %m\n", __func__); return -1; } if(scim_port_list(port) < 0) { goto done; } for(scim_port_list_t list = port->list; **list; list++) { scim_port_item_t info = *list; snprintf(name, sizeof(name), "%s", info[_PORT_NAME]); if(strcmp(name, "lo") && strncmp(name + 3, "bone", 4) && strncmp(name + 3, "port", 4)) { continue; } if(!sscanf(info[_PORT_INDEX], "%d", &index)) { errno = EINVAL; fprintf(stderr, "%s: port->info[_PORT_INDEX]: %m\n", __func__); goto done; } if(name[2] && !strncmp(name + 3, "port", 4)) { if(isdigit(name[7])) { name[7] = '\0'; if(netlink_link_rename(netlink, name, index) < 0) { fprintf(stderr, "%s: netlink_link_rename %s to %s: %m\n", __func__, info[_PORT_NAME], name); goto done; } } for(lane = __lane; *lane->name && strncmp(lane->name, name, 3); lane++); if(*lane->name && lane->base) { uint32_t mask = ((uint32_t)0xffffffffU << lane->size) >> lane->size; uint32_t address = htonl(lane->base|(_root->task->cell->code + 1)); uint32_t broadcast = htonl(lane->base|mask); if(netlink_address_four_create(netlink, index, address, broadcast, lane->size, 0) < 0) { if(errno != EEXIST) { fprintf(stderr, "%s: netlink_address_four_create: %s, %08x: %m\n", __func__, name, address); goto done; } } } } netlink_link_change(netlink, index, IFF_UP, IFF_UP); }
int scim_port_make(scim_task_t _task) { int index; int netlink; int result = -1; char name[IFNAMSIZ]; unsigned char mac[6] = {}; scim_port_data_t port; scim_port_data_t link; scim_port_wipe(link); scim_port_head(link); if((netlink = netlink_open()) < 0) { return -1; } if(scim_port_list(port) < 0) { return -1; } mac[0] = 0x02; mac[5] = _task->cell->code + 1; for(scim_lane_t* lane = *_task->cell->lanes; *lane; lane++) { snprintf(name, sizeof(name), "%sbone", (*lane)->name); if(scim_port_pick(port, _PORT_NAME, name) < 0) { goto done; } sscanf(port->info[_PORT_INDEX], "%d", &index); if(_task->form == __form_cell) { snprintf(name, sizeof(name), "%sport%d", (*lane)->name, _task->cell->code); } else { snprintf(name, sizeof(name), "%sport", (*lane)->name); } if((netlink_macvlan_create(netlink, name, mac, index, MACVLAN_MODE_BRIDGE)) < 0 && errno != EEXIST) { fprintf(stderr, "%s: netlink_macvlan_create: %m\n", __func__); goto done; } if(scim_port_read(link, name) < 0) { goto done; } sscanf(link->info[_PORT_INDEX], "%d", &index); if(_task->form == __form_cell) { if(netlink_link_move(netlink, index, _task->stat->pawn) < 0) { fprintf(stderr, "%s: netlink_link_move: %s to %d: %m\n", __func__, name, _task->stat->pawn); } } } result = 0; done: close(netlink); return result; }
int lxc_veth_create(const char *name1, const char *name2) { struct nl_handler nlh; struct nlmsg *nlmsg = NULL, *answer = NULL; struct link_req *link_req; struct rtattr *nest1, *nest2, *nest3; int len, err; err = netlink_open(&nlh, NETLINK_ROUTE); if (err) return err; err = -EINVAL; len = strlen(name1); if (len == 1 || len >= IFNAMSIZ) goto out; len = strlen(name2); if (len == 1 || len >= IFNAMSIZ) goto out; err = -ENOMEM; nlmsg = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!nlmsg) goto out; answer = nlmsg_alloc(NLMSG_GOOD_SIZE); if (!answer) goto out; link_req = (struct link_req *)nlmsg; link_req->ifinfomsg.ifi_family = AF_UNSPEC; nlmsg->nlmsghdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); nlmsg->nlmsghdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE|NLM_F_EXCL|NLM_F_ACK; nlmsg->nlmsghdr.nlmsg_type = RTM_NEWLINK; err = -EINVAL; nest1 = nla_begin_nested(nlmsg, IFLA_LINKINFO); if (!nest1) goto out; if (nla_put_string(nlmsg, IFLA_INFO_KIND, "veth")) goto out; nest2 = nla_begin_nested(nlmsg, IFLA_INFO_DATA); if (!nest2) goto out; nest3 = nla_begin_nested(nlmsg, VETH_INFO_PEER); if (!nest3) goto out; nlmsg->nlmsghdr.nlmsg_len += sizeof(struct ifinfomsg); if (nla_put_string(nlmsg, IFLA_IFNAME, name2)) goto out; nla_end_nested(nlmsg, nest3); nla_end_nested(nlmsg, nest2); nla_end_nested(nlmsg, nest1); if (nla_put_string(nlmsg, IFLA_IFNAME, name1)) goto out; err = netlink_transaction(&nlh, nlmsg, answer); out: netlink_close(&nlh); nlmsg_free(answer); nlmsg_free(nlmsg); return err; }
static int netlink_receive(struct netlink_fd *fd, struct nlmsghdr *reply) { struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int got_reply = FALSE, len; char buf[16*1024]; iov.iov_base = buf; while (!got_reply) { int status; struct nlmsghdr *h; iov.iov_len = sizeof(buf); status = recvmsg(fd->fd, &msg, MSG_DONTWAIT); if (status < 0) { if (errno == EINTR) continue; if (errno == EAGAIN) return reply == NULL; fprintf(stderr, "Netlink overrun\n"); continue; } if (status == 0) { fprintf(stderr, "Netlink returned EOF\n"); return FALSE; } h = (struct nlmsghdr *) buf; while (NLMSG_OK(h, status)) { if (reply != NULL && h->nlmsg_seq == reply->nlmsg_seq) { len = h->nlmsg_len; if (len > reply->nlmsg_len) { fprintf(stderr, "Netlink message " "truncated\n"); len = reply->nlmsg_len; } memcpy(reply, h, len); got_reply = TRUE; } else if (h->nlmsg_type != NLMSG_DONE) { fprintf(stderr, "Unknown NLmsg: 0x%08x, len %d\n", h->nlmsg_type, h->nlmsg_len); } h = NLMSG_NEXT(h, status); } } return TRUE; } static int netlink_send(struct netlink_fd *fd, struct nlmsghdr *req) { struct sockaddr_nl nladdr; struct iovec iov = { .iov_base = (void*) req, .iov_len = req->nlmsg_len }; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; int status; memset(&nladdr, 0, sizeof(nladdr)); nladdr.nl_family = AF_NETLINK; req->nlmsg_seq = ++fd->seq; status = sendmsg(fd->fd, &msg, 0); if (status < 0) { fprintf(stderr, "Cannot talk to rtnetlink\n"); return FALSE; } return TRUE; } static int netlink_talk(struct nlmsghdr *req, size_t replysize, struct nlmsghdr *reply) { struct netlink_fd fd; int ret = FALSE; if (!netlink_open(&fd)) return FALSE; if (reply == NULL) req->nlmsg_flags |= NLM_F_ACK; if (!netlink_send(&fd, req)) goto out; if (reply != NULL) { reply->nlmsg_len = replysize; ret = netlink_receive(&fd, reply); } else { ret = TRUE; } out: netlink_close(&fd); return ret; } int netlink_route_get(struct sockaddr *dst, u_int16_t *mtu, char *ifname) { struct { struct nlmsghdr n; union { struct rtmsg r; struct ifinfomsg i; }; char buf[1024]; } req; struct rtmsg *r = NLMSG_DATA(&req.n); struct rtattr *rta[RTA_MAX+1]; struct rtattr *rtax[RTAX_MAX+1]; struct rtattr *ifla[IFLA_MAX+1]; int index; memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETROUTE; req.r.rtm_family = dst->sa_family; netlink_add_rtaddr_l(&req.n, sizeof(req), RTA_DST, dst); req.r.rtm_dst_len = 32; if (!netlink_talk(&req.n, sizeof(req), &req.n)) return FALSE; netlink_parse_rtattr(rta, RTA_MAX, RTM_RTA(r), RTM_PAYLOAD(&req.n)); if (mtu != NULL) { if (rta[RTA_METRICS] == NULL) return FALSE; netlink_parse_rtattr(rtax, RTAX_MAX, RTA_DATA(rta[RTA_METRICS]), RTA_PAYLOAD(rta[RTA_METRICS])); if (rtax[RTAX_MTU] == NULL) return FALSE; *mtu = *(int*) RTA_DATA(rtax[RTAX_MTU]); } if (ifname != NULL) { if (rta[RTA_OIF] == NULL) return FALSE; index = *(int*) RTA_DATA(rta[RTA_OIF]); memset(&req, 0, sizeof(req)); req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); req.n.nlmsg_flags = NLM_F_REQUEST; req.n.nlmsg_type = RTM_GETLINK; req.i.ifi_index = index; if (!netlink_talk(&req.n, sizeof(req), &req.n)) return FALSE; netlink_parse_rtattr(ifla, IFLA_MAX, IFLA_RTA(r), IFLA_PAYLOAD(&req.n)); if (ifla[IFLA_IFNAME] == NULL) return FALSE; memcpy(ifname, RTA_DATA(ifla[IFLA_IFNAME]), RTA_PAYLOAD(ifla[IFLA_IFNAME])); } return TRUE; }
int ifplugd_main(int argc UNUSED_PARAM, char **argv) { int iface_status; int delay_time; const char *iface_status_str; struct pollfd netlink_pollfd[1]; unsigned opts; #if ENABLE_FEATURE_PIDFILE char *pidfile_name; pid_t pid_from_pidfile; #endif INIT_G(); opt_complementary = "t+:u+:d+"; opts = getopt32(argv, OPTION_STR, &G.iface, &G.script_name, &G.poll_time, &G.delay_up, &G.delay_down, &G.api_mode, &G.extra_arg); G.poll_time *= 1000; applet_name = xasprintf("ifplugd(%s)", G.iface); #if ENABLE_FEATURE_PIDFILE pidfile_name = xasprintf(_PATH_VARRUN"ifplugd.%s.pid", G.iface); pid_from_pidfile = read_pid(pidfile_name); if (opts & FLAG_KILL) { if (pid_from_pidfile > 0) kill(pid_from_pidfile, SIGQUIT); return EXIT_SUCCESS; } if (pid_from_pidfile > 0 && kill(pid_from_pidfile, 0) == 0) bb_error_msg_and_die("daemon already running"); #endif switch (G.api_mode[0]) { case API_AUTO: G.detect_link_func = detect_link_auto; break; case API_ETHTOOL: G.detect_link_func = detect_link_ethtool; break; case API_MII: G.detect_link_func = detect_link_mii; break; case API_PRIVATE: G.detect_link_func = detect_link_priv; break; case API_WLAN: G.detect_link_func = detect_link_wlan; break; case API_IFF: G.detect_link_func = detect_link_iff; break; default: bb_error_msg_and_die("unknown API mode '%s'", G.api_mode); } if (!(opts & FLAG_NO_DAEMON)) bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), ioctl_fd); if (opts & FLAG_MONITOR) { xmove_fd(netlink_open(), netlink_fd); } write_pidfile(pidfile_name); /* this can't be moved before socket creation */ if (!(opts & FLAG_NO_SYSLOG)) { openlog(applet_name, 0, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } bb_signals(0 | (1 << SIGINT ) | (1 << SIGTERM) | (1 << SIGQUIT) | (1 << SIGHUP ) /* why we ignore it? */ /* | (1 << SIGCHLD) - run_script does not use it anymore */ , record_signo); bb_error_msg("started: %s", bb_banner); if (opts & FLAG_MONITOR) { struct ifreq ifrequest; set_ifreq_to_ifname(&ifrequest); G.iface_exists = (network_ioctl(SIOCGIFINDEX, &ifrequest, NULL) == 0); } if (G.iface_exists) maybe_up_new_iface(); iface_status = detect_link(); if (iface_status == IFSTATUS_ERR) goto exiting; iface_status_str = strstatus(iface_status); if (opts & FLAG_MONITOR) { bb_error_msg("interface %s", G.iface_exists ? "exists" : "doesn't exist, waiting"); } /* else we assume it always exists, but don't mislead user * by potentially lying that it really exists */ if (G.iface_exists) { bb_error_msg("link is %s", iface_status_str); } if ((!(opts & FLAG_NO_STARTUP) && iface_status == IFSTATUS_UP ) || (opts & FLAG_INITIAL_DOWN) ) { if (run_script(iface_status_str) != 0) goto exiting; } /* Main loop */ netlink_pollfd[0].fd = netlink_fd; netlink_pollfd[0].events = POLLIN; delay_time = 0; while (1) { int iface_status_old; int iface_exists_old; switch (bb_got_signal) { case SIGINT: case SIGTERM: bb_got_signal = 0; goto cleanup; case SIGQUIT: bb_got_signal = 0; goto exiting; default: bb_got_signal = 0; break; } if (poll(netlink_pollfd, (opts & FLAG_MONITOR) ? 1 : 0, G.poll_time ) < 0 ) { if (errno == EINTR) continue; bb_perror_msg("poll"); goto exiting; } iface_status_old = iface_status; iface_exists_old = G.iface_exists; if ((opts & FLAG_MONITOR) && (netlink_pollfd[0].revents & POLLIN) ) { G.iface_exists = check_existence_through_netlink(); if (G.iface_exists < 0) /* error */ goto exiting; if (iface_exists_old != G.iface_exists) { bb_error_msg("interface %sappeared", G.iface_exists ? "" : "dis"); if (G.iface_exists) maybe_up_new_iface(); } } /* note: if !G.iface_exists, returns DOWN */ iface_status = detect_link(); if (iface_status == IFSTATUS_ERR) { if (!(opts & FLAG_MONITOR)) goto exiting; iface_status = IFSTATUS_DOWN; } iface_status_str = strstatus(iface_status); if (iface_status_old != iface_status) { bb_error_msg("link is %s", iface_status_str); if (delay_time) { /* link restored its old status before * we run script. don't run the script: */ delay_time = 0; } else { delay_time = monotonic_sec(); if (iface_status == IFSTATUS_UP) delay_time += G.delay_up; if (iface_status == IFSTATUS_DOWN) delay_time += G.delay_down; if (delay_time == 0) delay_time++; } } if (delay_time && (int)(monotonic_sec() - delay_time) >= 0) { delay_time = 0; if (run_script(iface_status_str) != 0) goto exiting; } } /* while (1) */ cleanup: if (!(opts & FLAG_NO_SHUTDOWN) && (iface_status == IFSTATUS_UP || (iface_status == IFSTATUS_DOWN && delay_time) ) ) { setenv(IFPLUGD_ENV_PREVIOUS, strstatus(iface_status), 1); setenv(IFPLUGD_ENV_CURRENT, strstatus(-1), 1); run_script("down\0up"); /* reusing string */ } exiting: remove_pidfile(pidfile_name); bb_error_msg_and_die("exiting"); }