Changing language to go
It is being changed to go in order to practice the language before I start another project.stable
parent
a8677c97c9
commit
2a4c78c152
|
|
@ -1,6 +1,3 @@
|
|||
# ---> Build
|
||||
build/*
|
||||
|
||||
# ---> Vim
|
||||
# Swap
|
||||
[._]*.s[a-v][a-z]
|
||||
|
|
@ -22,57 +19,4 @@ tags
|
|||
# Persistent undo
|
||||
[._]*.un~
|
||||
|
||||
# ---> C
|
||||
# Prerequisites
|
||||
*.d
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Linker output
|
||||
*.ilk
|
||||
*.map
|
||||
*.exp
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
||||
*.idb
|
||||
*.pdb
|
||||
|
||||
# Kernel Module Compile Results
|
||||
*.mod*
|
||||
*.cmd
|
||||
.tmp_versions/
|
||||
modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.10)
|
||||
project(rhosts VERSION 0.0.0 LANGUAGES C)
|
||||
message(" Project Binary dir: '${PROJECT_SOURCE_DIR}'")
|
||||
include_directories(${PROJECT_SOURCE_DIR})
|
||||
add_executable(rhosts src/rhosts.c src/download.c)
|
||||
target_link_libraries(rhosts curl)
|
||||
target_include_directories(rhosts PUBLIC "${PROJECT_BINARY_DIR}")
|
||||
configure_file(src/rhostsConfig.h.in config.h)
|
||||
set(CMAKE_INSTALL_PREFIX "/usr/local")
|
||||
install(TARGETS rhosts DESTINATION bin)
|
||||
install(FILES "${PROJECT_SOURCE_DIR}/src/systemd/rhosts.service"
|
||||
DESTINATION rhosts/systemd)
|
||||
install(FILES "${PROJECT_SOURCE_DIR}/src/systemd/rhosts.timer"
|
||||
DESTINATION rhosts/systemd)
|
||||
install(FILES "${PROJECT_SOURCE_DIR}/src/systemd/rhosts.path"
|
||||
DESTINATION rhosts/systemd)
|
||||
218
src/download.c
218
src/download.c
|
|
@ -1,218 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 Justin Reichardt
|
||||
*
|
||||
* This file is part of rhosts.
|
||||
*
|
||||
* rhosts 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.
|
||||
*
|
||||
* rhosts 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 rhosts. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef DOWNLOAD_HEADER
|
||||
#include "download.h"
|
||||
#endif
|
||||
|
||||
int clean_download();
|
||||
int skip_to_next_line(FILE **fp);
|
||||
|
||||
int download_entries(struct entry **entries){
|
||||
int i = (*entries)[0].entrytype;
|
||||
int rc = 0;
|
||||
FILE *tmpf;
|
||||
tmpf = fopen(TMPLOCATION,"a");
|
||||
if (tmpf == NULL){
|
||||
return 1;
|
||||
}
|
||||
FILE *tmpdf;
|
||||
tmpdf = fopen(TMPDOWNLOADLOCATION,"w+");
|
||||
if (tmpdf == NULL){
|
||||
printf("Failed to open %s\n",TMPDOWNLOADLOCATION);
|
||||
fclose(tmpf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
for (;i >0 ; i--){
|
||||
if ((*entries)[i].entrytype == CONTENTTYPE_DOWNLOAD){
|
||||
printf("Download: %s\n",(*entries)[i].entry);
|
||||
rc = fprintf(tmpf, "# rhosts download - %s", \
|
||||
(*entries)[i].entry);
|
||||
fflush(tmpf);
|
||||
if (rc == EOF){
|
||||
printf("Failed to write to %s\n", \
|
||||
TMPLOCATION);
|
||||
fclose(tmpdf);
|
||||
fclose(tmpf);
|
||||
return 1;
|
||||
}
|
||||
download_libcurl((*entries)[i].entry);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(tmpf);
|
||||
fclose(tmpdf);
|
||||
remove(TMPDOWNLOADLOCATION);
|
||||
return 0;
|
||||
}
|
||||
int download_libcurl(char *e){
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
curl = curl_easy_init();
|
||||
if(curl){
|
||||
// Add the url
|
||||
curl_easy_setopt(curl, CURLOPT_URL, e);
|
||||
// Skip cert check
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
// Ignore if cert has a different HostName
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
// Send what is recieved to function
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, parse_download);
|
||||
|
||||
// Download the file
|
||||
res = curl_easy_perform(curl);
|
||||
if(res != CURLE_OK){
|
||||
printf("Failed to download the file: %d\n", res);
|
||||
fflush(stdin);
|
||||
copy_old_download(e);
|
||||
return 1;
|
||||
}
|
||||
clean_download();
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
curl_global_cleanup();
|
||||
remove(TMPDOWNLOADLOCATION);
|
||||
|
||||
return 0;
|
||||
}
|
||||
int parse_download(char *buff, size_t size, size_t nmemb){
|
||||
FILE *tmpdf;
|
||||
int i=0;
|
||||
int rc=0;
|
||||
tmpdf = fopen(TMPDOWNLOADLOCATION, "a");
|
||||
for(i=0;i<nmemb;i++){
|
||||
rc = fputc(buff[i], tmpdf);
|
||||
if(rc == EOF)
|
||||
break;
|
||||
rc = i +1;
|
||||
}
|
||||
fclose(tmpdf);
|
||||
return nmemb;
|
||||
}
|
||||
int copy_old_download(char *url){
|
||||
FILE *hostsf;
|
||||
FILE *tmpf;
|
||||
hostsf = fopen(HOSTSLOCATION, "r");
|
||||
if (hostsf == NULL){return 1;}
|
||||
tmpf = fopen(TMPLOCATION,"a");
|
||||
if (tmpf == NULL){
|
||||
fclose(hostsf);
|
||||
return 1;
|
||||
}
|
||||
char buff[MAXSTRSIZE] = "";
|
||||
char search[MAXSTRSIZE] = "# rhosts download - ";
|
||||
strncat(search,url,MAXSTRSIZE - 21);
|
||||
char c = '\0';
|
||||
int b =0;
|
||||
|
||||
do{
|
||||
b = fgetc(hostsf);
|
||||
c = (char)b;
|
||||
while(c != '\n' && b != EOF && strlen(buff) < MAXSTRSIZE){
|
||||
strncat(buff, &c, 1);
|
||||
b = fgetc(hostsf);
|
||||
c = (char)b;
|
||||
}
|
||||
strncat(buff, &c, 1);
|
||||
if(strncmp(buff,search, strlen(search)) == 0){
|
||||
printf("Found a local match for %s\n",url);
|
||||
b = EOF;
|
||||
}
|
||||
buff[0] = '\0';
|
||||
}while(b !=EOF);
|
||||
do{
|
||||
do{
|
||||
b = fgetc(hostsf);
|
||||
c = (char)b;
|
||||
if (b != EOF)
|
||||
strncat(buff, &c, 1);
|
||||
} while(c != '\n' && b != EOF && strlen(buff) < MAXSTRSIZE);
|
||||
if(strncmp(buff,"# rhosts", 8) != 0){
|
||||
fputs(buff, tmpf);
|
||||
}
|
||||
else
|
||||
b = EOF;
|
||||
buff[0] = '\0';
|
||||
}while(b !=EOF);
|
||||
|
||||
fclose(hostsf);
|
||||
fclose(tmpf);
|
||||
return 0;
|
||||
}
|
||||
int clean_download(){
|
||||
FILE *tmpdf;
|
||||
tmpdf = fopen(TMPDOWNLOADLOCATION, "r+");
|
||||
if (tmpdf == NULL){
|
||||
printf("Failed to open %s\n", TMPDOWNLOADLOCATION);
|
||||
return 1;
|
||||
}
|
||||
FILE *tmpf;
|
||||
tmpf = fopen(TMPLOCATION, "a");
|
||||
if (tmpf == NULL){
|
||||
printf("Failed to open %s\n", TMPLOCATION);
|
||||
return 1;
|
||||
}
|
||||
char c;
|
||||
int b;
|
||||
char buff[MAXSTRSIZE];
|
||||
int buffsize=1;
|
||||
buff[0] = '\0';
|
||||
|
||||
do{
|
||||
b = fgetc(tmpdf);
|
||||
c = (char)b;
|
||||
buffsize++;
|
||||
if (buffsize > MAXSTRSIZE){
|
||||
printf("String too long when cleaning download: %s\n",buff);
|
||||
return 1;
|
||||
}
|
||||
if (b!=EOF) // Later needs to check for NULL
|
||||
strncat(buff,&c,1);
|
||||
if (buffsize==2){
|
||||
if (buff[0]=='#' || buff[0]=='\n'){
|
||||
skip_to_next_line(&tmpdf);
|
||||
buff[0] = '\0';
|
||||
buffsize=1;
|
||||
}
|
||||
}
|
||||
if (c == '\n' || b == EOF){
|
||||
fputs(buff,tmpf);
|
||||
buff[0]='\0';
|
||||
buffsize=1;
|
||||
}
|
||||
}while (b!=EOF);
|
||||
fflush(tmpf);
|
||||
fclose(tmpf);
|
||||
fclose(tmpdf);
|
||||
return 0;
|
||||
}
|
||||
int skip_to_next_line(FILE **fp){
|
||||
char c;
|
||||
int b;
|
||||
do{
|
||||
b = fgetc(*fp);
|
||||
c = (char)b;
|
||||
}while(c != '\n' && b != EOF);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
module jbreich/rhosts
|
||||
|
||||
go 1.17
|
||||
226
src/rhosts.c
226
src/rhosts.c
|
|
@ -1,226 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 Justin Reichardt
|
||||
*
|
||||
* This file is part of rhosts.
|
||||
*
|
||||
* rhosts 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.
|
||||
*
|
||||
* rhosts 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 rhosts. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
/* rhosts - Program used to maintain a blocklist within a hostfile */
|
||||
#ifndef RHOSTS_HEADER
|
||||
#include "rhosts.h"
|
||||
#endif
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
struct entry *entries;
|
||||
int rc =0;
|
||||
|
||||
printf("version: %s\n",rhosts_VERSION);
|
||||
|
||||
rc = parse_config(&entries);
|
||||
if (rc != 0){
|
||||
printf("%d - parse_config failed",rc);
|
||||
return rc;
|
||||
}
|
||||
rc = preserve_static_entries();
|
||||
if (rc != 0){
|
||||
printf("%d - preserve_static_entries failed",rc);
|
||||
return rc;
|
||||
}
|
||||
rc = download_entries(&entries);
|
||||
if (rc != 0){
|
||||
printf("%d - download_entries failed",rc);
|
||||
return rc;
|
||||
}
|
||||
rc = add_site_entries(&entries);
|
||||
if (rc != 0){
|
||||
printf("%d - download_entries failed",rc);
|
||||
return rc;
|
||||
}
|
||||
rc = copy_tmp_to_hosts();
|
||||
if (rc != 0){
|
||||
printf("%d - failed to copy to hosts file",rc);
|
||||
return rc;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int parse_config(struct entry **entries){
|
||||
int rc=0;
|
||||
|
||||
FILE *configfile;
|
||||
configfile = fopen(CONFIGFILE, "r+");
|
||||
if (configfile == NULL){return 1;}
|
||||
|
||||
*entries = malloc(sizeof(struct entry));
|
||||
if (entries == NULL){return 1;}
|
||||
entries[0]->entrytype = 0;
|
||||
int *j = NULL; // A shorter reference to how many entries
|
||||
j = &(*entries)[0].entrytype;
|
||||
|
||||
char c='\0';
|
||||
int b=0;
|
||||
char buff[MAXSTRSIZE];
|
||||
buff[0]='\0';
|
||||
short int valtyp = CONTENTTYPE_BLANK;
|
||||
|
||||
// Loop through config file
|
||||
do{
|
||||
b = fgetc(configfile);
|
||||
c = (char)b;
|
||||
// Detect if a comment
|
||||
if (strncmp(buff, "#",(long unsigned int)1) == 0 && \
|
||||
valtyp == CONTENTTYPE_BLANK){
|
||||
while (c != '\n' && b != EOF){c =fgetc(configfile);}
|
||||
}
|
||||
// Detect end of value type string
|
||||
if (c == '=' && valtyp == CONTENTTYPE_BLANK){
|
||||
valtyp = determine_config_entry_value(buff);
|
||||
if (valtyp == CONTENTTYPE_ERROR){
|
||||
return 1;
|
||||
}
|
||||
buff[0]='\0';
|
||||
}
|
||||
|
||||
// Detect end of entry
|
||||
else if ((c == '\n' || b == EOF) \
|
||||
&& valtyp != CONTENTTYPE_BLANK){
|
||||
(*entries)[0].entrytype++;
|
||||
*entries = (struct entry *)realloc(*entries,\
|
||||
(*j + 1) * sizeof(struct entry));
|
||||
if (*entries == NULL){return 1;}
|
||||
j = &(*entries)[0].entrytype;
|
||||
(*entries)[*j].entrytype=valtyp;
|
||||
strcpy((*entries)[*j].entry,buff);
|
||||
buff[0] = '\0';
|
||||
valtyp = CONTENTTYPE_BLANK;
|
||||
}
|
||||
else if (c == '\n' || b == EOF){
|
||||
buff[0] = '\0';
|
||||
}
|
||||
else{
|
||||
strncat(buff, &c, 1);
|
||||
}
|
||||
}while (b != EOF);
|
||||
|
||||
rc = fclose(configfile);
|
||||
if (rc != 0){return 1;}
|
||||
return 0;
|
||||
}
|
||||
short int determine_config_entry_value(char *buff){
|
||||
if (strncmp(buff,"#", 1) == 0){return CONTENTTYPE_COMMENT;}
|
||||
else if (strcmp(buff,"site") == 0){return CONTENTTYPE_SITE;}
|
||||
else if (strcmp(buff,"download") == 0){return CONTENTTYPE_DOWNLOAD;}
|
||||
else {return CONTENTTYPE_ERROR;}
|
||||
}
|
||||
int preserve_static_entries(){
|
||||
FILE *hostsf;
|
||||
FILE *tmpf;
|
||||
hostsf = fopen(HOSTSLOCATION, "r");
|
||||
if (hostsf == NULL){return 1;}
|
||||
tmpf = fopen(TMPLOCATION,"w");
|
||||
if (tmpf == NULL){
|
||||
fclose(hostsf);
|
||||
return 1;
|
||||
}
|
||||
char buff[MAXSTRSIZE];
|
||||
char c = EOF;
|
||||
int b = 0;
|
||||
int rc = 0;
|
||||
|
||||
printf("Static hosts are:\n");
|
||||
do{
|
||||
b = fgetc(hostsf);
|
||||
c = (char)b;
|
||||
strncat(buff, &c, 1);
|
||||
if (strncmp(buff, "# rhosts begin", 14) == 0){b = EOF;}
|
||||
if (c == '\n'){
|
||||
rc = fputs(buff, tmpf);
|
||||
if (rc == EOF){
|
||||
fclose(hostsf);
|
||||
fclose(tmpf);
|
||||
return 1;
|
||||
}
|
||||
printf("%s",buff);
|
||||
buff[0] = '\0';
|
||||
}
|
||||
}while ( b != EOF);
|
||||
rc = fputs("# rhosts begin\n", tmpf);
|
||||
if (rc == EOF){
|
||||
fclose(hostsf);
|
||||
fclose(tmpf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
fclose(hostsf);
|
||||
fclose(tmpf);
|
||||
return 0;
|
||||
}
|
||||
int add_site_entries(struct entry **entries){
|
||||
int i = (*entries)[0].entrytype;
|
||||
int rc = 0;
|
||||
FILE *tmpf;
|
||||
tmpf = fopen(TMPLOCATION,"a");
|
||||
if (tmpf == NULL){
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
rc = fputs("# rhosts - static begin\n", tmpf);
|
||||
if (rc == EOF){
|
||||
printf("Failed to write to tmp file\n");
|
||||
fclose(tmpf);
|
||||
return 1;
|
||||
}
|
||||
for (;i >0 ; i--){
|
||||
if ((*entries)[i].entrytype == CONTENTTYPE_SITE){
|
||||
fprintf(tmpf, "0.0.0.0 %s\n:: %s\n", \
|
||||
(*entries)[i].entry, \
|
||||
(*entries)[i].entry);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
rc = fputs("# rhosts - static end\n# rhosts end\n", tmpf);
|
||||
if (rc == EOF){
|
||||
printf("Failed to write to tmp file\n");
|
||||
fclose(tmpf);
|
||||
return 1;
|
||||
}
|
||||
|
||||
fclose(tmpf);
|
||||
return 0;
|
||||
}
|
||||
int copy_tmp_to_hosts(){
|
||||
FILE *tmpf;
|
||||
tmpf = fopen(TMPLOCATION,"r");
|
||||
if (tmpf == NULL)
|
||||
return 1;
|
||||
FILE *hostsf;
|
||||
hostsf = fopen(HOSTSLOCATION, "w");
|
||||
if (hostsf == NULL){
|
||||
printf("Failed to open %s\n",HOSTSLOCATION);
|
||||
fclose(tmpf);
|
||||
return 1;
|
||||
}
|
||||
int b;
|
||||
|
||||
for(b = fgetc(tmpf);b != EOF;b = fgetc(tmpf)){
|
||||
fputc((char)b,hostsf);
|
||||
}
|
||||
remove(TMPLOCATION);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -18,15 +18,4 @@
|
|||
*/
|
||||
|
||||
|
||||
#ifndef RHOSTS_HEADER
|
||||
#include "rhosts.h"
|
||||
#endif
|
||||
#ifndef DOWNLOAD_HEADER
|
||||
#define DOWNLOAD_HEADER
|
||||
#include <curl/curl.h>
|
||||
|
||||
int download_entries(struct entry **entries);
|
||||
int download_libcurl(char *e);
|
||||
int parse_download(char *buff, size_t size, size_t nmemb);
|
||||
int copy_old_download(char *url);
|
||||
#endif
|
||||
/* rhosts - Program used to maintain a blocklist within a hostfile */
|
||||
69
src/rhosts.h
69
src/rhosts.h
|
|
@ -1,69 +0,0 @@
|
|||
/*
|
||||
* Copyright 2021 Justin Reichardt
|
||||
*
|
||||
* This file is part of rhosts.
|
||||
*
|
||||
* rhosts 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.
|
||||
*
|
||||
* rhosts 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 rhosts. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef RHOSTS_HEADER
|
||||
#define RHOSTS_HEADER
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef _WIN64
|
||||
#define TMPLOCATION "/tmp/rhosts"
|
||||
#define TMPDOWNLOADLOCATION "/tmp/rhostsdownload"
|
||||
#define HOSTSLOCATION "/Windows/System32/drivers/etc/hosts"
|
||||
#define CONFIGFILE "/ProgramData/rhosts/rhosts.cfg"
|
||||
#elif __APPLE__
|
||||
#define TMPLOCATION "/tmp/"
|
||||
#elif __linux__
|
||||
#define TMPLOCATION "/tmp/rhosts"
|
||||
#define TMPDOWNLOADLOCATION "/tmp/rhostsdownload"
|
||||
#define HOSTSLOCATION "/etc/hosts"
|
||||
#define CONFIGFILE "/etc/rhosts/rhosts.cfg"
|
||||
#else
|
||||
#endif
|
||||
|
||||
#define STRUCTS_HEADER
|
||||
#define MAXSTRSIZE 500
|
||||
// entry types
|
||||
#define CONTENTTYPE_ERROR 5
|
||||
#define CONTENTTYPE_BLANK 0
|
||||
#define CONTENTTYPE_SITE 1
|
||||
#define CONTENTTYPE_DOWNLOAD 2
|
||||
#define CONTENTTYPE_COMMENT 3
|
||||
|
||||
struct entry{
|
||||
int entrytype;
|
||||
char entry[MAXSTRSIZE];
|
||||
};
|
||||
|
||||
int parse_config(struct entry **entries);
|
||||
|
||||
short int determine_config_entry_value(char *buff);
|
||||
int preserve_static_entries();
|
||||
int add_site_entries(struct entry **entries);
|
||||
int copy_tmp_to_hosts();
|
||||
#endif
|
||||
#ifndef DOWNLOAD_HEADER
|
||||
#include "download.h"
|
||||
#endif
|
||||
|
|
@ -1 +0,0 @@
|
|||
#define rhosts_VERSION "@rhosts_VERSION@"
|
||||
Loading…
Reference in New Issue