s3-param: added lp_set_cmdline() and --option= parameter
authorAndrew Tridgell <tridge@samba.org>
Wed, 11 Aug 2010 03:35:14 +0000 (13:35 +1000)
committerAndrew Tridgell <tridge@samba.org>
Thu, 2 Sep 2010 03:37:08 +0000 (13:37 +1000)
Pair-Programmed-With: Andrew Bartlett <abartlet@samba.org>

source3/include/proto.h
source3/include/smb.h
source3/lib/popt_common.c
source3/param/loadparm.c

index a49aa66564c185cc238ad5b56266e370e2ecd722..180e1c03bddd41f33d582583aed57ca3bfcfc31e 100644 (file)
@@ -3605,6 +3605,8 @@ const char *lp_ldap_group_suffix(void);
 const char *lp_ldap_idmap_suffix(void);
 void *lp_local_ptr_by_snum(int snum, void *ptr);
 bool lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue);
+bool lp_set_cmdline(const char *pszParmName, const char *pszParmValue);
+bool lp_set_option(const char *option);
 void init_locals(void);
 bool lp_is_default(int snum, struct parm_struct *parm);
 bool dump_a_parameter(int snum, char *parm_name, FILE * f, bool isGlobal);
index 129be1cad85d815df5fb05b3baa64b11a0c3a588..f109739a42a70ff2e97be229769d30050e743e9b 100644 (file)
@@ -905,6 +905,7 @@ struct parm_struct {
 #define FLAG_HIDE      0x2000 /* options that should be hidden in SWAT */
 #define FLAG_DOS_STRING 0x4000 /* convert from UNIX to DOS codepage when reading this string. */
 #define FLAG_META      0x8000 /* A meta directive - not a real parameter */
+#define FLAG_CMDLINE   0x10000 /* option has been overridden */
 
 struct bitmap {
        uint32 *b;
index 9dd438b7f79fe1822dacccdcb7ba135b306ff7ae..a332cde56610db0ee3e7260997919b5a02f663ca 100644 (file)
@@ -34,6 +34,8 @@
  *             -i,--scope
  */
 
+enum {OPT_OPTION=1};
+
 extern bool AllowDebugChange;
 extern bool override_logfile;
 
@@ -96,6 +98,13 @@ static void popt_common_callback(poptContext con,
        }
 
        switch(opt->val) {
+       case OPT_OPTION:
+               if (!lp_set_option(arg)) {
+                       fprintf(stderr, "Error setting option '%s'\n", arg);
+                       exit(1);
+               }
+               break;
+
        case 'd':
                if (arg) {
                        debug_parse_levels(arg);
@@ -164,6 +173,7 @@ struct poptOption popt_common_samba[] = {
        { "configfile", 's', POPT_ARG_STRING, NULL, 's', "Use alternate configuration file", "CONFIGFILE" },
        { "log-basename", 'l', POPT_ARG_STRING, NULL, 'l', "Base name for log files", "LOGFILEBASE" },
        { "version", 'V', POPT_ARG_NONE, NULL, 'V', "Print version" },
+       { "option",         0, POPT_ARG_STRING, NULL, OPT_OPTION, "Set smb.conf option from command line", "name=value" },
        POPT_TABLEEND
 };
 
index 2981856caef67f79055b4fe5c797fe9fa71a9f76..e3fc2d8b3a942f315d3f8c722d480c84d28c90f9 100644 (file)
@@ -117,6 +117,7 @@ struct param_opt_struct {
        char *key;
        char *value;
        char **list;
+       unsigned flags;
 };
 
 /*
@@ -705,6 +706,7 @@ static void set_allowed_client_auth(void);
 static void *lp_local_ptr(struct service *service, void *ptr);
 
 static void add_to_file_list(const char *fname, const char *subfname);
+static bool lp_set_cmdline_helper(const char *pszParmName, const char *pszParmValue, bool store_values);
 
 static const struct enum_list enum_protocol[] = {
        {PROTOCOL_SMB2, "SMB2"},
@@ -4944,6 +4946,67 @@ static void free_global_parameters(void)
        free_parameters_by_snum(GLOBAL_SECTION_SNUM);
 }
 
+static int map_parameter(const char *pszParmName);
+
+struct lp_stored_option {
+       struct lp_stored_option *prev, *next;
+       const char *label;
+       const char *value;
+};
+
+static struct lp_stored_option *stored_options;
+
+/*
+  save options set by lp_set_cmdline() into a list. This list is
+  re-applied when we do a globals reset, so that cmdline set options
+  are sticky across reloads of smb.conf
+ */
+static bool store_lp_set_cmdline(const char *pszParmName, const char *pszParmValue)
+{
+       struct lp_stored_option *entry = NULL;
+       for (entry = stored_options; entry != NULL; entry = entry->next) {
+               if (strcmp(pszParmName, entry->label) == 0) {
+                       DLIST_REMOVE(stored_options, entry);
+                       talloc_free(entry);
+                       break;
+               }
+       }
+
+       entry = talloc(NULL, struct lp_stored_option);
+       if (!entry) {
+               return false;
+       }
+
+       entry->label = talloc_strdup(entry, pszParmName);
+       if (!entry->label) {
+               talloc_free(entry);
+               return false;
+       }
+
+       entry->value = talloc_strdup(entry, pszParmValue);
+       if (!entry->value) {
+               talloc_free(entry);
+               return false;
+       }
+
+       DLIST_ADD_END(stored_options, entry, struct lp_stored_option);
+
+       return true;
+}
+
+static bool apply_lp_set_cmdline(void)
+{
+       struct lp_stored_option *entry = NULL;
+       for (entry = stored_options; entry != NULL; entry = entry->next) {
+               if (!lp_set_cmdline_helper(entry->label, entry->value, false)) {
+                       DEBUG(0, ("Failed to re-apply cmdline parameter %s = %s\n",
+                                 entry->label, entry->value));
+                       return false;
+               }
+       }
+       return true;
+}
+
 /***************************************************************************
  Initialise the global parameter structure.
 ***************************************************************************/
@@ -4971,6 +5034,10 @@ static void init_globals(bool reinit_globals)
                free_global_parameters();
        }
 
+       /* This memset and the free_global_parameters() above will
+        * wipe out smb.conf options set with lp_set_cmdline().  The
+        * apply_lp_set_cmdline() call puts these values back in the
+        * table once the defaults are set */
        memset((void *)&Globals, '\0', sizeof(Globals));
 
        for (i = 0; parm_table[i].label; i++) {
@@ -5287,6 +5354,9 @@ static void init_globals(bool reinit_globals)
        Globals.ismb2_max_read = 1024*1024;
        Globals.ismb2_max_write = 1024*1024;
        Globals.ismb2_max_trans = 1024*1024;
+
+       /* Now put back the settings that were set with lp_set_cmdline() */
+       apply_lp_set_cmdline();
 }
 
 /*******************************************************************
@@ -5816,7 +5886,6 @@ FN_GLOBAL_INTEGER(lp_client_ldap_sasl_wrapping, &Globals.client_ldap_sasl_wrappi
 
 /* local prototypes */
 
-static int map_parameter(const char *pszParmName);
 static int map_parameter_canonical(const char *pszParmName, bool *inverse);
 static const char *get_boolean(bool bool_value);
 static int getservicebyname(const char *pszServiceName,
@@ -6819,7 +6888,8 @@ static int getservicebyname(const char *pszServiceName, struct service *pservice
  */
 static void set_param_opt(struct param_opt_struct **opt_list,
                          const char *opt_name,
-                         const char *opt_value)
+                         const char *opt_value,
+                         unsigned flags)
 {
        struct param_opt_struct *new_opt, *opt;
        bool not_added;
@@ -6835,9 +6905,16 @@ static void set_param_opt(struct param_opt_struct **opt_list,
        while (opt) {
                /* If we already have same option, override it */
                if (strwicmp(opt->key, opt_name) == 0) {
+                       if ((opt->flags & FLAG_CMDLINE) &&
+                           !(flags & FLAG_CMDLINE)) {
+                               /* it's been marked as not to be
+                                  overridden */
+                               return;
+                       }
                        string_free(&opt->value);
                        TALLOC_FREE(opt->list);
                        opt->value = SMB_STRDUP(opt_value);
+                       opt->flags = flags;
                        not_added = false;
                        break;
                }
@@ -6848,6 +6925,7 @@ static void set_param_opt(struct param_opt_struct **opt_list,
            new_opt->key = SMB_STRDUP(opt_name);
            new_opt->value = SMB_STRDUP(opt_value);
            new_opt->list = NULL;
+           new_opt->flags = flags;
            DLIST_ADD(*opt_list, new_opt);
        }
 }
@@ -6915,7 +6993,7 @@ static void copy_service(struct service *pserviceDest, struct service *pserviceS
 
        data = pserviceSource->param_opt;
        while (data) {
-               set_param_opt(&pserviceDest->param_opt, data->key, data->value);
+               set_param_opt(&pserviceDest->param_opt, data->key, data->value, data->flags);
                data = data->next;
        }
 }
@@ -7672,11 +7750,17 @@ bool lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue
 
                opt_list = (snum < 0)
                        ? &Globals.param_opt : &ServicePtrs[snum]->param_opt;
-               set_param_opt(opt_list, pszParmName, pszParmValue);
+               set_param_opt(opt_list, pszParmName, pszParmValue, 0);
 
                return (True);
        }
 
+       /* if it's already been set by the command line, then we don't
+          override here */
+       if (parm_table[parmnum].flags & FLAG_CMDLINE) {
+               return true;
+       }
+
        if (parm_table[parmnum].flags & FLAG_DEPRECATED) {
                DEBUG(1, ("WARNING: The \"%s\" option is deprecated\n",
                          pszParmName));
@@ -7765,6 +7849,42 @@ bool lp_do_parameter(int snum, const char *pszParmName, const char *pszParmValue
        return (True);
 }
 
+/***************************************************************************
+set a parameter, marking it with FLAG_CMDLINE. Parameters marked as
+FLAG_CMDLINE won't be overridden by loads from smb.conf.
+***************************************************************************/
+
+static bool lp_set_cmdline_helper(const char *pszParmName, const char *pszParmValue, bool store_values)
+{
+       int parmnum;
+       parmnum = map_parameter(pszParmName);
+       if (parmnum >= 0) {
+               parm_table[parmnum].flags &= ~FLAG_CMDLINE;
+               if (!lp_do_parameter(-1, pszParmName, pszParmValue)) {
+                       return false;
+               }
+               parm_table[parmnum].flags |= FLAG_CMDLINE;
+
+               store_lp_set_cmdline(pszParmName, pszParmValue);
+               return true;
+       }
+
+       /* it might be parametric */
+       if (strchr(pszParmName, ':') != NULL) {
+               set_param_opt(&Globals.param_opt, pszParmName, pszParmValue, FLAG_CMDLINE);
+               store_lp_set_cmdline(pszParmName, pszParmValue);
+               return true;
+       }
+
+       DEBUG(0, ("Ignoring unknown parameter \"%s\"\n",  pszParmName));
+       return true;
+}
+
+bool lp_set_cmdline(const char *pszParmName, const char *pszParmValue)
+{
+       return lp_set_cmdline_helper(pszParmName, pszParmValue, true);
+}
+
 /***************************************************************************
  Process a parameter.
 ***************************************************************************/
@@ -7781,7 +7901,33 @@ static bool do_parameter(const char *pszParmName, const char *pszParmValue,
                                pszParmName, pszParmValue));
 }
 
-/***************************************************************************
+/*
+  set a option from the commandline in 'a=b' format. Use to support --option
+*/
+bool lp_set_option(const char *option)
+{
+       char *p, *s;
+       bool ret;
+
+       s = talloc_strdup(NULL, option);
+       if (!s) {
+               return false;
+       }
+
+       p = strchr(s, '=');
+       if (!p) {
+               talloc_free(s);
+               return false;
+       }
+
+       *p = 0;
+
+       ret = lp_set_cmdline(s, p+1);
+       talloc_free(s);
+       return ret;
+}
+
+/**************************************************************************
  Print a parameter of the specified type.
 ***************************************************************************/