关键词搜索

源码搜索 ×
×

漫话Redis源码之七十二

发布2022-02-13浏览491次

详情内容

这里主要是枚举和配置相关的:

  1. configEnum syslog_facility_enum[] = {
  2. {"user", LOG_USER},
  3. {"local0", LOG_LOCAL0},
  4. {"local1", LOG_LOCAL1},
  5. {"local2", LOG_LOCAL2},
  6. {"local3", LOG_LOCAL3},
  7. {"local4", LOG_LOCAL4},
  8. {"local5", LOG_LOCAL5},
  9. {"local6", LOG_LOCAL6},
  10. {"local7", LOG_LOCAL7},
  11. {NULL, 0}
  12. };
  13. configEnum loglevel_enum[] = {
  14. {"debug", LL_DEBUG},
  15. {"verbose", LL_VERBOSE},
  16. {"notice", LL_NOTICE},
  17. {"warning", LL_WARNING},
  18. {NULL,0}
  19. };
  20. configEnum supervised_mode_enum[] = {
  21. {"upstart", SUPERVISED_UPSTART},
  22. {"systemd", SUPERVISED_SYSTEMD},
  23. {"auto", SUPERVISED_AUTODETECT},
  24. {"no", SUPERVISED_NONE},
  25. {NULL, 0}
  26. };
  27. configEnum aof_fsync_enum[] = {
  28. {"everysec", AOF_FSYNC_EVERYSEC},
  29. {"always", AOF_FSYNC_ALWAYS},
  30. {"no", AOF_FSYNC_NO},
  31. {NULL, 0}
  32. };
  33. configEnum repl_diskless_load_enum[] = {
  34. {"disabled", REPL_DISKLESS_LOAD_DISABLED},
  35. {"on-empty-db", REPL_DISKLESS_LOAD_WHEN_DB_EMPTY},
  36. {"swapdb", REPL_DISKLESS_LOAD_SWAPDB},
  37. {NULL, 0}
  38. };
  39. configEnum tls_auth_clients_enum[] = {
  40. {"no", TLS_CLIENT_AUTH_NO},
  41. {"yes", TLS_CLIENT_AUTH_YES},
  42. {"optional", TLS_CLIENT_AUTH_OPTIONAL},
  43. {NULL, 0}
  44. };
  45. configEnum oom_score_adj_enum[] = {
  46. {"no", OOM_SCORE_ADJ_NO},
  47. {"yes", OOM_SCORE_RELATIVE},
  48. {"relative", OOM_SCORE_RELATIVE},
  49. {"absolute", OOM_SCORE_ADJ_ABSOLUTE},
  50. {NULL, 0}
  51. };
  52. configEnum acl_pubsub_default_enum[] = {
  53. {"allchannels", USER_FLAG_ALLCHANNELS},
  54. {"resetchannels", 0},
  55. {NULL, 0}
  56. };
  57. configEnum sanitize_dump_payload_enum[] = {
  58. {"no", SANITIZE_DUMP_NO},
  59. {"yes", SANITIZE_DUMP_YES},
  60. {"clients", SANITIZE_DUMP_CLIENTS},
  61. {NULL, 0}
  62. };
  63. /* Output buffer limits presets. */
  64. clientBufferLimitsConfig clientBufferLimitsDefaults[CLIENT_TYPE_OBUF_COUNT] = {
  65. {0, 0, 0}, /* normal */
  66. {1024*1024*256, 1024*1024*64, 60}, /* slave */
  67. {1024*1024*32, 1024*1024*8, 60} /* pubsub */
  68. };
  69. /* OOM Score defaults */
  70. int configOOMScoreAdjValuesDefaults[CONFIG_OOM_COUNT] = { 0, 200, 800 };
  71. /* Generic config infrastructure function pointers
  72. * int is_valid_fn(val, err)
  73. * Return 1 when val is valid, and 0 when invalid.
  74. * Optionally set err to a static error string.
  75. * int update_fn(val, prev, err)
  76. * This function is called only for CONFIG SET command (not at config file parsing)
  77. * It is called after the actual config is applied,
  78. * Return 1 for success, and 0 for failure.
  79. * Optionally set err to a static error string.
  80. * On failure the config change will be reverted.
  81. */
  82. /* Configuration values that require no special handling to set, get, load or
  83. * rewrite. */
  84. typedef struct boolConfigData {
  85. int *config; /* The pointer to the server config this value is stored in */
  86. const int default_value; /* The default value of the config on rewrite */
  87. int (*is_valid_fn)(int val, const char **err); /* Optional function to check validity of new value (generic doc above) */
  88. int (*update_fn)(int val, int prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
  89. } boolConfigData;
  90. typedef struct stringConfigData {
  91. char **config; /* Pointer to the server config this value is stored in. */
  92. const char *default_value; /* Default value of the config on rewrite. */
  93. int (*is_valid_fn)(char* val, const char **err); /* Optional function to check validity of new value (generic doc above) */
  94. int (*update_fn)(char* val, char* prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
  95. int convert_empty_to_null; /* Boolean indicating if empty strings should
  96. be stored as a NULL value. */
  97. } stringConfigData;
  98. typedef struct sdsConfigData {
  99. sds *config; /* Pointer to the server config this value is stored in. */
  100. const char *default_value; /* Default value of the config on rewrite. */
  101. int (*is_valid_fn)(sds val, const char **err); /* Optional function to check validity of new value (generic doc above) */
  102. int (*update_fn)(sds val, sds prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
  103. int convert_empty_to_null; /* Boolean indicating if empty SDS strings should
  104. be stored as a NULL value. */
  105. } sdsConfigData;
  106. typedef struct enumConfigData {
  107. int *config; /* The pointer to the server config this value is stored in */
  108. configEnum *enum_value; /* The underlying enum type this data represents */
  109. const int default_value; /* The default value of the config on rewrite */
  110. int (*is_valid_fn)(int val, const char **err); /* Optional function to check validity of new value (generic doc above) */
  111. int (*update_fn)(int val, int prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
  112. } enumConfigData;
  113. typedef enum numericType {
  114. NUMERIC_TYPE_INT,
  115. NUMERIC_TYPE_UINT,
  116. NUMERIC_TYPE_LONG,
  117. NUMERIC_TYPE_ULONG,
  118. NUMERIC_TYPE_LONG_LONG,
  119. NUMERIC_TYPE_ULONG_LONG,
  120. NUMERIC_TYPE_SIZE_T,
  121. NUMERIC_TYPE_SSIZE_T,
  122. NUMERIC_TYPE_OFF_T,
  123. NUMERIC_TYPE_TIME_T,
  124. } numericType;
  125. typedef struct numericConfigData {
  126. union {
  127. int *i;
  128. unsigned int *ui;
  129. long *l;
  130. unsigned long *ul;
  131. long long *ll;
  132. unsigned long long *ull;
  133. size_t *st;
  134. ssize_t *sst;
  135. off_t *ot;
  136. time_t *tt;
  137. } config; /* The pointer to the numeric config this value is stored in */
  138. int is_memory; /* Indicates if this value can be loaded as a memory value */
  139. numericType numeric_type; /* An enum indicating the type of this value */
  140. long long lower_bound; /* The lower bound of this numeric value */
  141. long long upper_bound; /* The upper bound of this numeric value */
  142. const long long default_value; /* The default value of the config on rewrite */
  143. int (*is_valid_fn)(long long val, const char **err); /* Optional function to check validity of new value (generic doc above) */
  144. int (*update_fn)(long long val, long long prev, const char **err); /* Optional function to apply new value at runtime (generic doc above) */
  145. } numericConfigData;
  146. typedef union typeData {
  147. boolConfigData yesno;
  148. stringConfigData string;
  149. sdsConfigData sds;
  150. enumConfigData enumd;
  151. numericConfigData numeric;
  152. } typeData;
  153. typedef struct typeInterface {
  154. /* Called on server start, to init the server with default value */
  155. void (*init)(typeData data);
  156. /* Called on server startup and CONFIG SET, returns 1 on success, 0 on error
  157. * and can set a verbose err string, update is true when called from CONFIG SET */
  158. int (*set)(typeData data, sds value, int update, const char **err);
  159. /* Called on CONFIG GET, required to add output to the client */
  160. void (*get)(client *c, typeData data);
  161. /* Called on CONFIG REWRITE, required to rewrite the config state */
  162. void (*rewrite)(typeData data, const char *name, struct rewriteConfigState *state);
  163. } typeInterface;
  164. typedef struct standardConfig {
  165. const char *name; /* The user visible name of this config */
  166. const char *alias; /* An alias that can also be used for this config */
  167. const unsigned int flags; /* Flags for this specific config */
  168. typeInterface interface; /* The function pointers that define the type interface */
  169. typeData data; /* The type specific data exposed used by the interface */
  170. } standardConfig;
  171. #define MODIFIABLE_CONFIG 0 /* This is the implied default for a standard
  172. * config, which is mutable. */
  173. #define IMMUTABLE_CONFIG (1ULL<<0) /* Can this value only be set at startup? */
  174. #define SENSITIVE_CONFIG (1ULL<<1) /* Does this value contain sensitive information */
  175. standardConfig configs[];
  176. /*-----------------------------------------------------------------------------
  177. * Enum access functions
  178. *----------------------------------------------------------------------------*/
  179. /* Get enum value from name. If there is no match INT_MIN is returned. */
  180. int configEnumGetValue(configEnum *ce, char *name) {
  181. while(ce->name != NULL) {
  182. if (!strcasecmp(ce->name,name)) return ce->val;
  183. ce++;
  184. }
  185. return INT_MIN;
  186. }
  187. /* Get enum name from value. If no match is found NULL is returned. */
  188. const char *configEnumGetName(configEnum *ce, int val) {
  189. while(ce->name != NULL) {
  190. if (ce->val == val) return ce->name;
  191. ce++;
  192. }
  193. return NULL;
  194. }
  195. /* Wrapper for configEnumGetName() returning "unknown" instead of NULL if
  196. * there is no match. */
  197. const char *configEnumGetNameOrUnknown(configEnum *ce, int val) {
  198. const char *name = configEnumGetName(ce,val);
  199. return name ? name : "unknown";
  200. }
  201. /* Used for INFO generation. */
  202. const char *evictPolicyToString(void) {
  203. return configEnumGetNameOrUnknown(maxmemory_policy_enum,server.maxmemory_policy);
  204. }
  205. /*-----------------------------------------------------------------------------
  206. * Config file parsing
  207. *----------------------------------------------------------------------------*/
  208. int yesnotoi(char *s) {
  209. if (!strcasecmp(s,"yes")) return 1;
  210. else if (!strcasecmp(s,"no")) return 0;
  211. else return -1;
  212. }
  213. void appendServerSaveParams(time_t seconds, int changes) {
  214. server.saveparams = zrealloc(server.saveparams,sizeof(struct saveparam)*(server.saveparamslen+1));
  215. server.saveparams[server.saveparamslen].seconds = seconds;
  216. server.saveparams[server.saveparamslen].changes = changes;
  217. server.saveparamslen++;
  218. }
  219. void resetServerSaveParams(void) {
  220. zfree(server.saveparams);
  221. server.saveparams = NULL;
  222. server.saveparamslen = 0;
  223. }
  224. void queueLoadModule(sds path, sds *argv, int argc) {
  225. int i;
  226. struct moduleLoadQueueEntry *loadmod;
  227. loadmod = zmalloc(sizeof(struct moduleLoadQueueEntry));
  228. loadmod->argv = zmalloc(sizeof(robj*)*argc);
  229. loadmod->path = sdsnew(path);
  230. loadmod->argc = argc;
  231. for (i = 0; i < argc; i++) {
  232. loadmod->argv[i] = createRawStringObject(argv[i],sdslen(argv[i]));
  233. }
  234. listAddNodeTail(server.loadmodule_queue,loadmod);
  235. }
  236. /* Parse an array of CONFIG_OOM_COUNT sds strings, validate and populate
  237. * server.oom_score_adj_values if valid.
  238. */
  239. static int updateOOMScoreAdjValues(sds *args, const char **err, int apply) {
  240. int i;
  241. int values[CONFIG_OOM_COUNT];
  242. for (i = 0; i < CONFIG_OOM_COUNT; i++) {
  243. char *eptr;
  244. long long val = strtoll(args[i], &eptr, 10);
  245. if (*eptr != '\0' || val < -2000 || val > 2000) {
  246. if (err) *err = "Invalid oom-score-adj-values, elements must be between -2000 and 2000.";
  247. return C_ERR;
  248. }
  249. values[i] = val;
  250. }
  251. /* Verify that the values make sense. If they don't omit a warning but
  252. * keep the configuration, which may still be valid for privileged processes.
  253. */
  254. if (values[CONFIG_OOM_REPLICA] < values[CONFIG_OOM_MASTER] ||
  255. values[CONFIG_OOM_BGCHILD] < values[CONFIG_OOM_REPLICA]) {
  256. serverLog(LOG_WARNING,
  257. "The oom-score-adj-values configuration may not work for non-privileged processes! "
  258. "Please consult the documentation.");
  259. }
  260. /* Store values, retain previous config for rollback in case we fail. */
  261. int old_values[CONFIG_OOM_COUNT];
  262. for (i = 0; i < CONFIG_OOM_COUNT; i++) {
  263. old_values[i] = server.oom_score_adj_values[i];
  264. server.oom_score_adj_values[i] = values[i];
  265. }
  266. /* When parsing the config file, we want to apply only when all is done. */
  267. if (!apply)
  268. return C_OK;
  269. /* Update */
  270. if (setOOMScoreAdj(-1) == C_ERR) {
  271. /* Roll back */
  272. for (i = 0; i < CONFIG_OOM_COUNT; i++)
  273. server.oom_score_adj_values[i] = old_values[i];
  274. if (err)
  275. *err = "Failed to apply oom-score-adj-values configuration, check server logs.";
  276. return C_ERR;
  277. }
  278. return C_OK;
  279. }
  280. void initConfigValues() {
  281. for (standardConfig *config = configs; config->name != NULL; config++) {
  282. config->interface.init(config->data);
  283. }
  284. }
  285. void loadServerConfigFromString(char *config) {
  286. const char *err = NULL;
  287. int linenum = 0, totlines, i;
  288. int slaveof_linenum = 0;
  289. sds *lines;
  290. int save_loaded = 0;
  291. lines = sdssplitlen(config,strlen(config),"\n",1,&totlines);
  292. for (i = 0; i < totlines; i++) {
  293. sds *argv;
  294. int argc;
  295. linenum = i+1;
  296. lines[i] = sdstrim(lines[i]," \t\r\n");
  297. /* Skip comments and blank lines */
  298. if (lines[i][0] == '#' || lines[i][0] == '\0') continue;
  299. /* Split into arguments */
  300. argv = sdssplitargs(lines[i],&argc);
  301. if (argv == NULL) {
  302. err = "Unbalanced quotes in configuration line";
  303. goto loaderr;
  304. }
  305. /* Skip this line if the resulting command vector is empty. */
  306. if (argc == 0) {
  307. sdsfreesplitres(argv,argc);
  308. continue;
  309. }
  310. sdstolower(argv[0]);
  311. /* Iterate the configs that are standard */
  312. int match = 0;
  313. for (standardConfig *config = configs; config->name != NULL; config++) {
  314. if ((!strcasecmp(argv[0],config->name) ||
  315. (config->alias && !strcasecmp(argv[0],config->alias))))
  316. {
  317. if (argc != 2) {
  318. err = "wrong number of arguments";
  319. goto loaderr;
  320. }
  321. if (!config->interface.set(config->data, argv[1], 0, &err)) {
  322. goto loaderr;
  323. }
  324. match = 1;
  325. break;
  326. }
  327. }
  328. if (match) {
  329. sdsfreesplitres(argv,argc);
  330. continue;
  331. }
  332. /* Execute config directives */
  333. if (!strcasecmp(argv[0],"bind") && argc >= 2) {
  334. int j, addresses = argc-1;
  335. if (addresses > CONFIG_BINDADDR_MAX) {
  336. err = "Too many bind addresses specified"; goto loaderr;
  337. }
  338. /* Free old bind addresses */
  339. for (j = 0; j < server.bindaddr_count; j++) {
  340. zfree(server.bindaddr[j]);
  341. }
  342. for (j = 0; j < addresses; j++)
  343. server.bindaddr[j] = zstrdup(argv[j+1]);
  344. server.bindaddr_count = addresses;
  345. } else if (!strcasecmp(argv[0],"unixsocketperm") && argc == 2) {
  346. errno = 0;
  347. server.unixsocketperm = (mode_t)strtol(argv[1], NULL, 8);
  348. if (errno || server.unixsocketperm > 0777) {
  349. err = "Invalid socket file permissions"; goto loaderr;
  350. }
  351. } else if (!strcasecmp(argv[0],"save")) {
  352. /* We don't reset save params before loading, because if they're not part
  353. * of the file the defaults should be used.
  354. */
  355. if (!save_loaded) {
  356. save_loaded = 1;
  357. resetServerSaveParams();
  358. }
  359. if (argc == 3) {
  360. int seconds = atoi(argv[1]);
  361. int changes = atoi(argv[2]);
  362. if (seconds < 1 || changes < 0) {
  363. err = "Invalid save parameters"; goto loaderr;
  364. }
  365. appendServerSaveParams(seconds,changes);
  366. } else if (argc == 2 && !strcasecmp(argv[1],"")) {
  367. resetServerSaveParams();
  368. }
  369. } else if (!strcasecmp(argv[0],"dir") && argc == 2) {
  370. if (chdir(argv[1]) == -1) {
  371. serverLog(LL_WARNING,"Can't chdir to '%s': %s",
  372. argv[1], strerror(errno));
  373. exit(1);
  374. }
  375. } else if (!strcasecmp(argv[0],"logfile") && argc == 2) {
  376. FILE *logfp;
  377. zfree(server.logfile);
  378. server.logfile = zstrdup(argv[1]);
  379. if (server.logfile[0] != '\0') {
  380. /* Test if we are able to open the file. The server will not
  381. * be able to abort just for this problem later... */
  382. logfp = fopen(server.logfile,"a");
  383. if (logfp == NULL) {
  384. err = sdscatprintf(sdsempty(),
  385. "Can't open the log file: %s", strerror(errno));
  386. goto loaderr;
  387. }
  388. fclose(logfp);
  389. }
  390. } else if (!strcasecmp(argv[0],"include") && argc == 2) {
  391. loadServerConfig(argv[1], 0, NULL);
  392. } else if ((!strcasecmp(argv[0],"slaveof") ||
  393. !strcasecmp(argv[0],"replicaof")) && argc == 3) {
  394. slaveof_linenum = linenum;
  395. sdsfree(server.masterhost);
  396. if (!strcasecmp(argv[1], "no") && !strcasecmp(argv[2], "one")) {
  397. server.masterhost = NULL;
  398. continue;
  399. }
  400. server.masterhost = sdsnew(argv[1]);
  401. char *ptr;
  402. server.masterport = strtol(argv[2], &ptr, 10);
  403. if (server.masterport < 0 || server.masterport > 65535 || *ptr != '\0') {
  404. err = "Invalid master port"; goto loaderr;
  405. }
  406. server.repl_state = REPL_STATE_CONNECT;
  407. } else if (!strcasecmp(argv[0],"list-max-ziplist-entries") && argc == 2){
  408. /* DEAD OPTION */
  409. } else if (!strcasecmp(argv[0],"list-max-ziplist-value") && argc == 2) {
  410. /* DEAD OPTION */
  411. } else if (!strcasecmp(argv[0],"rename-command") && argc == 3) {
  412. struct redisCommand *cmd = lookupCommand(argv[1]);
  413. int retval;
  414. if (!cmd) {
  415. err = "No such command in rename-command";
  416. goto loaderr;
  417. }
  418. /* If the target command name is the empty string we just
  419. * remove it from the command table. */
  420. retval = dictDelete(server.commands, argv[1]);
  421. serverAssert(retval == DICT_OK);
  422. /* Otherwise we re-add the command under a different name. */
  423. if (sdslen(argv[2]) != 0) {
  424. sds copy = sdsdup(argv[2]);
  425. retval = dictAdd(server.commands, copy, cmd);
  426. if (retval != DICT_OK) {
  427. sdsfree(copy);
  428. err = "Target command name already exists"; goto loaderr;
  429. }
  430. }
  431. } else if (!strcasecmp(argv[0],"cluster-config-file") && argc == 2) {
  432. zfree(server.cluster_configfile);
  433. server.cluster_configfile = zstrdup(argv[1]);
  434. } else if (!strcasecmp(argv[0],"client-output-buffer-limit") &&
  435. argc == 5)
  436. {
  437. int class = getClientTypeByName(argv[1]);
  438. unsigned long long hard, soft;
  439. int soft_seconds;
  440. if (class == -1 || class == CLIENT_TYPE_MASTER) {
  441. err = "Unrecognized client limit class: the user specified "
  442. "an invalid one, or 'master' which has no buffer limits.";
  443. goto loaderr;
  444. }
  445. hard = memtoll(argv[2],NULL);
  446. soft = memtoll(argv[3],NULL);
  447. soft_seconds = atoi(argv[4]);
  448. if (soft_seconds < 0) {
  449. err = "Negative number of seconds in soft limit is invalid";
  450. goto loaderr;
  451. }
  452. server.client_obuf_limits[class].hard_limit_bytes = hard;
  453. server.client_obuf_limits[class].soft_limit_bytes = soft;
  454. server.client_obuf_limits[class].soft_limit_seconds = soft_seconds;
  455. } else if (!strcasecmp(argv[0],"oom-score-adj-values") && argc == 1 + CONFIG_OOM_COUNT) {
  456. if (updateOOMScoreAdjValues(&argv[1], &err, 0) == C_ERR) goto loaderr;
  457. } else if (!strcasecmp(argv[0],"notify-keyspace-events") && argc == 2) {
  458. int flags = keyspaceEventsStringToFlags(argv[1]);
  459. if (flags == -1) {
  460. err = "Invalid event class character. Use 'g$lshzxeA'.";
  461. goto loaderr;
  462. }
  463. server.notify_keyspace_events = flags;
  464. } else if (!strcasecmp(argv[0],"user") && argc >= 2) {
  465. int argc_err;
  466. if (ACLAppendUserForLoading(argv,argc,&argc_err) == C_ERR) {
  467. char buf[1024];
  468. const char *errmsg = ACLSetUserStringError();
  469. snprintf(buf,sizeof(buf),"Error in user declaration '%s': %s",
  470. argv[argc_err],errmsg);
  471. err = buf;
  472. goto loaderr;
  473. }
  474. } else if (!strcasecmp(argv[0],"loadmodule") && argc >= 2) {
  475. queueLoadModule(argv[1],&argv[2],argc-2);
  476. } else if (!strcasecmp(argv[0],"sentinel")) {
  477. /* argc == 1 is handled by main() as we need to enter the sentinel
  478. * mode ASAP. */
  479. if (argc != 1) {
  480. if (!server.sentinel_mode) {
  481. err = "sentinel directive while not in sentinel mode";
  482. goto loaderr;
  483. }
  484. queueSentinelConfig(argv+1,argc-1,linenum,lines[i]);
  485. }
  486. } else {
  487. err = "Bad directive or wrong number of arguments"; goto loaderr;
  488. }
  489. sdsfreesplitres(argv,argc);
  490. }
  491. /* Sanity checks. */
  492. if (server.cluster_enabled && server.masterhost) {
  493. linenum = slaveof_linenum;
  494. i = linenum-1;
  495. err = "replicaof directive not allowed in cluster mode";
  496. goto loaderr;
  497. }
  498. /* To ensure backward compatibility and work while hz is out of range */
  499. if (server.config_hz < CONFIG_MIN_HZ) server.config_hz = CONFIG_MIN_HZ;
  500. if (server.config_hz > CONFIG_MAX_HZ) server.config_hz = CONFIG_MAX_HZ;
  501. sdsfreesplitres(lines,totlines);
  502. return;
  503. loaderr:
  504. fprintf(stderr, "\n*** FATAL CONFIG FILE ERROR (Redis %s) ***\n",
  505. REDIS_VERSION);
  506. fprintf(stderr, "Reading the configuration file, at line %d\n", linenum);
  507. fprintf(stderr, ">>> '%s'\n", lines[i]);
  508. fprintf(stderr, "%s\n", err);
  509. exit(1);
  510. }
  511. /* Load the server configuration from the specified filename.
  512. * The function appends the additional configuration directives stored
  513. * in the 'options' string to the config file before loading.
  514. *
  515. * Both filename and options can be NULL, in such a case are considered
  516. * empty. This way loadServerConfig can be used to just load a file or
  517. * just load a string. */
  518. void loadServerConfig(char *filename, char config_from_stdin, char *options) {
  519. sds config = sdsempty();
  520. char buf[CONFIG_MAX_LINE+1];
  521. FILE *fp;
  522. /* Load the file content */
  523. if (filename) {
  524. if ((fp = fopen(filename,"r")) == NULL) {
  525. serverLog(LL_WARNING,
  526. "Fatal error, can't open config file '%s': %s",
  527. filename, strerror(errno));
  528. exit(1);
  529. }
  530. while(fgets(buf,CONFIG_MAX_LINE+1,fp) != NULL)
  531. config = sdscat(config,buf);
  532. fclose(fp);
  533. }
  534. /* Append content from stdin */
  535. if (config_from_stdin) {
  536. serverLog(LL_WARNING,"Reading config from stdin");
  537. fp = stdin;
  538. while(fgets(buf,CONFIG_MAX_LINE+1,fp) != NULL)
  539. config = sdscat(config,buf);
  540. }
  541. /* Append the additional options */
  542. if (options) {
  543. config = sdscat(config,"\n");
  544. config = sdscat(config,options);
  545. }
  546. loadServerConfigFromString(config);
  547. sdsfree(config);
  548. }

相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载