#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <mysql/mysql.h>
#include <errno.h>
#include <time.h>
#include <sys/wait.h>
#include <pwd.h>
#include <unistd.h>
#define MB_T_AUDIO 1
#define MB_T_DATA 2
#define MB_T_EMPTY 3
#define MAX_TITLE_SIZE 128
#define MAX_PASS_SIZE 1024
#define DEFAULT_MYSQL_USER "mediabase"
#define DEFAULT_MYSQL_PASS "mediabase"
#define DEFAULT_MYSQL_HOST "localhost"
#define DEFAULT_MYSQL_DB "mediabase"
#define DEFAULT_MOUNT_CMD "sudo /sbin/mount /cdrom"
#define DEFAULT_UNMOUNT_CMD "sudo /sbin/umount /cdrom"
#define DEFAULT_MOUNTDIR "/cdrom"
#define MAX_PATH_DEPTH 65535
#define INITIAL_BUFFER_ADD 4096
#define BUFFER_ADD 4096
char strTitle[MAX_TITLE_SIZE+2];
char strPass[MAX_PASS_SIZE];
char *pszPathBuffer = NULL;
size_t nPathBufferSize = 0;
size_t nMountPrefixLength;
unsigned long nTotalFiles;
unsigned long long nTotalSize;
my_ulonglong nMediaID = 0ULL;
char *pszSQLQuery = NULL;
size_t nSQLQueryBufferSize = 0;
MYSQL *pMYSQL = NULL;
int blnMediaMounted = 0;
int blnExiting = 0;
const char *pszHost = DEFAULT_MYSQL_HOST;
const char *pszUser = DEFAULT_MYSQL_USER;
const char *pszPass = DEFAULT_MYSQL_PASS;
const char *pszDB = DEFAULT_MYSQL_DB;
const char *pszMountMediaCommand = DEFAULT_MOUNT_CMD;
const char *pszUnmountMediaCommand = DEFAULT_UNMOUNT_CMD;
const char *pszMountDir = DEFAULT_MOUNTDIR;
char *pszEscapeBuffer1 = NULL;
size_t nEscapeBuffer1Size = 0;
char *pszEscapeBuffer2 = NULL;
size_t nEscapeBuffer2Size = 0;
void
ExecuteCommand(const char *pszCommand);
void
MountMedia()
{
printf("--> Mounting media ...\n");
ExecuteCommand(pszMountMediaCommand);
printf("--> Media mounted.\n");
blnMediaMounted = 1;
}
void
UnmountMedia()
{
printf("--> Unmounting media ...\n");
ExecuteCommand(pszUnmountMediaCommand);
printf("--> Media unmounted.\n");
blnMediaMounted = 0;
}
void
Exit(int nRet)
{
if (blnExiting)
return;
blnExiting = 1;
if (pMYSQL != NULL)
{
mysql_close(pMYSQL);
}
if (blnMediaMounted)
UnmountMedia();
exit(nRet);
}
void
ExecuteCommand(const char *pszCommand)
{
int nRet;
nRet = system(pszCommand);
if (nRet == -1)
{
fprintf(stderr,
"Cannot execute command \"%s\". "
"system() returned -1, error is %d (%s)\n",
pszCommand,
errno,
strerror(errno));
Exit(1);
}
if (WIFEXITED(nRet))
{
if (WEXITSTATUS(nRet) != 0)
{
fprintf(stderr,
"Cannot execute command \"%s\". "
"Command returned %d\n",
pszCommand,
(int)WEXITSTATUS(nRet));
Exit(1);
}
}
else if (WIFSIGNALED(nRet))
{
fprintf(stderr,
"Cannot execute command \"%s\". "
"Cammand was terminated because of signal %d\n",
pszCommand,
(int)WTERMSIG(nRet));
Exit(1);
}
else
{
fprintf(stderr,
"Cannot execute command \"%s\". "
"system() returned %d\n",
pszCommand,
nRet);
Exit(1);
}
}
void
ReadTitle()
{
char *pch;
printf("Title: ");
if (fgets(strTitle, sizeof(strTitle), stdin) == NULL)
{
printf("\n");
if (feof(stdin))
{
Exit(0);
}
fprintf(stderr, "Error occured while reading standard input.\n");
Exit(1);
}
else if (strTitle[0] == '\n')
{
Exit(0);
}
if ((pch = strchr(strTitle, '\n')) == NULL)
{
fprintf(stderr, "input line too long.\n");
Exit(1);
}
*pch = '\0';
}
void
AskForPassword()
{
char *pszPass;
pszPass = getpass("MySQL password: ");
strcpy(strPass, pszPass);
}
void
MaybeEnlargeBuffer(char ** ppBuffer,
size_t *pnBufferSize,
size_t nSizeRequired)
{
char *pNewBuffer;
size_t nNewBufferSize;
if (nSizeRequired <= *pnBufferSize)
return;
if (*pnBufferSize == 0 || *ppBuffer == NULL)
{
nNewBufferSize = nSizeRequired + INITIAL_BUFFER_ADD;
pNewBuffer = (char *)malloc(nNewBufferSize);
if (pNewBuffer == NULL)
{
fprintf(stderr,
"Cannot allocate %u bytes of memory.\n",
(unsigned int)nNewBufferSize);
Exit(0);
}
}
else
{
nNewBufferSize = nSizeRequired + BUFFER_ADD;
pNewBuffer = (char *)malloc(nNewBufferSize);
if (pNewBuffer == NULL)
{
fprintf(stderr,
"Cannot allocate %u bytes of memory.\n",
(unsigned int)nNewBufferSize);
Exit(0);
}
memcpy(pNewBuffer, *ppBuffer, *pnBufferSize);
free(*ppBuffer);
}
*pnBufferSize = nNewBufferSize;
*ppBuffer = pNewBuffer;
}
void
ScanDir(unsigned long nDepth)
{
DIR *pDir;
struct dirent *pDE;
size_t nCurrentPathLength;
struct stat st;
size_t nEscapedSize;
if (nDepth >= MAX_PATH_DEPTH)
{
fprintf(stderr,
"Max path depth of reached \"%u\"\n",
(unsigned int)MAX_PATH_DEPTH);
Exit(1);
}
nCurrentPathLength = strlen(pszPathBuffer);
pDir = opendir(pszPathBuffer);
if (pDir == NULL)
{
fprintf(stderr, "Cannot open \"%s\"\n", pszPathBuffer);
Exit(1);
}
if (pDir)
{
while ((pDE = readdir(pDir)) != NULL)
{
if (strcmp(pDE->d_name, ".") == 0)
continue;
if (strcmp(pDE->d_name, "..") == 0)
continue;
MaybeEnlargeBuffer(&pszPathBuffer,
&nPathBufferSize,
nCurrentPathLength + pDE->d_namlen + 1);
memcpy(pszPathBuffer + nCurrentPathLength, pDE->d_name, pDE->d_namlen);
pszPathBuffer[nCurrentPathLength + pDE->d_namlen] = 0;
if (lstat(pszPathBuffer, &st) != 0)
{
fprintf(stderr,
"Cannot stat() %s. Error is %d (%s)\n",
pszPathBuffer,
errno,
strerror(errno));
}
pszPathBuffer[nCurrentPathLength] = 0;
MaybeEnlargeBuffer(&pszEscapeBuffer1,
&nEscapeBuffer1Size,
(nCurrentPathLength - nMountPrefixLength)*2+1);
nEscapedSize = mysql_real_escape_string(
pMYSQL,
pszEscapeBuffer1,
pszPathBuffer + nMountPrefixLength,
nCurrentPathLength - nMountPrefixLength);
MaybeEnlargeBuffer(&pszEscapeBuffer2,
&nEscapeBuffer2Size,
pDE->d_namlen*2+1);
nEscapedSize += mysql_real_escape_string(
pMYSQL,
pszEscapeBuffer2,
pDE->d_name,
pDE->d_namlen);
MaybeEnlargeBuffer(&pszSQLQuery,
&nSQLQueryBufferSize,
nEscapedSize + 1024);
sprintf(pszSQLQuery,
"INSERT INTO mb_files "
"(mediaid,size,time,path,name) "
"VALUES (%u,%u,%u,'%s','%s%s')",
(unsigned int)nMediaID,
(unsigned int)((S_ISDIR(st.st_mode))?0:st.st_size),
(unsigned int)st.st_ctimespec.tv_sec,
pszEscapeBuffer1,
pszEscapeBuffer2,
(S_ISDIR(st.st_mode))?"/":"");
#ifdef DUMMY_SQL_QUERIES
printf("MySQL query \"%s\"\n", pszSQLQuery);
#else
if (mysql_query(pMYSQL, pszSQLQuery) != 0)
{
fprintf(stderr, "Failed to execute query \"%s\" Error: %s\n",
pszSQLQuery,
mysql_error(pMYSQL));
Exit(1);
}
#endif
memcpy(pszPathBuffer + nCurrentPathLength, pDE->d_name, pDE->d_namlen);
pszPathBuffer[nCurrentPathLength + pDE->d_namlen] = 0;
#ifdef PRINT_FILENAMES
printf("%s", pszPathBuffer + nMountPrefixLength);
#endif
nTotalFiles++;
if (S_ISDIR(st.st_mode))
{
#ifdef PRINT_FILENAMES
printf("/\n");
#else
printf("/");
#endif
fflush(stdout);
memcpy(pszPathBuffer + nCurrentPathLength + pDE->d_namlen, "/", 2);
ScanDir(nDepth + 1);
}
else
{
nTotalSize += st.st_size;
#ifdef PRINT_FILENAMES
printf("\n");
#else
printf(".");
#endif
fflush(stdout);
}
}
closedir(pDir);
}
}
void
Help(char *arg0)
{
char *pszExecutable;
pszExecutable = strrchr(arg0, '/');
if (pszExecutable == NULL)
{
pszExecutable = arg0;
}
else
{
pszExecutable++;
}
printf("Usage:\n");
printf("[<path_to>]%s [options]\n", pszExecutable);
printf(" Options can be:\n");
printf(" -h <mysql_host> - MySQL server host, default is \"%s\"\n", pszHost);
printf(" -u <mysql_user> - MySQL user, default is \"%s\"\n", pszUser);
printf(" -p [mysql_pass] - MySQL password, default is \"%s\"\n", pszPass);
printf(" -b <mysql_database> - MySQL database, default is \"%s\"\n", pszDB);
printf(" -m <mount_cmd> - command to mount media, default is \"%s\"\n", pszMountMediaCommand);
printf(" -n <unmount_cmd> - command to unmount, default is \"%s\"\n", pszUnmountMediaCommand);
printf(" -d <mount_dir> - where media is mounted, default is \"%s\"\n", pszMountDir);
Exit(0);
}
int
main(
int argc,
char ** argv
)
{
time_t timeAdded;
int i;
size_t nTitleSize;
printf("Adding media to MediaBase\n");
printf("=========================\n");
for (i = 1; i < argc ; i++)
{
if (strcmp(argv[i],"-h") == 0)
{
i++;
if (i < argc)
{
pszHost = argv[i];
}
else
{
fprintf(stderr,
"Missing parameter of -h option\n");
Help(argv[0]);
}
}
else if (strcmp(argv[i],"-u") == 0)
{
i++;
if (i < argc)
{
pszUnmountMediaCommand = argv[i];
}
else
{
fprintf(stderr,
"Missing parameter of -u option\n");
Help(argv[0]);
}
}
else if (strcmp(argv[i],"-p") == 0)
{
if (i+1 < argc && argv[i+1][0] != '-')
{
i++;
pszPass = argv[i];
}
else
{
AskForPassword();
pszPass = strPass;
}
}
else if (strcmp(argv[i],"-b") == 0)
{
i++;
if (i < argc)
{
pszDB = argv[i];
}
else
{
fprintf(stderr,
"Missing parameter of -b option\n");
Help(argv[0]);
}
}
else if (strcmp(argv[i],"-m") == 0)
{
i++;
if (i < argc)
{
pszMountMediaCommand = argv[i];
}
else
{
fprintf(stderr,
"Missing parameter of -m option\n");
Help(argv[0]);
}
}
else if (strcmp(argv[i],"-n") == 0)
{
i++;
if (i < argc)
{
pszUnmountMediaCommand = argv[i];
}
else
{
fprintf(stderr,
"Missing parameter of -n option\n");
Help(argv[0]);
}
}
else if (strcmp(argv[i],"-d") == 0)
{
i++;
if (i < argc)
{
pszMountDir = argv[i];
}
else
{
fprintf(stderr,
"Missing parameter of -d option\n");
Help(argv[0]);
}
}
else if (strcmp(argv[i],"-h") == 0)
{
Help(argv[0]);
}
else
{
fprintf(stderr,
"Unknown option \"%s\"\n",
argv[i]);
Help(argv[0]);
}
}
printf("NOTE: Currently audio media is not supported.\n");
MaybeEnlargeBuffer(&pszSQLQuery,
&nSQLQueryBufferSize,
MAX_TITLE_SIZE + 1024);
pMYSQL = mysql_init(NULL);
if (pMYSQL == NULL)
{
fprintf(stderr,
"Cannot create MYSQL object. Error is \"%s\"\n",
mysql_error(pMYSQL));
Exit(1);
}
if (mysql_real_connect(pMYSQL,
pszHost,
pszUser,
pszPass,
pszDB,
0,
NULL,
0) == NULL)
{
fprintf(stderr, "Failed to connect to database. Error: %s\n",
mysql_error(pMYSQL));
Exit(1);
}
nMountPrefixLength = strlen(pszMountDir);
MaybeEnlargeBuffer(&pszPathBuffer,
&nPathBufferSize,
nMountPrefixLength + 2);
memcpy(pszPathBuffer, pszMountDir, nMountPrefixLength);
Loop:
memcpy(pszPathBuffer + nMountPrefixLength, "/", 2);
printf("--> Please insert media and enter title.\n");
ReadTitle();
nTitleSize = strlen(strTitle);
MaybeEnlargeBuffer(&pszEscapeBuffer1,
&nEscapeBuffer1Size,
nTitleSize*2+1);
mysql_real_escape_string(pMYSQL,
pszEscapeBuffer1,
strTitle,
nTitleSize);
MountMedia();
nTotalFiles = 0UL;
nTotalSize = 0ULL;
printf("--> Processing media ...\n");
sprintf(pszSQLQuery,
"INSERT INTO mb_media (name,type,comment) VALUES ('%s',%u,'')",
pszEscapeBuffer1,
(unsigned int)MB_T_DATA);
#ifdef DUMMY_SQL_QUERIES
printf("MySQL query \"%s\"\n", pszSQLQuery);
#else
if (mysql_query(pMYSQL, pszSQLQuery) != 0)
{
fprintf(stderr, "Failed to execute query \"%s\" Error: %s\n",
pszSQLQuery,
mysql_error(pMYSQL));
Exit(1);
}
nMediaID = mysql_insert_id(pMYSQL);
if (nMediaID == 0ULL)
{
fprintf(stderr, "Invalid media ID 0 after media INSERT\n");
Exit(1);
}
#endif
ScanDir(0);
printf("\n");
timeAdded = time(NULL);
sprintf(pszSQLQuery,
"UPDATE mb_media SET added=%u, info1=%u, info2=%u WHERE mediaid = %u",
(unsigned int)timeAdded,
(unsigned int)nTotalFiles,
(unsigned int)nTotalSize,
(unsigned int)nMediaID);
#ifdef DUMMY_SQL_QUERIES
printf("MySQL query \"%s\"\n", pszSQLQuery);
#else
if (mysql_query(pMYSQL, pszSQLQuery) != 0)
{
fprintf(stderr, "Failed to execute query \"%s\" Error: %s\n",
pszSQLQuery,
mysql_error(pMYSQL));
Exit(1);
}
#endif
UnmountMedia();
printf("--> SUCCESS - Media added.\n");
printf("Media title: %s\n", strTitle);
printf("Media ID: %u\n", (unsigned int)nMediaID);
printf("Added: %s", ctime(&timeAdded));
printf("Total files: %u\n", (unsigned int)nTotalFiles);
printf("Total size: %u\n", (unsigned int)nTotalSize);
goto Loop;
}