Compare commits

...

9 Commits

Author SHA1 Message Date
randomuser 03717f37a9 add the two clause BSD license
I would usually license it under the GNU GPL v3 but because I'm
unsure as to what the licensing situation is when combining a part
of a program and extending it to make another.
2022-09-20 17:10:13 -05:00
randomuser 9afa755580 rename the bspc module the bspwm module 2022-09-20 17:05:23 -05:00
randomuser 8023a5ea94 clean out the residual cruft from bspc 2022-09-20 17:02:35 -05:00
randomuser 9c211f5139 remove buffer overflow vulnerability 2022-09-20 16:49:14 -05:00
randomuser 474ac61f6e when a desktop is focused but not occupied, include it in the display 2022-09-20 16:40:18 -05:00
randomuser c97943855f add a module system 2022-09-20 16:29:25 -05:00
randomuser f44a1c3ffe add scary warnings 2022-09-19 13:31:20 -05:00
randomuser a4ea977c68 fix bug 2022-09-19 13:29:32 -05:00
randomuser 454ac588d0 add debug build 2022-09-19 13:29:23 -05:00
9 changed files with 234 additions and 324 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
tags
bspc
tstatus

22
LICENSE Normal file
View File

@ -0,0 +1,22 @@
Copyright 2022 randomuser
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,5 +1,8 @@
bspc:
cc bspc.c -o bspc -lxcb -Wall -Wextra -std=c99
tstatus:
cc tstatus.c -o tstatus -lxcb -Wall -Wextra -std=c99
debug:
cc tstatus.c -o tstatus -lxcb -Wall -Wextra -std=c99 -ggdb
clean:
rm bspc
rm tstatus

4
README
View File

@ -0,0 +1,4 @@
tstatus
-------
simple modular status bar program

321
bspc.c
View File

@ -1,321 +0,0 @@
/* Copyright (c) 2012, Bastien Dejean
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#define RUNTIME_DIR_ENV "XDG_RUNTIME_DIR"
#define SOCKET_PATH_TPL "/tmp/bspwm%s_%i_%i-socket"
#define SOCKET_ENV_VAR "BSPWM_SOCKET"
#define FAILURE_MESSAGE "\x07"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <xcb/xcb.h>
#include <poll.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
/* prototypes */
void warn(char *fmt, ...);
void err(char *fmt, ...);
char *read_string(const char *file_path, size_t *tlen);
char *copy_string(char *str, size_t len);
char *mktempfifo(const char *template);
int asprintf(char **buf, const char *fmt, ...);
int vasprintf(char **buf, const char *fmt, va_list args);
bool is_hex_color(const char *color);
void warn(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
__attribute__((noreturn))
void err(char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
char *read_string(const char *file_path, size_t *tlen)
{
if (file_path == NULL) {
return NULL;
}
int fd = open(file_path, O_RDONLY);
if (fd == -1) {
perror("Read file: open");
return NULL;
}
char buf[BUFSIZ], *content = NULL;
size_t len = sizeof(buf);
if ((content = calloc(len, sizeof(char))) == NULL) {
perror("Read file: calloc");
goto end;
}
int nb;
*tlen = 0;
while (true) {
nb = read(fd, buf, sizeof(buf));
if (nb < 0) {
perror("Restore tree: read");
free(content);
content = NULL;
goto end;
} else if (nb == 0) {
break;
} else {
*tlen += nb;
if (*tlen > len) {
len *= 2;
char *rcontent = realloc(content, len * sizeof(char));
if (rcontent == NULL) {
perror("Read file: realloc");
free(content);
content = NULL;
goto end;
} else {
content = rcontent;
}
}
strncpy(content + (*tlen - nb), buf, nb);
}
}
end:
close(fd);
return content;
}
char *copy_string(char *str, size_t len)
{
char *cpy = calloc(1, ((len+1) * sizeof(char)));
if (cpy == NULL) {
perror("Copy string: callow");
return NULL;
}
strncpy(cpy, str, len);
cpy[len] = '\0';
return cpy;
}
char *mktempfifo(const char *template)
{
int tempfd;
char *runtime_dir = getenv(RUNTIME_DIR_ENV);
if (runtime_dir == NULL) {
runtime_dir = "/tmp";
}
char *fifo_path = malloc(strlen(runtime_dir)+1+strlen(template)+1);
if (fifo_path == NULL) {
return NULL;
}
sprintf(fifo_path, "%s/%s", runtime_dir, template);
if ((tempfd = mkstemp(fifo_path)) == -1) {
free(fifo_path);
return NULL;
}
close(tempfd);
unlink(fifo_path);
if (mkfifo(fifo_path, 0666) == -1) {
free(fifo_path);
return NULL;
}
return fifo_path;
}
int asprintf(char **buf, const char *fmt, ...)
{
int size = 0;
va_list args;
va_start(args, fmt);
size = vasprintf(buf, fmt, args);
va_end(args);
return size;
}
int vasprintf(char **buf, const char *fmt, va_list args)
{
va_list tmp;
va_copy(tmp, args);
int size = vsnprintf(NULL, 0, fmt, tmp);
va_end(tmp);
if (size < 0) {
return -1;
}
*buf = malloc(size + 1);
if (*buf == NULL) {
return -1;
}
size = vsprintf(*buf, fmt, args);
return size;
}
bool is_hex_color(const char *color)
{
if (color[0] != '#' || strlen(color) != 7) {
return false;
}
for (int i = 1; i < 7; i++) {
if (!isxdigit(color[i])) {
return false;
}
}
return true;
}
char *send_msg_to_bspwm(char *args[], int count)
{
int sock_fd;
struct sockaddr_un sock_address;
char msg[BUFSIZ];
static char rsp[BUFSIZ];
sock_address.sun_family = AF_UNIX;
char *sp;
if ((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
err("Failed to create the socket.\n");
}
sp = getenv(SOCKET_ENV_VAR);
if (sp != NULL) {
snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", sp);
} else {
char *host = NULL;
int dn = 0, sn = 0;
if (xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), SOCKET_PATH_TPL, host, dn, sn);
}
free(host);
}
if (connect(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) {
err("Failed to connect to the socket.\n");
}
int msg_len = 0;
for (int offset = 0, rem = sizeof(msg), n = 0; count > 0 && rem > 0; offset += n, rem -= n, count--, args++) {
n = snprintf(msg + offset, rem, "%s%c", *args, 0);
msg_len += n;
}
if (send(sock_fd, msg, msg_len, 0) == -1) {
err("Failed to send the data.\n");
}
int nb;
struct pollfd fds[] = {
{sock_fd, POLLIN, 0},
{STDOUT_FILENO, POLLHUP, 0},
};
while (poll(fds, 2, -1) > 0) {
if (fds[0].revents & POLLIN) {
if ((nb = recv(sock_fd, rsp, sizeof(rsp)-1, 0)) > 0) {
rsp[nb] = '\0';
return rsp;
} else {
break;
}
}
if (fds[1].revents & (POLLERR | POLLHUP)) {
break;
}
}
close(sock_fd);
return NULL;
}
int main(void) {
char finalbuffer[64], currentdesktop[2];
char *occupied[] = {"query", "-D", "-d", ".occupied", "--names"};
char *focused[] = {"query", "-D", "-d", ".focused", "--names"};
char *result;
char current;
int count = 5;
result = send_msg_to_bspwm(occupied, count);
if(!result) {
printf("error: sending message to bspwm failed!\n");
return 1;
}
memcpy(&finalbuffer, result, 64);
result = send_msg_to_bspwm(focused, count);
if(!result) {
printf("error: sending message to bspwm failed!\n");
return 1;
}
memcpy(&currentdesktop, result, 2);
*(currentdesktop + 1) = '\0';
result = finalbuffer;
for(int i = 0; i < 64; i++) {
current = *(finalbuffer + i);
if(current == '\0') break;
if(isdigit(current) && *currentdesktop == current)
*(finalbuffer + i + 1) = '<';
if(current == '\n')
current = ' ';
}
printf("%s", finalbuffer);
return 0;
}

139
bspwm.c Normal file
View File

@ -0,0 +1,139 @@
/* see bspc.h for copyright and distribution information */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdarg.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <xcb/xcb.h>
#include <poll.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <ctype.h>
#include "module.h"
#include "bspwm.h"
__attribute__((noreturn))
void err(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
char *send_msg_to_bspwm(char *args[], int count) {
int sock_fd;
struct sockaddr_un sock_address;
char msg[BUFSIZ];
static char rsp[BUFSIZ];
sock_address.sun_family = AF_UNIX;
char *sp;
if((sock_fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
err("Failed to create the socket.\n");
}
sp = getenv(SOCKET_ENV_VAR);
if(sp != NULL) {
snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), "%s", sp);
} else {
char *host = NULL;
int dn = 0, sn = 0;
if(xcb_parse_display(NULL, &host, &dn, &sn) != 0) {
snprintf(sock_address.sun_path, sizeof(sock_address.sun_path), SOCKET_PATH_TPL, host, dn, sn);
}
free(host);
}
if(connect(sock_fd, (struct sockaddr *) &sock_address, sizeof(sock_address)) == -1) {
err("Failed to connect to the socket.\n");
}
int msg_len = 0;
for(int offset = 0, rem = sizeof(msg), n = 0; count > 0 && rem > 0; offset += n, rem -= n, count--, args++) {
n = snprintf(msg + offset, rem, "%s%c", *args, 0);
msg_len += n;
}
if(send(sock_fd, msg, msg_len, 0) == -1) {
err("Failed to send the data.\n");
}
int nb;
struct pollfd fds[] = {
{sock_fd, POLLIN, 0},
{STDOUT_FILENO, POLLHUP, 0},
};
while(poll(fds, 2, -1) > 0) {
if(fds[0].revents & POLLIN) {
if((nb = recv(sock_fd, rsp, sizeof(rsp)-1, 0)) > 0) {
rsp[nb] = '\0';
return rsp;
} else {
break;
}
}
if(fds[1].revents & (POLLERR | POLLHUP)) {
break;
}
}
close(sock_fd);
return NULL;
}
int bspwm_update(struct module *module) {
char current[2];
char *occupied[] = {"query", "-D", "-d", ".occupied", "--names"};
char *focused[] = {"query", "-D", "-d", ".focused", "--names"};
char *result;
result = send_msg_to_bspwm(occupied, LENGTH(occupied));
if(!result) {
printf("error: sending message to bspwm failed!\n");
return 1;
}
memcpy(&module->buffer, result, MODULE_BUFFER_LEN);
result = send_msg_to_bspwm(focused, LENGTH(focused));
if(!result) {
printf("error: sending message to bspwm failed!\n");
return 1;
}
memcpy(&current, result, 2);
current[1] = '\0';
for(int i = 0; i < MODULE_BUFFER_LEN; i++) {
if(module->buffer[i] == '\0' && i) {
if(*current != '\0' && i <= MODULE_BUFFER_LEN - 2) {
module->buffer[i - 1] = ' ';
module->buffer[i] = *current;
module->buffer[i + 1] = '<';
module->buffer[i + 2] = '\0';
} else module->buffer[i - 1] = '\0';
break;
}
if(isdigit(module->buffer[i]) && *current == module->buffer[i]) {
if(i <= MODULE_BUFFER_LEN - 2) module->buffer[i + 1] = '<';
*current = '\0';
}
if(module->buffer[i] == '\n')
module->buffer[i] = ' ';
}
return 0;
}

36
bspwm.h Normal file
View File

@ -0,0 +1,36 @@
/* Copyright (c) 2012 Bastien Dejean
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* modifications made by randomuser for use in tstatus
*/
#define RUNTIME_DIR_ENV "XDG_RUNTIME_DIR"
#define SOCKET_PATH_TPL "/tmp/bspwm%s_%i_%i-socket"
#define SOCKET_ENV_VAR "BSPWM_SOCKET"
#define FAILURE_MESSAGE "\x07"
#define LENGTH(x) (sizeof(x) / sizeof(*x))
void err(char *fmt, ...);
char *send_msg_to_bspwm(char *args[], int count);
int bspwm_update(struct module *module);

12
module.h Normal file
View File

@ -0,0 +1,12 @@
/* see LICENSE file for details on license */
#ifndef TSTATUS_MODULE_H
#define MODULE_BUFFER_LEN 64
struct module {
int update; /* update interval in seconds */
int termcode; /* update termcode */
int (*updatecallback)(struct module *); /* update function */
char buffer[MODULE_BUFFER_LEN]; /* buffer for text */
};
#endif
#define TSTATUS_MODULE_H

14
tstatus.c Normal file
View File

@ -0,0 +1,14 @@
/* see LICENSE file for details on license */
#include "bspwm.c"
#include "module.h"
struct module table[] = {
{0, 10, bspwm_update, {'\0'}},
};
int main(void) {
table[0].updatecallback(&table[0]);
printf("%s\n", table[0].buffer);
return 0;
}