2 * Copyright (C) 2013 Felix Fietkau <nbd@openwrt.org>
3 * Copyright (C) 2013 John Crispin <blogic@openwrt.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License version 2.1
7 * as published by the Free Software Foundation
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
16 #include <libubox/avl.h>
17 #include <libubox/avl-cmp.h>
21 #include <sys/types.h>
30 #define O_PATH 010000000
34 __blobmsg_list_init(struct blobmsg_list
*list
, int offset
, int len
, blobmsg_list_cmp cmp
)
36 avl_init(&list
->avl
, avl_strcmp
, false, NULL
);
37 list
->node_offset
= offset
;
43 blobmsg_list_fill(struct blobmsg_list
*list
, void *data
, int len
, bool array
)
45 struct avl_tree
*tree
= &list
->avl
;
46 struct blobmsg_list_node
*node
;
47 struct blob_attr
*cur
;
52 __blob_for_each_attr(cur
, data
, rem
) {
53 if (!blobmsg_check_attr(cur
, !array
))
56 ptr
= calloc(1, list
->node_len
);
60 node
= (void *) ((char *)ptr
+ list
->node_offset
);
62 node
->avl
.key
= blobmsg_data(cur
);
64 node
->avl
.key
= blobmsg_name(cur
);
66 if (avl_insert(tree
, &node
->avl
)) {
78 blobmsg_list_move(struct blobmsg_list
*list
, struct blobmsg_list
*src
)
80 struct blobmsg_list_node
*node
, *tmp
;
83 avl_remove_all_elements(&src
->avl
, node
, avl
, tmp
) {
84 if (avl_insert(&list
->avl
, &node
->avl
)) {
85 ptr
= ((char *) node
- list
->node_offset
);
92 blobmsg_list_free(struct blobmsg_list
*list
)
94 struct blobmsg_list_node
*node
, *tmp
;
97 avl_remove_all_elements(&list
->avl
, node
, avl
, tmp
) {
98 ptr
= ((char *) node
- list
->node_offset
);
104 blobmsg_list_equal(struct blobmsg_list
*l1
, struct blobmsg_list
*l2
)
106 struct blobmsg_list_node
*n1
, *n2
;
107 int count
= l1
->avl
.count
;
109 if (count
!= l2
->avl
.count
)
112 n1
= avl_first_element(&l1
->avl
, n1
, avl
);
113 n2
= avl_first_element(&l2
->avl
, n2
, avl
);
115 while (count
-- > 0) {
118 len
= blob_len(n1
->data
);
119 if (len
!= blob_len(n2
->data
))
122 if (memcmp(n1
->data
, n2
->data
, len
) != 0)
125 if (l1
->cmp
&& !l1
->cmp(n1
, n2
))
131 n1
= avl_next_element(n1
, avl
);
132 n2
= avl_next_element(n2
, avl
);
138 char *get_active_console(char *out
, int len
)
140 char line
[CMDLINE_SIZE
+ 1];
141 int fd
= open("/sys/class/tty/console/active", O_RDONLY
);
147 r
= read(fd
, line
, sizeof(line
) - 1);
148 line
[CMDLINE_SIZE
] = '\0';
155 /* The active file is terminated by a newline which we need to strip */
156 char *newline
= strtok(line
, "\n");
158 if (newline
!= NULL
) {
159 strncpy(out
, newline
, len
);
166 char *get_cmdline_val_offset(const char *name
, char *out
, int len
, int offset
)
168 char line
[CMDLINE_SIZE
+ 1], *c
, *sptr
;
169 int i
, fd
= open("/proc/cmdline", O_RDONLY
);
170 ssize_t r
= read(fd
, line
, sizeof(line
) - 1);
178 for (i
= 0, c
= strtok_r(line
, " \t\n", &sptr
); c
;
179 c
= strtok_r(NULL
, " \t\n", &sptr
)) {
180 char *sep
= strchr(c
, '=');
184 ssize_t klen
= sep
- c
;
185 if (strncmp(name
, c
, klen
) || name
[klen
] != 0)
190 strncpy(out
, &sep
[1], len
);
198 int patch_fd(const char *device
, int fd
, int flags
)
203 device
= "/dev/null";
205 if (*device
!= '/') {
206 dfd
= open("/dev", O_PATH
|O_DIRECTORY
);
211 nfd
= openat(dfd
, device
, flags
);
215 nfd
= open(device
, flags
);
218 if (nfd
< 0 && strcmp(device
, "/dev/null"))
219 nfd
= open("/dev/null", flags
);
226 if (nfd
> STDERR_FILENO
)
229 return (fd
< 0) ? -1 : 0;
232 int patch_stdio(const char *device
)
235 const char *fdname
[3] = { "stdin", "stdout", "stderr" };
237 for (fd
= STDIN_FILENO
; fd
<= STDERR_FILENO
; fd
++) {
238 if (patch_fd(device
, fd
, fd
? O_WRONLY
: O_RDONLY
)) {
239 ERROR("Failed to redirect %s to %s: %m\n",