├── .gitignore ├── PKGBUILD ├── makefile ├── netctld.c ├── netctld.h ├── netctldcli.c ├── netctldlist.c ├── netmenu └── netmenu.service /.gitignore: -------------------------------------------------------------------------------- 1 | netctld 2 | netctldcli 3 | netctldlist 4 | .wifi-info 5 | *.swp 6 | -------------------------------------------------------------------------------- /PKGBUILD: -------------------------------------------------------------------------------- 1 | # Maintainer: Ted Meyer 2 | 3 | _pkgname=netmenu 4 | pkgname=${_pkgname} 5 | pkgver=2 6 | pkgrel=1 7 | pkgdesc='A wifi controller for dmenu' 8 | arch=('x86_64') 9 | url="https://github.com/tmathmeyer/${_pkgname}" 10 | license=('GPL') 11 | depends=(dmenu) 12 | makedepends=('git') 13 | optdepends=(systemd) 14 | provides=("${_pkgname}") 15 | conflicts=("${_pkgname}") 16 | source=("git://github.com/tmathmeyer/${_pkgname}.git") 17 | md5sums=('SKIP') 18 | 19 | pkgver() { 20 | cd "$srcdir/$_pkgname" 21 | git rev-list --count HEAD 22 | } 23 | 24 | build() { 25 | cd "$srcdir/$_pkgname" 26 | make 27 | } 28 | 29 | package() { 30 | installDir="$pkgdir/usr/bin" 31 | systemDir="$pkgdir/etc/systemd/system" 32 | install -dm755 "$systemDir" 33 | install -dm755 "$installDir" 34 | install -m755 "$srcdir/$_pkgname/netmenu.service" "$systemDir/netmenu.service" 35 | install -m755 "$srcdir/$_pkgname/netmenu" "$installDir/netmenu" 36 | install -m755 "$srcdir/$_pkgname/netctld" "$installDir/netctld" 37 | install -m755 "$srcdir/$_pkgname/netctldcli" "$installDir/netctldcli" 38 | install -m755 "$srcdir/$_pkgname/netctldlist" "$installDir/netctldlist" 39 | } 40 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -g -o netctld netctld.c 3 | gcc -g -o netctldcli netctldcli.c 4 | gcc -g -o netctldlist netctldlist.c 5 | -------------------------------------------------------------------------------- /netctld.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "netctld.h" 12 | 13 | // every 10 profiles requires about 400B. 14 | #define BUFFER_SIZE 2048 15 | 16 | 17 | int write_sysctl(char *buffer, char *profile); 18 | int write_chars_to_buffer(char *buffer, const char *src); 19 | int echo_socket(); 20 | char *generate_sysctl_stop(); 21 | char *generate_sysctl_start(char *profile_name); 22 | void chown_socket(void); 23 | 24 | void forkd() { 25 | pid_t pid = fork(); 26 | if (pid < 0) { 27 | perror("can't fork"); 28 | exit(EXIT_FAILURE); 29 | } 30 | if (pid > 0) { 31 | exit(EXIT_SUCCESS); 32 | } 33 | umask(0); 34 | pid_t sid = setsid(); 35 | if (sid < 0) { 36 | perror("can't set sid"); 37 | exit(EXIT_FAILURE); 38 | } 39 | 40 | if ((chdir("/")) < 0) { 41 | perror("cant chdir to /"); 42 | exit(EXIT_FAILURE); 43 | } 44 | close(STDIN_FILENO); 45 | close(STDOUT_FILENO); 46 | close(STDERR_FILENO); 47 | 48 | echo_socket(); 49 | } 50 | 51 | 52 | 53 | int main(int argc, char **argv) { 54 | int fork = 1; 55 | int verbose = 0; 56 | 57 | while(argc--) { 58 | if (!strncmp("--no-fork", argv[argc], 9)) { 59 | fork = 0; 60 | } 61 | } 62 | 63 | if (fork) { 64 | forkd(); 65 | } else { 66 | echo_socket(); 67 | } 68 | 69 | puts("finished"); 70 | return 0; 71 | } 72 | 73 | void chown_socket(void) { 74 | char syscall[100] = {0}; 75 | int pos = 0; 76 | 77 | pos += write_chars_to_buffer(syscall+pos, "chmod 777 " SOCK_PATH); 78 | system(syscall); 79 | } 80 | 81 | char *generate_sysctl_start(char *profile_name) { 82 | char *buffer = calloc(1, BUFFER_SIZE); 83 | int pos = 0; 84 | if (!buffer) { 85 | return NULL; 86 | } 87 | pos += write_chars_to_buffer(buffer+pos, "systemctl start "); 88 | pos += write_sysctl(buffer+pos, profile_name); 89 | buffer[pos] = '\0'; 90 | return buffer; 91 | } 92 | 93 | 94 | char *generate_sysctl_stop() { 95 | DIR *profile_dir = opendir("/etc/netctl/"); 96 | struct dirent *entries; 97 | char *buffer; 98 | int pos; 99 | if (!profile_dir) { 100 | perror("cannot open directory /etc/netctl/"); 101 | return NULL; 102 | } 103 | 104 | buffer = malloc(BUFFER_SIZE); 105 | if (!buffer) { 106 | fprintf(stderr, "cannot allocate %i bytes", BUFFER_SIZE); 107 | return NULL; 108 | } 109 | 110 | pos = write_chars_to_buffer(buffer, "systemctl stop "); 111 | while (entries = readdir(profile_dir)) { 112 | switch(entries->d_type) { // so what if it's not POSIX? 113 | case DT_REG: 114 | case DT_LNK: 115 | pos += write_sysctl(buffer+pos, entries->d_name); 116 | break; 117 | } 118 | } 119 | 120 | closedir(profile_dir); 121 | buffer[pos] = '\0'; 122 | 123 | return buffer; 124 | } 125 | 126 | char *get_list_of_interfaces() { 127 | DIR *profile_dir = opendir("/etc/netctl/"); 128 | struct dirent *entries; 129 | char *buffer = NULL; 130 | int pos = 0; 131 | int size = BUFFER_SIZE; 132 | 133 | if (!profile_dir) { 134 | perror("cannot open directory /etc/netctl/"); 135 | return NULL; 136 | } 137 | 138 | buffer = calloc(1, size); 139 | if (!buffer) { 140 | fprintf(stderr, "cannot allocate %i bytes", BUFFER_SIZE); 141 | return NULL; 142 | } 143 | 144 | rewinddir(profile_dir); 145 | while (entries = readdir(profile_dir)) { 146 | switch(entries->d_type) { // so what if it's not POSIX? 147 | case DT_REG: 148 | case DT_LNK: 149 | pos += write_chars_to_buffer(buffer+pos, entries->d_name); 150 | pos += write_chars_to_buffer(buffer+pos, "\n"); 151 | if (pos > size-15) { 152 | void *n = realloc(buffer, size*=2); 153 | if (n) { 154 | buffer = n; 155 | } else { 156 | perror("cannot allocate"); 157 | free(buffer); 158 | return NULL; 159 | } 160 | } 161 | break; 162 | } 163 | } 164 | 165 | closedir(profile_dir); 166 | buffer[pos] = '\0'; 167 | 168 | return buffer; 169 | 170 | } 171 | 172 | char *sanitize(char *profile) { 173 | char *newprof = calloc(1, BUFFER_SIZE), *prof=profile; 174 | int npl = 0; 175 | while(*prof) { 176 | switch(*prof) { 177 | case '-': 178 | newprof[npl++] = '\\'; 179 | newprof[npl++] = '\\'; 180 | newprof[npl++] = 'x'; 181 | newprof[npl++] = '2'; 182 | newprof[npl++] = 'd'; 183 | break; 184 | default: 185 | newprof[npl++] = *prof; 186 | break; 187 | } 188 | prof++; 189 | } 190 | newprof[npl] = '\0'; 191 | return newprof; 192 | } 193 | 194 | 195 | 196 | int write_sysctl(char *buffer, char *profile) { 197 | int place=0, sec=0; 198 | while(profile[sec]) { 199 | if (profile[sec] == ' ') { 200 | profile[sec] = '\0'; 201 | break; 202 | } 203 | sec++; 204 | } 205 | profile = sanitize(profile); 206 | place += write_chars_to_buffer(buffer+place, "netctl@"); 207 | place += write_chars_to_buffer(buffer+place, profile); 208 | place += write_chars_to_buffer(buffer+place, ".service "); 209 | free(profile); 210 | return place; 211 | } 212 | 213 | int write_chars_to_buffer(char *buffer, const char *data) { 214 | int count = 0; 215 | while(data[count]) { 216 | buffer[count] = data[count++]; 217 | } 218 | return count; 219 | } 220 | 221 | 222 | 223 | void list_to_socket(int socket) { 224 | 225 | char *interfaces = get_list_of_interfaces(); 226 | size_t i = strlen(interfaces); 227 | send(socket, (char *)&i, sizeof(size_t), 0); 228 | send(socket, interfaces, strlen(interfaces), 0); 229 | send(socket, "\0", 1, 0); 230 | free(interfaces); 231 | 232 | return; 233 | } 234 | 235 | void do_disconnect(int socket, char *interface) { 236 | char *stop_cmd = generate_sysctl_stop(); 237 | char *start_cmd = generate_sysctl_start(interface); 238 | 239 | if (!stop_cmd || !start_cmd) { 240 | send(socket, "error - could not allocate commands", 6, 0); 241 | if (stop_cmd) { 242 | free(stop_cmd); 243 | } 244 | if (start_cmd) { 245 | free(start_cmd); 246 | } 247 | } else { 248 | int stop_status = system(stop_cmd); 249 | int start_status; 250 | 251 | if (stop_status == 0) { 252 | start_status = system(start_cmd); 253 | 254 | if (start_status == 0) { 255 | send(socket, "success", 8, 0); 256 | } else { 257 | send(socket, "error - connection failed", 6, 0); 258 | } 259 | } else { 260 | send(socket, "error - disconnection failed", 6, 0); 261 | } 262 | free(stop_cmd); 263 | free(start_cmd); 264 | } 265 | 266 | return; 267 | } 268 | 269 | char *alloc_name(char *buffer){ 270 | int ctr = 0; 271 | while(buffer[ctr]!=' ' && buffer[ctr]!='\n' && buffer[ctr]!='\0') { 272 | ctr++; 273 | } 274 | char *result = malloc(ctr+1); 275 | memcpy(result, buffer, ctr); 276 | result[ctr] = '\0'; 277 | return result; 278 | } 279 | 280 | void sock_listener(int server_socket, struct sockaddr *remote) { 281 | int socket, status; 282 | char buffer[100], *req_iface; 283 | while(1) { 284 | if ((socket = accept(server_socket, remote, &status)) == -1) { 285 | exit(1); 286 | } 287 | memset(buffer, 0, 100); 288 | status = recv(socket, buffer, 100, 0); 289 | switch(buffer[0]){ 290 | case 'l': 291 | list_to_socket(socket); 292 | break; 293 | case 's': 294 | req_iface = alloc_name(buffer+2); 295 | do_disconnect(socket, req_iface); 296 | free(req_iface); 297 | break; 298 | } 299 | close(socket); 300 | } 301 | } 302 | 303 | 304 | 305 | int echo_socket() 306 | { 307 | int s, s2, t, len; 308 | struct sockaddr_un local, remote; 309 | char str[100], trash, *sysctl_stop, *sysctl_start; 310 | 311 | if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 312 | perror("socket cant be opened"); 313 | exit(1); 314 | } 315 | 316 | local.sun_family = AF_UNIX; 317 | strcpy(local.sun_path, SOCK_PATH); 318 | unlink(local.sun_path); 319 | len = strlen(local.sun_path) + sizeof(local.sun_family); 320 | if (bind(s, (struct sockaddr *)&local, len) == -1) { 321 | perror("socket cant be bound"); 322 | exit(1); 323 | } 324 | 325 | if (listen(s, 5) == -1) { 326 | perror("socket can't be listened to"); 327 | exit(1); 328 | } 329 | 330 | chown_socket(); 331 | 332 | sock_listener(s, (struct sockaddr *) &remote); 333 | 334 | return 0; 335 | } 336 | 337 | -------------------------------------------------------------------------------- /netctld.h: -------------------------------------------------------------------------------- 1 | #ifndef _NETCTL_D_H_ 2 | #define _NETCTL_D_H_ 3 | 4 | #define SOCK_PATH "/tmp/netctl.d.socket" 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /netctldcli.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "netctld.h" 11 | 12 | int main(void) 13 | { 14 | int s, t, len; 15 | struct sockaddr_un remote; 16 | char str[100]; 17 | 18 | if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 19 | perror("socket"); 20 | exit(1); 21 | } 22 | 23 | remote.sun_family = AF_UNIX; 24 | strcpy(remote.sun_path, SOCK_PATH); 25 | len = strlen(remote.sun_path) + sizeof(remote.sun_family); 26 | if (connect(s, (struct sockaddr *)&remote, len) == -1) { 27 | perror("connect"); 28 | exit(1); 29 | } 30 | 31 | printf("Connected ...\n"); 32 | fgets(str, 100, stdin); 33 | if (!strncmp(str, "+ new interface", 15)) { 34 | char *argv[] = { "urxvt", "-e", "sudo", "wifi-menu", 0 }; 35 | int status = execvp(argv[0], argv); 36 | printf("%i\n", status); 37 | if (status == -1) { 38 | printf("%s\n", strerror(errno)); 39 | } 40 | return status; 41 | } 42 | send(s, "s ", 2, 0); 43 | if (send(s, str, strlen(str), 0) == -1) { 44 | perror("send"); 45 | exit(1); 46 | } 47 | 48 | memset(str, 0, 100); 49 | recv(s, str, 100, 0); 50 | puts(str); 51 | 52 | close(s); 53 | 54 | return 0; 55 | } 56 | -------------------------------------------------------------------------------- /netctldlist.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "netctld.h" 11 | 12 | #define BUFFER 2048 13 | 14 | int main(void) 15 | { 16 | int s, t, len; 17 | struct sockaddr_un remote; 18 | 19 | if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) { 20 | perror("socket"); 21 | exit(1); 22 | } 23 | 24 | remote.sun_family = AF_UNIX; 25 | strcpy(remote.sun_path, SOCK_PATH); 26 | len = strlen(remote.sun_path) + sizeof(remote.sun_family); 27 | if (connect(s, (struct sockaddr *)&remote, len) == -1) { 28 | exit(1); 29 | } 30 | 31 | if (send(s, "list", 5, 0) == -1) { 32 | exit(1); 33 | } 34 | 35 | size_t size = 0; 36 | if ((t=recv(s, (char *)&size, sizeof(size_t), 0)) > 0) { 37 | char *str = malloc(size+2); 38 | if ((t=recv(s, str, size, 0)) > 0) { 39 | str[t] = '\0'; 40 | printf(str); 41 | } 42 | free(str); 43 | printf("\n+ new interface"); 44 | } 45 | 46 | 47 | close(s); 48 | 49 | return 0; 50 | } 51 | -------------------------------------------------------------------------------- /netmenu: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | netctldlist > .wifi-info 2>/dev/null 4 | 5 | CONNECT=$(exec dmenu $@ < .wifi-info) 6 | 7 | if [ -n "$CONNECT" ]; then 8 | echo $CONNECT | netctldcli 9 | fi 10 | -------------------------------------------------------------------------------- /netmenu.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=A daemon for managing the wifi 3 | 4 | [Service] 5 | ExecStart=/usr/bin/netctld --no-fork 6 | 7 | [Install] 8 | WantedBy=multi-user.target 9 | --------------------------------------------------------------------------------