Created
October 25, 2014 23:42
-
-
Save juntalis/09e667ff5c0db6cd4790 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "common.h" | |
#include <sys/types.h> | |
#include <string.h> | |
#include <errno.h> | |
int execute(char cmd[]); | |
void print_help(void); | |
void daemonize(void); | |
void prepend(char* s, const char* t); | |
int save_pid(pid_t pid,const char *pid_file); | |
int is_running(const char *pid_file); | |
int can_write(const char *pid_file); | |
int main(int argc, char* argv[]) { | |
if (getuid() != 0) { | |
fprintf(stderr, "Only root can execute %s - exiting\n", argv[0]); | |
exit(1); | |
} | |
// Make sure we have args necessary. | |
if (argc != 2) { | |
print_help(); | |
exit(0); | |
} | |
// Make sure launcher isn't currently running | |
if(is_running(TEMPLOCK)) { | |
fprintf(stderr, "Server launcher is currently being ran.\n"); | |
} | |
// Begin actual work. | |
// Allocate memory for command parsing. | |
char * cmd = (char *)malloc((size_t)strlen(argv[1])); | |
strncpy(cmd, argv[1], strlen(argv[1])); | |
if(cmd == NULL) { | |
fprintf(stderr, "Error while allocating memory. :/\n"); | |
exit(1); | |
} | |
// Lowercase the cmd string for sanity. | |
int i; | |
for(i=0; cmd[i]; i++) | |
if(cmd[i]>='a' && cmd[i]<='z') cmd[i] -= 32; | |
if(strcmp(cmd, "START") == 0) { | |
if(!is_running(LOCKFILE)) { | |
fprintf(stderr, "Attempting to start service..\n"); | |
if(!can_write("/tmp")) { | |
fprintf(stderr, "Error: %s\nCannot write to server lock file!\nServer start unsuccessful.\n", strerror( errno )); | |
return 2; | |
} | |
if(!save_pid(getpid(), TEMPLOCK)) { | |
fprintf(stderr, "Error: %s\nCannot write to launcher lock file!\nServer start unsuccessful.\n", strerror( errno )); | |
return 2; | |
} | |
return execute("START"); | |
} else { | |
fprintf(stderr, "Minecraft server is already running!\n"); | |
} | |
} else if(strcmp(cmd, "STOP") == 0) { | |
if(is_running(LOCKFILE)) { | |
fprintf(stderr, "Attempting to stop service..\n"); | |
if(!can_write("/tmp")) { | |
fprintf(stderr, "Error: %s\nCannot write to server lock file!\nServer stop unsuccessful.\n", strerror( errno )); | |
return 2; | |
} | |
if(!save_pid(getpid(), TEMPLOCK)) { | |
fprintf(stderr, "Error: %s\nCannot write to launcher lock file!\nServer stop unsuccessful.\n", strerror( errno )); | |
return 2; | |
} | |
return execute("STOP"); | |
} else { | |
fprintf(stderr, "Minecraft server is not currently running!\n"); | |
} | |
} else if(strcmp(cmd, "RESTART") == 0) { | |
if(is_running(LOCKFILE)) { | |
fprintf(stderr, "Attempting to stop service..\n"); | |
if(!can_write("/tmp")) { | |
fprintf(stderr, "Error: %s\nCannot write to server lock file!\nServer restart unsuccessful.\n", strerror( errno )); | |
return 2; | |
} | |
if(!save_pid(getpid(), TEMPLOCK)) { | |
fprintf(stderr, "Error: %s\nCannot write to launcher lock file!\nServer restart unsuccessful.\n", strerror( errno )); | |
return 2; | |
} | |
return execute("RESTART"); | |
} else { | |
fprintf(stderr, "Minecraft server is not currently running!\n"); | |
} | |
} | |
return 0; | |
} | |
int execute(char cmd[]) { | |
pid_t pid; | |
if (setgid(NEEDED_GID) == -1) { | |
fprintf(stderr, "couldn't switch groupid - exiting\n"); | |
remove(TEMPLOCK); | |
exit(2); | |
} | |
if (setuid(NEEDED_UID) == -1) { | |
fprintf(stderr, "couldn't switch userid - exiting\n"); | |
remove(TEMPLOCK); | |
exit(2); | |
} | |
pid = fork(); | |
if (pid == 0) { | |
// Daemonize it. | |
daemonize(); | |
// Get PATH environment variable. | |
char *bufpwd, *pwdptr,*bufbin,*bufjar; | |
long size = (strlen(getenv("PATH\0")) + 5) * sizeof(char); | |
char *bufpath = (char*)malloc((size_t)size); | |
strncpy(bufpath, "PATH=", (size_t)5); | |
strncat(bufpath, getenv("PATH\0"), (size_t)size); | |
// Get current working directory. | |
size = pathconf(".", _PC_PATH_MAX); | |
if ((bufpwd = (char *)malloc((size_t)size + 8)) != NULL) { | |
pwdptr = getcwd(bufpwd, (size_t)size); | |
// Assemble paths to the various binaries. | |
strncat(bufpwd, "/bin", 4); | |
// mc-wrap | |
bufbin = (char *)malloc((size_t)size + 8); | |
if(bufbin == NULL) { | |
fprintf(stderr, "Error: Cant get current directory.\n"); | |
remove(TEMPLOCK); | |
exit(2); | |
} | |
strncpy(bufbin, bufpwd, (size_t)size); | |
strncat(bufbin, "/mc-wrap", 8); | |
// minecraft_mod.jar | |
bufjar = (char *)malloc((size_t)size + 18); | |
if(bufjar == NULL) { | |
fprintf(stderr, "Error: Cant get current directory.\n"); | |
remove(TEMPLOCK); | |
exit(2); | |
} | |
strncpy(bufjar, bufpwd, (size_t)size); | |
strncat(bufjar, "/minecraft_mod.jar", 18); | |
// Make sure we can move around. | |
if (chdir("/\0") != 0) { | |
fprintf(stderr, "Couldn't change working directory - Exiting\n"); | |
remove(TEMPLOCK); | |
exit(5); | |
} | |
if (chdir(bufpwd) != 0) { | |
fprintf(stderr, "Couldn't change working directory - Exiting\n"); | |
remove(TEMPLOCK); | |
exit(5); | |
} | |
// Add PWD to path for use with environment. | |
prepend(bufpwd, "PWD="); | |
} else { | |
fprintf(stderr, "Error: Cant get current directory.\n"); | |
remove(TEMPLOCK); | |
exit(2); | |
} | |
char *eenv[3]= {bufpath, bufpwd, NULL}; | |
char *args[6] = {bufbin,cmd,bufjar,INITIALHEAP,MAXHEAP,NULL}; | |
return execve(bufbin, args, eenv); | |
} else if (pid == -1) { | |
fprintf(stderr, "Error: Couldn't fork the wrapped process - Exiting\n"); | |
remove(TEMPLOCK); | |
exit(3); | |
} | |
/* parent */ | |
remove(TEMPLOCK); | |
return 0; | |
} | |
/* Prepends t into s. Assumes s has enough space allocated | |
** for the combined string. | |
*/ | |
void prepend(char* s, const char* t) { | |
size_t len = strlen(t); | |
size_t i; | |
memmove(s + len, s, len + strlen(s) + 1); | |
for (i = 0; i < len; ++i) { | |
s[i] = t[i]; | |
} | |
} | |
void print_help(void) { | |
fprintf(stdout, "Launches Minecraft Server Daemon\nlaunch [start|stop|restart]\n"); | |
} | |
void daemonize(void) { | |
int fd; | |
if (setsid() == -1) { | |
fprintf(stderr, "Couldn't create new process group - Exiting"); | |
exit(4); | |
} | |
if ((fd = open("/dev/null", O_RDWR, 0)) != -1) { | |
(void)dup2(fd, STDIN_FILENO); | |
(void)dup2(fd, STDOUT_FILENO); | |
(void)dup2(fd, STDERR_FILENO); | |
if (fd > STDERR_FILENO) | |
(void)close(fd); | |
} else { | |
fprintf(stderr, "Couldn't redirect stdout, stderr, stdin - proceeding nontheless\n"); | |
} | |
} | |
int save_pid(pid_t pid,const char *pid_file) { | |
FILE *fp; | |
if (!pid_file) | |
return 0; | |
if (!(fp = fopen(pid_file,"w"))) { | |
fprintf(stderr,"Could not open the pid file %s for writing\n",pid_file); | |
return 0; | |
} | |
fprintf(fp,"%ld\n",(long) pid); | |
if (fclose(fp) == -1) { | |
fprintf(stderr,"Could not close the pid file %s.\n",pid_file); | |
return 0; | |
} | |
return 1; | |
} | |
int is_running(const char *pid_file) { | |
if(access(pid_file, F_OK) == 0) { | |
return 1; | |
} | |
return 0; | |
} | |
int can_write(const char *pid_file) { | |
if(access(pid_file, W_OK) == 0) { | |
return 1; | |
} | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment