? pdbtool.patch
Index: alprocs.c
===================================================================
RCS file: /afs/cs/project/coda-src/cvs/coda/coda-src/al/alprocs.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -r1.2 -r1.3
--- alprocs.c	1999/05/11 20:08:00	1.2
+++ alprocs.c	1999/08/06 19:40:14	1.3
@@ -42,6 +42,7 @@
 
 #include <stdio.h>
 #include <ctype.h>
+#include <fcntl.h>
 #include <sys/types.h>
 #include <sys/file.h>
 #include <sys/stat.h>
Index: pdb.c
===================================================================
RCS file: /afs/cs/project/coda-src/cvs/coda/coda-src/al/pdb.c,v
retrieving revision 1.7
diff -u -r1.7 pdb.c
--- pdb.c	1999/05/11 18:07:44	1.7
+++ pdb.c	1999/08/19 22:49:19
@@ -348,7 +348,7 @@
 	while(nextid != 0){
 		PDB_readProfile(h, nextid, &p);
 		CODA_ASSERT(p.id != 0);
-		pdb_array_del(&(p.groups_or_members), id);
+		pdb_array_del(&(p.member_of), id);
 		if(PDB_ISGROUP(p.id))
 			PDB_updateCps(h, &p);
 		else
Index: pdbdb.c
===================================================================
RCS file: /afs/cs/project/coda-src/cvs/coda/coda-src/al/pdbdb.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- pdbdb.c	1999/06/16 03:17:02	1.8
+++ pdbdb.c	1999/07/17 19:30:41	1.9
@@ -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
retrieving revision 1.6
diff -u -r1.3 -r1.6
--- pdbtool.c	1999/03/17 00:57:55	1.3
+++ pdbtool.c	1999/08/19 15:57:05	1.6
@@ -49,18 +49,33 @@
 	else return 0;
 }
 
+/* Convert a name or id argument into a numerical id value */
+int32_t get_id(char *n)
+{
+	int32_t id;
+	
+	/* try to interpret the passed argument as a numeric id */
+	id = atoi(n);
+	if(id != 0) return id;
+
+	/* Attempt to find the argument as a name */
+	PDB_lookupByName(n, &id);
+
+	return id;
+}
+
 /* LOOKUP BY ID */
-void tool_byId(int argc,char *argv[]){
+void tool_byNameOrId(int argc,char *argv[]){
 	PDB_profile sample;
 	PDB_HANDLE h;
-	long arg1;
+	int32_t arg1;
 	if(check_args_num(argc,2)){
 		printf("Usage: i idnum\nidnum\t\tnumber of user/group\n");
 		return;
 	}
-	arg1 = atol(argv[1]);
+	arg1 = get_id(argv[1]);
 	if(arg1 == 0){
-		printf("Give numerical value.\n");
+		printf("'%s' not found.\n", argv[1]);
 		return;
 	}
 	h = PDB_db_open(O_RDONLY);
@@ -70,24 +85,6 @@
 	PDB_db_close(h);
 }
 
-/* LOOKUP BY NAME */
-void tool_byName(int argc,char *argv[]){
-	int32_t id;
-	PDB_profile sample;
-	PDB_HANDLE h;
-	if(check_args_num(argc,2)){
-		printf("Usage: n name\nnamet\tname of user/group\n");
-		return;
-	}
-	PDB_lookupByName(argv[1], &id);
-	h = PDB_db_open(O_RDONLY);
-	PDB_readProfile(h, id, &sample);
-	PDB_printProfile(stdout, &sample);
-	PDB_freeProfile(&sample);
-	PDB_db_close(h);
-}
-
-
 /* LIST EVERTHING */
 void tool_list(int argc,char *argv[]){
 	int32_t id;
@@ -127,15 +124,15 @@
 void tool_newUser_Id(int argc,char *argv[]){
 	char *s;
 	int32_t id;
-	long arg2;
+	int32_t arg2;
 	if(check_args_num(argc,3)){
 		printf("Usage: nui name id\nname\t\t"
 		       "name of new user\nid\t\tid of new user\n");
 		return;
 	}
-	arg2 = atol(argv[2]);
-	if(arg2 == 0){
-		printf("Give numerical value.\n");
+	arg2 = atoi(argv[2]);
+	if(!PDB_ISUSER(arg2)){
+		printf("Not a valid user-id (it needs to be > 0).\n");
 		return;
 	}
 	PDB_lookupById((int32_t) arg2, &s);
@@ -144,7 +141,6 @@
 		free(s);
 		return;
 	}
-	free(s);
 	PDB_createUser(argv[1], &id);
 	if (id == 0){
 		printf("Failed to creat user.\n");
@@ -157,13 +153,13 @@
 
 /* CREATE NEW USER */
 void tool_changeName(int argc,char *argv[]){
-	long arg1;
+	int32_t arg1;
 	if(check_args_num(argc,3)){
 		printf("Usage: cn id name\nid\t\t"
 		       "id number of user\n\nname\t\tnew name of user\n");
 		return;
 	}
-	arg1 = atol(argv[1]);
+	arg1 = atoi(argv[1]);
 	if(arg1 == 0){
 		printf("Give numerical value.\n");
 		return;
@@ -176,25 +172,19 @@
 void tool_newGroup(int argc,char *argv[]){
 	char *s;
 	int32_t id;
-	long arg2;
+	int32_t arg2;
 	if(check_args_num(argc,3)){
 		printf("Usage: ng name owner\nname\t\t"
 		       "name of new group\nowner\t\t"
-		       "id number of group owner\n");
-		return;
-	}
-	arg2 = atol(argv[2]);
-	if(arg2 == 0){
-		printf("Give numerical value.\n");
-		return;
-	}
-	if(!PDB_ISUSER(arg2)){
-		printf("Owner must be a user!\n");
+		       "id/name number of group owner\n");
 		return;
 	}
+	arg2 = get_id(argv[2]);
 	PDB_lookupById((int32_t) arg2, &s);
-	if(s == NULL){
-		printf("No user %ld!\n",arg2);
+	if(!PDB_ISUSER(arg2) || s == NULL){
+		printf("Owner must be a valid username/id, %s not found!\n",
+		       argv[2]);
+		if (s) free(s);
 		return;
 	}
 	free(s);
@@ -269,29 +259,23 @@
 	long arg1, arg2;
 	if(check_args_num(argc,3)){
 		printf("Usage: ag group user\ngroup\t\t"
-		       "id of group to add to\nuser\t\t"
-		       "id number of user to add\n");
-		return;
-	}
-	arg1 = atol(argv[1]);
-	if(arg1 == 0){
-		printf("Give numerical value.\n");
+		       "id or name of group to add to\nuser\t\t"
+		       "id or name of user to add\n");
 		return;
 	}
+	arg1 = get_id(argv[1]);
 	PDB_lookupById((int32_t) arg1, &s);
-	if(s == NULL){
-		printf("No group %ld!\n",arg1);
+	if(!PDB_ISGROUP(arg1) || s == NULL){
+		printf("No group %s found!\n", argv[1]);
+		if (s) free(s);
 		return;
 	}
 	free(s);
-	arg2 = atol(argv[2]);
-	if(arg2 == 0){
-		printf("Give numerical value.\n");
-		return;
-	}
+	arg2 = get_id(argv[2]);
 	PDB_lookupById((int32_t) arg2, &s);
 	if(s == NULL){
-		printf("No user %ld!\n",arg2);
+		printf("No user or group %s found!\n", argv[2]);
+		if (s) free(s);
 		return;
 	}
 	free(s);
@@ -300,21 +284,21 @@
 
 /* REMOVE SOMEONE (USER OR GROUP) TO A GROUP */
 void tool_removefromGroup(int argc,char *argv[]){
-	long arg1, arg2;
+	int32_t arg1, arg2;
 	if(check_args_num(argc,3)){
 		printf("Usage: rg group user\ngroup\t\t"
-		       "id of group to remove from\nuser\t\t"
-		       "id number of user to remove\n");
+		       "id or name of group to remove from\nuser\t\t"
+		       "id or name of user to remove\n");
 		return;
 	}
-	arg1 = atol(argv[1]);
-	if(arg1 == 0){
-		printf("Give numerical value.\n");
+	arg1 = get_id(argv[1]);
+	if(!PDB_ISGROUP(arg1)) {
+		printf("No group %s found!\n", argv[1]);
 		return;
 	}
-	arg2 = atol(argv[2]);
-	if(arg2 == 0){
-		printf("Give numerical value.\n");
+	arg2 = get_id(argv[2]);
+	if(arg2 == 0) {
+		printf("No user or group %s found!\n", argv[2]);
 		return;
 	}
 	PDB_removeFromGroup(arg2, arg1);
@@ -325,17 +309,14 @@
 	char *s;
 	long arg1;
 	if(check_args_num(argc,2)){
-		printf("Usage: d id\nid\t\tid number of user/group\n");
-		return;
-	}
-	arg1 = atol(argv[1]);
-	if(arg1 == 0){
-		printf("Give numerical value.\n");
+		printf("Usage: d id/name\n"
+		       "id/name\t\tid or name of user/group\n");
 		return;
 	}
+	arg1 = get_id(argv[1]);
 	PDB_lookupById((int32_t) arg1, &s);
 	if(s == NULL){
-		printf("No user %ld!\n",arg1);
+		printf("%s not found!\n",argv[1]);
 		return;
 	}
 	free(s);
@@ -352,13 +333,14 @@
 	PDB_HANDLE h;
 	PDB_profile p;
 	if(check_args_num(argc,2)){
-		printf("Usage: u id\nid\t\tid number of user/group\n");
+		printf("Usage: u id/name\n"
+		       "id/name\t\tid or name of user/group\n");
 		return;
 	}
 	h = PDB_db_open(O_RDWR);
-	arg1 = atol(argv[1]);
+	arg1 = get_id(argv[1]);
 	if(arg1 == 0){
-		printf("Give numerical value.\n");
+		printf("%s not found.\n", argv[1]);
 		return;
 	}
 	PDB_readProfile(h, arg1, &p);
@@ -379,6 +361,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[]){
@@ -409,48 +403,227 @@
 	int32_t id;
 	long arg2;
 	if(check_args_num(argc,3)) {
-		printf("Usage %s username newid\n", argv[0]);
+		printf("Usage %s user/group newid\n", argv[0]);
 		return;
 	}
-	arg2 = atol(argv[2]);
-	if(arg2 == 0){
-		printf("Give numerical value.\n");
+	id = get_id(argv[1]);
+	if (id == 0) {
+		printf("%s not found.\n", argv[1]);
 		return;
 	}
-	PDB_lookupByName(argv[1], &id);
-	if (id == 0){
-		printf("Invalid user.\n");
+	arg2 = atol(argv[2]);
+	if(arg2 == 0){
+		printf("Give numerical value for newid.\n");
 		return;
 	}
 	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/name>\t\t\tget info from database about ID/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/name>\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/name> <id/name>\tadd a group or user to a group\n");
+	printf("rg <groupid/name> <id/name>\tremove a group or user from a group\n");
+	printf("d <id/name>\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/name>\t\t\tupdate an id/name\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");
+	printf("exit\t\t\t\texit the pdbtool\n");
 }
 
 command_t pdbcmds[] =
 {
-        {"i", tool_byId, 0, "read database by user ID"},
-	{"n", tool_byName, 0, "read database by user name"},
+        {"i", tool_byNameOrId, 0, "get info from the database (by name or id)"},
+	/* 'n' only for compatibility with pre-5.3 pdbtool */
+	{"n", tool_byNameOrId, 0, "get info from the database (by name or id)"},
 	{"nu", tool_newUser, 0, "create a new user"},
 	{"nui", tool_newUser_Id, 0, "create a new user with id"},
 	{"ng", tool_newGroup, 0, "create a new group"},
@@ -465,7 +638,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 +652,7 @@
 
 int main(int argc, char **argv)
 {
-	char *nl;
-
+	int i;
 	coda_assert_action = CODA_ASSERT_EXIT;
 
 	PDB_setupdb();
@@ -485,16 +661,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;
 }

