On Fri, Jul 16, 1999 at 07:21:27AM -0400, Greg Troxel wrote: > I am guessing that the problems are due to incomplete conversion to > the ntohl/htonl conversion just made to make the pdb > endian-independent. No, it was not related to that. The code was doing a read-modify-write of the database record containing the maxids, and for some reason this confused libdb. I managed to fix it by doing read-copy-modify-write. > It would be nice if there were an 'pdbtool export' command that > printed out the contents in plain ascii so that it could be edited if > necessary and then fed into 'pdbtool import'. Added this as well, I believe it will be a very useful feature. The dump format mimics the format used by /etc/passwd and /etc/group. The differences are that the first member of a group will be the group owner. This information is currently not used, but in the future a group owner should be able to add/remove groupmembers. And :'s in the group names are encoded as %'s. I also modified pdbtool to accept all commands from the commandline. Because pdbtool used to consider first argument on the commandline as a file to parse commands from, I've added a `source' command. For those who are interested, I'll attach a patch against 5.2.7. Greg's `ids' command to list the current maxids is also included. > Greg Troxel <[EMAIL PROTECTED]> Jan
Index: pdbdb.c =================================================================== RCS file: /afs/cs/project/coda-src/cvs/coda/coda-src/al/pdbdb.c,v retrieving revision 1.8 diff -u -r1.8 pdbdb.c --- pdbdb.c 1999/06/16 03:17:02 1.8 +++ pdbdb.c 1999/07/17 19:28:31 @@ -176,7 +176,7 @@ int rc; char zero = 0; int32_t olduid, oldgid; - int32_t *ids = NULL; + int32_t ids[2]; CODA_ASSERT(uid >= 0 && gid <= 0); @@ -190,18 +190,16 @@ if ( rc != RET_SUCCESS ) { CODA_ASSERT( (uid == 0) && (gid == 0) ); - olduid = -1; - oldgid = 1; - value.size = 2 * sizeof(int32_t); - ids = malloc(value.size); - value.data = (void *) ids; - } else { + ids[0] = htonl(0); + ids[1] = htonl(0); + } else { CODA_ASSERT(value.size == 2*sizeof(int32_t)); - ids = (int32_t *) value.data; - olduid = ntohl(ids[0]); - oldgid = ntohl(ids[1]); - CODA_ASSERT(olduid >= 0 || oldgid <= 0); + ids[0] = ((int32_t *)value.data)[0]; + ids[1] = ((int32_t *)value.data)[1]; } + olduid = ntohl(ids[0]); + oldgid = ntohl(ids[1]); + CODA_ASSERT(olduid >= 0 || oldgid <= 0); if ( mode != PDB_MAXID_FORCE ) { if ( uid > olduid ) @@ -214,6 +212,9 @@ ids[1] = htonl(gid); } + value.size = 2 * sizeof(int32_t); + value.data = (void *) &ids; + rc = h->main->put(h->main, &key, &value, 0); CODA_ASSERT(rc == RET_SUCCESS); } @@ -361,7 +362,7 @@ /* this record has a special 1-byte key equal to zero */ memset(&key, 0, sizeof(DBT)); - key.size = 1; + key.size = sizeof(zero); key.data = &zero; /* open the profile database in read mode */ Index: pdbtool.c =================================================================== RCS file: /afs/cs/project/coda-src/cvs/coda/coda-src/al/pdbtool.c,v retrieving revision 1.3 diff -u -r1.3 pdbtool.c --- pdbtool.c 1999/03/17 00:57:55 1.3 +++ pdbtool.c 1999/07/17 19:28:31 @@ -379,6 +379,18 @@ PDB_db_close(h); } +/* SHOW MAXIDS */ +void tool_get_maxids(int argc,char *argv[]){ + PDB_HANDLE h; + int maxuid, maxgid; + if(check_args_num(argc,1)){ + printf("Usage: get_maxids\n"); + } + h = PDB_db_open(O_RDWR); + PDB_db_maxids(h, &maxuid, &maxgid); + PDB_db_close(h); + printf("maxuid %d maxgid %d\n", maxuid, maxgid); +} /* SET MAXIDS */ void tool_maxids(int argc,char *argv[]){ @@ -425,26 +437,204 @@ PDB_changeId(id,arg2); } +/* dump/restore database contents */ +void tool_export(int argc, char *argv[]) +{ + int32_t id, i; + PDB_profile rec; + PDB_HANDLE h; + FILE *userfile, *groupfile; + char *s; + int rc; + + if (check_args_num(argc, 3)) { + printf("Usage: export <userfile> <groupfile>\n"); + return; + } + + userfile = fopen(argv[1], "w"); + groupfile = fopen(argv[2], "w"); + + h = PDB_db_open(O_RDONLY); + while ((rc = PDB_db_nextkey(h, &id))) { + if (rc == -1) continue; + + PDB_readProfile(h, id, &rec); + { + if (PDB_ISUSER(rec.id)) { + /* users are dumped in an /etc/passwd like format + * "<username>:x:<userid>:500::/:" */ + fprintf(userfile, "%s:*:%d:500::/:\n", rec.name, rec.id); + } else { + /* groups and group members are dumped in an /etc/group like + * format "<groupname>:x:<groupid>:<owner>[,<members>]*" */ + + /* escape the :'s in the group names */ + s = rec.name; while ((s = strchr(s, ':')) != NULL) *s = '%'; + + fprintf(groupfile, "%s:*:%d:%s", rec.name, rec.id, + rec.owner_name); + for (i = 0; i < rec.groups_or_members.size; i++) { + if (rec.groups_or_members.data[i] == rec.owner_id) + continue; + + PDB_lookupById(rec.groups_or_members.data[i], &s); + if (s == NULL) continue; + + fprintf(groupfile, ",%s", s); + free(s); + } + fprintf(groupfile, "\n"); + } + } + PDB_freeProfile(&rec); + } + PDB_db_close(h); + + fclose(userfile); + fclose(groupfile); +} + +void tool_import(int argc, char *argv[]) +{ + FILE *userfile, *groupfile; + char user[64], group[64], owner_and_members[1024], *owner, *member, *s; + int32_t user_id, group_id, owner_id, member_id, create_id; + int rc; + + if (check_args_num(argc, 3)) { + printf("Usage: import <userfile> <groupfile>\n"); + return; + } + + /* recreate all users */ + userfile = fopen(argv[1], "r"); + while(1) { + rc = fscanf(userfile, "%[^:]:%*[^:]:%d:%*s\n", user, &user_id); + if (rc < 0) break; + + /* create user */ + PDB_lookupById(user_id, &s); + if (s) { + printf("Duplicate user for id %d, found both %s and %s\n", + user_id, s, user); + free(s); + continue; + } + + PDB_createUser(user, &create_id); + PDB_changeId(create_id, user_id); + printf("Created user %s, id %d\n", user, user_id); + } + fclose(userfile); + + /* recreate groups */ + groupfile = fopen(argv[2], "r"); + while (1) { + rc = fscanf(groupfile, "%[^:]:%*[^:]:%d:%s\n", + group, &group_id, owner_and_members); + if (rc < 0) break; + + /* restore the :'s in the group name */ + s = group; while ((s = strchr(s, '%')) != NULL) *s = ':'; + + owner = strtok(owner_and_members, ","); + + /* create group */ + PDB_lookupByName(owner, &owner_id); + if (owner_id == 0) { + printf("Group %s's owner %s cannot be found\n", group, owner); + continue; + } + if (!PDB_ISUSER(owner_id)) { + printf("Group %s's owner %s is a group but should be a user\n", + group, owner); + continue; + } + PDB_createGroup(group, owner_id, &create_id); + PDB_changeId(create_id, group_id); + printf("Created group %s, id %d, owner %s\n", group, group_id, owner); + } + + /* add group members*/ + rewind(groupfile); + while (1) { + rc = fscanf(groupfile, "%[^:]:%*[^:]:%d:%s\n", + group, &group_id, owner_and_members); + if (rc < 0) break; + + /* restore the :'s in the group name */ + s = group; while ((s = strchr(s, '%')) != NULL) *s = ':'; + + /* skip the owner */ + (void)strtok(owner_and_members, ","); + + /* add group members */ + printf("Adding members to %s\n\t", group); + while ((member = strtok(NULL, ",")) != NULL) { + /* restore the :'s in the name */ + s = member; while ((s = strchr(s, '%')) != NULL) *s = ':'; + + PDB_lookupByName(member, &member_id); + if (member_id == 0) { + printf("\nGroup %s's member %s cannot be found\n\t", + group, member); + continue; + } + PDB_addToGroup(member_id, group_id); + printf(" %s", member); + } + printf("\n"); + } + fclose(groupfile); +} + +void tool_source(int argc, char *argv[]) +{ + char line[1024]; + char *nl; + + FILE *file = fopen(argv[1], "r"); + if ( !file ) { + perror(""); + return; + } + while ( fgets(line, 1024, file) ) { + if ( (nl = strchr(line, '\n')) ) + *nl = '\0'; + execute_line(line); + } +} /* HELP */ -void tool_help(int argc, char *argv[]){ - printf("i\tread database by user ID\n"); - printf("n\tread database by user name\n"); - printf("nu\tcreate a new user\n"); - printf("nui\tcreate a new user with id\n"); - printf("ng\tcreate a new group\n"); - printf("l\tlook up an ID by name\n"); - printf("list\tlist all entries\n"); - printf("cu\tclone a user\n"); - printf("ag\tadd a group or user to a group\n"); - printf("rg\tremove a group or user from a group\n"); - printf("d\tdelete a user or a group\n"); - printf("cm\tcompact the database (RARE)\n"); - printf("ci\tchange the Id of a new user or group\n"); - printf("cn\tchange the Name of a user\n"); - printf("maxids\tset the database maxids\n"); - printf("u\tupdate an id\n"); +void tool_help(int argc, char *argv[]) +{ + if (argc > 1) { + Parser_help(argc, argv); + return; + } + + printf("i <id>\t\t\t\tread database by ID\n"); + printf("n <name>\t\t\tread database by name\n"); + printf("nu <username>\t\t\tcreate a new user\n"); + printf("nui <username> <userid>\t\tcreate a new user with id\n"); + printf("ng <groupname> <ownerid>\tcreate a new group\n"); + printf("l <name>\t\t\tlook up an ID by name\n"); + printf("list\t\t\t\tlist all entries\n"); + printf("cu <newusername> <userid>\tclone a user\n"); + printf("ag <groupid> <id>\t\tadd a group or user to a group\n"); + printf("rg <groupid> <id>\t\tremove a group or user from a group\n"); + printf("d <id>\t\t\t\tdelete a user or a group\n"); + printf("cm\t\t\t\tcompact the database (RARE)\n"); + printf("ci <name> <newid>\t\tchange the Id of a user or group\n"); + printf("cn <id> <newname>\t\tchange the Name of a user or group\n"); + printf("u <id>\t\t\t\tupdate an id\n"); + printf("ids\t\t\t\tget the database maxids\n"); + printf("maxids <userid> <groupid>\tset the database maxids\n"); + printf("export <userfile> <groupfile>\tdump the contents of the pdb +database\n"); + printf("import <userfile> <groupfile>\tread a dumped pdb database\n"); + printf("source <file>\t\t\tread commands from file\n"); } command_t pdbcmds[] = @@ -465,7 +655,11 @@ {"ci", tool_changeId, 0, "change the Id of a user or group"}, {"cn", tool_changeName, 0, "change the Name of a user"}, {"u", tool_update, 0, "update an id"}, + {"ids", tool_get_maxids, 0, "get the database maxids"}, {"maxids", tool_maxids, 0, "set the database maxids"}, + {"export", tool_export, 0, "dump the contents of the database"}, + {"import", tool_import, 0, "load the contents of the database"}, + {"source", tool_source, 0, "read commands from file"}, {"help", tool_help, 0, "print help on commands"}, {"quit", Parser_exit, 0, "get me out of here"}, {"exit", Parser_exit, 0, "get me out of here"}, @@ -475,8 +669,7 @@ int main(int argc, char **argv) { - char *nl; - + int i; coda_assert_action = CODA_ASSERT_EXIT; PDB_setupdb(); @@ -485,16 +678,12 @@ Parser_commands(); else { char line[1024]; - FILE *file = fopen(argv[1], "r"); - if ( !file ) { - perror(""); - return 1; - } - while ( fgets(line, 1024, file) ) { - if ( (nl = strchr(line, '\n')) ) - *nl = '\0'; - execute_line(line); + strcpy(line, argv[1]); + for (i = 2; i < argc; i++) { + strcat(line, " "); + strcat(line, argv[i]); } + execute_line(line); } return 0; }