PageRenderTime 55ms CodeModel.GetById 27ms RepoModel.GetById 0ms app.codeStats 0ms

/dali/rfs/rfsmysql/rfsmysql.cpp

https://github.com/narpaldhillon/HPCC-Platform
C++ | 831 lines | 729 code | 66 blank | 36 comment | 130 complexity | 86f937f5871f53a445a51d39100266f9 MD5 | raw file
  1. /*##############################################################################
  2. Copyright (C) 2011 HPCC Systems.
  3. All rights reserved. This program is free software: you can redistribute it and/or modify
  4. it under the terms of the GNU Affero General Public License as
  5. published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Affero General Public License for more details.
  11. You should have received a copy of the GNU Affero General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>.
  13. ############################################################################## */
  14. // MYSQL RFS Gateway
  15. #ifdef _WIN32
  16. #define WIN32_LEAN_AND_MEAN
  17. #ifndef _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES
  18. #define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1
  19. #undef _CRT_SECURE_NO_WARNINGS
  20. #define _CRT_SECURE_NO_WARNINGS 1
  21. #endif
  22. #undef UNICODE
  23. #include <windows.h>
  24. #include <io.h>
  25. #include <sys/utime.h>
  26. #include <sys/types.h>
  27. #include <ctype.h>
  28. #else
  29. #include <sys/types.h>
  30. #include <unistd.h>
  31. #define _strdup strdup
  32. #define _O_RDONLY O_RDONLY
  33. #define _O_WRONLY O_WRONLY
  34. #define _O_RDWR O_RDWR
  35. #define _O_CREAT O_CREAT
  36. #define _O_TRUNC O_TRUNC
  37. #define _O_BINARY (0)
  38. #define _open ::open
  39. #define _read ::read
  40. #define _write ::write
  41. #define _lseek ::lseek
  42. #define _close ::close
  43. #define _unlink unlink
  44. #define _tempnam tempnam
  45. #include <ctype.h>
  46. static int _memicmp (const void *s1, const void *s2, size_t len)
  47. {
  48. const unsigned char *b1 = (const unsigned char *)s1;
  49. const unsigned char *b2 = (const unsigned char *)s2;
  50. int ret = 0;
  51. while (len&&((ret = tolower(*b1)-tolower(*b2)) == 0)) {
  52. b1++;
  53. b2++;
  54. len--;
  55. }
  56. return ret;
  57. }
  58. #endif
  59. #if defined(_M_X64) || defined ( __x86_64) || __WORDSIZE==64
  60. #define __64BIT__
  61. typedef unsigned long memsize_t;
  62. #else
  63. typedef unsigned memsize_t;
  64. #endif
  65. #include <stdlib.h>
  66. #include <stdio.h>
  67. #include <stdarg.h>
  68. #include <string.h>
  69. #include <errno.h>
  70. #include <assert.h>
  71. #include <time.h>
  72. #include <fcntl.h>
  73. #include <sys/stat.h>
  74. typedef unsigned int u_int;
  75. #ifdef SOCKET
  76. #undef SOCKET
  77. #endif
  78. typedef u_int SOCKET;
  79. #include <mysql.h>
  80. #include "rfs.h"
  81. static char *tempdir=NULL;
  82. static int createTempFile(RFS_ServerBase &base,char *&name)
  83. {
  84. free(name);
  85. #ifdef _WIN32
  86. name = _tempnam(tempdir,"rfsmysqltmp");
  87. int ret = _open(name, _O_RDWR | _O_CREAT | _O_BINARY, _S_IREAD|_S_IWRITE);
  88. #else
  89. size_t ds = tempdir?strlen(tempdir):0;
  90. name = (char *)malloc(ds+32);
  91. if (ds) {
  92. memcpy(name,tempdir,ds);
  93. if (tempdir[ds-1]!='/')
  94. tempdir[ds++] = '/';
  95. }
  96. else
  97. *name = 0;
  98. strcat(name,"rfsmysqltmp_XXXXXX");
  99. int ret = mkstemp(name);
  100. #endif
  101. if (ret==-1) {
  102. printf("name = '%s'\n",name);
  103. free(name);
  104. name = NULL;
  105. base.throwError(errno,"Creating temp file");
  106. }
  107. return ret;
  108. }
  109. #define RFSMYSQLERR_BASE 8200
  110. static void mySqlError(RFS_ServerBase &base,MYSQL &mysql)
  111. {
  112. static char errstr[8192];
  113. strcpy(errstr,"MYSQL Error: ");
  114. const char *err = mysql_error(&mysql);
  115. if (!err||!*err)
  116. err = "NONE";
  117. strcat(errstr,err);
  118. base.throwError(RFSMYSQLERR_BASE,errstr,false);
  119. }
  120. class CMySqlRFSconn: public RFS_ConnectionBase
  121. {
  122. RFS_ServerBase &base;
  123. char * query;
  124. byte querymode;
  125. bool eos;
  126. MYSQL &mysql;
  127. MYSQL_RES *res;
  128. MYSQL_ROW row;
  129. MYSQL_ROW_OFFSET startrow;
  130. rfs_fpos_t lastpos;
  131. unsigned long *lengths;
  132. unsigned numfields;
  133. RFS_CSVwriter csvwriter;
  134. RFS_CSVreader csvreader;
  135. bool needlocalinput;
  136. bool multistatement;
  137. int tempfile;
  138. char * tempfilename;
  139. bool readok;
  140. bool writeok;
  141. rfs_fpos_t savesize;
  142. int localerr;
  143. int localread(char *buf, unsigned int buf_len)
  144. {
  145. if (lastpos>=savesize)
  146. return 0;
  147. long ret = (long)_lseek(tempfile,(long)lastpos,SEEK_SET);
  148. if (ret!=lastpos) {
  149. localerr = errno;
  150. return -1;
  151. }
  152. int rd = _read(tempfile,buf,buf_len);
  153. if (rd==-1) {
  154. localerr = errno;
  155. return -1;
  156. }
  157. lastpos += rd;
  158. return rd;
  159. }
  160. int localerror(char *error_msg, unsigned int error_msg_len)
  161. {
  162. if (!error_msg_len)
  163. return localerr;
  164. const char *err = NULL;
  165. if (localerr)
  166. err = strerror(localerr);
  167. if (!err)
  168. err = "Error";
  169. size_t l = strlen(err);
  170. if (l+1>error_msg_len)
  171. l = error_msg_len-1;
  172. memcpy(error_msg,err,l);
  173. error_msg[l] = 0;
  174. return localerr;
  175. }
  176. static int local_infile_init(void **ptr, const char *filename, void *userdata)
  177. {
  178. *ptr = userdata; // we are non reentrant so this should suffice
  179. return 0;
  180. }
  181. static int local_infile_read(void *ptr, char *buf, unsigned int buf_len)
  182. {
  183. return ((CMySqlRFSconn *)ptr)->localread(buf,buf_len);
  184. }
  185. static void local_infile_end(void *ptr)
  186. {
  187. // nothing to do here
  188. }
  189. static int local_infile_error(void *ptr, char *error_msg, unsigned int error_msg_len)
  190. {
  191. return ((CMySqlRFSconn *)ptr)->localerror(error_msg, error_msg_len);
  192. }
  193. void mySqlError()
  194. {
  195. ::mySqlError(base,mysql);
  196. free(query);
  197. query = NULL;
  198. }
  199. void transformQuery(const char *in, bool forwrite)
  200. {
  201. if (*in=='/') // added by client
  202. in++;
  203. if (*in=='>') // added by client
  204. in++;
  205. free(query);
  206. query = NULL;
  207. needlocalinput = false;
  208. multistatement = false;
  209. bool istable = true;
  210. if (!in)
  211. return;
  212. query = NULL;
  213. RFS_SimpleString out;
  214. // NB only the first INFILE is transformed (deliberately)
  215. bool quoting = false;
  216. while (isspace((unsigned char)*in))
  217. in++;
  218. while (*in) {
  219. char c = *(in++);
  220. if (c=='\\') {
  221. out.appendc(c);
  222. c = *(in++);
  223. }
  224. else if (c=='\'') {
  225. quoting = !quoting;
  226. }
  227. else if (!quoting) {
  228. if (c==';') {
  229. unsigned i = 1;
  230. while (isspace((unsigned char)in[i])||(in[i]==';'))
  231. i++;
  232. if (!in[i])
  233. break; // e.g. trailing ;
  234. multistatement = true;
  235. }
  236. if (c==' ') {
  237. if (!needlocalinput&&(_memicmp(in,"INFILE []",9)==0)) {
  238. out.appends(" INFILE '#'");
  239. in+=9;
  240. needlocalinput = true;
  241. continue;
  242. }
  243. }
  244. }
  245. if (istable&&!isalnum((unsigned char)c)&&(c!='_')&&(c!='$'))
  246. istable = false;
  247. out.appendc(c);
  248. }
  249. out.trim();
  250. if (istable) {
  251. char *tablename = out.dup();
  252. out.clear();
  253. if (forwrite) {
  254. out.appends("LOAD DATA LOCAL INFILE '#' INTO TABLE ");
  255. out.appends(tablename);
  256. out.appends(" FIELDS TERMINATED BY ',' ENCLOSED BY '\\''");
  257. }
  258. else {
  259. out.appends("SELECT * FROM ");
  260. out.appends(tablename);
  261. }
  262. }
  263. if (multistatement&&needlocalinput)
  264. base.throwError(EACCES,"Multi-statement not allowed here");
  265. query = out.dup();
  266. }
  267. bool storeresults()
  268. {
  269. numfields = 0;
  270. while (1) { // this seems bit OTT
  271. res = mysql_store_result(&mysql);
  272. if (res) {
  273. startrow = mysql_row_tell(res);
  274. numfields = mysql_num_fields(res);
  275. if (numfields)
  276. break;
  277. mysql_free_result(res);
  278. res = NULL;
  279. }
  280. int r = mysql_next_result(&mysql);
  281. if (r>0)
  282. mySqlError();
  283. if (r!=0)
  284. break;
  285. }
  286. return numfields!=0;
  287. }
  288. bool firstresult()
  289. {
  290. if (!query)
  291. return false;
  292. if (res)
  293. return numfields!=0;
  294. if (base.debugLevel())
  295. base.log("Query: '%s'",query);
  296. if (mysql_real_query(&mysql, query, strlen(query)))
  297. mySqlError();
  298. return storeresults();
  299. }
  300. bool nextresult()
  301. {
  302. if (!query||!multistatement) // NB don't close in single statement
  303. return false;
  304. close(false);
  305. if (mysql_next_result(&mysql)!=0) { // see if more results
  306. free(query);
  307. query = NULL;
  308. return false;
  309. }
  310. return storeresults();
  311. }
  312. void writeQuery()
  313. {
  314. if (!query||!savesize||(tempfile==-1))
  315. return;
  316. lastpos = 0;
  317. localerr = 0;
  318. mysql_set_local_infile_handler(&mysql, local_infile_init, local_infile_read, local_infile_end, local_infile_error, this);
  319. if (mysql_real_query(&mysql, query, strlen(query))==0) {
  320. // I *think* this should execute all the multi statements
  321. }
  322. else {
  323. mysql_set_local_infile_default(&mysql);
  324. mySqlError();
  325. return;
  326. }
  327. mysql_set_local_infile_default(&mysql);
  328. free(query);
  329. query = NULL;
  330. }
  331. bool nextrow()
  332. {
  333. do {
  334. row = mysql_fetch_row(res);
  335. if (row) {
  336. lengths = mysql_fetch_lengths(res);
  337. if (lengths)
  338. return true;
  339. }
  340. } while (nextresult());
  341. return false;
  342. }
  343. public:
  344. CMySqlRFSconn(RFS_ServerBase &_base,MYSQL &_mysql)
  345. : base(_base), mysql(_mysql)
  346. {
  347. res = NULL;
  348. lastpos = 0;
  349. numfields = 0;
  350. query = NULL;
  351. readok = false;
  352. writeok = false;
  353. needlocalinput = false;
  354. multistatement = false;
  355. eos = false;
  356. tempfilename = NULL;
  357. tempfile = -1;
  358. savesize = (rfs_fpos_t)-1;
  359. }
  360. ~CMySqlRFSconn()
  361. {
  362. close(true);
  363. }
  364. bool openRead(const char *_query)
  365. {
  366. transformQuery(_query,false);
  367. close(true);
  368. eos = false;
  369. readok = true;
  370. writeok = false;
  371. savesize = (rfs_fpos_t)-1;
  372. return firstresult();
  373. }
  374. bool openWrite(const char *_query)
  375. {
  376. transformQuery(_query,true);
  377. close(true);
  378. eos = false;
  379. readok = false;
  380. writeok = true;
  381. savesize = (rfs_fpos_t)-1;
  382. return true;
  383. }
  384. void read(rfs_fpos_t pos, size_t len, size_t &outlen, void *out)
  385. {
  386. if (!readok)
  387. base.throwError(errno,"invalid mode for read");
  388. outlen = 0;
  389. if (tempfile!=-1) {
  390. if (out==NULL) {
  391. long length = (long)_lseek(tempfile,0,SEEK_END);
  392. if (length==-1)
  393. base.throwError(errno,"read size.1");
  394. if ((long)pos>length)
  395. outlen = 0;
  396. else if (length-(long)pos>(long)len)
  397. outlen = len;
  398. else
  399. outlen = (size_t)(length-(long)pos);
  400. return;
  401. }
  402. long ret = (long)_lseek(tempfile,(long)pos,SEEK_SET);
  403. if (ret!=pos)
  404. base.throwError(errno,"read.1");
  405. int rd = _read(tempfile,out,len);
  406. if (rd==-1)
  407. base.throwError(errno,"read.2");
  408. outlen = (size_t)rd;
  409. return;
  410. }
  411. if (pos==0) {
  412. row = NULL;
  413. csvwriter.rewrite();
  414. eos = false;
  415. lastpos = 0;
  416. }
  417. if (pos!=lastpos)
  418. base.throwError(EACCES,"Out of order read");
  419. if (eos||(csvwriter.length()>=len)) {
  420. if (len>csvwriter.length())
  421. len = csvwriter.length();
  422. if (out)
  423. memcpy(out,csvwriter.base(),len);
  424. csvwriter.consume(len);
  425. outlen = len;
  426. lastpos += len;
  427. return;
  428. }
  429. while (nextrow()) {
  430. for (unsigned f=0;f<numfields;f++)
  431. csvwriter.putField(lengths[f],row[f]);
  432. csvwriter.putRow();
  433. if (csvwriter.length()>=len) {
  434. if (out)
  435. memcpy(out,csvwriter.base(),len);
  436. csvwriter.consume(len);
  437. outlen = len;
  438. lastpos += len;
  439. return;
  440. }
  441. }
  442. eos = true;
  443. outlen = csvwriter.length();
  444. if (outlen>len)
  445. outlen = len;
  446. if (out)
  447. memcpy(out,csvwriter.base(),outlen);
  448. csvwriter.consume(outlen);
  449. lastpos += outlen;
  450. savesize = lastpos+csvwriter.length();
  451. }
  452. rfs_fpos_t size()
  453. {
  454. if (savesize!=(rfs_fpos_t)-1)
  455. return savesize;
  456. if (lastpos!=0)
  457. base.throwError(EACCES,"Getting size mid-read");
  458. // multi (and not prev saved) then save to a temporary file
  459. // bit of a shame but ...
  460. if (tempfile==-1) {
  461. rfs_fpos_t pos = 0;
  462. if (multistatement) {
  463. int newtempfile = createTempFile(base,tempfilename);
  464. struct cBuff
  465. {
  466. void *b;
  467. cBuff() { b = malloc(0x10000); }
  468. ~cBuff() { free(b); }
  469. } buf;
  470. while (1) {
  471. size_t rd = 0;
  472. read(pos,0x10000,rd,buf.b);
  473. if (!rd)
  474. break;
  475. int wr = _write(newtempfile,buf.b,rd);
  476. if (wr==-1)
  477. base.throwError(errno,"size write.1");
  478. if (wr!=rd) // disk full
  479. base.throwError(ENOSPC,"size write.2");
  480. pos+=rd;
  481. if (rd<0x10000)
  482. break;
  483. }
  484. tempfile = newtempfile;
  485. }
  486. else {
  487. while (1) {
  488. size_t rd = 0;
  489. read(pos,0x10000000,rd,NULL);
  490. if (!rd)
  491. break;
  492. pos+=rd;
  493. if (rd<0x10000000)
  494. break;
  495. }
  496. mysql_row_seek(res,startrow); // seek back to 0
  497. }
  498. eos = false;
  499. // we could reopen tempfile for read here
  500. lastpos = 0;
  501. savesize = pos;
  502. return pos;
  503. }
  504. long savedPos = (long)_lseek(tempfile,0,SEEK_CUR);
  505. if (savedPos == -1)
  506. base.throwError(errno,"size.1");
  507. long length = (long)_lseek(tempfile,0,SEEK_END);
  508. if (length==-1)
  509. base.throwError(errno,"size.2");
  510. if ((long)_lseek(tempfile,savedPos,SEEK_SET)!=savedPos)
  511. base.throwError(errno,"size.3");
  512. savesize = (rfs_fpos_t)length;
  513. return savesize;
  514. }
  515. void close(bool closetmp)
  516. {
  517. if(res) {
  518. mysql_free_result(res);
  519. res = NULL;
  520. numfields = 0;
  521. }
  522. if (writeok)
  523. writeQuery();
  524. if (closetmp) {
  525. if (tempfile!=-1)
  526. _close(tempfile);
  527. if (tempfilename)
  528. _unlink(tempfilename);
  529. free(tempfilename);
  530. tempfilename = NULL;
  531. tempfile = -1;
  532. }
  533. }
  534. void close()
  535. {
  536. close(true);
  537. }
  538. void write(rfs_fpos_t pos, size_t len, const void *in)
  539. {
  540. if (!writeok)
  541. base.throwError(EACCES,"invalid mode for write");
  542. if (tempfile==-1)
  543. tempfile = createTempFile(base,tempfilename);
  544. long ret = (long)_lseek(tempfile,(long)pos,SEEK_SET);
  545. if (ret!=pos)
  546. base.throwError(errno,"write.1");
  547. int wr = _write(tempfile,in,len);
  548. if (wr==-1)
  549. base.throwError(errno,"write.2");
  550. if (wr!=len) // disk full
  551. base.throwError(ENOSPC,"write.3");
  552. if (pos+wr>savesize)
  553. savesize = pos+wr;
  554. }
  555. };
  556. class CMySqlRFS: public RFS_ServerBase
  557. {
  558. MYSQL mysql;
  559. bool isopen;
  560. unsigned lastping;
  561. public:
  562. CMySqlRFS()
  563. {
  564. if (mysql_library_init(0, NULL, NULL)) {
  565. fprintf(stderr, "could not initialize MySQL library\n");
  566. exit(1);
  567. }
  568. isopen = false;
  569. tempdir = NULL;
  570. lastping = (unsigned)time(NULL);
  571. }
  572. ~CMySqlRFS()
  573. {
  574. if (isopen)
  575. mysql_close(&mysql);
  576. mysql_library_end();
  577. free(tempdir);
  578. }
  579. virtual RFS_ConnectionBase * open(const char *name, byte mode, byte share)
  580. {
  581. if ((unsigned)time(NULL)-lastping>60*30) { // ping every 30m
  582. if (mysql_ping(&mysql)) {
  583. mySqlError(*this,mysql);
  584. }
  585. lastping = (unsigned)time(NULL);
  586. }
  587. CMySqlRFSconn *conn = new CMySqlRFSconn(*this,mysql);
  588. if ((*name=='/')||(*name=='\\'))
  589. *name++;
  590. if ((mode&RFS_OPEN_MODE_MASK)==RFS_OPEN_MODE_READ) {
  591. if (conn->openRead(name))
  592. return conn;
  593. }
  594. else if ((mode&RFS_OPEN_MODE_MASK)==RFS_OPEN_MODE_CREATE) {
  595. if (conn->openWrite(name))
  596. return conn;
  597. }
  598. else
  599. throwError(EACCES,"Open mode not supported");
  600. // error TBD?
  601. delete conn;
  602. return NULL;
  603. }
  604. virtual void existFile(const char *filename, bool &existsout)
  605. {
  606. existsout = true; // assume exists (query may fail but that will be an error)
  607. }
  608. virtual void removeFile(const char *filename)
  609. {
  610. // error TBD
  611. }
  612. virtual void renameFile(const char *fromname,const char *toname)
  613. {
  614. // error TBD
  615. }
  616. virtual void getFileTime(const char *filename, time_t &outaccessedtime, time_t &outcreatedtime, time_t &outmodifiedtime)
  617. {
  618. time(&outaccessedtime);
  619. outcreatedtime = outaccessedtime;
  620. outmodifiedtime = outaccessedtime;
  621. // bit odd that changes...
  622. // Alternative would be to keep a past query cache (i.e. when done) but that isn't really ideal.
  623. }
  624. virtual void setFileTime(const char *filename, time_t *outaccessedtime, time_t *outcreatedtime, time_t *outmodifiedtime) // params NULL if not to be set
  625. {
  626. // ignore
  627. }
  628. virtual void isFile(const char *filename, bool &outisfile)
  629. {
  630. outisfile = true; // pretend we are a file
  631. }
  632. virtual void isDir(const char *filename, bool &outisdir)
  633. {
  634. outisdir = true; // we aren't a directory
  635. }
  636. virtual void isReadOnly(const char *filename, bool &outisreadonly)
  637. {
  638. outisreadonly = true; // no update supported currently
  639. }
  640. virtual void setReadOnly(const char *filename, bool readonly)
  641. {
  642. // ignore
  643. }
  644. virtual void createDir(const char *dirname,bool &createdout)
  645. {
  646. // ignore
  647. }
  648. virtual void openDir(const char *dirname, const char *mask, bool recursive, bool includedir, void * &outhandle)
  649. {
  650. // TBD use mysql_list_tables()
  651. outhandle = NULL;
  652. }
  653. virtual void nextDirEntry(void * handle, size_t maxfilenamesize, char *outfilename, bool &isdir, rfs_fpos_t &filesizeout, time_t &outmodifiedtime) // empty return for filename marks end
  654. {
  655. // TBD return table
  656. outfilename[0] = 0;
  657. }
  658. virtual void closeDir(void * handle)
  659. {
  660. // TBD
  661. }
  662. virtual void getVersion(size_t programnamemax, char *programname, short &version)
  663. {
  664. assert(programnamemax>sizeof("rfsmysql")+1);
  665. strcpy(programname,"rfsmysql");
  666. version = 1;
  667. }
  668. int run(const char *server,const char *user,const char *password,const char *db, int mysqlport,const char *mygroup,const char *myconf,char *_tempdir)
  669. {
  670. if (_tempdir[0])
  671. tempdir = _strdup(_tempdir);
  672. mysql_init(&mysql);
  673. if (mygroup[0])
  674. mysql_options(&mysql,MYSQL_READ_DEFAULT_GROUP,mygroup);
  675. if (myconf[0]) {
  676. if (!mysql_options(&mysql,MYSQL_READ_DEFAULT_FILE ,myconf))
  677. fprintf(stderr, "Failed read option file: Error: %s\n", mysql_error(&mysql));
  678. }
  679. my_bool enabled = 1;
  680. mysql_options(&mysql, MYSQL_OPT_RECONNECT, &enabled);
  681. mysql_options(&mysql, MYSQL_OPT_LOCAL_INFILE, &enabled);
  682. if (!mysql_real_connect(&mysql, server, user, password, db, mysqlport, 0, CLIENT_MULTI_STATEMENTS | CLIENT_MULTI_RESULTS)) {
  683. fprintf(stderr, "Failed to connect to database: Error: %s\n", mysql_error(&mysql));
  684. mysql_close(&mysql);
  685. return 1;
  686. }
  687. isopen = false;
  688. return RFS_ServerBase::run();
  689. }
  690. };
  691. void usage()
  692. {
  693. printf("rfsmysql --port=<port>\n");
  694. printf(" --mysqlserver=<mysqlep> --mysqlport=<port>\n");
  695. printf(" --user=<username> --password=<password>\n");
  696. printf(" --db=<database>\n");
  697. printf(" --mygroup=<groupname> -- for specifying server option group\n");
  698. printf(" --myconfig=<filename> -- for specifying server option file\n");
  699. printf(" --tempdir=<dirname> -- directory for temporary files\n");
  700. }
  701. bool checkparam(const char *param,const char *name,char *out,size_t size)
  702. {
  703. if ((param[0]!='-')||(param[0]!='-'))
  704. return false;
  705. param+=2;
  706. if (strncmp(param,name,strlen(name))==0) {
  707. const char *v = param+strlen(name);
  708. if (*v=='=') {
  709. if (strlen(v+1)>size-1) {
  710. fprintf(stderr,"parameter %s to large (> %d chars)",param,size-1);
  711. exit(1);
  712. }
  713. strcpy(out,v+1);
  714. return true;
  715. }
  716. }
  717. return false;
  718. }
  719. int main(int argc, const char **argv)
  720. {
  721. #ifdef _WIN32
  722. // for windows service must be static (main returns)
  723. static
  724. #endif
  725. CMySqlRFS rfsserver;
  726. if (!rfsserver.init(argc,argv)) {
  727. usage();
  728. return 1;
  729. }
  730. char server[256];
  731. char user[256];
  732. char password[256];
  733. char db[256];
  734. char mysqlport[32];
  735. char mygroup[128];
  736. char myconf[256];
  737. char tempdir[256];
  738. strcpy(server,"localhost");
  739. user[0] = 0;
  740. password[0] = 0;
  741. mysqlport[0] = 0;
  742. mygroup[0] = 0;
  743. myconf[0] = 0;
  744. db[0] = 0;
  745. tempdir[0] = 0;
  746. for (int i=1;i<argc;i++) {
  747. if (checkparam(argv[i],"mysqlserver",server,sizeof(server))) continue;
  748. if (checkparam(argv[i],"user",user,sizeof(user))) continue;
  749. if (checkparam(argv[i],"password",password,sizeof(password))) continue;
  750. if (checkparam(argv[i],"db",db,sizeof(db))) continue;
  751. if (checkparam(argv[i],"mysqlport",mysqlport,sizeof(mysqlport))) continue;
  752. if (checkparam(argv[i],"mygroup",mygroup,sizeof(mygroup))) continue;
  753. if (checkparam(argv[i],"myconf",myconf,sizeof(myconf))) continue;
  754. if (checkparam(argv[i],"tempdir",tempdir,sizeof(tempdir))) continue;
  755. }
  756. if (!db) {
  757. usage();
  758. return 0;
  759. }
  760. return rfsserver.run(server,user,password,db,atoi(mysqlport),mygroup,myconf,tempdir);
  761. }