First commit
This commit is contained in:
36
src/log.c
Normal file
36
src/log.c
Normal file
@ -0,0 +1,36 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include "log.h"
|
||||
|
||||
void info(const char* msg, ...){
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
|
||||
printf(LOG_BOLD LOG_BLUE">>> "LOG_RESET LOG_BOLD);
|
||||
vprintf(msg, args);
|
||||
printf(LOG_RESET"\n");
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void error(const char* msg, ...){
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
|
||||
printf(LOG_BOLD LOG_RED">>> "LOG_RESET LOG_BOLD);
|
||||
vprintf(msg, args);
|
||||
printf(LOG_RESET"\n");
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void success(const char* msg, ...){
|
||||
va_list args;
|
||||
va_start(args, msg);
|
||||
|
||||
printf(LOG_BOLD LOG_GREEN">>> "LOG_RESET LOG_BOLD);
|
||||
vprintf(msg, args);
|
||||
printf(LOG_RESET"\n");
|
||||
|
||||
va_end(args);
|
||||
}
|
9
src/log.h
Normal file
9
src/log.h
Normal file
@ -0,0 +1,9 @@
|
||||
#define LOG_RED "\x1b[31m"
|
||||
#define LOG_BOLD "\x1b[1m"
|
||||
#define LOG_BLUE "\x1b[34m"
|
||||
#define LOG_GREEN "\x1b[32m"
|
||||
#define LOG_RESET "\x1b[0m"
|
||||
|
||||
void info(const char* msg, ...);
|
||||
void error(const char* msg, ...);
|
||||
void success(const char* msg, ...);
|
277
src/main.c
Normal file
277
src/main.c
Normal file
@ -0,0 +1,277 @@
|
||||
/*
|
||||
|
||||
* xcfg | simple xorg configuration tool
|
||||
* MatterLinux 2024 (https://matterlinux.xyz)
|
||||
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
*/
|
||||
|
||||
#include <sys/wait.h>
|
||||
#include <stdbool.h>
|
||||
#include <libintl.h>
|
||||
#include <locale.h>
|
||||
#include <limits.h>
|
||||
#include <curses.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <spawn.h>
|
||||
#include <stdio.h>
|
||||
#include <menu.h>
|
||||
#include "util.h"
|
||||
#include "log.h"
|
||||
|
||||
#define _(x) gettext(x)
|
||||
|
||||
int ask(char* text, ITEM** items, int sz) {
|
||||
attron(COLOR_PAIR(1) | A_BOLD);
|
||||
|
||||
mvprintw(1, 1, "%s", text);
|
||||
char line[strlen(text)+5];
|
||||
int i = 0;
|
||||
for (; i < strlen(text); i++){
|
||||
line[i] = '#';
|
||||
}
|
||||
line[i] = '\0';
|
||||
mvprintw(2, 1, "%s", line);
|
||||
|
||||
attroff(COLOR_PAIR(1) | A_BOLD);
|
||||
refresh();
|
||||
|
||||
WINDOW* swin = newwin(LINES-3, COLS-1, 3, 1);
|
||||
keypad(swin, TRUE);
|
||||
MENU* menu = new_menu((ITEM **)items);
|
||||
set_menu_win(menu, swin);
|
||||
set_menu_sub(menu, swin);
|
||||
set_menu_mark(menu, ">");
|
||||
|
||||
post_menu(menu);
|
||||
wrefresh(swin);
|
||||
|
||||
bool done = false;
|
||||
int indx = 0, c = 0;
|
||||
|
||||
while((c = wgetch(swin))){
|
||||
switch(c){
|
||||
case KEY_DOWN:
|
||||
if (indx != (sz+1))
|
||||
indx++;
|
||||
menu_driver(menu, REQ_DOWN_ITEM);
|
||||
break;
|
||||
case KEY_UP:
|
||||
if (indx != 0)
|
||||
indx--;
|
||||
menu_driver(menu, REQ_UP_ITEM);
|
||||
break;
|
||||
case '\n':
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
|
||||
wrefresh(swin);
|
||||
if(done)
|
||||
break;
|
||||
}
|
||||
|
||||
free_menu(menu);
|
||||
return indx;
|
||||
}
|
||||
|
||||
bool add_startx(){
|
||||
bool ret = false;
|
||||
|
||||
char* profile = ".bash_profile";
|
||||
char* shellenv = getenv("SHELL");
|
||||
if (NULL != shellenv && endswith(shellenv, "zsh"))
|
||||
profile = ".zshrc";
|
||||
|
||||
char profile_file[PATH_MAX];
|
||||
if(!joinhome(profile_file, profile)){
|
||||
error(_("Failed to get the home directory"));
|
||||
return ret;
|
||||
}
|
||||
|
||||
FILE* pf = fopen(profile_file, "r");
|
||||
if(NULL==pf){
|
||||
error(_("Failed to open %s for reading"), profile_file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
char* line = NULL, *all = NULL;
|
||||
int indx = 0;
|
||||
size_t sz, len;
|
||||
|
||||
while((sz = getline(&line, &len, pf)) != -1) {
|
||||
if(strcmp(line, "#auto-startx \n")==0){
|
||||
ret = true;
|
||||
goto END;
|
||||
}
|
||||
|
||||
if (NULL == all){
|
||||
all = malloc(sz);
|
||||
for(int i = 0; i < sz; i++){
|
||||
all[indx] = line[i];
|
||||
indx++;
|
||||
}
|
||||
}else {
|
||||
all = realloc(all, indx+sz);
|
||||
for(int i = 0; i < sz; i++){
|
||||
all[indx] = line[i];
|
||||
indx++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char* startx = AUTOSTARTX;
|
||||
all = realloc(all, indx+strlen(startx)+10);
|
||||
for(int i = 0; i < strlen(startx); i++){
|
||||
all[indx] = startx[i];
|
||||
indx++;
|
||||
}
|
||||
|
||||
fclose(pf);
|
||||
pf = fopen(profile_file, "w");
|
||||
if(NULL==pf){
|
||||
error(_("Failed to open %s for writing"), profile_file);
|
||||
goto END;
|
||||
}
|
||||
|
||||
all[indx] = '\0';
|
||||
if(fwrite(all, 1, indx, pf)<=0)
|
||||
error(_("Failed to write to %s"), profile_file);
|
||||
ret = true;
|
||||
|
||||
END:
|
||||
free(all);
|
||||
free(line);
|
||||
fclose(pf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv, char** envp){
|
||||
signal(SIGINT, SIG_IGN);
|
||||
setlocale(LC_ALL, "");
|
||||
textdomain("mp");
|
||||
|
||||
struct Desktop desktops[] = {
|
||||
{
|
||||
.name="XFCE4",
|
||||
.desc="Lightweight desktop environment for UNIX-like operating systems",
|
||||
.pkg="xfce4",
|
||||
.cmd="startxfce4",
|
||||
},
|
||||
{
|
||||
.name="bspwm",
|
||||
.desc="Tiling window manager based on binary space partitioning",
|
||||
.pkg="bspwm",
|
||||
.cmd="bspwm"
|
||||
}
|
||||
};
|
||||
|
||||
char* mpi_path = check_path("mp-install");
|
||||
if(NULL==mpi_path){
|
||||
error(_("mp is not installed!"));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
free(mpi_path);
|
||||
|
||||
char* doas_path = check_path("doas");
|
||||
if(NULL==doas_path) {
|
||||
doas_path = check_path("sudo");
|
||||
if(NULL==doas_path){
|
||||
error(_("Install doas or sudo to use this script"));
|
||||
free(mpi_path);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
initscr();
|
||||
cbreak();
|
||||
noecho();
|
||||
keypad(stdscr, TRUE);
|
||||
init_pair(1, COLOR_BLUE, COLOR_BLUE);
|
||||
|
||||
int sz = sizeof(desktops)/sizeof(struct Desktop);
|
||||
ITEM** items = (ITEM **)malloc(sizeof(ITEM *)*(sz+1));
|
||||
|
||||
for(int i = 0; i < sz; i++)
|
||||
items[i] = new_item(desktops[i].name, desktops[i].desc);
|
||||
|
||||
int indx = ask(_("Choose a desktop enviroment"), items, sz);
|
||||
for (int i = 0; i < sz; i++)
|
||||
free_item(items[i]);
|
||||
free(items);
|
||||
clear();
|
||||
|
||||
char* yn[] = {_("Yes"), _("No")};
|
||||
sz = sizeof(yn)/sizeof(char*);
|
||||
items = (ITEM **)malloc(sizeof(ITEM *)*(sz+1));
|
||||
|
||||
for(int i = 0; i < sz; i++)
|
||||
items[i] = new_item(yn[i], "");
|
||||
|
||||
bool autox = ask(_("Add auto-startx to shell configuration?"), items, sz) == 0;
|
||||
for (int i = 0; i < sz; i++)
|
||||
free_item(items[i]);
|
||||
free(items);
|
||||
clear();
|
||||
|
||||
clear();
|
||||
endwin();
|
||||
|
||||
if(autox && !add_startx())
|
||||
goto FAIL;
|
||||
|
||||
info(_("Installing %s"), desktops[indx].name, mpi_path);
|
||||
char* args[] = {
|
||||
doas_path, "mp-install", desktops[indx].pkg, NULL
|
||||
};
|
||||
|
||||
pid_t pid;
|
||||
|
||||
if(posix_spawn(&pid, doas_path, NULL, NULL, args, envp) != 0) {
|
||||
error(_("Installation failed"));
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
int status;
|
||||
waitpid(pid, &status, 0);
|
||||
|
||||
if(status!=0){
|
||||
error(_("Installation failed"));
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
char xinitrc[PATH_MAX];
|
||||
if(!joinhome(xinitrc, ".xinitrc")){
|
||||
error(_("Failed to get the home directory"));
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
FILE* xf = fopen(xinitrc, "w");
|
||||
if(fwrite(xinitrc, 1, strlen(desktops[indx].cmd), xf)<0){
|
||||
error(_("Failed to write to %s"), xinitrc);
|
||||
fclose(xf);
|
||||
goto FAIL;
|
||||
}
|
||||
|
||||
success(_("Configuration has been saved!"));
|
||||
fclose(xf);
|
||||
free(doas_path);
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
FAIL:
|
||||
free(doas_path);
|
||||
return EXIT_FAILURE;
|
||||
}
|
55
src/util.c
Normal file
55
src/util.c
Normal file
@ -0,0 +1,55 @@
|
||||
#include <stdbool.h>
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include "util.h"
|
||||
|
||||
bool joinhome(char* res, char* path){
|
||||
char* homedir = getenv("HOME");
|
||||
|
||||
if(NULL==homedir)
|
||||
return false;
|
||||
|
||||
snprintf(res, PATH_MAX, "%s/%s", homedir, path);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool exists(char* path){
|
||||
return access(path, F_OK)==0;
|
||||
}
|
||||
|
||||
bool endswith(const char *str, const char *suf){
|
||||
int strl = strlen(str);
|
||||
int sufl = strlen(suf);
|
||||
|
||||
if (sufl > strl)
|
||||
return false;
|
||||
|
||||
return strncmp(str + strl - sufl, suf, sufl) == 0;
|
||||
}
|
||||
|
||||
char* check_path(char* bin) {
|
||||
char* path = getenv("PATH");
|
||||
char* res = NULL;
|
||||
|
||||
if(NULL == path)
|
||||
return NULL;
|
||||
path = strdup(path);
|
||||
|
||||
char* p = strtok(path, ":");
|
||||
while(NULL != p) {
|
||||
char* fp = malloc(PATH_MAX);
|
||||
snprintf(fp, PATH_MAX, "%s/%s", p, bin);
|
||||
if(exists(fp)){
|
||||
res = fp;
|
||||
break;
|
||||
}
|
||||
p = strtok(NULL, ":");
|
||||
}
|
||||
|
||||
free(path);
|
||||
return res;
|
||||
}
|
13
src/util.h
Normal file
13
src/util.h
Normal file
@ -0,0 +1,13 @@
|
||||
#define AUTOSTARTX "\n#auto-startx \nif [ -z '$DISPLAY' ] && [ '$XDG_VTNR' = 1 ]; then\nexec startx\nfi\n"
|
||||
|
||||
struct Desktop {
|
||||
char* name;
|
||||
char* desc;
|
||||
char* pkg;
|
||||
char* cmd;
|
||||
};
|
||||
|
||||
bool exists(char*);
|
||||
char* check_path(char*);
|
||||
bool joinhome(char*, char*);
|
||||
bool endswith(const char*, const char*);
|
Reference in New Issue
Block a user