root/source3/lib/ldb/tools/ldbedit.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ldif_write_msg
  2. modify_record
  3. msg_find
  4. merge_edits
  5. save_ldif
  6. do_edit
  7. usage
  8. main

   1 /* 
   2    ldb database library
   3 
   4    Copyright (C) Andrew Tridgell  2004
   5 
   6      ** NOTE! The following LGPL license applies to the ldb
   7      ** library. This does NOT imply that all of Samba is released
   8      ** under the LGPL
   9    
  10    This library is free software; you can redistribute it and/or
  11    modify it under the terms of the GNU Lesser General Public
  12    License as published by the Free Software Foundation; either
  13    version 3 of the License, or (at your option) any later version.
  14 
  15    This library is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  18    Lesser General Public License for more details.
  19 
  20    You should have received a copy of the GNU Lesser General Public
  21    License along with this library; if not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 /*
  25  *  Name: ldb
  26  *
  27  *  Component: ldbedit
  28  *
  29  *  Description: utility for ldb database editing
  30  *
  31  *  Author: Andrew Tridgell
  32  */
  33 
  34 #include "includes.h"
  35 #include "ldb/include/includes.h"
  36 #include "ldb/tools/cmdline.h"
  37 
  38 static struct ldb_cmdline *options;
  39 
  40 /*
  41   debug routine 
  42 */
  43 static void ldif_write_msg(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
  44                            FILE *f, 
  45                            enum ldb_changetype changetype,
  46                            struct ldb_message *msg)
  47 {
  48         struct ldb_ldif ldif;
  49         ldif.changetype = changetype;
  50         ldif.msg = msg;
  51         ldb_ldif_write_file(ldb, f, &ldif);
  52 }
  53 
  54 /*
  55   modify a database record so msg1 becomes msg2
  56   returns the number of modified elements
  57 */
  58 static int modify_record(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
  59                          struct ldb_message *msg1,
  60                          struct ldb_message *msg2)
  61 {
  62         struct ldb_message *mod;
  63 
  64         mod = ldb_msg_diff(ldb, msg1, msg2);
  65         if (mod == NULL) {
  66                 fprintf(stderr, "Failed to calculate message differences\n");
  67                 return -1;
  68         }
  69 
  70         if (mod->num_elements == 0) {
  71                 return 0;
  72         }
  73 
  74         if (options->verbose > 0) {
  75                 ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_MODIFY, mod);
  76         }
  77 
  78         if (ldb_modify(ldb, mod) != 0) {
  79                 fprintf(stderr, "failed to modify %s - %s\n", 
  80                         ldb_dn_linearize(ldb, msg1->dn), ldb_errstring(ldb));
  81                 return -1;
  82         }
  83 
  84         return mod->num_elements;
  85 }
  86 
  87 /*
  88   find dn in msgs[]
  89 */
  90 static struct ldb_message *msg_find(struct ldb_context *ldb,
     /* [<][>][^][v][top][bottom][index][help] */
  91                                     struct ldb_message **msgs,
  92                                     int count,
  93                                     const struct ldb_dn *dn)
  94 {
  95         int i;
  96         for (i=0;i<count;i++) {
  97                 if (ldb_dn_compare(ldb, dn, msgs[i]->dn) == 0) {
  98                         return msgs[i];
  99                 }
 100         }
 101         return NULL;
 102 }
 103 
 104 /*
 105   merge the changes in msgs2 into the messages from msgs1
 106 */
 107 static int merge_edits(struct ldb_context *ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 108                        struct ldb_message **msgs1, int count1,
 109                        struct ldb_message **msgs2, int count2)
 110 {
 111         int i;
 112         struct ldb_message *msg;
 113         int ret = 0;
 114         int adds=0, modifies=0, deletes=0;
 115 
 116         /* do the adds and modifies */
 117         for (i=0;i<count2;i++) {
 118                 msg = msg_find(ldb, msgs1, count1, msgs2[i]->dn);
 119                 if (!msg) {
 120                         if (options->verbose > 0) {
 121                                 ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_ADD, msgs2[i]);
 122                         }
 123                         if (ldb_add(ldb, msgs2[i]) != 0) {
 124                                 fprintf(stderr, "failed to add %s - %s\n",
 125                                         ldb_dn_linearize(ldb, msgs2[i]->dn),
 126                                         ldb_errstring(ldb));
 127                                 return -1;
 128                         }
 129                         adds++;
 130                 } else {
 131                         if (modify_record(ldb, msg, msgs2[i]) > 0) {
 132                                 modifies++;
 133                         }
 134                 }
 135         }
 136 
 137         /* do the deletes */
 138         for (i=0;i<count1;i++) {
 139                 msg = msg_find(ldb, msgs2, count2, msgs1[i]->dn);
 140                 if (!msg) {
 141                         if (options->verbose > 0) {
 142                                 ldif_write_msg(ldb, stdout, LDB_CHANGETYPE_DELETE, msgs1[i]);
 143                         }
 144                         if (ldb_delete(ldb, msgs1[i]->dn) != 0) {
 145                                 fprintf(stderr, "failed to delete %s - %s\n",
 146                                         ldb_dn_linearize(ldb, msgs1[i]->dn),
 147                                         ldb_errstring(ldb));
 148                                 return -1;
 149                         }
 150                         deletes++;
 151                 }
 152         }
 153 
 154         printf("# %d adds  %d modifies  %d deletes\n", adds, modifies, deletes);
 155 
 156         return ret;
 157 }
 158 
 159 /*
 160   save a set of messages as ldif to a file
 161 */
 162 static int save_ldif(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
 163                      FILE *f, struct ldb_message **msgs, int count)
 164 {
 165         int i;
 166 
 167         fprintf(f, "# editing %d records\n", count);
 168 
 169         for (i=0;i<count;i++) {
 170                 struct ldb_ldif ldif;
 171                 fprintf(f, "# record %d\n", i+1);
 172 
 173                 ldif.changetype = LDB_CHANGETYPE_NONE;
 174                 ldif.msg = msgs[i];
 175 
 176                 ldb_ldif_write_file(ldb, f, &ldif);
 177         }
 178 
 179         return 0;
 180 }
 181 
 182 
 183 /*
 184   edit the ldb search results in msgs using the user selected editor
 185 */
 186 static int do_edit(struct ldb_context *ldb, struct ldb_message **msgs1, int count1,
     /* [<][>][^][v][top][bottom][index][help] */
 187                    const char *editor)
 188 {
 189         int fd, ret;
 190         FILE *f;
 191         char file_template[] = "/tmp/ldbedit.XXXXXX";
 192         char *cmd;
 193         struct ldb_ldif *ldif;
 194         struct ldb_message **msgs2 = NULL;
 195         int count2 = 0;
 196 
 197         /* write out the original set of messages to a temporary
 198            file */
 199         fd = mkstemp(file_template);
 200 
 201         if (fd == -1) {
 202                 perror(file_template);
 203                 return -1;
 204         }
 205 
 206         f = fdopen(fd, "r+");
 207 
 208         if (!f) {
 209                 perror("fopen");
 210                 close(fd);
 211                 unlink(file_template);
 212                 return -1;
 213         }
 214 
 215         if (save_ldif(ldb, f, msgs1, count1) != 0) {
 216                 return -1;
 217         }
 218 
 219         fclose(f);
 220 
 221         cmd = talloc_asprintf(ldb, "%s %s", editor, file_template);
 222 
 223         if (!cmd) {
 224                 unlink(file_template);
 225                 fprintf(stderr, "out of memory\n");
 226                 return -1;
 227         }
 228 
 229         /* run the editor */
 230         ret = system(cmd);
 231         talloc_free(cmd);
 232 
 233         if (ret != 0) {
 234                 unlink(file_template);
 235                 fprintf(stderr, "edit with %s failed\n", editor);
 236                 return -1;
 237         }
 238 
 239         /* read the resulting ldif into msgs2 */
 240         f = fopen(file_template, "r");
 241         if (!f) {
 242                 perror(file_template);
 243                 return -1;
 244         }
 245 
 246         while ((ldif = ldb_ldif_read_file(ldb, f))) {
 247                 msgs2 = talloc_realloc(ldb, msgs2, struct ldb_message *, count2+1);
 248                 if (!msgs2) {
 249                         fprintf(stderr, "out of memory");
 250                         return -1;
 251                 }
 252                 msgs2[count2++] = ldif->msg;
 253         }
 254 
 255         fclose(f);
 256         unlink(file_template);
 257 
 258         return merge_edits(ldb, msgs1, count1, msgs2, count2);
 259 }
 260 
 261 static void usage(void)
     /* [<][>][^][v][top][bottom][index][help] */
 262 {
 263         printf("Usage: ldbedit <options> <expression> <attributes ...>\n");
 264         printf("Options:\n");
 265         printf("  -H ldb_url       choose the database (or $LDB_URL)\n");
 266         printf("  -s base|sub|one  choose search scope\n");
 267         printf("  -b basedn        choose baseDN\n");
 268         printf("  -a               edit all records (expression 'objectclass=*')\n");
 269         printf("  -e editor        choose editor (or $VISUAL or $EDITOR)\n");
 270         printf("  -v               verbose mode\n");
 271         exit(1);
 272 }
 273 
 274 int main(int argc, const char **argv)
     /* [<][>][^][v][top][bottom][index][help] */
 275 {
 276         struct ldb_context *ldb;
 277         struct ldb_result *result = NULL;
 278         struct ldb_dn *basedn = NULL;
 279         int ret;
 280         const char *expression = "(|(objectClass=*)(distinguishedName=*))";
 281         const char * const * attrs = NULL;
 282 
 283         ldb_global_init();
 284 
 285         ldb = ldb_init(NULL);
 286 
 287         options = ldb_cmdline_process(ldb, argc, argv, usage);
 288 
 289         /* the check for '=' is for compatibility with ldapsearch */
 290         if (options->argc > 0 && 
 291             strchr(options->argv[0], '=')) {
 292                 expression = options->argv[0];
 293                 options->argv++;
 294                 options->argc--;
 295         }
 296 
 297         if (options->argc > 0) {
 298                 attrs = (const char * const *)(options->argv);
 299         }
 300 
 301         if (options->basedn != NULL) {
 302                 basedn = ldb_dn_explode(ldb, options->basedn);
 303                 if (basedn == NULL) {
 304                         printf("Invalid Base DN format\n");
 305                         exit(1);
 306                 }
 307         }
 308 
 309         ret = ldb_search(ldb, ldb, &result, basedn, options->scope, attrs, "%s", expression);
 310         if (ret != LDB_SUCCESS) {
 311                 printf("search failed - %s\n", ldb_errstring(ldb));
 312                 exit(1);
 313         }
 314 
 315         if (result->count == 0) {
 316                 printf("no matching records - cannot edit\n");
 317                 return 0;
 318         }
 319 
 320         do_edit(ldb, result->msgs, result->count, options->editor);
 321 
 322         ret = talloc_free(result);
 323         if (ret == -1) {
 324                 fprintf(stderr, "talloc_free failed\n");
 325                 exit(1);
 326         }
 327 
 328         talloc_free(ldb);
 329         return 0;
 330 }

/* [<][>][^][v][top][bottom][index][help] */