Skip to content

Instantly share code, notes, and snippets.

@juntalis
Created October 25, 2014 23:42
Show Gist options
  • Save juntalis/09e667ff5c0db6cd4790 to your computer and use it in GitHub Desktop.
Save juntalis/09e667ff5c0db6cd4790 to your computer and use it in GitHub Desktop.
#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